Imported Upstream version 2.1.10 upstream/2.1.10
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:06 +0000 (16:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:06 +0000 (16:00 +0900)
242 files changed:
Makefile.am
NEWS
README
agent/ChangeLog-2011
agent/cache.c
agent/call-pinentry.c
agent/call-scd.c
agent/command-ssh.c
agent/command.c
agent/divert-scd.c
agent/findkey.c
agent/genkey.c
agent/gpg-agent.c
agent/trustlist.c
agent/w32main.c
autogen.sh
build-aux/speedo/w32/inst.nsi
common/ChangeLog-2011
common/Makefile.am
common/argparse.c
common/asshelp.c
common/asshelp.h
common/audit.c
common/audit.h
common/call-gpg.c [moved from g13/call-gpg.c with 67% similarity]
common/call-gpg.h [moved from g13/call-gpg.h with 63% similarity]
common/convert.c
common/dotlock.c
common/exechelp-posix.c
common/exechelp-w32.c
common/exechelp-w32ce.c
common/exechelp.h
common/helpfile.c
common/i18n.h
common/iobuf.c
common/iobuf.h
common/localename.c
common/logging.c
common/mkdir_p.c
common/mkdir_p.h
common/openpgp-oid.c
common/session-env.c
common/sexputil.c
common/srv.c [deleted file]
common/status.h
common/stringhelp.c
common/stringhelp.h
common/strlist.c
common/strlist.h
common/sysutils.c
common/t-sexputil.c
common/t-stringhelp.c
common/t-strlist.c [new file with mode: 0644]
common/t-support.h
common/t-zb32.c
common/ttyio.c
common/userids.c
common/util.h
common/w32-afunix.h
common/zb32.h [moved from common/srv.h with 57% similarity]
configure.ac
dirmngr/Makefile.am
dirmngr/cdblib.c
dirmngr/certcache.c
dirmngr/crlcache.c
dirmngr/crlfetch.c
dirmngr/dirmngr-client.c
dirmngr/dirmngr.c
dirmngr/dirmngr.h
dirmngr/dirmngr_ldap.c
dirmngr/dns-cert.c [deleted file]
dirmngr/dns-cert.h [deleted file]
dirmngr/dns-stuff.c [new file with mode: 0644]
dirmngr/dns-stuff.h [new file with mode: 0644]
dirmngr/http.c [moved from common/http.c with 90% similarity]
dirmngr/http.h [moved from common/http.h with 99% similarity]
dirmngr/ks-engine-hkp.c
dirmngr/ks-engine-ldap.c
dirmngr/ks-engine.h
dirmngr/ldap-wrapper.c
dirmngr/ldap.c
dirmngr/misc.c
dirmngr/ocsp.c
dirmngr/server.c
dirmngr/t-dns-cert.c [deleted file]
dirmngr/t-dns-stuff.c [new file with mode: 0644]
dirmngr/t-http.c [moved from common/t-http.c with 97% similarity]
dirmngr/tls-ca.pem [moved from common/tls-ca.pem with 100% similarity]
dirmngr/validate.c
doc/DETAILS
doc/HACKING
doc/Makefile.am
doc/dirmngr.texi
doc/gnupg.texi
doc/gpg.texi
doc/gpgv.texi
doc/tools.texi
doc/yat2m.c
g10/Makefile.am
g10/call-agent.c
g10/call-agent.h
g10/call-dirmngr.c
g10/card-util.c
g10/decrypt-data.c
g10/delkey.c
g10/dirmngr-conf.skel
g10/encrypt.c
g10/export.c
g10/getkey.c
g10/gpg.c
g10/gpg.h
g10/gpgv.c
g10/import.c
g10/keydb.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/keyring.c
g10/keyring.h
g10/keyserver.c
g10/main.h
g10/mainproc.c
g10/misc.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/pkclist.c
g10/pkglue.c
g10/plaintext.c
g10/pubkey-enc.c
g10/revoke.c
g10/server.c
g10/sig-check.c
g10/sign.c
g10/skclist.c
g10/sqlite.c [new file with mode: 0644]
g10/sqlite.h [new file with mode: 0644]
g10/t-keydb-get-keyblock.c [new file with mode: 0644]
g10/t-keydb-get-keyblock.gpg [new file with mode: 0644]
g10/t-keydb.c
g10/tdbio.c
g10/test-stubs.c
g10/tofu.c [new file with mode: 0644]
g10/tofu.h [new file with mode: 0644]
g10/trust.c
g10/trustdb.c
g10/trustdb.h
g13/Makefile.am
g13/create.c
g13/g13-common.h
g13/g13.c
g13/mount.c
g13/mountinfo.c
kbx/keybox-blob.c
kbx/keybox-file.c
kbx/keybox-init.c
kbx/keybox-search-desc.h
kbx/keybox-search.c
kbx/keybox-update.c
po/POTFILES.in
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/apdu.c
scd/apdu.h
scd/app-common.h
scd/app-openpgp.c
scd/app-p15.c
scd/app.c
scd/ccid-driver.c
scd/ccid-driver.h
scd/command.c
scd/iso7816.c
scd/scdaemon.c
sm/base64.c
sm/call-agent.c
sm/call-dirmngr.c
sm/certchain.c
sm/certdump.c
sm/certreqgen.c
sm/gpgsm.c
sm/import.c
sm/keydb.c
sm/minip12.c
sm/qualified.c
sm/server.c
tests/openpgp/Makefile.am
tests/openpgp/conventional-mdc.test
tests/openpgp/gpgtar.test [new file with mode: 0755]
tests/openpgp/privkeys/00FE67F28A52A8AA08FFAED20AF832DA916D1985.asc [new file with mode: 0644]
tests/openpgp/privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc [new file with mode: 0644]
tests/openpgp/privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc [new file with mode: 0644]
tests/openpgp/privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc [new file with mode: 0644]
tests/openpgp/privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc [new file with mode: 0644]
tests/openpgp/samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc [new file with mode: 0644]
tests/openpgp/samplekeys/README
tests/openpgp/tofu-2183839A-1.txt [new file with mode: 0644]
tests/openpgp/tofu-BC15C85A-1.txt [new file with mode: 0644]
tests/openpgp/tofu-EE37CF96-1.txt [new file with mode: 0644]
tests/openpgp/tofu-keys-secret.asc [new file with mode: 0755]
tests/openpgp/tofu-keys.asc [new file with mode: 0755]
tests/openpgp/tofu.test [new file with mode: 0755]
tests/openpgp/use-exact-key.test [new file with mode: 0755]
tests/openpgp/version.test
tools/Makefile.am
tools/gpg-check-pattern.c
tools/gpg-zip.in
tools/gpgconf-comp.c
tools/gpgkey2ssh.c
tools/gpgparsemail.c
tools/gpgtar-create.c
tools/gpgtar-extract.c
tools/gpgtar-list.c
tools/gpgtar.c
tools/gpgtar.h
tools/rfc822parse.c
tools/symcryptrun.c

index 0613545..8e213f3 100644 (file)
@@ -19,7 +19,7 @@
 ## Process this file with automake to produce Makefile.in
 
 ACLOCAL_AMFLAGS = -I m4
-DISTCHECK_CONFIGURE_FLAGS = --enable-symcryptrun --enable-mailto --enable-gpgtar
+DISTCHECK_CONFIGURE_FLAGS = --enable-symcryptrun --enable-mailto --enable-g13
 
 GITLOG_TO_CHANGELOG=gitlog-to-changelog
 
diff --git a/NEWS b/NEWS
index b502b78..4965652 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,61 @@
+Noteworthy changes in version 2.1.10 (2015-12-04)
+-------------------------------------------------
+
+ * gpg: New trust models "tofu" and "tofu+pgp".
+
+ * gpg: New command --tofu-policy.  New options --tofu-default-policy
+   and --tofu-db-format.
+
+ * gpg: New option --weak-digest to specify hash algorithms which
+   should be considered weak.
+
+ * gpg: Allow the use of multiple --default-key options; take the last
+   available key.
+
+ * gpg: New option --encrypt-to-default-key.
+
+ * gpg: New option --unwrap to only strip the encryption layer.
+
+ * gpg: New option --only-sign-text-ids to exclude photo IDs from key
+   signing.
+
+ * gpg: Check for ambigious or non-matching key specification in the
+   config file or given to --encrypt-to.
+
+ * gpg: Show the used card reader with --card-status.
+
+ * gpg: Print export statistics and an EXPORTED status line.
+
+ * gpg: Allow selecting subkeys by keyid in --edit-key.
+
+ * gpg: Allow updating the expiration time of multiple subkeys at
+   once.
+
+ * dirmngr: New option --use-tor.  For full support this requires
+   libassuan version 2.4.2 and a patched version of libadns
+   (e.g. adns-1.4-g10-7 as used by the standard Windows installer).
+
+ * dirmngr: New option --nameserver to specify the nameserver used in
+   Tor mode.
+
+ * dirmngr: Keyservers may again be specified by IP address.
+
+ * dirmngr: Fixed problems in resolving keyserver pools.
+
+ * dirmngr: Fixed handling of premature termination of TLS streams so
+   that large numbers of keys can be refreshed via hkps.
+
+ * gpg: Fixed a regression in --locate-key [since 2.1.9].
+
+ * gpg: Fixed another bug for keyrings with legacy keys.
+
+ * gpgsm: Allow combinations of usage flags in --gen-key.
+
+ * Make tilde expansion work with most options.
+
+ * Many other cleanups and bug fixes.
+
+
 Noteworthy changes in version 2.1.9 (2015-10-09)
 ------------------------------------------------
 
diff --git a/README b/README
index 6ad3e51..f1215ef 100644 (file)
--- a/README
+++ b/README
   "https://gnupg.org/faq/whats-new-in-2.1.html" .
 
   The primary WWW page is "https://www.gnupg.org"
-             or using TOR "http://ic6au7wa3f6naxjq.onion"
+             or using Tor "http://ic6au7wa3f6naxjq.onion"
   The primary FTP site is "ftp://ftp.gnupg.org/gcrypt/"
 
   See [[https://gnupg.org/download/mirrors.html]] for a list of
index f56be1f..d32d69c 100644 (file)
        to the control struct so that they are per connection.
        * gpg-agent.c (agent_init_default_ctrl): New.
        (main): Assign those command line options to new default_* variables.
-       Reset DISPLAY in server mode so that tehre is no implicit default.
+       Reset DISPLAY in server mode so that there is no implicit default.
        * command.c (start_command_handler): Initialize and deinitialize
        the control values.
        (option_handler): Work on the ctrl values and not on the opt.
index 49402e4..3fffd2d 100644 (file)
@@ -167,7 +167,7 @@ new_data (const char *string, struct secret_data_s **r_data)
 
   /* We pad the data to 32 bytes so that it get more complicated
      finding something out by watching allocation patterns.  This is
-     usally not possible but we better assume nothing about our secure
+     usually not possible but we better assume nothing about our secure
      storage provider.  To support the AESWRAP mode we need to add 8
      extra bytes as well. */
   total = (length + 8) + 32 - ((length+8) % 32);
index ada477a..33e3ec3 100644 (file)
@@ -226,7 +226,7 @@ getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
 }
 
 /* Fork off the pin entry if this has not already been done.  Note,
-   that this function must always be used to aquire the lock for the
+   that this function must always be used to acquire the lock for the
    pinentry - we will serialize _all_ pinentry calls.
  */
 static gpg_error_t
@@ -717,6 +717,8 @@ setup_qualitybar (ctrl_t ctrl)
   char *tmpstr, *tmpstr2;
   const char *tooltip;
 
+  (void)ctrl;
+
   /* TRANSLATORS: This string is displayed by Pinentry as the label
      for the quality bar.  */
   tmpstr = try_percent_escape (L_("Quality:"), "\t\r\n\f\v");
index 65b5e7c..9c4d7b1 100644 (file)
@@ -189,7 +189,7 @@ atfork_cb (void *opaque, int where)
 /* Fork off the SCdaemon if this has not already been done.  Lock the
    daemon and make sure that a proper context has been setup in CTRL.
    This function might also lock the daemon, which means that the
-   caller must call unlock_scd after this fucntion has returned
+   caller must call unlock_scd after this function has returned
    success and the actual Assuan transaction been done. */
 static int
 start_scd (ctrl_t ctrl)
index 6144ae1..5f159f1 100644 (file)
@@ -3569,7 +3569,7 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
  out:
 
   if (err && es_feof (stream_sock))
-    log_error ("error occured while processing request: %s\n",
+    log_error ("error occurred while processing request: %s\n",
               gpg_strerror (err));
 
   if (send_err)
index f09a2ff..4b6040a 100644 (file)
@@ -1978,7 +1978,7 @@ static const char hlp_keywrap_key[] =
   "mechanism or not used at all if the key is a pre-shared key.  In any\n"
   "case wrapping the import and export of keys is a requirement for\n"
   "certain cryptographic validations and thus useful.  The key persists\n"
-  "a RESET command but may be cleared using the option --clear.\n"
+  "until a RESET command but may be cleared using the option --clear.\n"
   "\n"
   "Supported modes are:\n"
   "  --import  - Return a key to import a key into gpg-agent\n"
@@ -2585,7 +2585,7 @@ static const char hlp_putval[] =
   "\n"
   "KEY is an an arbitrary symbol with the same syntax rules as keys\n"
   "for shell environment variables.  PERCENT_ESCAPED_VALUE is the\n"
-  "corresponsing value; they should be similar to the values of\n"
+  "corresponding value; they should be similar to the values of\n"
   "envronment variables but gpg-agent does not enforce any\n"
   "restrictions.  If that value is not given any value under that KEY\n"
   "is removed from this special environment.";
index a2da9e7..5d3b1ef 100644 (file)
@@ -224,7 +224,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
     log_debug ("pin_cb called without proper PIN info hack\n");
 
   /* If BUF has been passed as NULL, we are in pinpad mode: The
-     callback opens the popup and immediatley returns. */
+     callback opens the popup and immediately returns. */
   if (!buf)
     {
       if (maxbuf == 0) /* Close the pinentry. */
index af61e7e..c5e7ae7 100644 (file)
@@ -1219,7 +1219,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
 
 \f
 /* Delete the key with GRIP from the disk after having asked for
-   confirmation using DESC_TEXT.  If FORCE is set the fucntion won't
+   confirmation using DESC_TEXT.  If FORCE is set the function won't
    require a confirmation via Pinentry or warns if the key is also
    used by ssh.
 
index b780c50..2eec974 100644 (file)
@@ -221,7 +221,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
 
   /* Now check the constraints and collect the error messages unless
      in in silent mode which returns immediately.  */
-  if (utf8_charcount (pw) < minlen )
+  if (utf8_charcount (pw, -1) < minlen )
     {
       if (!failed_constraint)
         {
index f81a2fb..b60287d 100644 (file)
@@ -1178,7 +1178,9 @@ main (int argc, char **argv )
       gnupg_fd_t fd_extra = GNUPG_INVALID_FD;
       gnupg_fd_t fd_browser = GNUPG_INVALID_FD;
       gnupg_fd_t fd_ssh = GNUPG_INVALID_FD;
+#ifndef HAVE_W32_SYSTEM
       pid_t pid;
+#endif
 
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
@@ -1237,7 +1239,6 @@ main (int argc, char **argv )
 #ifdef HAVE_W32_SYSTEM
       (void)csh_style;
       (void)nodetach;
-      pid = getpid ();
 #else /*!HAVE_W32_SYSTEM*/
       pid = fork ();
       if (pid == (pid_t)-1)
@@ -1485,7 +1486,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
 
 /* Because the ssh protocol does not send us information about the
    current TTY setting, we use this function to use those from startup
-   or those explictly set.  This is also used for the restricted mode
+   or those explicitly set.  This is also used for the restricted mode
    where we ignore requests to change the environment.  */
 gpg_error_t
 agent_copy_startup_env (ctrl_t ctrl)
@@ -1681,17 +1682,12 @@ create_server_socket (char *name, int primary, int cygwin,
       agent_exit (2);
     }
 
-#if ASSUAN_VERSION_NUMBER >= 0x020300 /* >= 2.3.0 */
   if (cygwin)
     assuan_sock_set_flag (fd, "cygwin", 1);
-#else
-  (void)cygwin;
-#endif
 
   unaddr = xmalloc (sizeof *unaddr);
   addr = (struct sockaddr*)unaddr;
 
-#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
   {
     int redirected;
 
@@ -1712,17 +1708,6 @@ create_server_socket (char *name, int primary, int cygwin,
           log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
       }
   }
-#else /* Assuan < 2.1.4 */
-  memset (unaddr, 0, sizeof *unaddr);
-  unaddr->sun_family = AF_UNIX;
-  if (strlen (name) + 1 >= sizeof (unaddr->sun_path))
-    {
-      log_error (_("socket name '%s' is too long\n"), name);
-      *name = 0; /* Inhibit removal of the socket by cleanup(). */
-      agent_exit (2);
-    }
-  strcpy (unaddr->sun_path, name);
-#endif /* Assuan < 2.1.4 */
 
   len = SUN_LEN (unaddr);
   rc = assuan_sock_bind (fd, addr, len);
index 175ebe4..af5f645 100644 (file)
@@ -398,7 +398,7 @@ static gpg_error_t
 istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
                     int already_locked)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   int locked = already_locked;
   trustitem_t *ti;
   size_t len;
index 5ccbb5e..d907fe5 100644 (file)
@@ -258,7 +258,7 @@ handle_taskbar (void *ctx)
 
 /* This function initializes the Window system and sets up the taskbar
    icon.  We only have very limited GUI support just to give the
-   taskbar icon a little bit of life.  This fucntion is called once to
+   taskbar icon a little bit of life.  This function is called once to
    fire up the icon.  */
 int
 w32_setup_taskbar (void)
index 7effd56..3fe24ea 100755 (executable)
@@ -311,6 +311,7 @@ if [ "$myhost" = "w32" ]; then
     $tsdir/configure --enable-maintainer-mode ${SILENT} \
              --prefix=${w32root}  \
              --host=${host} --build=${build} SYSROOT=${w32root} \
+             PKG_CONFIG_LIBDIR=${w32root} \
              ${configure_opts} ${extraoptions} "$@"
     rc=$?
     exit $rc
index 19babb9..cb73e91 100644 (file)
@@ -606,6 +606,8 @@ Section "GnuPG" SEC_gnupg
 
   SetOutPath "$INSTDIR\share\gnupg"
   File "share/gnupg/gpg-conf.skel"
+  File "share/gnupg/dirmngr-conf.skel"
+  File "share/gnupg/distsigkey.gpg"
 SectionEnd
 
 
@@ -908,6 +910,7 @@ Section "-un.gnupglast"
   no_uiserver:
   ifFileExists "$INSTDIR\bin\gpgconf.exe"  0 no_gpgconf
     ExecWait '"$INSTDIR\bin\gpgconf" --kill gpg-agent'
+    ExecWait '"$INSTDIR\bin\gpgconf" --kill dirmngr'
   no_gpgconf:
 SectionEnd
 
index 7fed0a7..4b95b35 100644 (file)
        (SPWQ_NO_PIN_ENTRY): New.
        * simple-pwquery.c (simple_pw_set_socket): New.
        (agent_open): Use it if GPG_AGENT_INFO is not set.
-       (simple_pwquery): Extended to allow returning of otehyr error codes.
+       (simple_pwquery): Extended to allow returning of other error codes.
 
        * util.h (GNUPG_MODULE_NAME_AGENT, GNUPG_MODULE_NAME_PINENTRY)
        (GNUPG_MODULE_NAME_SCDAEMON, GNUPG_MODULE_NAME_DIRMNGR)
index 7c87fa9..c02c60e 100644 (file)
 
 EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk ChangeLog-2011 \
              audit-events.h status-codes.h ChangeLog.jnlib \
-            ChangeLog-2011.include w32info-rc.h.in gnupg.ico tls-ca.pem
+            ChangeLog-2011.include w32info-rc.h.in gnupg.ico
 
-noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a \
-                   libcommontls.a libcommontlsnpth.a
+noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a
 if !HAVE_W32CE_SYSTEM
 noinst_LIBRARIES += libsimple-pwquery.a
 endif
@@ -65,7 +64,7 @@ common_sources = \
        homedir.c \
        gettime.c gettime.h \
        yesno.c \
-       b64enc.c b64dec.c zb32.c \
+       b64enc.c b64dec.c zb32.c zb32.h \
        convert.c \
        percent.c \
        mbox-util.c mbox-util.h \
@@ -79,7 +78,6 @@ common_sources = \
        exechelp.h \
        signal.c \
        audit.c audit.h \
-       srv.h \
        localename.c \
        session-env.c session-env.h \
        userids.c userids.h \
@@ -87,18 +85,14 @@ common_sources = \
        ssh-utils.c ssh-utils.h \
        agent-opt.c \
        helpfile.c \
-       mkdir_p.c mkdir_p.h
+       mkdir_p.c mkdir_p.h \
+       strlist.c strlist.h \
+       call-gpg.c call-gpg.h
 
 if HAVE_W32_SYSTEM
 common_sources += w32-reg.c w32-afunix.c w32-afunix.h
 endif
 
-# Sources possible requiring a TLS library are put into a separate
-# conveince library.
-tls_sources = \
-       http.c http.h
-
-
 # To make the code easier to read we have split home some code into
 # separate source files.
 if HAVE_W32_SYSTEM
@@ -117,23 +111,11 @@ without_npth_sources = \
 
 
 libcommon_a_SOURCES = $(common_sources) $(without_npth_sources)
-if USE_DNS_SRV
-libcommon_a_SOURCES += srv.c
-endif
 libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_NPTH=1
 
 libcommonpth_a_SOURCES = $(common_sources)
-if USE_DNS_SRV
-libcommonpth_a_SOURCES += srv.c
-endif
 libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
 
-libcommontls_a_SOURCES = $(tls_sources)
-libcommontls_a_CFLAGS = $(AM_CFLAGS) $(LIBGNUTLS_CFLAGS) -DWITHOUT_NPTH=1
-
-libcommontlsnpth_a_SOURCES = $(tls_sources)
-libcommontlsnpth_a_CFLAGS = $(AM_CFLAGS) $(LIBGNUTLS_CFLAGS) $(NPTH_CFLAGS)
-
 if !HAVE_W32CE_SYSTEM
 libsimple_pwquery_a_SOURCES = \
        simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
@@ -170,7 +152,7 @@ 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-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -179,7 +161,7 @@ module_tests += t-w32-reg
 endif
 
 if MAINTAINER_MODE
-module_maint_tests = t-helpfile t-b64 t-http
+module_maint_tests = t-helpfile t-b64
 else
 module_maint_tests =
 endif
@@ -212,9 +194,13 @@ t_session_env_LDADD = $(t_common_ldadd)
 t_openpgp_oid_LDADD = $(t_common_ldadd)
 t_ssh_utils_LDADD = $(t_common_ldadd)
 t_mapstrings_LDADD = $(t_common_ldadd)
+
+t_zb32_SOURCES = t-zb32.c $(t_extra_src)
 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)
 
 # System specific test
 if HAVE_W32_SYSTEM
@@ -222,11 +208,5 @@ t_w32_reg_SOURCES = t-w32-reg.c $(t_extra_src)
 t_w32_reg_LDADD   = $(t_common_ldadd)
 endif
 
-# http tests
-t_http_SOURCES = t-http.c
-t_http_CFLAGS  = $(t_common_cflags) $(NTBTLS_CFLAGS) $(LIBGNUTLS_CFLAGS)
-t_http_LDADD   = libcommontls.a $(t_common_ldadd) \
-                $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
-
 # All programs should depend on the created libs.
-$(PROGRAMS) : libcommon.a libcommonpth.a libcommontls.a libcommontlsnpth.a
+$(PROGRAMS) : libcommon.a libcommonpth.a
index 53c20fc..b6abf86 100644 (file)
@@ -851,7 +851,7 @@ find_long_option( ARGPARSE_ARGS *arg,
     /* Would be better if we can do a binary search, but it is not
        possible to reorder our option table because we would mess
        up our help strings - What we can do is: Build a nice option
-       lookup table wehn this function is first invoked */
+       lookup table when this function is first invoked */
     if( !*keyword )
        return -1;
     for(i=0; opts[i].short_opt; i++ )
index 4447607..d33ffb5 100644 (file)
@@ -498,7 +498,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
     }
 
   if (debug && !did_success_msg)
-    log_debug (_("connection to agent established\n"));
+    log_debug ("connection to agent established\n");
 
   err = assuan_transact (ctx, "RESET",
                          NULL, NULL, NULL, NULL, NULL, NULL);
@@ -694,7 +694,7 @@ start_new_dirmngr (assuan_context_t *r_ctx,
     }
 
   if (debug && !did_success_msg)
-    log_debug (_("connection to the dirmngr established\n"));
+    log_debug ("connection to the dirmngr established\n");
 
   *r_ctx = ctx;
   return 0;
index 6a52172..35d2115 100644 (file)
@@ -34,6 +34,7 @@
 #include <gpg-error.h>
 
 #include "session-env.h"
+#include "util.h"
 
 /*-- asshelp.c --*/
 
index 198b8e6..efd5fcd 100644 (file)
@@ -164,7 +164,7 @@ audit_release (audit_ctx_t ctx)
 
 
 /* Set the type for the audit operation.  If CTX is NULL, this is a
-   dummy fucntion.  */
+   dummy function.  */
 void
 audit_set_type (audit_ctx_t ctx, audit_type_t type)
 {
index 345477d..b324a28 100644 (file)
@@ -174,7 +174,7 @@ typedef enum
 
     AUDIT_ROOT_TRUSTED,  /* cert, err */
     /* Tells whether the root certificate is trusted.  This event is
-       emmited durcing chain validation.  */
+       emitted during chain validation.  */
 
     AUDIT_CRL_CHECK, /* err */
     /* Tells the status of a CRL or OCSP check.  */
similarity index 67%
rename from g13/call-gpg.c
rename to common/call-gpg.c
index 0bd935c..cd865ef 100644 (file)
  */
 
 #include <config.h>
-#include <stdio.h>
+
+#include <assert.h>
+#include <assuan.h>
+#include <errno.h>
+#include <npth.h>
 #include <stdlib.h>
+#include <stdio.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 "call-gpg.h"
-#include "utils.h"
-#include "../common/exechelp.h"
-
+#include "exechelp.h"
+#include "i18n.h"
+#include "logging.h"
+#include "membuf.h"
+#include "strlist.h"
+#include "util.h"
 
 \f
 /* Fire up a new GPG.  Handle the server's initial greeting.  Returns
    0 on success and stores the assuan context at R_CTX.  */
 static gpg_error_t
-start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
+start_gpg (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments,
+           int input_fd, int output_fd, assuan_context_t *r_ctx)
 {
   gpg_error_t err;
   assuan_context_t ctx = NULL;
   const char *pgmname;
-  const char *argv[10];
-  int no_close_list[5];
+  const char **argv;
+  assuan_fd_t no_close_list[5];
   int i;
   char line[ASSUAN_LINELENGTH];
 
@@ -60,15 +63,12 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
     }
 
   /* The first time we are used, intialize the gpg_program variable.  */
-  if ( !opt.gpg_program || !*opt.gpg_program )
-    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
-
-  if (opt.verbose)
-    log_info (_("no running gpg - starting '%s'\n"), opt.gpg_program);
+  if ( !gpg_program || !*gpg_program )
+    gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
 
   /* Compute argv[0].  */
-  if ( !(pgmname = strrchr (opt.gpg_program, '/')))
-    pgmname = opt.gpg_program;
+  if ( !(pgmname = strrchr (gpg_program, '/')))
+    pgmname = gpg_program;
   else
     pgmname++;
 
@@ -79,15 +79,17 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
       return err;
     }
 
+  argv = xtrycalloc (strlist_length (gpg_arguments) + 3, sizeof *argv);
+  if (argv == NULL)
+    {
+      err = gpg_error_from_syserror ();
+      return err;
+    }
   i = 0;
   argv[i++] = pgmname;
   argv[i++] = "--server";
-  if ((opt.debug & 1024))
-    argv[i++] = "--debug=1024";
-  argv[i++] = "-z";
-  argv[i++] = "0";
-  argv[i++] = "--trust-model";
-  argv[i++] = "always";
+  for (; gpg_arguments; gpg_arguments = gpg_arguments->next)
+    argv[i++] = gpg_arguments->d;
   argv[i++] = NULL;
 
   i = 0;
@@ -98,10 +100,10 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
     no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
   if (output_fd != -1)
     no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
-  no_close_list[i] = -1;
+  no_close_list[i] = ASSUAN_INVALID_FD;
 
   /* Connect to GPG and perform initial handshaking.  */
-  err = assuan_pipe_connect (ctx, opt.gpg_program, argv, no_close_list,
+  err = assuan_pipe_connect (ctx, gpg_program, argv, no_close_list,
                             NULL, NULL, 0);
   if (err)
     {
@@ -135,9 +137,6 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
     }
 
   *r_ctx = ctx;
-
-  if (DBG_IPC)
-    log_debug ("connection to GPG established\n");
   return 0;
 }
 
@@ -157,6 +156,7 @@ struct writer_thread_parms
   int fd;
   const void *data;
   size_t datalen;
+  estream_t stream;
   gpg_error_t *err_addr;
 };
 
@@ -165,9 +165,27 @@ struct writer_thread_parms
 static void *
 writer_thread_main (void *arg)
 {
+  gpg_error_t err = 0;
   struct writer_thread_parms *parm = arg;
-  const char *buffer = parm->data;
-  size_t length = parm->datalen;
+  char _buffer[4096];
+  char *buffer;
+  size_t length;
+
+  if (parm->stream)
+    {
+      buffer = _buffer;
+      err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+      if (err)
+        {
+          log_error ("reading stream failed: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    {
+      buffer = (char *) parm->data;
+      length = parm->datalen;
+    }
 
   while (length)
     {
@@ -178,13 +196,33 @@ writer_thread_main (void *arg)
         {
           if (errno == EINTR)
             continue;
-          *parm->err_addr = gpg_error_from_syserror ();
+          err = gpg_error_from_syserror ();
           break; /* Write error.  */
         }
       length -= nwritten;
-      buffer += nwritten;
+
+      if (parm->stream)
+        {
+          if (length == 0)
+            {
+              err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+              if (err)
+                {
+                  log_error ("reading stream failed: %s\n",
+                             gpg_strerror (err));
+                  break;
+                }
+              if (length == 0)
+                /* We're done.  */
+                break;
+            }
+        }
+      else
+        buffer += nwritten;
     }
 
+ leave:
+  *parm->err_addr = err;
   if (close (parm->fd))
     log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
   xfree (parm);
@@ -198,7 +236,7 @@ writer_thread_main (void *arg)
    variable to receive a possible write error after the thread has
    finished.  */
 static gpg_error_t
-start_writer (int fd, const void *data, size_t datalen,
+start_writer (int fd, const void *data, size_t datalen, estream_t stream,
               npth_t *r_thread, gpg_error_t *err_addr)
 {
   gpg_error_t err;
@@ -216,6 +254,7 @@ start_writer (int fd, const void *data, size_t datalen,
   parm->fd = fd;
   parm->data = data;
   parm->datalen = datalen;
+  parm->stream = stream;
   parm->err_addr = err_addr;
 
   npth_attr_init (&tattr);
@@ -245,6 +284,7 @@ struct reader_thread_parms
 {
   int fd;
   membuf_t *mb;
+  estream_t stream;
   gpg_error_t *err_addr;
 };
 
@@ -253,6 +293,7 @@ struct reader_thread_parms
 static void *
 reader_thread_main (void *arg)
 {
+  gpg_error_t err = 0;
   struct reader_thread_parms *parm = arg;
   char buffer[4096];
   int nread;
@@ -263,13 +304,33 @@ reader_thread_main (void *arg)
         {
           if (errno == EINTR)
             continue;
-          *parm->err_addr = gpg_error_from_syserror ();
+          err = gpg_error_from_syserror ();
           break;  /* Read error.  */
         }
 
-      put_membuf (parm->mb, buffer, nread);
+      if (parm->stream)
+        {
+          const char *p = buffer;
+          size_t nwritten;
+          while (nread)
+            {
+              err = es_write (parm->stream, p, nread, &nwritten);
+              if (err)
+                {
+                  log_error ("writing stream failed: %s\n",
+                             gpg_strerror (err));
+                  goto leave;
+                }
+              nread -= nwritten;
+              p += nwritten;
+            }
+        }
+      else
+        put_membuf (parm->mb, buffer, nread);
     }
 
+ leave:
+  *parm->err_addr = err;
   if (close (parm->fd))
     log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
   xfree (parm);
@@ -282,7 +343,8 @@ reader_thread_main (void *arg)
    is stored at R_TID.  After the thread has finished an error from
    the thread will be stored at ERR_ADDR.  */
 static gpg_error_t
-start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
+start_reader (int fd, membuf_t *mb, estream_t stream,
+              npth_t *r_thread, gpg_error_t *err_addr)
 {
   gpg_error_t err;
   struct reader_thread_parms *parm;
@@ -298,6 +360,7 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
     return gpg_error_from_syserror ();
   parm->fd = fd;
   parm->mb = mb;
+  parm->stream = stream;
   parm->err_addr = err_addr;
 
   npth_attr_init (&tattr);
@@ -327,9 +390,15 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
 
 
  */
-gpg_error_t
-gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
-                  strlist_t keys, void **r_ciph, size_t *r_ciphlen)
+static gpg_error_t
+_gpg_encrypt (ctrl_t ctrl,
+              const char *gpg_program,
+              strlist_t gpg_arguments,
+              const void *plain, size_t plainlen,
+              estream_t plain_stream,
+              strlist_t keys,
+              membuf_t *reader_mb,
+              estream_t cipher_stream)
 {
   gpg_error_t err;
   assuan_context_t ctx = NULL;
@@ -338,16 +407,14 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
   npth_t writer_thread = (npth_t)0;
   npth_t reader_thread = (npth_t)0;
   gpg_error_t writer_err, reader_err;
-  membuf_t reader_mb;
   char line[ASSUAN_LINELENGTH];
   strlist_t sl;
   int ret;
 
-  *r_ciph = NULL;
-  *r_ciphlen = 0;
-
-  /* Init the memory buffer to receive the encrypted stuff.  */
-  init_membuf (&reader_mb, 4096);
+  /* Make sure that either the stream interface xor the buffer
+     interface is used.  */
+  assert ((plain == NULL) != (plain_stream == NULL));
+  assert ((reader_mb == NULL) != (cipher_stream == NULL));
 
   /* Create two pipes.  */
   err = gnupg_create_outbound_pipe (outbound_fds);
@@ -360,14 +427,15 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
     }
 
   /* Start GPG and send the INPUT and OUTPUT commands.  */
-  err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
+  err = start_gpg (ctrl, gpg_program, gpg_arguments,
+                   outbound_fds[0], inbound_fds[1], &ctx);
   if (err)
     goto leave;
   close (outbound_fds[0]); outbound_fds[0] = -1;
   close (inbound_fds[1]); inbound_fds[1] = -1;
 
   /* Start a writer thread to feed the INPUT command of the server.  */
-  err = start_writer (outbound_fds[1], plain, plainlen,
+  err = start_writer (outbound_fds[1], plain, plainlen, plain_stream,
                       &writer_thread, &writer_err);
   if (err)
     return err;
@@ -375,7 +443,7 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
 
   /* Start a reader thread to eat from the OUTPUT command of the
      server.  */
-  err = start_reader (inbound_fds[0], &reader_mb,
+  err = start_reader (inbound_fds[0], reader_mb, cipher_stream,
                       &reader_thread, &reader_err);
   if (err)
     return err;
@@ -435,16 +503,6 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
       goto leave;
     }
 
-  /* Return the data.  */
-  *r_ciph = get_membuf (&reader_mb, r_ciphlen);
-  if (!*r_ciph)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error while storing the data in the reader thread: %s\n",
-                 gpg_strerror (err));
-      goto leave;
-    }
-
  leave:
   /* FIXME: Not valid, as npth_t is an opaque type.  */
   if (reader_thread)
@@ -460,19 +518,73 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
   if (inbound_fds[1] != -1)
     close (inbound_fds[1]);
   release_gpg (ctx);
-  xfree (get_membuf (&reader_mb, NULL));
   return err;
 }
 
+gpg_error_t
+gpg_encrypt_blob (ctrl_t ctrl,
+                  const char *gpg_program,
+                  strlist_t gpg_arguments,
+                  const void *plain, size_t plainlen,
+                  strlist_t keys,
+                  void **r_ciph, size_t *r_ciphlen)
+{
+  gpg_error_t err;
+  membuf_t reader_mb;
+
+  *r_ciph = NULL;
+  *r_ciphlen = 0;
+
+  /* Init the memory buffer to receive the encrypted stuff.  */
+  init_membuf (&reader_mb, 4096);
+
+  err = _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
+                      plain, plainlen, NULL,
+                      keys,
+                      &reader_mb, NULL);
+
+  if (! err)
+    {
+      /* Return the data.  */
+      *r_ciph = get_membuf (&reader_mb, r_ciphlen);
+      if (!*r_ciph)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error while storing the data in the reader thread: %s\n",
+                     gpg_strerror (err));
+        }
+    }
+
+  xfree (get_membuf (&reader_mb, NULL));
+  return err;
+}
 
+gpg_error_t
+gpg_encrypt_stream (ctrl_t ctrl,
+                    const char *gpg_program,
+                    strlist_t gpg_arguments,
+                    estream_t plain_stream,
+                    strlist_t keys,
+                    estream_t cipher_stream)
+{
+  return _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
+                       NULL, 0, plain_stream,
+                       keys,
+                       NULL, cipher_stream);
+}
 \f
 /* Call GPG to decrypt a block of data.
 
 
  */
-gpg_error_t
-gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
-                  void **r_plain, size_t *r_plainlen)
+static gpg_error_t
+_gpg_decrypt (ctrl_t ctrl,
+              const char *gpg_program,
+              strlist_t gpg_arguments,
+              const void *ciph, size_t ciphlen,
+              estream_t cipher_stream,
+              membuf_t *reader_mb,
+              estream_t plain_stream)
 {
   gpg_error_t err;
   assuan_context_t ctx = NULL;
@@ -481,14 +593,12 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
   npth_t writer_thread = (npth_t)0;
   npth_t reader_thread = (npth_t)0;
   gpg_error_t writer_err, reader_err;
-  membuf_t reader_mb;
   int ret;
 
-  *r_plain = NULL;
-  *r_plainlen = 0;
-
-  /* Init the memory buffer to receive the encrypted stuff.  */
-  init_membuf_secure (&reader_mb, 1024);
+  /* Make sure that either the stream interface xor the buffer
+     interface is used.  */
+  assert ((ciph == NULL) != (cipher_stream == NULL));
+  assert ((reader_mb == NULL) != (plain_stream == NULL));
 
   /* Create two pipes.  */
   err = gnupg_create_outbound_pipe (outbound_fds);
@@ -501,14 +611,15 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
     }
 
   /* Start GPG and send the INPUT and OUTPUT commands.  */
-  err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
+  err = start_gpg (ctrl, gpg_program, gpg_arguments,
+                   outbound_fds[0], inbound_fds[1], &ctx);
   if (err)
     goto leave;
   close (outbound_fds[0]); outbound_fds[0] = -1;
   close (inbound_fds[1]); inbound_fds[1] = -1;
 
   /* Start a writer thread to feed the INPUT command of the server.  */
-  err = start_writer (outbound_fds[1], ciph, ciphlen,
+  err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream,
                       &writer_thread, &writer_err);
   if (err)
     return err;
@@ -516,7 +627,7 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
 
   /* Start a reader thread to eat from the OUTPUT command of the
      server.  */
-  err = start_reader (inbound_fds[0], &reader_mb,
+  err = start_reader (inbound_fds[0], reader_mb, plain_stream,
                       &reader_thread, &reader_err);
   if (err)
     return err;
@@ -563,16 +674,6 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
       goto leave;
     }
 
-  /* Return the data.  */
-  *r_plain = get_membuf (&reader_mb, r_plainlen);
-  if (!*r_plain)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error while storing the data in the reader thread: %s\n",
-                 gpg_strerror (err));
-      goto leave;
-    }
-
  leave:
   if (reader_thread)
     npth_detach (reader_thread);
@@ -587,6 +688,53 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
   if (inbound_fds[1] != -1)
     close (inbound_fds[1]);
   release_gpg (ctx);
+  return err;
+}
+
+gpg_error_t
+gpg_decrypt_blob (ctrl_t ctrl,
+                  const char *gpg_program,
+                  strlist_t gpg_arguments,
+                  const void *ciph, size_t ciphlen,
+                  void **r_plain, size_t *r_plainlen)
+{
+  gpg_error_t err;
+  membuf_t reader_mb;
+
+  *r_plain = NULL;
+  *r_plainlen = 0;
+
+  /* Init the memory buffer to receive the encrypted stuff.  */
+  init_membuf_secure (&reader_mb, 1024);
+
+  err = _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
+                      ciph, ciphlen, NULL,
+                      &reader_mb, NULL);
+
+  if (! err)
+    {
+      /* Return the data.  */
+      *r_plain = get_membuf (&reader_mb, r_plainlen);
+      if (!*r_plain)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error while storing the data in the reader thread: %s\n",
+                     gpg_strerror (err));
+        }
+    }
+
   xfree (get_membuf (&reader_mb, NULL));
   return err;
 }
+
+gpg_error_t
+gpg_decrypt_stream (ctrl_t ctrl,
+                    const char *gpg_program,
+                    strlist_t gpg_arguments,
+                    estream_t cipher_stream,
+                    estream_t plain_stream)
+{
+  return _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
+                       NULL, 0, cipher_stream,
+                       NULL, plain_stream);
+}
similarity index 63%
rename from g13/call-gpg.h
rename to common/call-gpg.h
index 339544d..74d3819 100644 (file)
 #ifndef G13_CALL_GPG_H
 #define G13_CALL_GPG_H
 
+#include <gpg-error.h>
+
+#include "strlist.h"
+
+typedef struct server_control_s *ctrl_t;
+
 gpg_error_t gpg_encrypt_blob (ctrl_t ctrl,
+                             const char *gpg_program,
+                             strlist_t gpg_arguments,
                               const void *plain, size_t plainlen,
                               strlist_t keys,
                               void **r_ciph, size_t *r_ciphlen);
-gpg_error_t gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
-                              void **r_plain, size_t *r_plainlen);
 
+gpg_error_t gpg_encrypt_stream (ctrl_t ctrl,
+                               const char *gpg_program,
+                               strlist_t gpg_arguments,
+                               estream_t plain_stream,
+                               strlist_t keys,
+                               estream_t cipher_stream);
+
+gpg_error_t gpg_decrypt_blob (ctrl_t ctrl,
+                             const char *gpg_program,
+                             strlist_t gpg_arguments,
+                             const void *ciph, size_t ciphlen,
+                              void **r_plain, size_t *r_plainlen);
 
+gpg_error_t gpg_decrypt_stream (ctrl_t ctrl,
+                               const char *gpg_program,
+                               strlist_t gpg_arguments,
+                               estream_t cipher_stream,
+                               estream_t plain_stream);
 
 #endif /*G13_CALL_GPG_H*/
index 6b0ff35..30e5a60 100644 (file)
@@ -70,7 +70,7 @@ hex2bin (const char *string, void *buffer, size_t length)
 /* Convert STRING consisting of hex characters into its binary representation
    and store that at BUFFER.  BUFFER needs to be of LENGTH bytes.  The
    function check that the STRING will convert exactly to LENGTH
-   bytes. Colons inbetween the hex digits are allowed, if one colon
+   bytes. Colons between the hex digits are allowed, if one colon
    has been given a colon is expected very 2 characters. The string
    is delimited by either end of string or a white space character.
    The function returns -1 on error or the length of the parsed
@@ -180,7 +180,7 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
    Nul byte at the end is used to make sure tha the result can always
    be used as a C-string.
 
-   BUFSIZE is the availabe length of BUFFER; if the converted result
+   BUFSIZE is the available length of BUFFER; if the converted result
    plus a possible required extra Nul character does not fit into this
    buffer, the function returns NULL and won't change the existing
    content of BUFFER.  In-place conversion is possible as long as
@@ -190,7 +190,7 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
    does not store anything.  This may be used to find the end of
    HEXSTRING.
 
-   On sucess the function returns a pointer to the next character
+   On success the function returns a pointer to the next character
    after HEXSTRING (which is either end-of-string or a the next white
    space).  If BUFLEN is not NULL the number of valid vytes in BUFFER
    is stored there (an extra Nul byte is not counted); this will even
index bccd0c6..d880859 100644 (file)
@@ -1293,7 +1293,7 @@ dotlock_remove_lockfiles (void)
   dotlock_t h, h2;
 
   /* First set the lockfiles list to NULL so that for example
-     dotlock_release is ware that this fucntion is currently
+     dotlock_release is aware that this function is currently
      running.  */
   LOCK_all_lockfiles ();
   h = all_lockfiles;
index 2bf2592..5706dbe 100644 (file)
@@ -171,7 +171,7 @@ close_all_fds (int first, int *except)
 /* Returns an array with all currently open file descriptors.  The end
    of the array is marked by -1.  The caller needs to release this
    array using the *standard free* and not with xfree.  This allow the
-   use of this fucntion right at startup even before libgcrypt has
+   use of this function right at startup even before libgcrypt has
    been initialized.  Returns NULL on error and sets ERRNO
    accordingly.  */
 int *
index ba3b357..bc9b5b4 100644 (file)
@@ -116,7 +116,7 @@ close_all_fds (int first, int *except)
 /* Returns an array with all currently open file descriptors.  The end
    of the array is marked by -1.  The caller needs to release this
    array using the *standard free* and not with xfree.  This allow the
-   use of this fucntion right at startup even before libgcrypt has
+   use of this function right at startup even before libgcrypt has
    been initialized.  Returns NULL on error and sets ERRNO
    accordingly.  */
 int *
@@ -751,7 +751,7 @@ gnupg_release_process (pid_t pid)
 }
 
 
-/* Spawn a new process and immediatley detach from it.  The name of
+/* Spawn a new process and immediately detach from it.  The name of
    the program to exec is PGMNAME and its arguments are in ARGV (the
    programname is automatically passed as first argument).
    Environment strings in ENVP are set.  An error is returned if
index 975386a..49ccdbb 100644 (file)
@@ -799,7 +799,7 @@ gnupg_release_process (pid_t pid)
 }
 
 
-/* Spawn a new process and immediatley detach from it.  The name of
+/* Spawn a new process and immediately detach from it.  The name of
    the program to exec is PGMNAME and its arguments are in ARGV (the
    programname is automatically passed as first argument).
    Environment strings in ENVP are set.  An error is returned if
index a146d89..9088342 100644 (file)
@@ -46,7 +46,7 @@ void close_all_fds (int first, int *except);
 /* Returns an array with all currently open file descriptors.  The end
    of the array is marked by -1.  The caller needs to release this
    array using the *standard free* and not with xfree.  This allow the
-   use of this fucntion right at startup even before libgcrypt has
+   use of this function right at startup even before libgcrypt has
    been initialized.  Returns NULL on error and sets ERRNO accordingly.  */
 int *get_all_open_fds (void);
 
@@ -168,7 +168,7 @@ void gnupg_kill_process (pid_t pid);
 void gnupg_release_process (pid_t pid);
 
 
-/* Spawn a new process and immediatley detach from it.  The name of
+/* Spawn a new process and immediately detach from it.  The name of
    the program to exec is PGMNAME and its arguments are in ARGV (the
    programname is automatically passed as first argument).
    Environment strings in ENVP are set.  An error is returned if
index faed819..0fb4e02 100644 (file)
@@ -216,7 +216,7 @@ findkey_locale (const char *key, const char *locname,
      /usr/share/gnupg/help.txt
 
    Here LL denotes the two digit language code of the current locale.
-   If ONLY_CURRENT_LOCALE is set, the fucntion won;t fallback to the
+   If ONLY_CURRENT_LOCALE is set, the function won't fallback to the
    english valiant ("help.txt") unless that locale has been requested.
 
    The help file needs to be encoded in UTF-8, lines with a '#' in the
index 45710b2..22e8a90 100644 (file)
@@ -53,7 +53,7 @@ const char *i18n_utf8 (const char *string);
 const char *i18n_localegettext (const char *lc_messages, const char *string)
                                 GNUPG_GCC_ATTR_FORMAT_ARG(2);
 
-/* If a module wants a local L_() fucntion we define it here.  */
+/* If a module wants a local L_() function we define it here.  */
 #ifdef LunderscoreIMPL
 LunderscorePROTO
 LunderscoreIMPL
index 795ff11..e8b4a03 100644 (file)
@@ -267,6 +267,7 @@ direct_open (const char *fname, const char *mode, int mode700)
   unsigned long da, cd, sm;
   HANDLE hfile;
 
+  (void)mode700;
   /* Note, that we do not handle all mode combinations */
 
   /* According to the ReactOS source it seems that open() of the
@@ -1141,7 +1142,7 @@ iobuf_close (iobuf_t a)
                                         a->chain, NULL, &dummy_len)))
        log_error ("IOBUFCTRL_FREE failed on close: %s\n", gpg_strerror (rc));
       if (! rc && rc2)
-       /* Whoops!  An error occured.  Save it in RC if we haven't
+       /* Whoops!  An error occurred.  Save it in RC if we haven't
           already recorded an error.  */
        rc = rc2;
 
@@ -1391,7 +1392,7 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open)
 {
   iobuf_t a;
   file_es_filter_ctx_t *fcx;
-  size_t len;
+  size_t len = 0;
 
   a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
                   IOBUF_BUFFER_SIZE);
@@ -2208,6 +2209,41 @@ iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
   return n;
 }
 
+/* Copies the data from the input iobuf SOURCE to the output iobuf
+   DEST until either an error is encountered or EOF is reached.
+   Returns the number of bytes copies.  */
+size_t
+iobuf_copy (iobuf_t dest, iobuf_t source)
+{
+  char *temp;
+  /* Use a 1 MB buffer.  */
+  const size_t temp_size = 1024 * 1024;
+
+  size_t nread;
+  size_t nwrote = 0;
+  int err;
+
+  assert (source->use == IOBUF_INPUT || source->use == IOBUF_INPUT_TEMP);
+  assert (dest->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
+
+  temp = xmalloc (temp_size);
+  while (1)
+    {
+      nread = iobuf_read (source, temp, temp_size);
+      if (nread == -1)
+        /* EOF.  */
+        break;
+
+      err = iobuf_write (dest, temp, nread);
+      if (err)
+        break;
+      nwrote += nread;
+    }
+  xfree (temp);
+
+  return nwrote;
+}
+
 
 void
 iobuf_flush_temp (iobuf_t temp)
@@ -2236,8 +2272,6 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
 off_t
 iobuf_get_filelength (iobuf_t a, int *overflow)
 {
-  struct stat st;
-
   if (overflow)
     *overflow = 0;
 
@@ -2295,11 +2329,15 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
       }
     log_error ("GetFileSize for handle %p failed: %s\n",
               fp, w32_strerror (0));
-#else
-    if ( !fstat (FD2INT (fp), &st) )
-      return st.st_size;
-    log_error("fstat() failed: %s\n", strerror(errno) );
-#endif
+#else /*!HAVE_W32_SYSTEM*/
+    {
+      struct stat st;
+
+      if ( !fstat (FD2INT (fp), &st) )
+        return st.st_size;
+      log_error("fstat() failed: %s\n", strerror(errno) );
+    }
+#endif /*!HAVE_W32_SYSTEM*/
   }
 
   return 0;
index bce6c31..cb79105 100644 (file)
@@ -426,7 +426,7 @@ int iobuf_push_filter2 (iobuf_t a,
    IOBUF_DEBUG_MODE is not 0.  */
 int iobuf_print_chain (iobuf_t a);
 
-/* Indicate that some error occured on the specified filter.  */
+/* Indicate that some error occurred on the specified filter.  */
 #define iobuf_set_error(a)    do { (a)->error = 1; } while(0)
 
 /* Return any pending error on filter A.  */
@@ -458,7 +458,7 @@ off_t iobuf_tell (iobuf_t a);
      That is, data is appended to the buffer and the seek does not
      cause the size of the buffer to grow.
 
-   If no error occured, then any limit previous set by
+   If no error occurred, then any limit previous set by
    iobuf_set_limit() is cleared.  Further, any error on the filter
    (the file filter or the temp filter) is cleared.
 
@@ -552,6 +552,14 @@ int iobuf_write_temp (iobuf_t dest, iobuf_t source);
    BUFFER.  Returns the number of bytes actually copied.  */
 size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen);
 
+/* Copies the data from the input iobuf SOURCE to the output iobuf
+   DEST until either an error is encountered or EOF is reached.
+   Returns the number of bytes successfully written.  If an error
+   occurred, then any buffered bytes are not returned to SOURCE and are
+   effectively lost.  To check if an error occurred, use
+   iobuf_error.  */
+size_t iobuf_copy (iobuf_t dest, iobuf_t source);
+
 /* Return the size of any underlying file.  This only works with
    file_filter based pipelines.
 
index 54d22d0..876fdb0 100644 (file)
@@ -55,7 +55,7 @@
 
 /* Use a dummy value for LC_MESSAGES in case it is not defined.  This
    works because we always test for HAVE_LC_MESSAGES and the core
-   fucntion takes the category as a string as well.  */
+   function takes the category as a string as well.  */
 #ifndef HAVE_LC_MESSAGES
 #define LC_MESSAGES 0
 #endif
index 2932c3d..b7f1419 100644 (file)
@@ -195,7 +195,7 @@ parse_portno (const char *str, unsigned short *r_port)
 }
 
 
-static ssize_t
+static gpgrt_ssize_t
 fun_writer (void *cookie_arg, const void *buffer, size_t size)
 {
   struct fun_cookie_s *cookie = cookie_arg;
@@ -204,7 +204,7 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
      avoids the ugly mix of fd and estream code.  */
 
   /* Note that we always try to reconnect to the socket but print
-     error messages only the first time an error occured.  If
+     error messages only the first time an error occurred.  If
      RUNNING_DETACHED is set we don't fall back to stderr and even do
      not print any error messages.  This is needed because detached
      processes often close stderr and by writing to file descriptor 2
@@ -391,11 +391,11 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
           DWORD nwritten;
 
           WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL);
-          return (ssize_t)size; /* Okay.  */
+          return (gpgrt_ssize_t)size; /* Okay.  */
         }
 #endif
       if (!writen (cookie->fd, buffer, size, cookie->is_socket))
-        return (ssize_t)size; /* Okay. */
+        return (gpgrt_ssize_t)size; /* Okay. */
     }
 
   if (!running_detached && cookie->fd != -1
@@ -415,7 +415,7 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
       log_socket = -1;
     }
 
-  return (ssize_t)size;
+  return (gpgrt_ssize_t)size;
 }
 
 
index 42469f8..37b44ec 100644 (file)
@@ -41,7 +41,7 @@
 
 
 gpg_error_t
-amkdir_p (char **directory_components)
+gnupg_amkdir_p (const char **directory_components)
 {
   gpg_error_t err = 0;
   int count;
@@ -53,16 +53,21 @@ amkdir_p (char **directory_components)
 
   /* log_debug ("%s: %d directory components.\n", __func__, count); */
 
-  dirs = xtrycalloc (count, sizeof (char *));
+  dirs = xtrycalloc (count, sizeof *dirs);
   if (!dirs)
     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
 
   for (i = 0; directory_components[i]; i ++)
     {
       if (i == 0)
-       dirs[i] = directory_components[i];
+       dirs[i] = make_filename_try (directory_components[i], NULL);
       else
-       dirs[i] = make_filename (dirs[i - 1], directory_components[i], NULL);
+       dirs[i] = make_filename_try (dirs[i-1], directory_components[i], NULL);
+      if (!dirs[i])
+        {
+          err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+          goto out;
+        }
 
       /* log_debug ("%s: Directory %d: `%s'.\n", __func__, i, dirs[i]); */
     }
@@ -127,7 +132,7 @@ amkdir_p (char **directory_components)
     }
 
  out:
-  for (i = 1; i < count; i ++)
+  for (i = 0; i < count; i ++)
     xfree (dirs[i]);
   xfree (dirs);
 
@@ -138,13 +143,13 @@ amkdir_p (char **directory_components)
 
 
 gpg_error_t
-mkdir_p (char *directory_component, ...)
+gnupg_mkdir_p (const char *directory_component, ...)
 {
   va_list ap;
   gpg_error_t err = 0;
   int i;
   int space = 1;
-  char **dirs;
+  const char **dirs;
 
   dirs = xtrymalloc (space * sizeof (char *));
   if (!dirs)
@@ -157,7 +162,7 @@ mkdir_p (char *directory_component, ...)
     {
       if (i == space)
        {
-          char **tmp_dirs;
+          const char **tmp_dirs;
 
          space = 2 * space;
          tmp_dirs = xtryrealloc (dirs, space * sizeof (char *));
@@ -174,7 +179,7 @@ mkdir_p (char *directory_component, ...)
   va_end (ap);
 
   if (!err)
-    err = amkdir_p (dirs);
+    err = gnupg_amkdir_p (dirs);
 
   xfree (dirs);
 
index 0a6cf3d..28f38d1 100644 (file)
@@ -39,7 +39,7 @@
    first try to create the directory "foo/bar" and then the directory
    "foo/bar/xyzzy".  On success returns 0, otherwise an error code is
    returned.  */
-gpg_error_t mkdir_p (char *directory_component, ...) GPGRT_ATTR_SENTINEL(0);
+gpg_error_t gnupg_mkdir_p (const char *directory_component, ...) GPGRT_ATTR_SENTINEL(0);
 
 /* Like mkdir_p, but DIRECTORY_COMPONENTS is a NULL terminated
    array, e.g.:
@@ -47,6 +47,6 @@ gpg_error_t mkdir_p (char *directory_component, ...) GPGRT_ATTR_SENTINEL(0);
      char **dirs = { "foo", "bar", NULL };
      amkdir_p (dirs);
  */
-gpg_error_t amkdir_p (char **directory_components);
+gpg_error_t gnupg_amkdir_p (const char **directory_components);
 
 #endif
index 8a964a4..1b6d5f3 100644 (file)
@@ -390,7 +390,7 @@ curve_supported_p (const char *name)
 
 /* Enumerate available and supported OpenPGP curves.  The caller needs
    to set the integer variable at ITERP to zero and keep on calling
-   this fucntion until NULL is returned.  */
+   this function until NULL is returned.  */
 const char *
 openpgp_enum_curves (int *iterp)
 {
index 171bf8f..8c3dbb5 100644 (file)
@@ -97,7 +97,7 @@ static size_t lastallocatedarraysize;
 
 /* Return the names of standard environment variables one after the
    other.  The caller needs to set the value at the address of
-   ITERATOR initally to 0 and then call this function until it returns
+   ITERATOR initially to 0 and then call this function until it returns
    NULL.  */
 const char *
 session_env_list_stdenvnames (int *iterator, const char **r_assname)
index c24facb..a63fc20 100644 (file)
@@ -335,7 +335,7 @@ hash_algo_from_sigval (const unsigned char *sigval)
   if (sskip (&s, &depth) || depth)
     return 0; /* Invalid S-expression.  */
   if (*s != '(')
-    return 0; /* No futher list.  */
+    return 0; /* No further list.  */
   /* Check whether this is (hash ALGO).  */
   s++;
   n = snext (&s);
diff --git a/common/srv.c b/common/srv.c
deleted file mode 100644 (file)
index 2107aa5..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/* srv.c - DNS SRV code
- * Copyright (C) 2003, 2009 Free Software Foundation, Inc.
- *
- * 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 <sys/types.h>
-#ifdef _WIN32
-# ifdef HAVE_WINSOCK2_H
-#  include <winsock2.h>
-# endif
-# include <windows.h>
-#else
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#endif
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#ifdef USE_ADNS
-# include <adns.h>
-#endif
-
-#include "util.h"
-#include "host2net.h"
-#include "srv.h"
-
-/* Not every installation has gotten around to supporting SRVs
-   yet... */
-#ifndef T_SRV
-#define T_SRV 33
-#endif
-
-static int
-priosort(const void *a,const void *b)
-{
-  const struct srventry *sa=a,*sb=b;
-  if(sa->priority>sb->priority)
-    return 1;
-  else if(sa->priority<sb->priority)
-    return -1;
-  else
-    return 0;
-}
-
-
-int
-getsrv (const char *name,struct srventry **list)
-{
-  int srvcount=0;
-  u16 count;
-  int i, rc;
-
-  *list = NULL;
-
-#ifdef USE_ADNS
-  {
-    adns_state state;
-    adns_answer *answer = NULL;
-
-    rc = adns_init (&state, adns_if_noerrprint, NULL);
-    if (rc)
-      {
-        log_error ("error initializing adns: %s\n", strerror (errno));
-        return -1;
-      }
-
-    rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
-                           &answer);
-    if (rc)
-      {
-        log_error ("DNS query failed: %s\n", strerror (errno));
-        adns_finish (state);
-        return -1;
-      }
-    if (answer->status != adns_s_ok
-        || answer->type != adns_r_srv || !answer->nrrs)
-      {
-        log_error ("DNS query returned an error or no records: %s (%s)\n",
-                   adns_strerror (answer->status),
-                   adns_errabbrev (answer->status));
-        adns_free (answer);
-        adns_finish (state);
-        return 0;
-      }
-
-    for (count = 0; count < answer->nrrs; count++)
-      {
-        struct srventry *srv = NULL;
-        struct srventry *newlist;
-
-        if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME)
-          {
-            log_info ("hostname in SRV record too long - skipped\n");
-            continue;
-          }
-
-        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
-        if (!newlist)
-          goto fail;
-        *list = newlist;
-        memset (&(*list)[srvcount], 0, sizeof(struct srventry));
-        srv = &(*list)[srvcount];
-        srvcount++;
-
-        srv->priority = answer->rrs.srvha[count].priority;
-        srv->weight   = answer->rrs.srvha[count].weight;
-        srv->port     = answer->rrs.srvha[count].port;
-        strcpy (srv->target, answer->rrs.srvha[count].ha.host);
-      }
-
-    adns_free (answer);
-    adns_finish (state);
-  }
-#else /*!USE_ADNS*/
-  {
-    unsigned char answer[2048];
-    HEADER *header = (HEADER *)answer;
-    unsigned char *pt, *emsg;
-    int r;
-    u16 dlen;
-
-    r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
-    if (r < sizeof (HEADER) || r > sizeof answer)
-      return -1;
-    if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
-      return 0; /* Error or no record found.  */
-
-    emsg = &answer[r];
-    pt = &answer[sizeof(HEADER)];
-
-    /* Skip over the query */
-    rc = dn_skipname (pt, emsg);
-    if (rc == -1)
-      goto fail;
-
-    pt += rc + QFIXEDSZ;
-
-    while (count-- > 0 && pt < emsg)
-      {
-        struct srventry *srv=NULL;
-        u16 type,class;
-        struct srventry *newlist;
-
-        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
-        if (!newlist)
-          goto fail;
-        *list = newlist;
-        memset(&(*list)[srvcount],0,sizeof(struct srventry));
-        srv=&(*list)[srvcount];
-        srvcount++;
-
-        rc = dn_skipname(pt,emsg); /* the name we just queried for */
-        if (rc == -1)
-          goto fail;
-        pt+=rc;
-
-        /* Truncated message? */
-        if((emsg-pt)<16)
-          goto fail;
-
-        type = buf16_to_u16 (pt);
-        pt += 2;
-        /* We asked for SRV and got something else !? */
-        if(type!=T_SRV)
-          goto fail;
-
-        class = buf16_to_u16 (pt);
-        pt += 2;
-        /* We asked for IN and got something else !? */
-        if(class!=C_IN)
-          goto fail;
-
-        pt += 4; /* ttl */
-        dlen = buf16_to_u16 (pt);
-        pt += 2;
-
-        srv->priority = buf16_to_ushort (pt);
-        pt += 2;
-        srv->weight = buf16_to_ushort (pt);
-        pt += 2;
-        srv->port = buf16_to_ushort (pt);
-        pt += 2;
-
-        /* Get the name.  2782 doesn't allow name compression, but
-           dn_expand still works to pull the name out of the
-           packet. */
-        rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME);
-        if (rc == 1 && srv->target[0] == 0) /* "." */
-          {
-            xfree(*list);
-            *list = NULL;
-            return 0;
-          }
-        if (rc == -1)
-          goto fail;
-        pt += rc;
-        /* Corrupt packet? */
-        if (dlen != rc+6)
-          goto fail;
-      }
-  }
-#endif /*!USE_ADNS*/
-
-  /* Now we have an array of all the srv records. */
-
-  /* Order by priority */
-  qsort(*list,srvcount,sizeof(struct srventry),priosort);
-
-  /* For each priority, move the zero-weighted items first. */
-  for (i=0; i < srvcount; i++)
-    {
-      int j;
-
-      for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
-        {
-          if((*list)[j].weight==0)
-            {
-              /* Swap j with i */
-              if(j!=i)
-                {
-                  struct srventry temp;
-
-                  memcpy (&temp,&(*list)[j],sizeof(struct srventry));
-                  memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
-                  memcpy (&(*list)[i],&temp,sizeof(struct srventry));
-                }
-
-              break;
-            }
-        }
-    }
-
-  /* Run the RFC-2782 weighting algorithm.  We don't need very high
-     quality randomness for this, so regular libc srand/rand is
-     sufficient.  Fixme: It is a bit questionaly to reinitalize srand
-     - better use a gnupg fucntion for this.  */
-  srand(time(NULL)*getpid());
-
-  for (i=0; i < srvcount; i++)
-    {
-      int j;
-      float prio_count=0,chose;
-
-      for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
-        {
-          prio_count+=(*list)[j].weight;
-          (*list)[j].run_count=prio_count;
-        }
-
-      chose=prio_count*rand()/RAND_MAX;
-
-      for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
-        {
-          if (chose<=(*list)[j].run_count)
-            {
-              /* Swap j with i */
-              if(j!=i)
-                {
-                  struct srventry temp;
-
-                  memcpy(&temp,&(*list)[j],sizeof(struct srventry));
-                  memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
-                  memcpy(&(*list)[i],&temp,sizeof(struct srventry));
-                }
-              break;
-            }
-        }
-    }
-
-  return srvcount;
-
- fail:
-  xfree(*list);
-  *list=NULL;
-  return -1;
-}
-
-#ifdef TEST
-int
-main(int argc,char *argv[])
-{
-  struct srventry *srv;
-  int rc,i;
-
-  rc=getsrv("_hkp._tcp.wwwkeys.pgp.net",&srv);
-  printf("Count=%d\n\n",rc);
-  for(i=0;i<rc;i++)
-    {
-      printf("priority=%hu\n",srv[i].priority);
-      printf("weight=%hu\n",srv[i].weight);
-      printf("port=%hu\n",srv[i].port);
-      printf("target=%s\n",srv[i].target);
-      printf("\n");
-    }
-
-  xfree(srv);
-
-  return 0;
-}
-#endif /* TEST */
-
-/*
-Local Variables:
-compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv  ../tools/no-libgcrypt.o  ../common/libcommon.a"
-End:
-*/
index f1af587..71bcc95 100644 (file)
@@ -55,12 +55,16 @@ enum
     STATUS_GOODMDC,
     STATUS_BADMDC,
     STATUS_ERRMDC,
+
     STATUS_IMPORTED,
     STATUS_IMPORT_OK,
     STATUS_IMPORT_PROBLEM,
     STATUS_IMPORT_RES,
     STATUS_IMPORT_CHECK,
 
+    STATUS_EXPORTED,
+    STATUS_EXPORT_RES,
+
     STATUS_FILE_START,
     STATUS_FILE_DONE,
     STATUS_FILE_ERROR,
@@ -124,6 +128,8 @@ enum
 
     STATUS_PINENTRY_LAUNCHED,
 
+    STATUS_PLAINTEXT_FOLLOWS,   /* Used by g13-syshelp  */
+
     STATUS_ERROR,
     STATUS_SUCCESS,
     STATUS_FAILURE,
index 38c3832..e8b990a 100644 (file)
@@ -746,16 +746,30 @@ sanitize_buffer (const void *p_arg, size_t n, int delim)
 
 /* Given a string containing an UTF-8 encoded text, return the number
    of characters in this string.  It differs from strlen in that it
-   only counts complete UTF-8 characters.  Note, that this function
-   does not take combined characters into account.  */
+   only counts complete UTF-8 characters.  SIZE is the maximum length
+   of the string in bytes.  If SIZE is -1, then a NUL character is
+   taken to be the end of the string.  Note, that this function does
+   not take combined characters into account.  */
 size_t
-utf8_charcount (const char *s)
+utf8_charcount (const char *s, int len)
 {
   size_t n;
 
+  if (len == 0)
+    return 0;
+
   for (n=0; *s; s++)
-    if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
-      n++;
+    {
+      if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
+        n++;
+
+      if (len != -1)
+        {
+          len --;
+          if (len == 0)
+            break;
+        }
+    }
 
   return n;
 }
@@ -1313,3 +1327,136 @@ strtokenize (const char *string, const char *delim)
 
   return result;
 }
+
+
+/* Format a string so that it fits within about TARGET_COLS columns.
+   If IN_PLACE is 0, then TEXT is copied to a new buffer, which is
+   returned.  Otherwise, TEXT is modified in place and returned.
+   Normally, target_cols will be 72 and max_cols is 80.  */
+char *
+format_text (char *text, int in_place, int target_cols, int max_cols)
+{
+  const int do_debug = 0;
+
+  /* The character under consideration.  */
+  char *p;
+  /* The start of the current line.  */
+  char *line;
+  /* The last space that we saw.  */
+  char *last_space = NULL;
+  int last_space_cols = 0;
+  int copied_last_space = 0;
+
+  if (! in_place)
+    text = xstrdup (text);
+
+  p = line = text;
+  while (1)
+    {
+      /* The number of columns including any trailing space.  */
+      int cols;
+
+      p = p + strcspn (p, "\n ");
+      if (! p)
+        /* P now points to the NUL character.  */
+        p = &text[strlen (text)];
+
+      if (*p == '\n')
+        /* Pass through any newlines.  */
+        {
+          p ++;
+          line = p;
+          last_space = NULL;
+          last_space_cols = 0;
+          copied_last_space = 1;
+          continue;
+        }
+
+      /* Have a space or a NUL.  Note: we don't count the trailing
+         space.  */
+      cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
+      if (cols < target_cols)
+        {
+          if (! *p)
+            /* Nothing left to break.  */
+            break;
+
+          last_space = p;
+          last_space_cols = cols;
+          p ++;
+          /* Skip any immediately following spaces.  If we break:
+             "... foo bar ..." between "foo" and "bar" then we want:
+             "... foo\nbar ...", which means that the left space has
+             to be the first space after foo, not the last space
+             before bar.  */
+          while (*p == ' ')
+            p ++;
+        }
+      else
+        {
+          int cols_with_left_space;
+          int cols_with_right_space;
+          int left_penalty;
+          int right_penalty;
+
+          cols_with_left_space = last_space_cols;
+          cols_with_right_space = cols;
+
+          if (do_debug)
+            log_debug ("Breaking: '%.*s'\n",
+                       (int) ((uintptr_t) p - (uintptr_t) line), line);
+
+          /* The number of columns away from TARGET_COLS.  We prefer
+             to underflow than to overflow.  */
+          left_penalty = target_cols - cols_with_left_space;
+          right_penalty = 2 * (cols_with_right_space - target_cols);
+
+          if (cols_with_right_space > max_cols)
+            /* Add a large penalty for each column that exceeds
+               max_cols.  */
+            right_penalty += 4 * (cols_with_right_space - max_cols);
+
+          if (do_debug)
+            log_debug ("Left space => %d cols (penalty: %d); right space => %d cols (penalty: %d)\n",
+                       cols_with_left_space, left_penalty,
+                       cols_with_right_space, right_penalty);
+          if (last_space_cols && left_penalty <= right_penalty)
+            /* Prefer the left space.  */
+            {
+              if (do_debug)
+                log_debug ("Breaking at left space.\n");
+              p = last_space;
+            }
+          else
+            {
+              if (do_debug)
+                log_debug ("Breaking at right space.\n");
+            }
+
+          if (! *p)
+            break;
+
+          *p = '\n';
+          p ++;
+          if (*p == ' ')
+            {
+              int spaces;
+              for (spaces = 1; p[spaces] == ' '; spaces ++)
+                ;
+              memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
+            }
+          line = p;
+          last_space = NULL;
+          last_space_cols = 0;
+          copied_last_space = 0;
+        }
+    }
+
+  /* Chop off any trailing space.  */
+  trim_trailing_chars (text, strlen (text), " ");
+  /* If we inserted the trailing newline, then remove it.  */
+  if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
+    text[strlen (text) - 1] = '\0';
+
+  return text;
+}
index a84c81b..c813662 100644 (file)
@@ -64,7 +64,7 @@ int hextobyte (const char *s);
 char *sanitize_buffer (const void *p, size_t n, int delim);
 
 
-size_t utf8_charcount (const char *s);
+size_t utf8_charcount (const char *s, int len);
 
 
 #ifdef HAVE_W32_SYSTEM
@@ -148,6 +148,9 @@ char **strsplit (char *string, char delim, char replacement, int *count);
 /* Tokenize STRING using the set of delimiters in DELIM.  */
 char **strtokenize (const char *string, const char *delim);
 
+/* Format a string so that it fits within about TARGET_COLS columns.  */
+char *format_text (char *text, int in_place, int target_cols, int max_cols);
+
 
 /*-- mapstrings.c --*/
 const char *map_static_macro_string (const char *string);
index 9bd6195..760a460 100644 (file)
@@ -231,3 +231,22 @@ strlist_length (strlist_t list)
 
   return i;
 }
+
+/* Reverse the list *LIST in place.  */
+strlist_t
+strlist_rev (strlist_t *list)
+{
+  strlist_t l = *list;
+  strlist_t lrev = NULL;
+
+  while (l)
+    {
+      strlist_t tail = l->next;
+      l->next = lrev;
+      lrev = l;
+      l = tail;
+    }
+
+  *list = lrev;
+  return lrev;
+}
index fccce87..acb92f7 100644 (file)
@@ -58,6 +58,7 @@ char * strlist_pop (strlist_t *list);
 strlist_t strlist_find (strlist_t haystack, const char *needle);
 int strlist_length (strlist_t list);
 
+strlist_t strlist_rev (strlist_t *haystack);
 
 #define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
 
index 3971845..ccd3542 100644 (file)
@@ -267,7 +267,7 @@ check_permissions(const char *path,int extension,int checkonly)
 #endif
 
 
-/* Wrapper around the usual sleep fucntion.  This one won't wake up
+/* Wrapper around the usual sleep function.  This one won't wake up
    before the sleep time has really elapsed.  When build with Pth it
    merely calls pth_sleep and thus suspends only the current
    thread. */
@@ -446,7 +446,7 @@ gnupg_tmpfile (void)
    some folks close them before an exec and the next file we open will
    get one of them assigned and thus any output (i.e. diagnostics) end
    up in that file (e.g. the trustdb).  Not actually a gpg problem as
-   this will hapen with almost all utilities when called in a wrong
+   this will happen with almost all utilities when called in a wrong
    way.  However we try to minimize the damage here and raise
    awareness of the problem.
 
index 987b062..77f8199 100644 (file)
@@ -79,7 +79,7 @@ test_make_canon_sexp_from_rsa_pk (void)
     size_t elen;
     unsigned char *result;
     size_t resultlen;
-    gpg_err_code_t reverr;  /* Expected error from the reverse fucntion.  */
+    gpg_err_code_t reverr;  /* Expected error from the reverse function.  */
   } tests[] = {
     {
       "\x82\xB4\x12\x48\x08\x48\xC0\x76\xAA\x8E\xF1\xF8\x7F\x5E\x9B\x89"
index 13f3afa..9e5410b 100644 (file)
@@ -677,6 +677,142 @@ test_strtokenize (void)
     }
 }
 
+static char *
+stresc (char *s)
+{
+  char *p;
+  int l = strlen (s) + 1;
+
+  for (p = s; *p; p ++)
+    if (*p == '\n')
+      l ++;
+
+  p = xmalloc (l);
+  for (l = 0; *s; s ++, l ++)
+    {
+      if (*s == ' ')
+        p[l] = '_';
+      else if (*p == '\n')
+        {
+          p[l ++] = '\\';
+          p[l ++] = 'n';
+          p[l] = '\n';
+        }
+      else
+        p[l] = *s;
+    }
+  p[l] = *s;
+
+  return p;
+}
+
+static void
+test_format_text (void)
+{
+  struct test
+  {
+    int target_cols, max_cols;
+    char *input;
+    char *expected;
+  };
+
+  struct test tests[] = {
+    {
+      10, 12,
+      "",
+      "",
+    },
+    {
+      10, 12,
+      " ",
+      "",
+    },
+    {
+      10, 12,
+      "  ",
+      "",
+    },
+    {
+      10, 12,
+      " \n ",
+      " \n",
+    },
+    {
+      10, 12,
+      " \n  \n ",
+      " \n  \n",
+    },
+    {
+      10, 12,
+      "0123456789 0123456789 0",
+      "0123456789\n0123456789\n0",
+    },
+    {
+      10, 12,
+      "   0123456789   0123456789   0  ",
+      "   0123456789\n0123456789\n0",
+    },
+    {
+      10, 12,
+      "01 34 67 90 23 56  89 12 45 67 89 1",
+      "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+    },
+    {
+      10, 12,
+      "01 34 67 90 23 56  89 12 45 67 89 1",
+      "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+    },
+    {
+      72, 80,
+      "Warning: if you think you've seen more than 10 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 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
+      "Warning: if you think you've seen more than 10 messages signed by this\n"
+      "key, then this key might be a forgery!  Carefully examine the email\n"
+      "address for small variations (e.g., additional white space).  If the key\n"
+      "is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
+      "being bad.\n"
+
+    },
+    {
+      72, 80,
+      "Normally, there is only a single key associated with an email "
+      "address.  However, people sometimes generate a new key if "
+      "their key is too old or they think it might be compromised.  "
+      "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.",
+      "Normally, there is only a single key associated with an email "
+      "address.\nHowever, people sometimes generate a new key if "
+      "their key is too old or\nthey think it might be compromised.  "
+      "Alternatively, a new key may indicate\na man-in-the-middle "
+      "attack!  Before accepting this key, you should talk\nto or "
+      "call the person to make sure this new key is legitimate.",
+    }
+  };
+
+  int i;
+  int failed = 0;
+
+  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
+    {
+      struct test *test = &tests[i];
+      char *result =
+        format_text (test->input, 0, test->target_cols, test->max_cols);
+      if (strcmp (result, test->expected) != 0)
+        {
+          printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
+                  __func__, i + 1, stresc (test->expected), stresc (result));
+          failed ++;
+        }
+      xfree (result);
+    }
+
+  if (failed)
+    fail(0);
+}
 
 int
 main (int argc, char **argv)
@@ -692,6 +828,7 @@ main (int argc, char **argv)
   test_make_absfilename_try ();
   test_strsplit ();
   test_strtokenize ();
+  test_format_text ();
 
   xfree (home_buffer);
   return 0;
diff --git a/common/t-strlist.c b/common/t-strlist.c
new file mode 100644 (file)
index 0000000..b033905
--- /dev/null
@@ -0,0 +1,82 @@
+/* t-strlist.c - Regression tests for strist.c
+ * Copyright (C) 2015  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 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 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/>.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "strlist.h"
+
+#include "t-support.h"
+
+static void
+test_strlist_rev (void)
+{
+  strlist_t s = NULL;
+
+  /* Reversing an empty list should yield the empty list.  */
+  if (! (strlist_rev (&s) == NULL))
+    fail (1);
+
+  add_to_strlist (&s, "1");
+  add_to_strlist (&s, "2");
+  add_to_strlist (&s, "3");
+
+  if (strcmp (s->d, "3") != 0)
+    fail (2);
+  if (strcmp (s->next->d, "2") != 0)
+    fail (2);
+  if (strcmp (s->next->next->d, "1") != 0)
+    fail (2);
+  if (s->next->next->next)
+    fail (2);
+
+  strlist_rev (&s);
+
+  if (strcmp (s->d, "1") != 0)
+    fail (2);
+  if (strcmp (s->next->d, "2") != 0)
+    fail (2);
+  if (strcmp (s->next->next->d, "3") != 0)
+    fail (2);
+  if (s->next->next->next)
+    fail (2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  (void)argc;
+  (void)argv;
+
+  test_strlist_rev ();
+
+  return 0;
+}
index 555158e..8ff2810 100644 (file)
@@ -35,6 +35,9 @@
 #error The regression tests should not include with gcrypt.h
 #endif
 
+#include <stdlib.h>
+#include <stdio.h>
+
 #ifdef HAVE_W32CE_SYSTEM
 #include <gpg-error.h>  /* Defines strerror.  */
 #endif
@@ -69,8 +72,15 @@ void  gcry_free (void *a);
 #define pass()  do { ; } while(0)
 #define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
                                __FILE__,__LINE__, (a));          \
-                     exit (1);                                   \
+                      errcount++;                                \
+                      if (!no_exit_on_fail)                      \
+                         exit (1);                               \
                    } while(0)
 
+/* If this flag is set the fail macro does not call exit.  */
+static int no_exit_on_fail;
+/* Error counter.  */
+static int errcount;
+
 
 #endif /*GNUPG_COMMON_T_SUPPORT_H*/
index 2b19c09..c46d47f 100644 (file)
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_DOSISH_SYSTEM
+# include <fcntl.h>
+#endif
 
-#include "util.h"
+#include "zb32.h"
+#include "t-support.h"
 
-#define pass()  do { ; } while(0)
-#define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
-                               __FILE__,__LINE__, (a));          \
-                     errcount++;                                 \
-                   } while(0)
+#define PGM "t-zb32"
 
+static int verbose;
+static int debug;
 static int errcount;
 
 
@@ -89,8 +93,8 @@ test_zb32enc (void)
       output = zb32_encode (tests[tidx].data, tests[tidx].datalen);
       if (!output)
         {
-          fprintf (stderr, "%s:%d: error encoding test %d: %s\n",
-                   __FILE__, __LINE__, tidx, strerror (errno));
+          fprintf (stderr, PGM": error encoding test %d: %s\n",
+                   tidx, strerror (errno));
           exit (1);
         }
       /* puts (output); */
@@ -101,13 +105,201 @@ test_zb32enc (void)
 }
 
 
+/* Read the file FNAME or stdin if FNAME is NULL and return a malloced
+   buffer with the content.  R_LENGTH received the length of the file.
+   Print a diagnostic and returns NULL on error.  */
+static char *
+read_file (const char *fname, size_t *r_length)
+{
+  FILE *fp;
+  char *buf;
+  size_t buflen;
+
+  if (!fname)
+    {
+      size_t nread, bufsize = 0;
+
+      fp = stdin;
+#ifdef HAVE_DOSISH_SYSTEM
+      setmode (fileno(fp) , O_BINARY );
+#endif
+      buf = NULL;
+      buflen = 0;
+#define NCHUNK 8192
+      do
+        {
+          bufsize += NCHUNK;
+          if (!buf)
+            buf = xmalloc (bufsize);
+          else
+            buf = xrealloc (buf, bufsize);
+
+          nread = fread (buf+buflen, 1, NCHUNK, fp);
+          if (nread < NCHUNK && ferror (fp))
+            {
+              fprintf (stderr, PGM": error reading '[stdin]': %s\n",
+                       strerror (errno));
+              xfree (buf);
+              return NULL;
+            }
+          buflen += nread;
+        }
+      while (nread == NCHUNK);
+#undef NCHUNK
+
+    }
+  else
+    {
+      struct stat st;
+
+      fp = fopen (fname, "rb");
+      if (!fp)
+        {
+          fprintf (stderr, PGM": can't open '%s': %s\n",
+                   fname, strerror (errno));
+          return NULL;
+        }
+
+      if (fstat (fileno(fp), &st))
+        {
+          fprintf (stderr, PGM": can't stat '%s': %s\n",
+                   fname, strerror (errno));
+          fclose (fp);
+          return NULL;
+        }
+
+      buflen = st.st_size;
+      buf = xmalloc (buflen+1);
+      if (fread (buf, buflen, 1, fp) != 1)
+        {
+          fprintf (stderr, PGM": error reading '%s': %s\n",
+                   fname, strerror (errno));
+          fclose (fp);
+          xfree (buf);
+          return NULL;
+        }
+      fclose (fp);
+    }
+
+  *r_length = buflen;
+  return buf;
+}
+
+
+/* Debug helper to encode or decode to/from zb32.  */
+static void
+endecode_file (const char *fname, int decode)
+{
+  char *buffer;
+  size_t buflen;
+  char *result;
+
+  if (decode)
+    {
+      fprintf (stderr, PGM": decode mode has not yet been implemented\n");
+      errcount++;
+      return;
+    }
+
+#ifdef HAVE_DOSISH_SYSTEM
+  if (decode)
+    setmode (fileno (stdout), O_BINARY);
+#endif
+
+
+  buffer = read_file (fname, &buflen);
+  if (!buffer)
+    {
+      errcount++;
+      return;
+    }
+
+  result = zb32_encode (buffer, 8 * buflen);
+  if (!result)
+    {
+      fprintf (stderr, PGM": error encoding data: %s\n", strerror (errno));
+      errcount++;
+      xfree (buffer);
+      return;
+    }
+
+  fputs (result, stdout);
+  putchar ('\n');
+
+  xfree (result);
+  xfree (buffer);
+}
+
+
 int
 main (int argc, char **argv)
 {
-  (void)argc;
-  (void)argv;
+  int last_argc = -1;
+  int opt_endecode = 0;
 
-  test_zb32enc ();
+  no_exit_on_fail = 1;
+
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " [FILE]\n"
+                 "Options:\n"
+                 "  --verbose         Print timings etc.\n"
+                 "  --debug           Flyswatter\n"
+                 "  --encode          Encode FILE or stdin\n"
+                 "  --decode          Decode FILE or stdin\n"
+                 , stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--encode"))
+        {
+          opt_endecode = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--decode"))
+        {
+          opt_endecode = -1;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        {
+          fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+          exit (1);
+        }
+    }
+
+  if (argc > 1)
+    {
+      fprintf (stderr, PGM ": to many arguments given\n");
+      exit (1);
+    }
+
+  if (opt_endecode)
+    {
+      endecode_file (argc? *argv : NULL, (opt_endecode < 0));
+    }
+  else
+    test_zb32enc ();
 
   return !!errcount;
 }
index 0f8c780..6167412 100644 (file)
@@ -134,7 +134,7 @@ tty_get_ttyname (void)
       got_name = 1;
     }
 #endif /*HAVE_CTERMID*/
-  /* Assume the standard tty on memory error or when tehre is no
+  /* Assume the standard tty on memory error or when there is no
      ctermid. */
   return name? name : "/dev/tty";
 }
@@ -502,7 +502,7 @@ do_get( const char *prompt, int hidden )
     do {
 #ifdef HAVE_W32CE_SYSTEM
       /* Using getchar is not a correct solution but for now it
-         doesn't matter becuase we have no real console at all.  We
+         doesn't matter because we have no real console at all.  We
          should rework this as soon as we have switched this entire
          module to estream.  */
         c = getchar();
index e1304be..e094c69 100644 (file)
@@ -1,6 +1,7 @@
 /* userids.c - Utility functions for user ids.
  * Copyright (C) 2001, 2003, 2004, 2006,
  *               2009 Free Software Foundation, Inc.
+ * Copyright (C) 2015  g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -70,6 +71,8 @@ gpg_error_t
 classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
 {
   const char *s;
+  char *s2 = NULL;
+  int rc = 0;
   int hexprefix = 0;
   int hexlength;
   int mode = 0;
@@ -83,14 +86,26 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
      function. */
   memset (desc, 0, sizeof *desc);
 
-  /* Skip leading spaces.  */
+  /* Skip leading and trailing spaces.  */
   for(s = name; *s && spacep (s); s++ )
     ;
+  if (*s && spacep (s + strlen(s) - 1))
+    {
+      s2 = xtrystrdup (s);
+      if (!s2)
+        {
+          rc = gpg_error_from_syserror ();
+          goto out;
+        }
+      trim_trailing_spaces (s2);
+      s = s2;
+    }
 
   switch (*s)
     {
     case 0:  /* Empty string is an error.  */
-      return gpg_error (GPG_ERR_INV_USER_ID);
+      rc = gpg_error (GPG_ERR_INV_USER_ID);
+      goto out;
 
     case '.': /* An email address, compare from end.  Note that this
                  has not yet been implemented in the search code.  */
@@ -138,7 +153,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
     case '/': /* Subject's DN.  */
       s++;
       if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
-        return gpg_error (GPG_ERR_INV_USER_ID);
+        {
+          rc = gpg_error (GPG_ERR_INV_USER_ID);
+          goto out;
+        }
       desc->u.name = s;
       mode = KEYDB_SEARCH_MODE_SUBJECT;
       break;
@@ -152,7 +170,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
           { /* "#/" indicates an issuer's DN.  */
             s++;
             if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
-              return gpg_error (GPG_ERR_INV_USER_ID);
+              {
+                rc = gpg_error (GPG_ERR_INV_USER_ID);
+                goto out;
+              }
             desc->u.name = s;
             mode = KEYDB_SEARCH_MODE_ISSUER;
           }
@@ -162,7 +183,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
               {
                  /* Check for an invalid digit in the serial number. */
                 if (!strchr("01234567890abcdefABCDEF", *si))
-                  return gpg_error (GPG_ERR_INV_USER_ID);
+                  {
+                    rc = gpg_error (GPG_ERR_INV_USER_ID);
+                    goto out;
+                  }
               }
             desc->sn = (const unsigned char*)s;
             desc->snlen = -1;
@@ -172,7 +196,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
               {
                 s = si+1;
                 if (!*s || spacep (s))  /* No DN or prefixed with a space.  */
-                  return gpg_error (GPG_ERR_INV_USER_ID);
+                  {
+                    rc = gpg_error (GPG_ERR_INV_USER_ID);
+                    goto out;
+                  }
                 desc->u.name = s;
                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
               }
@@ -187,14 +214,23 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
 
         se = strchr (++s,':');
         if (!se)
-          return gpg_error (GPG_ERR_INV_USER_ID);
+          {
+            rc = gpg_error (GPG_ERR_INV_USER_ID);
+            goto out;
+          }
         for (i=0,si=s; si < se; si++, i++ )
           {
             if (!strchr("01234567890abcdefABCDEF", *si))
-              return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
+              {
+                rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
+                goto out;
+              }
           }
         if (i != 32 && i != 40)
-          return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
+          {
+            rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
+            goto out;
+          }
         for (i=0,si=s; si < se; i++, si +=2)
           desc->u.fpr[i] = hextobyte(si);
         for (; i < 20; i++)
@@ -207,7 +243,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
     case '&': /* Keygrip*/
       {
         if (hex2bin (s+1, desc->u.grip, 20) < 0)
-          return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
+          {
+            rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
+            goto out;
+          }
         mode = KEYDB_SEARCH_MODE_KEYGRIP;
       }
       break;
@@ -231,7 +270,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
         {
           if (hexprefix) /* A "0x" prefix without a correct
                             termination is an error.  */
-            return gpg_error (GPG_ERR_INV_USER_ID);
+            {
+              rc = gpg_error (GPG_ERR_INV_USER_ID);
+              goto out;
+            }
           /* The first characters looked like a hex number, but the
              entire string is not.  */
           hexlength = 0;
@@ -240,7 +282,9 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
       if (desc->exact)
         hexlength--; /* Remove the bang.  */
 
-      if (hexlength == 8
+      if ((hexlength == 8
+           && (s[hexlength] == 0
+               || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
           || (!hexprefix && hexlength == 9 && *s == '0'))
         {
           /* Short keyid.  */
@@ -249,7 +293,9 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
           desc->u.kid[1] = strtoul( s, NULL, 16 );
           mode = KEYDB_SEARCH_MODE_SHORT_KID;
         }
-      else if (hexlength == 16
+      else if ((hexlength == 16
+                && (s[hexlength] == 0
+                    || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
                || (!hexprefix && hexlength == 17 && *s == '0'))
         {
           /* Long keyid.  */
@@ -261,7 +307,9 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
           desc->u.kid[1] = strtoul (s+8, NULL, 16);
           mode = KEYDB_SEARCH_MODE_LONG_KID;
         }
-      else if (hexlength == 32
+      else if ((hexlength == 32
+                && (s[hexlength] == 0
+                    || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
                || (!hexprefix && hexlength == 33 && *s == '0'))
         {
           /* MD5 fingerprint.  */
@@ -273,12 +321,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
             {
               int c = hextobyte(s);
               if (c == -1)
-                return gpg_error (GPG_ERR_INV_USER_ID);
+                {
+                  rc = gpg_error (GPG_ERR_INV_USER_ID);
+                  goto out;
+                }
               desc->u.fpr[i] = c;
             }
           mode = KEYDB_SEARCH_MODE_FPR16;
         }
-      else if (hexlength == 40
+      else if ((hexlength == 40
+                && (s[hexlength] == 0
+                    || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
                || (!hexprefix && hexlength == 41 && *s == '0'))
         {
           /* SHA1/RMD160 fingerprint.  */
@@ -289,7 +342,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
             {
               int c = hextobyte(s);
               if (c == -1)
-                return gpg_error (GPG_ERR_INV_USER_ID);
+                {
+                  rc = gpg_error (GPG_ERR_INV_USER_ID);
+                  goto out;
+                }
               desc->u.fpr[i] = c;
             }
           mode = KEYDB_SEARCH_MODE_FPR20;
@@ -367,10 +423,13 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
       else
        {
           /* Hex number with a prefix but with a wrong length.  */
-          return gpg_error (GPG_ERR_INV_USER_ID);
+          rc = gpg_error (GPG_ERR_INV_USER_ID);
+          goto out;
         }
     }
 
   desc->mode = mode;
-  return 0;
+ out:
+  xfree (s2);
+  return rc;
 }
index af1a319..81d63ee 100644 (file)
 # define GPG_ERR_LDAP_PROX_AUTH_DENIED      891
 #endif /*GPG_ERROR_VERSION_NUMBER < 0x011300*/
 #if GPG_ERROR_VERSION_NUMBER < 0x011500  /* 1.21 */
+# define GPG_ERR_SERVER_FAILED              219
+# define GPG_ERR_NO_KEY                     220
+# define GPG_ERR_NO_NAME                    221
 # define GPG_ERR_TRUE                       255
 # define GPG_ERR_FALSE                      256
 #endif
@@ -218,7 +221,7 @@ extern gpg_err_source_t default_errsource;
 
 /* Convenience function to return a gpg-error code for memory
    allocation failures.  This function makes sure that an error will
-   be returned even if accidently ERRNO is not set.  */
+   be returned even if accidentally ERRNO is not set.  */
 static inline gpg_error_t
 out_of_core (void)
 {
@@ -271,11 +274,6 @@ gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length,
                          size_t *r_nbytes);
 gpg_error_t b64dec_finish (struct b64state *state);
 
-
-/*-- zb32.c --*/
-char *zb32_encode (const void *data, unsigned int databits);
-
-
 /*-- sexputil.c */
 char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
 void log_printcanon (const char *text,
index f6282a3..7025a49 100644 (file)
@@ -38,7 +38,7 @@
 #include <unistd.h>
 
 /* We can easiliy replace this code by the socket wrappers from libassuan.  */
-#warning Please do not use this module anymore
+#warning Remove this code; it is only used on w32 by symcryptrun.
 
 #define DIRSEP_C '\\'
 
similarity index 57%
rename from common/srv.h
rename to common/zb32.h
index 016d2b1..1fb41ec 100644 (file)
@@ -1,7 +1,7 @@
-/* srv.h
- * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* zb32.h - z-base-32 functions
+ * Copyright (C) 2014  Werner Koch
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of either
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef GNUPG_COMMON_SRV_H
-#define GNUPG_COMMON_SRV_H
+#ifndef GNUPG_COMMON_ZB32_H
+#define GNUPG_COMMON_ZB32_H
 
-#ifdef USE_DNS_SRV
-# ifdef _WIN32
-#  ifdef HAVE_WINSOCK2_H
-#   include <winsock2.h>
-#  endif
-#  include <windows.h>
-# else
-#  include <netinet/in.h>
-#  include <arpa/nameser.h>
-#  include <resolv.h>
-# endif /* !_WIN32 */
-#endif /* USE_DNS_SRV */
+/* Encode DATA which has a length of DATABITS (bits!) using the
+   zbase32 encoder and return a malloced string.  Returns NULL on
+   error and sets ERRNO.  */
+char *zb32_encode (const void *data, unsigned int databits);
 
-
-#ifndef MAXDNAME
-#define MAXDNAME 1025
-#endif
-
-struct srventry
-{
-  unsigned short priority;
-  unsigned short weight;
-  unsigned short port;
-  int run_count;
-  char target[MAXDNAME];
-};
-
-int getsrv(const char *name,struct srventry **list);
-
-#endif /*GNUPG_COMMON_SRV_H*/
+#endif /*GNUPG_COMMON_ZB32_H*/
index 27fc9a9..412ea8b 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], [9])
+m4_define([mym4_micro], [10])
 
 # 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
@@ -55,7 +55,7 @@ NEED_LIBGCRYPT_API=1
 NEED_LIBGCRYPT_VERSION=1.6.0
 
 NEED_LIBASSUAN_API=2
-NEED_LIBASSUAN_VERSION=2.1.0
+NEED_LIBASSUAN_VERSION=2.4.1
 
 NEED_KSBA_API=1
 NEED_KSBA_VERSION=1.2.0
@@ -69,6 +69,7 @@ NEED_NPTH_VERSION=0.91
 
 NEED_GNUTLS_VERSION=3.0
 
+NEED_SQLITE_VERSION=3.7
 
 development_version=mym4_isbeta
 PACKAGE=$PACKAGE_NAME
@@ -91,6 +92,7 @@ have_libassuan=no
 have_ksba=no
 have_ntbtls=no
 have_gnutls=no
+have_sqlite=no
 have_npth=no
 have_libusb=no
 have_adns=no
@@ -100,18 +102,21 @@ use_zip=yes
 use_bzip2=yes
 use_exec=yes
 use_trust_models=yes
+use_tofu=yes
 card_support=yes
 use_ccid_driver=yes
 dirmngr_auto_start=yes
 use_tls_library=no
 large_secmem=no
+show_tor_support=no
+
 
 GNUPG_BUILD_PROGRAM(gpg, yes)
 GNUPG_BUILD_PROGRAM(gpgsm, yes)
 # The agent is a required part and can't be disabled anymore.
 build_agent=yes
 GNUPG_BUILD_PROGRAM(scdaemon, yes)
-GNUPG_BUILD_PROGRAM(g13, yes)
+GNUPG_BUILD_PROGRAM(g13, no)
 GNUPG_BUILD_PROGRAM(dirmngr, yes)
 GNUPG_BUILD_PROGRAM(tools, yes)
 GNUPG_BUILD_PROGRAM(doc, yes)
@@ -247,6 +252,14 @@ if test "$use_trust_models" = no ; then
              [Define to include only trust-model always])
 fi
 
+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)
+AC_MSG_RESULT($use_tofu)
+
+
 
 #
 # Options to disable algorithm
@@ -648,14 +661,14 @@ case "${host}" in
 
     *-*-hpux*)
         if test -z "$GCC" ; then
-            CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE"
+            CFLAGS="-Ae -D_HPUX_SOURCE $CFLAGS"
         fi
         ;;
     *-dec-osf4*)
         if test -z "$GCC" ; then
             # Suppress all warnings
             # to get rid of the unsigned/signed char mismatch warnings.
-            CFLAGS="$CFLAGS -w"
+            CFLAGS="-w $CFLAGS"
         fi
         ;;
     *-dec-osf5*)
@@ -664,7 +677,7 @@ case "${host}" in
             # get rid of the unsigned/signed char mismatch warnings.
             # Using this may hide other pointer mismatch warnings, but
            # it at least lets other warning classes through
-            CFLAGS="$CFLAGS -msg_disable ptrmismatch1"
+            CFLAGS="-msg_disable ptrmismatch1 $CFLAGS"
         fi
         ;;
     m68k-atari-mint)
@@ -744,10 +757,10 @@ AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_API:$NEED_LIBASSUAN_VERSION",
 if test "$have_libassuan" = "yes"; then
   AC_DEFINE_UNQUOTED(GNUPG_LIBASSUAN_VERSION, "$libassuan_version",
                      [version of the libassuan library])
+  show_tor_support="only .onion"
 fi
 
 
-
 #
 # libksba is our X.509 support library
 #
@@ -780,6 +793,42 @@ DL_LIBS=$LIBS
 AC_SUBST(DL_LIBS)
 LIBS="$gnupg_dlopen_save_libs"
 
+
+# Checks for g10
+
+AC_ARG_ENABLE(sqlite,
+                AC_HELP_STRING([--disable-sqlite],
+                               [disable the use of SQLITE]),
+              try_sqlite=$enableval, try_sqlite=yes)
+
+if test x"$use_tofu" = xyes ; then
+  if test x"$try_sqlite" = xyes ; then
+    PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= $NEED_SQLITE_VERSION],
+                                 [have_sqlite=yes],
+                                 [have_sqlite=no])
+  fi
+  if test "$have_sqlite" = "yes"; then
+    :
+    AC_SUBST([SQLITE3_CFLAGS])
+    AC_SUBST([SQLITE3_LIBS])
+  else
+    use_tofu=no
+    tmp=$(echo "$SQLITE3_PKG_ERRORS" | tr '\n' '\v' | sed 's/\v/\n*** /g')
+    AC_MSG_WARN([[
+***
+*** Building without SQLite support - TOFU disabled
+***
+*** $tmp]])
+  fi
+fi
+
+AM_CONDITIONAL(SQLITE3, test "$have_sqlite" = "yes")
+
+if test x"$use_tofu" = xyes ; then
+    AC_DEFINE(USE_TOFU, 1, [Enable to build the TOFU code])
+fi
+
+
 # Checks for g13
 
 AC_PATH_PROG(ENCFS, encfs, /usr/bin/encfs)
@@ -898,12 +947,23 @@ AC_ARG_WITH(adns,
                LDFLAGS="${LDFLAGS} -L$withval/lib"
              fi])
 if test "$with_adns" != "no"; then
-  AC_CHECK_HEADERS(adns.h,
-                AC_CHECK_LIB(adns, adns_free,
-                             [have_adns=yes],
-                             [CPPFLAGS=${_cppflags} LDFLAGS=${_ldflags}]),
-                             [CPPFLAGS=${_cppflags} LDFLAGS=${_ldflags}])
+  AC_CHECK_HEADERS(adns.h,AC_CHECK_LIB(adns, adns_init_strcfg,[have_adns=yes]))
+  AC_CHECK_FUNCS(adns_free)
+  AC_MSG_CHECKING([if adns supports adns_if_tormode])
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+    #include <adns.h>
+    adns_initflags flags = adns_if_tormode;
+  ]],[])],[adns_if_tormode=yes],[adns_if_tormode=no])
+  AC_MSG_RESULT($adns_if_tormode)
+  if test x"$adns_if_tormode" = xyes; then
+    AC_DEFINE(HAVE_ADNS_IF_TORMODE,1,[define if adns_if_tormode is available])
+    if test "$show_tor_support" != "no"; then
+      show_tor_support=yes
+    fi
+  fi
 fi
+CPPFLAGS=${_cppflags}
+LDFLAGS=${_ldflags}
 if test "$have_adns" = "yes"; then
   ADNSLIBS="-ladns"
 fi
@@ -925,24 +985,40 @@ AC_ARG_ENABLE(dns-cert,
 if test x"$use_dns_srv" = xyes || test x"$use_dns_cert" = xyes; then
   _dns_save_libs=$LIBS
   LIBS=""
-  # the double underscore thing is a glibc-ism?
-  AC_SEARCH_LIBS(res_query,resolv bind,,
-                 AC_SEARCH_LIBS(__res_query,resolv bind,,have_resolver=no))
-  AC_SEARCH_LIBS(dn_expand,resolv bind,,
-                 AC_SEARCH_LIBS(__dn_expand,resolv bind,,have_resolver=no))
-  AC_SEARCH_LIBS(dn_skipname,resolv bind,,
-                 AC_SEARCH_LIBS(__dn_skipname,resolv bind,,have_resolver=no))
-
-  if test x"$have_resolver" != xno ; then
-
-    # Make sure that the BIND 4 resolver interface is workable before
-    # enabling any code that calls it.  At some point I'll rewrite the
-    # code to use the BIND 8 resolver API.
-    # We might also want to use adns instead.  Problem with ADNS is that
-    # it does not support v6.
-
-    AC_MSG_CHECKING([whether the resolver is usable])
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+
+  if test x"$have_adns" = xyes ; then
+    # We prefer ADNS.
+    DNSLIBS="$ADNSLIBS"
+    AC_DEFINE(USE_ADNS,1,[Use ADNS as resolver library.])
+
+    if test x"$use_dns_srv" = xyes ; then
+        AC_DEFINE(USE_DNS_SRV,1)
+    fi
+
+    if test x"$use_dns_cert" = xyes ; then
+        AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT])
+    fi
+  else
+    # With no ADNS find the system resolver.
+
+    # the double underscore thing is a glibc-ism?
+    AC_SEARCH_LIBS(res_query,resolv bind,,
+                   AC_SEARCH_LIBS(__res_query,resolv bind,,have_resolver=no))
+    AC_SEARCH_LIBS(dn_expand,resolv bind,,
+                   AC_SEARCH_LIBS(__dn_expand,resolv bind,,have_resolver=no))
+    AC_SEARCH_LIBS(dn_skipname,resolv bind,,
+                   AC_SEARCH_LIBS(__dn_skipname,resolv bind,,have_resolver=no))
+
+    if test x"$have_resolver" != xno ; then
+
+      # Make sure that the BIND 4 resolver interface is workable before
+      # enabling any code that calls it.  At some point I'll rewrite the
+      # code to use the BIND 8 resolver API.
+      # We might also want to use adns instead.  Problem with ADNS is that
+      # it does not support v6.
+
+      AC_MSG_CHECKING([whether the resolver is usable])
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>]],
@@ -951,15 +1027,15 @@ if test x"$use_dns_srv" = xyes || test x"$use_dns_cert" = xyes; then
   dn_skipname(0,0);
   dn_expand(0,0,0,0,0);
 ]])],have_resolver=yes,have_resolver=no)
-    AC_MSG_RESULT($have_resolver)
+      AC_MSG_RESULT($have_resolver)
 
-    # This is Apple-specific and somewhat bizarre as they changed the
-    # define in bind 8 for some reason.
+      # This is Apple-specific and somewhat bizarre as they changed the
+      # define in bind 8 for some reason.
 
-    if test x"$have_resolver" != xyes ; then
-       AC_MSG_CHECKING(
+      if test x"$have_resolver" != xyes ; then
+         AC_MSG_CHECKING(
              [whether I can make the resolver usable with BIND_8_COMPAT])
-       AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define BIND_8_COMPAT
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define BIND_8_COMPAT
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
@@ -968,42 +1044,28 @@ if test x"$use_dns_srv" = xyes || test x"$use_dns_cert" = xyes; then
   res_query("foo.bar",C_IN,T_A,answer,PACKETSZ);
   dn_skipname(0,0); dn_expand(0,0,0,0,0);
 ]])],[have_resolver=yes ; need_compat=yes])
-       AC_MSG_RESULT($have_resolver)
+         AC_MSG_RESULT($have_resolver)
+      fi
     fi
-  fi
 
-  if test x"$have_resolver" = xyes ; then
-     DNSLIBS=$LIBS
+    if test x"$have_resolver" = xyes ; then
+      DNSLIBS=$LIBS
 
-     if test x"$use_dns_srv" = xyes ; then
-        AC_DEFINE(USE_DNS_SRV,1,[define to use DNS SRV])
-     fi
+      if test x"$use_dns_srv" = xyes ; then
+         AC_DEFINE(USE_DNS_SRV,1,[define to use DNS SRV])
+      fi
 
-     if test x"$use_dns_cert" = xyes ; then
+      if test x"$use_dns_cert" = xyes ; then
         AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT])
-     fi
+      fi
 
-     if test x"$need_compat" = xyes ; then
+      if test x"$need_compat" = xyes ; then
         AC_DEFINE(BIND_8_COMPAT,1,[an Apple OSXism])
-     fi
-  else
-     # If we have no resolver library but ADNS (e.g. under W32) enable the
-     # code parts which can be used with ADNS.
-     if test x"$have_adns" = xyes ; then
-        DNSLIBS="$ADNSLIBS"
-        AC_DEFINE(USE_ADNS,1,[Use ADNS as resolver library.])
-
-        if test x"$use_dns_srv" = xyes ; then
-           AC_DEFINE(USE_DNS_SRV,1)
-        fi
-
-        if test x"$use_dns_cert" = xyes ; then
-           AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT])
-        fi
-     else
-        use_dns_srv=no
-        use_dns_cert=no
-     fi
+      fi
+    else
+      use_dns_srv=no
+      use_dns_cert=no
+    fi
   fi
 
   LIBS=$_dns_save_libs
@@ -1430,6 +1492,9 @@ AC_SUBST(W32SOCKLIBS)
 #
 AC_MSG_NOTICE([checking for cc features])
 if test "$GCC" = yes; then
+    mycflags=
+    mycflags_save=$CFLAGS
+
     # Check whether gcc does not emit a diagnositc for unknow -Wno-*
     # options.  This is the case for gcc >= 4.6
     AC_MSG_CHECKING([if gcc ignores unknown -Wno-* options])
@@ -1443,60 +1508,55 @@ if test "$GCC" = yes; then
     # warning options and the user should have a chance of overriding
     # them.
     if test "$USE_MAINTAINER_MODE" = "yes"; then
-        CFLAGS="$CFLAGS -O3 -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
-        CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security"
+        mycflags="$mycflags -O3 -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+        mycflags="$mycflags -Wformat -Wno-format-y2k -Wformat-security"
         if test x"$_gcc_silent_wno" = xyes ; then
           _gcc_wopt=yes
         else
           AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
-          _gcc_cflags_save=$CFLAGS
           CFLAGS="-Wno-missing-field-initializers"
           AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],
                             [_gcc_wopt=yes],[_gcc_wopt=no])
           AC_MSG_RESULT($_gcc_wopt)
-          CFLAGS=$_gcc_cflags_save;
         fi
         if test x"$_gcc_wopt" = xyes ; then
-          CFLAGS="$CFLAGS -W -Wno-sign-compare -Wno-missing-field-initializers"
+          mycflags="$mycflags -W -Wno-sign-compare"
+          mycflags="$mycflags -Wno-missing-field-initializers"
         fi
 
         AC_MSG_CHECKING([if gcc supports -Wdeclaration-after-statement])
-        _gcc_cflags_save=$CFLAGS
         CFLAGS="-Wdeclaration-after-statement"
         AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_wopt=yes,_gcc_wopt=no)
         AC_MSG_RESULT($_gcc_wopt)
-        CFLAGS=$_gcc_cflags_save;
         if test x"$_gcc_wopt" = xyes ; then
-          CFLAGS="$CFLAGS -Wdeclaration-after-statement"
+          mycflags="$mycflags -Wdeclaration-after-statement"
         fi
     else
-        CFLAGS="$CFLAGS -Wall"
+        mycflags="$mycflags -Wall"
     fi
 
     if test x"$_gcc_silent_wno" = xyes ; then
       _gcc_psign=yes
     else
       AC_MSG_CHECKING([if gcc supports -Wno-pointer-sign])
-      _gcc_cflags_save=$CFLAGS
       CFLAGS="-Wno-pointer-sign"
       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],
                         [_gcc_psign=yes],[_gcc_psign=no])
       AC_MSG_RESULT($_gcc_psign)
-      CFLAGS=$_gcc_cflags_save;
     fi
     if test x"$_gcc_psign" = xyes ; then
-       CFLAGS="$CFLAGS -Wno-pointer-sign"
+       mycflags="$mycflags -Wno-pointer-sign"
     fi
 
     AC_MSG_CHECKING([if gcc supports -Wpointer-arith])
-    _gcc_cflags_save=$CFLAGS
     CFLAGS="-Wpointer-arith"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_psign=yes,_gcc_psign=no)
     AC_MSG_RESULT($_gcc_psign)
-    CFLAGS=$_gcc_cflags_save;
     if test x"$_gcc_psign" = xyes ; then
-       CFLAGS="$CFLAGS -Wpointer-arith"
+       mycflags="$mycflags -Wpointer-arith"
     fi
+
+    CFLAGS="$mycflags $mycflags_save"
 fi
 
 
@@ -1541,7 +1601,8 @@ AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes")
 AM_CONDITIONAL(BUILD_GPGTAR,      test "$build_gpgtar" = "yes")
 
 AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
-AM_CONDITIONAL(NO_TRUST_MODELS, test "$use_trust_models" = no)
+AM_CONDITIONAL(NO_TRUST_MODELS,     test "$use_trust_models" = no)
+AM_CONDITIONAL(USE_TOFU,            test "$use_tofu" = yes)
 
 AM_CONDITIONAL(RUN_GPG_TESTS,
                test x$cross_compiling = xno -a "$build_gpg" = yes )
@@ -1794,6 +1855,8 @@ echo "
         LDAP support:        $gnupg_have_ldap
         DNS SRV support:     $use_dns_srv
         TLS support:         $use_tls_library
+        TOFU support:        $use_tofu
+        Tor support:         $show_tor_support
 "
 if test x"$use_regex" != xyes ; then
 echo "
index cee777a..c3bce0d 100644 (file)
@@ -19,7 +19,7 @@
 
 ## Process this file with automake to produce Makefile.in
 
-EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011
+EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem
 
 bin_PROGRAMS = dirmngr dirmngr-client
 
@@ -27,7 +27,7 @@ if USE_LDAPWRAPPER
 libexec_PROGRAMS = dirmngr_ldap
 endif
 
-noinst_PROGRAMS = $(module_tests)
+noinst_PROGRAMS = $(module_tests) $(module_maint_tests)
 TESTS = $(module_tests)
 
 AM_CPPFLAGS = -I$(top_srcdir)/common
@@ -61,7 +61,8 @@ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c  \
        certcache.c certcache.h \
        cdb.h cdblib.c misc.c dirmngr-err.h  \
        ocsp.c ocsp.h validate.c validate.h  \
-       dns-cert.c dns-cert.h \
+       dns-stuff.c dns-stuff.h \
+       http.c http.h \
        ks-action.c ks-action.h ks-engine.h \
        ks-engine-hkp.c ks-engine-http.c ks-engine-finger.c ks-engine-kdns.c
 
@@ -75,7 +76,7 @@ ldaplibs =
 endif
 
 
-dirmngr_LDADD = $(libcommontlsnpth) $(libcommonpth) \
+dirmngr_LDADD = $(libcommonpth) \
         $(DNSLIBS) $(LIBASSUAN_LIBS) \
        $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) \
        $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) $(LIBINTL) $(LIBICONV)
@@ -108,24 +109,41 @@ no-libgcrypt.c : $(top_srcdir)/tools/no-libgcrypt.c
 
 
 t_common_src = t-support.h
-# We need libcommontls, because we use the http functions.
-t_common_ldadd = $(libcommontls) $(libcommon) no-libgcrypt.o \
+t_common_ldadd = $(libcommon) no-libgcrypt.o $(LIBASSUAN_LIBS) \
                  $(GPG_ERROR_LIBS) $(NETLIBS) \
                  $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
                  $(DNSLIBS) $(LIBINTL) $(LIBICONV)
 
-module_tests = t-dns-cert
+module_tests = t-dns-stuff
 
 if USE_LDAP
 module_tests += t-ldap-parse-uri
 endif
 
+if MAINTAINER_MODE
+module_maint_tests = t-http
+else
+module_maint_tests =
+endif
+
+
+# http tests
+t_http_SOURCES = t-http.c http.c dns-stuff.c
+t_http_CFLAGS  = -DWITHOUT_NPTH=1 \
+                $(LIBGCRYPT_CFLAGS) $(NTBTLS_CFLAGS) $(LIBGNUTLS_CFLAGS) \
+                 $(GPG_ERROR_CFLAGS)
+t_http_LDADD   = $(t_common_ldadd) \
+                $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
+
 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_LDADD = $(ldaplibs) $(t_common_ldadd)
+t_ldap_parse_uri_CFLAGS = -DWITHOUT_NPTH=1
+t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd) $(DNSLIBS)
 
-t_dns_cert_SOURCES = t-dns-cert.c dns-cert.c
-t_dns_cert_LDADD   = $(t_common_ldadd)
+t_dns_stuff_CFLAGS = -DWITHOUT_NPTH=1
+t_dns_stuff_SOURCES = t-dns-stuff.c dns-stuff.c
+t_dns_stuff_LDADD   = $(t_common_ldadd) $(DNSLIBS)
 
-$(PROGRAMS) : $(libcommon) $(libcommonpth) $(libcommontls) $(libcommontlsnpth)
+$(PROGRAMS) : $(libcommon) $(libcommonpth)
index 9636b6c..23cb317 100644 (file)
@@ -696,7 +696,7 @@ make_find (struct cdb_make *cdbmp,
 {
   struct cdb_rl *rl = cdbmp->cdb_rec[hval&255];
   int r, i;
-  int seeked = 0;
+  int sought = 0;
   while(rl) {
     for(i = rl->cnt - 1; i >= 0; --i) { /* search backward */
       if (rl->rec[i].hval != hval)
@@ -711,7 +711,7 @@ make_find (struct cdb_make *cdbmp,
           return -1;
         cdbmp->cdb_bpos = cdbmp->cdb_buf;
       }
-      seeked = 1;
+      sought = 1;
       r = match(cdbmp->cdb_fd, rl->rec[i].rpos, key, klen);
       if (!r)
        continue;
@@ -725,7 +725,7 @@ make_find (struct cdb_make *cdbmp,
     }
     rl = rl->next;
   }
-  if (seeked && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0)
+  if (sought && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0)
     return -1;
   return 0;
 }
index 8c5feef..45be1f2 100644 (file)
@@ -331,7 +331,7 @@ put_cert (ksba_cert_t cert, int is_loaded, int is_trusted, void *fpr_buffer)
 /* Load certificates from the directory DIRNAME.  All certificates
    matching the pattern "*.crt" or "*.der"  are loaded.  We assume that
    certificates are DER encoded and not PEM encapsulated. The cache
-   should be in a locked state when calling this fucntion.  */
+   should be in a locked state when calling this function.  */
 static gpg_error_t
 load_certs_from_dir (const char *dirname, int are_trusted)
 {
@@ -687,7 +687,7 @@ get_cert_bysubject (const char *subject_dn, unsigned int seq)
 
 
 
-/* Return a value decribing the the class of PATTERN.  The offset of
+/* Return a value describing the the class of PATTERN.  The offset of
    the actual string to be used for the comparison is stored at
    R_OFFSET.  The offset of the serialnumer is stored at R_SN_OFFSET. */
 static enum pattern_class
index a0a5104..13d8a26 100644 (file)
@@ -859,7 +859,7 @@ update_dir (crl_cache_t cache)
                  field, thus we can compare it pretty easily. */
               *endp = 0;
               e = find_entry ( cache->entries, fieldp);
-              *endp = ':'; /* Restore orginal line. */
+              *endp = ':'; /* Restore original line. */
               if (e && e->deleted)
                 {
                   /* Marked for deletion, so don't write it. */
@@ -994,7 +994,7 @@ hash_dbfile (const char *fname, unsigned char *md5buffer)
   char *buffer;
   size_t n;
   gcry_md_hd_t md5;
-  gpg_err_code_t err;
+  gpg_error_t err;
 
   buffer = xtrymalloc (65536);
   fp = buffer? es_fopen (fname, "rb") : NULL;
@@ -1212,7 +1212,7 @@ find_entry (crl_cache_entry_t first, const char *issuer_hash)
 }
 
 
-/* Create a new CRL cache. This fucntion is usually called only once.
+/* Create a new CRL cache. This function is usually called only once.
    never fail. */
 void
 crl_cache_init(void)
@@ -1512,6 +1512,7 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
       break;
     case CRL_CACHE_DONTKNOW:
       err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+      break;
     case CRL_CACHE_CANTUSE:
       err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
       break;
@@ -1702,7 +1703,8 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
         {
         case KSBA_SR_BEGIN_ITEMS:
           {
-            if (start_sig_check (crl, &md, &algo ))
+            err = start_sig_check (crl, &md, &algo);
+            if (err)
               goto failure;
 
             err = ksba_crl_get_update_times (crl, thisupdate, nextupdate);
index 0f34e27..7e814f5 100644 (file)
@@ -292,8 +292,8 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
         }
       else if (opt.use_tor)
         {
-          /* For now we do not support LDAP over TOR.  */
-          log_error (_("CRL access not possible due to TOR mode\n"));
+          /* For now we do not support LDAP over Tor.  */
+          log_error (_("CRL access not possible due to Tor mode\n"));
           err = gpg_error (GPG_ERR_NOT_SUPPORTED);
         }
       else
@@ -318,8 +318,8 @@ crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
 {
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("CRL access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("CRL access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
   if (opt.disable_ldap)
@@ -350,8 +350,8 @@ ca_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context, const char *dn)
 {
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("CRL access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("CRL access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
   if (opt.disable_ldap)
@@ -377,8 +377,8 @@ start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
 {
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("CRL access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("CRL access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
   if (opt.disable_ldap)
index 29e29b5..02920d6 100644 (file)
@@ -36,6 +36,7 @@
 #include "../common/stringhelp.h"
 #include "../common/mischelp.h"
 #include "../common/strlist.h"
+#include "../common/asshelp.h"
 
 #include "i18n.h"
 #include "util.h"
@@ -89,7 +90,6 @@ static struct
   int quiet;
   int verbose;
   const char *dirmngr_program;
-  int force_pipe_server;
   int force_default_responder;
   int pem;
   int escaped_pem; /* PEM is additional percent encoded.  */
@@ -117,7 +117,6 @@ static unsigned char asctobin[256]; /* runtime initialized */
 
 
 /* Prototypes.  */
-static assuan_context_t start_dirmngr (int only_daemon);
 static gpg_error_t read_certificate (const char *fname,
                                      unsigned char **rbuf, size_t *rbuflen);
 static gpg_error_t do_check (assuan_context_t ctx,
@@ -185,7 +184,7 @@ main (int argc, char **argv )
   log_set_prefix ("dirmngr-client",
                   GPGRT_LOG_WITH_PREFIX);
 
-  /* For W32 we need to initialize the socket subsystem.  Becuase we
+  /* For W32 we need to initialize the socket subsystem.  Because we
      don't use Pth we need to do this explicit. */
 #ifdef HAVE_W32_SYSTEM
  {
@@ -291,9 +290,21 @@ main (int argc, char **argv )
       exit (2);
     }
 
-  ctx = start_dirmngr (1);
-  if (!ctx)
-    exit (2);
+  err = start_new_dirmngr (&ctx,
+                           GPG_ERR_SOURCE_DEFAULT,
+                           default_homedir (),
+                           opt.dirmngr_program
+                             ? opt.dirmngr_program
+                             : gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
+                           ! cmd_ping,
+                           opt.verbose,
+                           0,
+                           NULL, NULL);
+  if (err)
+    {
+      log_error (_("can't connect to the dirmngr: %s\n"), gpg_strerror (err));
+      exit (2);
+    }
 
   if (cmd_ping)
     ;
@@ -431,131 +442,6 @@ data_cb (void *opaque, const void *buffer, size_t length)
 }
 
 
-/* Try to connect to the dirmngr via socket or fork it off and work by
-   pipes.  Handle the server's initial greeting */
-static assuan_context_t
-start_dirmngr (int only_daemon)
-{
-  int rc;
-  char *infostr, *p;
-  assuan_context_t ctx;
-  int try_default = 0;
-
-  infostr = opt.force_pipe_server? NULL : getenv (DIRMNGR_INFO_NAME);
-  if (only_daemon && (!infostr || !*infostr))
-    {
-      if (dirmngr_user_socket_name ())
-        infostr = xstrdup (dirmngr_user_socket_name ());
-      else
-        infostr = xstrdup (dirmngr_sys_socket_name ());
-      try_default = 1;
-    }
-
-  rc = assuan_new (&ctx);
-  if (rc)
-    {
-      log_error (_("failed to allocate assuan context: %s\n"),
-                 gpg_strerror (rc));
-      return NULL;
-    }
-
-  if (!infostr || !*infostr)
-    {
-      const char *pgmname;
-      const char *argv[3];
-      assuan_fd_t no_close_list[3];
-      int i;
-
-      if (only_daemon)
-        {
-          log_error (_("apparently no running dirmngr\n"));
-          return NULL;
-        }
-
-      if (opt.verbose)
-        log_info (_("no running dirmngr - starting one\n"));
-
-      if (!opt.dirmngr_program || !*opt.dirmngr_program)
-        opt.dirmngr_program = "./dirmngr";
-      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
-        pgmname = opt.dirmngr_program;
-      else
-        pgmname++;
-
-      argv[0] = pgmname;
-      argv[1] = "--server";
-      argv[2] = NULL;
-
-      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;
-
-      /* Connect to the agent and perform initial handshaking.  */
-      rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv,
-                                no_close_list, NULL, NULL, 0);
-    }
-  else /* Connect to a daemon.  */
-    {
-      int prot;
-      int pid;
-
-      infostr = xstrdup (infostr);
-      if (!try_default && *infostr)
-        {
-          if ( !(p = strchr (infostr, ':')) || p == infostr)
-            {
-              log_error (_("malformed %s environment variable\n"),
-                         DIRMNGR_INFO_NAME);
-              xfree (infostr);
-              if (only_daemon)
-                return NULL;
-              /* Try again by starting a new instance.  */
-              opt.force_pipe_server = 1;
-              return start_dirmngr (0);
-            }
-          *p++ = 0;
-          pid = atoi (p);
-          while (*p && *p != ':')
-            p++;
-          prot = *p? atoi (p+1) : 0;
-          if (prot != 1)
-            {
-              log_error (_("dirmngr protocol version %d is not supported\n"),
-                         prot);
-              xfree (infostr);
-              if (only_daemon)
-                return NULL;
-              opt.force_pipe_server = 1;
-              return start_dirmngr (0);
-            }
-        }
-      else
-        pid = -1;
-
-      rc = assuan_socket_connect (ctx, infostr, pid, 0);
-      xfree (infostr);
-      if (gpg_err_code(rc) == GPG_ERR_ASS_CONNECT_FAILED && !only_daemon)
-        {
-          log_error (_("can't connect to the dirmngr - trying fall back\n"));
-          opt.force_pipe_server = 1;
-          return start_dirmngr (0);
-        }
-    }
-
-  if (rc)
-    {
-      assuan_release (ctx);
-      log_error (_("can't connect to the dirmngr: %s\n"),
-                 gpg_strerror (rc));
-      return NULL;
-    }
-
-  return ctx;
-}
-
-
 /* Read the first PEM certificate from the file FNAME.  If fname is
    NULL the next certificate is read from stdin.  The certificate is
    returned in an alloced buffer whose address will be returned in
index a32040e..f249d68 100644 (file)
@@ -68,6 +68,7 @@
 #endif
 #include "../common/init.h"
 #include "gc-opt-flags.h"
+#include "dns-stuff.h"
 
 /* The plain Windows version uses the windows service system.  For
    example to start the service you may use "sc start dirmngr".
@@ -142,6 +143,7 @@ enum cmd_and_opt_values {
   oIgnoreCertExtension,
   oUseTor,
   oKeyServer,
+  oNameServer,
   aTest
 };
 
@@ -214,11 +216,12 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oMaxReplies, "max-replies",
                 N_("|N|do not return more than N items in one query")),
 
+  ARGPARSE_s_s (oNameServer, "nameserver", "@"),
   ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
   ARGPARSE_s_s (oHkpCaCert, "hkp-cacert",
                 N_("|FILE|use the CA certificates in FILE for HKP over TLS")),
 
-  ARGPARSE_s_n (oUseTor, "use-tor", N_("route all network traffic via TOR")),
+  ARGPARSE_s_n (oUseTor, "use-tor", N_("route all network traffic via Tor")),
 
   ARGPARSE_s_s (oSocketName, "socket-name", "@"),  /* Only for debugging.  */
 
@@ -466,6 +469,20 @@ set_debug (void)
 
 
 static void
+set_tor_mode (void)
+{
+  if (opt.use_tor)
+    {
+      if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
+        {
+          log_error ("error enabling Tor mode: %s\n", strerror (errno));
+          log_info ("(is your Libassuan recent enough?)\n");
+        }
+    }
+}
+
+
+static void
 wrong_args (const char *text)
 {
   es_fprintf (es_stderr, _("usage: %s [options] "), DIRMNGR_NAME);
@@ -522,8 +539,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
         }
       FREE_STRLIST (opt.ignored_cert_extensions);
       http_register_tls_ca (NULL);
-      xfree (opt.keyserver);
-      opt.keyserver = NULL;
+      FREE_STRLIST (opt.keyserver);
       /* Note: We do not allow resetting of opt.use_tor at runtime.  */
       return 1;
     }
@@ -603,8 +619,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oUseTor: opt.use_tor = 1; break;
 
     case oKeyServer:
-      xfree (opt.keyserver);
-      opt.keyserver = *pargs->r.ret_str? xtrystrdup (pargs->r.ret_str) : NULL;
+      if (*pargs->r.ret_str)
+        add_to_strlist (&opt.keyserver, pargs->r.ret_str);
+      break;
+
+    case oNameServer:
+      set_dns_nameserver (pargs->r.ret_str);
       break;
 
     default:
@@ -985,11 +1005,10 @@ main (int argc, char **argv)
   if (opt.use_tor)
     {
       log_info ("WARNING: ***************************************\n");
-      log_info ("WARNING: TOR mode (--use-tor) DOES NOT YET WORK!\n");
+      log_info ("WARNING: Tor mode (--use-tor) MAY NOT FULLY WORK!\n");
       log_info ("WARNING: ***************************************\n");
     }
 
-
   /* Print a warning if an argument looks like an option.  */
   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
     {
@@ -1018,6 +1037,7 @@ main (int argc, char **argv)
     }
 
   set_debug ();
+  set_tor_mode ();
 
   /* Get LDAP server list from file. */
 #if USE_LDAP
@@ -1113,7 +1133,6 @@ main (int argc, char **argv)
           dirmngr_exit (1);
         }
 
-#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
       {
         int redirected;
 
@@ -1137,16 +1156,6 @@ main (int argc, char **argv)
                         socket_name, redir_socket_name);
           }
       }
-#else /* Assuan < 2.1.4 */
-      memset (&serv_addr, 0, sizeof serv_addr);
-      serv_addr.sun_family = AF_UNIX;
-      if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
-        {
-          log_error (_("socket name '%s' is too long\n"), socket_name);
-          dirmngr_exit (1);
-        }
-      strcpy (serv_addr.sun_path, socket_name);
-#endif /* Assuan < 2.1.4 */
 
       len = SUN_LEN (&serv_addr);
 
@@ -1783,6 +1792,7 @@ reread_configuration (void)
   fclose (fp);
 
   set_debug ();
+  set_tor_mode ();
 }
 
 
@@ -1963,7 +1973,7 @@ check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 }
 
 
-/* Helper to call a connection's main fucntion. */
+/* Helper to call a connection's main function. */
 static void *
 start_connection_thread (void *arg)
 {
index b2b94f9..6078884 100644 (file)
@@ -33,7 +33,7 @@
 #include "../common/membuf.h"
 #include "../common/sysutils.h" /* (gnupg_fd_t) */
 #include "../common/i18n.h"
-#include "../common/http.h"     /* (parsed_uri_t) */
+#include "http.h"     /* (parsed_uri_t) */
 
 /* This objects keeps information about a particular LDAP server and
    is used as item of a single linked list of servers. */
@@ -93,7 +93,7 @@ struct
   int system_service;   /* We are running as W32 service (implies daemon).  */
   int system_daemon;    /* We are running in system daemon mode.  */
   int running_detached; /* We are running in detached mode.  */
-  int use_tor;          /* TOR mode has been enabled.  */
+  int use_tor;          /* Tor mode has been enabled.  */
 
   int force;          /* Force loading outdated CRLs. */
 
@@ -131,7 +131,7 @@ struct
   unsigned int ocsp_current_period; /* Seconds a response is considered
                                        current after nextUpdate. */
 
-  char *keyserver;    /* Malloced string with the default keyserver.  */
+  strlist_t keyserver;              /* List of default keyservers.  */
 } opt;
 
 
index 61a7e39..6309413 100644 (file)
@@ -165,7 +165,7 @@ struct my_opt_s
   unsigned int alarm_timeout; /* And for the alarm based timeout.  */
   int multi;
 
-  estream_t outstream;    /* Send output to thsi stream.  */
+  estream_t outstream;    /* Send output to this stream.  */
 
   /* Note that we can't use const for the strings because ldap_* are
      not defined that way.  */
diff --git a/dirmngr/dns-cert.c b/dirmngr/dns-cert.c
deleted file mode 100644 (file)
index 3845a4b..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/* dns-cert.c - DNS CERT code (rfc-4398)
- * Copyright (C) 2005, 2006, 2009 Free Software Foundation, Inc.
- *
- * 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 <sys/types.h>
-#ifdef USE_DNS_CERT
-# ifdef HAVE_W32_SYSTEM
-#  ifdef HAVE_WINSOCK2_H
-#   include <winsock2.h>
-#  endif
-#  include <windows.h>
-# else
-#  include <netinet/in.h>
-#  include <arpa/nameser.h>
-#  include <resolv.h>
-# endif
-# include <string.h>
-#endif
-#ifdef USE_ADNS
-# include <adns.h>
-#endif
-
-#include "util.h"
-#include "host2net.h"
-#include "dns-cert.h"
-
-/* Not every installation has gotten around to supporting CERTs
-   yet... */
-#ifndef T_CERT
-# define T_CERT 37
-#endif
-
-/* ADNS has no support for CERT yet. */
-#define my_adns_r_cert 37
-
-
-
-/* Returns 0 on success or an error code.  If a PGP CERT record was
-   found, the malloced data is returned at (R_KEY, R_KEYLEN) and
-   the other return parameters are set to NULL/0.  If an IPGP CERT
-   record was found the fingerprint is stored as an allocated block at
-   R_FPR and its length at R_FPRLEN; an URL is is allocated as a
-   string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
-   returns the first CERT found with a supported type; it is expected
-   that only one CERT record is used.  If WANT_CERTTYPE is one of the
-   supported certtypes only records with this certtype are considered
-   and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
-gpg_error_t
-get_dns_cert (const char *name, int want_certtype,
-              void **r_key, size_t *r_keylen,
-              unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
-{
-#ifdef USE_DNS_CERT
-#ifdef USE_ADNS
-  gpg_error_t err;
-  adns_state state;
-  adns_answer *answer = NULL;
-  unsigned int ctype;
-  int count;
-
-  if (r_key)
-    *r_key = NULL;
-  if (r_keylen)
-    *r_keylen = 0;
-  *r_fpr = NULL;
-  *r_fprlen = 0;
-  *r_url = NULL;
-
-  if (adns_init (&state, adns_if_noerrprint, NULL))
-    {
-      err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
-      log_error ("error initializing adns: %s\n", strerror (errno));
-      return err;
-    }
-
-  if (adns_synchronous (state, name,
-                        (adns_r_unknown
-                         | (want_certtype < DNS_CERTTYPE_RRBASE
-                            ? my_adns_r_cert
-                            : (want_certtype - DNS_CERTTYPE_RRBASE))),
-                        adns_qf_quoteok_query, &answer))
-    {
-      err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
-      /* log_error ("DNS query failed: %s\n", strerror (errno)); */
-      adns_finish (state);
-      return err;
-    }
-  if (answer->status != adns_s_ok)
-    {
-      /* log_error ("DNS query returned an error: %s (%s)\n", */
-      /*            adns_strerror (answer->status), */
-      /*            adns_errabbrev (answer->status)); */
-      err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
-      goto leave;
-    }
-
-  err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
-  for (count = 0; count < answer->nrrs; count++)
-    {
-      int datalen = answer->rrs.byteblock[count].len;
-      const unsigned char *data = answer->rrs.byteblock[count].data;
-
-      /* First check for our generic RR hack.  */
-      if (datalen
-          && want_certtype >= DNS_CERTTYPE_RRBASE
-          && ((want_certtype - DNS_CERTTYPE_RRBASE)
-              == (answer->type & ~adns_r_unknown)))
-        {
-          /* Found the requested record - return it.  */
-          *r_key = xtrymalloc (datalen);
-          if (!*r_key)
-            err = gpg_err_make (default_errsource,
-                                gpg_err_code_from_syserror ());
-          else
-            {
-              memcpy (*r_key, data, datalen);
-              *r_keylen = datalen;
-              err = 0;
-            }
-          goto leave;
-        }
-
-      if (datalen < 5)
-        continue;  /* Truncated CERT record - skip.  */
-
-      ctype = buf16_to_uint (data);
-      /* (key tag and algorithm fields are not required.) */
-      data += 5;
-      datalen -= 5;
-
-      if (want_certtype && want_certtype != ctype)
-        ; /* Not of the requested certtype.  */
-      else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
-        {
-          /* CERT type is PGP.  Gpg checks for a minimum length of 11,
-             thus we do the same.  */
-          *r_key = xtrymalloc (datalen);
-          if (!*r_key)
-            err = gpg_err_make (default_errsource,
-                                gpg_err_code_from_syserror ());
-          else
-            {
-              memcpy (*r_key, data, datalen);
-              *r_keylen = datalen;
-              err = 0;
-            }
-          goto leave;
-        }
-      else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
-               && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
-        {
-          /* CERT type is IPGP.  We made sure that the data is
-             plausible and that the caller requested this
-             information.  */
-          *r_fprlen = data[0];
-          if (*r_fprlen)
-            {
-              *r_fpr = xtrymalloc (*r_fprlen);
-              if (!*r_fpr)
-                {
-                  err = gpg_err_make (default_errsource,
-                                      gpg_err_code_from_syserror ());
-                  goto leave;
-                }
-              memcpy (*r_fpr, data + 1, *r_fprlen);
-            }
-          else
-            *r_fpr = NULL;
-
-          if (datalen > *r_fprlen + 1)
-            {
-              *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
-              if (!*r_url)
-                {
-                  err = gpg_err_make (default_errsource,
-                                      gpg_err_code_from_syserror ());
-                  xfree (*r_fpr);
-                  *r_fpr = NULL;
-                  goto leave;
-                }
-              memcpy (*r_url,
-                      data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
-              (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
-            }
-          else
-            *r_url = NULL;
-
-          err = 0;
-          goto leave;
-        }
-    }
-
- leave:
-  adns_free (answer);
-  adns_finish (state);
-  return err;
-
-#else /*!USE_ADNS*/
-
-  gpg_error_t err;
-  unsigned char *answer;
-  int r;
-  u16 count;
-
-  if (r_key)
-    *r_key = NULL;
-  if (r_keylen)
-    *r_keylen = 0;
-  *r_fpr = NULL;
-  *r_fprlen = 0;
-  *r_url = NULL;
-
-  /* Allocate a 64k buffer which is the limit for an DNS response.  */
-  answer = xtrymalloc (65536);
-  if (!answer)
-    return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
-
-  err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
-
-  r = res_query (name, C_IN,
-                 (want_certtype < DNS_CERTTYPE_RRBASE
-                  ? T_CERT
-                  : (want_certtype - DNS_CERTTYPE_RRBASE)),
-                 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)))
-    {
-      int rc;
-      unsigned char *pt, *emsg;
-
-      emsg = &answer[r];
-
-      pt = &answer[sizeof (HEADER)];
-
-      /* Skip over the query */
-
-      rc = dn_skipname (pt, emsg);
-      if (rc == -1)
-        {
-          err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
-          goto leave;
-        }
-      pt += rc + QFIXEDSZ;
-
-      /* There are several possible response types for a CERT request.
-         We're interested in the PGP (a key) and IPGP (a URI) types.
-         Skip all others.  TODO: A key is better than a URI since
-         we've gone through all this bother to fetch it, so favor that
-         if we have both PGP and IPGP? */
-
-      while (count-- > 0 && pt < emsg)
-        {
-          u16 type, class, dlen, ctype;
-
-          rc = dn_skipname (pt, emsg);  /* the name we just queried for */
-          if (rc == -1)
-            {
-              err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
-              goto leave;
-            }
-
-          pt += rc;
-
-          /* Truncated message? 15 bytes takes us to the point where
-             we start looking at the ctype. */
-          if ((emsg - pt) < 15)
-            break;
-
-          type = buf16_to_u16 (pt);
-          pt += 2;
-
-          class = buf16_to_u16 (pt);
-          pt += 2;
-
-          if (class != C_IN)
-            break;
-
-          /* ttl */
-          pt += 4;
-
-          /* data length */
-          dlen = buf16_to_u16 (pt);
-          pt += 2;
-
-          /* Check the type and parse.  */
-          if (want_certtype >= DNS_CERTTYPE_RRBASE
-              && type == (want_certtype - DNS_CERTTYPE_RRBASE)
-              && r_key)
-            {
-              *r_key = xtrymalloc (dlen);
-              if (!*r_key)
-                err = gpg_err_make (default_errsource,
-                                    gpg_err_code_from_syserror ());
-              else
-                {
-                  memcpy (*r_key, pt, dlen);
-                  *r_keylen = dlen;
-                  err = 0;
-                }
-              goto leave;
-            }
-          else if (want_certtype >= DNS_CERTTYPE_RRBASE)
-            {
-              /* We did not found the requested RR.  */
-              pt += dlen;
-            }
-          else if (type == T_CERT)
-            {
-              /* We got a CERT type.   */
-              ctype = buf16_to_u16 (pt);
-              pt += 2;
-
-              /* Skip the CERT key tag and algo which we don't need. */
-              pt += 3;
-
-              dlen -= 5;
-
-              /* 15 bytes takes us to here */
-              if (want_certtype && want_certtype != ctype)
-                ; /* Not of the requested certtype.  */
-              else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
-                {
-                  /* PGP type */
-                  *r_key = xtrymalloc (dlen);
-                  if (!*r_key)
-                    err = gpg_err_make (default_errsource,
-                                        gpg_err_code_from_syserror ());
-                  else
-                    {
-                      memcpy (*r_key, pt, dlen);
-                      *r_keylen = dlen;
-                      err = 0;
-                    }
-                  goto leave;
-                }
-              else if (ctype == DNS_CERTTYPE_IPGP
-                       && dlen && dlen < 1023 && dlen >= pt[0] + 1)
-                {
-                  /* IPGP type */
-                  *r_fprlen = pt[0];
-                  if (*r_fprlen)
-                    {
-                      *r_fpr = xtrymalloc (*r_fprlen);
-                      if (!*r_fpr)
-                        {
-                          err = gpg_err_make (default_errsource,
-                                              gpg_err_code_from_syserror ());
-                          goto leave;
-                        }
-                      memcpy (*r_fpr, &pt[1], *r_fprlen);
-                    }
-                  else
-                    *r_fpr = NULL;
-
-                  if (dlen > *r_fprlen + 1)
-                    {
-                      *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
-                      if (!*r_fpr)
-                        {
-                          err = gpg_err_make (default_errsource,
-                                              gpg_err_code_from_syserror ());
-                          xfree (*r_fpr);
-                          *r_fpr = NULL;
-                          goto leave;
-                        }
-                      memcpy (*r_url, &pt[*r_fprlen + 1],
-                              dlen - (*r_fprlen + 1));
-                      (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
-                    }
-                  else
-                    *r_url = NULL;
-
-                  err = 0;
-                  goto leave;
-                }
-
-              /* No subtype matches, so continue with the next answer. */
-              pt += dlen;
-            }
-          else
-            {
-              /* Not a requested type - might be a CNAME. Try next item.  */
-              pt += dlen;
-            }
-        }
-    }
-
- leave:
-  xfree (answer);
-  return err;
-
-#endif /*!USE_ADNS */
-#else /* !USE_DNS_CERT */
-  (void)name;
-  if (r_key)
-    *r_key = NULL;
-  if (r_keylen)
-    *r_keylen = NULL;
-  *r_fpr = NULL;
-  *r_fprlen = 0;
-  *r_url = NULL;
-
-  return gpg_err_make (default_errsource, GPG_ERR_NOT_SUPPORTED);
-#endif
-}
diff --git a/dirmngr/dns-cert.h b/dirmngr/dns-cert.h
deleted file mode 100644 (file)
index 9dbc58c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* dns-cert.h - DNS CERT definition
- * Copyright (C) 2006 Free Software Foundation, Inc.
- *
- * 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_DIRMNGR_DNS_CERT_H
-#define GNUPG_DIRMNGR_DNS_CERT_H
-
-
-#define DNS_CERTTYPE_ANY       0 /* Internal catch all type. */
-/* Certificate types according to RFC-4398:  */
-#define DNS_CERTTYPE_PKIX      1 /* X.509 as per PKIX. */
-#define DNS_CERTTYPE_SPKI      2 /* SPKI certificate.  */
-#define DNS_CERTTYPE_PGP       3 /* OpenPGP packet.  */
-#define DNS_CERTTYPE_IPKIX     4 /* The URL of an X.509 data object. */
-#define DNS_CERTTYPE_ISPKI     5 /* The URL of an SPKI certificate.  */
-#define DNS_CERTTYPE_IPGP      6 /* The fingerprint
-                                    and URL of an OpenPGP packet.  */
-#define DNS_CERTTYPE_ACPKIX    7 /* Attribute Certificate.  */
-#define DNS_CERTTYPE_IACPKIX   8 /* The URL of an Attribute Certificate.  */
-#define DNS_CERTTYPE_URI     253 /* URI private.  */
-#define DNS_CERTTYPE_OID     254 /* OID private.  */
-/* Hacks for our implementation.  */
-#define DNS_CERTTYPE_RRBASE 1024 /* Base of special constants.  */
-#define DNS_CERTTYPE_RR61   (DNS_CERTTYPE_RRBASE + 61)
-
-gpg_error_t get_dns_cert (const char *name, int want_certtype,
-                          void **r_key, size_t *r_keylen,
-                          unsigned char **r_fpr, size_t *r_fprlen,
-                          char **r_url);
-
-
-
-#endif /*GNUPG_DIRMNGR_DNS_CERT_H*/
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
new file mode 100644 (file)
index 0000000..1bf6cfc
--- /dev/null
@@ -0,0 +1,1360 @@
+/* dns-stuff.c - DNS related code including CERT RR (rfc-4398)
+ * Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005, 2006, 2009, 2015 Werner Koch
+ *
+ * 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 <sys/types.h>
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <windows.h>
+#else
+# include <netinet/in.h>
+# include <arpa/nameser.h>
+# include <resolv.h>
+# include <netdb.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+#ifdef USE_ADNS
+# include <adns.h>
+#endif
+
+#if !defined(HAVE_GETADDRINFO) && !defined(USE_ADNS)
+# error Either getaddrinfo or the ADNS library is required.
+#endif
+
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
+# undef USE_NPTH
+#endif
+#ifdef USE_NPTH
+# include <npth.h>
+#endif
+
+#include "util.h"
+#include "host2net.h"
+#include "dns-stuff.h"
+
+#ifdef USE_NPTH
+# define my_unprotect()        npth_unprotect ()
+# define my_protect()          npth_protect ()
+#else
+# define my_unprotect()        do { } while(0)
+# define my_protect()          do { } while(0)
+#endif
+
+/* We allow the use of 0 instead of AF_UNSPEC - check this assumption.  */
+#if AF_UNSPEC != 0
+# error AF_UNSPEC does not have the value 0
+#endif
+
+/* Windows does not support the AI_ADDRCONFIG flag - use zero instead.  */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+/* Provide a replacement function for older ADNS versions.  */
+#ifndef HAVE_ADNS_FREE
+# define adns_free(a) free ((a))
+#endif
+
+/* Not every installation has gotten around to supporting SRVs or
+   CERTs yet... */
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+#ifndef T_CERT
+# define T_CERT 37
+#endif
+
+/* ADNS has no support for CERT yet. */
+#define my_adns_r_cert 37
+
+
+/* The default nameserver used with ADNS in Tor mode.  */
+#define DEFAULT_NAMESERVER "8.8.8.8"
+
+
+/* If set Tor mode shall be used.  */
+static int tor_mode;
+
+/* A string with the nameserver IP address used with Tor.
+  (40 should be sufficient for v6 but we add some extra for a scope.) */
+static char tor_nameserver[40+20];
+
+/* A string to hold the credentials presented to Tor.  */
+#ifdef USE_ADNS
+static char tor_credentials[50];
+#endif
+
+/* Sets the module in Tor mode.  Returns 0 is this is possible or an
+   error code.  */
+gpg_error_t
+enable_dns_tormode (int new_circuit)
+{
+#if defined(USE_DNS_CERT) && defined(USE_ADNS)
+# if HAVE_ADNS_IF_TORMODE
+   if (!*tor_credentials || new_circuit)
+     {
+       static unsigned int counter;
+
+       gpgrt_snprintf (tor_credentials, sizeof tor_credentials,
+                       "dirmngr-%lu:p%u",
+                       (unsigned long)getpid (), counter);
+       counter++;
+     }
+   tor_mode = 1;
+   return 0;
+# endif
+#endif
+
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
+/* Change the default IP address of the nameserver to IPADDR.  The
+   address needs to be a numerical IP address and will be used for the
+   next DNS query.  Note that this is only used in Tor mode.  */
+void
+set_dns_nameserver (const char *ipaddr)
+{
+  strncpy (tor_nameserver, ipaddr? ipaddr : DEFAULT_NAMESERVER,
+           sizeof tor_nameserver -1);
+  tor_nameserver[sizeof tor_nameserver -1] = 0;
+}
+
+
+/* Free an addressinfo linked list as returned by resolve_dns_name.  */
+void
+free_dns_addrinfo (dns_addrinfo_t ai)
+{
+  while (ai)
+    {
+      dns_addrinfo_t next = ai->next;
+      xfree (ai);
+      ai = next;
+    }
+}
+
+
+static gpg_error_t
+map_eai_to_gpg_error (int ec)
+{
+  gpg_error_t err;
+
+  switch (ec)
+    {
+    case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
+    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;
+    case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
+    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
+    case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
+    case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
+#endif
+    default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
+    }
+  return err;
+}
+
+
+#ifdef USE_ADNS
+/* Init ADNS and store the new state at R_STATE.  Returns 0 on
+   success; prints an error message and returns an error code on
+   failure.  */
+static gpg_error_t
+my_adns_init (adns_state *r_state)
+{
+  gpg_error_t err = 0;
+  int ret;
+
+  if (tor_mode)
+    {
+      char *cfgstr;
+
+      if (!*tor_nameserver)
+        set_dns_nameserver (NULL);
+
+      cfgstr = xtryasprintf ("nameserver %s\n"
+                             "options adns_tormode adns_sockscred:%s",
+                             tor_nameserver, tor_credentials);
+      if (!cfgstr)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          ret = adns_init_strcfg (r_state, adns_if_debug /*adns_if_noerrprint*/, NULL, cfgstr);
+          if (ret)
+            err = gpg_error_from_errno (ret);
+          xfree (cfgstr);
+        }
+    }
+  else
+    {
+      ret = adns_init (r_state, adns_if_noerrprint, NULL);
+      if (ret)
+        err = gpg_error_from_errno (ret);
+    }
+
+  if (err)
+    {
+      log_error ("error initializing adns: %s\n", gpg_strerror (err));
+      return err;
+    }
+  return 0;
+}
+#endif /*USE_ADNS*/
+
+
+#ifdef USE_ADNS
+/* Resolve a name using the ADNS library.  See resolve_dns_name for
+   the description.  */
+static gpg_error_t
+resolve_name_adns (const char *name, unsigned short port,
+                   int want_family, int want_socktype,
+                   dns_addrinfo_t *r_dai, char **r_canonname)
+{
+  gpg_error_t err = 0;
+  int ret;
+  dns_addrinfo_t daihead = NULL;
+  dns_addrinfo_t dai;
+  adns_state state;
+  adns_answer *answer = NULL;
+  int count;
+
+  (void)want_family;
+
+  *r_dai = NULL;
+  if (r_canonname)
+    *r_canonname = NULL;
+
+  if (want_socktype != SOCK_STREAM && want_socktype != SOCK_DGRAM)
+    return gpg_error (GPG_ERR_ESOCKTNOSUPPORT);
+
+  err = my_adns_init (&state);
+  if (err)
+    return err;
+
+  my_unprotect ();
+  ret = adns_synchronous (state, name, adns_r_addr,
+                          adns_qf_quoteok_query, &answer);
+  my_protect ();
+  if (ret)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("DNS query failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  err = gpg_error (GPG_ERR_NOT_FOUND);
+  if (answer->status != adns_s_ok || answer->type != adns_r_addr)
+    {
+      log_error ("DNS query returned an error: %s (%s)\n",
+                 adns_strerror (answer->status),
+                 adns_errabbrev (answer->status));
+      goto leave;
+    }
+
+  if (r_canonname && answer->cname)
+    {
+      *r_canonname = xtrystrdup (answer->cname);
+      if (!*r_canonname)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
+  for (count = 0; count < answer->nrrs; count++)
+    {
+      int len;
+      adns_rr_addr *addr;
+
+      len  = answer->rrs.addr[count].len;
+      addr = &answer->rrs.addr[count];
+      if (addr->addr.sa.sa_family != AF_INET6
+          && addr->addr.sa.sa_family != AF_INET)
+        continue;
+
+      dai = xtrymalloc (sizeof *dai + len - 1);
+      if (!dai)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      dai->family = addr->addr.sa.sa_family;
+      dai->socktype = want_socktype == SOCK_STREAM? SOCK_STREAM : SOCK_DGRAM;
+      dai->protocol = want_socktype == SOCK_STREAM? IPPROTO_TCP : IPPROTO_UDP;
+      dai->addrlen = len;
+      memcpy (dai->addr, &addr->addr.sa, len);
+      ((struct sockaddr_in *) dai->addr)->sin_port = htons (port);
+      dai->next = daihead;
+      daihead = dai;
+      err = 0;
+    }
+
+ leave:
+  adns_free (answer);
+  adns_finish (state);
+  if (err)
+    {
+      if (r_canonname)
+        {
+          xfree (*r_canonname);
+          *r_canonname = NULL;
+        }
+      free_dns_addrinfo (daihead);
+    }
+  else
+    *r_dai = daihead;
+  return err;
+}
+#endif /*USE_ADNS*/
+
+
+#ifndef USE_ADNS
+/* Resolve a name using the standard system function.  */
+static gpg_error_t
+resolve_name_standard (const char *name, unsigned short port,
+                       int want_family, int want_socktype,
+                       dns_addrinfo_t *r_dai, char **r_canonname)
+{
+  gpg_error_t err = 0;
+  dns_addrinfo_t daihead = NULL;
+  dns_addrinfo_t dai;
+  struct addrinfo *aibuf = NULL;
+  struct addrinfo hints, *ai;
+  char portstr[21];
+  int ret;
+
+  *r_dai = NULL;
+  if (r_canonname)
+    *r_canonname = NULL;
+
+  memset (&hints, 0, sizeof hints);
+  hints.ai_family = want_family;
+  hints.ai_socktype = want_socktype;
+  hints.ai_flags = AI_ADDRCONFIG;
+  if (r_canonname)
+    hints.ai_flags |= AI_CANONNAME;
+
+  if (port)
+    snprintf (portstr, sizeof portstr, "%hu", port);
+  else
+    *portstr = 0;
+
+  /* We can't use the the AI_IDN flag because that does the conversion
+     using the current locale.  However, GnuPG always used UTF-8.  To
+     support IDN we would need to make use of the libidn API.  */
+  ret = getaddrinfo (name, *portstr? portstr : NULL, &hints, &aibuf);
+  if (ret)
+    {
+      aibuf = NULL;
+      err = map_eai_to_gpg_error (ret);
+      if (gpg_err_code (err) == GPG_ERR_NO_NAME)
+        {
+          /* There seems to be a bug in the glibc getaddrinfo function
+             if the CNAME points to a long list of A and AAAA records
+             in which case the function return NO_NAME.  Let's do the
+             CNAME redirection again.  */
+          char *cname;
+
+          if (get_dns_cname (name, &cname))
+            goto leave; /* Still no success.  */
+
+          ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf);
+          xfree (cname);
+          if (ret)
+            {
+              aibuf = NULL;
+              err = map_eai_to_gpg_error (ret);
+              goto leave;
+            }
+          err = 0; /* Yep, now it worked.  */
+        }
+      else
+        goto leave;
+    }
+
+  if (r_canonname && aibuf && aibuf->ai_canonname)
+    {
+      *r_canonname = xtrystrdup (aibuf->ai_canonname);
+      if (!*r_canonname)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
+  for (ai = aibuf; ai; ai = ai->ai_next)
+    {
+      if (ai->ai_family != AF_INET6 && ai->ai_family != AF_INET)
+        continue;
+
+      dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
+      dai->family = ai->ai_family;
+      dai->socktype = ai->ai_socktype;
+      dai->protocol = ai->ai_protocol;
+      dai->addrlen = ai->ai_addrlen;
+      memcpy (dai->addr, ai->ai_addr, ai->ai_addrlen);
+      dai->next = daihead;
+      daihead = dai;
+    }
+
+ leave:
+  if (aibuf)
+    freeaddrinfo (aibuf);
+  if (err)
+    {
+      if (r_canonname)
+        {
+          xfree (*r_canonname);
+          *r_canonname = NULL;
+        }
+      free_dns_addrinfo (daihead);
+    }
+  else
+    *r_dai = daihead;
+  return err;
+}
+#endif /*!USE_ADNS*/
+
+
+/* Resolve an address using the standard system function.  */
+static gpg_error_t
+resolve_addr_standard (const struct sockaddr *addr, int addrlen,
+                       unsigned int flags, char **r_name)
+{
+  gpg_error_t err;
+  int ec;
+  char *buffer, *p;
+  int buflen;
+
+  *r_name = NULL;
+
+  buflen = NI_MAXHOST;
+  buffer = xtrymalloc (buflen + 2 + 1);
+  if (!buffer)
+    return gpg_error_from_syserror ();
+
+  if ((flags & DNS_NUMERICHOST) || tor_mode)
+    ec = EAI_NONAME;
+  else
+    ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
+
+  if (!ec && *buffer == '[')
+    ec = EAI_FAIL;  /* A name may never start with a bracket.  */
+  else if (ec == EAI_NONAME)
+    {
+      p = buffer;
+      if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+        {
+          *p++ = '[';
+          buflen -= 2;
+        }
+      ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
+      if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+        strcat (buffer, "]");
+    }
+
+  if (ec)
+    err = map_eai_to_gpg_error (ec);
+  else
+    {
+      p = xtryrealloc (buffer, strlen (buffer)+1);
+      if (!p)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          buffer = p;
+          err = 0;
+        }
+    }
+
+  if (err)
+    xfree (buffer);
+  else
+    *r_name = buffer;
+
+  return err;
+}
+
+
+/* This a wrapper around getaddrinfo with slightly different semantics.
+   NAME is the name to resolve.
+   PORT is the requested port or 0.
+   WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
+   WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
+
+   On success the result is stored in a linked list with the head
+   stored at the address R_AI; the caller must call gpg_addrinfo_free
+   on this.  If R_CANONNAME is not NULL the official name of the host
+   is stored there as a malloced string; if that name is not available
+   NULL is stored.  */
+gpg_error_t
+resolve_dns_name (const char *name, unsigned short port,
+                  int want_family, int want_socktype,
+                  dns_addrinfo_t *r_ai, char **r_canonname)
+{
+#ifdef USE_ADNS
+  return resolve_name_adns (name, port, want_family, want_socktype,
+                            r_ai, r_canonname);
+#else
+  return resolve_name_standard (name, port, want_family, want_socktype,
+                                r_ai, r_canonname);
+#endif
+}
+
+
+gpg_error_t
+resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+                  unsigned int flags, char **r_name)
+{
+#ifdef USE_ADNS_disabled_for_now
+  return resolve_addr_adns (addr, addrlen, flags, r_name);
+#else
+  return resolve_addr_standard (addr, addrlen, flags, r_name);
+#endif
+}
+
+
+/* Check whether NAME is an IP address.  Returns true if it is either
+   an IPv6 or IPv4 numerical address.  */
+int
+is_ip_address (const char *name)
+{
+  const char *s;
+  int ndots, dblcol, n;
+
+  if (*name == '[')
+    return 1; /* yes: A legal DNS name may not contain this character;
+                 this mut be bracketed v6 address.  */
+  if (*name == '.')
+    return 0; /* No.  A leading dot is not a valid IP address.  */
+
+  /* Check whether this is a v6 address.  */
+  ndots = n = dblcol = 0;
+  for (s=name; *s; s++)
+    {
+      if (*s == ':')
+        {
+          ndots++;
+          if (s[1] == ':')
+            {
+              ndots++;
+              if (dblcol)
+                return 0; /* No: Only one "::" allowed.  */
+              dblcol++;
+              if (s[1])
+                s++;
+            }
+          n = 0;
+        }
+      else if (*s == '.')
+        goto legacy;
+      else if (!strchr ("0123456789abcdefABCDEF", *s))
+        return 0; /* No: Not a hex digit.  */
+      else if (++n > 4)
+        return 0; /* To many digits in a group.  */
+    }
+  if (ndots > 7)
+    return 0; /* No: Too many colons.  */
+  else if (ndots > 1)
+    return 1; /* Yes: At least 2 colons indicate an v6 address.  */
+
+ legacy:
+  /* Check whether it is legacy IP address.  */
+  ndots = n = 0;
+  for (s=name; *s; s++)
+    {
+      if (*s == '.')
+        {
+          if (s[1] == '.')
+            return 0; /* No:  Douple dot. */
+          if (atoi (s+1) > 255)
+            return 0; /* No:  Ipv4 byte value too large.  */
+          ndots++;
+          n = 0;
+        }
+      else if (!strchr ("0123456789", *s))
+        return 0; /* No: Not a digit.  */
+      else if (++n > 3)
+        return 0; /* No: More than 3 digits.  */
+    }
+  return !!(ndots == 3);
+}
+
+
+/* Return true if NAME is an onion address.  */
+int
+is_onion_address (const char *name)
+{
+  size_t len;
+
+  len = name? strlen (name) : 0;
+  if (len < 8 || strcmp (name + len - 6, ".onion"))
+    return 0;
+  /* Note that we require at least 2 characters before the suffix.  */
+  return 1;  /* Yes.  */
+}
+
+
+/* Returns 0 on success or an error code.  If a PGP CERT record was
+   found, the malloced data is returned at (R_KEY, R_KEYLEN) and
+   the other return parameters are set to NULL/0.  If an IPGP CERT
+   record was found the fingerprint is stored as an allocated block at
+   R_FPR and its length at R_FPRLEN; an URL is is allocated as a
+   string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
+   returns the first CERT found with a supported type; it is expected
+   that only one CERT record is used.  If WANT_CERTTYPE is one of the
+   supported certtypes only records with this certtype are considered
+   and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
+gpg_error_t
+get_dns_cert (const char *name, int want_certtype,
+              void **r_key, size_t *r_keylen,
+              unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
+{
+#ifdef USE_DNS_CERT
+#ifdef USE_ADNS
+  gpg_error_t err;
+  int ret;
+  adns_state state;
+  adns_answer *answer = NULL;
+  unsigned int ctype;
+  int count;
+
+  if (r_key)
+    *r_key = NULL;
+  if (r_keylen)
+    *r_keylen = 0;
+  *r_fpr = NULL;
+  *r_fprlen = 0;
+  *r_url = NULL;
+
+  err = my_adns_init (&state);
+  if (err)
+    return err;
+
+  my_unprotect ();
+  ret = adns_synchronous (state, name,
+                          (adns_r_unknown
+                           | (want_certtype < DNS_CERTTYPE_RRBASE
+                              ? my_adns_r_cert
+                              : (want_certtype - DNS_CERTTYPE_RRBASE))),
+                          adns_qf_quoteok_query, &answer);
+  my_protect ();
+  if (ret)
+    {
+      err = gpg_error_from_syserror ();
+      /* log_error ("DNS query failed: %s\n", strerror (errno)); */
+      adns_finish (state);
+      return err;
+    }
+  if (answer->status != adns_s_ok)
+    {
+      /* log_error ("DNS query returned an error: %s (%s)\n", */
+      /*            adns_strerror (answer->status), */
+      /*            adns_errabbrev (answer->status)); */
+      err = gpg_error (GPG_ERR_NOT_FOUND);
+      goto leave;
+    }
+
+  err = gpg_error (GPG_ERR_NOT_FOUND);
+  for (count = 0; count < answer->nrrs; count++)
+    {
+      int datalen = answer->rrs.byteblock[count].len;
+      const unsigned char *data = answer->rrs.byteblock[count].data;
+
+      /* First check for our generic RR hack.  */
+      if (datalen
+          && want_certtype >= DNS_CERTTYPE_RRBASE
+          && ((want_certtype - DNS_CERTTYPE_RRBASE)
+              == (answer->type & ~adns_r_unknown)))
+        {
+          /* Found the requested record - return it.  */
+          *r_key = xtrymalloc (datalen);
+          if (!*r_key)
+            err = gpg_error_from_syserror ();
+          else
+            {
+              memcpy (*r_key, data, datalen);
+              *r_keylen = datalen;
+              err = 0;
+            }
+          goto leave;
+        }
+
+      if (datalen < 5)
+        continue;  /* Truncated CERT record - skip.  */
+
+      ctype = buf16_to_uint (data);
+      /* (key tag and algorithm fields are not required.) */
+      data += 5;
+      datalen -= 5;
+
+      if (want_certtype && want_certtype != ctype)
+        ; /* Not of the requested certtype.  */
+      else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
+        {
+          /* CERT type is PGP.  Gpg checks for a minimum length of 11,
+             thus we do the same.  */
+          *r_key = xtrymalloc (datalen);
+          if (!*r_key)
+            err = gpg_error_from_syserror ();
+          else
+            {
+              memcpy (*r_key, data, datalen);
+              *r_keylen = datalen;
+              err = 0;
+            }
+          goto leave;
+        }
+      else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
+               && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
+        {
+          /* CERT type is IPGP.  We made sure that the data is
+             plausible and that the caller requested this
+             information.  */
+          *r_fprlen = data[0];
+          if (*r_fprlen)
+            {
+              *r_fpr = xtrymalloc (*r_fprlen);
+              if (!*r_fpr)
+                {
+                  err = gpg_error_from_syserror ();
+                  goto leave;
+                }
+              memcpy (*r_fpr, data + 1, *r_fprlen);
+            }
+          else
+            *r_fpr = NULL;
+
+          if (datalen > *r_fprlen + 1)
+            {
+              *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
+              if (!*r_url)
+                {
+                  err = gpg_error_from_syserror ();
+                  xfree (*r_fpr);
+                  *r_fpr = NULL;
+                  goto leave;
+                }
+              memcpy (*r_url,
+                      data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
+              (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
+            }
+          else
+            *r_url = NULL;
+
+          err = 0;
+          goto leave;
+        }
+    }
+
+ leave:
+  adns_free (answer);
+  adns_finish (state);
+  return err;
+
+#else /*!USE_ADNS*/
+
+  gpg_error_t err;
+  unsigned char *answer;
+  int r;
+  u16 count;
+
+  if (r_key)
+    *r_key = NULL;
+  if (r_keylen)
+    *r_keylen = 0;
+  *r_fpr = NULL;
+  *r_fprlen = 0;
+  *r_url = NULL;
+
+  /* Allocate a 64k buffer which is the limit for an DNS response.  */
+  answer = xtrymalloc (65536);
+  if (!answer)
+    return gpg_error_from_syserror ();
+
+  err = gpg_error (GPG_ERR_NOT_FOUND);
+  r = res_query (name, C_IN,
+                 (want_certtype < DNS_CERTTYPE_RRBASE
+                  ? T_CERT
+                  : (want_certtype - DNS_CERTTYPE_RRBASE)),
+                 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)))
+    {
+      int rc;
+      unsigned char *pt, *emsg;
+
+      emsg = &answer[r];
+
+      pt = &answer[sizeof (HEADER)];
+
+      /* Skip over the query */
+
+      rc = dn_skipname (pt, emsg);
+      if (rc == -1)
+        {
+          err = gpg_error (GPG_ERR_INV_OBJ);
+          goto leave;
+        }
+      pt += rc + QFIXEDSZ;
+
+      /* There are several possible response types for a CERT request.
+         We're interested in the PGP (a key) and IPGP (a URI) types.
+         Skip all others.  TODO: A key is better than a URI since
+         we've gone through all this bother to fetch it, so favor that
+         if we have both PGP and IPGP? */
+
+      while (count-- > 0 && pt < emsg)
+        {
+          u16 type, class, dlen, ctype;
+
+          rc = dn_skipname (pt, emsg);  /* the name we just queried for */
+          if (rc == -1)
+            {
+              err = gpg_error (GPG_ERR_INV_OBJ);
+              goto leave;
+            }
+
+          pt += rc;
+
+          /* Truncated message? 15 bytes takes us to the point where
+             we start looking at the ctype. */
+          if ((emsg - pt) < 15)
+            break;
+
+          type = buf16_to_u16 (pt);
+          pt += 2;
+
+          class = buf16_to_u16 (pt);
+          pt += 2;
+
+          if (class != C_IN)
+            break;
+
+          /* ttl */
+          pt += 4;
+
+          /* data length */
+          dlen = buf16_to_u16 (pt);
+          pt += 2;
+
+          /* Check the type and parse.  */
+          if (want_certtype >= DNS_CERTTYPE_RRBASE
+              && type == (want_certtype - DNS_CERTTYPE_RRBASE)
+              && r_key)
+            {
+              *r_key = xtrymalloc (dlen);
+              if (!*r_key)
+                err = gpg_error_from_syserror ();
+              else
+                {
+                  memcpy (*r_key, pt, dlen);
+                  *r_keylen = dlen;
+                  err = 0;
+                }
+              goto leave;
+            }
+          else if (want_certtype >= DNS_CERTTYPE_RRBASE)
+            {
+              /* We did not found the requested RR.  */
+              pt += dlen;
+            }
+          else if (type == T_CERT)
+            {
+              /* We got a CERT type.   */
+              ctype = buf16_to_u16 (pt);
+              pt += 2;
+
+              /* Skip the CERT key tag and algo which we don't need. */
+              pt += 3;
+
+              dlen -= 5;
+
+              /* 15 bytes takes us to here */
+              if (want_certtype && want_certtype != ctype)
+                ; /* Not of the requested certtype.  */
+              else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
+                {
+                  /* PGP type */
+                  *r_key = xtrymalloc (dlen);
+                  if (!*r_key)
+                    err = gpg_error_from_syserror ();
+                  else
+                    {
+                      memcpy (*r_key, pt, dlen);
+                      *r_keylen = dlen;
+                      err = 0;
+                    }
+                  goto leave;
+                }
+              else if (ctype == DNS_CERTTYPE_IPGP
+                       && dlen && dlen < 1023 && dlen >= pt[0] + 1)
+                {
+                  /* IPGP type */
+                  *r_fprlen = pt[0];
+                  if (*r_fprlen)
+                    {
+                      *r_fpr = xtrymalloc (*r_fprlen);
+                      if (!*r_fpr)
+                        {
+                          err = gpg_error_from_syserror ();
+                          goto leave;
+                        }
+                      memcpy (*r_fpr, &pt[1], *r_fprlen);
+                    }
+                  else
+                    *r_fpr = NULL;
+
+                  if (dlen > *r_fprlen + 1)
+                    {
+                      *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
+                      if (!*r_fpr)
+                        {
+                          err = gpg_error_from_syserror ();
+                          xfree (*r_fpr);
+                          *r_fpr = NULL;
+                          goto leave;
+                        }
+                      memcpy (*r_url, &pt[*r_fprlen + 1],
+                              dlen - (*r_fprlen + 1));
+                      (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
+                    }
+                  else
+                    *r_url = NULL;
+
+                  err = 0;
+                  goto leave;
+                }
+
+              /* No subtype matches, so continue with the next answer. */
+              pt += dlen;
+            }
+          else
+            {
+              /* Not a requested type - might be a CNAME. Try next item.  */
+              pt += dlen;
+            }
+        }
+    }
+
+ leave:
+  xfree (answer);
+  return err;
+
+#endif /*!USE_ADNS */
+#else /* !USE_DNS_CERT */
+  (void)name;
+  if (r_key)
+    *r_key = NULL;
+  if (r_keylen)
+    *r_keylen = NULL;
+  *r_fpr = NULL;
+  *r_fprlen = 0;
+  *r_url = NULL;
+
+  return gpg_error (GPG_ERR_NOT_SUPPORTED);
+#endif
+}
+
+#ifdef USE_DNS_SRV
+static int
+priosort(const void *a,const void *b)
+{
+  const struct srventry *sa=a,*sb=b;
+  if(sa->priority>sb->priority)
+    return 1;
+  else if(sa->priority<sb->priority)
+    return -1;
+  else
+    return 0;
+}
+
+
+int
+getsrv (const char *name,struct srventry **list)
+{
+  int srvcount=0;
+  u16 count;
+  int i, rc;
+
+  *list = NULL;
+
+#ifdef USE_ADNS
+  {
+    adns_state state;
+    adns_answer *answer = NULL;
+
+    if (my_adns_init (&state))
+      return -1;
+
+    my_unprotect ();
+    rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
+                           &answer);
+    my_protect ();
+    if (rc)
+      {
+        log_error ("DNS query failed: %s\n", strerror (errno));
+        adns_finish (state);
+        return -1;
+      }
+    if (answer->status != adns_s_ok
+        || answer->type != adns_r_srv || !answer->nrrs)
+      {
+        log_error ("DNS query returned an error or no records: %s (%s)\n",
+                   adns_strerror (answer->status),
+                   adns_errabbrev (answer->status));
+        adns_free (answer);
+        adns_finish (state);
+        return 0;
+      }
+
+    for (count = 0; count < answer->nrrs; count++)
+      {
+        struct srventry *srv = NULL;
+        struct srventry *newlist;
+
+        if (strlen (answer->rrs.srvha[count].ha.host) >= sizeof srv->target)
+          {
+            log_info ("hostname in SRV record too long - skipped\n");
+            continue;
+          }
+
+        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
+        if (!newlist)
+          goto fail;
+        *list = newlist;
+        memset (&(*list)[srvcount], 0, sizeof(struct srventry));
+        srv = &(*list)[srvcount];
+        srvcount++;
+
+        srv->priority = answer->rrs.srvha[count].priority;
+        srv->weight   = answer->rrs.srvha[count].weight;
+        srv->port     = answer->rrs.srvha[count].port;
+        strcpy (srv->target, answer->rrs.srvha[count].ha.host);
+      }
+
+    adns_free (answer);
+    adns_finish (state);
+  }
+#else /*!USE_ADNS*/
+  {
+    unsigned char answer[2048];
+    HEADER *header = (HEADER *)answer;
+    unsigned char *pt, *emsg;
+    int r;
+    u16 dlen;
+
+    /* Do not allow a query using the standard resolver in Tor mode.  */
+    if (tor_mode)
+      return -1;
+
+    r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
+    if (r < sizeof (HEADER) || r > sizeof answer
+        || header->rcode != NOERROR || !(count=ntohs (header->ancount)))
+      return 0; /* Error or no record found.  */
+
+    emsg = &answer[r];
+    pt = &answer[sizeof(HEADER)];
+
+    /* Skip over the query */
+    rc = dn_skipname (pt, emsg);
+    if (rc == -1)
+      goto fail;
+
+    pt += rc + QFIXEDSZ;
+
+    while (count-- > 0 && pt < emsg)
+      {
+        struct srventry *srv=NULL;
+        u16 type,class;
+        struct srventry *newlist;
+
+        newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
+        if (!newlist)
+          goto fail;
+        *list = newlist;
+        memset(&(*list)[srvcount],0,sizeof(struct srventry));
+        srv=&(*list)[srvcount];
+        srvcount++;
+
+        rc = dn_skipname(pt,emsg); /* the name we just queried for */
+        if (rc == -1)
+          goto fail;
+        pt+=rc;
+
+        /* Truncated message? */
+        if((emsg-pt)<16)
+          goto fail;
+
+        type = buf16_to_u16 (pt);
+        pt += 2;
+        /* We asked for SRV and got something else !? */
+        if(type!=T_SRV)
+          goto fail;
+
+        class = buf16_to_u16 (pt);
+        pt += 2;
+        /* We asked for IN and got something else !? */
+        if(class!=C_IN)
+          goto fail;
+
+        pt += 4; /* ttl */
+        dlen = buf16_to_u16 (pt);
+        pt += 2;
+
+        srv->priority = buf16_to_ushort (pt);
+        pt += 2;
+        srv->weight = buf16_to_ushort (pt);
+        pt += 2;
+        srv->port = buf16_to_ushort (pt);
+        pt += 2;
+
+        /* Get the name.  2782 doesn't allow name compression, but
+           dn_expand still works to pull the name out of the
+           packet. */
+        rc = dn_expand(answer,emsg,pt,srv->target, sizeof srv->target);
+        if (rc == 1 && srv->target[0] == 0) /* "." */
+          {
+            xfree(*list);
+            *list = NULL;
+            return 0;
+          }
+        if (rc == -1)
+          goto fail;
+        pt += rc;
+        /* Corrupt packet? */
+        if (dlen != rc+6)
+          goto fail;
+      }
+  }
+#endif /*!USE_ADNS*/
+
+  /* Now we have an array of all the srv records. */
+
+  /* Order by priority */
+  qsort(*list,srvcount,sizeof(struct srventry),priosort);
+
+  /* For each priority, move the zero-weighted items first. */
+  for (i=0; i < srvcount; i++)
+    {
+      int j;
+
+      for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
+        {
+          if((*list)[j].weight==0)
+            {
+              /* Swap j with i */
+              if(j!=i)
+                {
+                  struct srventry temp;
+
+                  memcpy (&temp,&(*list)[j],sizeof(struct srventry));
+                  memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
+                  memcpy (&(*list)[i],&temp,sizeof(struct srventry));
+                }
+
+              break;
+            }
+        }
+    }
+
+  /* Run the RFC-2782 weighting algorithm.  We don't need very high
+     quality randomness for this, so regular libc srand/rand is
+     sufficient.  */
+
+  {
+    static int done;
+    if (!done)
+      {
+        done = 1;
+        srand (time (NULL)*getpid());
+      }
+  }
+
+  for (i=0; i < srvcount; i++)
+    {
+      int j;
+      float prio_count=0,chose;
+
+      for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
+        {
+          prio_count+=(*list)[j].weight;
+          (*list)[j].run_count=prio_count;
+        }
+
+      chose=prio_count*rand()/RAND_MAX;
+
+      for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
+        {
+          if (chose<=(*list)[j].run_count)
+            {
+              /* Swap j with i */
+              if(j!=i)
+                {
+                  struct srventry temp;
+
+                  memcpy(&temp,&(*list)[j],sizeof(struct srventry));
+                  memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
+                  memcpy(&(*list)[i],&temp,sizeof(struct srventry));
+                }
+              break;
+            }
+        }
+    }
+
+  return srvcount;
+
+ fail:
+  xfree(*list);
+  *list=NULL;
+  return -1;
+}
+#endif /*USE_DNS_SRV*/
+
+
+gpg_error_t
+get_dns_cname (const char *name, char **r_cname)
+{
+  gpg_error_t err;
+  int rc;
+
+  *r_cname = NULL;
+
+#ifdef USE_ADNS
+  {
+    adns_state state;
+    adns_answer *answer = NULL;
+
+    if (my_adns_init (&state))
+      return gpg_error (GPG_ERR_GENERAL);
+
+    my_unprotect ();
+    rc = adns_synchronous (state, name, adns_r_cname, adns_qf_quoteok_query,
+                           &answer);
+    my_protect ();
+    if (rc)
+      {
+        err = gpg_error_from_syserror ();
+        log_error ("DNS query failed: %s\n", gpg_strerror (err));
+        adns_finish (state);
+        return err;
+      }
+    if (answer->status != adns_s_ok
+        || answer->type != adns_r_cname || answer->nrrs != 1)
+      {
+        err = gpg_error (GPG_ERR_GENERAL);
+        log_error ("DNS query returned an error or no records: %s (%s)\n",
+                   adns_strerror (answer->status),
+                   adns_errabbrev (answer->status));
+        adns_free (answer);
+        adns_finish (state);
+        return err;
+      }
+    *r_cname = xtrystrdup (answer->rrs.str[0]);
+    if (!*r_cname)
+      err = gpg_error_from_syserror ();
+    else
+      err = 0;
+
+    adns_free (answer);
+    adns_finish (state);
+    return err;
+  }
+#else /*!USE_ADNS*/
+  {
+    unsigned char answer[2048];
+    HEADER *header = (HEADER *)answer;
+    unsigned char *pt, *emsg;
+    int r;
+    char *cname;
+    int cnamesize = 1025;
+    u16 count;
+
+    /* Do not allow a query using the standard resolver in Tor mode.  */
+    if (tor_mode)
+      return -1;
+
+    r = res_query (name, C_IN, T_CERT, answer, sizeof answer);
+    if (r < sizeof (HEADER) || r > sizeof answer)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+    if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
+      return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found.  */
+    if (count != 1)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+
+    emsg = &answer[r];
+    pt = &answer[sizeof(HEADER)];
+    rc = dn_skipname (pt, emsg);
+    if (rc == -1)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+
+    pt += rc + QFIXEDSZ;
+    if (pt >= emsg)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+
+    rc = dn_skipname (pt, emsg);
+    if (rc == -1)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+    pt += rc + 2 + 2 + 4;
+    if (pt+2 >= emsg)
+      return gpg_error (GPG_ERR_SERVER_FAILED);
+    pt += 2;  /* Skip rdlen */
+
+    cname = xtrymalloc (cnamesize);
+    if (!cname)
+      return gpg_error_from_syserror ();
+
+    rc = dn_expand (answer, emsg, pt, cname, cnamesize -1);
+    if (rc == -1)
+      {
+        xfree (cname);
+        return gpg_error (GPG_ERR_SERVER_FAILED);
+      }
+    *r_cname = xtryrealloc (cname, strlen (cname)+1);
+    if (!*r_cname)
+      {
+        err = gpg_error_from_syserror ();
+        xfree (cname);
+        return err;
+      }
+    return 0;
+  }
+#endif /*!USE_ADNS*/
+}
diff --git a/dirmngr/dns-stuff.h b/dirmngr/dns-stuff.h
new file mode 100644 (file)
index 0000000..ee5132d
--- /dev/null
@@ -0,0 +1,135 @@
+/* dns-stuff.c - DNS related code including CERT RR (rfc-4398)
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2006, 2015 Werner Koch
+ *
+ * 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_DIRMNGR_DNS_STUFF_H
+#define GNUPG_DIRMNGR_DNS_STUFF_H
+
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <windows.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+#endif
+
+/*
+ * Flags used with resolve_dns_addr.
+ */
+#define DNS_NUMERICHOST        1  /* Force numeric output format.  */
+#define DNS_WITHBRACKET        2  /* Put brackets around numeric v6
+                                     addresses.  */
+
+/*
+ * Constants for use with get_dns_cert.
+ */
+#define DNS_CERTTYPE_ANY       0 /* Internal catch all type. */
+/* Certificate types according to RFC-4398:  */
+#define DNS_CERTTYPE_PKIX      1 /* X.509 as per PKIX. */
+#define DNS_CERTTYPE_SPKI      2 /* SPKI certificate.  */
+#define DNS_CERTTYPE_PGP       3 /* OpenPGP packet.  */
+#define DNS_CERTTYPE_IPKIX     4 /* The URL of an X.509 data object. */
+#define DNS_CERTTYPE_ISPKI     5 /* The URL of an SPKI certificate.  */
+#define DNS_CERTTYPE_IPGP      6 /* The fingerprint
+                                    and URL of an OpenPGP packet.  */
+#define DNS_CERTTYPE_ACPKIX    7 /* Attribute Certificate.  */
+#define DNS_CERTTYPE_IACPKIX   8 /* The URL of an Attribute Certificate.  */
+#define DNS_CERTTYPE_URI     253 /* URI private.  */
+#define DNS_CERTTYPE_OID     254 /* OID private.  */
+/* Hacks for our implementation.  */
+#define DNS_CERTTYPE_RRBASE 1024 /* Base of special constants.  */
+#define DNS_CERTTYPE_RR61   (DNS_CERTTYPE_RRBASE + 61)
+
+
+
+struct dns_addrinfo_s;
+typedef struct dns_addrinfo_s *dns_addrinfo_t;
+struct dns_addrinfo_s
+{
+  dns_addrinfo_t next;
+  int family;
+  int socktype;
+  int protocol;
+  int addrlen;
+  struct sockaddr addr[1];
+};
+
+
+struct srventry
+{
+  unsigned short priority;
+  unsigned short weight;
+  unsigned short port;
+  int run_count;
+  char target[1025];
+};
+
+
+/* Calling this function switches the DNS code into Tor mode if
+   possibe.  Return 0 on success.  */
+gpg_error_t enable_dns_tormode (int new_circuit);
+
+/* Change the default IP address of the nameserver to IPADDR.  The
+   address needs to be a numerical IP address and will be used for the
+   next DNS query.  Note that this is only used in Tor mode.  */
+void set_dns_nameserver (const char *ipaddr);
+
+
+void free_dns_addrinfo (dns_addrinfo_t ai);
+
+/* Function similar to getaddrinfo.  */
+gpg_error_t resolve_dns_name (const char *name, unsigned short port,
+                              int want_family, int want_socktype,
+                              dns_addrinfo_t *r_dai, char **r_canonname);
+
+/* Function similar to getnameinfo.  */
+gpg_error_t resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+                              unsigned int flags, char **r_name);
+
+/* Return true if NAME is a numerical IP address.  */
+int is_ip_address (const char *name);
+
+/* Return true if NAME is an onion address.  */
+int is_onion_address (const char *name);
+
+/* Get the canonical name for NAME.  */
+gpg_error_t get_dns_cname (const char *name, char **r_cname);
+
+/* Return a CERT record or an arbitray RR.  */
+gpg_error_t get_dns_cert (const char *name, int want_certtype,
+                          void **r_key, size_t *r_keylen,
+                          unsigned char **r_fpr, size_t *r_fprlen,
+                          char **r_url);
+
+
+int getsrv (const char *name,struct srventry **list);
+
+
+#endif /*GNUPG_DIRMNGR_DNS_STUFF_H*/
similarity index 90%
rename from common/http.c
rename to dirmngr/http.c
index edd8a6d..74b6911 100644 (file)
 # include <gnutls/x509.h>
 #endif /*HTTP_USE_GNUTLS*/
 
+#include <assuan.h>  /* We need the socket wrapper.  */
 
 #include "util.h"
 #include "i18n.h"
+#include "dns-stuff.h"
 #include "http.h"
-#ifdef USE_DNS_SRV
-# include "srv.h"
-#else /*!USE_DNS_SRV*/
-  /* If we are not compiling with SRV record support we provide stub
-     data structures. */
-# ifndef MAXDNAME
-#  define MAXDNAME 1025
-# endif
-struct srventry
-{
-  unsigned short priority;
-  unsigned short weight;
-  unsigned short port;
-  int run_count;
-  char target[MAXDNAME];
-};
-#endif/*!USE_DNS_SRV*/
 
 
 #ifdef USE_NPTH
 # define my_select(a,b,c,d,e)  npth_select ((a), (b), (c), (d), (e))
-# define my_connect(a,b,c)     npth_connect ((a), (b), (c))
 # define my_accept(a,b,c)      npth_accept ((a), (b), (c))
 #else
 # define my_select(a,b,c,d,e)  select ((a), (b), (c), (d), (e))
-# define my_connect(a,b,c)     connect ((a), (b), (c))
 # define my_accept(a,b,c)      accept ((a), (b), (c))
 #endif
 
@@ -181,21 +164,22 @@ static gpg_error_t send_request (http_t hd, const char *httphost,
 static char *build_rel_path (parsed_uri_t uri);
 static gpg_error_t parse_response (http_t hd);
 
-static int connect_server (const char *server, unsigned short port,
-                           unsigned int flags, const char *srvtag,
-                           int *r_host_not_found);
+static assuan_fd_t connect_server (const char *server, unsigned short port,
+                                   unsigned int flags, const char *srvtag,
+                                   int *r_host_not_found);
 static gpg_error_t write_server (int sock, const char *data, size_t length);
 
-static ssize_t cookie_read (void *cookie, void *buffer, size_t size);
-static ssize_t cookie_write (void *cookie, const void *buffer, size_t size);
+static gpgrt_ssize_t cookie_read (void *cookie, void *buffer, size_t size);
+static gpgrt_ssize_t cookie_write (void *cookie,
+                                   const void *buffer, size_t size);
 static int cookie_close (void *cookie);
 
 
 /* A socket object used to a allow ref counting of sockets.  */
 struct my_socket_s
 {
-  int fd;       /* The actual socket - shall never be -1.  */
-  int refcount; /* Number of references to this socket.  */
+  assuan_fd_t fd; /* The actual socket - shall never be ASSUAN_INVALID_FD.  */
+  int refcount;   /* Number of references to this socket.  */
 };
 typedef struct my_socket_s *my_socket_t;
 
@@ -280,7 +264,7 @@ struct http_context_s
 };
 
 
-/* The global callback for the verification fucntion.  */
+/* The global callback for the verification function.  */
 static gpg_error_t (*tls_callback) (http_t, http_session_t, int);
 
 /* The list of files with trusted CA certificates.  */
@@ -338,7 +322,7 @@ init_sockets (void)
 /* Create a new socket object.  Returns NULL and closes FD if not
    enough memory is available.  */
 static my_socket_t
-_my_socket_new (int lnr, int fd)
+_my_socket_new (int lnr, assuan_fd_t fd)
 {
   my_socket_t so;
 
@@ -346,7 +330,7 @@ _my_socket_new (int lnr, int fd)
   if (!so)
     {
       int save_errno = errno;
-      sock_close (fd);
+      assuan_sock_close (fd);
       gpg_err_set_errno (save_errno);
       return NULL;
     }
@@ -389,7 +373,7 @@ _my_socket_unref (int lnr, my_socket_t so,
         {
           if (preclose)
             preclose (preclosearg);
-          sock_close (so->fd);
+          assuan_sock_close (so->fd);
           xfree (so);
         }
     }
@@ -397,20 +381,28 @@ _my_socket_unref (int lnr, my_socket_t so,
 #define my_socket_unref(a,b,c) _my_socket_unref (__LINE__,(a),(b),(c))
 
 
-#if defined (USE_NPTH) && defined(HTTP_USE_GNUTLS)
+#ifdef HTTP_USE_GNUTLS
 static ssize_t
-my_npth_read (gnutls_transport_ptr_t ptr, void *buffer, size_t size)
+my_gnutls_read (gnutls_transport_ptr_t ptr, void *buffer, size_t size)
 {
   my_socket_t sock = ptr;
+#if USE_NPTH
   return npth_read (sock->fd, buffer, size);
+#else
+  return read (sock->fd, buffer, size);
+#endif
 }
 static ssize_t
-my_npth_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
+my_gnutls_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
 {
   my_socket_t sock = ptr;
+#if USE_NPTH
   return npth_write (sock->fd, buffer, size);
+#else
+  return write (sock->fd, buffer, size);
+#endif
 }
-#endif /*USE_NPTH && HTTP_USE_GNUTLS*/
+#endif /*HTTP_USE_GNUTLS*/
 
 
 
@@ -516,6 +508,27 @@ http_register_tls_ca (const char *fname)
 }
 
 
+#ifdef USE_TLS
+/* Free the TLS session associated with SESS, if any.  */
+static void
+close_tls_session (http_session_t sess)
+{
+  if (sess->tls_session)
+    {
+# ifdef HTTP_USE_GNUTLS
+      my_socket_t sock = gnutls_transport_get_ptr (sess->tls_session);
+      my_socket_unref (sock, NULL, NULL);
+      gnutls_deinit (sess->tls_session);
+      if (sess->certcred)
+        gnutls_certificate_free_credentials (sess->certcred);
+# endif /*HTTP_USE_GNUTLS*/
+      xfree (sess->servername);
+      sess->tls_session = NULL;
+    }
+}
+#endif /*USE_TLS*/
+
+
 /* Release a session.  Take care not to release it while it is being
    used by a http context object.  */
 static void
@@ -532,17 +545,7 @@ session_unref (int lnr, http_session_t sess)
     return;
 
 #ifdef USE_TLS
-# ifdef HTTP_USE_GNUTLS
-  if (sess->tls_session)
-    {
-      my_socket_t sock = gnutls_transport_get_ptr (sess->tls_session);
-      my_socket_unref (sock, NULL, NULL);
-      gnutls_deinit (sess->tls_session);
-    }
-  if (sess->certcred)
-    gnutls_certificate_free_credentials (sess->certcred);
-# endif /*HTTP_USE_GNUTLS*/
-  xfree (sess->servername);
+  close_tls_session (sess);
 #endif /*USE_TLS*/
 
   xfree (sess);
@@ -740,7 +743,6 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
                   unsigned int flags, const char *srvtag)
 {
   gpg_error_t err = 0;
-  int sock;
   http_t hd;
   cookie_t cookie;
   int hnf;
@@ -749,8 +751,13 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
 
   if ((flags & HTTP_FLAG_FORCE_TOR))
     {
-      log_error ("TOR support is not yet available\n");
-      return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
+      int mode;
+
+      if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
+        {
+          log_error ("Tor support is not available\n");
+          return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
+        }
     }
 
   /* Create the handle. */
@@ -761,22 +768,26 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
   hd->flags = flags;
 
   /* Connect.  */
-  sock = connect_server (server, port, hd->flags, srvtag, &hnf);
-  if (sock == -1)
-    {
-      err = gpg_err_make (default_errsource,
-                          (hnf? GPG_ERR_UNKNOWN_HOST
-                              : gpg_err_code_from_syserror ()));
-      xfree (hd);
-      return err;
-    }
-  hd->sock = my_socket_new (sock);
-  if (!hd->sock)
-    {
-      err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
-      xfree (hd);
-      return err;
-    }
+  {
+    assuan_fd_t sock;
+
+    sock = connect_server (server, port, hd->flags, srvtag, &hnf);
+    if (sock == ASSUAN_INVALID_FD)
+      {
+        err = gpg_err_make (default_errsource,
+                            (hnf? GPG_ERR_UNKNOWN_HOST
+                             : gpg_err_code_from_syserror ()));
+        xfree (hd);
+        return err;
+      }
+    hd->sock = my_socket_new (sock);
+    if (!hd->sock)
+      {
+        err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+        xfree (hd);
+        return err;
+      }
+  }
 
   /* Setup estreams for reading and writing.  */
   cookie = xtrycalloc (1, sizeof *cookie);
@@ -1073,6 +1084,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
   uri->is_http = 0;
   uri->opaque = 0;
   uri->v6lit = 0;
+  uri->onion = 0;
 
   /* A quick validity check. */
   if (strspn (p, VALID_URI_CHARS) != n)
@@ -1159,49 +1171,54 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
         {
           uri->opaque = 1;
           uri->path = p;
+          if (is_onion_address (uri->path))
+            uri->onion = 1;
           return 0;
         }
 
     } /* End global URI part. */
 
-  /* Parse the pathname part */
-  if (!p || !*p)
-    return 0;  /* We don't have a path.  Okay. */
-
-  /* TODO: Here we have to check params. */
-
-  /* Do we have a query part? */
-  if ((p2 = strchr (p, '?')))
-    *p2++ = 0;
-
-  uri->path = p;
-  if ((n = remove_escapes (p)) < 0)
-    return GPG_ERR_BAD_URI;
-  if (n != strlen (p))
-    return GPG_ERR_BAD_URI;    /* Path includes a Nul. */
-  p = p2 ? p2 : NULL;
-
-  if (!p || !*p)
-    return 0; /* We don't have a query string.  Okay. */
-
-  /* Now parse the query string. */
-  tail = &uri->query;
-  for (;;)
+  /* Parse the pathname part if any.  */
+  if (p && *p)
     {
-      uri_tuple_t elem;
+      /* TODO: Here we have to check params. */
 
-      if ((p2 = strchr (p, '&')))
-       *p2++ = 0;
-      if (!(elem = parse_tuple (p)))
-       return GPG_ERR_BAD_URI;
-      *tail = elem;
-      tail = &elem->next;
+      /* Do we have a query part? */
+      if ((p2 = strchr (p, '?')))
+        *p2++ = 0;
 
-      if (!p2)
-       break; /* Ready. */
-      p = p2;
+      uri->path = p;
+      if ((n = remove_escapes (p)) < 0)
+        return GPG_ERR_BAD_URI;
+      if (n != strlen (p))
+        return GPG_ERR_BAD_URI;        /* Path includes a Nul. */
+      p = p2 ? p2 : NULL;
+
+      /* Parse a query string if any.  */
+      if (p && *p)
+        {
+          tail = &uri->query;
+          for (;;)
+            {
+              uri_tuple_t elem;
+
+              if ((p2 = strchr (p, '&')))
+                *p2++ = 0;
+              if (!(elem = parse_tuple (p)))
+                return GPG_ERR_BAD_URI;
+              *tail = elem;
+              tail = &elem->next;
+
+              if (!p2)
+                break; /* Ready. */
+              p = p2;
+            }
+        }
     }
 
+  if (is_onion_address (uri->host))
+    uri->onion = 1;
+
   return 0;
 }
 
@@ -1460,8 +1477,13 @@ send_request (http_t hd, const char *httphost, const char *auth,
 
   if ((hd->flags & HTTP_FLAG_FORCE_TOR))
     {
-      log_error ("TOR support is not yet available\n");
-      return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
+      int mode;
+
+      if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
+        {
+          log_error ("Tor support is not available\n");
+          return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
+        }
     }
 
   server = *hd->uri->host ? hd->uri->host : "localhost";
@@ -1560,7 +1582,7 @@ send_request (http_t hd, const char *httphost, const char *auth,
                              hd->flags, srvtag, &hnf);
       save_errno = errno;
       http_release_parsed_uri (uri);
-      if (sock == -1)
+      if (sock == ASSUAN_INVALID_FD)
         gpg_err_set_errno (save_errno);
     }
   else
@@ -1568,7 +1590,7 @@ send_request (http_t hd, const char *httphost, const char *auth,
       sock = connect_server (server, port, hd->flags, srvtag, &hnf);
     }
 
-  if (sock == -1)
+  if (sock == ASSUAN_INVALID_FD)
     {
       xfree (proxy_authstr);
       return gpg_err_make (default_errsource,
@@ -1621,12 +1643,10 @@ send_request (http_t hd, const char *httphost, const char *auth,
 
       my_socket_ref (hd->sock);
       gnutls_transport_set_ptr (hd->session->tls_session, hd->sock);
-#ifdef USE_NPTH
       gnutls_transport_set_pull_function (hd->session->tls_session,
-                                          my_npth_read);
+                                          my_gnutls_read);
       gnutls_transport_set_push_function (hd->session->tls_session,
-                                          my_npth_write);
-#endif
+                                          my_gnutls_write);
 
       do
         {
@@ -2183,66 +2203,70 @@ start_server ()
 
 /* Actually connect to a server.  Returns the file descriptor or -1 on
    error.  ERRNO is set on error. */
-static int
+static assuan_fd_t
 connect_server (const char *server, unsigned short port,
                 unsigned int flags, const char *srvtag, int *r_host_not_found)
 {
-  int sock = -1;
+  gpg_error_t err;
+  assuan_fd_t sock = ASSUAN_INVALID_FD;
   int srvcount = 0;
   int hostfound = 0;
   int anyhostaddr = 0;
   int srv, connected;
   int last_errno = 0;
   struct srventry *serverlist = NULL;
-#ifdef HAVE_W32_SYSTEM
-  unsigned long inaddr;
-#endif
+  int ret;
 
   *r_host_not_found = 0;
-#ifdef HAVE_W32_SYSTEM
-
-#ifndef HTTP_NO_WSASTARTUP
+#if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
   init_sockets ();
-#endif
-  /* Win32 gethostbyname doesn't handle IP addresses internally, so we
-     try inet_addr first on that platform only. */
-  inaddr = inet_addr(server);
-  if ( inaddr != INADDR_NONE )
+#endif /*Windows*/
+
+  /* Onion addresses require special treatment.  */
+  if (is_onion_address (server))
     {
-      struct sockaddr_in addr;
+#ifdef ASSUAN_SOCK_TOR
 
-      memset(&addr,0,sizeof(addr));
+      sock = assuan_sock_connect_byname (server, port, 0, NULL,
+                                         ASSUAN_SOCK_TOR);
+      if (sock == ASSUAN_INVALID_FD)
+        {
+          if (errno == EHOSTUNREACH)
+            *r_host_not_found = 1;
+          log_error ("can't connect to '%s': %s\n", server, strerror (errno));
+        }
+      return sock;
 
-      sock = socket(AF_INET,SOCK_STREAM,0);
-      if ( sock==INVALID_SOCKET )
-       {
-         log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
-         return -1;
-       }
+#else /*!ASSUAN_SOCK_TOR*/
 
-      addr.sin_family = AF_INET;
-      addr.sin_port = htons(port);
-      memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));
+      gpg_err_set_errno (ENETUNREACH);
+      return -1; /* Out of core.  */
 
-      if (!my_connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
-       return sock;
-      sock_close(sock);
-      return -1;
+#endif /*!HASSUAN_SOCK_TOR*/
     }
-#endif /*HAVE_W32_SYSTEM*/
 
 #ifdef USE_DNS_SRV
   /* Do the SRV thing */
   if (srvtag)
     {
       /* We're using SRV, so append the tags. */
-      if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
+      if (1 + strlen (srvtag) + 6 + strlen (server) + 1
+          <= DIMof (struct srventry, target))
        {
-         char srvname[MAXDNAME];
+         char *srvname = xtrymalloc (DIMof (struct srventry, target));
 
-         stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
-                           "._tcp."), server);
-         srvcount = getsrv (srvname, &serverlist);
+          if (!srvname) /* Out of core */
+            {
+              serverlist = NULL;
+              srvcount = 0;
+            }
+          else
+            {
+              stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
+                              "._tcp."), server);
+              srvcount = getsrv (srvname, &serverlist);
+              xfree (srvname);
+            }
        }
     }
 #else
@@ -2258,111 +2282,55 @@ connect_server (const char *server, unsigned short port,
       if (!serverlist)
         return -1; /* Out of core.  */
       serverlist->port = port;
-      strncpy (serverlist->target, server, MAXDNAME);
-      serverlist->target[MAXDNAME-1] = '\0';
+      strncpy (serverlist->target, server, DIMof (struct srventry, target));
+      serverlist->target[DIMof (struct srventry, target)-1] = '\0';
       srvcount = 1;
     }
 
-#ifdef HAVE_GETADDRINFO
   connected = 0;
   for (srv=0; srv < srvcount && !connected; srv++)
     {
-      struct addrinfo hints, *res, *ai;
-      char portstr[35];
+      dns_addrinfo_t aibuf, ai;
 
-      snprintf (portstr, sizeof portstr, "%hu", port);
-      memset (&hints, 0, sizeof (hints));
-      hints.ai_socktype = SOCK_STREAM;
-      if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
-        continue; /* Not found - try next one. */
+      err = resolve_dns_name (serverlist[srv].target, port, 0, SOCK_STREAM,
+                              &aibuf, NULL);
+      if (err)
+        {
+          log_info ("resolving '%s' failed: %s\n",
+                    serverlist[srv].target, gpg_strerror (err));
+          continue; /* Not found - try next one. */
+        }
       hostfound = 1;
 
-      for (ai = res; ai && !connected; ai = ai->ai_next)
+      for (ai = aibuf; ai && !connected; ai = ai->next)
         {
-          if (ai->ai_family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4))
+          if (ai->family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4))
             continue;
-          if (ai->ai_family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6))
+          if (ai->family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6))
             continue;
 
-          if (sock != -1)
-            sock_close (sock);
-          sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-          if (sock == -1)
+          if (sock != ASSUAN_INVALID_FD)
+            assuan_sock_close (sock);
+          sock = assuan_sock_new (ai->family, ai->socktype, ai->protocol);
+          if (sock == ASSUAN_INVALID_FD)
             {
               int save_errno = errno;
               log_error ("error creating socket: %s\n", strerror (errno));
-              freeaddrinfo (res);
+              free_dns_addrinfo (aibuf);
               xfree (serverlist);
               errno = save_errno;
-              return -1;
+              return ASSUAN_INVALID_FD;
             }
 
           anyhostaddr = 1;
-          if (my_connect (sock, ai->ai_addr, ai->ai_addrlen))
+          ret = assuan_sock_connect (sock, ai->addr, ai->addrlen);
+          if (ret)
             last_errno = errno;
           else
             connected = 1;
         }
-      freeaddrinfo (res);
-    }
-#else /* !HAVE_GETADDRINFO */
-  connected = 0;
-  for (srv=0; srv < srvcount && !connected; srv++)
-    {
-      int i;
-      struct hostent *host = NULL;
-      struct sockaddr_in addr;
-
-      /* Note: This code is not thread-safe.  */
-
-      memset (&addr, 0, sizeof (addr));
-      host = gethostbyname (serverlist[srv].target);
-      if (!host)
-        continue;
-      hostfound = 1;
-
-      if (sock != -1)
-        sock_close (sock);
-      sock = socket (host->h_addrtype, SOCK_STREAM, 0);
-      if (sock == -1)
-        {
-          log_error ("error creating socket: %s\n", strerror (errno));
-          xfree (serverlist);
-          return -1;
-        }
-
-      addr.sin_family = host->h_addrtype;
-      if (addr.sin_family != AF_INET)
-       {
-         log_error ("unknown address family for '%s'\n",
-                     serverlist[srv].target);
-          xfree (serverlist);
-         return -1;
-       }
-      addr.sin_port = htons (serverlist[srv].port);
-      if (host->h_length != 4)
-        {
-          log_error ("illegal address length for '%s'\n",
-                     serverlist[srv].target);
-          xfree (serverlist);
-          return -1;
-        }
-
-      /* Try all A records until one responds. */
-      for (i = 0; host->h_addr_list[i] && !connected; i++)
-        {
-          anyhostaddr = 1;
-          memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
-          if (my_connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
-            last_errno = errno;
-          else
-            {
-              connected = 1;
-              break;
-            }
-        }
+      free_dns_addrinfo (aibuf);
     }
-#endif /* !HAVE_GETADDRINFO */
 
   xfree (serverlist);
 
@@ -2386,10 +2354,10 @@ connect_server (const char *server, unsigned short port,
         }
       if (!hostfound || (hostfound && !anyhostaddr))
         *r_host_not_found = 1;
-      if (sock != -1)
-       sock_close (sock);
+      if (sock != ASSUAN_INVALID_FD)
+       assuan_sock_close (sock);
       gpg_err_set_errno (last_errno);
-      return -1;
+      return ASSUAN_INVALID_FD;
     }
   return sock;
 }
@@ -2450,7 +2418,7 @@ write_server (int sock, const char *data, size_t length)
 
 \f
 /* Read handler for estream.  */
-static ssize_t
+static gpgrt_ssize_t
 cookie_read (void *cookie, void *buffer, size_t size)
 {
   cookie_t c = cookie;
@@ -2484,6 +2452,13 @@ cookie_read (void *cookie, void *buffer, size_t size)
             }
           if (nread == GNUTLS_E_REHANDSHAKE)
             goto again; /* A client is allowed to just ignore this request. */
+          if (nread == GNUTLS_E_PREMATURE_TERMINATION)
+            {
+              /* The server terminated the connection.  Close the TLS
+                 session, and indicate EOF using a short read.  */
+              close_tls_session (c->session);
+              return 0;
+            }
           log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
           gpg_err_set_errno (EIO);
           return -1;
@@ -2525,11 +2500,11 @@ cookie_read (void *cookie, void *buffer, size_t size)
         c->content_length = 0;
     }
 
-  return nread;
+  return (gpgrt_ssize_t)nread;
 }
 
 /* Write handler for estream.  */
-static ssize_t
+static gpgrt_ssize_t
 cookie_write (void *cookie, const void *buffer_arg, size_t size)
 {
   const char *buffer = buffer_arg;
@@ -2578,7 +2553,7 @@ cookie_write (void *cookie, const void *buffer_arg, size_t size)
         nwritten = size;
     }
 
-  return nwritten;
+  return (gpgrt_ssize_t)nwritten;
 }
 
 
similarity index 99%
rename from common/http.h
rename to dirmngr/http.h
index 73a423c..64f55e1 100644 (file)
@@ -52,6 +52,7 @@ struct parsed_uri_s
   unsigned int use_tls:1; /* Whether TLS should be used. */
   unsigned int opaque:1;/* Unknown scheme; PATH has the rest.  */
   unsigned int v6lit:1; /* Host was given as a literal v6 address.  */
+  unsigned int onion:1; /* .onion address given.  */
   char *auth;           /* username/password for basic auth.  */
   char *host;          /* Host (converted to lowercase). */
   unsigned short port;  /* Port (always set if the host is set). */
index 411f108..e458899 100644 (file)
@@ -38,6 +38,7 @@
 #include "dirmngr.h"
 #include "misc.h"
 #include "userids.h"
+#include "dns-stuff.h"
 #include "ks-engine.h"
 
 /* Substitutes for missing Mingw macro.  The EAI_SYSTEM mechanism
@@ -79,6 +80,7 @@ struct hostinfo_s
   int poolidx;       /* Index into POOL with the used host.  -1 if not set.  */
   unsigned int v4:1; /* Host supports AF_INET.  */
   unsigned int v6:1; /* Host supports AF_INET6.  */
+  unsigned int onion:1;/* NAME is an onion (Tor HS) address.  */
   unsigned int dead:1; /* Host is currently unresponsive.  */
   time_t died_at;    /* The time the host was marked dead.  If this is
                         0 the host has been manually marked dead.  */
@@ -88,8 +90,9 @@ struct hostinfo_s
                         NULL if NAME has a numeric IP address or no v4
                         address is available.  */
   char *v6addr;      /* A string with the v6 IP address of the host.
-                        NULL if NAME has a numeric IP address or no v4
+                        NULL if NAME has a numeric IP address or no v6
                         address is available.  */
+  unsigned short port; /* The port used by the host, 0 if unknown.  */
   char name[1];      /* The hostname.  */
 };
 
@@ -99,7 +102,7 @@ struct hostinfo_s
 static hostinfo_t *hosttable;
 static int hosttable_size;
 
-/* The number of host slots we initally allocate for HOSTTABLE.  */
+/* The number of host slots we initially allocate for HOSTTABLE.  */
 #define INITIAL_HOSTTABLE_SIZE 10
 
 
@@ -123,11 +126,13 @@ create_new_hostinfo (const char *name)
   hi->lastfail = (time_t)(-1);
   hi->v4 = 0;
   hi->v6 = 0;
+  hi->onion = 0;
   hi->dead = 0;
   hi->died_at = 0;
   hi->cname = NULL;
   hi->v4addr = NULL;
   hi->v6addr = NULL;
+  hi->port = 0;
 
   /* Add it to the hosttable. */
   for (idx=0; idx < hosttable_size; idx++)
@@ -233,81 +238,138 @@ select_random_host (int *table)
 }
 
 
-/* Simplified version of getnameinfo which also returns a numeric
-   hostname inside of brackets.  The caller should provide a buffer
-   for HOST which is 2 bytes larger than the largest hostname.  If
-   NUMERIC is true the returned value is numeric IP address.  Returns
-   0 on success or an EAI error code.  True is stored at R_ISNUMERIC
-   if HOST has a numeric IP address. */
+/* Figure out if a set of DNS records looks like a pool.  */
 static int
-my_getnameinfo (struct addrinfo *ai, char *host, size_t hostlen,
-                int numeric, int *r_isnumeric)
+arecords_is_pool (dns_addrinfo_t aibuf)
 {
-  int ec;
-  char *p;
+  dns_addrinfo_t ai;
+  int n_v6, n_v4;
+
+  n_v6 = n_v4 = 0;
+  for (ai = aibuf; ai; ai = ai->next)
+    {
+      if (ai->family == AF_INET6)
+        n_v6++;
+      else if (ai->family == AF_INET)
+        n_v4++;
+    }
+
+  return n_v6 > 1 || n_v4 > 1;
+}
 
-  *r_isnumeric = 0;
 
-  if (hostlen < 5)
-    return EAI_OVERFLOW;
+/* Add the host AI under the NAME into the HOSTTABLE.  If PORT is not
+   zero, it specifies which port to use to talk to the host.  If NAME
+   specifies a pool (as indicated by IS_POOL), update the given
+   reference table accordingly.  */
+static void
+add_host (const char *name, int is_pool,
+          const dns_addrinfo_t ai, unsigned short port,
+          int *reftbl, size_t reftblsize, int *refidx)
+{
+  gpg_error_t tmperr;
+  char *tmphost;
+  int idx, tmpidx;
+  int is_numeric = 0;
+  int i;
+
+  idx = find_hostinfo (name);
 
-  if (numeric)
-    ec = EAI_NONAME;
+  if (!is_pool && !is_ip_address (name))
+    {
+      /* This is a hostname but not a pool.  Use the name
+         as given without going through resolve_dns_addr.  */
+      tmphost = xtrystrdup (name);
+      if (!tmphost)
+        tmperr = gpg_error_from_syserror ();
+      else
+        tmperr = 0;
+    }
   else
-    ec = getnameinfo (ai->ai_addr, ai->ai_addrlen,
-                      host, hostlen, NULL, 0, NI_NAMEREQD);
+    {
+      tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
+                                 DNS_WITHBRACKET, &tmphost);
+      if (tmphost && is_ip_address (tmphost))
+        is_numeric = 1;
+    }
 
-  if (!ec && *host == '[')
-    ec = EAI_FAIL;  /* A name may never start with a bracket.  */
-  else if (ec == EAI_NONAME)
+  if (tmperr)
+    {
+      log_info ("resolve_dns_addr failed while checking '%s': %s\n",
+                name, gpg_strerror (tmperr));
+    }
+  else if ((*refidx) + 1 >= reftblsize)
+    {
+      log_error ("resolve_dns_addr for '%s': '%s'"
+                 " [index table full - ignored]\n", name, tmphost);
+    }
+  else
     {
-      p = host;
-      if (ai->ai_family == AF_INET6)
+      if (!is_pool && is_ip_address (name))
+        /* Update the original entry.  */
+        tmpidx = idx;
+      else
+        tmpidx = find_hostinfo (tmphost);
+      log_info ("resolve_dns_addr for '%s': '%s'%s\n",
+                name, tmphost,
+                tmpidx == -1? "" : " [already known]");
+
+      if (tmpidx == -1) /* Create a new entry.  */
+        tmpidx = create_new_hostinfo (tmphost);
+
+      if (tmpidx == -1)
         {
-          *p++ = '[';
-          hostlen -= 2;
+          log_error ("map_host for '%s' problem: %s - '%s'"
+                     " [ignored]\n",
+                     name, strerror (errno), tmphost);
         }
-      ec = getnameinfo (ai->ai_addr, ai->ai_addrlen,
-                        p, hostlen, NULL, 0, NI_NUMERICHOST);
-      if (!ec && ai->ai_family == AF_INET6)
-        strcat (host, "]");
-
-      *r_isnumeric = 1;
-    }
+      else  /* Set or update the entry. */
+        {
+          char *ipaddr = NULL;
 
-  return ec;
-}
+          if (port)
+            hosttable[tmpidx]->port = port;
 
+          if (!is_numeric)
+            {
+              xfree (tmphost);
+              tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
+                                         (DNS_NUMERICHOST
+                                          | DNS_WITHBRACKET),
+                                         &tmphost);
+              if (tmperr)
+                log_info ("resolve_dns_addr failed: %s\n",
+                          gpg_strerror (tmperr));
+              else
+                {
+                  ipaddr = tmphost;
+                  tmphost = NULL;
+                }
+            }
 
-/* Check whether NAME is an IP address.  */
-static int
-is_ip_address (const char *name)
-{
-  int ndots, n;
-
-  if (*name == '[')
-    return 1;
-  /* Check whether it is legacy IP address.  */
-  if (*name == '.')
-    return 0; /* No.  */
-  ndots = n = 0;
-  for (; *name; name++)
-    {
-      if (*name == '.')
-        {
-          if (name[1] == '.')
-            return 0; /* No. */
-          if (atoi (name+1) > 255)
-            return 0; /* Value too large.  */
-          ndots++;
-          n = 0;
+          if (ai->family == AF_INET6)
+            {
+              hosttable[tmpidx]->v6 = 1;
+              xfree (hosttable[tmpidx]->v6addr);
+              hosttable[tmpidx]->v6addr = ipaddr;
+            }
+          else if (ai->family == AF_INET)
+            {
+              hosttable[tmpidx]->v4 = 1;
+              xfree (hosttable[tmpidx]->v4addr);
+              hosttable[tmpidx]->v4addr = ipaddr;
+            }
+          else
+            BUG ();
+
+          for (i=0; i < *refidx; i++)
+            if (reftbl[i] == tmpidx)
+              break;
+          if (!(i < *refidx) && tmpidx != idx)
+            reftbl[(*refidx)++] = tmpidx;
         }
-      else if (!strchr ("012345678", *name))
-        return 0; /* Not a digit.  */
-      else if (++n > 3)
-        return 0; /* More than 3 digits.  */
     }
-  return !!(ndots == 3);
+  xfree (tmphost);
 }
 
 
@@ -317,13 +379,16 @@ is_ip_address (const char *name)
    failed for some time and we stick to one host for a time
    independent of DNS retry times.  If FORCE_RESELECT is true a new
    host is always selected.  The selected host is stored as a malloced
-   string at R_HOST; on error NULL is stored.  If R_HTTPFLAGS is not
+   string at R_HOST; on error NULL is stored.  If we know the port
+   used by the selected host, a string representation is written to
+   R_PORTSTR, otherwise it is left untouched.  If R_HTTPFLAGS is not
    NULL it will receive flags which are to be passed to http_open.  If
    R_POOLNAME is not NULL a malloced name of the pool is stored or
    NULL if it is not a pool. */
 static gpg_error_t
 map_host (ctrl_t ctrl, const char *name, int force_reselect,
-          char **r_host, unsigned int *r_httpflags, char **r_poolname)
+          char **r_host, char *r_portstr,
+          unsigned int *r_httpflags, char **r_poolname)
 {
   gpg_error_t err = 0;
   hostinfo_t hi;
@@ -344,14 +409,28 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
 
   /* See whether the host is in our table.  */
   idx = find_hostinfo (name);
-  if (idx == -1)
+  if (idx == -1 && is_onion_address (name))
+    {
+      idx = create_new_hostinfo (name);
+      if (idx == -1)
+        return gpg_error_from_syserror ();
+      hi = hosttable[idx];
+      hi->onion = 1;
+    }
+  else if (idx == -1)
     {
       /* We never saw this host.  Allocate a new entry.  */
-      struct addrinfo hints, *aibuf, *ai;
+      dns_addrinfo_t aibuf, ai;
       int *reftbl;
       size_t reftblsize;
       int refidx;
       int is_pool = 0;
+      char *cname;
+#ifdef USE_DNS_SRV
+      char *srvrecord;
+      struct srventry *srvs;
+      int srvscount;
+#endif /* USE_DNS_SRV */
 
       reftblsize = 100;
       reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
@@ -368,138 +447,82 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
         }
       hi = hosttable[idx];
 
+#ifdef USE_DNS_SRV
+      /* Check for SRV records.  */
+      srvrecord = xtryasprintf ("_hkp._tcp.%s", name);
+      if (srvrecord == NULL)
+        {
+          err = gpg_error_from_syserror ();
+          xfree (reftbl);
+          return err;
+        }
+
+      srvscount = getsrv (srvrecord, &srvs);
+      xfree (srvrecord);
+      if (srvscount < 0)
+        {
+          err = gpg_error_from_syserror ();
+          xfree (reftbl);
+          return err;
+        }
+
+      if (srvscount > 0)
+        {
+          int i;
+          is_pool = srvscount > 1;
+
+          for (i = 0; i < srvscount; i++)
+            {
+              err = resolve_dns_name (srvs[i].target, 0,
+                                      AF_UNSPEC, SOCK_STREAM,
+                                      &ai, &cname);
+              if (err)
+                continue;
+              dirmngr_tick (ctrl);
+              add_host (name, is_pool, ai, srvs[i].port,
+                        reftbl, reftblsize, &refidx);
+            }
+
+          xfree (srvs);
+        }
+#endif /* USE_DNS_SRV */
+
       /* Find all A records for this entry and put them into the pool
          list - if any.  */
-      memset (&hints, 0, sizeof (hints));
-      hints.ai_family = AF_UNSPEC;
-      hints.ai_socktype = SOCK_STREAM;
-      hints.ai_flags = AI_CANONNAME;
-      /* We can't use the the AI_IDN flag because that does the
-         conversion using the current locale.  However, GnuPG always
-         used UTF-8.  To support IDN we would need to make use of the
-         libidn API.  */
-      if (!getaddrinfo (name, NULL, &hints, &aibuf))
+      err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
+      if (err)
+        {
+          log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
+          err = 0;
+        }
+      else
         {
-          int n_v6, n_v4;
-
           /* First figure out whether this is a pool.  For a pool we
              use a different strategy than for a plain server: We use
              the canonical name of the pool as the virtual host along
              with the IP addresses.  If it is not a pool, we use the
              specified name. */
-          n_v6 = n_v4 = 0;
-          for (ai = aibuf; ai; ai = ai->ai_next)
+          if (! is_pool)
+            is_pool = arecords_is_pool (aibuf);
+          if (is_pool && cname)
             {
-              if (ai->ai_family != AF_INET6)
-                n_v6++;
-              else if (ai->ai_family != AF_INET)
-                n_v4++;
+              hi->cname = cname;
+              cname = NULL;
             }
-          if (n_v6 > 1 || n_v4 > 1)
-            is_pool = 1;
-          if (is_pool && aibuf->ai_canonname)
-            hi->cname = xtrystrdup (aibuf->ai_canonname);
 
-          for (ai = aibuf; ai; ai = ai->ai_next)
+          for (ai = aibuf; ai; ai = ai->next)
             {
-              char tmphost[NI_MAXHOST + 2];
-              int tmpidx;
-              int is_numeric;
-              int ec;
-              int i;
-
-              if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+              if (ai->family != AF_INET && ai->family != AF_INET6)
                 continue;
-
               dirmngr_tick (ctrl);
 
-              if (!is_pool && !is_ip_address (name))
-                {
-                  /* This is a hostname but not a pool.  Use the name
-                     as given without going through getnameinfo.  */
-                  if (strlen (name)+1 > sizeof tmphost)
-                    {
-                      ec = EAI_SYSTEM;
-                      gpg_err_set_errno (EINVAL);
-                    }
-                  else
-                    {
-                      ec = 0;
-                      strcpy (tmphost, name);
-                    }
-                  is_numeric = 0;
-                }
-              else
-                ec = my_getnameinfo (ai, tmphost, sizeof tmphost,
-                                     0, &is_numeric);
-
-              if (ec)
-                {
-                  log_info ("getnameinfo failed while checking '%s': %s\n",
-                            name, gai_strerror (ec));
-                }
-              else if (refidx+1 >= reftblsize)
-                {
-                  log_error ("getnameinfo returned for '%s': '%s'"
-                            " [index table full - ignored]\n", name, tmphost);
-                }
-              else
-                {
-                  tmpidx = find_hostinfo (tmphost);
-                  log_info ("getnameinfo returned for '%s': '%s'%s\n",
-                            name, tmphost,
-                            tmpidx == -1? "" : " [already known]");
-
-                  if (tmpidx == -1) /* Create a new entry.  */
-                    tmpidx = create_new_hostinfo (tmphost);
-
-                  if (tmpidx == -1)
-                    {
-                      log_error ("map_host for '%s' problem: %s - '%s'"
-                                 " [ignored]\n",
-                                 name, strerror (errno), tmphost);
-                    }
-                  else  /* Set or update the entry. */
-                    {
-                      char *ipaddr = NULL;
-
-                      if (!is_numeric)
-                        {
-                          ec = my_getnameinfo (ai, tmphost, sizeof tmphost,
-                                               1, &is_numeric);
-                          if (!ec && !(ipaddr = xtrystrdup (tmphost)))
-                            ec = EAI_SYSTEM;
-                          if (ec)
-                            log_info ("getnameinfo failed: %s\n",
-                                      gai_strerror (ec));
-                        }
-
-                      if (ai->ai_family == AF_INET6)
-                        {
-                          hosttable[tmpidx]->v6 = 1;
-                          xfree (hosttable[tmpidx]->v6addr);
-                          hosttable[tmpidx]->v6addr = ipaddr;
-                        }
-                      else if (ai->ai_family == AF_INET)
-                        {
-                          hosttable[tmpidx]->v4 = 1;
-                          xfree (hosttable[tmpidx]->v4addr);
-                          hosttable[tmpidx]->v4addr = ipaddr;
-                        }
-                      else
-                        BUG ();
-
-                      for (i=0; i < refidx; i++)
-                        if (reftbl[i] == tmpidx)
-                          break;
-                      if (!(i < refidx) && tmpidx != idx)
-                        reftbl[refidx++] = tmpidx;
-                    }
-                }
+              add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
             }
-          freeaddrinfo (aibuf);
         }
       reftbl[refidx] = -1;
+      xfree (cname);
+      free_dns_addrinfo (aibuf);
+
       if (refidx && is_pool)
         {
           assert (!hi->pool);
@@ -580,6 +603,11 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
         *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
       if (!hi->v6)
         *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
+
+      /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
+         addresses because the http module detects this itself.  This
+         also allows us to use an onion address without Tor mode being
+         enabled.  */
     }
 
   *r_host = xtrystrdup (hi->name);
@@ -593,6 +621,9 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
         }
       return err;
     }
+  if (hi->port)
+    snprintf (r_portstr, 6 /* five digits and the sentinel */,
+              "%hu", hi->port);
   return 0;
 }
 
@@ -751,7 +782,9 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
         else
           diedstr = died = NULL;
         err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
-                              idx, hi->v6? "6":" ", hi->v4? "4":" ",
+                              idx,
+                              hi->onion? "O" : hi->v6? "6":" ",
+                              hi->v4? "4":" ",
                               hi->dead? "d":" ",
                               hi->name,
                               hi->v6addr? " v6=":"",
@@ -842,16 +875,24 @@ make_host_part (ctrl_t ctrl,
 
   *r_hostport = NULL;
 
+  portstr[0] = 0;
+  err = map_host (ctrl, host, force_reselect,
+                  &hostname, portstr, r_httpflags, r_poolname);
+  if (err)
+    return err;
+
   /* Map scheme and port.  */
   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
     {
       scheme = "https";
-      strcpy (portstr, "443");
+      if (! *portstr)
+        strcpy (portstr, "443");
     }
   else /* HKP or HTTP.  */
     {
       scheme = "http";
-      strcpy (portstr, "11371");
+      if (! *portstr)
+        strcpy (portstr, "11371");
     }
   if (port)
     snprintf (portstr, sizeof portstr, "%hu", port);
@@ -860,11 +901,6 @@ make_host_part (ctrl_t ctrl,
       /*fixme_do_srv_lookup ()*/
     }
 
-  err = map_host (ctrl, host, force_reselect,
-                  &hostname, r_httpflags, r_poolname);
-  if (err)
-    return err;
-
   *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
   xfree (hostname);
   if (!*r_hostport)
index c6fa5eb..ad2110e 100644 (file)
@@ -433,10 +433,10 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact)
 
    If this function successfully interrogated the server, it returns
    0.  If there was an LDAP error, it returns the LDAP error code.  If
-   an error occured, *basednp, etc., are undefined (and don't need to
+   an error occurred, *basednp, etc., are undefined (and don't need to
    be freed.)
 
-   If no LDAP error occured, you still need to check that *basednp is
+   If no LDAP error occurred, you still need to check that *basednp is
    valid.  If it is NULL, then the server does not appear to be an
    OpenPGP Keyserver.  In this case, you also do not need to xfree
    *pgpkeyattrp.  */
@@ -838,8 +838,8 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
 
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("LDAP access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
 
@@ -1021,8 +1021,8 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
 
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("LDAP access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
 
@@ -1616,7 +1616,7 @@ extract_attributes (LDAPMod ***modlist, char *line)
 
   fields = strsplit (line, ':', '\0', &field_count);
   if (field_count == 1)
-    /* We only have a single field.  There is definately nothing to
+    /* We only have a single field.  There is definitely nothing to
        do.  */
     goto out;
 
@@ -1897,8 +1897,8 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
 
   if (opt.use_tor)
     {
-      /* For now we do not support LDAP over TOR.  */
-      log_error (_("LDAP access not possible due to TOR mode\n"));
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
 
index aff6cf4..6684a12 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef DIRMNGR_KS_ENGINE_H
 #define DIRMNGR_KS_ENGINE_H 1
 
-#include "../common/http.h"
+#include "http.h"
 
 /*-- ks-action.c --*/
 gpg_error_t ks_print_help (ctrl_t ctrl, const char *text);
index a54e405..c073f17 100644 (file)
@@ -160,7 +160,7 @@ destroy_wrapper (struct wrapper_context_s *ctx)
 
 /* Print the content of LINE to thye log stream but make sure to only
    print complete lines.  Using NULL for LINE will flush any pending
-   output.  LINE may be modified by this fucntion. */
+   output.  LINE may be modified by this function. */
 static void
 print_log_line (struct wrapper_context_s *ctx, char *line)
 {
index e4c6aa2..20cbbd8 100644 (file)
@@ -382,7 +382,7 @@ parse_one_pattern (const char *pattern)
   return result;
 }
 
-/* Take the string STRING and escape it accoring to the URL rules.
+/* Take the string STRING and escape it according to the URL rules.
    Retun a newly allocated string. */
 static char *
 escape4url (const char *string)
@@ -512,7 +512,7 @@ start_default_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
 }
 
 
-/* Prepare an LDAP query to return certificates maching PATTERNS using
+/* Prepare an LDAP query to return certificates matching PATTERNS using
    the SERVER.  This function returns an error code or 0 and a CONTEXT
    on success. */
 gpg_error_t
@@ -520,32 +520,54 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
                        strlist_t patterns, const ldap_server_t server)
 {
   gpg_error_t err;
-  const char *host;
+  char *proxy = NULL;
+  char *host = NULL;
   int port;
-  const char *user;
-  const char *pass;
+  char *user = NULL;
+  char *pass = NULL;
   const char *base;
-  const char *argv[50];
-  int argc;
+  char *argv[50];
+  int argc = 0;
+  int argc_malloced = 0;
   char portbuf[30], timeoutbuf[30];
 
 
   *context = NULL;
+
+  if (opt.ldap_proxy && !(proxy = xtrystrdup (opt.ldap_proxy)))
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
   if (server)
     {
-      host = server->host;
+      if (server->host && !(host = xtrystrdup (server->host)))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
       port = server->port;
-      user = server->user;
-      pass = server->pass;
+      if (server->user && !(user = xtrystrdup (server->user)))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      if (server->pass && !(pass = xtrystrdup (server->pass)))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
       base = server->base;
+
     }
   else /* Use a default server. */
     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
+
   if (!base)
     base = "";
 
-  argc = 0;
   if (pass) /* Note: Must be the first item. */
     {
       argv[argc++] = "--pass";
@@ -557,14 +579,14 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
   argv[argc++] = "--multi";
   if (opt.ldaptimeout)
     {
-      sprintf (timeoutbuf, "%u", opt.ldaptimeout);
+      snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
       argv[argc++] = "--timeout";
       argv[argc++] = timeoutbuf;
     }
   if (opt.ldap_proxy)
     {
       argv[argc++] = "--proxy";
-      argv[argc++] = opt.ldap_proxy;
+      argv[argc++] = proxy;
     }
   if (host)
     {
@@ -573,7 +595,7 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
     }
   if (port)
     {
-      sprintf (portbuf, "%d", port);
+      snprintf (portbuf, sizeof portbuf, "%d", port);
       argv[argc++] = "--port";
       argv[argc++] = portbuf;
     }
@@ -583,6 +605,8 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
       argv[argc++] = user;
     }
 
+  /* All entries in argv from this index on are malloc'ed.  */
+  argc_malloced = argc;
 
   for (; patterns; patterns = patterns->next)
     {
@@ -602,8 +626,8 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
         {
           log_error (_("start_cert_fetch: invalid pattern '%s'\n"),
                      patterns->d);
-          /* fixme: cleanup argv.  */
-          return gpg_error (GPG_ERR_INV_USER_ID);
+          err = gpg_error (GPG_ERR_INV_USER_ID);
+          goto leave;
         }
       if ((sl->flags & 1))
         err = make_url (&url, sl->d, "objectClass=*");
@@ -611,19 +635,19 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
         err = make_url (&url, base, sl->d);
       free_strlist (sl);
       if (err)
-        {
-          /* fixme: cleanup argv. */
-          return err;
-        }
+        goto leave;
       argv[argc++] = url;
     }
   argv[argc] = NULL;
 
   *context = xtrycalloc (1, sizeof **context);
   if (!*context)
-    return gpg_error_from_errno (errno);
+    {
+      err = gpg_error_from_errno (errno);
+      goto leave;
+    }
 
-  err = ldap_wrapper (ctrl, &(*context)->reader, argv);
+  err = ldap_wrapper (ctrl, &(*context)->reader, (const char**)argv);
 
   if (err)
     {
@@ -631,6 +655,13 @@ start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
       *context = NULL;
     }
 
+ leave:
+  for (; argc_malloced < argc; argc_malloced++)
+    xfree (argv[argc_malloced]);
+  xfree (proxy);
+  xfree (host);
+  xfree (user);
+  xfree (pass);
   return err;
 }
 
index 244919e..c2c5af1 100644 (file)
@@ -36,7 +36,7 @@
    buffer will be returned.  The caller should provide RESULT of at
    least strlen(STRING)/2 bytes.  There is no error detection, the
    parsing stops at the first non hex character.  With RESULT given as
-   NULL, the fucntion does only return the size of the buffer which
+   NULL, the function does only return the size of the buffer which
    would be needed.  */
 size_t
 unhexify (unsigned char *result, const char *string)
index f81f335..e123409 100644 (file)
@@ -83,7 +83,7 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
           return err;
         }
       if ( !(nread == bufsize-nbytes && !es_feof (fp)))
-        { /* Response succesfully received. */
+        { /* Response successfully received. */
           nbytes += nread;
           *r_buffer = buffer;
           *r_buflen = nbytes;
@@ -116,7 +116,7 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
 
 /* Construct an OCSP request, send it to the configured OCSP responder
    and parse the response. On success the OCSP context may be used to
-   further process the reponse. */
+   further process the response. */
 static gpg_error_t
 do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
                  const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert)
@@ -134,9 +134,9 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
 
   if (opt.use_tor)
     {
-      /* For now we do not allow OCSP via TOR due to possible privacy
+      /* For now we do not allow OCSP via Tor due to possible privacy
          concerns.  Needs further research.  */
-      log_error (_("OCSP request not possible due to TOR mode\n"));
+      log_error (_("OCSP request not possible due to Tor mode\n"));
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
 
index bfcdd57..0794509 100644 (file)
@@ -50,8 +50,9 @@
 #if USE_LDAP
 # include "ldap-parse-uri.h"
 #endif
-#include "dns-cert.h"
+#include "dns-stuff.h"
 #include "mbox-util.h"
+#include "zb32.h"
 
 /* To avoid DoS attacks we limit the size of a certificate to
    something reasonable.  The DoS was actually only an issue back when
@@ -90,12 +91,15 @@ struct server_local_s
   /* If this flag is set to true this dirmngr process will be
      terminated after the end of this session.  */
   int stopme;
+
+  /* State variable private to is_tor_running.  */
+  int tor_state;
 };
 
 
 /* Cookie definition for assuan data line output.  */
-static ssize_t data_line_cookie_write (void *cookie,
-                                       const void *buffer, size_t size);
+static gpgrt_ssize_t data_line_cookie_write (void *cookie,
+                                             const void *buffer, size_t size);
 static int data_line_cookie_close (void *cookie);
 static es_cookie_io_functions_t data_line_cookie_functions =
   {
@@ -119,6 +123,18 @@ get_ldapservers_from_ctrl (ctrl_t ctrl)
     return NULL;
 }
 
+/* Release an uri_item_t list.  */
+static void
+release_uri_item_list (uri_item_t list)
+{
+  while (list)
+    {
+      uri_item_t tmp = list->next;
+      http_release_parsed_uri (list->parsed_uri);
+      xfree (list);
+      list = tmp;
+    }
+}
 
 /* Release all configured keyserver info from CTRL.  */
 void
@@ -127,13 +143,8 @@ release_ctrl_keyservers (ctrl_t ctrl)
   if (! ctrl->server_local)
     return;
 
-  while (ctrl->server_local->keyservers)
-    {
-      uri_item_t tmp = ctrl->server_local->keyservers->next;
-      http_release_parsed_uri (ctrl->server_local->keyservers->parsed_uri);
-      xfree (ctrl->server_local->keyservers);
-      ctrl->server_local->keyservers = tmp;
-    }
+  release_uri_item_list (ctrl->server_local->keyservers);
+  ctrl->server_local->keyservers = NULL;
 }
 
 
@@ -209,14 +220,14 @@ data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size)
 
 /* A write handler used by es_fopencookie to write assuan data
    lines.  */
-static ssize_t
+static gpgrt_ssize_t
 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
 {
   assuan_context_t ctx = cookie;
 
   if (data_line_write (ctx, buffer, size))
     return -1;
-  return (ssize_t)size;
+  return (gpgrt_ssize_t)size;
 }
 
 
@@ -334,6 +345,38 @@ skip_options (char *line)
 }
 
 
+/* This fucntion returns true if a Tor server is running.  The sattus
+   is cached for the current conenction.  */
+static int
+is_tor_running (ctrl_t ctrl)
+{
+#if ASSUAN_VERSION_NUMBER >= 0x020402
+  /* Check whether we can connect to the proxy.  We use a
+     special feature introduced with libassuan 2.4.2.  */
+
+  if (!ctrl || !ctrl->server_local)
+    return 0; /* Ooops.  */
+
+  if (!ctrl->server_local->tor_state)
+    {
+      assuan_fd_t sock;
+
+      sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
+      if (sock == ASSUAN_INVALID_FD)
+        ctrl->server_local->tor_state = -1; /* Not running.  */
+      else
+        {
+          assuan_sock_close (sock);
+          ctrl->server_local->tor_state = 1; /* Running.  */
+        }
+    }
+  return (ctrl->server_local->tor_state > 0);
+#else /* Libassuan < 2.4.2 */
+  return 0;  /* We don't know.  */
+#endif
+}
+
+
 /* Return an error if the assuan context does not belong to the owner
    of the process or to root.  On error FAILTEXT is set as Assuan
    error string.  */
@@ -628,7 +671,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
     }
   else if (!strcmp (key, "honor-keyserver-url-used"))
     {
-      /* Return an error if we are running in TOR mode.  */
+      /* Return an error if we are running in Tor mode.  */
       if (opt.use_tor)
         err = gpg_error (GPG_ERR_FORBIDDEN);
     }
@@ -713,9 +756,10 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
         }
     }
 
-  if (opt.use_tor)
+  if (opt.use_tor && (err = enable_dns_tormode (0)))
     {
-      err = gpg_error (GPG_ERR_FORBIDDEN);
+      /* Tor mode is requested but the DNS code can't enable it.  */
+      assuan_set_error (ctx, err, "error enabling Tor mode");
       goto leave;
     }
 
@@ -1708,15 +1752,74 @@ ensure_keyserver (ctrl_t ctrl)
 {
   gpg_error_t err;
   uri_item_t item;
+  uri_item_t onion_items = NULL;
+  uri_item_t plain_items = NULL;
+  uri_item_t ui;
+  strlist_t sl;
 
   if (ctrl->server_local->keyservers)
     return 0; /* Already set for this session.  */
   if (!opt.keyserver)
     return 0; /* No global option set.  */
 
-  err = make_keyserver_item (opt.keyserver, &item);
-  if (!err)
-    ctrl->server_local->keyservers = item;
+  for (sl = opt.keyserver; sl; sl = sl->next)
+    {
+      err = make_keyserver_item (sl->d, &item);
+      if (err)
+        goto leave;
+      if (item->parsed_uri->onion)
+        {
+          item->next = onion_items;
+          onion_items = item;
+        }
+      else
+        {
+          item->next = plain_items;
+          plain_items = item;
+        }
+    }
+
+  /* Decide which to use.  Note that the sesssion has no keyservers
+     yet set. */
+  if (onion_items && !onion_items->next && plain_items && !plain_items->next)
+    {
+      /* If there is just one onion and one plain keyserver given, we take
+         only one depending on whether Tor is running or not.  */
+      if (is_tor_running (ctrl))
+        {
+          ctrl->server_local->keyservers = onion_items;
+          onion_items = NULL;
+        }
+      else
+        {
+          ctrl->server_local->keyservers = plain_items;
+          plain_items = NULL;
+        }
+    }
+  else if (!is_tor_running (ctrl))
+    {
+      /* Tor is not running.  It does not make sense to add Onion
+         addresses.  */
+      ctrl->server_local->keyservers = plain_items;
+      plain_items = NULL;
+    }
+  else
+    {
+      /* In all other cases add all keyservers.  */
+      ctrl->server_local->keyservers = onion_items;
+      onion_items = NULL;
+      for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next)
+        ;
+      if (ui)
+        ui->next = plain_items;
+      else
+        ctrl->server_local->keyservers = plain_items;
+      plain_items = NULL;
+    }
+
+ leave:
+  release_uri_item_list (onion_items);
+  release_uri_item_list (plain_items);
 
   return err;
 }
@@ -2086,11 +2189,13 @@ static const char hlp_getinfo[] =
   "\n"
   "version     - Return the version of the program.\n"
   "pid         - Return the process id of the server.\n"
-  "tor         - Return OK if running in TOR mode\n"
+  "tor         - Return OK if running in Tor mode\n"
+  "dnsinfo     - Return info about the DNS resolver\n"
   "socket_name - Return the name of the socket.\n";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
 {
+  ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
 
   if (!strcmp (line, "version"))
@@ -2119,7 +2224,28 @@ cmd_getinfo (assuan_context_t ctx, char *line)
     }
   else if (!strcmp (line, "tor"))
     {
-      err = opt.use_tor? 0:set_error (GPG_ERR_GENERAL, "TOR mode not enabled");
+      if (opt.use_tor)
+        {
+          if (!is_tor_running (ctrl))
+            err = assuan_write_status (ctx, "NO_TOR", "Tor not running");
+          else
+            err = 0;
+          if (!err)
+            assuan_set_okay_line (ctx, "- Tor mode is enabled");
+        }
+      else
+        err = set_error (GPG_ERR_FALSE, "Tor mode is NOT enabled");
+    }
+  else if (!strcmp (line, "dnsinfo"))
+    {
+#if USE_ADNS && HAVE_ADNS_IF_TORMODE
+      assuan_set_okay_line (ctx, "- ADNS with Tor support");
+#elif USE_ADNS
+      assuan_set_okay_line (ctx, "- ADNS w/o Tor support");
+#else
+      assuan_set_okay_line (ctx, "- System resolver w/o Tor support");
+#endif
+      err = 0;
     }
   else
     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
@@ -2373,6 +2499,7 @@ start_command_handler (assuan_fd_t fd)
         }
     }
 
+
 #if USE_LDAP
   ldap_wrapper_connection_cleanup (ctrl);
 
@@ -2380,6 +2507,8 @@ start_command_handler (assuan_fd_t fd)
 #endif /*USE_LDAP*/
   ctrl->server_local->ldapservers = NULL;
 
+  release_ctrl_keyservers (ctrl);
+
   ctrl->server_local->assuan_ctx = NULL;
   assuan_release (ctx);
 
diff --git a/dirmngr/t-dns-cert.c b/dirmngr/t-dns-cert.c
deleted file mode 100644 (file)
index 61536c5..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* t-dns-cert.c - Module test for dns-cert.c
- * Copyright (C) 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 <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "util.h"
-#include "dns-cert.h"
-
-
-int
-main (int argc, char **argv)
-{
-  gpg_error_t err;
-  unsigned char *fpr;
-  size_t fpr_len;
-  char *url;
-  void *key;
-  size_t keylen;
-  char const *name;
-
-  if (argc)
-    {
-      argc--;
-      argv++;
-    }
-
-  if (!argc)
-    name = "simon.josefsson.org";
-  else if (argc == 1)
-    name = *argv;
-  else
-    {
-      fputs ("usage: t-dns-cert [name]\n", stderr);
-      return 1;
-    }
-
-  printf ("CERT lookup on '%s'\n", name);
-
-  err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &keylen,
-                      &fpr, &fpr_len, &url);
-  if (err)
-    printf ("get_dns_cert failed: %s <%s>\n",
-            gpg_strerror (err), gpg_strsource (err));
-  else if (key)
-    {
-      printf ("Key found (%u bytes)\n", (unsigned int)keylen);
-    }
-  else
-    {
-      if (fpr)
-       {
-         int i;
-
-         printf ("Fingerprint found (%d bytes): ", (int)fpr_len);
-         for (i = 0; i < fpr_len; i++)
-           printf ("%02X", fpr[i]);
-         putchar ('\n');
-       }
-      else
-       printf ("No fingerprint found\n");
-
-      if (url)
-       printf ("URL found: %s\n", url);
-      else
-       printf ("No URL found\n");
-
-    }
-
-  xfree (key);
-  xfree (fpr);
-  xfree (url);
-
-  return 0;
-}
diff --git a/dirmngr/t-dns-stuff.c b/dirmngr/t-dns-stuff.c
new file mode 100644 (file)
index 0000000..3030277
--- /dev/null
@@ -0,0 +1,283 @@
+/* t-dns-cert.c - Module test for dns-stuff.c
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2011, 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 <assert.h>
+
+
+#include "util.h"
+#include "dns-stuff.h"
+
+#define PGM "t-dns-stuff"
+
+static int verbose;
+static int debug;
+
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  gpg_error_t err;
+  int any_options = 0;
+  int opt_tor = 0;
+  int opt_new_circuit = 0;
+  int opt_cert = 0;
+  int opt_srv = 0;
+  int opt_bracket = 0;
+  int opt_cname = 0;
+  char const *name = NULL;
+
+  gpgrt_init ();
+  log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX);
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " [HOST]\n"
+                 "Options:\n"
+                 "  --verbose         print timings etc.\n"
+                 "  --debug           flyswatter\n"
+                 "  --use-tor         use Tor\n"
+                 "  --new-circuit     use a new Tor circuit\n"
+                 "  --bracket         enclose v6 addresses in brackets\n"
+                 "  --cert            lookup a CERT RR\n"
+                 "  --srv             lookup a SRV RR\n"
+                 "  --cname           lookup a CNAME RR\n"
+                 , stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--use-tor"))
+        {
+          opt_tor = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--new-circuit"))
+        {
+          opt_new_circuit = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--bracket"))
+        {
+          opt_bracket = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cert"))
+        {
+          any_options = opt_cert = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--srv"))
+        {
+          any_options = opt_srv = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cname"))
+        {
+          any_options = opt_cname = 1;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        {
+          fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+          exit (1);
+        }
+    }
+
+  if (!argc && !any_options)
+    {
+      opt_cert = 1;
+      name = "simon.josefsson.org";
+    }
+  else if (argc == 1)
+    name = *argv;
+  else
+    {
+      fprintf (stderr, PGM ": none or too many host names given\n");
+      exit (1);
+    }
+
+  if (opt_tor)
+    {
+      err = enable_dns_tormode (opt_new_circuit);
+      if (err)
+        {
+          fprintf (stderr, "error switching into Tor mode: %s\n",
+                   gpg_strerror (err));
+          exit (1);
+        }
+    }
+
+  if (opt_cert)
+    {
+      unsigned char *fpr;
+      size_t fpr_len;
+      char *url;
+      void *key;
+      size_t keylen;
+
+      printf ("CERT lookup on '%s'\n", name);
+
+      err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &keylen,
+                          &fpr, &fpr_len, &url);
+      if (err)
+        printf ("get_dns_cert failed: %s <%s>\n",
+                gpg_strerror (err), gpg_strsource (err));
+      else if (key)
+        {
+          printf ("Key found (%u bytes)\n", (unsigned int)keylen);
+        }
+      else
+        {
+          if (fpr)
+            {
+              int i;
+
+              printf ("Fingerprint found (%d bytes): ", (int)fpr_len);
+              for (i = 0; i < fpr_len; i++)
+                printf ("%02X", fpr[i]);
+              putchar ('\n');
+            }
+          else
+            printf ("No fingerprint found\n");
+
+          if (url)
+            printf ("URL found: %s\n", url);
+          else
+            printf ("No URL found\n");
+
+        }
+
+      xfree (key);
+      xfree (fpr);
+      xfree (url);
+    }
+  else if (opt_cname)
+    {
+      char *cname;
+
+      printf ("CNAME lookup on '%s'\n", name);
+      err = get_dns_cname (name, &cname);
+      if (err)
+        printf ("get_dns_cname failed: %s <%s>\n",
+                gpg_strerror (err), gpg_strsource (err));
+      else
+        {
+          printf ("CNAME found: '%s'\n", cname);
+        }
+
+      xfree (cname);
+    }
+  else if (opt_srv)
+    {
+      struct srventry *srv;
+      int rc,i;
+
+      rc=getsrv (name? name : "_hkp._tcp.wwwkeys.pgp.net", &srv);
+      printf("Count=%d\n",rc);
+      for(i=0;i<rc;i++)
+        {
+          printf("priority=%-8hu  ",srv[i].priority);
+          printf("weight=%-8hu  ",srv[i].weight);
+          printf("port=%-5hu  ",srv[i].port);
+          printf("target=%s\n",srv[i].target);
+        }
+
+      xfree(srv);
+    }
+  else /* Standard lookup.  */
+    {
+      char *cname;
+      dns_addrinfo_t aibuf, ai;
+      char *host;
+
+      printf ("Lookup on '%s'\n", name);
+
+      err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
+      if (err)
+        {
+          fprintf (stderr, PGM": resolving '%s' failed: %s\n",
+                   name, gpg_strerror (err));
+          exit (1);
+        }
+
+      if (cname)
+        printf ("cname: %s\n", cname);
+      for (ai = aibuf; ai; ai = ai->next)
+        {
+          printf ("%s %3d %3d   ",
+                  ai->family == AF_INET6? "inet6" :
+                  ai->family == AF_INET?  "inet4" : "?    ",
+                  ai->socktype, ai->protocol);
+
+          err = resolve_dns_addr (ai->addr, ai->addrlen,
+                                  (DNS_NUMERICHOST
+                                   | (opt_bracket? DNS_WITHBRACKET:0)),
+                                  &host);
+          if (err)
+            printf ("[resolve_dns_addr failed: %s]", gpg_strerror (err));
+          else
+            {
+              printf ("%s", host);
+              xfree (host);
+            }
+
+          err = resolve_dns_addr (ai->addr, ai->addrlen,
+                                  (opt_bracket? DNS_WITHBRACKET:0),
+                                  &host);
+          if (err)
+            printf ("[resolve_dns_addr failed (2): %s]", gpg_strerror (err));
+          else
+            {
+              if (!is_ip_address (host))
+                printf ("  (%s)", host);
+              xfree (host);
+            }
+          putchar ('\n');
+        }
+      xfree (cname);
+      free_dns_addrinfo (aibuf);
+    }
+
+
+  return 0;
+}
similarity index 97%
rename from common/t-http.c
rename to dirmngr/t-http.c
index 41b2dd1..63662a2 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <assuan.h>
 
 #include "util.h"
 #include "logging.h"
@@ -243,6 +244,9 @@ main (int argc, char **argv)
   if (!cafile)
     cafile = prepend_srcdir ("tls-ca.pem");
 
+  /* http.c makes use of the assuan socket wrapper.  */
+  assuan_sock_init ();
+
 #if HTTP_USE_NTBTLS
 
   (void)err;
@@ -319,6 +323,11 @@ main (int argc, char **argv)
             }
           putchar ('\n');
         }
+      printf ("Flags :%s%s%s%s\n",
+              uri->is_http? " http":"",
+              uri->opaque?  " opaque":"",
+              uri->v6lit?   " v6lit":"",
+              uri->onion?   " onion":"");
       printf ("TLS   : %s\n",
               uri->use_tls? "yes":
               (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no");
similarity index 100%
rename from common/tls-ca.pem
rename to dirmngr/tls-ca.pem
index 574eca6..1a851b6 100644 (file)
@@ -597,7 +597,7 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
           break;  /* Okay: a self-signed certicate is an end-point. */
         }
 
-      /* To avoid loops, we use an arbitary limit on the length of
+      /* To avoid loops, we use an arbitrary limit on the length of
          the chain. */
       depth++;
       if (depth > maxdepth)
@@ -757,7 +757,7 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
          here because this does not seem to make much sense.  This
          might become a recursive process and we should better cache
          our validity results to avoid double work.  Far worse a
-         catch-22 may happen for an improper setup hierachy and we
+         catch-22 may happen for an improper setup hierarchy and we
          need a way to break up such a deadlock. */
       err = check_revocations (ctrl, chain);
     }
index 811b105..7c3e67c 100644 (file)
@@ -206,6 +206,10 @@ described here.
 
     For pub, sub, sec, and ssb records this field is used for the ECC
     curve name.
+*** Field 18 - TOFU Policy
+
+    This is the TOFU policy.  It is either good, bad, unknown, ask or
+    auto.  This is only shows for uid records.
 
 ** Special fields
 
@@ -764,6 +768,21 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     - <not_imported>
     - <skipped_v3_keys>
 
+*** EXPORTED  <fingerprint>
+    The key with <fingerprint> has been exported.  The fingerprint is
+    the fingerprint of the primary key even if the primary key has
+    been replaced by a stub key during secret key export.
+
+*** EXPORT_RES <args>
+
+    Final statistics on export process (this is one long line). The
+    args are a list of unsigned numbers separated by white space:
+
+    - <count>
+    - <secret_count>
+    - <exported>
+
+
 ** Smartcard related
 *** CARDCTRL <what> [<serialno>]
     This is used to control smartcard operations.  Defined values for
index 5d72017..2f3dd43 100644 (file)
@@ -123,11 +123,51 @@ Note that such a comment will be removed if the git commit option
   need.  If you really need to do it, use a separate commit for such a
   change.
 
-  - C99 syntax should not be used; stick to C90.
+  - Only certain C99 features may be used (see below); in general
+    stick to C90.
   - Please do not use C++ =//= style comments.
   - Try to fit lines into 80 columns.
   - 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.
+  - 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.
+  - Always use xfree() instead of free().  If it is not easy to see
+    that the freed variable is not anymore used, explicitly set the
+    variable to NULL.
+  - Init function local variables only if needed so that the compiler
+    can do a better job in detecting uninitialized variables which may
+    indicate a problem with the code.
+  - Never init static or file local variables to 0 to make sure they
+    end up in BSS.
+  - Use --enable-maintainer-mode with configure.
+
+*** C99 language features
+
+  In GnuPG 2.x, but *not in 1.4* and not in most libraries, a limited
+  set of C99 features may be used:
+
+  - Variadic macros:
+    : #define foo(a,...)  bar(a, __VA_ARGS__)
+
+  - The predefined macro =__func__=:
+    : log_debug ("%s: Problem with foo\n", __func__);
+
+  - Variable declaration inside a for():
+    : for (int i = 0; i < 5; ++)
+    :   bar (i);
+
+  Although we usually make use of the =u16=, =u32=, and =u64= types,
+  it is also possible to include =<stdint.h>= and use =int16_t=,
+  =int32_t=, =int64_t=, =uint16_t=, =uint32_t=, and =uint64_t=.  But do
+  not use =int8_t= or =uint8_t=.
 
 ** Commit log keywords
 
index 3ed3057..6e0bc15 100644 (file)
@@ -59,6 +59,8 @@ gnupg_TEXINFOS = \
        sysnotes.texi gnupg-card-architecture.fig dirmngr.texi \
        howtos.texi howto-create-a-server-cert.texi
 
+gnupg.texi : defs.inc
+
 DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips
 
 AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css
@@ -71,7 +73,7 @@ myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
 myman_pages   = gpg2.1 gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 gpgv2.1 \
                 watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
                gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 \
-               applygnupgdefaults.8 gpg-zip.1 \
+               applygnupgdefaults.8 \
                dirmngr-client.1
 
 man_MANS = $(myman_pages) gnupg.7
@@ -82,7 +84,7 @@ watchgnupg_SOURCE = gnupg.texi
 CLEANFILES = yat2m mkdefsinc defs.inc
 
 DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \
-                $(myman_pages) gnupg.7
+                $(myman_pages) gpg-zip.1 gpgkey2ssh.1 gnupg.7
 
 yat2m: yat2m.c
        $(CC_FOR_BUILD) -o $@ $(srcdir)/yat2m.c
@@ -108,8 +110,10 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h
 yat2m-stamp: $(myman_sources) defs.inc
        @rm -f yat2m-stamp.tmp
        @touch yat2m-stamp.tmp
+       incd="`test -f defsincdate || echo '$(srcdir)/'`defsincdate"; \
        for file in $(myman_sources) ; do \
               ./yat2m $(YAT2M_OPTIONS) --store \
+                  --date "`cat $$incd 2>/dev/null`" \
                  `test -f '$$file' || echo '$(srcdir)/'`$$file ; done
        @mv -f yat2m-stamp.tmp $@
 
index 18e8189..5b73d7b 100644 (file)
@@ -238,29 +238,46 @@ useful for debugging.
 
 @item --use-tor
 @opindex use-tor
-This options is not yet functional!  It will eventually switch GnuPG
-into a TOR mode to route all network access via TOR (an anonymity
-network).
+This option switches Dirmngr and thus GnuPG into ``Tor mode'' to route
+all network access via Tor (an anonymity network).  WARNING: As of now
+this still leaks the DNS queries; e.g. to lookup the hosts in a
+keyserver pool.  Certain other features are disabled if this mode is
+active.
 
-@item --keyserver @code{name}
+@item --keyserver @var{name}
 @opindex keyserver
-Use @code{name} as your keyserver.  This is the server that @command{gpg}
+Use @var{name} as your keyserver.  This is the server that @command{gpg}
 communicates with to receive keys, send keys, and search for
-keys.  The format of the @code{name} is a URI:
+keys.  The format of the @var{name} is a URI:
 `scheme:[//]keyservername[:port]' The scheme is the type of keyserver:
 "hkp" for the HTTP (or compatible) keyservers, "ldap" for the LDAP
 keyservers, or "mailto" for the Graff email keyserver. Note that your
 particular installation of GnuPG may have other keyserver types
 available as well. Keyserver schemes are case-insensitive. After the
 keyserver name, optional keyserver configuration options may be
-provided. These are the same as the global @option{--keyserver-options}
-from below, but apply only to this particular keyserver.
+provided.  These are the same as the @option{--keyserver-options} of
+@command{gpg}, but apply only to this particular keyserver.
 
 Most keyservers synchronize with each other, so there is generally no
 need to send keys to more than one server. The keyserver
 @code{hkp://keys.gnupg.net} uses round robin DNS to give a different
 keyserver each time you use it.
 
+If exactly two keyservers are configured and only one is a Tor hidden
+service (.onion), Dirmngr selects the keyserver to use depending on
+whether Tor is locally running or not.  The check for a running Tor is
+done for each new connection.
+
+
+@item --nameserver @var{ipaddr}
+@opindex nameserver
+In ``Tor mode'' Dirmngr uses a public resolver via Tor to resolve DNS
+names.  If the default public resolver, which is @code{8.8.8.8}, shall
+not be used a different one can be given using this option.  Note that
+a numerical IP address must be given (IPv6 or IPv4) and that no error
+checking is done for @var{ipaddr}.  DNS queries in Tor mode do only
+work if GnuPG as been build with ADNS support.
+
 @item --disable-ldap
 @opindex disable-ldap
 Entirely disables the use of LDAP.
@@ -1000,7 +1017,7 @@ as a binary blob.
 @c
 @c Here we may encounter a recursive situation:
 @c @code{validate_cert_chain} needs to look at other certificates and
-@c also at CRLs to check whether tehse other certificates and well, the
+@c also at CRLs to check whether these other certificates and well, the
 @c CRL issuer certificate itself are not revoked.  FIXME: We need to make
 @c sure that @code{validate_cert_chain} does not try to lookup the CRL we
 @c are currently processing. This would be a catch-22 and may indicate a
index 1fddeb0..d0e5199 100644 (file)
@@ -35,7 +35,8 @@ Published by The GnuPG Project@*
 @end iftex
 
 @copyright{} 2002, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.@*
-@copyright{} 2013, 2014, 2015 Werner Koch.
+@copyright{} 2013, 2014, 2015 Werner Koch.@*
+@copyright{} 2015 g10 Code GmbH.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
index 35291a8..d6ae579 100644 (file)
@@ -525,6 +525,12 @@ 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
+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
+fingerprint (preferred) or their keyid.
 
 @c @item --server
 @c @opindex server
@@ -607,7 +613,7 @@ line.
 
   @item key @code{n}
   @opindex keyedit:key
-  Toggle selection of subkey with index @code{n}.
+  Toggle selection of subkey with index @code{n} or key ID @code{n}.
   Use @code{*} to select all and @code{0} to deselect all.
 
   @item sign
@@ -644,6 +650,10 @@ and "t" (for trust) may be freely mixed and prefixed to "sign" to
 create a signature of any type desired.
 @c man:.RE
 
+If the option @option{--only-sign-text-ids} is specified, then any
+non-text based user ids (e.g., photo IDs) will not be selected for
+signing.
+
 @table @asis
 
   @item delsig
@@ -987,6 +997,10 @@ in the option file.
 Use @var{name} as the default key to sign with. If this option is not
 used, the default key is the first key found in the secret keyring.
 Note that @option{-u} or @option{--local-user} overrides this option.
+This option may be given multiple times.  In this case, the last key
+for which a secret key is available is used.  If there is no secret
+key available for any of the specified values, GnuPG will not emit an
+error message but continue as if this option wasn't given.
 
 @item --default-recipient @var{name}
 @opindex default-recipient
@@ -1093,7 +1107,7 @@ give the opposite meaning.  The options are:
   @item show-uid-validity
   @opindex list-options:show-uid-validity
   Display the calculated validity of user IDs during key listings.
-  Defaults to no.
+  Defaults to yes.
 
   @item show-unusable-uids
   @opindex list-options:show-unusable-uids
@@ -1138,7 +1152,7 @@ the opposite meaning. The options are:
 
   @item show-policy-urls
   @opindex verify-options:show-policy-urls
-  Show policy URLs in the signature being verified. Defaults to no.
+  Show policy URLs in the signature being verified. Defaults to yes.
 
   @item show-notations
   @itemx show-std-notations
@@ -1152,12 +1166,12 @@ the opposite meaning. The options are:
   @item show-keyserver-urls
   @opindex verify-options:show-keyserver-urls
   Show any preferred keyserver URL in the signature being verified.
-  Defaults to no.
+  Defaults to yes.
 
   @item show-uid-validity
   @opindex verify-options:show-uid-validity
   Display the calculated validity of the user IDs on the key that issued
-  the signature. Defaults to no.
+  the signature. Defaults to yes.
 
   @item show-unusable-uids
   @opindex verify-options:show-unusable-uids
@@ -1408,7 +1422,7 @@ don't want to keep your secret keys (or one of them)
 online but still want to be able to check the validity of a given
 recipient's or signator's key.
 
-@item --trust-model @code{pgp|classic|direct|always|auto}
+@item --trust-model @code{pgp|classic|tofu|tofu+pgp|direct|always|auto}
 @opindex trust-model
 Set what trust model GnuPG should follow. The models are:
 
@@ -1424,6 +1438,65 @@ Set what trust model GnuPG should follow. The models are:
   @opindex trust-mode:classic
   This is the standard Web of Trust as introduced by PGP 2.
 
+  @item tofu
+  @opindex trust-mode:tofu
+  @anchor{trust-model-tofu}
+  TOFU stands for Trust On First Use.  In this trust model, the first
+  time a key is seen, it is memorized.  If later another key is seen
+  with a user id with the same email address, a warning is displayed
+  indicating that there is a conflict and that the key might be a
+  forgery and an attempt at a man-in-the-middle attack.
+
+  Because a potential attacker is able to control the email address
+  and thereby circumvent the conflict detection algorithm by using an
+  email address that is similar in appearance to a trusted email
+  address, whenever a message is verified, statistics about the number
+  of messages signed with the key are shown.  In this way, a user can
+  easily identify attacks using fake keys for regular correspondents.
+
+  When compared with the Web of Trust, TOFU offers significantly
+  weaker security guarantees.  In particular, TOFU only helps ensure
+  consistency (that is, that the binding between a key and email
+  address doesn't change).  A major advantage of TOFU is that it
+  requires little maintenance to use correctly.  To use the web of
+  trust properly, you need to actively sign keys and mark users as
+  trusted introducers.  This is a time-consuming process and anecdotal
+  evidence suggests that even security-conscious users rarely take the
+  time to do this thoroughly and instead rely on an ad-hoc TOFU
+  process.
+
+  In the TOFU model, policies are associated with bindings between
+  keys and email addresses (which are extracted from user ids and
+  normalized).  There are five policies, which can be set manually
+  using the @option{--tofu-policy} option.  The default policy can be
+  set using the @option{--tofu-default-policy} policy.
+
+  The TOFU policies are: @code{auto}, @code{good}, @code{unknown},
+  @code{bad} and @code{ask}.  The @code{auto} policy is used by
+  default (unless overridden by @option{--tofu-default-policy}) and
+  marks a binding as marginally trusted.  The @code{good},
+  @code{unknown} and @code{bad} policies mark a binding as fully
+  trusted, as having unknown trust or as having trust never,
+  respectively.  The @code{unknown} policy is useful for just using
+  TOFU to detect conflicts, but to never assign positive trust to a
+  binding.  The final policy, @code{ask} prompts the user to indicate
+  the binding's trust.  If batch mode is enabled (or input is
+  inappropriate in the context), then the user is not prompted and the
+  @code{undefined} trust level is returned.
+
+  @item tofu+pgp
+  @opindex trust-mode:tofu+pgp
+  This trust model combines TOFU with the Web of Trust.  This is done
+  by computing the trust level for each model and then taking the
+  maximum trust level where the trust levels are ordered as follows:
+  @code{unknown < undefined < marginal < fully < ultimate < expired <
+  never}.
+
+  By setting @option{--tofu-default-policy=unknown}, this model can be
+  used to implement the web of trust with TOFU's conflict detection
+  algorithm, but without its assignment of positive trust values,
+  which some security-conscious users don't like.
+
   @item direct
   @opindex trust-mode:direct
   Key validity is set directly by the user and not calculated via the
@@ -1625,6 +1698,30 @@ key signer (defaults to 1).
 Number of marginally trusted users to introduce a new
 key signer (defaults to 3)
 
+@item --tofu-default-policy @code{auto|good|unknown|bad|ask}
+@opindex tofu-default-policy
+The default TOFU policy (defaults to @code{auto}).  For more
+information about the meaning of this option, @xref{trust-model-tofu}.
+
+@item --tofu-db-format @code{auto|split|flat}
+@opindex tofu-default-policy
+The format for the TOFU DB.
+
+The split file format splits the data across many DBs under the
+@code{tofu.d} directory (one per email address and one per key).  This
+makes it easier to automatically synchronize the data using a tool
+such as Unison (@url{https://www.cis.upenn.edu/~bcpierce/unison/}),
+since the individual files change rarely.
+
+The flat file format keeps all of the data in the single file
+@code{tofu.db}.  This format results in better performance.
+
+If set to auto (which is the default), GnuPG will first check for the
+existence of @code{tofu.d} and @code{tofu.db}.  If one of these
+exists, the corresponding format is used.  If neither or both of these
+exist, then GnuPG defaults to the @code{split} format.  In the latter
+case, a warning is emitted.
+
 @item --max-cert-depth @code{n}
 @opindex max-cert-depth
 Maximum depth of a certification chain (default is 5).
@@ -1823,6 +1920,11 @@ recipients given either by use of @option{--recipient} or by the asked user id.
 No trust checking is performed for these user ids and even disabled
 keys can be used.
 
+@item --encrypt-to-default-key
+@opindex encrypt-to-default-key
+If the default secret key is taken from @option{--default-key}, then
+also encrypt to that key.
+
 @item --no-encrypt-to
 @opindex no-encrypt-to
 Disable the use of all @option{--encrypt-to} and
@@ -2700,9 +2802,20 @@ message was tampered with intentionally by an attacker.
 
 @item --allow-weak-digest-algos
 @opindex allow-weak-digest-algos
-Signatures made with the broken MD5 algorithm are normally rejected
-with an ``invalid digest algorithm'' message.  This option allows the
-verification of signatures made with such weak algorithms.
+Signatures made with known-weak digest algorithms are normally
+rejected with an ``invalid digest algorithm'' message.  This option
+allows the verification of signatures made with such weak algorithms.
+MD5 is the only digest algorithm considered weak by default.  See also
+@option{--weak-digest} to reject other digest algorithms.
+
+@item --weak-digest @code{name}
+@opindex weak-digest
+Treat the specified digest algorithm as weak.  Signatures made over
+weak digests algorithms are normally rejected. This option can be
+supplied multiple times if multiple algorithms should be considered
+weak.  See also @option{--allow-weak-digest-algos} to disable
+rejection of weak digests.  MD5 is always considered weak, and does
+not need to be listed explicitly.
 
 @item --no-default-keyring
 @opindex no-default-keyring
index 6bcbc0a..280966b 100644 (file)
@@ -118,6 +118,14 @@ checks into warnings.
 
 @include opt-homedir.texi
 
+@item --weak-digest @code{name}
+@opindex weak-digest
+Treat the specified digest algorithm as weak.  Signatures made over
+weak digests algorithms are normally rejected. This option can be
+supplied multiple times if multiple algorithms should be considered
+weak.  MD5 is always considered weak, and does not need to be listed
+explicitly.
+
 @end table
 
 @mansect return value
index 1dd1b35..633502e 100644 (file)
@@ -21,6 +21,7 @@ GnuPG comes with a couple of smaller tools:
 * gpgparsemail::          Parse a mail message into an annotated format
 * symcryptrun::           Call a simple symmetric encryption tool.
 * gpg-zip::               Encrypt or sign files into an archive.
+* gpgkey2ssh::            Emit GPG public keys in OpenSSH format.
 @end menu
 
 @c
@@ -1500,7 +1501,7 @@ The return value of this command is
 
 @item 0
 The certificate under question is valid; i.e. there is a valid CRL
-available and it is not listed tehre or teh OCSP request returned that
+available and it is not listed there or the OCSP request returned that
 that certificate is valid.
 
 @item 1
@@ -1893,3 +1894,75 @@ gpg-zip --list-archive test1
 @command{tar}(1),
 @end ifset
 @include see-also-note.texi
+
+
+@c
+@c  GPGKEY2SSH
+@c
+@manpage gpgkey2ssh.1
+@node gpgkey2ssh
+@section Emit GPG public keys in OpenSSH format
+@ifset manverb
+.B gpgkey2ssh \- Emit GPG public keys in OpenSSH format
+@end ifset
+
+@mansect synopsis
+@ifset manverb
+.B  gpgkey2ssh
+.I keyid
+@end ifset
+
+@mansect description
+This tool is deprecated and will be removed soon.
+
+@command{gpgkey2ssh} emits the public key of an OpenPGP RSA or DSA key
+in a format readable by OpenSSH clients and servers.
+
+It takes only a single argument, a key ID, which designates the
+primary key or subkey whose public key should be converted.
+
+The key ID should use upper-case (A-F, not a-f) for all hex digits
+greater than 9, and the key in question must be present in
+@code{gpg}'s public keyring.
+
+The output of a successful run can be used verbatim as an entry in an
+@code{authorized_keys} file for @code{sshd}, or can be prefixed with a
+host name and appended to a @code{known_hosts} file for @code{ssh}.
+
+@mansect return value
+
+The program returns 0 if the key was successfully converted and
+non-zero if there was an error (e.g., if the key ID was malformed, the
+key was not present in the public keyring, or if the key is not an RSA
+or DSA key).
+
+@mansect environment
+@subsection Environment
+
+@table @asis
+
+@item HOME
+Used to locate the default home directory.
+
+@item GNUPGHOME
+If set directory used instead of "~/.gnupg".
+
+@end table
+
+@mansect files
+@subsection FILES
+
+@table @asis
+
+@item gpg2
+The command used to search the user's keyring.
+
+@end table
+
+@mansect see also
+@ifset isman
+@command{gpg2}(1),
+@command{sshd}(8),
+@command{ssh}(1)
+@end ifset
+@include see-also-note.texi
index e2ab86e..1634985 100644 (file)
@@ -1,5 +1,5 @@
 /* yat2m.c - Yet Another Texi 2 Man converter
- *     Copyright (C) 2005, 2013 g10 Code GmbH
+ *     Copyright (C) 2005, 2013, 2015 g10 Code GmbH
  *      Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -120,6 +120,7 @@ static int quiet;
 static int debug;
 static const char *opt_source;
 static const char *opt_release;
+static const char *opt_date;
 static const char *opt_select;
 static const char *opt_include;
 static int opt_store;
@@ -323,8 +324,12 @@ isodatestring (void)
 {
   static char buffer[11+5];
   struct tm *tp;
-  time_t atime = time (NULL);
+  time_t atime;
 
+  if (opt_date && *opt_date)
+    atime = strtoul (opt_date, NULL, 10);
+  else
+    atime = time (NULL);
   if (atime < 0)
     strcpy (buffer, "????" "-??" "-??");
   else
@@ -679,6 +684,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
   } cmdtbl[] = {
     { "command", 0, "\\fB", "\\fR" },
     { "code",    0, "\\fB", "\\fR" },
+    { "url",     0, "\\fB", "\\fR" },
     { "sc",      0, "\\fB", "\\fR" },
     { "var",     0, "\\fI", "\\fR" },
     { "samp",    0, "\\(aq", "\\(aq"  },
@@ -1466,13 +1472,14 @@ main (int argc, char **argv)
                 "Extract man pages from a Texinfo source.\n\n"
                 "  --source NAME    use NAME as source field\n"
                 "  --release STRING use STRING as the release field\n"
+                "  --date EPOCH     use EPOCH as publication date\n"
                 "  --store          write output using @manpage name\n"
                 "  --select NAME    only output pages with @manpage NAME\n"
                 "  --verbose        enable extra informational output\n"
                 "  --debug          enable additional debug output\n"
                 "  --help           display this help and exit\n"
                 "  -I DIR           also search in include DIR\n"
-                "  -D gpgone        the only useable define\n\n"
+                "  -D gpgone        the only usable define\n\n"
                 "With no FILE, or when FILE is -, read standard input.\n\n"
                 "Report bugs to <bugs@g10code.com>.");
           exit (0);
@@ -1519,6 +1526,15 @@ main (int argc, char **argv)
               argc--; argv++;
             }
         }
+      else if (!strcmp (*argv, "--date"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              opt_date = *argv;
+              argc--; argv++;
+            }
+        }
       else if (!strcmp (*argv, "--store"))
         {
           opt_store = 1;
index cd12183..10714f6 100644 (file)
 
 EXTRA_DIST = options.skel dirmngr-conf.skel distsigkey.gpg \
             ChangeLog-2011 gpg-w32info.rc \
-            gpg.w32-manifest.in test.c t-keydb-keyring.kbx
+            gpg.w32-manifest.in test.c t-keydb-keyring.kbx \
+            t-keydb-get-keyblock.gpg
 
 AM_CPPFLAGS = -I$(top_srcdir)/common
 
 include $(top_srcdir)/am/cmacros.am
 
-AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \
+AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
             $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
 
 needed_libs = ../kbx/libkeybox.a $(libcommon)
@@ -56,6 +57,12 @@ else
 trust_source = trustdb.c trustdb.h tdbdump.c tdbio.c tdbio.h
 endif
 
+if USE_TOFU
+tofu_source = tofu.h tofu.c sqlite.c sqlite.h
+else
+tofu_source =
+endif
+
 
 if HAVE_W32_SYSTEM
 resource_objs += gpg-w32info.o
@@ -124,7 +131,7 @@ gpg2_SOURCES  = gpg.c               \
              call-dirmngr.c call-dirmngr.h \
              photoid.c photoid.h \
              call-agent.c call-agent.h \
-             trust.c $(trust_source) \
+             trust.c $(trust_source) $(tofu_source) \
              $(card_source) \
              exec.c exec.h
 
@@ -141,7 +148,7 @@ gpgv2_SOURCES = gpgv.c           \
 
 LDADD =  $(needed_libs) ../common/libgpgrl.a \
          $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
-gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+gpg2_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
              $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
             $(LIBICONV) $(resource_objs) $(extra_sys_libs)
 gpg2_LDFLAGS = $(extra_bin_ldflags)
@@ -151,12 +158,16 @@ gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
 gpgv2_LDFLAGS = $(extra_bin_ldflags)
 
 t_common_ldadd =
-module_tests = t-rmd160 t-keydb
+module_tests = t-rmd160 t-keydb t-keydb-get-keyblock
 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)
 t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(t_common_ldadd)
+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)
 
 
 $(PROGRAMS): $(needed_libs) ../common/libgpgrl.a
index 6345784..8eb16e4 100644 (file)
@@ -480,6 +480,7 @@ agent_release_card_info (struct agent_card_info_s *info)
   if (!info)
     return;
 
+  xfree (info->reader); info->reader = NULL;
   xfree (info->serialno); info->serialno = NULL;
   xfree (info->apptype); info->apptype = NULL;
   xfree (info->disp_name); info->disp_name = NULL;
@@ -509,7 +510,12 @@ learn_status_cb (void *opaque, const char *line)
   while (spacep (line))
     line++;
 
-  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+  if (keywordlen == 6 && !memcmp (keyword, "READER", keywordlen))
+    {
+      xfree (parm->reader);
+      parm->reader = unescape_status_string (line);
+    }
+  else if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
     {
       xfree (parm->serialno);
       parm->serialno = store_serialno (line);
index 70421db..fa1b88a 100644 (file)
@@ -23,6 +23,7 @@
 struct agent_card_info_s
 {
   int error;         /* private. */
+  char *reader;      /* Reader information.  */
   char *apptype;     /* Malloced application type string.  */
   char *serialno;    /* malloced hex string. */
   char *disp_name;   /* malloced. */
index 10dcb20..83af0be 100644 (file)
@@ -183,13 +183,13 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
       else if ((opt.keyserver_options.options & KEYSERVER_HONOR_KEYSERVER_URL))
         {
           /* Tell the dirmngr that this possibly privacy invading
-             option is in use.  If Dirmngr is running in TOR mode, it
+             option is in use.  If Dirmngr is running in Tor mode, it
              will return an error.  */
           err = assuan_transact (ctx, "OPTION honor-keyserver-url-used",
                                  NULL, NULL, NULL, NULL, NULL, NULL);
           if (gpg_err_code (err) == GPG_ERR_FORBIDDEN)
             log_error (_("keyserver option \"honor-keyserver-url\""
-                         " may not be used in TOR mode\n"));
+                         " may not be used in Tor mode\n"));
           else if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
             err = 0; /* Old dirmngr versions do not support this option.  */
         }
index ed69058..7196031 100644 (file)
@@ -210,6 +210,7 @@ get_manufacturer (unsigned int no)
     case 0x0006: return "Yubico";
     case 0x0007: return "OpenKMS";
     case 0x0008: return "LogoEmail";
+    case 0x0009: return "Fidesmo";
 
     case 0x002A: return "Magrathea";
 
@@ -386,6 +387,11 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen)
     }
 
   if (opt.with_colons)
+    es_fprintf (fp, "Reader:%s:", info.reader? info.reader : "");
+  else
+    tty_fprintf (fp, "Reader ...........: %s\n",
+                 info.reader? info.reader : "[none]");
+  if (opt.with_colons)
     es_fprintf (fp, "AID:%s:", info.serialno? info.serialno : "");
   else
     tty_fprintf (fp, "Application ID ...: %s\n",
index 570a71d..2d9f54f 100644 (file)
@@ -221,7 +221,38 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
   else
     iobuf_push_filter ( ed->buf, decode_filter, dfx );
 
-  proc_packets (ctrl, procctx, ed->buf );
+  if (opt.unwrap_encryption)
+    {
+      char *filename;
+      estream_t fp;
+      rc = get_output_file ("", 0, ed->buf, &filename, &fp);
+      if (! rc)
+        {
+          iobuf_t output = iobuf_esopen (fp, "w", 0);
+          armor_filter_context_t *afx = NULL;
+
+          if (opt.armor)
+            {
+              afx = new_armor_context ();
+              push_armor_filter (afx, output);
+            }
+
+          iobuf_copy (output, ed->buf);
+          if ((rc = iobuf_error (ed->buf)))
+            log_error (_("error reading '%s': %s\n"),
+                       filename, gpg_strerror (rc));
+          else if ((rc = iobuf_error (output)))
+            log_error (_("error writing '%s': %s\n"),
+                       filename, gpg_strerror (rc));
+
+          iobuf_close (output);
+          if (afx)
+            release_armor_context (afx);
+        }
+    }
+  else
+    proc_packets (ctrl, procctx, ed->buf );
+
   ed->buf = NULL;
   if (dfx->eof_seen > 1 )
     rc = gpg_error (GPG_ERR_INV_PACKET);
index 063de78..b0a2b0d 100644 (file)
@@ -65,6 +65,8 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
   *r_sec_avail = 0;
 
   hd = keydb_new ();
+  if (!hd)
+    return gpg_error_from_syserror ();
 
   /* Search the userid.  */
   err = classify_user_id (username, &desc, 1);
@@ -114,7 +116,7 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
   if (secret && !have_secret_key_with_kid (keyid))
     {
       err = gpg_error (GPG_ERR_NOT_FOUND);
-      log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
+      log_error (_("key \"%s\" not found\n"), username);
       write_status_text (STATUS_DELETE_PROBLEM, "1");
       goto leave;
     }
index 8857843..d5a02d9 100644 (file)
@@ -29,6 +29,9 @@
 # Example HKP keyservers:
 #      hkp://keys.gnupg.net
 #
+# Example HKP keyserver using a Tor hidden service
+#      hkp://dyh2j3qyrirn43iw.onion
+#
 # Example HKPS keyservers (see --hkp-cacert below):
 #       hkps://hkps.pool.sks-keyservers.net
 #
 # servers via DNS round-robin.  hkp://keys.gnupg.net is an example of
 # such a "server", which spreads the load over a number of physical
 # servers.
+#
+# If exactly two keyservers are configured and only one is a Tor hidden
+# service, Dirmngr selects the keyserver to use depending on whether
+# Tor is locally running or not (on a per session base).
 
+keyserver hkp://dyh2j3qyrirn43iw.onion
 keyserver hkp://keys.gnupg.net
 
 # --hkp-cacert FILENAME
index e2e1c05..4432f29 100644 (file)
@@ -85,7 +85,7 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
   buf[0] = (*seskey)->algo;
   memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
 
-  /* We only pass already checked values to the following fucntion,
+  /* We only pass already checked values to the following function,
      thus we consider any failure as fatal.  */
   if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
     BUG ();
@@ -101,8 +101,8 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
 
 
 /* We try very hard to use a MDC */
-static int
-use_mdc(PK_LIST pk_list,int algo)
+int
+use_mdc (pk_list_t pk_list,int algo)
 {
   /* RFC-2440 don't has MDC */
   if (RFC2440)
index 2e9e61c..f7ad1b2 100644 (file)
@@ -46,14 +46,28 @@ struct subkey_list_s
 typedef struct subkey_list_s *subkey_list_t;
 
 
-static int do_export (ctrl_t ctrl,
-                      strlist_t users, int secret, unsigned int options );
+/* An object to track statistics for export operations.  */
+struct export_stats_s
+{
+  ulong count;            /* Number of processed keys.        */
+  ulong secret_count;     /* Number of secret keys seen.      */
+  ulong exported;         /* Number of actual exported keys.  */
+};
+
+
+/* Local prototypes.  */
+static int do_export (ctrl_t ctrl, strlist_t users, int secret,
+                      unsigned int options, export_stats_t stats);
 static int do_export_stream (ctrl_t ctrl, iobuf_t out,
                              strlist_t users, int secret,
                              kbnode_t *keyblock_out, unsigned int options,
-                            int *any);
+                            export_stats_t stats, int *any);
+
+\f
 
 
+/* Option parser for export options.  See parse_options fro
+   details.  */
 int
 parse_export_options(char *str,unsigned int *options,int noisy)
 {
@@ -85,39 +99,102 @@ parse_export_options(char *str,unsigned int *options,int noisy)
 }
 
 
-/****************
- * Export the public keys (to standard out or --output).
- * Depending on opt.armor the output is armored.
- * options are defined in main.h.
- * If USERS is NULL, the complete ring will be exported.  */
+/* Create a new export stats object initialized to zero.  On error
+   returns NULL and sets ERRNO.  */
+export_stats_t
+export_new_stats (void)
+{
+  export_stats_t stats;
+
+  return xtrycalloc (1, sizeof *stats);
+}
+
+
+/* Release an export stats object.  */
+void
+export_release_stats (export_stats_t stats)
+{
+  xfree (stats);
+}
+
+
+/* Print export statistics using the status interface.  */
+void
+export_print_stats (export_stats_t stats)
+{
+  if (!stats)
+    return;
+
+  if (is_status_enabled ())
+    {
+      char buf[15*20];
+
+      snprintf (buf, sizeof buf, "%lu %lu %lu",
+               stats->count,
+               stats->secret_count,
+               stats->exported );
+      write_status_text (STATUS_EXPORT_RES, buf);
+    }
+}
+
+
+/*
+ * Export public keys (to stdout or to --output FILE).
+ *
+ * Depending on opt.armor the output is armored.  OPTIONS are defined
+ * in main.h.  If USERS is NULL, all keys will be exported.  STATS is
+ * either an export stats object for update or NULL.
+ *
+ * This function is the core of "gpg --export".
+ */
 int
-export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options )
+export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
+                export_stats_t stats)
 {
-  return do_export (ctrl, users, 0, options );
+  return do_export (ctrl, users, 0, options, stats);
 }
 
-/****************
- * Export to an already opened stream; return -1 if no keys have
- * been exported
+
+/*
+ * Export secret keys (to stdout or to --output FILE).
+ *
+ * Depending on opt.armor the output is armored.  If USERS is NULL,
+ * all secret keys will be exported.  STATS is either an export stats
+ * object for update or NULL.
+ *
+ * This function is the core of "gpg --export-secret-keys".
  */
 int
-export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
-                      kbnode_t *keyblock_out, unsigned int options )
+export_seckeys (ctrl_t ctrl, strlist_t users, export_stats_t stats)
 {
-  int any, rc;
+  return do_export (ctrl, users, 1, 0, stats);
+}
 
-  rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any);
-  if (!rc && !any)
-    rc = -1;
-  return rc;
+
+/*
+ * Export secret sub keys (to stdout or to --output FILE).
+ *
+ * This is the same as export_seckeys but replaces the primary key by
+ * a stub key.  Depending on opt.armor the output is armored.  If
+ * USERS is NULL, all secret subkeys will be exported.  STATS is
+ * either an export stats object for update or NULL.
+ *
+ * This function is the core of "gpg --export-secret-subkeys".
+ */
+int
+export_secsubkeys (ctrl_t ctrl, strlist_t users, export_stats_t stats)
+{
+  return do_export (ctrl, users, 2, 0, stats);
 }
 
 
 /*
- * Export a single key into a memory buffer.
+ * Export a single key into a memory buffer.  STATS is either an
+ * export stats object for update or NULL.
  */
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   gpg_error_t err;
@@ -134,7 +211,8 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
     return gpg_error_from_syserror ();
 
   iobuf = iobuf_temp ();
-  err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &any);
+  err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options,
+                          stats, &any);
   if (!err && !any)
     err = gpg_error (GPG_ERR_NOT_FOUND);
   if (!err)
@@ -166,26 +244,14 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 
-int
-export_seckeys (ctrl_t ctrl, strlist_t users )
-{
-  return do_export (ctrl, users, 1, 0);
-}
-
-int
-export_secsubkeys (ctrl_t ctrl, strlist_t users )
-{
-  return do_export (ctrl, users, 2, 0);
-}
-
-
 /* Export the keys identified by the list of strings in USERS.  If
    Secret is false public keys will be exported.  With secret true
    secret keys will be exported; in this case 1 means the entire
    secret keyblock and 2 only the subkeys.  OPTIONS are the export
    options to apply.  */
 static int
-do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
+do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
+           export_stats_t stats)
 {
   IOBUF out = NULL;
   int any, rc;
@@ -205,7 +271,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
       push_armor_filter (afx, out);
     }
 
-  rc = do_export_stream (ctrl, out, users, secret, NULL, options, &any );
+  rc = do_export_stream (ctrl, out, users, secret, NULL, options, stats, &any);
 
   if ( rc || !any )
     iobuf_cancel (out);
@@ -743,6 +809,22 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   goto leave;
 }
 
+
+/* Print an "EXPORTED" status line.  PK is the primary public key.  */
+static void
+print_status_exported (PKT_public_key *pk)
+{
+  char *hexfpr;
+
+  if (!is_status_enabled ())
+    return;
+
+  hexfpr = hexfingerprint (pk, NULL, 0);
+  write_status_text (STATUS_EXPORTED, hexfpr? hexfpr : "[?]");
+  xfree (hexfpr);
+}
+
+
 /* Export the keys identified by the list of strings in USERS to the
    stream OUT.  If Secret is false public keys will be exported.  With
    secret true secret keys will be exported; in this case 1 means the
@@ -754,7 +836,8 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
    key has been exported true is stored at ANY. */
 static int
 do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
-                 kbnode_t *keyblock_out, unsigned int options, int *any)
+                 kbnode_t *keyblock_out, unsigned int options,
+                  export_stats_t stats, int *any)
 {
   gpg_error_t err = 0;
   PACKET pkt;
@@ -767,10 +850,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   strlist_t sl;
   gcry_cipher_hd_t cipherhd = NULL;
   char *cache_nonce = NULL;
+  struct export_stats_s dummystats;
 
+  if (!stats)
+    stats = &dummystats;
   *any = 0;
   init_packet (&pkt);
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    return gpg_error_from_syserror ();
 
   /* For the DANE format override the options.  */
   if ((options & EXPORT_DANE_FORMAT))
@@ -854,8 +942,6 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       err = keydb_search (kdbhd, desc, ndesc, &descindex);
       if (!users)
         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
-      if (gpg_err_code (err) == GPG_ERR_LEGACY_KEY)
-        continue;  /* Skip PGP2 keys.  */
       if (err)
         break;
 
@@ -863,8 +949,6 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       release_kbnode (keyblock);
       keyblock = NULL;
       err = keydb_get_keyblock (kdbhd, &keyblock);
-      if (gpg_err_code (err) == GPG_ERR_LEGACY_KEY)
-        continue;  /* Skip PGP2 keys.  */
       if (err)
         {
           log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
@@ -877,6 +961,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           log_error ("public key packet not found in keyblock - skipped\n");
           continue;
         }
+      stats->count++;
       setup_main_keyids (keyblock);  /* gpg_format_keydesc needs it.  */
       pk = node->pkt->pkt.public_key;
       keyid_from_pk (pk, keyid);
@@ -906,6 +991,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                         "not yet supported - skipped\n", keystr (keyid));
               continue;
             }
+          stats->secret_count++;
         }
 
       /* Always do the cleaning on the public key part if requested.
@@ -1109,6 +1195,11 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     }
 
                   err = build_packet (out, node->pkt);
+                  if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                    {
+                      stats->exported++;
+                      print_status_exported (node->pkt->pkt.public_key);
+                    }
                 }
               else if (!err)
                 {
@@ -1164,6 +1255,11 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     goto unwraperror;
 
                   err = build_packet (out, node->pkt);
+                  if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                    {
+                      stats->exported++;
+                      print_status_exported (node->pkt->pkt.public_key);
+                    }
                   goto unwraperror_leave;
 
                 unwraperror:
@@ -1201,8 +1297,14 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           else
             {
               err = build_packet (out, node->pkt);
+              if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                {
+                  stats->exported++;
+                  print_status_exported (node->pkt->pkt.public_key);
+                }
             }
 
+
           if (err)
             {
               log_error ("build_packet(%d) failed: %s\n",
index a5f5689..b09d967 100644 (file)
@@ -77,6 +77,10 @@ struct getkey_ctx_s
      released using getkey_end()).  */
   int not_allocated;
 
+  /* This variable is used as backing store for strings which have
+     their address used in ITEMS.  */
+  strlist_t extra_list;
+
   /* Part of the search criteria: The low-level search specification
      as passed to keydb_search.  */
   int nitems;
@@ -420,6 +424,11 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
     ctx.exact = 1; /* Use the key ID exactly as given.  */
     ctx.not_allocated = 1;
     ctx.kr_handle = keydb_new ();
+    if (!ctx.kr_handle)
+      {
+        rc = gpg_error_from_syserror ();
+        goto leave;
+      }
     ctx.nitems = 1;
     ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
     ctx.items[0].u.kid[0] = keyid[0];
@@ -478,6 +487,8 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
 #endif
 
   hd = keydb_new ();
+  if (!hd)
+    return gpg_error_from_syserror ();
   rc = keydb_search_kid (hd, keyid);
   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
@@ -524,6 +535,8 @@ get_pubkeyblock (u32 * keyid)
   /* No need to set exact here because we want the entire block.  */
   ctx.not_allocated = 1;
   ctx.kr_handle = keydb_new ();
+  if (!ctx.kr_handle)
+    return NULL;
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
@@ -548,6 +561,8 @@ get_seckey (PKT_public_key *pk, u32 *keyid)
   ctx.exact = 1; /* Use the key ID exactly as given.  */
   ctx.not_allocated = 1;
   ctx.kr_handle = keydb_new ();
+  if (!ctx.kr_handle)
+    return gpg_error_from_syserror ();
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
@@ -744,6 +759,13 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
 
   ctx->want_secret = want_secret;
   ctx->kr_handle = keydb_new ();
+  if (!ctx->kr_handle)
+    {
+      rc = gpg_error_from_syserror ();
+      getkey_end (ctx);
+      return rc;
+    }
+
   if (!ret_kb)
     ret_kb = &help_kb;
 
@@ -982,7 +1004,7 @@ 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 occured, but it
+           /* The acquisition method said no failure occurred, but it
               didn't return a fingerprint.  That's a failure.  */
            {
              no_fingerprint = 1;
@@ -1028,7 +1050,14 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
       *retctx = NULL;
     }
 
-  free_strlist (namelist);
+  if (retctx && *retctx)
+    {
+      assert (!(*retctx)->extra_list);
+      (*retctx)->extra_list = namelist;
+    }
+  else
+    free_strlist (namelist);
+
   return rc;
 }
 
@@ -1057,6 +1086,9 @@ get_pubkey_byfprint (PKT_public_key *pk, kbnode_t *r_keyblock,
       ctx.exact = 1;
       ctx.not_allocated = 1;
       ctx.kr_handle = keydb_new ();
+      if (!ctx.kr_handle)
+        return gpg_error_from_syserror ();
+
       ctx.nitems = 1;
       ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
        : KEYDB_SEARCH_MODE_FPR20;
@@ -1095,6 +1127,9 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
     fprbuf[i++] = 0;
 
   hd = keydb_new ();
+  if (!hd)
+    return gpg_error_from_syserror ();
+
   rc = keydb_search_fpr (hd, fprbuf);
   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
@@ -1121,17 +1156,90 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
   return 0;
 }
 
+const char *
+parse_def_secret_key (ctrl_t ctrl)
+{
+  KEYDB_HANDLE hd = NULL;
+  strlist_t t;
+  static int warned;
+
+  for (t = opt.def_secret_key; t; t = t->next)
+    {
+      gpg_error_t err;
+      KEYDB_SEARCH_DESC desc;
+      KBNODE kb;
+
+      err = classify_user_id (t->d, &desc, 1);
+      if (err)
+        {
+          log_error (_("secret key \"%s\" not found: %s\n"),
+                     t->d, gpg_strerror (err));
+          if (!opt.quiet)
+            log_info (_("(check argument of option '%s')\n"), "--default-key");
+          continue;
+        }
+
+      if (! hd)
+        {
+          hd = keydb_new ();
+          if (!hd)
+            return NULL;
+        }
+      else
+        keydb_search_reset (hd);
+
+
+      err = keydb_search (hd, &desc, 1, NULL);
+      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        continue;
+
+      if (err)
+        {
+          log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
+          t = NULL;
+          break;
+        }
+
+      err = keydb_get_keyblock (hd, &kb);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"),
+                     gpg_strerror (err));
+          continue;
+        }
+
+      err = agent_probe_secret_key (ctrl, kb->pkt->pkt.public_key);
+      release_kbnode (kb);
+      if (! err)
+        {
+          if (! warned)
+            log_info (_("using \"%s\" as default secret key\n"), t->d);
+          break;
+        }
+    }
+
+  warned = 1;
+
+  if (hd)
+    keydb_release (hd);
+
+  if (t)
+    return t->d;
+  return NULL;
+}
 
 /* For documentation see keydb.h.  */
 gpg_error_t
-get_seckey_default (PKT_public_key *pk)
+get_seckey_default (ctrl_t ctrl, PKT_public_key *pk)
 {
   gpg_error_t err;
   strlist_t namelist = NULL;
   int include_unusable = 1;
 
-  if (opt.def_secret_key && *opt.def_secret_key)
-    add_to_strlist (&namelist, opt.def_secret_key);
+
+  const char *def_secret_key = parse_def_secret_key (ctrl);
+  if (def_secret_key)
+    add_to_strlist (&namelist, def_secret_key);
   else
     include_unusable = 0;
 
@@ -1154,15 +1262,19 @@ getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
 
 /* For documentation see keydb.h.  */
 gpg_error_t
-getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
+getkey_byname (ctrl_t ctrl, getkey_ctx_t *retctx, PKT_public_key *pk,
                const char *name, int want_secret, kbnode_t *ret_keyblock)
 {
   gpg_error_t err;
   strlist_t namelist = NULL;
   int with_unusable = 1;
+  const char *def_secret_key = NULL;
 
-  if (want_secret && !name && opt.def_secret_key && *opt.def_secret_key)
-    add_to_strlist (&namelist, opt.def_secret_key);
+  if (want_secret && !name)
+    def_secret_key = parse_def_secret_key (ctrl);
+
+  if (want_secret && !name && def_secret_key)
+    add_to_strlist (&namelist, def_secret_key);
   else if (name)
     add_to_strlist (&namelist, name);
   else
@@ -1208,6 +1320,7 @@ getkey_end (getkey_ctx_t ctx)
   if (ctx)
     {
       keydb_release (ctx->kr_handle);
+      free_strlist (ctx->extra_list);
       if (!ctx->not_allocated)
        xfree (ctx);
     }
@@ -2214,7 +2327,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
 
       if (backsig)
        {
-         /* At ths point, backsig contains the most recent 0x19 sig.
+         /* At this point, backsig contains the most recent 0x19 sig.
             Let's see if it is good. */
 
          /* 2==valid, 1==invalid, 0==didn't check */
@@ -2596,29 +2709,6 @@ found:
 }
 
 
-/* Return true if all the search modes are fingerprints.  */
-static int
-search_modes_are_fingerprint (getkey_ctx_t ctx)
-{
-  size_t n, found;
-
-  for (n=found=0; n < ctx->nitems; n++)
-    {
-      switch (ctx->items[n].mode)
-        {
-        case KEYDB_SEARCH_MODE_FPR16:
-        case KEYDB_SEARCH_MODE_FPR20:
-        case KEYDB_SEARCH_MODE_FPR:
-          found++;
-          break;
-        default:
-          break;
-        }
-    }
-  return found && found == ctx->nitems;
-}
-
-
 /* A high-level function to lookup keys.
 
    This function builds on top of the low-level keydb API.  It first
@@ -2626,10 +2716,6 @@ search_modes_are_fingerprint (getkey_ctx_t ctx)
    then it filters the results using CTX and, finally, if WANT_SECRET
    is set, it ignores any keys for which no secret key is available.
 
-   Note: this function skips any legacy keys unless the search mode is
-   KEYDB_SEARCH_MODE_FIRST or KEYDB_SEARCH_MODE_NEXT or we are
-   searching by fingerprint.
-
    Unlike the low-level search functions, this function also merges
    all of the self-signed data into the keys, subkeys and user id
    packets (see the merge_selfsigs for details).
@@ -2647,18 +2733,6 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
   for (;;)
     {
       rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL);
-
-      /* Skip over all legacy keys unless we are iterating over all
-        keys in the DB or the key was requested by its fingerprint.
-
-         Fixme: The lower level keydb code should actually do that but
-         then it would be harder to report the number of skipped
-         legacy keys during import. */
-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
-          && !(ctx->nitems && (ctx->items->mode == KEYDB_SEARCH_MODE_FIRST
-                              || ctx->items->mode == KEYDB_SEARCH_MODE_NEXT))
-          && !search_modes_are_fingerprint (ctx))
-        continue;
       if (rc)
         break;
 
@@ -2706,8 +2780,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
     }
 
 found:
-  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND
-      && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
 
   if (!rc)
@@ -2715,8 +2788,7 @@ found:
       *ret_keyblock = keyblock; /* Return the keyblock.  */
       keyblock = NULL;
     }
-  else if ((gpg_err_code (rc) == GPG_ERR_NOT_FOUND
-            || gpg_err_code (rc) == GPG_ERR_LEGACY_KEY) && no_suitable_key)
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
     rc = want_secret? GPG_ERR_UNUSABLE_SECKEY : GPG_ERR_UNUSABLE_PUBKEY;
   else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = want_secret? GPG_ERR_NO_SECKEY : GPG_ERR_NO_PUBKEY;
@@ -2737,7 +2809,7 @@ found:
 
 /* For documentation see keydb.h.  */
 gpg_error_t
-enum_secret_keys (void **context, PKT_public_key *sk)
+enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
 {
   gpg_error_t err = 0;
   const char *name;
@@ -2783,8 +2855,7 @@ enum_secret_keys (void **context, PKT_public_key *sk)
               switch (c->state)
                 {
                 case 0: /* First try to use the --default-key.  */
-                  if (opt.def_secret_key && *opt.def_secret_key)
-                    name = opt.def_secret_key;
+                  name = parse_def_secret_key (ctrl);
                   c->state = 1;
                   break;
 
@@ -2810,7 +2881,7 @@ enum_secret_keys (void **context, PKT_public_key *sk)
             }
           while (!name || !*name);
 
-          err = getkey_byname (NULL, NULL, name, 1, &c->keyblock);
+          err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
           if (err)
             {
               /* getkey_byname might return a keyblock even in the
@@ -3106,7 +3177,11 @@ parse_auto_key_locate (char *options)
 }
 
 
-/* For documentation see keydb.h.  */
+/* Returns true if a secret key is available for the public key with
+   key id KEYID; returns false if not.  This function ignores legacy
+   keys.  Note: this is just a fast check and does not tell us whether
+   the secret key is valid; this check merely indicates whether there
+   is some secret key with the specified key id.  */
 int
 have_secret_key_with_kid (u32 *keyid)
 {
@@ -3118,6 +3193,8 @@ have_secret_key_with_kid (u32 *keyid)
   int result = 0;
 
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    return 0;
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = keyid[0];
@@ -3125,8 +3202,6 @@ have_secret_key_with_kid (u32 *keyid)
   while (!result)
     {
       err = keydb_search (kdbhd, &desc, 1, NULL);
-      if (gpg_err_code (err) == GPG_ERR_LEGACY_KEY)
-        continue;
       if (err)
         break;
 
@@ -3147,9 +3222,8 @@ have_secret_key_with_kid (u32 *keyid)
               assert (node->pkt->pkttype == PKT_PUBLIC_KEY
                       || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
 
-              if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key) == 0)
-               /* Not available.  */
-               result = 1;
+              if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
+               result = 1; /* Secret key available.  */
              else
                result = 0;
 
index 39cc2e5..2b48421 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -59,6 +59,7 @@
 #include "gc-opt-flags.h"
 #include "asshelp.h"
 #include "call-dirmngr.h"
+#include "tofu.h"
 #include "../common/init.h"
 #include "../common/shareddefs.h"
 
@@ -162,6 +163,7 @@ enum cmd_and_opt_values
     aChangePIN,
     aPasswd,
     aServer,
+    aTOFUPolicy,
 
     oTextmode,
     oNoTextmode,
@@ -301,6 +303,7 @@ enum cmd_and_opt_values
     oEncryptTo,
     oHiddenEncryptTo,
     oNoEncryptTo,
+    oEncryptToDefaultKey,
     oLoggerFD,
     oLoggerFile,
     oUtf8Strings,
@@ -385,6 +388,11 @@ enum cmd_and_opt_values
     oNoAutostart,
     oPrintPKARecords,
     oPrintDANERecords,
+    oTOFUDefaultPolicy,
+    oTOFUDBFormat,
+    oWeakDigest,
+    oUnwrap,
+    oOnlySignTextIDs,
 
     oNoop
   };
@@ -475,6 +483,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aPrimegen, "gen-prime", "@" ),
   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)")),
 
   ARGPARSE_group (301, N_("@\nOptions:\n ")),
 
@@ -493,6 +503,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oEncryptTo,      "encrypt-to", "@"),
   ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"),
   ARGPARSE_s_s (oHiddenEncryptTo, "hidden-encrypt-to", "@"),
+  ARGPARSE_s_n (oEncryptToDefaultKey, "encrypt-to-default-key", "@"),
   ARGPARSE_s_s (oLocalUser, "local-user",
                 N_("|USER-ID|use USER-ID to sign or decrypt")),
 
@@ -670,6 +681,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
   ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
   ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
+  ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
+  ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
   ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
   ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"),
@@ -741,6 +754,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oPersonalCompressPreferences,
                                          "personal-compress-preferences", "@"),
   ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
+  ARGPARSE_s_s (oWeakDigest, "weak-digest","@"),
+  ARGPARSE_s_n (oUnwrap, "unwrap", "@"),
+  ARGPARSE_s_n (oOnlySignTextIDs, "only-sign-text-ids", "@"),
 
   /* Aliases.  I constantly mistype these, and assume other people do
      as well. */
@@ -1027,7 +1043,7 @@ build_list (const char *text, char letter,
   if (maybe_setuid)
     gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
 
-  indent = utf8_charcount (text);
+  indent = utf8_charcount (text, -1);
   len = 0;
   init_membuf (&mb, 512);
 
@@ -1939,6 +1955,12 @@ parse_trust_model(const char *model)
     opt.trust_model=TM_ALWAYS;
   else if(ascii_strcasecmp(model,"direct")==0)
     opt.trust_model=TM_DIRECT;
+#ifdef USE_TOFU
+  else if(ascii_strcasecmp(model,"tofu")==0)
+    opt.trust_model=TM_TOFU;
+  else if(ascii_strcasecmp(model,"tofu+pgp")==0)
+    opt.trust_model=TM_TOFU_PGP;
+#endif /*USE_TOFU*/
   else if(ascii_strcasecmp(model,"auto")==0)
     opt.trust_model=TM_AUTO;
   else
@@ -1947,7 +1969,64 @@ parse_trust_model(const char *model)
 #endif /*NO_TRUST_MODELS*/
 
 
-/* This fucntion called to initialized a new control object.  It is
+static int
+parse_tofu_policy (const char *policystr)
+{
+#ifdef USE_TOFU
+  struct { const char *keyword; int policy; } list[] = {
+    { "auto",    TOFU_POLICY_AUTO },
+    { "good",    TOFU_POLICY_GOOD },
+    { "unknown", TOFU_POLICY_UNKNOWN },
+    { "bad",     TOFU_POLICY_BAD },
+    { "ask",     TOFU_POLICY_ASK }
+  };
+  int i;
+
+  if (!ascii_strcasecmp (policystr, "help"))
+    {
+      log_info (_("available TOFU policies:\n"));
+      for (i=0; i < DIM (list); i++)
+        log_info ("  %s\n", list[i].keyword);
+      g10_exit (1);
+    }
+
+  for (i=0; i < DIM (list); i++)
+    if (!ascii_strcasecmp (policystr, list[i].keyword))
+      return list[i].policy;
+#endif /*USE_TOFU*/
+
+  log_error (_("unknown TOFU policy '%s'\n"), policystr);
+  if (!opt.quiet)
+    log_info (_("(use \"help\" to list choices)\n"));
+  g10_exit (1);
+}
+
+static int
+parse_tofu_db_format (const char *db_format)
+{
+#ifdef USE_TOFU
+  if (ascii_strcasecmp (db_format, "auto") == 0)
+    return TOFU_DB_AUTO;
+  else if (ascii_strcasecmp (db_format, "split") == 0)
+    return TOFU_DB_SPLIT;
+  else if (ascii_strcasecmp (db_format, "flat") == 0)
+    return TOFU_DB_FLAT;
+  else if (ascii_strcasecmp (db_format, "help") == 0)
+    {
+      log_info ("available TOFU DB fomats: auto, split, flat\n");
+      g10_exit (1);
+    }
+  else
+#endif /*USE_TOFU*/
+    {
+      log_error (_("unknown TOFU DB format '%s'\n"), db_format);
+      if (!opt.quiet)
+        log_info (_("(use \"help\" to list choices)\n"));
+      g10_exit (1);
+    }
+}
+
+/* This function called to initialized a new control object.  It is
    assumed that this object has been zeroed out before calling this
    function. */
 static void
@@ -2023,6 +2102,248 @@ get_default_configname (void)
 }
 
 
+static gpg_error_t
+check_user_ids (strlist_t *sp,
+                int warn_possibly_ambiguous,
+                int error_if_not_found)
+{
+  strlist_t s = *sp;
+  strlist_t s2 = NULL;
+  strlist_t t;
+
+  gpg_error_t rc = 0;
+  gpg_error_t err;
+
+  KEYDB_HANDLE hd = NULL;
+
+  /* A quick check to avoid allocating a new strlist if we can skip
+     all keys.  Handles also the case of !SP.  See below for details.  */
+  for (t = s; t && (!(t->flags & PK_LIST_CONFIG)
+                    && !(t->flags & PK_LIST_ENCRYPT_TO)); t = t->next)
+    ;
+  if (!t)
+    return 0;
+
+  for (t = s; t; t = t->next)
+    {
+      const char *option;
+
+      KEYDB_SEARCH_DESC desc;
+      KBNODE kb;
+      PKT_public_key *pk;
+      char fingerprint_bin[MAX_FINGERPRINT_LEN];
+      size_t fingerprint_bin_len = sizeof (fingerprint_bin);
+      /* We also potentially need a ! at the end.  */
+      char fingerprint[2 * MAX_FINGERPRINT_LEN + 1 + 1];
+
+      /* If the key has been given on the command line and it has not
+         been given by one of the encrypt-to options, we skip the
+         checks.  The reason is that the actual key selection code
+         does its own checks and provides proper status message to the
+         caller to detect the wrong keys.  */
+      if (!(t->flags & PK_LIST_CONFIG) && !(t->flags & PK_LIST_ENCRYPT_TO))
+        {
+          add_to_strlist (&s2, t->d);
+          s2->flags = t->flags;
+          continue;
+        }
+
+      switch (t->flags >> PK_LIST_SHIFT)
+        {
+        case oDefaultKey: option = "--default-key"; break;
+        case oEncryptTo: option = "--encrypt-to"; break;
+        case oHiddenEncryptTo: option = "--hidden-encrypt-to"; break;
+        case oEncryptToDefaultKey: option = "--encrypt-to-default-key"; break;
+        case oRecipient: option = "--recipient"; break;
+        case oHiddenRecipient: option = "--hidden-recipient"; break;
+        case oLocalUser: option = "--local-user"; break;
+        default:
+          log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
+        }
+
+      if (DBG_LOOKUP)
+        {
+          log_debug ("\n");
+          log_debug ("%s: Checking %s=%s\n", __func__, option, t->d);
+        }
+
+      err = classify_user_id (t->d, &desc, 1);
+      if (err)
+        {
+          if (! rc)
+            rc = err;
+
+          log_error (_("key \"%s\" not found: %s\n"),
+                       t->d, gpg_strerror (err));
+          if (!opt.quiet)
+            log_info (_("(check argument of option '%s')\n"), option);
+          continue;
+        }
+
+      if (warn_possibly_ambiguous
+          && ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+                || desc.mode == KEYDB_SEARCH_MODE_FPR16
+                || desc.mode == KEYDB_SEARCH_MODE_FPR20
+                || desc.mode == KEYDB_SEARCH_MODE_FPR))
+        log_info (_("Warning: value '%s' for option '%s'"
+                    " should be a long key ID or a fingerprint\n"),
+                  t->d, option);
+
+      if (! hd)
+        {
+          hd = keydb_new ();
+          if (!hd)
+            {
+              rc = gpg_error_from_syserror ();
+              break;
+            }
+        }
+      else
+        keydb_search_reset (hd);
+
+      err = keydb_search (hd, &desc, 1, NULL);
+      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        {
+          if (DBG_LOOKUP)
+            log_debug ("%s: '%s' not found.\n", __func__, t->d);
+
+          if (error_if_not_found)
+            {
+              if (! rc)
+                rc = err;
+
+              log_error (_("key \"%s\" not found\n"), t->d);
+              if (!opt.quiet)
+                log_info (_("(check argument of option '%s')\n"), option);
+            }
+          continue;
+        }
+      if (err)
+        {
+          if (! rc)
+            rc = err;
+
+          log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
+          break;
+        }
+
+      err = keydb_get_keyblock (hd, &kb);
+      if (err)
+        {
+          if (! rc)
+            rc = err;
+
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+          continue;
+        }
+
+      pk = kb->pkt->pkt.public_key;
+      if ((desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
+           || desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+           || desc.mode == KEYDB_SEARCH_MODE_FPR16
+           || desc.mode == KEYDB_SEARCH_MODE_FPR20)
+          && strchr (t->d, '!'))
+        /* Exact search.  In this case we want to set FINGERPRINT not
+           to the primary key, but the key (primary or sub) that
+           matched the search criteria.  Note: there will always be
+           exactly one match.  */
+        {
+          kbnode_t n = kb;
+          PKT_public_key *match = NULL;
+          int i;
+
+          do
+            {
+              if ((n->flag & 1))
+                /* The matched node.  */
+                {
+                  assert (! match);
+                  match = n->pkt->pkt.public_key;
+                }
+            }
+          while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
+          assert (match);
+
+          fingerprint_from_pk (match, fingerprint_bin, &fingerprint_bin_len);
+          assert (fingerprint_bin_len == sizeof (fingerprint_bin));
+          bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
+
+          i = strlen (fingerprint);
+          fingerprint[i] = '!';
+          fingerprint[i + 1] = '\0';
+        }
+      else
+        {
+          fingerprint_from_pk (pk, fingerprint_bin, &fingerprint_bin_len);
+          assert (fingerprint_bin_len == sizeof (fingerprint_bin));
+          bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
+        }
+
+      add_to_strlist (&s2, fingerprint);
+      s2->flags = s->flags;
+
+      release_kbnode (kb);
+
+      /* Continue the search.  */
+      if (DBG_LOOKUP)
+        log_debug ("%s: Check for duplicates for %s='%s'\n",
+                   __func__, option, t->d);
+      err = keydb_search (hd, &desc, 1, NULL);
+      if (! err)
+        /* Another result!  */
+        {
+          char fingerprint_bin2[MAX_FINGERPRINT_LEN];
+          size_t fingerprint_bin2_len = sizeof (fingerprint_bin2);
+          char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
+
+          log_error (_("key specification '%s' is ambiguous\n"), t->d);
+          if (!opt.quiet)
+            log_info (_("(check argument of option '%s')\n"), option);
+
+          if (! rc)
+            rc = GPG_ERR_AMBIGUOUS_NAME;
+
+          err = keydb_get_keyblock (hd, &kb);
+          if (err)
+            log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+          else
+            {
+              pk = kb->pkt->pkt.public_key;
+              fingerprint_from_pk (pk, fingerprint_bin2, &fingerprint_bin2_len);
+              assert (fingerprint_bin2_len == sizeof (fingerprint_bin2));
+              bin2hex (fingerprint_bin2, MAX_FINGERPRINT_LEN, fingerprint2);
+
+              /* TRANSLATORS: The %s prints a key specification which
+                 for example has been given at the command line.  Two
+                 lines with fingerprints are printed after this message.  */
+              log_info (_("'%s' matches at least:\n"), t->d);
+              log_info ("  %s\n", fingerprint);
+              log_info ("  %s\n", fingerprint2);
+
+              release_kbnode (kb);
+            }
+        }
+      else if (! (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+                  || gpg_err_code (err) == GPG_ERR_EOF))
+        /* An error (other than "not found").  */
+        {
+          log_error (_("error searching the keyring: %s\n"),
+                     gpg_strerror (err));
+          if (! rc)
+            rc = err;
+        }
+    }
+
+  strlist_rev (&s2);
+
+  keydb_release (hd);
+
+  free_strlist (s);
+  *sp = s2;
+  return rc;
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -2034,7 +2355,9 @@ main (int argc, char **argv)
     const char *fname;
     char *username;
     int may_coredump;
-    strlist_t sl, remusr= NULL, locusr=NULL;
+    strlist_t sl;
+    strlist_t remusr = NULL;
+    strlist_t locusr = NULL;
     strlist_t nrings = NULL;
     armor_filter_context_t *afx = NULL;
     int detached_sig = 0;
@@ -2150,6 +2473,8 @@ main (int argc, char **argv)
 #else
     opt.trust_model = TM_AUTO;
 #endif
+    opt.tofu_default_policy = TOFU_POLICY_AUTO;
+    opt.tofu_db_format = TOFU_DB_AUTO;
     opt.mangle_dos_filenames = 0;
     opt.min_cert_level = 2;
     set_screen_dimensions ();
@@ -2159,6 +2484,8 @@ main (int argc, char **argv)
     set_homedir (default_homedir ());
     opt.passphrase_repeat = 1;
     opt.emit_version = 1; /* Limit to the major number.  */
+    opt.weak_digests = NULL;
+    additional_weak_digest("MD5");
 
     /* Check whether we have a config file on the command line.  */
     orig_argc = argc;
@@ -2372,6 +2699,10 @@ main (int argc, char **argv)
             opt.batch = 1;
             break;
 
+          case aTOFUPolicy:
+            set_cmd (&cmd, pargs.r_opt);
+            break;
+
          case oArmor: opt.armor = 1; opt.no_armor=0; break;
          case oOutput: opt.outfile = pargs.r.ret_str; break;
          case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
@@ -2514,10 +2845,16 @@ main (int argc, char **argv)
          case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
 
 #endif /*!NO_TRUST_MODELS*/
-         case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break;
+         case oDefaultKey:
+            sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            break;
          case oDefRecipient:
             if( *pargs.r.ret_str )
-              opt.def_recipient = make_username(pargs.r.ret_str);
+             {
+               xfree (opt.def_recipient);
+               opt.def_recipient = make_username(pargs.r.ret_str);
+             }
             break;
          case oDefRecipientSelf:
             xfree(opt.def_recipient); opt.def_recipient = NULL;
@@ -2553,6 +2890,12 @@ main (int argc, char **argv)
            parse_trust_model(pargs.r.ret_str);
            break;
 #endif /*!NO_TRUST_MODELS*/
+         case oTOFUDefaultPolicy:
+           opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
+           break;
+         case oTOFUDBFormat:
+           opt.tofu_db_format = parse_tofu_db_format (pargs.r.ret_str);
+           break;
 
          case oForceOwnertrust:
            log_info(_("Note: %s is not for normal use!\n"),
@@ -2696,19 +3039,32 @@ main (int argc, char **argv)
          case oNoEncryptTo: opt.no_encrypt_to = 1; break;
          case oEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = 1;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oHiddenEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = 1|2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
+                         | PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
+          case oEncryptToDefaultKey:
+            opt.encrypt_to_default_key = 1;
+            break;
          case oRecipient: /* store the recipient */
-           add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+           sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+           sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             any_explicit_recipient = 1;
            break;
          case oHiddenRecipient: /* store the recipient with a flag */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = 2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             any_explicit_recipient = 1;
            break;
 
@@ -2751,7 +3107,10 @@ main (int argc, char **argv)
          case oAskCertLevel: opt.ask_cert_level = 1; break;
          case oNoAskCertLevel: opt.ask_cert_level = 0; break;
          case oLocalUser: /* store the local users */
-           add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
+           sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oCompress:
            /* this is the -z command line option */
@@ -3065,6 +3424,15 @@ main (int argc, char **argv)
            break;
           case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
           case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
+          case oWeakDigest:
+           additional_weak_digest(pargs.r.ret_str);
+           break;
+          case oUnwrap:
+            opt.unwrap_encryption = 1;
+            break;
+          case oOnlySignTextIDs:
+            opt.only_sign_text_ids = 1;
+            break;
 
           case oDisplay:
             set_opt_session_env ("DISPLAY", pargs.r.ret_str);
@@ -3319,7 +3687,7 @@ main (int argc, char **argv)
     /* Do these after the switch(), so they can override settings. */
     if(PGP6)
       {
-        /* That does not anymore work becuase we have no more support
+        /* That does not anymore work because we have no more support
            for v3 signatures.  */
        opt.disable_mdc=1;
        opt.escape_from=1;
@@ -3421,6 +3789,9 @@ main (int argc, char **argv)
          case aSign:
            cmdname="--sign";
            break;
+         case aSignEncr:
+           cmdname="--sign --encrypt";
+           break;
          case aClearsign:
            cmdname="--clearsign";
            break;
@@ -3650,6 +4021,37 @@ main (int argc, char **argv)
         break;
       }
 
+    {
+      int have_def_secret_key = opt.def_secret_key != NULL;
+
+      rc = check_user_ids (&locusr, 1, 1);
+      if (rc)
+        g10_exit (1);
+      rc = check_user_ids (&remusr, 0, 1);
+      if (rc)
+        g10_exit (1);
+      rc = check_user_ids (&opt.def_secret_key, 1, 0);
+      if (rc)
+        g10_exit (1);
+
+      if (opt.encrypt_to_default_key)
+        {
+          const char *default_key = parse_def_secret_key (ctrl);
+          if (default_key)
+            {
+              sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
+              sl->flags = ((oEncryptToDefaultKey << PK_LIST_SHIFT)
+                           | PK_LIST_ENCRYPT_TO);
+            }
+          else if (have_def_secret_key)
+            log_info (_("option '%s' given, but no valid default keys given\n"),
+                      "--encrypt-to-default-key");
+          else
+            log_info (_("option '%s' given, but option '%s' not given\n"),
+                      "--encrypt-to-default-key", "--default-key");
+        }
+    }
+
     /* The command dispatcher.  */
     switch( cmd )
       {
@@ -3790,7 +4192,7 @@ main (int argc, char **argv)
       case aSignSym: /* sign and conventionally encrypt the given file */
        if (argc > 1)
            wrong_args(_("--sign --symmetric [filename]"));
-       rc = sign_symencrypt_file (fname, locusr);
+       rc = sign_symencrypt_file (ctrl, fname, locusr);
         if (rc)
           {
             write_status_failure ("sign-symencrypt", rc);
@@ -3802,7 +4204,7 @@ main (int argc, char **argv)
       case aClearsign: /* make a clearsig */
        if( argc > 1 )
            wrong_args(_("--clearsign [filename]"));
-       if( (rc = clearsign_file(fname, locusr, NULL)) )
+       if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) )
           {
             write_status_failure ("sign", rc);
            log_error("%s: clearsign failed: %s\n",
@@ -4027,7 +4429,12 @@ main (int argc, char **argv)
        else if( cmd == aRecvKeys )
             rc = keyserver_import (ctrl, sl );
        else
-            rc = export_pubkeys (ctrl, sl, opt.export_options);
+          {
+            export_stats_t stats = export_new_stats ();
+            rc = export_pubkeys (ctrl, sl, opt.export_options, stats);
+            export_print_stats (stats);
+            export_release_stats (stats);
+          }
        if(rc)
          {
            if(cmd==aSendKeys)
@@ -4093,7 +4500,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_seckeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_seckeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
@@ -4101,7 +4513,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_secsubkeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_secsubkeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
@@ -4114,11 +4531,11 @@ main (int argc, char **argv)
        break;
 
       case aDesigRevoke:
-       if( argc != 1 )
-           wrong_args("--desig-revoke user-id");
-       username =  make_username(*argv);
-       gen_desig_revoke( username, locusr );
-       xfree( username );
+       if (argc != 1)
+           wrong_args ("--desig-revoke user-id");
+       username = make_username (*argv);
+       gen_desig_revoke (ctrl, username, locusr);
+       xfree (username);
        break;
 
       case aDeArmor:
@@ -4351,6 +4768,85 @@ main (int argc, char **argv)
         gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
         break;
 
+      case aTOFUPolicy:
+#ifdef USE_TOFU
+       {
+         int policy;
+         int i;
+         KEYDB_HANDLE hd;
+
+         if (argc < 2)
+           wrong_args ("--tofu-policy POLICY KEYID [KEYID...]");
+
+         policy = parse_tofu_policy (argv[0]);
+
+         hd = keydb_new ();
+         if (! hd)
+            g10_exit (1);
+
+         for (i = 1; i < argc; i ++)
+           {
+             KEYDB_SEARCH_DESC desc;
+             kbnode_t kb;
+
+             rc = classify_user_id (argv[i], &desc, 0);
+             if (rc)
+               {
+                 log_error (_("error parsing key specification '%s': %s\n"),
+                             argv[i], gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
+                    || desc.mode == KEYDB_SEARCH_MODE_LONG_KID
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR16
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR20
+                    || desc.mode == KEYDB_SEARCH_MODE_FPR
+                    || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP))
+               {
+                 log_error (_("'%s' does not appear to be a valid"
+                              " key ID, fingerprint or keygrip\n"),
+                            argv[i]);
+                 g10_exit (1);
+               }
+
+             rc = keydb_search_reset (hd);
+             if (rc)
+               {
+                  /* This should not happen, thus no need to tranalate
+                     the string.  */
+                  log_error ("keydb_search_reset failed: %s\n",
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             rc = keydb_search (hd, &desc, 1, NULL);
+             if (rc)
+               {
+                 log_error (_("key \"%s\" not found: %s\n"), argv[i],
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             rc = keydb_get_keyblock (hd, &kb);
+             if (rc)
+               {
+                 log_error (_("error reading keyblock: %s\n"),
+                             gpg_strerror (rc));
+                 g10_exit (1);
+               }
+
+             merge_keys_and_selfsig (kb);
+             if (tofu_set_policy (kb, policy))
+               g10_exit (1);
+           }
+
+         keydb_release (hd);
+
+       }
+#endif /*USE_TOFU*/
+       break;
+
       case aListPackets:
        opt.list_packets=2;
       default:
index accec24..5cd8366 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
 /* Number of bits we accept when reading or writing MPIs. */
 #define MAX_EXTERN_MPI_BITS 16384
 
-/* The maximum length of a binary fingerprints.
+/* The maximum length of a binary fingerprints.  This is used to
+   provide a static buffer and will be increased if we need to support
+   longer fingerprints.
    Warning: At some places we still use 20 instead of this macro. */
 #define MAX_FINGERPRINT_LEN 20
 
+/* The maximum length of a formatted fingerprint as returned by
+   format_hexfingerprint().  */
+#define MAX_FORMATTED_FINGERPRINT_LEN 50
+
 
 /*
    Forward declarations.
index 8bb3fc4..9932756 100644 (file)
@@ -61,6 +61,7 @@ enum cmd_and_opt_values {
   oStatusFD,
   oLoggerFD,
   oHomedir,
+  oWeakDigest,
   aTest
 };
 
@@ -78,6 +79,7 @@ static ARGPARSE_OPTS opts[] = {
                 N_("|FD|write status info to this FD")),
   ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
+  ARGPARSE_s_s (oWeakDigest, "weak-digest", "@"),
 
   ARGPARSE_end ()
 };
@@ -167,11 +169,13 @@ main( int argc, char **argv )
   opt.batch = 1;
 
   opt.homedir = default_homedir ();
+  opt.weak_digests = NULL;
 
   tty_no_terminal(1);
   tty_batchmode(1);
   dotlock_disable ();
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  additional_weak_digest("MD5");
 
   pargs.argc = &argc;
   pargs.argv = &argv;
@@ -192,6 +196,9 @@ main( int argc, char **argv )
           log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
           break;
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
+        case oWeakDigest:
+          additional_weak_digest(pargs.r.ret_str);
+          break;
         case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
         default : pargs.err = ARGPARSE_PRINT_ERROR; break;
        }
@@ -235,7 +242,7 @@ g10_exit( int rc )
 
 
 /* Stub:
- * We have to override the trustcheck from pkclist.c becuase
+ * We have to override the trustcheck from pkclist.c because
  * this utility assumes that all keys in the keyring are trustworthy
  */
 int
@@ -285,10 +292,13 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 }
 
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid)
+get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
+             int may_ask)
 {
   (void)pk;
   (void)uid;
+  (void)sig;
+  (void)may_ask;
   return 0;
 }
 
@@ -376,8 +386,9 @@ keyserver_import_ldap (const char *name)
  * No encryption here but mainproc links to these functions.
  */
 gpg_error_t
-get_session_key (PKT_pubkey_enc *k, DEK *dek)
+get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek)
 {
+  (void)ctrl;
   (void)k;
   (void)dek;
   return GPG_ERR_GENERAL;
@@ -595,14 +606,44 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
 
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   (void)ctrl;
   (void)keyspec;
   (void)options;
+  (void)stats;
 
   *r_keyblock = NULL;
   *r_data = NULL;
   *r_datalen = 0;
   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 }
+
+gpg_error_t
+tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+                enum tofu_policy *policy)
+{
+  (void)pk;
+  (void)user_id;
+  (void)policy;
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+const char *
+tofu_policy_str (enum tofu_policy policy)
+{
+  (void)policy;
+
+  return "unknown";
+}
+
+void
+tofu_begin_batch_update (void)
+{
+}
+
+void
+tofu_end_batch_update (void)
+{
+}
index 048b136..518e97f 100644 (file)
@@ -1071,7 +1071,11 @@ import_one (ctrl_t ctrl,
     }
   else if (rc )  /* Insert this key. */
     {
-      KEYDB_HANDLE hd = keydb_new ();
+      KEYDB_HANDLE hd;
+
+      hd = keydb_new ();
+      if (!hd)
+        return gpg_error_from_syserror ();
 
       rc = keydb_locate_writable (hd);
       if (rc)
@@ -1136,6 +1140,11 @@ import_one (ctrl_t ctrl,
       /* Now read the original keyblock again so that we can use
          that handle for updating the keyblock.  */
       hd = keydb_new ();
+      if (!hd)
+        {
+          rc = gpg_error_from_syserror ();
+          goto leave;
+        }
       keydb_disable_caching (hd);
       rc = keydb_search_fpr (hd, fpr2);
       if (rc )
@@ -1331,6 +1340,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
   unsigned char *wrappedkey = NULL;
   size_t wrappedkeylen;
   char *cache_nonce = NULL;
+  int stub_key_skipped = 0;
 
   /* Get the current KEK.  */
   err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
@@ -1391,7 +1401,10 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
          has been inserted and a stub key is in turn generated by the
          agent.  */
       if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
-        continue;
+        {
+          stub_key_skipped = 1;
+          continue;
+        }
 
       /* Convert our internal secret key object into an S-expression.  */
       nskey = pubkey_get_nskey (pk->pubkey_algo);
@@ -1568,6 +1581,10 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
         }
     }
 
+  if (!err && stub_key_skipped)
+    /* We need to notify user how to migrate stub keys.  */
+    err = gpg_error (GPG_ERR_NOT_PROCESSED);
+
  leave:
   gcry_sexp_release (curve);
   xfree (cache_nonce);
@@ -1630,7 +1647,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
 /****************
  * Ditto for secret keys.  Handling is simpler than for public keys.
  * We allow secret key importing only when allow is true, this is so
- * that a secret key can not be imported accidently and thereby tampering
+ * that a secret key can not be imported accidentally and thereby tampering
  * with the trust calculation.
  */
 static int
@@ -1757,8 +1774,27 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
                        keystr_from_pk (pk));
           else
             {
+              gpg_error_t err;
+
              nr_prev = stats->secret_imported;
-              if (!transfer_secret_keys (ctrl, stats, keyblock, batch))
+              err = transfer_secret_keys (ctrl, stats, keyblock, batch);
+              if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
+                {
+                  /* TRANSLATORS: For smartcard, each private key on
+                     host has a reference (stub) to a smartcard and
+                     actual private key data is stored on the card.  A
+                     single smartcard can have up to three private key
+                     data.  Importing private key stub is always
+                     skipped in 2.1, and it returns
+                     GPG_ERR_NOT_PROCESSED.  Instead, user should be
+                     suggested to run 'gpg --card-status', then,
+                     references to a card will be automatically
+                     created again.  */
+                  log_info (_("To migrate '%s', with each smartcard, "
+                              "run: %s\n"), "secring.gpg", "gpg --card-status");
+                  err = 0;
+                }
+              if (!err)
                 {
                  int status = 16;
                   if (!opt.quiet)
@@ -1819,6 +1855,12 @@ import_revoke_cert( const char *fname, kbnode_t node, struct stats_s *stats )
 
   /* Read the original keyblock. */
   hd = keydb_new ();
+  if (!hd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
+
   {
     byte afp[MAX_FINGERPRINT_LEN];
     size_t an;
index da18bc0..97dfb5f 100644 (file)
@@ -156,7 +156,7 @@ static int lock_all (KEYDB_HANDLE hd);
 static void unlock_all (KEYDB_HANDLE hd);
 
 
-/* Check whether the keyid KID is in key id is definately not in the
+/* Check whether the keyid KID is in key id is definitely not in the
    database.
 
    Returns:
@@ -465,8 +465,70 @@ rt_from_file (const char *filename, int *r_found, int *r_openpgp)
 
   return rt;
 }
+\f
+char *
+keydb_search_desc_dump (struct keydb_search_desc *desc)
+{
+  char b[MAX_FORMATTED_FINGERPRINT_LEN + 1];
+  char fpr[MAX_FINGERPRINT_LEN + 1];
 
-
+  switch (desc->mode)
+    {
+    case KEYDB_SEARCH_MODE_EXACT:
+      return xasprintf ("EXACT: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_SUBSTR:
+      return xasprintf ("SUBSTR: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_MAIL:
+      return xasprintf ("MAIL: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_MAILSUB:
+      return xasprintf ("MAILSUB: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_MAILEND:
+      return xasprintf ("MAILEND: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_WORDS:
+      return xasprintf ("WORDS: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_SHORT_KID:
+      return xasprintf ("SHORT_KID: '%s'",
+                        format_keyid (desc->u.kid, KF_SHORT, b, sizeof (b)));
+    case KEYDB_SEARCH_MODE_LONG_KID:
+      return xasprintf ("LONG_KID: '%s'",
+                        format_keyid (desc->u.kid, KF_LONG, b, sizeof (b)));
+    case KEYDB_SEARCH_MODE_FPR16:
+      bin2hex (desc->u.fpr, 16, fpr);
+      return xasprintf ("FPR16: '%s'",
+                        format_hexfingerprint (fpr, b, sizeof (b)));
+    case KEYDB_SEARCH_MODE_FPR20:
+      bin2hex (desc->u.fpr, 20, fpr);
+      return xasprintf ("FPR20: '%s'",
+                        format_hexfingerprint (fpr, b, sizeof (b)));
+    case KEYDB_SEARCH_MODE_FPR:
+      bin2hex (desc->u.fpr, 20, fpr);
+      return xasprintf ("FPR: '%s'",
+                        format_hexfingerprint (fpr, b, sizeof (b)));
+    case KEYDB_SEARCH_MODE_ISSUER:
+      return xasprintf ("ISSUER: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_ISSUER_SN:
+      return xasprintf ("ISSUER_SN: '%*s'",
+                        (int) (desc->snlen == -1
+                               ? strlen (desc->sn) : desc->snlen),
+                        desc->sn);
+    case KEYDB_SEARCH_MODE_SN:
+      return xasprintf ("SN: '%*s'",
+                        (int) (desc->snlen == -1
+                               ? strlen (desc->sn) : desc->snlen),
+                        desc->sn);
+    case KEYDB_SEARCH_MODE_SUBJECT:
+      return xasprintf ("SUBJECT: '%s'", desc->u.name);
+    case KEYDB_SEARCH_MODE_KEYGRIP:
+      return xasprintf ("KEYGRIP: %s", desc->u.grip);
+    case KEYDB_SEARCH_MODE_FIRST:
+      return xasprintf ("FIRST");
+    case KEYDB_SEARCH_MODE_NEXT:
+      return xasprintf ("NEXT");
+    default:
+      return xasprintf ("Bad search mode (%d)", desc->mode);
+    }
+}
+\f
 gpg_error_t
 keydb_add_resource (const char *url, unsigned int flags)
 {
@@ -692,17 +754,26 @@ keydb_dump_stats (void)
 }
 
 
+/* Create a new database handle.  A database handle is similar to a
+   file handle: it contains a local file position.  This is used when
+   searching: subsequent searches resume where the previous search
+   left off.  To rewind the position, use keydb_search_reset().  This
+   function returns NULL on error, sets ERRNO, and prints an error
+   diagnostic. */
 KEYDB_HANDLE
 keydb_new (void)
 {
   KEYDB_HANDLE hd;
   int i, j;
   int die = 0;
+  int reterrno;
 
   if (DBG_CLOCK)
     log_clock ("keydb_new");
 
-  hd = xmalloc_clear (sizeof *hd);
+  hd = xtrycalloc (1, sizeof *hd);
+  if (!hd)
+    goto leave;
   hd->found = -1;
   hd->saved_found = -1;
   hd->is_reset = 1;
@@ -719,7 +790,10 @@ keydb_new (void)
           hd->active[j].token  = all_resources[i].token;
           hd->active[j].u.kr = keyring_new (all_resources[i].token);
           if (!hd->active[j].u.kr)
-           die = 1;
+            {
+              reterrno = errno;
+              die = 1;
+            }
           j++;
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
@@ -727,7 +801,10 @@ keydb_new (void)
           hd->active[j].token  = all_resources[i].token;
           hd->active[j].u.kb   = keybox_new_openpgp (all_resources[i].token, 0);
           if (!hd->active[j].u.kb)
-           die = 1;
+            {
+              reterrno = errno;
+              die = 1;
+            }
           j++;
           break;
         }
@@ -739,9 +816,15 @@ keydb_new (void)
   if (die)
     {
       keydb_release (hd);
+      gpg_err_set_errno (reterrno);
       hd = NULL;
     }
 
+ leave:
+  if (!hd)
+    log_error (_("error opening key DB: %s\n"),
+               gpg_strerror (gpg_error_from_syserror()));
+
   return hd;
 }
 
@@ -1571,57 +1654,11 @@ keydb_search_reset (KEYDB_HANDLE hd)
 }
 
 
-static void
-dump_search_desc (KEYDB_HANDLE hd, const char *text,
-                  KEYDB_SEARCH_DESC *desc, size_t ndesc)
-{
-  int n;
-  const char *s;
-
-  for (n=0; n < ndesc; n++)
-    {
-      switch (desc[n].mode)
-        {
-        case KEYDB_SEARCH_MODE_NONE:      s = "none";      break;
-        case KEYDB_SEARCH_MODE_EXACT:     s = "exact";     break;
-        case KEYDB_SEARCH_MODE_SUBSTR:    s = "substr";    break;
-        case KEYDB_SEARCH_MODE_MAIL:      s = "mail";      break;
-        case KEYDB_SEARCH_MODE_MAILSUB:   s = "mailsub";   break;
-        case KEYDB_SEARCH_MODE_MAILEND:   s = "mailend";   break;
-        case KEYDB_SEARCH_MODE_WORDS:     s = "words";     break;
-        case KEYDB_SEARCH_MODE_SHORT_KID: s = "short_kid"; break;
-        case KEYDB_SEARCH_MODE_LONG_KID:  s = "long_kid";  break;
-        case KEYDB_SEARCH_MODE_FPR16:     s = "fpr16";     break;
-        case KEYDB_SEARCH_MODE_FPR20:     s = "fpr20";     break;
-        case KEYDB_SEARCH_MODE_FPR:       s = "fpr";       break;
-        case KEYDB_SEARCH_MODE_ISSUER:    s = "issuer";    break;
-        case KEYDB_SEARCH_MODE_ISSUER_SN: s = "issuer_sn"; break;
-        case KEYDB_SEARCH_MODE_SN:        s = "sn";        break;
-        case KEYDB_SEARCH_MODE_SUBJECT:   s = "subject";   break;
-        case KEYDB_SEARCH_MODE_KEYGRIP:   s = "keygrip";   break;
-        case KEYDB_SEARCH_MODE_FIRST:     s = "first";     break;
-        case KEYDB_SEARCH_MODE_NEXT:      s = "next";      break;
-        default:                          s = "?";         break;
-        }
-      if (!n)
-        log_debug ("%s: mode=%s  (hd=%p)", text, s, hd);
-      else
-        log_debug ("%*s  mode=%s", (int)strlen (text), "", s);
-      if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
-        log_printf (" %08lX%08lX", (unsigned long)desc[n].u.kid[0],
-                    (unsigned long)desc[n].u.kid[1]);
-      else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
-        log_printf (" %08lX", (unsigned long)desc[n].u.kid[1]);
-      else if (desc[n].mode == KEYDB_SEARCH_MODE_SUBSTR)
-        log_printf (" '%s'", desc[n].u.name);
-    }
-}
-
-
 gpg_error_t
 keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
               size_t ndesc, size_t *descindex)
 {
+  int i;
   gpg_error_t rc;
   int was_reset = hd->is_reset;
   /* If an entry is already in the cache, then don't add it again.  */
@@ -1636,8 +1673,16 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   if (DBG_CLOCK)
     log_clock ("keydb_search enter");
 
-  if (DBG_CACHE)
-    dump_search_desc (hd, "keydb_search", desc, ndesc);
+  if (DBG_LOOKUP)
+    {
+      log_debug ("%s: %zd search descriptions:\n", __func__, ndesc);
+      for (i = 0; i < ndesc; i ++)
+        {
+          char *t = keydb_search_desc_dump (&desc[i]);
+          log_debug ("%s   %d: %s\n", __func__, i, t);
+          xfree (t);
+        }
+    }
 
 
   if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
@@ -1668,21 +1713,43 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
          && hd->current >= 0 && hd->current < hd->used)
     {
-      switch (hd->active[hd->current].type)
+      if (DBG_LOOKUP)
+        log_debug ("%s: searching %s (resource %d of %d)\n",
+                   __func__,
+                   hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYRING
+                   ? "keyring"
+                   : (hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX
+                      ? "keybox" : "unknown type"),
+                   hd->current, hd->used);
+
+       switch (hd->active[hd->current].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           BUG(); /* we should never see it here */
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_search (hd->active[hd->current].u.kr, desc,
-                               ndesc, descindex);
+                               ndesc, descindex, 1);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
-          rc = keybox_search (hd->active[hd->current].u.kb, desc,
-                              ndesc, KEYBOX_BLOBTYPE_PGP,
-                              descindex, &hd->skipped_long_blobs);
+          do
+            rc = keybox_search (hd->active[hd->current].u.kb, desc,
+                                ndesc, KEYBOX_BLOBTYPE_PGP,
+                                descindex, &hd->skipped_long_blobs);
+          while (rc == GPG_ERR_LEGACY_KEY);
           break;
         }
+
+      if (DBG_LOOKUP)
+        log_debug ("%s: searched %s (resource %d of %d) => %s\n",
+                   __func__,
+                   hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYRING
+                   ? "keyring"
+                   : (hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX
+                      ? "keybox" : "unknown type"),
+                   hd->current, hd->used,
+                   rc == -1 ? "EOF" : gpg_strerror (rc));
+
       if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
         {
           /* EOF -> switch to next resource */
@@ -1701,7 +1768,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   if (!hd->no_caching
       && !rc
       && ndesc == 1 && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20
-                        || desc[0].mode == KEYDB_SEARCH_MODE_FPR))
+                        || desc[0].mode == KEYDB_SEARCH_MODE_FPR)
+      && hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX)
     {
       hd->keyblock_cache.state = KEYBLOCK_CACHE_PREPARED;
       memcpy (hd->keyblock_cache.fpr, desc[0].u.fpr, 20);
@@ -1731,28 +1799,18 @@ keydb_search_first (KEYDB_HANDLE hd)
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
-  err = keydb_search (hd, &desc, 1, NULL);
-  if (gpg_err_code (err) == GPG_ERR_LEGACY_KEY)
-    err = keydb_search_next (hd);
-  return err;
+  return keydb_search (hd, &desc, 1, NULL);
 }
 
 
 gpg_error_t
 keydb_search_next (KEYDB_HANDLE hd)
 {
-  gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
 
-  do
-    {
-      memset (&desc, 0, sizeof desc);
-      desc.mode = KEYDB_SEARCH_MODE_NEXT;
-      err = keydb_search (hd, &desc, 1, NULL);
-    }
-  while (gpg_err_code (err) == GPG_ERR_LEGACY_KEY);
-
-  return err;
+  memset (&desc, 0, sizeof desc);
+  desc.mode = KEYDB_SEARCH_MODE_NEXT;
+  return keydb_search (hd, &desc, 1, NULL);
 }
 
 gpg_error_t
@@ -1770,17 +1828,10 @@ keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
 gpg_error_t
 keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
 {
-  gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FPR;
   memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
-  do
-    {
-      err = keydb_search (hd, &desc, 1, NULL);
-    }
-  while (gpg_err_code (err) == GPG_ERR_LEGACY_KEY);
-
-  return err;
+  return keydb_search (hd, &desc, 1, NULL);
 }
index 680af1c..d7aa432 100644 (file)
@@ -69,6 +69,14 @@ enum resource_type {
 };
 
 
+/* Bit flags used with build_pk_list.  */
+#define PK_LIST_ENCRYPT_TO 1   /* This is an encrypt-to recipient.  */
+#define PK_LIST_HIDDEN     2   /* This is a hidden recipient.       */
+#define PK_LIST_CONFIG     4   /* Specified via config file.        */
+/* To store private data in the flags they must be left shifted by
+   this value.  */
+#define PK_LIST_SHIFT      3
+
 /****************
  * A data structure to hold information about the external position
  * of a keyblock.
@@ -133,6 +141,10 @@ union pref_hint
 #define KEYDB_RESOURCE_FLAG_READONLY 8  /* Open in read only mode.  */
 #define KEYDB_RESOURCE_FLAG_GPGVDEF 16  /* Default file for gpgv.  */
 
+/* Format a search term for debugging output.  The caller must free
+   the result.  */
+char *keydb_search_desc_dump (struct keydb_search_desc *desc);
+
 /* Register a resource (keyring or keybox).  The first keyring or
    keybox that is added using this function is created if it does not
    already exist and the KEYDB_RESOURCE_FLAG_READONLY is not set.
@@ -182,10 +194,8 @@ gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
 /* Dump some statistics to the log.  */
 void keydb_dump_stats (void);
 
-/* Create a new database handle.  A database handle is similar to a
-   file handle: it contains a local file position.  This is used when
-   searching: subsequent searches resume where the previous search
-   left off.  To rewind the position, use keydb_search_reset().  */
+/* Create a new database handle.  Returns NULL on error, sets ERRNO,
+   and prints an error diagnostic. */
 KEYDB_HANDLE keydb_new (void);
 
 /* Free all resources owned by the database handle.  */
@@ -288,11 +298,12 @@ unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
    so that the next search starts at the beginning of the database
    (the start of the first resource).
 
-   Returns 0 on success and an error code if an error occured.
+   Returns 0 on success and an error code if an error occurred.
    (Currently, this function always returns 0 if HD is valid.)  */
 gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
 
-/* Search the database for keys matching the search description.
+/* Search the database for keys matching the search description.  If
+   the DB contains any legacy keys, these are silently ignored.
 
    DESC is an array of search terms with NDESC entries.  The search
    terms are or'd together.  That is, the next entry in the DB that
@@ -305,7 +316,7 @@ gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
 
    If no key matches the search description, returns
    GPG_ERR_NOT_FOUND.  If there was a match, returns 0.  If an error
-   occured, returns an error code.
+   occurred, returns an error code.
 
    The returned key is considered to be selected and the raw data can,
    for instance, be returned by calling keydb_get_keyblock().  */
@@ -334,7 +345,7 @@ gpg_error_t keydb_search_next (KEYDB_HANDLE hd);
 gpg_error_t keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
 
 /* This is a convenience function for searching for keys with a long
-   (20 byte) fingerprint.  This function ignores legacy keys.
+   (20 byte) fingerprint.
 
    Note: this function resumes searching where the last search left
    off.  If you want to search the whole database, then you need to
@@ -364,8 +375,8 @@ void warn_missing_aes_from_pklist (PK_LIST pk_list);
 /*-- skclist.c --*/
 int  random_is_faked (void);
 void release_sk_list( SK_LIST sk_list );
-gpg_error_t  build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list,
-                            unsigned use);
+gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
+                           SK_LIST *ret_sk_list, unsigned use);
 
 /*-- passphrase.h --*/
 unsigned char encode_s2k_iterations (int iterations);
@@ -437,7 +448,7 @@ void getkey_disable_caches(void);
    occurs.
 
    If the data was not read from the cache, then the self-signed data
-   has definately been merged into the public key using
+   has definitely been merged into the public key using
    merge_selfsigs.  */
 int get_pubkey( PKT_public_key *pk, u32 *keyid );
 
@@ -575,13 +586,14 @@ int get_pubkey_byfprint (PKT_public_key *pk,  kbnode_t *r_keyblock,
 int get_pubkey_byfprint_fast (PKT_public_key *pk,
                               const byte *fprint, size_t fprint_len);
 
-/* Return whether a secret key is available for the public key with
-   key id KEYID.  This function ignores legacy keys.  Note: this is
-   just a fast check and does not tell us whether the secret key is
-   valid; this check merely indicates whether there is some secret key
-   with the specified key id.  */
+/* Returns true if a secret key is available for the public key with
+   key id KEYID.  */
 int have_secret_key_with_kid (u32 *keyid);
 
+/* Parse the --default-key parameter.  Returns the last key (in terms
+   of when the option is given) that is available.  */
+const char *parse_def_secret_key (ctrl_t ctrl);
+
 /* Look up a secret key.
 
    If PK is not NULL, the public key of the first result is returned
@@ -605,7 +617,7 @@ int have_secret_key_with_kid (u32 *keyid);
 
    This function returns the first match.  Additional results can be
    returned using getkey_next.  */
-gpg_error_t get_seckey_default (PKT_public_key *pk);
+gpg_error_t get_seckey_default (ctrl_t ctrl, PKT_public_key *pk);
 
 /* Search for keys matching some criteria.
 
@@ -686,7 +698,8 @@ gpg_error_t getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
 
    FIXME: We also have the get_pubkey_byname function which has a
    different semantic.  Should be merged with this one.  */
-gpg_error_t getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
+gpg_error_t getkey_byname (ctrl_t ctrl,
+                           getkey_ctx_t *retctx, PKT_public_key *pk,
                            const char *name, int want_secret,
                            kbnode_t *ret_keyblock);
 
@@ -746,9 +759,9 @@ KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
      free_public_key (sk);
 
      if (gpg_err_code (err) != GPG_ERR_EOF)
-       ; // An error occured.
+       ; // An error occurred.
  */
-gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
+gpg_error_t enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *pk);
 
 /* Set the mainkey_id fields for all keys in KEYBLOCK.  This is
    usually done by merge_selfsigs but at some places we only need the
@@ -781,6 +794,7 @@ 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);
 size_t keystrlen(void);
 const char *keystr(u32 *keyid);
 const char *keystr_with_sub (u32 *main_kid, u32 *sub_kid);
@@ -804,7 +818,9 @@ const char *colon_datestr_from_pk (PKT_public_key *pk);
 const char *colon_datestr_from_sig (PKT_signature *sig);
 const char *colon_expirestr_from_sig (PKT_signature *sig);
 byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
-char *hexfingerprint (PKT_public_key *pk);
+char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
+char *format_hexfingerprint (const char *fingerprint,
+                             char *buffer, size_t buflen);
 gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
 gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
 
index 4803f9e..0a4766e 100644 (file)
@@ -1,6 +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
  *
  * This file is part of GnuPG.
  *
@@ -47,6 +48,7 @@
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "host2net.h"
+#include "tofu.h"
 
 static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
                        int verbose);
@@ -75,7 +77,7 @@ static int menu_set_keyserver_url (const char *url, KBNODE pub_keyblock);
 static int menu_set_notation (const char *string, KBNODE pub_keyblock);
 static int menu_select_uid (KBNODE keyblock, int idx);
 static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash);
-static int menu_select_key (KBNODE keyblock, int idx);
+static int menu_select_key (KBNODE keyblock, int idx, char *p);
 static int count_uids (KBNODE keyblock);
 static int count_uids_with_flag (KBNODE keyblock, unsigned flag);
 static int count_keys_with_flag (KBNODE keyblock, unsigned flag);
@@ -564,7 +566,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
    * why to sign keys using a subkey.  Implementation of USAGE_CERT
    * is just a hack in getkey.c and does not mean that a subkey
    * marked as certification capable will be used. */
-  rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_CERT);
+  rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
   if (rc)
     goto leave;
 
@@ -613,7 +615,16 @@ sign_uids (ctrl_t ctrl, estream_t fp,
                   user = utf8_to_native (uidnode->pkt->pkt.user_id->name,
                                          uidnode->pkt->pkt.user_id->len, 0);
 
-                 if (uidnode->pkt->pkt.user_id->is_revoked)
+                  if (opt.only_sign_text_ids
+                      && uidnode->pkt->pkt.user_id->attribs)
+                    {
+                      tty_fprintf (fp, _("Skipping user ID \"%s\","
+                                         " which is not a text ID.\n"),
+                                   user);
+                      uidnode->flag &= ~NODFLG_MARK_A;
+                      uidnode = NULL;
+                    }
+                 else if (uidnode->pkt->pkt.user_id->is_revoked)
                    {
                      tty_fprintf (fp, _("User ID \"%s\" is revoked."), user);
 
@@ -1708,7 +1719,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            if (*arg_string == '*'
                && (!arg_string[1] || spacep (arg_string + 1)))
              arg_number = -1;  /* Select all. */
-           if (menu_select_key (keyblock, arg_number))
+           if (menu_select_key (keyblock, arg_number, p))
              redisplay = 1;
          }
          break;
@@ -1741,21 +1752,31 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                  }
              }
 
-           if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock)
-               && !cpr_get_answer_is_yes ("keyedit.sign_all.okay",
-                                          _("Really sign all user IDs?"
-                                            " (y/N) ")))
-             {
-               if (opt.interactive)
-                 interactive = 1;
-               else
-                 {
-                   tty_printf (_("Hint: Select the user IDs to sign\n"));
-                   have_commands = 0;
-                   break;
-                 }
-
-             }
+           if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock))
+              {
+                int result;
+                if (opt.only_sign_text_ids)
+                  result = cpr_get_answer_is_yes
+                    ("keyedit.sign_all.okay",
+                     _("Really sign all user IDs? (y/N) "));
+                else
+                  result = cpr_get_answer_is_yes
+                    ("keyedit.sign_all.okay",
+                     _("Really sign all text user IDs? (y/N) "));
+
+                if (! result)
+                  {
+                    if (opt.interactive)
+                      interactive = 1;
+                    else
+                      {
+                        tty_printf (_("Hint: Select the user IDs to sign\n"));
+                        have_commands = 0;
+                        break;
+                      }
+
+                  }
+              }
            /* What sort of signing are we doing? */
            if (!parse_sign_type
                (answer, &localsig, &nonrevokesig, &trustsig))
@@ -2318,7 +2339,7 @@ keyedit_passwd (ctrl_t ctrl, const char *username)
       err = gpg_error_from_syserror ();
       goto leave;
     }
-  err = getkey_byname (NULL, pk, username, 1, &keyblock);
+  err = getkey_byname (ctrl, NULL, pk, username, 1, &keyblock);
   if (err)
     goto leave;
 
@@ -2365,6 +2386,12 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 
   /* Search the key; we don't want the whole getkey stuff here.  */
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
   err = classify_user_id (username, &desc, 1);
   if (!err)
     err = keydb_search (kdbhd, &desc, 1, NULL);
@@ -2927,6 +2954,16 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
          if ((node->flag & NODFLG_MARK_A))
            es_putc ('m', fp);
          es_putc (':', fp);
+         if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
+           {
+#ifdef USE_TOFU
+             enum tofu_policy policy;
+             if (! tofu_get_policy (primary, uid, &policy)
+                 && policy != TOFU_POLICY_NONE)
+               es_fprintf (fp, "%s", tofu_policy_str (policy));
+#endif /*USE_TOFU*/
+           }
+         es_putc (':', fp);
          es_putc ('\n', fp);
        }
     }
@@ -3042,7 +3079,8 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
 
              /* Show a warning once */
              if (!did_warn
-                 && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK))
+                 && (get_validity (pk, NULL, NULL, 0)
+                     & TRUST_FLAG_PENDING_CHECK))
                {
                  did_warn = 1;
                  do_warn = 1;
@@ -3971,8 +4009,11 @@ menu_expire (KBNODE pub_keyblock)
   n1 = count_selected_keys (pub_keyblock);
   if (n1 > 1)
     {
-      tty_printf (_("Please select at most one subkey.\n"));
-      return 0;
+      if (!cpr_get_answer_is_yes
+          ("keyedit.expire_multiple_subkeys.okay",
+           _("Are you sure you want to change the"
+             " expiration time for multiple subkeys? (y/N) ")))
+       return 0;
     }
   else if (n1)
     tty_printf (_("Changing expiration time for a subkey.\n"));
@@ -3997,11 +4038,15 @@ menu_expire (KBNODE pub_keyblock)
          keyid_from_pk (main_pk, keyid);
          main_pk->expiredate = expiredate;
        }
-      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-              && (node->flag & NODFLG_SELKEY))
+      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
-         sub_pk = node->pkt->pkt.public_key;
-         sub_pk->expiredate = expiredate;
+          if (node->flag & NODFLG_SELKEY)
+            {
+              sub_pk = node->pkt->pkt.public_key;
+              sub_pk->expiredate = expiredate;
+            }
+          else
+            sub_pk = NULL;
        }
       else if (node->pkt->pkttype == PKT_USER_ID)
        uid = node->pkt->pkt.user_id;
@@ -4856,10 +4901,97 @@ menu_select_uid_namehash (KBNODE keyblock, const char *namehash)
  * Returns: True if the selection changed.
  */
 static int
-menu_select_key (KBNODE keyblock, int idx)
+menu_select_key (KBNODE keyblock, int idx, char *p)
 {
   KBNODE node;
-  int i;
+  int i, j;
+  int is_hex_digits;
+
+  is_hex_digits = p && strlen (p) >= 8;
+  if (is_hex_digits)
+    {
+      /* Skip initial spaces.  */
+      while (spacep (p))
+        p ++;
+      /* If the id starts with 0x accept and ignore it.  */
+      if (p[0] == '0' && p[1] == 'x')
+        p += 2;
+
+      for (i = 0, j = 0; p[i]; i ++)
+        if (hexdigitp (&p[i]))
+          {
+            p[j] = toupper (p[i]);
+            j ++;
+          }
+        else if (spacep (&p[i]))
+          /* Skip spaces.  */
+          {
+          }
+        else
+          {
+            is_hex_digits = 0;
+            break;
+          }
+      if (is_hex_digits)
+        /* In case we skipped some spaces, add a new NUL terminator.  */
+        {
+          p[j] = 0;
+          /* If we skipped some spaces, make sure that we still have
+             at least 8 characters.  */
+          is_hex_digits = (/* Short keyid.  */
+                           strlen (p) == 8
+                           /* Long keyid.  */
+                           || strlen (p) == 16
+                           /* Fingerprints are (currently) 32 or 40
+                              characters.  */
+                           || strlen (p) >= 32);
+        }
+    }
+
+  if (is_hex_digits)
+    {
+      int found_one = 0;
+      for (node = keyblock; node; node = node->next)
+       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+          {
+            int match = 0;
+            if (strlen (p) == 8 || strlen (p) == 16)
+              {
+                u32 kid[2];
+                char kid_str[17];
+                keyid_from_pk (node->pkt->pkt.public_key, kid);
+                format_keyid (kid, strlen (p) == 8 ? KF_SHORT : KF_LONG,
+                              kid_str, sizeof (kid_str));
+
+                if (strcmp (p, kid_str) == 0)
+                  match = 1;
+              }
+            else
+              {
+                char fp[2*MAX_FINGERPRINT_LEN + 1];
+                hexfingerprint (node->pkt->pkt.public_key, fp, sizeof (fp));
+                if (strcmp (fp, p) == 0)
+                  match = 1;
+              }
+
+            if (match)
+              {
+                if ((node->flag & NODFLG_SELKEY))
+                  node->flag &= ~NODFLG_SELKEY;
+                else
+                  node->flag |= NODFLG_SELKEY;
+
+                found_one = 1;
+              }
+          }
+
+      if (found_one)
+        return 1;
+
+      tty_printf (_("No subkey with key ID '%s'.\n"), p);
+      return 0;
+    }
 
   if (idx == -1)               /* Select all.  */
     {
@@ -5334,7 +5466,7 @@ menu_revuid (KBNODE pub_keyblock)
                /* If the trustdb has an entry for this key+uid then the
                   trustdb needs an update. */
                if (!update_trust
-                   && (get_validity (pk, uid) & TRUST_MASK) >=
+                   && (get_validity (pk, uid, NULL, 0) & TRUST_MASK) >=
                    TRUST_UNDEFINED)
                  update_trust = 1;
 #endif /*!NO_TRUST_MODELS*/
index 85bbe13..a1f449e 100644 (file)
@@ -1284,7 +1284,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 }
 
 
-/* Common code for the key generation fucntion gen_xxx.  */
+/* Common code for the key generation function gen_xxx.  */
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
@@ -2536,7 +2536,11 @@ ask_user_id (int mode, int full, KBNODE keyblock)
                    break;
 
                if( strpbrk( aname, "<>" ) )
+                  {
                    tty_printf(_("Invalid character in name\n"));
+                   tty_printf(_("The characters '%s' and '%s' may not "
+                                 "appear in name\n"), "<", ">");
+                  }
                else if( digitp(aname) )
                    tty_printf(_("Name may not start with a digit\n"));
                else if( strlen(aname) < 5 )
@@ -3529,6 +3533,9 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
     desc.u.name = uid;
 
     kdbhd = keydb_new ();
+    if (!kdbhd)
+      goto leave;
+
     err = keydb_search (kdbhd, &desc, 1, NULL);
     keydb_release (kdbhd);
     if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
@@ -4144,12 +4151,18 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
     }
   else if (!err) /* Write to the standard keyrings.  */
     {
-      KEYDB_HANDLE pub_hd = keydb_new ();
+      KEYDB_HANDLE pub_hd;
 
-      err = keydb_locate_writable (pub_hd);
-      if (err)
-        log_error (_("no writable public keyring found: %s\n"),
-                   gpg_strerror (err));
+      pub_hd = keydb_new ();
+      if (!pub_hd)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          err = keydb_locate_writable (pub_hd);
+          if (err)
+            log_error (_("no writable public keyring found: %s\n"),
+                       gpg_strerror (err));
+        }
 
       if (!err && opt.verbose)
         {
index 42a5f9f..cb237ef 100644 (file)
@@ -274,65 +274,81 @@ v3_keyid (gcry_mpi_t a, u32 *ki)
 }
 
 
-size_t
-keystrlen(void)
+const char *
+format_keyid (u32 *keyid, int format, char *buffer, int len)
 {
-  switch(opt.keyid_format)
+  char tmp[KEYID_STR_SIZE];
+  if (! buffer)
+    buffer = tmp;
+
+  if (format == KF_DEFAULT)
+    format = opt.keyid_format;
+  if (format == KF_DEFAULT)
+    format = KF_0xLONG;
+
+  switch (format)
     {
     case KF_SHORT:
-      return 8;
+      snprintf (buffer, len, "%08lX", (ulong)keyid[1]);
+      break;
 
     case KF_LONG:
-      return 16;
+      if (keyid[0])
+       snprintf (buffer, len, "%08lX%08lX",
+                  (ulong)keyid[0], (ulong)keyid[1]);
+      else
+       snprintf (buffer, len, "%08lX", (ulong)keyid[1]);
+      break;
 
     case KF_0xSHORT:
-      return 10;
+      snprintf (buffer, len, "0x%08lX", (ulong)keyid[1]);
+      break;
 
     case KF_0xLONG:
-      return 18;
+      if(keyid[0])
+       snprintf (buffer, len, "0x%08lX%08lX",
+                  (ulong)keyid[0],(ulong)keyid[1]);
+      else
+       snprintf (buffer, len, "0x%08lX", (ulong)keyid[1]);
+      break;
 
     default:
       BUG();
     }
-}
 
+  if (buffer == tmp)
+    return xstrdup (buffer);
+  return buffer;
+}
 
-const char *
-keystr (u32 *keyid)
+size_t
+keystrlen(void)
 {
-  static char keyid_str[KEYID_STR_SIZE];
-
-  switch (opt.keyid_format)
+  switch(opt.keyid_format)
     {
     case KF_SHORT:
-      snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]);
-      break;
+      return 8;
 
     case KF_LONG:
-      if (keyid[0])
-       snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX",
-                  (ulong)keyid[0], (ulong)keyid[1]);
-      else
-       snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]);
-      break;
+      return 16;
 
     case KF_0xSHORT:
-      snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]);
-      break;
+      return 10;
 
     case KF_0xLONG:
-      if(keyid[0])
-       snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX",
-                  (ulong)keyid[0],(ulong)keyid[1]);
-      else
-       snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]);
-      break;
+      return 18;
 
     default:
       BUG();
     }
+}
+
 
-  return keyid_str;
+const char *
+keystr (u32 *keyid)
+{
+  static char keyid_str[KEYID_STR_SIZE];
+  return format_keyid (keyid, opt.keyid_format, keyid_str, sizeof (keyid_str));
 }
 
 
@@ -704,25 +720,88 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
 
 
 /* Return an allocated buffer with the fingerprint of PK formatted as
-   a plain hexstring.  */
+   a plain hexstring.  If BUFFER is NULL the result is a malloc'd
+   string.  If BUFFER is not NULL the result will be copied into this
+   buffer.  In the latter case BUFLEN describes the length of the
+   buffer; if this is too short the function terminates the process.
+   Returns a malloc'ed string or BUFFER.  A suitable length for BUFFER
+   is (2*MAX_FINGERPRINT_LEN + 1). */
 char *
-hexfingerprint (PKT_public_key *pk)
+hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen)
 {
   unsigned char fpr[MAX_FINGERPRINT_LEN];
   size_t len;
-  char *result;
 
   fingerprint_from_pk (pk, fpr, &len);
-  result = xmalloc (2 * len + 1);
-  bin2hex (fpr, len, result);
-  return result;
+  if (!buffer)
+    buffer = xmalloc (2 * len + 1);
+  else if (buflen < 2*len+1)
+    log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen);
+  bin2hex (fpr, len, buffer);
+  return buffer;
+}
+
+
+/* Pretty print a hex fingerprint.  If BUFFER is NULL the result is a
+   malloc'd string.  If BUFFER is not NULL the result will be copied
+   into this buffer.  In the latter case BUFLEN describes the length
+   of the buffer; if this is too short the function terminates the
+   process.  Returns a malloc'ed string or BUFFER.  A suitable length
+   for BUFFER is (MAX_FORMATTED_FINGERPRINT_LEN + 1).  */
+char *
+format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
+{
+  int hexlen = strlen (fingerprint);
+  int space;
+  int i, j;
+
+  if (hexlen == 40)  /* v4 fingerprint */
+    {
+      space = (/* The characters and the NUL.  */
+              40 + 1
+              /* After every fourth character, we add a space (except
+                 the last).  */
+              + 40 / 4 - 1
+              /* Half way through we add a second space.  */
+              + 1);
+    }
+  else  /* Other fingerprint versions - print as is.  */
+    {
+      space = hexlen + 1;
+    }
+
+  if (!buffer)
+    buffer = xmalloc (space);
+  else if (buflen < space)
+    log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen);
+
+  if (hexlen == 40)  /* v4 fingerprint */
+    {
+      for (i = 0, j = 0; i < 40; i ++)
+        {
+          if (i && i % 4 == 0)
+            buffer[j ++] = ' ';
+          if (i == 40 / 2)
+            buffer[j ++] = ' ';
+
+          buffer[j ++] = fingerprint[i];
+        }
+      buffer[j ++] = 0;
+      assert (j == space);
+    }
+  else
+    {
+      strcpy (buffer, fingerprint);
+    }
+
+  return buffer;
 }
 
 
 \f
 /* Return the so called KEYGRIP which is the SHA-1 hash of the public
    key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
-   be 20 bytes long.  Returns 0 on sucess or an error code.  */
+   be 20 bytes long.  Returns 0 on success or an error code.  */
 gpg_error_t
 keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
 {
index 3814f1c..b2836e8 100644 (file)
@@ -43,6 +43,8 @@
 #include "status.h"
 #include "call-agent.h"
 #include "mbox-util.h"
+#include "zb32.h"
+#include "tofu.h"
 
 
 static void list_all (ctrl_t, int, int);
@@ -99,7 +101,8 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
        es_fprintf (es_stdout, "o");
       if (trust_model != opt.trust_model)
        es_fprintf (es_stdout, "t");
-      if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC)
+      if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
+         || opt.trust_model == TM_TOFU_PGP)
        {
          if (marginals != opt.marginals_needed)
            es_fprintf (es_stdout, "m");
@@ -130,12 +133,20 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
      which is associated with the inode of a deleted file.  */
   check_trustdb_stale ();
 
+#ifdef USE_TOFU
+  tofu_begin_batch_update ();
+#endif
+
   if (locate_mode)
     locate_one (ctrl, list);
   else if (!list)
     list_all (ctrl, 0, opt.with_secret);
   else
     list_one (ctrl, list, 0, opt.with_secret);
+
+#ifdef USE_TOFU
+  tofu_end_batch_update ();
+#endif
 }
 
 
@@ -152,20 +163,31 @@ secret_key_list (ctrl_t ctrl, strlist_t list)
     list_one (ctrl, list, 1, 0);
 }
 
-void
-print_seckey_info (PKT_public_key *pk)
+char *
+format_seckey_info (PKT_public_key *pk)
 {
   u32 keyid[2];
   char *p;
   char pkstrbuf[PUBKEY_STRING_SIZE];
+  char *info;
 
   keyid_from_pk (pk, keyid);
   p = get_user_id_native (keyid);
 
-  tty_printf ("\nsec  %s/%s %s %s\n",
-              pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-             keystr (keyid), datestr_from_pk (pk), p);
+  info = xtryasprintf ("sec  %s/%s %s %s",
+                       pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+                       keystr (keyid), datestr_from_pk (pk), p);
+
+  xfree (p);
 
+  return info;
+}
+
+void
+print_seckey_info (PKT_public_key *pk)
+{
+  char *p = format_seckey_info (pk);
+  tty_printf ("\n%s\n", p);
   xfree (p);
 }
 
@@ -483,7 +505,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
 
   hd = keydb_new ();
   if (!hd)
-    rc = gpg_error (GPG_ERR_GENERAL);
+    rc = gpg_error_from_syserror ();
   else
     rc = keydb_search_first (hd);
   if (rc)
@@ -848,7 +870,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
   char pkstrbuf[PUBKEY_STRING_SIZE];
   char *hexfpr;
   char *hexkeyblock = NULL;
-  unsigned int hexkeyblocklen;
+  unsigned int hexkeyblocklen = 0;  /* Init to avoid -Wmaybe-uninitialized. */
   const char *s;
 
   /* Get the keyid from the keyblock.  */
@@ -884,7 +906,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
     }
 
 
-  hexfpr = hexfingerprint (pk);
+  hexfpr = hexfingerprint (pk, NULL, 0);
   if (opt.print_dane_records)
     {
       kbnode_t dummy_keyblock;
@@ -892,10 +914,10 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
       size_t datalen;
       gpg_error_t err;
 
-      /* We do not have an export fucntion which allows to pass a
+      /* We do not have an export function which allows to pass a
          keyblock, thus we need to search the key again.  */
       err = export_pubkey_buffer (ctrl, hexfpr,
-                                  EXPORT_DANE_FORMAT,
+                                  EXPORT_DANE_FORMAT, NULL,
                                   &dummy_keyblock, &data, &datalen);
       release_kbnode (dummy_keyblock);
       if (!err)
@@ -1067,7 +1089,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
      include, but it looks sort of confusing in the listing... */
   if (opt.list_options & LIST_SHOW_VALIDITY)
     {
-      int validity = get_validity (pk, NULL);
+      int validity = get_validity (pk, NULL, NULL, 0);
       es_fprintf (es_stdout, " [%s]", trust_value_to_string (validity));
     }
 #endif
@@ -1438,6 +1460,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
       xfree (curve);
     }
   es_putc (':', es_stdout);            /* End of field 17. */
+  es_putc (':', es_stdout);            /* End of field 18. */
   es_putc ('\n', es_stdout);
 
   print_revokers (es_stdout, pk);
@@ -1495,6 +1518,16 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
            es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len);
          else
            es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
+         es_fprintf (es_stdout, "::::::::");
+         if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
+           {
+#ifdef USE_TOFU
+             enum tofu_policy policy;
+             if (! tofu_get_policy (pk, uid, &policy)
+                 && policy != TOFU_POLICY_NONE)
+               es_fprintf (es_stdout, "%s", tofu_policy_str (policy));
+#endif /*USE_TOFU*/
+           }
          es_putc (':', es_stdout);
          es_putc ('\n', es_stdout);
        }
@@ -1811,8 +1844,9 @@ print_icao_hexdigit (estream_t fp, int c)
 void
 print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
 {
-  byte array[MAX_FINGERPRINT_LEN], *p;
-  size_t i, n;
+  char hexfpr[2*MAX_FINGERPRINT_LEN+1];
+  char *p;
+  size_t i;
   estream_t fp;
   const char *text;
   int primary = 0;
@@ -1881,47 +1915,33 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
       text = _("      Key fingerprint =");
     }
 
-  fingerprint_from_pk (pk, array, &n);
-  p = array;
+  hexfingerprint (pk, hexfpr, sizeof hexfpr);
   if (with_colons && !mode)
     {
-      es_fprintf (fp, "fpr:::::::::");
-      for (i = 0; i < n; i++, p++)
-       es_fprintf (fp, "%02X", *p);
-      es_putc (':', fp);
+      es_fprintf (fp, "fpr:::::::::%s:", hexfpr);
     }
   else
     {
-      tty_fprintf (fp, "%s", text);
-      if (n == 20)
-       {
-         for (i = 0; i < n; i++, i++, p += 2)
-            tty_fprintf (fp, "%s %02X%02X", i==10? " ":"", *p, p[1]);
-       }
-      else
-       {
-         for (i = 0; i < n; i++, p++)
-            tty_fprintf (fp, "%s %02X", (i && !(i % 8))? " ":"", *p);
-       }
+      char fmtfpr[MAX_FORMATTED_FINGERPRINT_LEN + 1];
+      format_hexfingerprint (hexfpr, fmtfpr, sizeof fmtfpr);
+      tty_fprintf (fp, "%s %s", text, fmtfpr);
     }
   tty_fprintf (fp, "\n");
   if (!with_colons && with_icao)
     {
-      p = array;
+      ;
       tty_fprintf (fp, "%*s\"", (int)strlen(text)+1, "");
-      for (i = 0; i < n; i++, p++)
+      for (i = 0, p = hexfpr; *p; i++, p++)
         {
           if (!i)
             ;
-          else if (!(i%4))
+          else if (!(i%8))
             tty_fprintf (fp, "\n%*s ", (int)strlen(text)+1, "");
-          else if (!(i%2))
+          else if (!(i%4))
             tty_fprintf (fp, "  ");
           else
             tty_fprintf (fp, " ");
-          print_icao_hexdigit (fp, *p >> 4);
-          tty_fprintf (fp, " ");
-          print_icao_hexdigit (fp, *p & 15);
+          print_icao_hexdigit (fp, xtoi_1 (p));
         }
       tty_fprintf (fp, "\"\n");
     }
index 81d2174..6ba5202 100644 (file)
@@ -250,7 +250,7 @@ keyring_is_writable (void *token)
 
 \f
 /* Create a new handle for the resource associated with TOKEN.
-
+   On error NULL is returned and ERRNO is set.
    The returned handle must be released using keyring_release (). */
 KEYRING_HANDLE
 keyring_new (void *token)
@@ -260,7 +260,9 @@ keyring_new (void *token)
 
   assert (resource);
 
-  hd = xmalloc_clear (sizeof *hd);
+  hd = xtrycalloc (1, sizeof *hd);
+  if (!hd)
+    return hd;
   hd->resource = resource;
   active_handles++;
   return hd;
@@ -419,7 +421,20 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
            continue;
        }
         if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-          break;  /* Upper layer needs to handle this.  */
+          {
+            if (in_cert)
+              /* It is not this key that is problematic, but the
+                 following key.  */
+              {
+                rc = 0;
+                hd->found.n_packets --;
+              }
+            else
+              /* Upper layer needs to handle this.  */
+              {
+              }
+            break;
+          }
        if (rc) {
             log_error ("keyring_get_keyblock: read error: %s\n",
                        gpg_strerror (rc) );
@@ -699,29 +714,51 @@ prepare_search (KEYRING_HANDLE hd)
         /* If the last key was a legacy key, we simply ignore the error so that
            we can easily use search_next.  */
         if (gpg_err_code (hd->current.error) == GPG_ERR_LEGACY_KEY)
+          {
+            if (DBG_LOOKUP)
+              log_debug ("%s: last error was GPG_ERR_LEGACY_KEY, clearing\n",
+                         __func__);
             hd->current.error = 0;
+          }
         else
+          {
+            if (DBG_LOOKUP)
+              log_debug ("%s: returning last error: %s\n",
+                         __func__, gpg_strerror (hd->current.error));
             return hd->current.error; /* still in error state */
+          }
     }
 
     if (hd->current.kr && !hd->current.eof) {
         if ( !hd->current.iobuf )
+          {
+            if (DBG_LOOKUP)
+              log_debug ("%s: missing iobuf!\n", __func__);
             return GPG_ERR_GENERAL; /* Position invalid after a modify.  */
+          }
         return 0; /* okay */
     }
 
     if (!hd->current.kr && hd->current.eof)
+      {
+        if (DBG_LOOKUP)
+          log_debug ("%s: EOF!\n", __func__);
         return -1; /* still EOF */
+      }
 
     if (!hd->current.kr) { /* start search with first keyring */
         hd->current.kr = hd->resource;
         if (!hd->current.kr) {
+          if (DBG_LOOKUP)
+            log_debug ("%s: keyring not available!\n", __func__);
             hd->current.eof = 1;
             return -1; /* keyring not available */
         }
         assert (!hd->current.iobuf);
     }
     else { /* EOF */
+        if (DBG_LOOKUP)
+          log_debug ("%s: EOF\n", __func__);
         iobuf_close (hd->current.iobuf);
         hd->current.iobuf = NULL;
         hd->current.kr = NULL;
@@ -933,7 +970,7 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
  */
 int
 keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-               size_t ndesc, size_t *descindex)
+               size_t ndesc, size_t *descindex, int ignore_legacy)
 {
   int rc;
   PACKET pkt;
@@ -943,6 +980,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   int need_uid, need_words, need_keyid, need_fpr, any_skip;
   int pk_no, uid_no;
   int initial_skip;
+  int scanned_from_start;
   int use_offtbl;
   PKT_user_id *uid = NULL;
   PKT_public_key *pk = NULL;
@@ -987,22 +1025,44 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
     }
 
+  if (DBG_LOOKUP)
+    log_debug ("%s: need_uid = %d; need_words = %d; need_keyid = %d; need_fpr = %d; any_skip = %d\n",
+               __func__, need_uid, need_words, need_keyid, need_fpr, any_skip);
+
   rc = prepare_search (hd);
   if (rc)
-    return rc;
+    {
+      if (DBG_LOOKUP)
+        log_debug ("%s: prepare_search failed: %s (%d)\n",
+                   __func__, gpg_strerror (rc), gpg_err_code (rc));
+      return rc;
+    }
 
   use_offtbl = !!kr_offtbl;
   if (!use_offtbl)
-    ;
+    {
+      if (DBG_LOOKUP)
+        log_debug ("%s: no offset table.\n", __func__);
+    }
   else if (!kr_offtbl_ready)
-    need_keyid = 1;
+    {
+      if (DBG_LOOKUP)
+        log_debug ("%s: initializing offset table. (need_keyid: %d => 1)\n",
+                   __func__, need_keyid);
+      need_keyid = 1;
+    }
   else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
     {
       struct off_item *oi;
 
+      if (DBG_LOOKUP)
+        log_debug ("%s: look up by long key id, checking cache\n", __func__);
+
       oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
       if (!oi)
         { /* We know that we don't have this key */
+          if (DBG_LOOKUP)
+            log_debug ("%s: cache says not present\n", __func__);
           hd->found.kr = NULL;
           hd->current.eof = 1;
           return -1;
@@ -1045,11 +1105,24 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   main_offset = 0;
   pk_no = uid_no = 0;
   initial_skip = 1; /* skip until we see the start of a keyblock */
-  while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid)))
+  scanned_from_start = iobuf_tell (hd->current.iobuf) == 0;
+  if (DBG_LOOKUP)
+    log_debug ("%s: %ssearching from start of resource.\n",
+               __func__, scanned_from_start ? "" : "not ");
+  while (1)
     {
       byte afp[MAX_FINGERPRINT_LEN];
       size_t an;
 
+      rc = search_packet (hd->current.iobuf, &pkt, &offset, need_uid);
+      if (ignore_legacy && gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+        {
+          free_packet (&pkt);
+          continue;
+        }
+      if (rc)
+        break;
+
       if (pkt.pkttype == PKT_PUBLIC_KEY  || pkt.pkttype == PKT_SECRET_KEY)
         {
           main_offset = offset;
@@ -1080,7 +1153,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           if (need_keyid)
             keyid_from_pk (pk, aki);
 
-          if (use_offtbl && !kr_offtbl_ready)
+          if (use_offtbl && !kr_offtbl_ready && scanned_from_start)
             update_offset_hash_table (kr_offtbl, aki, main_offset);
         }
       else if (pkt.pkttype == PKT_USER_ID)
@@ -1141,6 +1214,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       free_packet (&pkt);
       continue;
     found:
+      if (rc)
+        goto real_found;
+
+      if (DBG_LOOKUP)
+        log_debug ("%s: packet starting at offset %lld matched descriptor %zu\n"
+                   , __func__, (long long)offset, n);
+
       /* Record which desc we matched on.  Note this value is only
         meaningful if this function returns with no errors. */
       if(descindex)
@@ -1149,7 +1229,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         {
           if (desc[n].skipfnc
               && desc[n].skipfnc (desc[n].skipfncvalue, aki, uid_no))
-            break;
+            {
+              if (DBG_LOOKUP)
+                log_debug ("%s: skipping match: desc %zd's skip function returned TRUE\n",
+                           __func__, n);
+              break;
+            }
         }
       if (n == ndesc)
         goto real_found;
@@ -1158,6 +1243,8 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
  real_found:
   if (!rc)
     {
+      if (DBG_LOOKUP)
+        log_debug ("%s: returing success\n", __func__);
       hd->found.offset = main_offset;
       hd->found.kr = hd->current.kr;
       hd->found.pk_no = pk? pk_no : 0;
@@ -1165,10 +1252,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
     }
   else if (rc == -1)
     {
+      if (DBG_LOOKUP)
+        log_debug ("%s: no matches (EOF)\n", __func__);
+
       hd->current.eof = 1;
       /* if we scanned all keyrings, we are sure that
        * all known key IDs are in our offtbl, mark that. */
-      if (use_offtbl && !kr_offtbl_ready)
+      if (use_offtbl && !kr_offtbl_ready && scanned_from_start)
         {
           KR_NAME kr;
 
@@ -1193,7 +1283,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
     }
   else
-    hd->current.error = rc;
+    {
+      if (DBG_LOOKUP)
+        log_debug ("%s: error encountered during search: %s (%d)\n",
+                   __func__, gpg_strerror (rc), rc);
+      hd->current.error = rc;
+    }
 
   free_packet(&pkt);
   set_packet_list_mode(save_mode);
@@ -1213,7 +1308,7 @@ create_tmp_file (const char *template,
 
 # ifdef USE_ONLY_8DOT3
   /* Here is another Windoze bug?:
-   * you cant rename("pubring.gpg.tmp", "pubring.gpg");
+   * you can't rename("pubring.gpg.tmp", "pubring.gpg");
    * but       rename("pubring.gpg.tmp", "pubring.aaa");
    * works.  So we replace .gpg by .bak or .tmp
    */
@@ -1394,6 +1489,8 @@ keyring_rebuild_cache (void *token,int noisy)
   ulong count = 0, sigcount = 0;
 
   hd = keyring_new (token);
+  if (!hd)
+    return gpg_error_from_syserror ();
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
 
@@ -1403,8 +1500,8 @@ keyring_rebuild_cache (void *token,int noisy)
 
   for (;;)
     {
-      rc = keyring_search (hd, &desc, 1, NULL);
-      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+      rc = keyring_search (hd, &desc, 1, NULL, 0);
+      if (rc)
         break;  /* ready.  */
 
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
index 1469b70..14d9f42 100644 (file)
@@ -36,11 +36,10 @@ int keyring_lock (KEYRING_HANDLE hd, int yes);
 int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
 int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
 int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
-int keyring_locate_writable (KEYRING_HANDLE hd);
 int keyring_delete_keyblock (KEYRING_HANDLE hd);
 int keyring_search_reset (KEYRING_HANDLE hd);
 int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-                   size_t ndesc, size_t *descindex);
+                   size_t ndesc, size_t *descindex, int skip_legacy);
 int keyring_rebuild_cache (void *token,int noisy);
 
 #endif /*GPG_KEYRING_H*/
index a6257e5..cf671c9 100644 (file)
@@ -41,9 +41,6 @@
 #include "trustdb.h"
 #include "keyserver-internal.h"
 #include "util.h"
-#ifdef USE_DNS_SRV
-#include "srv.h"
-#endif
 #include "membuf.h"
 #include "call-dirmngr.h"
 
@@ -1193,10 +1190,13 @@ keyserver_import_keyid (ctrl_t ctrl,
 static int
 keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
 {
-  int rc=0,ndesc,num=100;
-  KBNODE keyblock=NULL,node;
+  int rc = 0;
+  int num = 100;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
   KEYDB_HANDLE kdbhd;
-  KEYDB_SEARCH_DESC *desc;
+  int ndesc;
+  KEYDB_SEARCH_DESC *desc = NULL;
   strlist_t sl;
 
   *count=0;
@@ -1204,6 +1204,11 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
   *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
   keydb_disable_caching (kdbhd);  /* We are looping the search.  */
 
   if(!users)
@@ -1232,21 +1237,16 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
   for (;;)
     {
       rc = keydb_search (kdbhd, desc, ndesc, NULL);
-      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+      if (rc)
         break;  /* ready.  */
 
       if (!users)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-        continue;
-
       /* read the keyblock */
       rc = keydb_get_keyblock (kdbhd, &keyblock );
       if( rc )
        {
-          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-            continue;
           log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
          goto leave;
        }
@@ -1346,7 +1346,10 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
 
  leave:
   if(rc)
-    xfree(*klist);
+    {
+      xfree(*klist);
+      *klist = NULL;
+    }
   xfree(desc);
   keydb_release(kdbhd);
   release_kbnode(keyblock);
@@ -1799,6 +1802,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 
       err = export_pubkey_buffer (ctrl, kspec->d,
                                   opt.keyserver_options.export_options,
+                                  NULL,
                                   &keyblock, &data, &datalen);
       if (err)
         log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
@@ -2029,6 +2033,7 @@ keyserver_import_ldap (ctrl_t ctrl,
 #ifdef USE_DNS_SRV
   snprintf(srvname,MAXDNAME,"_pgpkey-ldap._tcp.%s",domain);
 
+  FIXME("network related - move to dirmngr or drop the code");
   srvcount=getsrv(srvname,&srvlist);
 
   for(i=0;i<srvcount;i++)
index 0bace61..0c2d1a9 100644 (file)
@@ -69,6 +69,13 @@ struct groupitem
   struct groupitem *next;
 };
 
+struct weakhash
+{
+  enum gcry_md_algos algo;
+  int rejection_shown;
+  struct weakhash *next;
+};
+
 
 /*-- gpg.c --*/
 extern int g10_errors_seen;
@@ -81,7 +88,8 @@ extern int g10_errors_seen;
 void print_pubkey_algo_note (pubkey_algo_t algo);
 void print_cipher_algo_note (cipher_algo_t algo);
 void print_digest_algo_note (digest_algo_t algo);
-void print_md5_rejected_note (void);
+void print_digest_rejected_note (enum gcry_md_algos algo);
+void additional_weak_digest (const char* digestname);
 
 /*-- armor.c --*/
 char *make_radix64_string( const byte *data, size_t len );
@@ -174,7 +182,7 @@ int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
 unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
 
 
-/*-- status.c --*/
+/*-- cpr.c --*/
 void set_status_fd ( int fd );
 int  is_status_enabled ( void );
 void write_status ( int no );
@@ -211,6 +219,7 @@ void display_online_help( const char *keyword );
 
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
+int use_mdc (pk_list_t pk_list,int algo);
 int encrypt_symmetric (const char *filename );
 int encrypt_store (const char *filename );
 int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
@@ -227,14 +236,27 @@ int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
                   const char *cache_nonce);
 int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
               int do_encrypt, strlist_t remusr, const char *outfile );
-int clearsign_file( const char *fname, strlist_t locusr, const char *outfile );
-int sign_symencrypt_file (const char *fname, strlist_t locusr);
+int clearsign_file (ctrl_t ctrl,
+                    const char *fname, strlist_t locusr, const char *outfile);
+int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr);
 
 /*-- sig-check.c --*/
+
+/* SIG is a revocation signature.  Check if any of PK's designated
+   revokers generated it.  If so, return 0.  Note: this function
+   (correctly) doesn't care if the designated revoker is revoked.  */
 int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig);
+/* Check that the backsig BACKSIG from the subkey SUB_PK to its
+   primary key MAIN_PK is valid.  */
 int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
                  PKT_signature *backsig);
-int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
+/* Check that the signature SIG over a key (e.g., a key binding or a
+   key revocation) is valid.  (To check signatures over data, use
+   check_signature.)  */
+int check_key_signature( KBNODE root, KBNODE sig, int *is_selfsig );
+/* Like check_key_signature, but with the ability to specify some
+   additional parameters and get back additional information.  See the
+   documentation for the implementation for details.  */
 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 );
@@ -317,16 +339,25 @@ int collapse_uids( KBNODE *keyblock );
 
 
 /*-- export.c --*/
+struct export_stats_s;
+typedef struct export_stats_s *export_stats_t;
+
+export_stats_t export_new_stats (void);
+void export_release_stats (export_stats_t stats);
+void export_print_stats (export_stats_t stats);
+
 int parse_export_options(char *str,unsigned int *options,int noisy);
-int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options );
-int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
-                          kbnode_t *keyblock_out, unsigned int options );
+
+int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
+                    export_stats_t stats);
+int export_seckeys (ctrl_t ctrl, strlist_t users, export_stats_t stats);
+int export_secsubkeys (ctrl_t ctrl, strlist_t users, export_stats_t stats);
+
 gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
                                   unsigned int options,
+                                  export_stats_t stats,
                                   kbnode_t *r_keyblock,
                                   void **r_data, size_t *r_datalen);
-int export_seckeys (ctrl_t ctrl, strlist_t users);
-int export_secsubkeys (ctrl_t ctrl, strlist_t users);
 
 /*-- dearmor.c --*/
 int dearmor_file( const char *fname );
@@ -336,7 +367,7 @@ int enarmor_file( const char *fname );
 struct revocation_reason_info;
 int gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce);
 int gen_revoke( const char *uname );
-int gen_desig_revoke( const char *uname, strlist_t locusr);
+int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
 int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
 struct revocation_reason_info *
                ask_revocation_reason( int key_rev, int cert_rev, int hint );
@@ -356,6 +387,7 @@ void show_keyserver_url(PKT_signature *sig,int indent,int mode);
 void show_notation(PKT_signature *sig,int indent,int mode,int which);
 void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk);
 void set_attrib_fd(int fd);
+char *format_seckey_info (PKT_public_key *pk);
 void print_seckey_info (PKT_public_key *pk);
 void print_pubkey_info (estream_t fp, PKT_public_key *pk);
 void print_card_key_info (estream_t fp, KBNODE keyblock);
index 9f02b15..8688325 100644 (file)
@@ -106,7 +106,7 @@ struct mainproc_context
 
 
 /*** Local prototypes.  ***/
-static int do_proc_packets (CTX c, iobuf_t a);
+static int do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a);
 static void list_node (CTX c, kbnode_t node);
 static void proc_tree (CTX c, kbnode_t node);
 static int literals_seen;
@@ -366,7 +366,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
 
 
 static void
-proc_pubkey_enc (CTX c, PACKET *pkt)
+proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt)
 {
   PKT_pubkey_enc *enc;
   int result = 0;
@@ -387,7 +387,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt)
          to the Libgcrypt defined one.  This is due a chicken-egg
          problem: We need to have code in Libgcrypt for a new
          algorithm so to implement a proposed new algorithm before the
-         IANA will finally assign an OpenPGP indentifier.  */
+         IANA will finally assign an OpenPGP identifier.  */
       snprintf (buf, sizeof buf, "%08lX%08lX %d 0",
                (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo);
       write_status_text (STATUS_ENC_TO, buf);
@@ -428,7 +428,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt)
           else
             {
               c->dek = xmalloc_secure_clear (sizeof *c->dek);
-              if ((result = get_session_key (enc, c->dek)))
+              if ((result = get_session_key (ctrl, enc, c->dek)))
                 {
                   /* Error: Delete the DEK. */
                   xfree (c->dek);
@@ -646,8 +646,9 @@ proc_encrypted (CTX c, PACKET *pkt)
       if (gpg_err_code (result) == GPG_ERR_BAD_KEY
           && *c->dek->s2k_cacheid != '\0')
         {
-          log_debug (_("cleared passphrase cached with ID: %s\n"),
-                     c->dek->s2k_cacheid);
+          if (opt.debug)
+            log_debug ("cleared passphrase cached with ID: %s\n",
+                       c->dek->s2k_cacheid);
           passphrase_clear_cache (NULL, c->dek->s2k_cacheid, 0);
         }
       glo_ctrl.lasterr = result;
@@ -851,6 +852,7 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
   PKT_signature *sig;
   gcry_md_hd_t md = NULL;
   gcry_md_hd_t md2 = NULL;
+  gcry_md_hd_t md_good = NULL;
   int algo, rc;
 
   assert (node->pkt->pkttype == PKT_SIGNATURE);
@@ -872,7 +874,7 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
         }
       else /* detached signature */
         {
-          /* signature_check() will enable the md. */
+          /* check_signature() will enable the md. */
           if (gcry_md_open (&md, 0, 0 ))
             BUG ();
         }
@@ -891,7 +893,7 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
       else /* detached signature */
         {
           log_debug ("Do we really need this here?");
-          /* signature_check() will enable the md*/
+          /* check_signature() will enable the md*/
           if (gcry_md_open (&md, 0, 0 ))
             BUG ();
           if (gcry_md_open (&md2, 0, 0 ))
@@ -925,9 +927,24 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
   else
     return GPG_ERR_SIG_CLASS;
 
-  rc = signature_check2 (sig, md, NULL, is_expkey, is_revkey, NULL);
-  if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
-    rc = signature_check2 (sig, md2, NULL, is_expkey, is_revkey, NULL);
+  /* We only get here if we are checking the signature of a binary
+     (0x00) or text document (0x01).  */
+  rc = check_signature2 (sig, md, NULL, is_expkey, is_revkey, NULL);
+  if (! rc)
+    md_good = md;
+  else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
+    {
+      rc = check_signature2 (sig, md2, NULL, is_expkey, is_revkey, NULL);
+      if (! rc)
+       md_good = md2;
+    }
+
+  if (md_good)
+    {
+      unsigned char *buffer = gcry_md_read (md_good, 0);
+      sig->digest_len = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (algo));
+      memcpy (sig->digest, buffer, sig->digest_len);
+    }
 
   gcry_md_close (md);
   gcry_md_close (md2);
@@ -1075,7 +1092,7 @@ list_node (CTX c, kbnode_t node)
     {
 
       log_debug ("FIXME: No way to print secret key packets here\n");
-      /* fixme: We may use a fucntion to turn a secret key packet into
+      /* fixme: We may use a function to turn a secret key packet into
          a public key one and use that here.  */
     }
   else if (node->pkt->pkttype == PKT_SIGNATURE)
@@ -1179,7 +1196,7 @@ proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
 
   c->ctrl = ctrl;
   c->anchor = anchor;
-  rc = do_proc_packets (c, a);
+  rc = do_proc_packets (ctrl, c, a);
   xfree (c);
 
   return rc;
@@ -1202,7 +1219,7 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
   c->signed_data.used = !!signedfiles;
 
   c->sigfilename = sigfilename;
-  rc = do_proc_packets ( c, a );
+  rc = do_proc_packets (ctrl, c, a);
 
   /* If we have not encountered any signature we print an error
      messages, send a NODATA status back and return an error code.
@@ -1245,7 +1262,7 @@ proc_signature_packets_by_fd (ctrl_t ctrl,
   c->signed_data.data_names = NULL;
   c->signed_data.used = (signed_data_fd != -1);
 
-  rc = do_proc_packets ( c, a );
+  rc = do_proc_packets (ctrl, c, a);
 
   /* If we have not encountered any signature we print an error
      messages, send a NODATA status back and return an error code.
@@ -1278,7 +1295,7 @@ proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
   c->ctrl = ctrl;
   c->anchor = anchor;
   c->encrypt_only = 1;
-  rc = do_proc_packets (c, a);
+  rc = do_proc_packets (ctrl, c, a);
   xfree (c);
   return rc;
 }
@@ -1304,7 +1321,7 @@ check_nesting (CTX c)
 
 
 static int
-do_proc_packets (CTX c, iobuf_t a)
+do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
 {
   PACKET *pkt;
   int rc = 0;
@@ -1336,7 +1353,7 @@ do_proc_packets (CTX c, iobuf_t a)
         {
           switch (pkt->pkttype)
             {
-            case PKT_PUBKEY_ENC:    proc_pubkey_enc (c, pkt); break;
+            case PKT_PUBKEY_ENC:    proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_SYMKEY_ENC:    proc_symkey_enc (c, pkt); break;
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
@@ -1380,7 +1397,7 @@ do_proc_packets (CTX c, iobuf_t a)
 
             case PKT_SIGNATURE:   newpkt = add_signature (c, pkt); break;
             case PKT_SYMKEY_ENC:  proc_symkey_enc (c, pkt); break;
-            case PKT_PUBKEY_ENC:  proc_pubkey_enc (c, pkt); break;
+            case PKT_PUBKEY_ENC:  proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
             case PKT_PLAINTEXT:   proc_plaintext (c, pkt); break;
@@ -1406,7 +1423,7 @@ do_proc_packets (CTX c, iobuf_t a)
               break;
             case PKT_USER_ID:     newpkt = add_user_id (c, pkt); break;
             case PKT_SIGNATURE:   newpkt = add_signature (c, pkt); break;
-            case PKT_PUBKEY_ENC:  proc_pubkey_enc (c, pkt); break;
+            case PKT_PUBKEY_ENC:  proc_pubkey_enc (ctrl, c, pkt); break;
             case PKT_SYMKEY_ENC:  proc_symkey_enc (c, pkt); break;
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break;
@@ -1426,7 +1443,7 @@ do_proc_packets (CTX c, iobuf_t a)
        * I used it.  Adding the MDC check here is a hack.
        * The right solution is to initiate another context for encrypted
        * packet and not to reuse the current one ...  It works right
-       * when there is a compression packet inbetween which adds just
+       * when there is a compression packet between which adds just
        * an extra layer.
        * Hmmm: Rewrite this whole module here??
        */
@@ -1822,7 +1839,8 @@ check_sig_and_print (CTX c, kbnode_t node)
       snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
                 (ulong)sig->keyid[0], (ulong)sig->keyid[1]);
 
-      /* Find and print the primary user ID.  */
+      /* Find and print the primary user ID along with the
+         "Good|Expired|Bad signature" line.  */
       for (un=keyblock; un; un = un->next)
         {
           int valid;
@@ -1848,9 +1866,15 @@ check_sig_and_print (CTX c, kbnode_t node)
 
           assert (pk);
 
-          /* Get it before we print anything to avoid interrupting the
-             output with the "please do a --check-trustdb" line. */
-          valid = get_validity (pk, un->pkt->pkt.user_id);
+         /* Since this is just informational, don't actually ask the
+            user to update any trust information.  (Note: we register
+            the signature later.)  Because print_good_bad_signature
+            does not print a LF we need to compute the validity
+            before calling that function.  */
+          if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY))
+            valid = get_validity (pk, un->pkt->pkt.user_id, NULL, 0);
+          else
+            valid = 0; /* Not used.  */
 
           keyid_str[17] = 0; /* cut off the "[uncertain]" part */
 
@@ -1861,11 +1885,17 @@ check_sig_and_print (CTX c, kbnode_t node)
           else
             log_printf ("\n");
 
+          /* Get a string description of the algo for informational
+             output we want to print later.  It is convenient to do it
+             here because we already have the right public key. */
           pubkey_string (pk, pkstrbuf, sizeof pkstrbuf);
           count++;
        }
 
-      if (!count)  /* Just in case that we have no valid textual userid */
+      /* In case we did not found a valid valid textual userid above
+         we print the first user id packet or a "[?]" instead along
+         with the "Good|Expired|Bad signature" line.  */
+      if (!count)
         {
           /* Try for an invalid textual userid */
           for (un=keyblock; un; un = un->next)
@@ -1910,11 +1940,12 @@ check_sig_and_print (CTX c, kbnode_t node)
                    || un->pkt->pkt.user_id->is_expired)
                   && !(opt.verify_options & VERIFY_SHOW_UNUSABLE_UIDS))
                 continue;
-              /* Only skip textual primaries */
+              /* Skip textual primary user ids which we printed above. */
               if (un->pkt->pkt.user_id->is_primary
                   && !un->pkt->pkt.user_id->attrib_data )
                 continue;
 
+              /* If this user id has attribute data, print that.  */
               if (un->pkt->pkt.user_id->attrib_data)
                 {
                   dump_attribs (un->pkt->pkt.user_id, pk);
@@ -1939,8 +1970,11 @@ check_sig_and_print (CTX c, kbnode_t node)
                   else if (un->pkt->pkt.user_id->is_expired)
                     valid = _("expired");
                   else
+                   /* Since this is just informational, don't
+                      actually ask the user to update any trust
+                      information.  */
                     valid = (trust_value_to_string
-                             (get_validity (pk, un->pkt->pkt.user_id)));
+                             (get_validity (pk, un->pkt->pkt.user_id, sig, 0)));
                   log_printf (" [%s]\n",valid);
                 }
               else
@@ -1949,6 +1983,7 @@ check_sig_and_print (CTX c, kbnode_t node)
        }
       release_kbnode( keyblock );
 
+      /* For good signatures print notation data.  */
       if (!rc)
         {
           if ((opt.verify_options & VERIFY_SHOW_POLICY_URLS))
@@ -1970,9 +2005,9 @@ check_sig_and_print (CTX c, kbnode_t node)
             show_notation (sig, 0, 2, 0);
         }
 
+      /* For good signatures print the VALIDSIG status line.  */
       if (!rc && is_status_enabled ())
         {
-          /* Print a status response with the fingerprint. */
           PKT_public_key *vpk = xmalloc_clear (sizeof *vpk);
 
           if (!get_pubkey (vpk, sig->keyid))
@@ -2020,6 +2055,9 @@ check_sig_and_print (CTX c, kbnode_t node)
           free_public_key (vpk);
        }
 
+      /* For good signatures compute and print the trust information.
+         Note that in the Tofu trust model this may ask the user on
+         how to resolve a conflict.  */
       if (!rc)
         {
           if ((opt.verify_options & VERIFY_PKA_LOOKUPS))
@@ -2027,6 +2065,7 @@ check_sig_and_print (CTX c, kbnode_t node)
           rc = check_signatures_trust (sig);
         }
 
+      /* Print extra information about the signature.  */
       if (sig->flags.expired)
         {
           log_info (_("Signature expired %s\n"), asctimestamp(sig->expiredate));
@@ -2043,6 +2082,7 @@ check_sig_and_print (CTX c, kbnode_t node)
                   *pkstrbuf?_(", key algorithm "):"",
                   pkstrbuf);
 
+      /* Print final warnings.  */
       if (!rc && !c->signed_data.used)
         {
           /* Signature is basically good but we test whether the
index 9134b28..547944d 100644 (file)
@@ -67,6 +67,7 @@
 #include "options.h"
 #include "call-agent.h"
 #include "i18n.h"
+#include "zb32.h"
 
 #include <assert.h>
 
@@ -97,7 +98,7 @@ register_secured_file (const char *fname)
   struct stat buf;
   struct secured_file_item *sf;
 
-  /* Note that we stop immediatley if something goes wrong here. */
+  /* Note that we stop immediately if something goes wrong here. */
   if (stat (fname, &buf))
     log_fatal (_("fstat of '%s' failed in %s: %s\n"), fname,
                "register_secured_file", strerror (errno));
@@ -307,6 +308,9 @@ print_cipher_algo_note (cipher_algo_t algo)
 void
 print_digest_algo_note (digest_algo_t algo)
 {
+  const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo);
+  const struct weakhash *weak;
+
   if(algo >= 100 && algo <= 110)
     {
       static int warn=0;
@@ -315,30 +319,41 @@ print_digest_algo_note (digest_algo_t algo)
          warn=1;
           es_fflush (es_stdout);
          log_info (_("WARNING: using experimental digest algorithm %s\n"),
-                    gcry_md_algo_name (algo));
+                    gcry_md_algo_name (galgo));
        }
     }
-  else if(algo==DIGEST_ALGO_MD5)
-    {
-      es_fflush (es_stdout);
-      log_info (_("WARNING: digest algorithm %s is deprecated\n"),
-                gcry_md_algo_name (algo));
-    }
+  else
+      for (weak = opt.weak_digests; weak != NULL; weak = weak->next)
+        if (weak->algo == galgo)
+          {
+            es_fflush (es_stdout);
+            log_info (_("WARNING: digest algorithm %s is deprecated\n"),
+                      gcry_md_algo_name (galgo));
+          }
 }
 
 
 void
-print_md5_rejected_note (void)
+print_digest_rejected_note (enum gcry_md_algos algo)
 {
-  static int shown;
-
-  if (!shown)
+  struct weakhash* weak;
+  int show = 1;
+  for (weak = opt.weak_digests; weak; weak = weak->next)
+    if (weak->algo == algo)
+      {
+        if (weak->rejection_shown)
+          show = 0;
+        else
+          weak->rejection_shown = 1;
+        break;
+      }
+
+  if (show)
     {
       es_fflush (es_stdout);
       log_info
         (_("Note: signatures using the %s algorithm are rejected\n"),
-         "MD5");
-      shown = 1;
+         gcry_md_algo_name(algo));
     }
 }
 
@@ -483,7 +498,7 @@ openpgp_cipher_blocklen (cipher_algo_t algo)
 }
 
 /****************
- * Wrapper around the libgcrypt function with additonal checks on
+ * Wrapper around the libgcrypt function with additional checks on
  * the OpenPGP contraints for the algo ID.
  */
 int
@@ -847,7 +862,7 @@ pct_expando(const char *string,struct expando_args *args)
 
            case 'f': /* Fingerprint of key being signed */
            case 'p': /* Fingerprint of the primary key making the signature. */
-           case 'g': /* Fingerprint of thge key making the signature.  */
+           case 'g': /* Fingerprint of the key making the signature.  */
              {
                byte array[MAX_FINGERPRINT_LEN];
                size_t len;
@@ -1059,7 +1074,7 @@ string_to_digest_algo (const char *string)
 {
   int val;
 
-  /* FIXME: We should make use of our wrapper fucntion and not assume
+  /* FIXME: We should make use of our wrapper function and not assume
      that there is a 1 to 1 mapping between OpenPGP and Libgcrypt.  */
   val = gcry_md_map_name (string);
   if (!val && string && (string[0]=='H' || string[0]=='h'))
@@ -1676,3 +1691,33 @@ ecdsa_qbits_from_Q (unsigned int qbits)
   qbits /= 2;
   return qbits;
 }
+
+
+/* Ignore signatures and certifications made over certain digest
+ * algorithms by default, MD5 is considered weak.  This allows users
+ * to deprecate support for other algorithms as well.
+ */
+void
+additional_weak_digest (const char* digestname)
+{
+  struct weakhash *weak = NULL;
+  const enum gcry_md_algos algo = string_to_digest_algo(digestname);
+
+  if (algo == GCRY_MD_NONE)
+    {
+      log_error (_("unknown weak digest '%s'\n"), digestname);
+      return;
+    }
+
+  /* Check to ensure it's not already present.  */
+  for (weak = opt.weak_digests; weak; weak = weak->next)
+    if (algo == weak->algo)
+      return;
+
+  /* Add it to the head of the list.  */
+  weak = xmalloc(sizeof(*weak));
+  weak->algo = algo;
+  weak->rejection_shown = 0;
+  weak->next = opt.weak_digests;
+  opt.weak_digests = weak;
+}
index d57ab5d..0bb2aae 100644 (file)
@@ -1,6 +1,7 @@
 /* options.h
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2007, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -24,6 +25,7 @@
 #include <types.h>
 #include "main.h"
 #include "packet.h"
+#include "tofu.h"
 #include "../common/session-env.h"
 
 #ifndef EXTERN_UNLESS_MAIN_MODULE
@@ -86,7 +88,7 @@ struct
   int compress_level;
   int bz2_compress_level;
   int bz2_decompress_lowmem;
-  const char *def_secret_key;
+  strlist_t def_secret_key;
   char *def_recipient;
   int def_recipient_self;
   strlist_t secret_keys_to_try;
@@ -114,12 +116,18 @@ struct
   int skip_verify;
   int skip_hidden_recipients;
 
-  /* TM_CLASSIC must be zero to accomodate trustdbs generated before
+  /* TM_CLASSIC must be zero to accommodate trustdbs generated before
      we started storing the trust model inside the trustdb. */
   enum
     {
-      TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2, TM_ALWAYS, TM_DIRECT, TM_AUTO
+      TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2,
+      TM_ALWAYS, TM_DIRECT, TM_AUTO, TM_TOFU, TM_TOFU_PGP
     } trust_model;
+  enum
+    {
+      TOFU_DB_AUTO=0, TOFU_DB_SPLIT, TOFU_DB_FLAT
+    } tofu_db_format;
+  enum tofu_policy tofu_default_policy;
   int force_ownertrust;
   enum
     {
@@ -128,7 +136,7 @@ struct
     } compliance;
   enum
     {
-      KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
+      KF_DEFAULT, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
     } keyid_format;
   int shm_coprocess;
   const char *set_filename;
@@ -162,10 +170,12 @@ struct
   prefitem_t *personal_cipher_prefs;
   prefitem_t *personal_digest_prefs;
   prefitem_t *personal_compress_prefs;
+  struct weakhash *weak_digests;
   int no_perm_warn;
   int no_mdc_warn;
   char *temp_dir;
   int no_encrypt_to;
+  int encrypt_to_default_key;
   int interactive;
   struct notation *sig_notations;
   struct notation *cert_notations;
@@ -252,6 +262,9 @@ struct
 
   int passphrase_repeat;
   int pinentry_mode;
+
+  int unwrap_encryption;
+  int only_sign_text_ids;
 } opt;
 
 /* CTRL is used to keep some global variables we currently can't
index eb7da75..9eb16cf 100644 (file)
@@ -175,6 +175,11 @@ typedef struct
   subpktarea_t *unhashed;    /* Ditto for unhashed data. */
   byte digest_start[2];      /* First 2 bytes of the digest. */
   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
+     the digest's value has not been saved here.  */
+  byte digest[512 / 8];
+  int digest_len;
 } PKT_signature;
 
 #define ATTRIB_IMAGE 1
@@ -476,7 +481,7 @@ int search_packet( iobuf_t inp, PACKET *pkt, off_t *retpos, int with_uid );
    reached.
 
    Returns -1 when end of file is reached or an error code, if an
-   error occured.  (Note: this function never returns 0, because it
+   error occurred.  (Note: this function never returns 0, because it
    effectively keeps going until it gets an EOF.)  */
 int copy_all_packets( iobuf_t inp, iobuf_t out );
 
@@ -573,7 +578,7 @@ const byte *parse_sig_subpkt2 ( PKT_signature *sig,
    constraints.
 
    Returns 0 if the size is acceptable.  Returns -2 if the buffer is
-   definately too short.  To check for an error, check whether the
+   definitely too short.  To check for an error, check whether the
    return value is less than 0.  */
 int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
 
@@ -616,7 +621,6 @@ void free_notation(struct notation *notation);
 void free_symkey_enc( PKT_symkey_enc *enc );
 void free_pubkey_enc( PKT_pubkey_enc *enc );
 void free_seckey_enc( PKT_signature *enc );
-int  digest_algo_from_sig( PKT_signature *sig );
 void release_public_key_parts( PKT_public_key *pk );
 void free_public_key( PKT_public_key *key );
 void free_attributes(PKT_user_id *uid);
@@ -633,13 +637,22 @@ int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
 
 
 /*-- sig-check.c --*/
-int signature_check( PKT_signature *sig, gcry_md_hd_t digest );
-int signature_check2( PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
-                     int *r_expired, int *r_revoked, PKT_public_key *ret_pk );
+/* Check a signature.  This is shorthand for check_signature2 with
+   the unnamed arguments passed as NULL.  */
+int check_signature (PKT_signature *sig, gcry_md_hd_t digest);
+
+/* Check a signature.  Looks up the public key from the key db.  (If
+   RET_PK is not NULL, it is returned in *RET_PK.)  DIGEST contains a
+   valid hash context that already includes the signed data.  This
+   function adds the relevant meta-data to the hash before finalizing
+   it and verifying the signature.  */
+int check_signature2 (PKT_signature *sig, gcry_md_hd_t digest,
+                     u32 *r_expiredate, int *r_expired, int *r_revoked,
+                     PKT_public_key *ret_pk);
 
 
 /*-- pubkey-enc.c --*/
-gpg_error_t get_session_key (PKT_pubkey_enc *k, DEK *dek);
+gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek);
 gpg_error_t get_override_session_key (DEK *dek, const char *string);
 
 /*-- compress.c --*/
@@ -650,6 +663,8 @@ int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd,
 int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek );
 
 /*-- plaintext.c --*/
+gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen,
+                             iobuf_t data, char **fnamep, estream_t *fpp);
 int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                                        int nooutput, int clearsig );
 int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2,
index 4e236cb..53b75a6 100644 (file)
@@ -3019,7 +3019,7 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
 /*
  * This packet is internally generated by us (ibn armor.c) to transfer
  * some information to the lower layer.  To make sure that this packet
- * is really a GPG faked one and not one comming from outside, we
+ * is really a GPG faked one and not one coming from outside, we
  * first check that there is a unique tag in it.
  *
  * The format of such a control packet is:
index 9996d18..c865660 100644 (file)
@@ -37,6 +37,7 @@
 #include "status.h"
 #include "photoid.h"
 #include "i18n.h"
+#include "tofu.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
@@ -112,7 +113,7 @@ do_show_revocation_reason( PKT_signature *sig )
 void
 show_revocation_reason( PKT_public_key *pk, int mode )
 {
-    /* Hmmm, this is not so easy becuase we have to duplicate the code
+    /* Hmmm, this is not so easy because we have to duplicate the code
      * used in the trustbd to calculate the keyflags.  We need to find
      * a clean way to check revocation certificates on keys and
      * signatures.  And there should be no duplicate code.  Because we
@@ -507,13 +508,13 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
 
 /****************
  * Check whether we can trust this signature.
- * Returns: Error if we shall not trust this signatures.
+ * Returns an error code if we should not trust this signature.
  */
 int
 check_signatures_trust( PKT_signature *sig )
 {
   PKT_public_key *pk = xmalloc_clear( sizeof *pk );
-  unsigned int trustlevel;
+  unsigned int trustlevel = TRUST_UNKNOWN;
   int rc=0;
 
   rc = get_pubkey( pk, sig->keyid );
@@ -537,7 +538,7 @@ check_signatures_trust( PKT_signature *sig )
     log_info(_("WARNING: this key might be revoked (revocation key"
               " not present)\n"));
 
-  trustlevel = get_validity (pk, NULL);
+  trustlevel = get_validity (pk, NULL, sig, 1);
 
   if ( (trustlevel & TRUST_FLAG_REVOKED) )
     {
@@ -701,7 +702,7 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
  * Return a malloced string with a default recipient if there is any
  */
 static char *
-default_recipient(void)
+default_recipient(ctrl_t ctrl)
 {
     PKT_public_key *pk;
     byte fpr[MAX_FINGERPRINT_LEN+1];
@@ -714,7 +715,7 @@ default_recipient(void)
     if( !opt.def_recipient_self )
        return NULL;
     pk = xmalloc_clear( sizeof *pk );
-    i = get_seckey_default (pk);
+    i = get_seckey_default (ctrl, pk);
     if( i ) {
        free_public_key( pk );
        return NULL;
@@ -829,7 +830,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (pk, pk->user_id);
+  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
   if ( (trustlevel & TRUST_FLAG_DISABLED) )
     {
       /* Key has been disabled. */
@@ -889,8 +890,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
    value but not very useful.  Group expansion is done on these names;
    they may be in any of the user Id formats we can handle.  The flags
    bits for each string in the string list are used for:
-     Bit 0: This is an encrypt-to recipient.
-     Bit 1: This is a hidden recipient.
+     Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
+     Bit 1 (PK_LIST_HIDDEN)    : This is a hidden recipient.
 
    USE is the desired use for the key - usually PUBKEY_USAGE_ENC.
 
@@ -920,7 +921,7 @@ build_pk_list (ctrl_t ctrl,
    * list of the encrypt-to ones (we always trust them). */
   for ( rov = remusr; rov; rov = rov->next )
     {
-      if ( !(rov->flags & 1) )
+      if ( !(rov->flags & PK_LIST_ENCRYPT_TO) )
         {
           /* This is a regular recipient; i.e. not an encrypt-to
              one. */
@@ -928,7 +929,7 @@ build_pk_list (ctrl_t ctrl,
 
           /* Hidden recipients are not allowed while in PGP mode,
              issue a warning and switch into GnuPG mode. */
-          if ((rov->flags&2) && (PGP6 || PGP7 || PGP8))
+          if ((rov->flags & PK_LIST_HIDDEN) && (PGP6 || PGP7 || PGP8))
             {
               log_info(_("you may not use %s while in %s mode\n"),
                        "--hidden-recipient",
@@ -972,13 +973,13 @@ build_pk_list (ctrl_t ctrl,
                   r = xmalloc( sizeof *r );
                   r->pk = pk; pk = NULL;
                   r->next = pk_list;
-                  r->flags = (rov->flags&2)?1:0;
+                  r->flags = (rov->flags&PK_LIST_HIDDEN)?1:0;
                   pk_list = r;
 
                   /* Hidden encrypt-to recipients are not allowed while
                      in PGP mode, issue a warning and switch into
                      GnuPG mode. */
-                  if ((r->flags&1) && (PGP6 || PGP7 || PGP8))
+                  if ((r->flags&PK_LIST_ENCRYPT_TO) && (PGP6 || PGP7 || PGP8))
                     {
                       log_info(_("you may not use %s while in %s mode\n"),
                                "--hidden-encrypt-to",
@@ -1009,7 +1010,7 @@ build_pk_list (ctrl_t ctrl,
 
       if (pk_list)
         any_recipients = 1;
-      def_rec = default_recipient();
+      def_rec = default_recipient(ctrl);
       have_def_rec = !!def_rec;
       if ( !have_def_rec )
         tty_printf(_("You did not specify a user ID. (you may use \"-r\")\n"));
@@ -1075,7 +1076,7 @@ build_pk_list (ctrl_t ctrl,
             }
 
           /* Do group expand here too.  The trick here is to continue
-             the loop if any expansion occured.  The code above will
+             the loop if any expansion occurred.  The code above will
              then list all expanded keys. */
           if (expand_id(answer,&backlog,0))
             continue;
@@ -1114,7 +1115,7 @@ build_pk_list (ctrl_t ctrl,
                 { /* Check validity of this key. */
                   int trustlevel;
 
-                  trustlevel = get_validity (pk, pk->user_id);
+                  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
                   if ( (trustlevel & TRUST_FLAG_DISABLED) )
                     {
                       tty_printf (_("Public key is disabled.\n") );
@@ -1152,7 +1153,7 @@ build_pk_list (ctrl_t ctrl,
           pk = NULL;
         }
     }
-  else if ( !any_recipients && (def_rec = default_recipient()) )
+  else if ( !any_recipients && (def_rec = default_recipient(ctrl)) )
     {
       /* We are in batch mode and have only a default recipient. */
       pk = xmalloc_clear( sizeof *pk );
@@ -1195,10 +1196,11 @@ build_pk_list (ctrl_t ctrl,
       any_recipients = 0;
       for (; remusr; remusr = remusr->next )
         {
-          if ( (remusr->flags & 1) )
+          if ( (remusr->flags & PK_LIST_ENCRYPT_TO) )
             continue; /* encrypt-to keys are already handled. */
 
-          rc = find_and_check_key (ctrl, remusr->d, use, !!(remusr->flags&2),
+          rc = find_and_check_key (ctrl, remusr->d, use,
+                                   !!(remusr->flags&PK_LIST_HIDDEN),
                                    &pk_list);
           if (rc)
             goto fail;
index a834621..c8a5d24 100644 (file)
@@ -31,7 +31,7 @@
 #include "main.h"
 #include "options.h"
 
-/* FIXME: Better chnage the fucntion name because mpi_ is used by
+/* FIXME: Better change the function name because mpi_ is used by
    gcrypt macros.  */
 gcry_mpi_t
 get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
index 7929f66..94ede07 100644 (file)
 #include "i18n.h"
 
 
-/* Handle a plaintext packet.  If MFX is not NULL, update the MDs
- * Note: We should have used the filter stuff here, but we have to add
- * some easy mimic to set a read limit, so we calculate only the bytes
- * from the plaintext.  */
-int
-handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
-                 int nooutput, int clearsig)
-{
-  char *fname = NULL;
-  estream_t fp = NULL;
-  static off_t count = 0;
-  int err = 0;
-  int c;
-  int convert = (pt->mode == 't' || pt->mode == 'u');
-#ifdef __riscos__
-  int filetype = 0xfff;
-#endif
+/* Get the output filename.  On success, the actual filename that is
+   used is set in *FNAMEP and a filepointer is returned in *FP.
 
-  /* Let people know what the plaintext info is. This allows the
-     receiving program to try and do something different based on the
-     format code (say, recode UTF-8 to local). */
-  if (!nooutput && is_status_enabled ())
-    {
-      char status[50];
+   EMBEDDED_NAME AND EMBEDDED_NAMELEN are normally stored in a
+   plaintext packet.  EMBEDDED_NAMELEN should not include any NUL
+   terminator (EMBEDDED_NAME does not need to be NUL terminated).
 
-      /* Better make sure that stdout has been flushed in case the
-         output will be written to it.  This is to make sure that no
-         not-yet-flushed stuff will be written after the plaintext
-         status message.  */
-      es_fflush (es_stdout);
-
-      snprintf (status, sizeof status,
-                "%X %lu ", (byte) pt->mode, (ulong) pt->timestamp);
-      write_status_text_and_buffer (STATUS_PLAINTEXT,
-                                   status, pt->name, pt->namelen, 0);
+   DATA is the iobuf containing the input data.  We just use it to get
+   the input file's filename.
 
-      if (!pt->is_partial)
-       {
-         snprintf (status, sizeof status, "%lu", (ulong) pt->len);
-         write_status_text (STATUS_PLAINTEXT_LENGTH, status);
-       }
-    }
+   On success, the caller is responsible for calling xfree on *FNAMEP
+   and calling es_close on *FPP.  */
+gpg_error_t
+get_output_file (const byte *embedded_name, int embedded_namelen,
+                 iobuf_t data, char **fnamep, estream_t *fpp)
+{
+  gpg_error_t err = 0;
+  char *fname = NULL;
+  estream_t fp = NULL;
+  int nooutput = 0;
 
   /* Create the filename as C string.  */
-  if (nooutput)
-    ;
-  else if (opt.outfp)
+  if (opt.outfp)
     {
       fname = xtrystrdup ("[FP]");
       if (!fname)
@@ -104,16 +80,17 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
           goto leave;
         }
     }
-  else if (pt->namelen == 8 && !memcmp (pt->name, "_CONSOLE", 8))
+  else if (embedded_namelen == 8 && !memcmp (embedded_name, "_CONSOLE", 8))
     {
       log_info (_("data not saved; use option \"--output\" to save it\n"));
       nooutput = 1;
     }
   else if (!opt.flags.use_embedded_filename)
     {
-      fname = make_outfile_name (iobuf_get_real_fname (pt->buf));
+      if (data)
+        fname = make_outfile_name (iobuf_get_real_fname (data));
       if (!fname)
-       fname = ask_outfile_name (pt->name, pt->namelen);
+       fname = ask_outfile_name (embedded_name, embedded_namelen);
       if (!fname)
        {
          err = gpg_error (GPG_ERR_GENERAL);    /* Can't create file. */
@@ -121,7 +98,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
        }
     }
   else
-    fname = utf8_to_native (pt->name, pt->namelen, 0);
+    fname = utf8_to_native (embedded_name, embedded_namelen, 0);
 
   if (nooutput)
     ;
@@ -188,7 +165,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
     ;
   else
     {
-      /* Note: riscos stuff is not expected to wrok anymore.  If we
+      /* Note: riscos stuff is not expected to work anymore.  If we
          want to port it again to riscos we should do most of the suff
          in estream.  FIXME: Consider to remove all riscos special
          cases.  */
@@ -205,7 +182,8 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
       /* If there's a ,xxx extension in the embedded filename,
          use that, else check whether the user input (in fname)
          has a ,xxx appended, then use that in preference */
-      if ((c = riscos_get_filetype_from_string (pt->name, pt->namelen)) != -1)
+      if ((c = riscos_get_filetype_from_string (embedded_name,
+                                                embedded_namelen)) != -1)
        filetype = c;
       if ((c = riscos_get_filetype_from_string (fname, strlen (fname))) != -1)
        filetype = c;
@@ -213,6 +191,70 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
     }
 #endif /* __riscos__ */
 
+ leave:
+  if (err)
+    {
+      if (fp && fp != es_stdout && fp != opt.outfp)
+        es_fclose (fp);
+      xfree (fname);
+      return err;
+    }
+
+  *fnamep = fname;
+  *fpp = fp;
+  return 0;
+}
+
+/* Handle a plaintext packet.  If MFX is not NULL, update the MDs
+ * Note: We should have used the filter stuff here, but we have to add
+ * some easy mimic to set a read limit, so we calculate only the bytes
+ * from the plaintext.  */
+int
+handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
+                 int nooutput, int clearsig)
+{
+  char *fname = NULL;
+  estream_t fp = NULL;
+  static off_t count = 0;
+  int err = 0;
+  int c;
+  int convert = (pt->mode == 't' || pt->mode == 'u');
+#ifdef __riscos__
+  int filetype = 0xfff;
+#endif
+
+  /* Let people know what the plaintext info is. This allows the
+     receiving program to try and do something different based on the
+     format code (say, recode UTF-8 to local). */
+  if (!nooutput && is_status_enabled ())
+    {
+      char status[50];
+
+      /* Better make sure that stdout has been flushed in case the
+         output will be written to it.  This is to make sure that no
+         not-yet-flushed stuff will be written after the plaintext
+         status message.  */
+      es_fflush (es_stdout);
+
+      snprintf (status, sizeof status,
+                "%X %lu ", (byte) pt->mode, (ulong) pt->timestamp);
+      write_status_text_and_buffer (STATUS_PLAINTEXT,
+                                   status, pt->name, pt->namelen, 0);
+
+      if (!pt->is_partial)
+       {
+         snprintf (status, sizeof status, "%lu", (ulong) pt->len);
+         write_status_text (STATUS_PLAINTEXT_LENGTH, status);
+       }
+    }
+
+  if (! nooutput)
+    {
+      err = get_output_file (pt->name, pt->namelen, pt->buf, &fname, &fp);
+      if (err)
+        goto leave;
+    }
+
   if (!pt->is_partial)
     {
       /* We have an actual length (which might be zero). */
index fd7f812..23a4473 100644 (file)
@@ -72,7 +72,7 @@ is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo)
  * which should have been allocated in secure memory by the caller.
  */
 gpg_error_t
-get_session_key (PKT_pubkey_enc * k, DEK * dek)
+get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
 {
   PKT_public_key *sk = NULL;
   int rc;
@@ -102,7 +102,7 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
         {
           free_public_key (sk);
           sk = xmalloc_clear (sizeof *sk);
-          rc = enum_secret_keys (&enum_context, sk);
+          rc = enum_secret_keys (ctrl, &enum_context, sk);
           if (rc)
             {
               rc = GPG_ERR_NO_SECKEY;
@@ -127,7 +127,7 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
           else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
             break; /* Don't try any more secret keys.  */
         }
-      enum_secret_keys (&enum_context, NULL);  /* free context */
+      enum_secret_keys (ctrl, &enum_context, NULL);  /* free context */
     }
 
 leave:
index eb3a989..ba87f35 100644 (file)
@@ -195,7 +195,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
  * Generate a revocation certificate for UNAME via a designated revoker
  */
 int
-gen_desig_revoke( const char *uname, strlist_t locusr )
+gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
 {
     int rc = 0;
     armor_filter_context_t *afx;
@@ -220,6 +220,11 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
     afx = new_armor_context ();
 
     kdbhd = keydb_new ();
+    if (!kdbhd)
+      {
+        rc = gpg_error_from_syserror ();
+        goto leave;
+      }
     rc = classify_user_id (uname, &desc, 1);
     if (!rc)
       rc = keydb_search (kdbhd, &desc, 1, NULL);
@@ -248,7 +253,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
 
     if(locusr)
       {
-       rc=build_sk_list(locusr, &sk_list, PUBKEY_USAGE_CERT);
+       rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
        if(rc)
          goto leave;
       }
@@ -312,6 +317,13 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
              tty_printf(_("(This is a sensitive revocation key)\n"));
            tty_printf("\n");
 
+           rc = agent_probe_secret_key (ctrl, pk2);
+           if (rc)
+             {
+               tty_printf (_("Secret key is not available.\n"));
+               continue;
+             }
+
            if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
          _("Create a designated revocation certificate for this key? (y/N) ")))
              continue;
@@ -321,10 +333,6 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
            if( !reason )
              continue;
 
-           rc = -1;/*FIXME: check_secret_key (pk2, 0 );*/
-           if (rc)
-             continue;
-
            if( !opt.armor )
              tty_printf(_("ASCII armored output forced.\n"));
 
@@ -527,7 +535,7 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
   char *orig_codeset;
 
   dir = get_openpgp_revocdir (opt.homedir);
-  tmpstr = hexfingerprint (psk);
+  tmpstr = hexfingerprint (psk, NULL, 0);
   fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
   xfree (tmpstr);
   xfree (dir);
@@ -606,13 +614,21 @@ gen_revoke (const char *uname)
 
   /* Search the userid; we don't want the whole getkey stuff here.  */
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
   rc = classify_user_id (uname, &desc, 1);
   if (!rc)
     rc = keydb_search (kdbhd, &desc, 1, NULL);
   if (rc)
     {
-      log_error (_("secret key \"%s\" not found: %s\n"),
-                 uname, gpg_strerror (rc));
+      if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+        log_error (_("secret key \"%s\" not found\n"), uname);
+      else
+        log_error (_("secret key \"%s\" not found: %s\n"),
+                   uname, gpg_strerror (rc));
       goto leave;
     }
 
@@ -623,6 +639,50 @@ gen_revoke (const char *uname)
       goto leave;
     }
 
+  rc = keydb_search (kdbhd, &desc, 1, NULL);
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+    /* Not ambiguous.  */
+    {
+    }
+  else if (rc == 0)
+    /* Ambiguous.  */
+    {
+      char *info;
+
+      /* TRANSLATORS: The %s prints a key specification which
+         for example has been given at the command line.  Several lines
+         lines with secret key infos are printed after this message.  */
+      log_error (_("'%s' matches multiple secret keys:\n"), uname);
+
+      info = format_seckey_info (keyblock->pkt->pkt.public_key);
+      log_error ("  %s\n", info);
+      xfree (info);
+      release_kbnode (keyblock);
+
+      rc = keydb_get_keyblock (kdbhd, &keyblock);
+      while (! rc)
+        {
+          info = format_seckey_info (keyblock->pkt->pkt.public_key);
+          log_info ("  %s\n", info);
+          xfree (info);
+          release_kbnode (keyblock);
+          keyblock = NULL;
+
+          rc = keydb_search (kdbhd, &desc, 1, NULL);
+          if (! rc)
+            rc = keydb_get_keyblock (kdbhd, &keyblock);
+        }
+
+      rc = GPG_ERR_AMBIGUOUS_NAME;
+
+      goto leave;
+    }
+  else
+    {
+      log_error (_("error searching the keyring: %s\n"), gpg_strerror (rc));
+      goto leave;
+    }
+
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
   if (!node)
index d02f20e..e5539d5 100644 (file)
@@ -257,7 +257,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
    then not be done for this key.  If the policy is not to sign at all
    if not all signer keys are valid, the client has to take care of
    this.  All SIGNER commands are cumulative until a RESET but they
-   are *not* reset by an SIGN command becuase it can be expected that
+   are *not* reset by an SIGN command because it can be expected that
    set of signers are used for more than one sign operation.
 
    Note that this command returns an INV_RECP status which is a bit
index d45a9f3..75b06e8 100644 (file)
@@ -1,6 +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
  *
  * This file is part of GnuPG.
  *
 #include "options.h"
 #include "pkglue.h"
 
+static int 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);
 
-
-
-static int do_check( PKT_public_key *pk, PKT_signature *sig,
-                     gcry_md_hd_t digest,
-                    int *r_expired, int *r_revoked, PKT_public_key *ret_pk);
-
-/****************
- * Check the signature which is contained in SIG.
- * The MD_HANDLE should be currently open, so that this function
- * is able to append some data, before finalizing the digest.
- */
+/* Check a signature.  This is shorthand for check_signature2 with
+   the unnamed arguments passed as NULL.  */
 int
-signature_check (PKT_signature *sig, gcry_md_hd_t digest)
+check_signature (PKT_signature *sig, gcry_md_hd_t digest)
 {
-    return signature_check2( sig, digest, NULL, NULL, NULL, NULL );
+    return check_signature2 (sig, digest, NULL, NULL, NULL, NULL);
 }
 
+/* Check a signature.
+
+   Looks up the public key that created the signature (SIG->KEYID)
+   from the key db.  Makes sure that the signature is valid (it was
+   not created prior to the key, the public key was created in the
+   past, and the signature does not include any unsupported critical
+   features), finishes computing the hash of the signature data, and
+   checks that the signature verifies the digest.  If the key that
+   generated the signature is a subkey, this function also verifies
+   that there is a valid backsig from the subkey to the primary key.
+   Finally, if status fd is enabled and the signature class is 0x00 or
+   0x01, then a STATUS_SIG_ID is emitted on the status fd.
+
+   SIG is the signature to check.
+
+   DIGEST contains a valid hash context that already includes the
+   signed data.  This function adds the relevant meta-data from the
+   signature packet to compute the final hash.  (See Section 5.2 of
+   RFC 4880: "The concatenation of the data being signed and the
+   signature data from the version number through the hashed subpacket
+   data (inclusive) is hashed.")
+
+   If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
+   expiry.
+
+   If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
+   (0 otherwise).  Note: PK being expired does not cause this function
+   to fail.
+
+   If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
+   revoked (0 otherwise).  Note: PK being revoked does not cause this
+   function to fail.
+
+   If PK is not NULL, the public key is saved in *PK on success.
+
+   Returns 0 on success.  An error code otherwise.  */
 int
-signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
+check_signature2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
                  int *r_expired, int *r_revoked, PKT_public_key *pk )
 {
     int rc=0;
@@ -93,14 +125,14 @@ signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
         if(r_expiredate)
          *r_expiredate = pk->expiredate;
 
-       rc = do_check( pk, sig, digest, r_expired, r_revoked, NULL );
+       rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
 
        /* Check the backsig.  This is a 0x19 signature from the
           subkey on the primary key.  The idea here is that it should
           not be possible for someone to "steal" subkeys and claim
           them as their own.  The attacker couldn't actually use the
           subkey, but they could try and claim ownership of any
-          signaures issued by it. */
+          signatures issued by it. */
        if(rc==0 && !pk->flags.primary && pk->flags.backsig < 2)
          {
            if (!pk->flags.backsig)
@@ -144,7 +176,7 @@ signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
         * like this feature here.
          *
          * Note that before 2.0.10, we used RIPE-MD160 for the hash
-         * and accidently didn't include the timestamp and algorithm
+         * and accidentally didn't include the timestamp and algorithm
          * information in the hash.  Given that this feature is not
          * commonly used and that a replay attacks detection should
          * not solely be based on this feature (because it does not
@@ -204,9 +236,26 @@ signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
 }
 
 
+/* The signature SIG was generated with the public key PK.  Check
+   whether the signature is valid in the following sense:
+
+     - Make sure the public key was created before the signature was
+       generated.
+
+     - Make sure the public key was created in the past
+
+     - Check whether PK has expired (set *R_EXPIRED to 1 if so and 0
+       otherwise)
+
+     - Check whether PK has been revoked (set *R_REVOKED to 1 if so
+       and 0 otherwise).
+
+   If either of the first two tests fail, returns an error code.
+   Otherwise returns 0.  (Thus, this function doesn't fail if the
+   public key is expired or revoked.)  */
 static int
-do_check_messages( PKT_public_key *pk, PKT_signature *sig,
-                  int *r_expired, int *r_revoked )
+check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
+                                  int *r_expired, int *r_revoked)
 {
     u32 cur_time;
 
@@ -268,22 +317,55 @@ do_check_messages( PKT_public_key *pk, PKT_signature *sig,
 }
 
 
+/* Finish generating a signature and check it.  Concretely: make sure
+   that the signature is valid (it was not created prior to the key,
+   the public key was created in the past, and the signature does not
+   include any unsupported critical features), finish computing the
+   digest by adding the relevant data from the signature packet, and
+   check that the signature verifies the digest.
+
+   DIGEST contains a hash context, which has already hashed the signed
+   data.  This function adds the relevant meta-data from the signature
+   packet to compute the final hash.  (See Section 5.2 of RFC 4880:
+   "The concatenation of the data being signed and the signature data
+   from the version number through the hashed subpacket data
+   (inclusive) is hashed.")
+
+   SIG is the signature to check.
+
+   PK is the public key used to generate the signature.
+
+   If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
+   (0 otherwise).  Note: PK being expired does not cause this function
+   to fail.
+
+   If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
+   revoked (0 otherwise).  Note: PK being revoked does not cause this
+   function to fail.
+
+   If RET_PK is not NULL, PK is copied into RET_PK on success.
+
+   Returns 0 on success.  An error code other.  */
 static int
-do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
-         int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
+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=do_check_messages(pk,sig,r_expired,r_revoked)) )
+    if ((rc = check_signature_metadata_validity (pk, sig,
+                                                r_expired, r_revoked)))
         return rc;
 
-    if (sig->digest_algo == GCRY_MD_MD5
-        && !opt.flags.allow_weak_digest_algos)
-      {
-        print_md5_rejected_note ();
-        return GPG_ERR_DIGEST_ALGO;
-      }
+    if (!opt.flags.allow_weak_digest_algos)
+      for (weak = opt.weak_digests; weak; weak = weak->next)
+        if (sig->digest_algo == weak->algo)
+          {
+            print_digest_rejected_note(sig->digest_algo);
+            return GPG_ERR_DIGEST_ALGO;
+          }
 
     /* Make sure the digest algo is enabled (in case of a detached
        signature).  */
@@ -319,7 +401,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
          gcry_md_putc (digest, 0);
          n = 6;
        }
-       /* add some magic */
+       /* add some magic per Section 5.2.4 of RFC 4880.  */
        buf[0] = sig->version;
        buf[1] = 0xff;
        buf[2] = n >> 24;
@@ -330,9 +412,12 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
     }
     gcry_md_final( digest );
 
+    /* Convert the digest to an MPI.  */
     result = encode_md_value (pk, digest, sig->digest_algo );
     if (!result)
         return GPG_ERR_GENERAL;
+
+    /* Verify the signature.  */
     rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey );
     gcry_mpi_release (result);
 
@@ -350,7 +435,8 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
 }
 
 
-
+/* 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 )
 {
@@ -400,24 +486,37 @@ cache_sig_result ( PKT_signature *sig, int result )
     }
 }
 
-/* Check the revocation keys to see if any of them have revoked our
-   pk.  sig is the revocation sig.  pk is the key it is on.  This code
-   will need to be modified if gpg ever becomes multi-threaded.  Note
-   that this guarantees that a designated revocation sig will never be
-   considered valid unless it is actually valid, as well as being
-   issued by a revocation key in a valid direct signature.  Note also
-   that this is written so that a revoked revoker can still issue
-   revocations: i.e. If A revokes B, but A is revoked, B is still
-   revoked.  I'm not completely convinced this is the proper behavior,
-   but it matches how PGP does it. -dms */
-
-/* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
-   revoked.  It is important that GPG_ERR_NO_PUBKEY is only returned
-   when a revocation signature is from a valid revocation key
-   designated in a revkey subpacket, but the revocation key itself
-   isn't present. */
+/* SIG is a key revocation signature.  Check if this signature was
+   generated by any of the public key PK's designated revokers.
+
+     PK is the public key that SIG allegedly revokes.
+
+     SIG is the revocation signature to check.
+
+   This function avoids infinite recursion, which can happen if two
+   keys are designed revokers for each other and they revoke each
+   other.  This is done by observing that if a key A is revoked by key
+   B we still consider the revocation to be valid even if B is
+   revoked.  Thus, we don't need to determine whether B is revoked to
+   determine whether A has been revoked by B, we just need to check
+   the signature.
+
+   Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
+   revoked.  We are careful to make sure that GPG_ERR_NO_PUBKEY is
+   only returned when a revocation signature is from a valid
+   revocation key designated in a revkey subpacket, but the revocation
+   key itself isn't present.  */
+
+/* XXX: This code will need to be modified if gpg ever becomes
+   multi-threaded.  Note that this guarantees that a designated
+   revocation sig will never be considered valid unless it is actually
+   valid, as well as being issued by a revocation key in a valid
+   direct signature.  Note also that this is written so that a revoked
+   revoker can still issue revocations: i.e. If A revokes B, but A is
+   revoked, B is still revoked.  I'm not completely convinced this is
+   the proper behavior, but it matches how PGP does it. -dms */
 int
-check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
+check_revocation_keys (PKT_public_key *pk, PKT_signature *sig)
 {
   static int busy=0;
   int i;
@@ -426,6 +525,30 @@ check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
   assert(IS_KEY_REV(sig));
   assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
 
+  /* Avoid infinite recursion.  Consider the following:
+
+       - We want to check if A is revoked.
+
+       - C is a designated revoker for B and has revoked B.
+
+       - B is a designated revoker for A and has revoked A.
+
+     When checking if A is revoked (in merge_selfsigs_main), we
+     observe that A has a designed revoker.  As such, we call this
+     function.  This function sees that there is a valid revocation
+     signature, which is signed by B.  It then calls check_signature()
+     to verify that the signature is good.  To check the sig, we need
+     to lookup B.  Looking up B means calling merge_selfsigs_main,
+     which checks whether B is revoked, which calls this function to
+     see if B was revoked by some key.
+
+     In this case, the added level of indirection doesn't hurt.  It
+     just means a bit more work.  However, if C == A, then we'd end up
+     in a loop.  But, it doesn't make sense to look up C anyways: even
+     if B is revoked, we conservatively consider a valid revocation
+     signed by B to revoke A.  Since this is the only place where this
+     type of recursion can occur, we simply cause this function to
+     fail if it is entered recursively.  */
   if (busy)
     {
       /* Return an error (i.e. not revoked), but mark the pk as
@@ -446,18 +569,23 @@ check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
   else
       for(i=0;i<pk->numrevkeys;i++)
        {
+         /* The revoker's keyid.  */
           u32 keyid[2];
 
           keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
 
           if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
+           /* The signature was generated by a designated revoker.
+              Verify the signature.  */
            {
               gcry_md_hd_t md;
 
               if (gcry_md_open (&md, sig->digest_algo, 0))
                 BUG ();
               hash_public_key(md,pk);
-              rc=signature_check(sig,md);
+             /* Note: check_signature only checks that the signature
+                is good.  It does not fail if the key is revoked.  */
+              rc=check_signature(sig,md);
              cache_sig_result(sig,rc);
               gcry_md_close (md);
              break;
@@ -469,21 +597,24 @@ check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
   return rc;
 }
 
-/* Backsigs (0x19) have the same format as binding sigs (0x18), but
+/* Check that the backsig BACKSIG from the subkey SUB_PK to its
+   primary key MAIN_PK is valid.
+
+   Backsigs (0x19) have the same format as binding sigs (0x18), but
    this function is simpler than check_key_signature in a few ways.
    For example, there is no support for expiring backsigs since it is
    questionable what such a thing actually means.  Note also that the
    sig cache check here, unlike other sig caches in GnuPG, is not
    persistent. */
 int
-check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
-             PKT_signature *backsig)
+check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk,
+              PKT_signature *backsig)
 {
   gcry_md_hd_t md;
   int rc;
 
   /* Always check whether the algorithm is available.  Although
-     gcry_md_open woyuld throw an error, some libgcrypt versions will
+     gcry_md_open would throw an error, some libgcrypt versions will
      print a debug message in that case too. */
   if ((rc=openpgp_md_test_algo (backsig->digest_algo)))
     return rc;
@@ -496,7 +627,7 @@ check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
     {
       hash_public_key(md,main_pk);
       hash_public_key(md,sub_pk);
-      rc=do_check(sub_pk,backsig,md,NULL,NULL,NULL);
+      rc = check_signature_end (sub_pk, backsig, md, NULL, NULL, NULL);
       cache_sig_result(backsig,rc);
       gcry_md_close(md);
     }
@@ -505,27 +636,53 @@ check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk,
 }
 
 
-/****************
- * check the signature pointed to by NODE. This is a key signature.
- * If the function detects a self-signature, it uses the PK from
- * ROOT and does not read any public key.
- */
+/* Check that a signature over a key is valid.  This is a
+   specialization of check_key_signature2 with the unnamed parameters
+   passed as NULL.  See the documentation for that function for more
+   details.  */
 int
-check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
+check_key_signature (KBNODE root, KBNODE node, int *is_selfsig)
 {
-  return check_key_signature2(root, node, NULL, NULL, is_selfsig, NULL, NULL );
+  return check_key_signature2 (root, node, NULL, NULL, is_selfsig, NULL, NULL);
 }
 
-/* If check_pk is set, then use it to check the signature in node
-   rather than getting it from root or the keydb.  If ret_pk is set,
-   fill in the public key that was used to verify the signature.
-   ret_pk is only meaningful when the verification was successful. */
+/* 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
+   key block and does not bother looking up the key specified in the
+   signature packet.
+
+   ROOT is a keyblock.
+
+   NODE references a signature packet that appears in the keyblock
+   that should be verified.
+
+   If CHECK_PK is set, the specified key is sometimes preferred for
+   verifying signatures.  See the implementation for details.
+
+   If RET_PK is not NULL, the public key that successfully verified
+   the signature is copied into *RET_PK.
+
+   If IS_SELFSIG is not NULL, *IS_SELFSIG is set to 1 if NODE is a
+   self-signature.
+
+   If R_EXPIREDATE is not NULL, *R_EXPIREDATE is set to the expiry
+   date.
+
+   If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has been
+   expired (0 otherwise).  Note: PK being revoked does not cause this
+   function to fail.
+
+
+   If OPT.NO_SIG_CACHE is not set, this function will first check if
+   the result of a previous verification is already cached in the
+   signature packet's data structure.  */
 /* TODO: add r_revoked here as well.  It has the same problems as
    r_expiredate and r_expired and the cache. */
 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 )
+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 )
 {
     gcry_md_hd_t md;
     PKT_public_key *pk;
@@ -561,7 +718,8 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
            }
            /* BUG: This is wrong for non-self-sigs.. needs to be the
               actual pk */
-           if((rc=do_check_messages(pk,sig,r_expired,NULL)))
+           if((rc = check_signature_metadata_validity (pk, sig,
+                                                       r_expired, NULL)))
              return rc;
             return sig->flags.valid? 0 : gpg_error (GPG_ERR_BAD_SIGNATURE);
         }
@@ -584,7 +742,7 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
            if (gcry_md_open (&md, algo, 0 ))
               BUG ();
            hash_public_key( md, pk );
-           rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
+           rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
            cache_sig_result ( sig, rc );
            gcry_md_close(md);
          }
@@ -597,7 +755,7 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
               BUG ();
            hash_public_key( md, pk );
            hash_public_key( md, snode->pkt->pkt.public_key );
-           rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
+           rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
             cache_sig_result ( sig, rc );
            gcry_md_close(md);
        }
@@ -624,7 +782,7 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
               BUG ();
            hash_public_key( md, pk );
            hash_public_key( md, snode->pkt->pkt.public_key );
-           rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
+           rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
             cache_sig_result ( sig, rc );
            gcry_md_close(md);
        }
@@ -640,7 +798,7 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
         if (gcry_md_open (&md, algo, 0 ))
           BUG ();
        hash_public_key( md, pk );
-       rc = do_check( pk, sig, md, r_expired, NULL, ret_pk );
+       rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
         cache_sig_result ( sig, rc );
        gcry_md_close(md);
     }
@@ -656,15 +814,21 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
            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 = do_check( pk, sig, md, r_expired, NULL, ret_pk );
+               rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
              }
            else if (check_pk)
-             rc=do_check(check_pk,sig,md,r_expired,NULL,ret_pk);
+             /* The caller specified a key.  Try that.  */
+             rc = check_signature_end (check_pk, sig, md,
+                                       r_expired, NULL, ret_pk);
            else
-             rc=signature_check2(sig,md,r_expiredate,r_expired,NULL,ret_pk);
+             /* Look up the key.  XXX: Could it be that the key is
+                not is not in this keyblock?  */
+             rc = check_signature2 (sig, md, r_expiredate, r_expired,
+                                    NULL, ret_pk);
 
             cache_sig_result ( sig, rc );
            gcry_md_close(md);
index 782b9fc..baa0068 100644 (file)
@@ -769,7 +769,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    if( (rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG )) )
+    if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
     if (encryptflag
@@ -1057,7 +1057,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
  * make a clear signature. note that opt.armor is not needed
  */
 int
-clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
+clearsign_file (ctrl_t ctrl,
+                const char *fname, strlist_t locusr, const char *outfile )
 {
     armor_filter_context_t *afx;
     progress_filter_context_t *pfx;
@@ -1080,7 +1081,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    if( (rc=build_sk_list( locusr, &sk_list, PUBKEY_USAGE_SIG )) )
+    if( (rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
     /* prepare iobufs */
@@ -1191,7 +1192,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
  * FIXME: Far too much code is duplicated - revamp the whole file.
  */
 int
-sign_symencrypt_file (const char *fname, strlist_t locusr)
+sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
 {
     armor_filter_context_t *afx;
     progress_filter_context_t *pfx;
@@ -1224,7 +1225,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG);
+    rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG);
     if (rc)
        goto leave;
 
@@ -1261,12 +1262,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
         goto leave;
     }
 
-    /* We have no way to tell if the recipient can handle messages
-       with an MDC, so this defaults to no.  Perhaps in a few years,
-       this can be defaulted to yes.  Note that like regular
-       encrypting, --force-mdc overrides --disable-mdc. */
-    if(opt.force_mdc)
-      cfx.dek->use_mdc=1;
+    cfx.dek->use_mdc = use_mdc (NULL, cfx.dek->algo);
 
     /* now create the outfile */
     rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
@@ -1309,7 +1305,11 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* Push the compress filter */
     if (default_compress_algo())
-      push_compress_filter(out,&zfx,default_compress_algo());
+      {
+        if (cfx.dek && cfx.dek->use_mdc)
+          zfx.new_ctb = 1;
+        push_compress_filter (out, &zfx,default_compress_algo() );
+      }
 
     /* Write the one-pass signature packets */
     /*(current filters: zip - encrypt - armor)*/
index 53d6f77..3d137b2 100644 (file)
@@ -114,7 +114,8 @@ is_duplicated_entry (strlist_t list, strlist_t item)
 
 
 gpg_error_t
-build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
+build_sk_list (ctrl_t ctrl,
+               strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
 {
   gpg_error_t err;
   SK_LIST sk_list = NULL;
@@ -125,7 +126,7 @@ build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
 
       pk = xmalloc_clear (sizeof *pk);
       pk->req_usage = use;
-      if ((err = getkey_byname (NULL, pk, NULL, 1, NULL)))
+      if ((err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL)))
        {
          free_public_key (pk);
          pk = NULL;
@@ -182,7 +183,7 @@ build_sk_list (strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
            }
          pk = xmalloc_clear (sizeof *pk);
          pk->req_usage = use;
-          if ((err = getkey_byname (NULL, pk, locusr->d, 1, NULL)))
+          if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL)))
            {
              free_public_key (pk);
              pk = NULL;
diff --git a/g10/sqlite.c b/g10/sqlite.c
new file mode 100644 (file)
index 0000000..599a3ef
--- /dev/null
@@ -0,0 +1,252 @@
+/* sqlite.c - SQLite helper functions.
+ * Copyright (C) 2015 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 <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "gpg.h"
+#include "util.h"
+#include "logging.h"
+
+#include "sqlite.h"
+
+/* This is a convenience function that combines sqlite3_mprintf and
+   sqlite3_exec.  */
+int
+sqlite3_exec_printf (sqlite3 *db,
+                    int (*callback)(void*,int,char**,char**), void *cookie,
+                    char **errmsg,
+                    const char *sql, ...)
+{
+  va_list ap;
+  int rc;
+  char *sql2;
+
+  va_start (ap, sql);
+  sql2 = sqlite3_vmprintf (sql, ap);
+  va_end (ap);
+
+#if 0
+  log_debug ("tofo db: executing: '%s'\n", sql2);
+#endif
+
+  rc = sqlite3_exec (db, sql2, callback, cookie, errmsg);
+
+  sqlite3_free (sql2);
+
+  return rc;
+}
+
+int
+sqlite3_stepx (sqlite3 *db,
+               sqlite3_stmt **stmtp,
+               sqlite3_stepx_callback callback,
+               void *cookie,
+               char **errmsg,
+               const char *sql, ...)
+{
+  int rc;
+  int err = 0;
+  sqlite3_stmt *stmt = NULL;
+
+  va_list va;
+  int args;
+  enum sqlite_arg_type t;
+  int i;
+
+  int cols;
+  /* Names of the columns.  We initialize this lazily to avoid the
+     overhead in case the query doesn't return any results.  */
+  const char **azColName = 0;
+  int callback_initialized = 0;
+
+  const char **azVals = 0;
+
+  callback_initialized = 0;
+
+  if (stmtp && *stmtp)
+    {
+      stmt = *stmtp;
+
+      /* Make sure this statement is associated with the supplied db.  */
+      assert (db == sqlite3_db_handle (stmt));
+
+#if DEBUG_TOFU_CACHE
+      prepares_saved ++;
+#endif
+    }
+  else
+    {
+      const char *tail = NULL;
+
+      rc = sqlite3_prepare_v2 (db, sql, -1, &stmt, &tail);
+      if (rc)
+        log_fatal ("failed to prepare SQL: %s", sql);
+
+      /* We can only process a single statement.  */
+      if (tail)
+        {
+          while (*tail == ' ' || *tail == ';' || *tail == '\n')
+            tail ++;
+
+          if (*tail)
+            log_fatal
+              ("sqlite3_stepx can only process a single SQL statement."
+               "  Second statement starts with: '%s'\n",
+               tail);
+        }
+
+      if (stmtp)
+        *stmtp = stmt;
+    }
+
+#if DEBUG_TOFU_CACHE
+  queries ++;
+#endif
+
+  args = sqlite3_bind_parameter_count (stmt);
+  va_start (va, sql);
+  if (args)
+    {
+      for (i = 1; i <= args; i ++)
+        {
+          t = va_arg (va, enum sqlite_arg_type);
+          switch (t)
+            {
+            case SQLITE_ARG_INT:
+              {
+                int value = va_arg (va, int);
+                err = sqlite3_bind_int (stmt, i, value);
+                break;
+              }
+            case SQLITE_ARG_LONG_LONG:
+              {
+                long long value = va_arg (va, long long);
+                err = sqlite3_bind_int64 (stmt, i, value);
+                break;
+              }
+            case SQLITE_ARG_STRING:
+              {
+                char *text = va_arg (va, char *);
+                err = sqlite3_bind_text (stmt, i, text, -1, SQLITE_STATIC);
+                break;
+              }
+            case SQLITE_ARG_BLOB:
+              {
+                char *blob = va_arg (va, void *);
+                long long length = va_arg (va, long long);
+                err = sqlite3_bind_blob (stmt, i, blob, length, SQLITE_STATIC);
+                break;
+              }
+            default:
+              /* Internal error.  Likely corruption.  */
+              log_fatal ("Bad value for parameter type %d.\n", t);
+            }
+
+          if (err)
+            {
+              log_fatal ("Error binding parameter %d\n", i);
+              goto out;
+            }
+        }
+
+    }
+  t = va_arg (va, enum sqlite_arg_type);
+  assert (t == SQLITE_ARG_END);
+  va_end (va);
+
+  for (;;)
+    {
+      rc = sqlite3_step (stmt);
+
+      if (rc != SQLITE_ROW)
+        /* No more data (SQLITE_DONE) or an error occurred.  */
+        break;
+
+      if (! callback)
+        continue;
+
+      if (! callback_initialized)
+        {
+          cols = sqlite3_column_count (stmt);
+          azColName = xmalloc (2 * cols * sizeof (const char *) + 1);
+
+          for (i = 0; i < cols; i ++)
+            azColName[i] = sqlite3_column_name (stmt, i);
+
+          callback_initialized = 1;
+        }
+
+      azVals = &azColName[cols];
+      for (i = 0; i < cols; i ++)
+        {
+          azVals[i] = sqlite3_column_text (stmt, i);
+          if (! azVals[i] && sqlite3_column_type (stmt, i) != SQLITE_NULL)
+            /* Out of memory.  */
+            {
+              err = SQLITE_NOMEM;
+              break;
+            }
+        }
+
+      if (callback (cookie, cols, (char **) azVals, (char **) azColName, stmt))
+        /* A non-zero result means to abort.  */
+        {
+          err = SQLITE_ABORT;
+          break;
+        }
+    }
+
+ out:
+  xfree (azColName);
+
+  if (stmtp)
+    rc = sqlite3_reset (stmt);
+  else
+    rc = sqlite3_finalize (stmt);
+  if (rc == SQLITE_OK && err)
+    /* Local error.  */
+    {
+      rc = err;
+      if (errmsg)
+        {
+          const char *e = sqlite3_errstr (err);
+          size_t l = strlen (e) + 1;
+          *errmsg = sqlite3_malloc (l);
+          if (! *errmsg)
+            log_fatal ("Out of memory.\n");
+          memcpy (*errmsg, e, l);
+        }
+    }
+  else if (rc != SQLITE_OK && errmsg)
+    /* Error reported by sqlite.  */
+    {
+      const char * e = sqlite3_errmsg (db);
+      size_t l = strlen (e) + 1;
+      *errmsg = sqlite3_malloc (l);
+      if (! *errmsg)
+        log_fatal ("Out of memory.\n");
+      memcpy (*errmsg, e, l);
+    }
+
+  return rc;
+}
diff --git a/g10/sqlite.h b/g10/sqlite.h
new file mode 100644 (file)
index 0000000..753e37a
--- /dev/null
@@ -0,0 +1,62 @@
+/* sqlite.h - SQLite helper functions.
+ * Copyright (C) 2015 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 GNUPG_SQLITE_H
+#define GNUPG_SQLITE_H
+
+#include <sqlite3.h>
+
+enum sqlite_arg_type
+  {
+    SQLITE_ARG_END = 0xdead001,
+    SQLITE_ARG_INT,
+    SQLITE_ARG_LONG_LONG,
+    SQLITE_ARG_STRING,
+    /* This takes two arguments: the blob as a void * and the length
+       of the blob as a long long.  */
+    SQLITE_ARG_BLOB
+  };
+
+
+int sqlite3_exec_printf (sqlite3 *db,
+                         int (*callback)(void*,int,char**,char**), void *cookie,
+                         char **errmsg,
+                         const char *sql, ...);
+
+typedef int (*sqlite3_stepx_callback) (void *cookie,
+                                       /* number of columns.  */
+                                       int cols,
+                                       /* columns as text.  */
+                                       char **values,
+                                       /* column names.  */
+                                       char **names,
+                                       /* The prepared statement so
+                                          that it is possible to use
+                                          something like
+                                          sqlite3_column_blob().  */
+                                       sqlite3_stmt *statement);
+
+int sqlite3_stepx (sqlite3 *db,
+                   sqlite3_stmt **stmtp,
+                   sqlite3_stepx_callback callback,
+                   void *cookie,
+                   char **errmsg,
+                   const char *sql, ...);
+
+#endif
diff --git a/g10/t-keydb-get-keyblock.c b/g10/t-keydb-get-keyblock.c
new file mode 100644 (file)
index 0000000..c12bab1
--- /dev/null
@@ -0,0 +1,62 @@
+/* t-keydb-get-keyblock.c - Tests for keydb.c.
+ * Copyright (C) 2015 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 "test.c"
+
+#include "keydb.h"
+
+static void
+do_test (int argc, char *argv[])
+{
+  char *fname;
+  int rc;
+  KEYDB_HANDLE hd1;
+  KEYDB_SEARCH_DESC desc1;
+  KBNODE kb1;
+
+  (void) argc;
+  (void) argv;
+
+  /* t-keydb-get-keyblock.gpg contains two keys: a modern key followed
+     by a legacy key.  If we get the keyblock for the modern key, we
+     shouldn't get
+
+     - */
+  fname = prepend_srcdir ("t-keydb-get-keyblock.gpg");
+  rc = keydb_add_resource (fname, 0);
+  test_free (fname);
+  if (rc)
+    ABORT ("Failed to open keyring.");
+
+  hd1 = keydb_new ();
+  if (!hd1)
+    ABORT ("");
+
+  rc = classify_user_id ("8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367",
+                        &desc1, 0);
+  if (rc)
+    ABORT ("Failed to convert fingerprint for 1E42B367");
+
+  rc = keydb_search (hd1, &desc1, 1, NULL);
+  if (rc)
+    ABORT ("Failed to lookup key associated with 1E42B367");
+
+  rc = keydb_get_keyblock (hd1, &kb1);
+  TEST_P ("", ! rc);
+}
diff --git a/g10/t-keydb-get-keyblock.gpg b/g10/t-keydb-get-keyblock.gpg
new file mode 100644 (file)
index 0000000..521487e
Binary files /dev/null and b/g10/t-keydb-get-keyblock.gpg differ
index 17a7611..f0b7778 100644 (file)
@@ -42,7 +42,11 @@ do_test (int argc, char *argv[])
     ABORT ("Failed to open keyring.");
 
   hd1 = keydb_new ();
+  if (!hd1)
+    ABORT ("");
   hd2 = keydb_new ();
+  if (!hd2)
+    ABORT ("");
 
   rc = classify_user_id ("2689 5E25 E844 6D44 A26D  8FAF 2F79 98F3 DBFC 6AD9",
                         &desc1, 0);
index 69b9789..63ccfae 100644 (file)
@@ -87,7 +87,7 @@ static int cache_entries;
 static int cache_is_dirty;
 
 
-/* An object to pass infomation to cmp_krec_fpr. */
+/* An object to pass information to cmp_krec_fpr. */
 struct cmp_krec_fpr_struct
 {
   int pubkey_algo;
@@ -95,7 +95,7 @@ struct cmp_krec_fpr_struct
   int fprlen;
 };
 
-/* An object used to pass infomation to cmp_[s]dir. */
+/* An object used to pass information to cmp_[s]dir. */
 struct cmp_xdir_struct
 {
   int pubkey_algo;
@@ -225,7 +225,7 @@ write_cache_item (CACHE_CTRL r)
  *
  * Returns: 0 on success or an error code.
  */
-int
+static int
 put_record_into_cache (ulong recno, const char *data)
 {
   CACHE_CTRL r, unused;
@@ -446,7 +446,7 @@ tdbio_sync()
 /*
  * Simple transactions system:
  * Everything between begin_transaction and end/cancel_transaction
- * is not immediatly written but at the time of end_transaction.
+ * is not immediately written but at the time of end_transaction.
  *
  * NOTE: The transaction code is disabled in the 1.2 branch, as it is
  * not yet used.
index f3155fd..a1988f0 100644 (file)
@@ -54,7 +54,7 @@ g10_exit( int rc )
 
 
 /* Stub:
- * We have to override the trustcheck from pkclist.c becuase
+ * We have to override the trustcheck from pkclist.c because
  * this utility assumes that all keys in the keyring are trustworthy
  */
 int
@@ -104,10 +104,13 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
 }
 
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid)
+get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
+             int may_ask)
 {
   (void)pk;
   (void)uid;
+  (void)sig;
+  (void)may_ask;
   return 0;
 }
 
@@ -195,8 +198,9 @@ keyserver_import_ldap (const char *name)
  * No encryption here but mainproc links to these functions.
  */
 gpg_error_t
-get_session_key (PKT_pubkey_enc *k, DEK *dek)
+get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek)
 {
+  (void)ctrl;
   (void)k;
   (void)dek;
   return GPG_ERR_GENERAL;
@@ -414,14 +418,44 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
 
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   (void)ctrl;
   (void)keyspec;
   (void)options;
+  (void)stats;
 
   *r_keyblock = NULL;
   *r_data = NULL;
   *r_datalen = 0;
   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 }
+
+gpg_error_t
+tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+                enum tofu_policy *policy)
+{
+  (void)pk;
+  (void)user_id;
+  (void)policy;
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+const char *
+tofu_policy_str (enum tofu_policy policy)
+{
+  (void)policy;
+
+  return "unknown";
+}
+
+void
+tofu_begin_batch_update (void)
+{
+}
+
+void
+tofu_end_batch_update (void)
+{
+}
diff --git a/g10/tofu.c b/g10/tofu.c
new file mode 100644 (file)
index 0000000..b7f61e9
--- /dev/null
@@ -0,0 +1,2912 @@
+/* tofu.c - TOFU trust model.
+ * Copyright (C) 2015 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/>.
+ */
+
+/* TODO:
+
+   - Format the fingerprints nicely when printing (similar to gpg
+     --list-keys)
+ */
+
+#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 "types.h"
+#include "logging.h"
+#include "stringhelp.h"
+#include "options.h"
+#include "mbox-util.h"
+#include "i18n.h"
+#include "trustdb.h"
+#include "mkdir_p.h"
+#include "sqlite.h"
+
+#include "tofu.h"
+
+#define DEBUG_TOFU_CACHE 0
+#if DEBUG_TOFU_CACHE
+static int prepares_saved;
+static int queries;
+#endif
+
+/* The TOFU data can be saved in two different formats: either in a
+   single combined database (opt.tofu_db_format == TOFU_DB_FLAT) or in
+   a split file format (opt.tofu_db_format == TOFU_DB_SPLIT).  In the
+   split format, there is one database per normalized email address
+   (DB_EMAIL) and one per key (DB_KEY).  */
+enum db_type
+  {
+    DB_COMBINED,
+    DB_EMAIL,
+    DB_KEY
+  };
+
+/* A list of open DBs.
+
+   In the flat format, this consists of a single element with the type
+   DB_COMBINED and whose name is the empty string.
+
+   In the split format, the first element is a dummy element (DB is
+   NULL) whose type is DB_COMBINED and whose name is the empty string.
+   Any following elements describe either DB_EMAIL or DB_KEY DBs.  In
+   theis case, NAME is either the normalized email address or the
+   fingerprint.
+
+   To initialize this data structure, call opendbs().  When you are
+   done, clean it up using closedbs().  To get a handle to a database,
+   use the getdb() function.  This will either return an existing
+   handle or open a new DB connection, as appropriate.  */
+struct db
+{
+  struct db *next;
+  struct db **prevp;
+
+  enum db_type type;
+
+  sqlite3 *db;
+
+  struct
+  {
+    sqlite3_stmt *savepoint_batch;
+    sqlite3_stmt *savepoint_batch_commit;
+
+    sqlite3_stmt *savepoint_inner;
+    sqlite3_stmt *savepoint_inner_commit;
+
+    sqlite3_stmt *record_binding_get_old_policy;
+    sqlite3_stmt *record_binding_update;
+    sqlite3_stmt *record_binding_update2;
+    sqlite3_stmt *get_policy_select_policy_and_conflict;
+    sqlite3_stmt *get_trust_bindings_with_this_email;
+    sqlite3_stmt *get_trust_gather_other_user_ids;
+    sqlite3_stmt *get_trust_gather_other_keys;
+    sqlite3_stmt *register_already_seen;
+    sqlite3_stmt *register_insert;
+  } s;
+
+#if DEBUG_TOFU_CACHE
+  int hits;
+#endif
+
+  int batch_update;
+
+  /* If TYPE is DB_COMBINED, this is "".  Otherwise, it is either the
+     fingerprint (type == DB_KEY) or the normalized email address
+     (type == DB_EMAIL).  */
+  char name[1];
+};
+
+static struct db *db_cache;
+static int db_cache_count;
+#define DB_CACHE_ENTRIES 16
+
+static void tofu_cache_dump (struct db *db) GPGRT_ATTR_USED;
+
+static void
+tofu_cache_dump (struct db *db)
+{
+  log_info ("Connection %p:\n", db);
+  for (; db; db = db->next)
+    log_info ("  %s: %sbatch mode\n", db->name, db->batch_update ? "" : "NOT ");
+  log_info ("Cache:\n");
+  for (db = db_cache; db; db = db->next)
+    log_info ("  %s: %sbatch mode\n", db->name, db->batch_update ? "" : "NOT ");
+}
+
+#define STRINGIFY(s) STRINGIFY2(s)
+#define STRINGIFY2(s) #s
+
+/* The grouping parameters when collecting signature statistics.  */
+
+/* If a message is signed a couple of hours in the future, just assume
+   some clock skew.  */
+#define TIME_AGO_FUTURE_IGNORE (2 * 60 * 60)
+#if 0
+#  define TIME_AGO_UNIT_SMALL 60
+#  define TIME_AGO_UNIT_SMALL_NAME _("minute")
+#  define TIME_AGO_UNIT_SMALL_NAME_PLURAL _("minutes")
+#  define TIME_AGO_MEDIUM_THRESHOLD (60 * TIME_AGO_UNIT_SMALL)
+#  define TIME_AGO_UNIT_MEDIUM (60 * 60)
+#  define TIME_AGO_UNIT_MEDIUM_NAME _("hour")
+#  define TIME_AGO_UNIT_MEDIUM_NAME_PLURAL _("hours")
+#  define TIME_AGO_LARGE_THRESHOLD (24 * 60 * TIME_AGO_UNIT_SMALL)
+#  define TIME_AGO_UNIT_LARGE (24 * 60 * 60)
+#  define TIME_AGO_UNIT_LARGE_NAME _("day")
+#  define TIME_AGO_UNIT_LARGE_NAME_PLURAL _("days")
+#else
+#  define TIME_AGO_UNIT_SMALL (24 * 60 * 60)
+#  define TIME_AGO_UNIT_SMALL_NAME _("day")
+#  define TIME_AGO_UNIT_SMALL_NAME_PLURAL _("days")
+#  define TIME_AGO_MEDIUM_THRESHOLD (4 * TIME_AGO_UNIT_SMALL)
+#  define TIME_AGO_UNIT_MEDIUM (7 * 24 * 60 * 60)
+#  define TIME_AGO_UNIT_MEDIUM_NAME _("week")
+#  define TIME_AGO_UNIT_MEDIUM_NAME_PLURAL _("weeks")
+#  define TIME_AGO_LARGE_THRESHOLD (28 * TIME_AGO_UNIT_SMALL)
+#  define TIME_AGO_UNIT_LARGE (30 * 24 * 60 * 60)
+#  define TIME_AGO_UNIT_LARGE_NAME _("month")
+#  define TIME_AGO_UNIT_LARGE_NAME_PLURAL _("months")
+#endif
+
+\f
+
+const char *
+tofu_policy_str (enum tofu_policy policy)
+{
+  switch (policy)
+    {
+    case TOFU_POLICY_NONE: return "none";
+    case TOFU_POLICY_AUTO: return "auto";
+    case TOFU_POLICY_GOOD: return "good";
+    case TOFU_POLICY_UNKNOWN: return "unknown";
+    case TOFU_POLICY_BAD: return "bad";
+    case TOFU_POLICY_ASK: return "ask";
+    default: return "???";
+    }
+}
+
+/* Convert a binding policy (e.g., TOFU_POLICY_BAD) to a trust level
+   (e.g., TRUST_BAD) in light of the current configuration.  */
+int
+tofu_policy_to_trust_level (enum tofu_policy policy)
+{
+  if (policy == TOFU_POLICY_AUTO)
+    /* If POLICY is AUTO, fallback to OPT.TOFU_DEFAULT_POLICY.  */
+    policy = opt.tofu_default_policy;
+
+  switch (policy)
+    {
+    case TOFU_POLICY_AUTO:
+      /* If POLICY and OPT.TOFU_DEFAULT_POLICY are both AUTO, default
+        to marginal trust.  */
+      return TRUST_MARGINAL;
+    case TOFU_POLICY_GOOD:
+      return TRUST_FULLY;
+    case TOFU_POLICY_UNKNOWN:
+      return TRUST_UNKNOWN;
+    case TOFU_POLICY_BAD:
+      return TRUST_NEVER;
+    case TOFU_POLICY_ASK:
+      return TRUST_UNKNOWN;
+    default:
+      log_bug ("Bad value for trust policy: %d\n",
+              opt.tofu_default_policy);
+      return 0;
+    }
+}
+\f
+static int batch_update;
+static time_t batch_update_started;
+
+static gpg_error_t end_transaction (struct db *db, int only_batch);
+
+/* Start a transaction on DB.  */
+static gpg_error_t
+begin_transaction (struct db *db, int only_batch)
+{
+  int rc;
+  char *err = NULL;
+
+  if (batch_update && batch_update_started != gnupg_get_time ())
+    /* We've been in batch update mode for a while (on average, more
+       than 500 ms).  To prevent starving other gpg processes, we drop
+       and retake the batch lock.
+
+       Note: if we wanted higher resolution, we could use
+       npth_clock_gettime.  */
+    {
+      struct db *t;
+
+      for (t = db_cache; t; t = t->next)
+        if (t->batch_update)
+          end_transaction (t, 1);
+      for (t = db; t; t = t->next)
+        if (t->batch_update)
+          end_transaction (t, 1);
+
+      batch_update_started = gnupg_get_time ();
+
+      /* Yield to allow another process a chance to run.  */
+      sched_yield ();
+    }
+
+  /* XXX: In split mode, this can end in deadlock.
+
+     Consider: we have two gpg processes running simultaneously and
+     they each want to lock DB A and B, but in different orders.  This
+     will be automatically resolved by causing one of them to return
+     EBUSY and aborting.
+
+     A more intelligent approach would be to commit and retake the
+     batch transaction.  This requires a list of all DBs that are
+     currently in batch mode.  */
+
+  if (batch_update && ! db->batch_update)
+    {
+      rc = sqlite3_stepx (db->db, &db->s.savepoint_batch,
+                          NULL, NULL, &err,
+                          "savepoint batch;", SQLITE_ARG_END);
+      if (rc)
+        {
+          log_error
+            (_("error beginning %s transaction on TOFU database '%s': %s\n"),
+             "batch", *db->name ? db->name : "combined", err);
+          sqlite3_free (err);
+          return gpg_error (GPG_ERR_GENERAL);
+        }
+
+      db->batch_update = 1;
+    }
+
+  if (only_batch)
+    return 0;
+
+  rc = sqlite3_stepx (db->db, &db->s.savepoint_inner,
+                      NULL, NULL, &err,
+                      "savepoint inner;", SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error
+        (_("error beginning %s transaction on TOFU database '%s': %s\n"),
+         "inner", *db->name ? db->name : "combined", err);
+      sqlite3_free (err);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  return 0;
+}
+
+/* Commit a transaction.  If ONLY_BATCH is 1, then this only ends the
+   batch transaction if we have left batch mode.  If ONLY_BATCH is 2,
+   this ends any open batch transaction even if we are still in batch
+   mode.  */
+static gpg_error_t
+end_transaction (struct db *db, int only_batch)
+{
+  int rc;
+  char *err = NULL;
+
+  if ((! batch_update || only_batch == 2) && db->batch_update)
+    /* The batch transaction is still in open, but we left batch
+       mode.  */
+    {
+      db->batch_update = 0;
+
+      rc = sqlite3_stepx (db->db, &db->s.savepoint_batch_commit,
+                          NULL, NULL, &err,
+                          "release batch;", SQLITE_ARG_END);
+      if (rc)
+        {
+          log_error
+            (_("error committing %s transaction on TOFU database '%s': %s\n"),
+             "batch", *db->name ? db->name : "combined", err);
+          sqlite3_free (err);
+          return gpg_error (GPG_ERR_GENERAL);
+        }
+
+      /* Releasing an outer transaction releases an open inner
+         transactions.  We're done.  */
+      return 0;
+    }
+
+  if (only_batch)
+    return 0;
+
+  rc = sqlite3_stepx (db->db, &db->s.savepoint_inner_commit,
+                      NULL, NULL, &err,
+                      "release inner;", SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error
+        (_("error committing %s transaction on TOFU database '%s': %s\n"),
+         "inner", *db->name ? db->name : "combined", err);
+      sqlite3_free (err);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  return 0;
+}
+
+static gpg_error_t
+rollback_transaction (struct db *db)
+{
+  int rc;
+  char *err = NULL;
+
+  if (db->batch_update)
+    /* Just undo the most recent update; don't revert any progress
+       made by the batch transaction.  */
+    rc = sqlite3_exec (db->db, "rollback to inner;", NULL, NULL, &err);
+  else
+    /* Rollback the whole she-bang.  */
+    rc = sqlite3_exec (db->db, "rollback;", NULL, NULL, &err);
+
+  if (rc)
+    {
+      log_error
+        (_("error rolling back inner transaction on TOFU database '%s': %s\n"),
+         *db->name ? db->name : "combined", err);
+      sqlite3_free (err);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  return 0;
+}
+
+void
+tofu_begin_batch_update (void)
+{
+  if (! batch_update)
+    batch_update_started = gnupg_get_time ();
+
+  batch_update ++;
+}
+
+void
+tofu_end_batch_update (void)
+{
+  assert (batch_update > 0);
+  batch_update --;
+
+  if (batch_update == 0)
+    {
+      struct db *db;
+
+      for (db = db_cache; db; db = db->next)
+        end_transaction (db, 1);
+    }
+}
+\f
+/* 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
+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);
+
+  errno = 0;
+  *count = strtoul (argv[0], &tail, 0);
+  if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
+    /* Abort.  */
+    return 1;
+  return 0;
+}
+
+static int
+get_single_unsigned_long_cb2 (void *cookie, int argc, char **argv,
+                            char **azColName, sqlite3_stmt *stmt)
+{
+  (void) stmt;
+  return get_single_unsigned_long_cb (cookie, argc, argv, azColName);
+}
+
+/* We expect a single integer column whose name is "version".  COOKIE
+   must point to an int.  This function always aborts.  On error or a
+   if the version is bad, sets *VERSION to -1.  */
+static int
+version_check_cb (void *cookie, int argc, char **argv, char **azColName)
+{
+  int *version = cookie;
+
+  if (argc != 1 || strcmp (azColName[0], "version") != 0)
+    {
+      *version = -1;
+      return 1;
+    }
+
+  if (strcmp (argv[0], "1") == 0)
+    *version = 1;
+  else
+    {
+      log_error (_("unsupported TOFU DB version: %s\n"), argv[0]);
+      *version = -1;
+    }
+
+  /* Don't run again.  */
+  return 1;
+}
+
+
+/* If the DB is new, initialize it.  Otherwise, check the DB's
+   version.
+
+   Return 0 if the database is okay and 1 otherwise.  */
+static int
+initdb (sqlite3 *db, enum db_type type)
+{
+  char *err = NULL;
+  int rc;
+  unsigned long int count;
+  int version = -1;
+
+  rc = sqlite3_exec (db, "begin transaction;", NULL, NULL, &err);
+  if (rc)
+    {
+      log_error (_("error beginning transaction on TOFU database: %s\n"),
+                err);
+      sqlite3_free (err);
+      return 1;
+    }
+
+  /* If the DB has no tables, then assume this is a new DB that needs
+     to be initialized.  */
+  rc = sqlite3_exec (db,
+                    "select count(*) from sqlite_master where type='table';",
+                    get_single_unsigned_long_cb, &count, &err);
+  if (rc)
+    {
+      log_error (_("error querying TOFU DB's available tables: %s\n"),
+                err);
+      sqlite3_free (err);
+      goto out;
+    }
+  else if (count != 0)
+    /* Assume that the DB is already initialized.  Make sure the
+       version is okay.  */
+    {
+      rc = sqlite3_exec (db, "select version from version;", version_check_cb,
+                        &version, &err);
+      if (rc == SQLITE_ABORT && version == 1)
+       /* Happy, happy, joy, joy.  */
+       {
+         sqlite3_free (err);
+          rc = 0;
+          goto out;
+       }
+      else if (rc == SQLITE_ABORT && version == -1)
+       /* Unsupported version.  */
+       {
+         /* An error message was already displayed.  */
+         sqlite3_free (err);
+          goto out;
+       }
+      else if (rc)
+       /* Some error.  */
+       {
+         log_error (_("error determining TOFU DB's version: %s\n"), err);
+         sqlite3_free (err);
+          goto out;
+       }
+      else
+       /* Unexpected success.  This can only happen if there are no
+          rows.  */
+       {
+         log_error (_("error determining TOFU DB's version: %s\n"),
+                    "select returned 0, but expected ABORT");
+          rc = 1;
+          goto out;
+       }
+    }
+
+  /* Create the version table.  */
+  rc = sqlite3_exec (db,
+                    "create table version (version INTEGER);",
+                    NULL, NULL, &err);
+  if (rc)
+    {
+      log_error (_("error initializing TOFU database (%s): %s\n"),
+                "version", err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  /* Initialize the version table, which contains a single integer
+     value.  */
+  rc = sqlite3_exec (db,
+                    "insert into version values (1);",
+                    NULL, NULL, &err);
+  if (rc)
+    {
+      log_error (_("error initializing TOFU database (%s): %s\n"),
+                "version, init", err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  /* The list of <fingerprint, email> bindings and auxiliary data.
+
+       OID is a unique ID identifying this binding (and used by the
+         signatures table, see below).  Note: OIDs will never be
+         reused.
+
+       FINGERPRINT: The key's fingerprint.
+
+       EMAIL: The normalized email address.
+
+       USER_ID: The unmodified user id from which EMAIL was extracted.
+
+       TIME: The time this binding was first observed.
+
+       POLICY: The trust policy (TOFU_POLICY_BAD, etc. as an integer).
+
+       CONFLICT is either NULL or a fingerprint.  Assume that we have
+         a binding <0xdeadbeef, foo@example.com> and then we observe
+         <0xbaddecaf, foo@example.com>.  There two bindings conflict
+         (they have the same email address).  When we observe the
+         latter binding, we warn the user about the conflict and ask
+         for a policy decision about the new binding.  We also change
+         the old binding's policy to ask if it was auto.  So that we
+         know why this occurred, we also set conflict to 0xbaddecaf.
+  */
+  if (type == DB_EMAIL || type == DB_COMBINED)
+    rc = sqlite3_exec_printf
+      (db, NULL, NULL, &err,
+       "create table bindings\n"
+       " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+       "  fingerprint TEXT, email TEXT, user_id TEXT, time INTEGER,\n"
+       "  policy BOOLEAN CHECK (policy in (%d, %d, %d, %d, %d)),\n"
+       "  conflict STRING,\n"
+       "  unique (fingerprint, email));\n"
+       "create index bindings_fingerprint_email\n"
+       " on bindings (fingerprint, email);\n"
+       "create index bindings_email on bindings (email);\n",
+       TOFU_POLICY_AUTO, TOFU_POLICY_GOOD, TOFU_POLICY_UNKNOWN,
+       TOFU_POLICY_BAD, TOFU_POLICY_ASK);
+  else
+    /* In the split DB case, the fingerprint DB only contains a subset
+       of the fields.  This reduces the amount of duplicated data.
+
+       Note: since the data is split on the email address, there is no
+       need to index the email column.  */
+    rc = sqlite3_exec_printf
+      (db, NULL, NULL, &err,
+       "create table bindings\n"
+       " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
+       "  fingerprint TEXT, email TEXT, user_id,\n"
+       "  unique (fingerprint, email));\n"
+       "create index bindings_fingerprint\n"
+       " on bindings (fingerprint);\n");
+  if (rc)
+    {
+      log_error (_("error initializing TOFU database (%s): %s\n"),
+                "bindings", err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  if (type != DB_KEY)
+    {
+      /* The signatures that we have observed.
+
+        BINDING refers to a record in the bindings table, which
+         describes the binding (i.e., this is a foreign key that
+         references bindings.oid).
+
+        SIG_DIGEST is the digest stored in the signature.
+
+        SIG_TIME is the timestamp stored in the signature.
+
+        ORIGIN is a free-form string that describes who fed this
+         signature to GnuPG (e.g., email:claws).
+
+        TIME is the time this signature was registered.  */
+      rc = sqlite3_exec (db,
+                        "create table signatures "
+                        " (binding INTEGER NOT NULL, sig_digest TEXT,"
+                        "  origin TEXT, sig_time INTEGER, time INTEGER,"
+                        "  primary key (binding, sig_digest, origin));",
+                        NULL, NULL, &err);
+      if (rc)
+       {
+         log_error (_("error initializing TOFU database (%s): %s\n"),
+                    "signatures", err);
+         sqlite3_free (err);
+         goto out;
+       }
+    }
+
+ out:
+  if (rc)
+    {
+      rc = sqlite3_exec (db, "rollback;", NULL, NULL, &err);
+      if (rc)
+       {
+         log_error (_("error aborting transaction on TOFU DB: %s\n"),
+                    err);
+         sqlite3_free (err);
+       }
+      return 1;
+    }
+  else
+    {
+      rc = sqlite3_exec (db, "end transaction;", NULL, NULL, &err);
+      if (rc)
+       {
+         log_error (_("error committing transaction on TOFU DB: %s\n"),
+                    err);
+         sqlite3_free (err);
+         return 1;
+       }
+      return 0;
+    }
+}
+
+/* Open and initialize a low-level TOFU database.  Returns NULL on
+   failure.  This function should not normally be directly called to
+   get a database handle.  Instead, use getdb().  */
+static sqlite3 *
+opendb (char *filename, enum db_type type)
+{
+  sqlite3 *db;
+  int filename_free = 0;
+  int rc;
+
+  if (opt.tofu_db_format == TOFU_DB_FLAT)
+    {
+      assert (! filename);
+      assert (type == DB_COMBINED);
+
+      filename = make_filename (opt.homedir, "tofu.db", NULL);
+      filename_free = 1;
+    }
+  else
+    assert (type == DB_EMAIL || type == DB_KEY);
+
+  assert (filename);
+
+  rc = sqlite3_open (filename, &db);
+  if (rc)
+    {
+      log_error (_("can't open TOFU DB ('%s'): %s\n"),
+                filename, sqlite3_errmsg (db));
+      /* Even if an error occurs, DB is guaranteed to be valid.  */
+      sqlite3_close (db);
+      db = NULL;
+    }
+
+  /* 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 (filename_free)
+    xfree (filename);
+
+  if (db && initdb (db, type))
+    {
+      sqlite3_close (db);
+      db = NULL;
+    }
+
+  return db;
+}
+
+struct dbs
+{
+  struct db *db;
+};
+
+static void
+unlink_db (struct db *db)
+{
+  *db->prevp = db->next;
+  if (db->next)
+    db->next->prevp = db->prevp;
+}
+
+static void
+link_db (struct db **head, struct db *db)
+{
+  db->next = *head;
+  if (db->next)
+    db->next->prevp = &db->next;
+  db->prevp = head;
+  *head = db;
+}
+
+/* Return a database handle.  <type, name> describes the required
+   database.  If there is a cached handle in DBS, that handle is
+   returned.  Otherwise, the database is opened and cached in DBS.
+
+   NAME is the name of the DB and may not be NULL.
+
+   TYPE must be either DB_MAIL or DB_KEY.  In the combined format, the
+   combined DB is always returned.  */
+static struct db *
+getdb (struct dbs *dbs, const char *name, enum db_type type)
+{
+  struct db *t = NULL;
+  char *name_sanitized = NULL;
+  int count;
+  char *filename = NULL;
+  int need_link = 1;
+  sqlite3 *sqlitedb = NULL;
+
+  assert (dbs);
+  assert (name);
+  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
+       combined DB.  */
+    {
+      if (dbs->db)
+        {
+          assert (dbs->db->type == DB_COMBINED);
+          assert (! dbs->db->next);
+          return dbs->db;
+        }
+
+      type = DB_COMBINED;
+    }
+
+  if (type != DB_COMBINED)
+    /* Only allow alpha-numeric characters in the name.  */
+    {
+      int i;
+
+      name_sanitized = xstrdup (name);
+      for (i = 0; name[i]; i ++)
+        {
+          char c = name_sanitized[i];
+          if (! (('a' <= c && c <= 'z')
+                 || ('A' <= c && c <= 'Z')
+                 || ('0' <= c && c <= '9')))
+            name_sanitized[i] = '_';
+        }
+    }
+
+  /* See if the DB is cached.  */
+  for (t = dbs->db; t; t = t->next)
+    if (t->type == type
+        && (type == DB_COMBINED || strcmp (t->name, name_sanitized) == 0))
+      {
+        need_link = 0;
+        goto out;
+      }
+
+  for (t = db_cache, count = 0; t; t = t->next, count ++)
+    if (type == t->type
+        && (type == DB_COMBINED || strcmp (t->name, name_sanitized) == 0))
+      {
+        unlink_db (t);
+        db_cache_count --;
+        goto out;
+      }
+
+  assert (db_cache_count == count);
+
+  if (type == DB_COMBINED)
+    filename = NULL;
+  else
+    {
+      /* Open the DB.  The filename has the form:
+
+         tofu.d/TYPE/PREFIX/NAME.db
+
+         We use a short prefix to try to avoid having many files in a
+         single directory.  */
+      {
+        char *type_str = type == DB_EMAIL ? "email" : "key";
+        char prefix[3] = { name_sanitized[0], name_sanitized[1], 0 };
+        char *name_db;
+
+        /* Make the directory.  */
+        if (gnupg_mkdir_p (opt.homedir, "tofu.d", type_str, prefix, NULL) != 0)
+          {
+            log_error (_("unable to create directory %s/%s/%s/%s"),
+                       opt.homedir, "tofu.d", type_str, prefix);
+            goto out;
+          }
+
+        name_db = xstrconcat (name_sanitized, ".db", NULL);
+        filename = make_filename
+          (opt.homedir, "tofu.d", type_str, prefix, name_db, NULL);
+        xfree (name_db);
+      }
+    }
+
+  sqlitedb = opendb (filename, type);
+  if (! sqlitedb)
+    goto out;
+
+  t = xmalloc_clear (sizeof (struct db)
+                     + (name_sanitized ? strlen (name_sanitized) : 0));
+  t->type = type;
+  t->db = sqlitedb;
+  if (name_sanitized)
+    strcpy (t->name, name_sanitized);
+
+ out:
+  if (t && need_link)
+    link_db (&dbs->db, t);
+
+#if DEBUG_TOFU_CACHE
+  if (t)
+    t->hits ++;
+#endif
+
+  xfree (filename);
+  xfree (name_sanitized);
+  return t;
+}
+
+static void
+closedb (struct db *db)
+{
+  sqlite3_stmt **statements;
+
+  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);
+
+  if (db->type == DB_COMBINED)
+    {
+      assert (opt.tofu_db_format == TOFU_DB_FLAT);
+      assert (! db->name[0]);
+    }
+  else
+    {
+      assert (opt.tofu_db_format == TOFU_DB_SPLIT);
+      assert (db->type != DB_COMBINED);
+      assert (db->name[0]);
+    }
+
+  if (db->batch_update)
+    end_transaction (db, 2);
+
+  for (statements = (void *) &db->s;
+       (void *) statements < (void *) &(&db->s)[1];
+       statements ++)
+    sqlite3_finalize (*statements);
+
+  sqlite3_close (db->db);
+
+#if DEBUG_TOFU_CACHE
+  log_debug ("Freeing db.  Used %d times.\n", db->hits);
+#endif
+
+  xfree (db);
+}
+
+
+/* Create a new DB meta-handle.  Returns NULL on error.  */
+static struct dbs *
+opendbs (void)
+{
+  if (opt.tofu_db_format == TOFU_DB_AUTO)
+    {
+      char *filename = make_filename (opt.homedir, "tofu.db", NULL);
+      struct stat s;
+      int have_tofu_db = 0;
+      int have_tofu_d = 0;
+
+      if (stat (filename, &s) == 0)
+       {
+         have_tofu_db = 1;
+         if (DBG_TRUST)
+           log_debug ("%s exists.\n", filename);
+       }
+      else
+       {
+         if (DBG_TRUST)
+           log_debug ("%s does not exist.\n", filename);
+       }
+
+      /* We now have tofu.d.  */
+      filename[strlen (filename) - 1] = '\0';
+      if (stat (filename, &s) == 0)
+       {
+         have_tofu_d = 1;
+         if (DBG_TRUST)
+           log_debug ("%s exists.\n", filename);
+       }
+      else
+       {
+         if (DBG_TRUST)
+           log_debug ("%s does not exist.\n", filename);
+       }
+
+      xfree (filename);
+
+      if (have_tofu_db && have_tofu_d)
+       {
+         log_info (_("Warning: Home directory contains both tofu.db"
+                      " and tofu.d.  Using split format for TOFU DB.\n"));
+         opt.tofu_db_format = TOFU_DB_SPLIT;
+       }
+      else if (have_tofu_db)
+       {
+         opt.tofu_db_format = TOFU_DB_FLAT;
+         if (DBG_TRUST)
+           log_debug ("Using flat format for TOFU DB.\n");
+       }
+      else if (have_tofu_d)
+       {
+         opt.tofu_db_format = TOFU_DB_SPLIT;
+         if (DBG_TRUST)
+           log_debug ("Using split format for TOFU DB.\n");
+       }
+      else
+       {
+         opt.tofu_db_format = TOFU_DB_FLAT;
+         if (DBG_TRUST)
+           log_debug ("Using flat format for TOFU DB.\n");
+       }
+    }
+
+  return xmalloc_clear (sizeof (struct dbs));
+}
+
+/* Release all of the resources associated with a DB meta-handle.  */
+static void
+closedbs (struct dbs *dbs)
+{
+  if (dbs->db)
+    {
+      struct db *old_head = db_cache;
+      struct db *db;
+      int count;
+
+      /* Find the last DB.  */
+      for (db = dbs->db, count = 1; db->next; db = db->next, count ++)
+        {
+          /* When we leave batch mode we leave batch mode on any
+             cached connections.  */
+          if (! batch_update)
+            assert (! db->batch_update);
+        }
+      if (! batch_update)
+        assert (! db->batch_update);
+
+      /* Join the two lists.  */
+      db->next = db_cache;
+      if (db_cache)
+        db_cache->prevp = &db->next;
+
+      /* Update the (new) first element.  */
+      db_cache = dbs->db;
+      dbs->db->prevp = &db_cache;
+
+      db_cache_count += count;
+
+      /* Make sure that we don't have too many DBs on DB_CACHE.  If
+         so, free some.  */
+      if (db_cache_count > DB_CACHE_ENTRIES)
+        {
+          /* We need to find the (DB_CACHE_ENTRIES + 1)th entry.  It
+             is easy to skip the first COUNT entries since we still
+             have a handle on the old head.  */
+          int skip = DB_CACHE_ENTRIES - count;
+          while (-- skip > 0)
+            old_head = old_head->next;
+
+          *old_head->prevp = NULL;
+
+          while (old_head)
+            {
+              db = old_head->next;
+              closedb (old_head);
+              old_head = db;
+              db_cache_count --;
+            }
+        }
+    }
+
+  xfree (dbs);
+
+#if DEBUG_TOFU_CACHE
+  log_debug ("Queries: %d (prepares saved: %d)\n",
+             queries, prepares_saved);
+#endif
+}
+
+
+/* Collect results of a select min (foo) ...; style query.  Aborts if
+   the argument is not a valid integer (or real of the form X.0).  */
+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);
+
+  errno = 0;
+  *count = strtol (argv[0], &tail, 0);
+  if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
+    /* Abort.  */
+    return 1;
+  return 0;
+}
+
+static int
+get_single_long_cb2 (void *cookie, int argc, char **argv, char **azColName,
+                     sqlite3_stmt *stmt)
+{
+  (void) stmt;
+  return get_single_long_cb (cookie, argc, argv, azColName);
+}
+
+/* Record (or update) a trust policy about a (possibly new)
+   binding.
+
+   If SHOW_OLD is set, the binding's old policy is displayed.  */
+static gpg_error_t
+record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
+               const char *user_id, enum tofu_policy policy, int show_old)
+{
+  char *fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
+  struct db *db_email = NULL, *db_key = NULL;
+  int rc;
+  char *err = NULL;
+  /* policy_old needs to be a long and not an enum tofu_policy,
+     because we pass it by reference to get_single_long_cb2, which
+     expects a long.  */
+  long policy_old = TOFU_POLICY_NONE;
+
+  if (! (policy == TOFU_POLICY_AUTO
+        || policy == TOFU_POLICY_GOOD
+        || policy == TOFU_POLICY_UNKNOWN
+        || policy == TOFU_POLICY_BAD
+        || policy == TOFU_POLICY_ASK))
+    log_bug ("%s: Bad value for policy (%d)!\n", __func__, policy);
+
+  db_email = getdb (dbs, email, DB_EMAIL);
+  if (! db_email)
+    return gpg_error (GPG_ERR_GENERAL);
+
+  if (opt.tofu_db_format == TOFU_DB_SPLIT)
+    /* In the split format, we need to update two DBs.  To keep them
+       consistent, we start a transaction on each.  Note: this is the
+       only place where we start two transaction and we always start
+       transaction on the DB_KEY DB first, thus deadlock is not
+       possible.  */
+    {
+      db_key = getdb (dbs, fingerprint, DB_KEY);
+      if (! db_key)
+       return gpg_error (GPG_ERR_GENERAL);
+
+      rc = begin_transaction (db_email, 0);
+      if (rc)
+        return gpg_error (GPG_ERR_GENERAL);
+
+      rc = begin_transaction (db_key, 0);
+      if (rc)
+        goto out_revert_one;
+    }
+  else
+    {
+      rc = begin_transaction (db_email, 1);
+      if (rc)
+        return gpg_error (GPG_ERR_GENERAL);
+    }
+
+
+  if (show_old)
+    /* Get the old policy.  Since this is just for informational
+       purposes, there is no need to start a transaction or to die if
+       there is a failure.  */
+    {
+      rc = sqlite3_stepx
+       (db_email->db, &db_email->s.record_binding_get_old_policy,
+         get_single_long_cb2, &policy_old, &err,
+        "select policy from bindings where fingerprint = ? and email = ?",
+        SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+         SQLITE_ARG_END);
+      if (rc)
+       {
+         log_debug ("TOFU: Error reading from binding database"
+                    " (reading policy for <%s, %s>): %s\n",
+                    fingerprint_pp, email, err);
+         sqlite3_free (err);
+       }
+    }
+
+  if (DBG_TRUST)
+    {
+      if (policy_old != TOFU_POLICY_NONE)
+       log_debug ("Changing TOFU trust policy for binding <%s, %s>"
+                  " from %s to %s.\n",
+                  fingerprint_pp, 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,
+                  tofu_policy_str (policy));
+    }
+
+  if (policy_old == policy)
+    /* Nothing to do.  */
+    goto out;
+
+  rc = sqlite3_stepx
+    (db_email->db, &db_email->s.record_binding_update, NULL, NULL, &err,
+     "insert or replace into bindings\n"
+     " (oid, fingerprint, email, user_id, time, policy)\n"
+     " values (\n"
+     /* If we don't explicitly reuse the OID, then SQLite will
+       reallocate a new one.  We just need to search for the OID
+       based on the fingerprint and email since they are unique.  */
+     "  (select oid from bindings where fingerprint = ? and email = ?),\n"
+     "  ?, ?, ?, strftime('%s','now'), ?);",
+     SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+     SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+     SQLITE_ARG_STRING, user_id, SQLITE_ARG_INT, (int) policy,
+     SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("error updating TOFU binding database"
+                  " (inserting <%s, %s> = %s): %s\n"),
+                fingerprint_pp, email, tofu_policy_str (policy),
+                err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  if (db_key)
+    /* We also need to update the key DB.  */
+    {
+      assert (opt.tofu_db_format == TOFU_DB_SPLIT);
+
+      rc = sqlite3_stepx
+       (db_key->db, &db_key->s.record_binding_update2, NULL, NULL, &err,
+        "insert or replace into bindings\n"
+        " (oid, fingerprint, email, user_id)\n"
+        " values (\n"
+        /* If we don't explicitly reuse the OID, then SQLite will
+           reallocate a new one.  We just need to search for the OID
+           based on the fingerprint and email since they are unique.  */
+        "  (select oid from bindings where fingerprint = ? and email = ?),\n"
+        "  ?, ?, ?);",
+        SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+         SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+         SQLITE_ARG_STRING, user_id, SQLITE_ARG_END);
+      if (rc)
+       {
+         log_error (_("error updating TOFU binding database"
+                      " (inserting <%s, %s>): %s\n"),
+                    fingerprint_pp, email, err);
+         sqlite3_free (err);
+         goto out;
+       }
+    }
+  else
+    assert (opt.tofu_db_format == TOFU_DB_FLAT);
+
+ out:
+  if (opt.tofu_db_format == TOFU_DB_SPLIT)
+    /* We only need a transaction for the split format.  */
+    {
+      int rc2;
+
+      if (rc)
+        rc2 = rollback_transaction (db_key);
+      else
+        rc2 = end_transaction (db_key, 0);
+      if (rc2)
+       {
+         log_error (_("error ending transaction on TOFU database: %s\n"),
+                    err);
+         sqlite3_free (err);
+       }
+
+    out_revert_one:
+      if (rc)
+        rc2 = rollback_transaction (db_email);
+      else
+        rc2 = end_transaction (db_email, 0);
+      if (rc2)
+       {
+         log_error (_("error ending transaction on TOFU database: %s\n"),
+                    err);
+         sqlite3_free (err);
+       }
+    }
+
+  xfree (fingerprint_pp);
+
+  if (rc)
+    return gpg_error (GPG_ERR_GENERAL);
+  return 0;
+}
+
+
+/* Collect the strings returned by a query in a simply string list.
+   Any NULL values are converted to the empty string.
+
+   If a result has 3 rows and each row contains two columns, then the
+   results are added to the list as follows (the value is parentheses
+   is the 1-based index in the final list):
+
+     row 1, col 2 (6)
+     row 1, col 1 (5)
+     row 2, col 2 (4)
+     row 2, col 1 (3)
+     row 3, col 2 (2)
+     row 3, col 1 (1)
+
+   This is because add_to_strlist pushes the results onto the front of
+   the list.  The end result is that the rows are backwards, but the
+   columns are in the expected order.  */
+static int
+strings_collect_cb (void *cookie, int argc, char **argv, char **azColName)
+{
+  int i;
+  strlist_t *strlist = cookie;
+
+  (void) azColName;
+
+  for (i = argc - 1; i >= 0; i --)
+    add_to_strlist (strlist, argv[i] ? argv[i] : "");
+
+  return 0;
+}
+
+static int
+strings_collect_cb2 (void *cookie, int argc, char **argv, char **azColName,
+                     sqlite3_stmt *stmt)
+{
+  (void) stmt;
+  return strings_collect_cb (cookie, argc, argv, azColName);
+
+}
+
+/* Auxiliary data structure to collect statistics about
+   signatures.  */
+struct signature_stats
+{
+  struct signature_stats *next;
+
+  /* The user-assigned policy for this binding.  */
+  enum tofu_policy policy;
+
+  /* How long ago the signature was created (rounded to a multiple of
+     TIME_AGO_UNIT_SMALL, etc.).  */
+  long time_ago;
+  /* Number of signatures during this time.  */
+  unsigned long count;
+
+  /* The key that generated this signature.  */
+  char fingerprint[1];
+};
+
+static void
+signature_stats_free (struct signature_stats *stats)
+{
+  while (stats)
+    {
+      struct signature_stats *next = stats->next;
+      xfree (stats);
+      stats = next;
+    }
+}
+
+static void
+signature_stats_prepend (struct signature_stats **statsp,
+                        const char *fingerprint,
+                        enum tofu_policy policy,
+                        long time_ago,
+                        unsigned long count)
+{
+  struct signature_stats *stats =
+    xmalloc (sizeof (*stats) + strlen (fingerprint));
+
+  stats->next = *statsp;
+  *statsp = stats;
+
+  strcpy (stats->fingerprint, fingerprint);
+  stats->policy = policy;
+  stats->time_ago = time_ago;
+  stats->count = count;
+}
+
+
+/* Process rows that contain the four columns:
+
+     <fingerprint, policy, time ago, count>.  */
+static int
+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;
+
+  (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;
+    }
+  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;
+        }
+    }
+  i ++;
+
+  /* If time_ago is NULL, then we had no messages, but we still have a
+     single row, which count(*) turns into 1.  */
+  if (! argv[i - 1])
+    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;
+        }
+    }
+  i ++;
+
+  assert (argc == i);
+
+  signature_stats_prepend (statsp, argv[0], policy, time_ago, count);
+
+  return 0;
+}
+
+/* Convert from seconds to time units.
+
+   Note: T should already be a multiple of TIME_AGO_UNIT_SMALL or
+   TIME_AGO_UNIT_MEDIUM or TIME_AGO_UNIT_LARGE.  */
+signed long
+time_ago_scale (signed long t)
+{
+  if (t < TIME_AGO_UNIT_MEDIUM)
+    return t / TIME_AGO_UNIT_SMALL;
+  if (t < TIME_AGO_UNIT_LARGE)
+    return t / TIME_AGO_UNIT_MEDIUM;
+  return t / TIME_AGO_UNIT_LARGE;
+}
+
+/* Return the appropriate unit (respecting whether it is plural or
+   singular).  */
+const char *
+time_ago_unit (signed long t)
+{
+  signed long t_scaled = time_ago_scale (t);
+
+  if (t < TIME_AGO_UNIT_MEDIUM)
+    {
+      if (t_scaled == 1)
+       return TIME_AGO_UNIT_SMALL_NAME;
+      return TIME_AGO_UNIT_SMALL_NAME_PLURAL;
+    }
+  if (t < TIME_AGO_UNIT_LARGE)
+    {
+      if (t_scaled == 1)
+       return TIME_AGO_UNIT_MEDIUM_NAME;
+      return TIME_AGO_UNIT_MEDIUM_NAME_PLURAL;
+    }
+  if (t_scaled == 1)
+    return TIME_AGO_UNIT_LARGE_NAME;
+  return TIME_AGO_UNIT_LARGE_NAME_PLURAL;
+}
+
+
+/* Return the policy for the binding <FINGERPRINT, EMAIL> (email has
+   already been normalized) and any conflict information in *CONFLICT
+   if CONFLICT is not NULL.  Returns _tofu_GET_POLICY_ERROR if an error
+   occurs.  */
+static enum tofu_policy
+get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
+           char **conflict)
+{
+  struct db *db;
+  int rc;
+  char *err = NULL;
+  strlist_t strlist = NULL;
+  char *tail = NULL;
+  enum tofu_policy policy = _tofu_GET_POLICY_ERROR;
+
+  db = getdb (dbs, email, DB_EMAIL);
+  if (! db)
+    return _tofu_GET_POLICY_ERROR;
+
+  /* Check if the <FINGERPRINT, EMAIL> binding is known
+     (TOFU_POLICY_NONE cannot appear in the DB.  Thus, if POLICY is
+     still TOFU_POLICY_NONE after executing the query, then the
+     result set was empty.)  */
+  rc = sqlite3_stepx (db->db, &db->s.get_policy_select_policy_and_conflict,
+                      strings_collect_cb2, &strlist, &err,
+                      "select policy, conflict from bindings\n"
+                      " where fingerprint = ? and email = ?",
+                      SQLITE_ARG_STRING, fingerprint,
+                      SQLITE_ARG_STRING, email,
+                      SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("error reading from TOFU database"
+                  " (checking for existing bad bindings): %s\n"),
+                err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  if (strlist_length (strlist) == 0)
+    /* No results.  */
+    {
+      policy = TOFU_POLICY_NONE;
+      goto out;
+    }
+  else if (strlist_length (strlist) != 2)
+    /* The result has the wrong form.  */
+    {
+      log_error (_("error reading from TOFU database"
+                  " (checking for existing bad bindings):"
+                  " expected 2 results, got %d\n"),
+                strlist_length (strlist));
+      goto out;
+    }
+
+  /* The result has the right form.  */
+
+  errno = 0;
+  policy = strtol (strlist->d, &tail, 0);
+  if (errno || *tail != '\0')
+    {
+      log_error (_("error reading from TOFU database: bad value for policy: %s\n"),
+                strlist->d);
+      goto out;
+    }
+
+  if (! (policy == TOFU_POLICY_AUTO
+        || policy == TOFU_POLICY_GOOD
+        || policy == TOFU_POLICY_UNKNOWN
+        || policy == TOFU_POLICY_BAD
+        || policy == TOFU_POLICY_ASK))
+    {
+      log_error (_("TOFU DB is corrupted.  Invalid value for policy (%d).\n"),
+                policy);
+      policy = _tofu_GET_POLICY_ERROR;
+      goto out;
+    }
+
+
+  /* If CONFLICT is set, then policy should be TOFU_POLICY_ASK.  But,
+     just in case, we do the check again here and ignore the conflict
+     is POLICY is not TOFU_POLICY_ASK.  */
+  if (conflict)
+    {
+      if (policy == TOFU_POLICY_ASK && *strlist->next->d)
+       *conflict = xstrdup (strlist->next->d);
+      else
+       *conflict = NULL;
+    }
+
+ 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);
+
+  free_strlist (strlist);
+
+  return policy;
+}
+
+/* Return the trust level (TRUST_NEVER, etc.) for the binding
+   <FINGERPRINT, EMAIL> (email is already normalized).  If no policy
+   is registered, returns TOFU_POLICY_NONE.  If an error occurs,
+   returns _tofu_GET_TRUST_ERROR.
+
+   USER_ID is the unadultered user id.
+
+   If MAY_ASK is set, then we may interact with the user.  This is
+   necessary if there is a conflict or the binding's policy is
+   TOFU_POLICY_ASK.  In the case of a conflict, we set the new
+   conflicting binding's policy to TOFU_POLICY_ASK.  In either case,
+   we return TRUST_UNDEFINED.  */
+static enum tofu_policy
+get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
+          const char *user_id, int may_ask)
+{
+  char *fingerprint_pp;
+  struct db *db;
+  enum tofu_policy policy;
+  char *conflict = NULL;
+  int rc;
+  char *err = NULL;
+  strlist_t bindings_with_this_email = NULL;
+  int bindings_with_this_email_count;
+  int change_conflicting_to_ask = 0;
+  int trust_level = TRUST_UNKNOWN;
+
+  if (opt.batch)
+    may_ask = 0;
+
+  /* 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);
+
+  db = getdb (dbs, email, DB_EMAIL);
+  if (! db)
+    return _tofu_GET_TRUST_ERROR;
+
+  fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
+
+  policy = get_policy (dbs, fingerprint, email, &conflict);
+  if (policy == TOFU_POLICY_AUTO || policy == TOFU_POLICY_NONE)
+    /* See if the key is ultimately trusted.  If so, we're done.  */
+    {
+      PKT_public_key *pk;
+      u32 kid[2];
+      char fpr_bin[MAX_FINGERPRINT_LEN+1];
+      size_t fpr_bin_len;
+
+      if (!hex2str (fingerprint, fpr_bin, sizeof fpr_bin, &fpr_bin_len))
+        {
+          log_error ("error converting fingerprint: %s\n",
+                     gpg_strerror (gpg_error_from_syserror ()));
+          return _tofu_GET_TRUST_ERROR;
+        }
+
+      /* We need to lookup the key by fingerprint again so that we can
+         properly extract the keyid.  Extracting direct from the
+         fingerprint works only for v4 keys and would assume that
+         there is no collision in the low 64 bit.  We can't guarantee
+         the latter in case the Tofu DB is used with a different
+         keyring.  In any case the UTK stuff needs to be changed to
+         use only fingerprints.  */
+      pk = xtrycalloc (1, sizeof *pk);
+      if (!pk)
+         {
+           log_error (_("out of core\n"));
+           return _tofu_GET_TRUST_ERROR;
+         }
+      rc = get_pubkey_byfprint_fast (pk, fpr_bin, fpr_bin_len);
+      if (rc)
+        {
+          log_error (_("public key %s not found: %s\n"),
+                     fingerprint, gpg_strerror (rc));
+          return _tofu_GET_TRUST_ERROR;
+        }
+      keyid_from_pk (pk, kid);
+      free_public_key (pk);
+
+      if (tdb_keyid_is_utk (kid))
+        {
+          if (policy == TOFU_POLICY_NONE)
+            {
+              if (record_binding (dbs, fingerprint, email, user_id,
+                                  TOFU_POLICY_AUTO, 0) != 0)
+                {
+                  log_error (_("error setting TOFU binding's trust level"
+                               " to %s\n"), "auto");
+                  trust_level = _tofu_GET_TRUST_ERROR;
+                  goto out;
+                }
+            }
+
+          trust_level = TRUST_ULTIMATE;
+          goto out;
+        }
+    }
+
+  if (policy == TOFU_POLICY_AUTO)
+    {
+      policy = opt.tofu_default_policy;
+      if (DBG_TRUST)
+       log_debug ("TOFU: binding <%s, %s>'s policy is auto (default: %s).\n",
+                  fingerprint_pp, email,
+                  tofu_policy_str (opt.tofu_default_policy));
+    }
+  switch (policy)
+    {
+    case TOFU_POLICY_AUTO:
+    case TOFU_POLICY_GOOD:
+    case TOFU_POLICY_UNKNOWN:
+    case TOFU_POLICY_BAD:
+      /* The saved judgement is auto -> auto, good, unknown or bad.
+        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));
+      trust_level = tofu_policy_to_trust_level (policy);
+      goto out;
+
+    case TOFU_POLICY_ASK:
+      /* We need to ask the user what to do.  Case #1 or #2 below.  */
+      if (! may_ask)
+       {
+         trust_level = TRUST_UNDEFINED;
+         goto out;
+       }
+
+      break;
+
+    case TOFU_POLICY_NONE:
+      /* The binding is new, we need to check for conflicts.  Case #3
+        below.  */
+      break;
+
+    case _tofu_GET_POLICY_ERROR:
+      trust_level = _tofu_GET_TRUST_ERROR;
+      goto out;
+
+    default:
+      log_bug ("%s: Impossible value for policy (%d)\n", __func__, policy);
+    }
+
+
+  /* We get here if:
+
+       1. The saved policy is auto and the default policy is ask
+          (get_policy() == TOFU_POLICY_AUTO
+           && opt.tofu_default_policy == TOFU_POLICY_ASK)
+
+       2. The saved policy is ask (either last time the user selected
+          accept once or reject once or there was a conflict and this
+          binding's policy was changed from auto to ask)
+         (policy == TOFU_POLICY_ASK), or,
+
+       3. We don't have a saved policy (policy == TOFU_POLICY_NONE)
+          (need to check for a conflict).
+   */
+
+  /* Look for conflicts.  This is needed in all 3 cases.
+
+     Get the fingerprints of any bindings that share the email
+     address.  Note: if the binding in question is in the DB, it will
+     also be returned.  Thus, if the result set is empty, then this is
+     a new binding.  */
+  rc = sqlite3_stepx
+    (db->db, &db->s.get_trust_bindings_with_this_email,
+     strings_collect_cb2, &bindings_with_this_email, &err,
+     "select distinct fingerprint from bindings where email = ?;",
+     SQLITE_ARG_STRING, email, SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("error reading from TOFU database"
+                  " (listing fingerprints): %s\n"),
+                err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  bindings_with_this_email_count = strlist_length (bindings_with_this_email);
+  if (bindings_with_this_email_count == 0
+      && opt.tofu_default_policy != TOFU_POLICY_ASK)
+    /* New binding with no conflict and a concrete default policy.
+
+       We've never observed a binding with this email address
+       (BINDINGS_WITH_THIS_EMAIL_COUNT is 0 and the above query would return
+       the current binding if it were in the DB) and we have a default
+       policy, which is not to ask the user.  */
+    {
+      /* 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);
+
+      if (DBG_TRUST)
+       log_debug ("TOFU: New binding <%s, %s>, no conflict.\n",
+                  email, fingerprint_pp);
+
+      if (record_binding (dbs, fingerprint, email, user_id,
+                         TOFU_POLICY_AUTO, 0) != 0)
+       {
+         log_error (_("error setting TOFU binding's trust level to %s\n"),
+                      "auto");
+         trust_level = _tofu_GET_TRUST_ERROR;
+         goto out;
+       }
+
+      trust_level = tofu_policy_to_trust_level (TOFU_POLICY_AUTO);
+      goto out;
+    }
+
+  if (policy == TOFU_POLICY_NONE)
+    /* This is a new binding and we have a conflict.  Mark any
+       conflicting bindings that have an automatic policy as now
+       requiring confirmation.  Note: we delay this until after we ask
+       for confirmation so that when the current policy is printed, it
+       is correct.  */
+    change_conflicting_to_ask = 1;
+
+  if (! may_ask)
+    /* We can only get here in the third case (no saved policy) and if
+       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);
+
+      if (record_binding (dbs, fingerprint, email, user_id,
+                         TOFU_POLICY_ASK, 0) != 0)
+       log_error (_("error setting TOFU binding's trust level to %s\n"),
+                  "ask");
+
+      trust_level = TRUST_UNDEFINED;
+      goto out;
+    }
+
+  /* If we get here, we need to ask the user about the binding.  There
+     are three ways we could end up here:
+
+       - This is a new binding and there is a conflict
+         (policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0),
+
+       - This is a new binding and opt.tofu_default_policy is set to
+         ask.  (policy == TOFU_POLICY_NONE && opt.tofu_default_policy ==
+         TOFU_POLICY_ASK), or,
+
+       - The policy is ask (the user deferred last time) (policy ==
+         TOFU_POLICY_ASK).
+   */
+  {
+    int is_conflict =
+      ((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;
+    char *prompt;
+    char *choices;
+
+    fp = es_fopenmem (0, "rw,samethread");
+    if (! fp)
+      log_fatal ("Error creating memory stream\n");
+
+    binding = xasprintf ("<%s, %s>", fingerprint_pp, email);
+    binding_shown = 0;
+
+    if (policy == TOFU_POLICY_NONE)
+      {
+       es_fprintf (fp, _("The binding %s is NOT known.  "), binding);
+       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);
+        xfree (conflict_pp);
+       binding_shown = 1;
+      }
+    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).\n\n"),
+               binding_shown ? "" : binding,
+               binding_shown ? "" : " ");
+
+    xfree (binding);
+
+    /* Find other user ids associated with this key and whether the
+       bindings are marked as good or bad.  */
+    {
+      struct db *db_key;
+
+      if (opt.tofu_db_format == TOFU_DB_SPLIT)
+       /* In the split format, we need to search in the fingerprint
+          DB for all the emails associated with this key, not the
+          email DB.  */
+       db_key = getdb (dbs, fingerprint, DB_KEY);
+      else
+       db_key = db;
+
+      if (db_key)
+       {
+         rc = sqlite3_stepx
+           (db_key->db, &db_key->s.get_trust_gather_other_user_ids,
+             strings_collect_cb2, &other_user_ids, &err,
+             opt.tofu_db_format == TOFU_DB_SPLIT
+            ? "select user_id, email from bindings where fingerprint = ?;"
+            : "select user_id, policy from bindings where fingerprint = ?;",
+            SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_END);
+         if (rc)
+           {
+             log_error (_("error gathering other user ids: %s.\n"), err);
+             sqlite3_free (err);
+             err = NULL;
+           }
+       }
+    }
+
+    if (other_user_ids)
+      {
+       strlist_t strlist_iter;
+
+       es_fprintf (fp, _("Known user ids associated with this key:\n"));
+       for (strlist_iter = other_user_ids;
+            strlist_iter;
+            strlist_iter = strlist_iter->next)
+         {
+           char *other_user_id = strlist_iter->d;
+           char *other_thing;
+           enum tofu_policy other_policy;
+
+           assert (strlist_iter->next);
+           strlist_iter = strlist_iter->next;
+           other_thing = strlist_iter->d;
+
+           if (opt.tofu_db_format == TOFU_DB_SPLIT)
+             other_policy = get_policy (dbs, fingerprint, other_thing, NULL);
+           else
+             other_policy = atoi (other_thing);
+
+           es_fprintf (fp, _("  %s (policy: %s)\n"),
+                       other_user_id,
+                       tofu_policy_str (other_policy));
+         }
+       es_fprintf (fp, "\n");
+
+       free_strlist (other_user_ids);
+      }
+
+    /* Find other keys associated with this email address.  */
+    /* XXX: When generating the statistics, do we want the time
+       embedded in the signature (column 'sig_time') or the time that
+       we first verified the signature (column 'time').  */
+    rc = sqlite3_stepx
+      (db->db, &db->s.get_trust_gather_other_keys,
+       signature_stats_collect_cb, &stats, &err,
+       "select fingerprint, policy, time_ago, count(*)\n"
+       " from (select bindings.*,\n"
+       "        case\n"
+       /* From the future (but if its just a couple of hours in the
+         future don't turn it into a warning)?  Or should we use
+         small, medium or large units?  (Note: whatever we do, we
+         keep the value in seconds.  Then when we group, everything
+         that rounds to the same number of seconds is grouped.)  */
+       "         when delta < -("STRINGIFY (TIME_AGO_FUTURE_IGNORE)") then -1\n"
+       "         when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n"
+       "          then max(0,\n"
+       "                   round(delta / ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
+       "               * ("STRINGIFY (TIME_AGO_UNIT_SMALL)"))\n"
+       "         when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n"
+       "          then round(delta / ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)"))\n"
+       "               * ("STRINGIFY (TIME_AGO_UNIT_MEDIUM)")\n"
+       "         else round(delta / ("STRINGIFY (TIME_AGO_UNIT_LARGE)"))\n"
+       "              * ("STRINGIFY (TIME_AGO_UNIT_LARGE)")\n"
+       "        end time_ago,\n"
+       "        delta time_ago_raw\n"
+       "       from bindings\n"
+       "       left join\n"
+       "         (select *,\n"
+       "            cast(strftime('%s','now') - sig_time as real) delta\n"
+       "           from signatures) ss\n"
+       "        on ss.binding = bindings.oid)\n"
+       " where email = ?\n"
+       " group by fingerprint, time_ago\n"
+       /* Make sure the current key is first.  */
+       " order by fingerprint = ? asc, fingerprint desc, time_ago desc;\n",
+       SQLITE_ARG_STRING, email, SQLITE_ARG_STRING, fingerprint,
+       SQLITE_ARG_END);
+    if (rc)
+      {
+       strlist_t strlist_iter;
+
+       log_error (_("error gathering signature stats: %s.\n"),
+                  err);
+       sqlite3_free (err);
+       err = NULL;
+
+       es_fprintf
+         (fp, _("The email address (%s) is associated with %d keys:\n"),
+          email, bindings_with_this_email_count);
+       for (strlist_iter = bindings_with_this_email;
+            strlist_iter;
+            strlist_iter = strlist_iter->next)
+         es_fprintf (fp, _("  %s\n"), strlist_iter->d);
+      }
+    else
+      {
+       char *key = NULL;
+
+       if (! stats || strcmp (stats->fingerprint, fingerprint) != 0)
+         /* If we have already added this key to the DB, then it will
+            be first (see the above select).  Since the first key on
+            the list is not this key, we must not yet have verified
+            any messages signed by this key.  Add a dummy entry.  */
+         signature_stats_prepend (&stats, fingerprint, TOFU_POLICY_AUTO, 0, 0);
+
+       es_fprintf (fp, _("Statistics for keys with the email '%s':\n"),
+                   email);
+       for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
+         {
+           if (! key || strcmp (key, stats_iter->fingerprint) != 0)
+             {
+               int this_key;
+                char *key_pp;
+               key = stats_iter->fingerprint;
+               this_key = strcmp (key, fingerprint) == 0;
+                key_pp = format_hexfingerprint (key, NULL, 0);
+               if (this_key)
+                 es_fprintf (fp, _("  %s (this key):"), key_pp);
+               else
+                 es_fprintf (fp, _("  %s (policy: %s):"),
+                             key_pp, tofu_policy_str (stats_iter->policy));
+                xfree (key_pp);
+               es_fprintf (fp, "\n");
+             }
+
+           if (stats_iter->time_ago == -1)
+             es_fprintf (fp, _("    %ld %s signed in the future.\n"),
+                         stats_iter->count,
+                         stats_iter->count == 1
+                         ? _("message") : _("messages"));
+           else if (stats_iter->count == 0)
+             es_fprintf (fp, _("    0 signed messages.\n"));
+           else
+             es_fprintf (fp, _("    %ld %s signed over the past %ld %s.\n"),
+                         stats_iter->count,
+                         stats_iter->count == 1
+                         ? _("message") : _("messages"),
+                         time_ago_scale (stats_iter->time_ago),
+                         time_ago_unit (stats_iter->time_ago));
+         }
+      }
+
+    if (is_conflict)
+      {
+       /* TRANSLATORS: translate the below text.  We don't directly
+          internationalize that text so that we can tweak it without
+          breaking translations.  */
+       char *text = _("TOFU detected a binding conflict");
+       if (strcmp (text, "TOFU detected a binding conflict") == 0)
+         /* No translation.  Use the English text.  */
+         text =
+           "Normally, there is only a single key associated with an email "
+           "address.  However, people sometimes generate a new key if "
+           "their key is too old or they think it might be compromised.  "
+           "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);
+       es_fprintf (fp, "\n%s\n", text);
+        xfree (text);
+      }
+
+    es_fputc ('\n', fp);
+    /* 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.  */
+    choices = _("gG" "aA" "uU" "rR" "bB");
+    es_fprintf (fp, _("(G)ood/(A)ccept once/(U)nknown/(R)eject once/(B)ad? "));
+
+    /* Add a NUL terminator.  */
+    es_fputc (0, fp);
+    if (es_fclose_snatch (fp, (void **) &prompt, NULL))
+      log_fatal ("error snatching memory stream\n");
+
+    while (1)
+      {
+       char *response;
+
+       if (strlen (choices) != 10)
+         log_bug ("Bad TOFU conflict translation!  Please report.");
+
+       response = cpr_get ("tofu conflict", prompt);
+       trim_spaces (response);
+       cpr_kill_prompt ();
+       if (strlen (response) == 1)
+         {
+           char *choice = strchr (choices, *response);
+           if (choice)
+             {
+               int c = ((size_t) choice - (size_t) choices) / 2;
+               assert (0 <= c && c <= 4);
+
+               switch (c)
+                 {
+                 case 0: /* Good.  */
+                   policy = TOFU_POLICY_GOOD;
+                   trust_level = tofu_policy_to_trust_level (policy);
+                   break;
+                 case 1: /* Accept once.  */
+                   policy = TOFU_POLICY_ASK;
+                   trust_level =
+                     tofu_policy_to_trust_level (TOFU_POLICY_GOOD);
+                   break;
+                 case 2: /* Unknown.  */
+                   policy = TOFU_POLICY_UNKNOWN;
+                   trust_level = tofu_policy_to_trust_level (policy);
+                   break;
+                 case 3: /* Reject once.  */
+                   policy = TOFU_POLICY_ASK;
+                   trust_level =
+                     tofu_policy_to_trust_level (TOFU_POLICY_BAD);
+                   break;
+                 case 4: /* Bad.  */
+                   policy = TOFU_POLICY_BAD;
+                   trust_level = tofu_policy_to_trust_level (policy);
+                   break;
+                 default:
+                   log_bug ("c should be between 0 and 4 but it is %d!", c);
+                 }
+
+               if (record_binding (dbs, fingerprint, email, user_id,
+                                   policy, 0) != 0)
+                 /* If there's an error registering the
+                    binding, don't save the signature.  */
+                 trust_level = _tofu_GET_TRUST_ERROR;
+
+               break;
+             }
+         }
+       xfree (response);
+      }
+
+    xfree (prompt);
+
+    signature_stats_free (stats);
+  }
+
+ out:
+  if (change_conflicting_to_ask)
+    {
+      if (! may_ask)
+       /* If we weren't allowed to ask, also update this key as
+          conflicting with itself.  */
+       rc = sqlite3_exec_printf
+         (db->db, NULL, NULL, &err,
+          "update bindings set policy = %d, conflict = %Q"
+          " where email = %Q"
+          "  and (policy = %d or (policy = %d and fingerprint = %Q));",
+          TOFU_POLICY_ASK, fingerprint, email, TOFU_POLICY_AUTO,
+          TOFU_POLICY_ASK, fingerprint);
+      else
+       rc = sqlite3_exec_printf
+         (db->db, NULL, NULL, &err,
+          "update bindings set policy = %d, conflict = %Q"
+          " where email = %Q and fingerprint != %Q and policy = %d;",
+          TOFU_POLICY_ASK, fingerprint, email, fingerprint, TOFU_POLICY_AUTO);
+      if (rc)
+       {
+         log_error (_("error changing TOFU policy: %s\n"), err);
+         sqlite3_free (err);
+         goto out;
+       }
+    }
+
+  xfree (conflict);
+  free_strlist (bindings_with_this_email);
+  xfree (fingerprint_pp);
+
+  return trust_level;
+}
+
+static char *
+time_ago_str (long long int t)
+{
+  estream_t fp;
+  int years = 0;
+  int months = 0;
+  int days = 0;
+  int hours = 0;
+  int minutes = 0;
+  int seconds = 0;
+
+  /* The number of units that we've printed so far.  */
+  int count = 0;
+  /* The first unit that we printed (year = 0, month = 1,
+     etc.).  */
+  int first = -1;
+  /* The current unit.  */
+  int i = 0;
+
+  char *str;
+
+  /* It would be nice to use a macro to do this, but gettext
+     works on the unpreprocessed code.  */
+#define MIN_SECS (60)
+#define HOUR_SECS (60 * MIN_SECS)
+#define DAY_SECS (24 * HOUR_SECS)
+#define MONTH_SECS (30 * DAY_SECS)
+#define YEAR_SECS (365 * DAY_SECS)
+
+  if (t > YEAR_SECS)
+    {
+      years = t / YEAR_SECS;
+      t -= years * YEAR_SECS;
+    }
+  if (t > MONTH_SECS)
+    {
+      months = t / MONTH_SECS;
+      t -= months * MONTH_SECS;
+    }
+  if (t > DAY_SECS)
+    {
+      days = t / DAY_SECS;
+      t -= days * DAY_SECS;
+    }
+  if (t > HOUR_SECS)
+    {
+      hours = t / HOUR_SECS;
+      t -= hours * HOUR_SECS;
+    }
+  if (t > MIN_SECS)
+    {
+      minutes = t / MIN_SECS;
+      t -= minutes * MIN_SECS;
+    }
+  seconds = t;
+
+#undef MIN_SECS
+#undef HOUR_SECS
+#undef DAY_SECS
+#undef MONTH_SECS
+#undef YEAR_SECS
+
+  fp = es_fopenmem (0, "rw,samethread");
+  if (! fp)
+    log_fatal ("error creating memory stream: %s\n",
+               gpg_strerror (gpg_error_from_syserror()));
+
+  if (years)
+    {
+      if (years > 1)
+        es_fprintf (fp, _("%d years"), years);
+      else
+        es_fprintf (fp, _("%d year"), years);
+      count ++;
+      first = i;
+    }
+  i ++;
+  if ((first == -1 || i - first <= 3) && months)
+    {
+      if (count)
+        es_fprintf (fp, ", ");
+
+      if (months > 1)
+        es_fprintf (fp, _("%d months"), months);
+      else
+        es_fprintf (fp, _("%d month"), months);
+      count ++;
+      first = i;
+    }
+  i ++;
+  if ((first == -1 || i - first <= 3) && count < 2 && days)
+    {
+      if (count)
+        es_fprintf (fp, ", ");
+
+      if (days > 1)
+        es_fprintf (fp, _("%d days"), days);
+      else
+        es_fprintf (fp, _("%d day"), days);
+      count ++;
+      first = i;
+    }
+  i ++;
+  if ((first == -1 || i - first <= 3) && count < 2 && hours)
+    {
+      if (count)
+        es_fprintf (fp, ", ");
+
+      if (hours > 1)
+        es_fprintf (fp, _("%d hours"), hours);
+      else
+        es_fprintf (fp, _("%d hour"), hours);
+      count ++;
+      first = i;
+    }
+  i ++;
+  if ((first == -1 || i - first <= 3) && count < 2 && minutes)
+    {
+      if (count)
+        es_fprintf (fp, ", ");
+
+      if (minutes > 1)
+        es_fprintf (fp, _("%d minutes"), minutes);
+      else
+        es_fprintf (fp, _("%d minute"), minutes);
+      count ++;
+      first = i;
+    }
+  i ++;
+  if ((first == -1 || i - first <= 3) && count < 2)
+    {
+      if (count)
+        es_fprintf (fp, ", ");
+
+      if (seconds > 1)
+        es_fprintf (fp, _("%d seconds"), seconds);
+      else
+        es_fprintf (fp, _("%d second"), seconds);
+    }
+
+  es_fputc (0, fp);
+  if (es_fclose_snatch (fp, (void **) &str, NULL))
+    log_fatal ("error snatching memory stream\n");
+
+  return str;
+}
+
+static void
+show_statistics (struct dbs *dbs, const char *fingerprint,
+                const char *email, const char *user_id,
+                const char *sig_exclude)
+{
+  struct db *db;
+  char *fingerprint_pp;
+  int rc;
+  strlist_t strlist = NULL;
+  char *err = NULL;
+
+  db = getdb (dbs, email, DB_EMAIL);
+  if (! db)
+    return;
+
+  fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
+
+  rc = sqlite3_exec_printf
+    (db->db, strings_collect_cb, &strlist, &err,
+     "select count (*), strftime('%%s','now') - min (signatures.time),\n"
+     "  strftime('%%s','now') - max (signatures.time)\n"
+     " from signatures\n"
+     " left join bindings on signatures.binding = bindings.oid\n"
+     " where fingerprint = %Q and email = %Q and sig_digest %s%s%s;",
+     fingerprint, email,
+     /* We want either: sig_digest != 'SIG_EXCLUDE' or sig_digest is
+       not NULL.  */
+     sig_exclude ? "!= '" : "is not NULL",
+     sig_exclude ? sig_exclude : "",
+     sig_exclude ? "'" : "");
+  if (rc)
+    {
+      log_error (_("error reading from TOFU database"
+                  " (getting statistics): %s\n"),
+                err);
+      sqlite3_free (err);
+      goto out;
+    }
+
+  if (! strlist)
+    log_info (_("Have never verified a message signed by key %s!\n"),
+              fingerprint_pp);
+  else
+    {
+      char *tail = NULL;
+      signed long messages;
+      signed long first_seen_ago;
+      signed long most_recent_seen_ago;
+
+      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;
+       }
+
+      if (messages == 0 && *strlist->next->d == '\0')
+       /* 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;
+           }
+       }
+
+      if (messages == -1 || first_seen_ago == 0)
+        log_info (_("Failed to collect signature statistics"
+                    " for \"%s\" (key %s)\n"),
+                  user_id, fingerprint_pp);
+      else
+       {
+         enum tofu_policy policy = get_policy (dbs, fingerprint, email, NULL);
+         estream_t fp;
+         char *msg;
+
+         fp = es_fopenmem (0, "rw,samethread");
+         if (! fp)
+           log_fatal ("error creating memory stream\n");
+
+         if (messages == 0)
+            es_fprintf (fp,
+                        _("Verified 0 messages signed by \"%s\""
+                          " (key: %s, policy %s)."),
+                        user_id, fingerprint_pp, tofu_policy_str (policy));
+         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);
+
+             es_fprintf (fp,
+                         _("Verified %ld messages signed by \"%s\""
+                           " (key: %s, policy: %s) in the past %s."),
+                         messages, user_id,
+                         fingerprint_pp, tofu_policy_str (policy),
+                          first_seen_ago_str);
+
+              if (messages > 1)
+                es_fprintf (fp,
+                            _("  The most recent message was verified %s ago."),
+                            most_recent_seen_ago_str);
+
+              xfree (first_seen_ago_str);
+              xfree (most_recent_seen_ago_str);
+            }
+
+         es_fputc (0, fp);
+         if (es_fclose_snatch (fp, (void **) &msg, NULL))
+           log_fatal ("error snatching memory stream\n");
+
+         log_info ("%s\n", msg);
+          xfree (msg);
+
+         if (policy == TOFU_POLICY_AUTO && messages < 10)
+           {
+             char *set_policy_command;
+             char *text;
+              char *tmp;
+
+             if (messages == 0)
+               log_info (_("Warning: we've have yet to see"
+                            " a message signed by this key!\n"));
+             else if (messages == 1)
+               log_info (_("Warning: we've only seen a"
+                            " 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 = _("TOFU: few signatures %d %s %s");
+             if (strcmp (text, "TOFU: few signatures %d %s %s") == 0)
+               text =
+                 "Warning: if you think you've seen more than %d %s "
+                 "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, messages == 1 ? _("message") : _("message"),
+                 set_policy_command);
+              text = format_text (tmp, 0, 72, 80);
+              xfree (tmp);
+             log_info ("%s", text);
+              xfree (text);
+             free (set_policy_command);
+           }
+       }
+    }
+
+ out:
+  free_strlist (strlist);
+  xfree (fingerprint_pp);
+
+  return;
+}
+
+/* Extract the email address from a user id and normalize it.  If the
+   user id doesn't contain an email address, then we use the whole
+   user_id and normalize that.  The returned string must be freed.  */
+static char *
+email_from_user_id (const char *user_id)
+{
+  char *email = mailbox_from_userid (user_id);
+  if (! email)
+    {
+      /* Hmm, no email address was provided or we are out of core.  Just
+         take the lower-case version of the whole user id.  It could be
+         a hostname, for instance.  */
+      email = ascii_strlwr (xstrdup (user_id));
+    }
+
+  return email;
+}
+
+/* Register the signature with the binding <fingerprint, USER_ID>.
+   The fingerprint is taken from the primary key packet PK.
+
+   SIG_DIGEST_BIN is the binary representation of the message's
+   digest.  SIG_DIGEST_BIN_LEN is its length.
+
+   SIG_TIME is the time that the signature was generated.
+
+   ORIGIN is a free-formed string describing the origin of the
+   signature.  If this was from an email and the Claws MUA was used,
+   then this should be something like: "email:claws".  If this is
+   NULL, the default is simply "unknown".
+
+   If MAY_ASK is 1, then this function may interact with the user.
+   This is necessary if there is a conflict or the binding's policy is
+   TOFU_POLICY_ASK.
+
+   This function returns the binding's trust level on return.  If an
+   error occurs, this function returns TRUST_UNKNOWN.  */
+int
+tofu_register (PKT_public_key *pk, const char *user_id,
+              const byte *sig_digest_bin, int sig_digest_bin_len,
+              time_t sig_time, const char *origin, int may_ask)
+{
+  struct dbs *dbs;
+  struct db *db;
+  char *fingerprint = NULL;
+  char *fingerprint_pp = NULL;
+  char *email = NULL;
+  char *err = NULL;
+  int rc;
+  int trust_level = TRUST_UNKNOWN;
+  char *sig_digest;
+  unsigned long c;
+  int already_verified = 0;
+
+  sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
+
+  dbs = opendbs ();
+  if (! dbs)
+    {
+      log_error (_("error opening TOFU DB.\n"));
+      goto die;
+    }
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+  fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
+
+  if (! *user_id)
+    {
+      log_debug ("TOFU: user id is empty.  Can't continue.\n");
+      goto die;
+    }
+
+  email = email_from_user_id (user_id);
+
+  if (! origin)
+    /* The default origin is simply "unknown".  */
+    origin = "unknown";
+
+  /* It's necessary to get the trust so that we are certain that the
+     binding has been registered.  */
+  trust_level = get_trust (dbs, fingerprint, email, user_id, may_ask);
+  if (trust_level == _tofu_GET_TRUST_ERROR)
+    /* An error.  */
+    {
+      trust_level = TRUST_UNKNOWN;
+      goto die;
+    }
+
+  /* Save the observed signature in the DB.  */
+  db = getdb (dbs, email, DB_EMAIL);
+  if (! db)
+    {
+      log_error (_("error opening TOFU DB.\n"));
+      goto die;
+    }
+
+  /* We do a query and then an insert.  Make sure they are atomic
+     by wrapping them in a transaction.  */
+  rc = begin_transaction (db, 0);
+  if (rc)
+    goto die;
+
+  /* If we've already seen this signature before, then don't add
+     it again.  */
+  rc = sqlite3_stepx
+    (db->db, &db->s.register_already_seen,
+     get_single_unsigned_long_cb2, &c, &err,
+     "select count (*)\n"
+     " from signatures left join bindings\n"
+     "  on signatures.binding = bindings.oid\n"
+     " where fingerprint = ? and email = ? and sig_time = ?\n"
+     "  and sig_digest = ?",
+     SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+     SQLITE_ARG_LONG_LONG, (long long) sig_time,
+     SQLITE_ARG_STRING, sig_digest,
+     SQLITE_ARG_END);
+  if (rc)
+    {
+      log_error (_("error reading from signatures database"
+                  " (checking existence): %s\n"),
+                err);
+      sqlite3_free (err);
+    }
+  else if (c > 1)
+    /* Duplicates!  This should not happen.  In particular,
+       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>."
+              "  Please report.\n",
+              fingerprint_pp, 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,
+                  sig_digest, origin);
+    }
+  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);
+
+      assert (c == 0);
+
+      rc = sqlite3_stepx
+       (db->db, &db->s.register_insert, NULL, NULL, &err,
+        "insert into signatures\n"
+        " (binding, sig_digest, origin, sig_time, time)\n"
+        " values\n"
+        " ((select oid from bindings\n"
+        "    where fingerprint = ? and email = ?),\n"
+        "  ?, ?, ?, strftime('%s', 'now'));",
+        SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+         SQLITE_ARG_STRING, sig_digest, SQLITE_ARG_STRING, origin,
+         SQLITE_ARG_LONG_LONG, (long long) sig_time,
+         SQLITE_ARG_END);
+      if (rc)
+       {
+         log_error (_("error updating TOFU DB"
+                      " (inserting into signatures table): %s\n"),
+                    err);
+         sqlite3_free (err);
+       }
+    }
+
+  /* It only matters whether we abort or commit the transaction
+     (so long as we do something) if we execute the insert.  */
+  if (rc)
+    rc = rollback_transaction (db);
+  else
+    rc = end_transaction (db, 0);
+  if (rc)
+    {
+      log_error (_("error ending transaction on TOFU database: %s\n"), err);
+      sqlite3_free (err);
+      goto die;
+    }
+
+ die:
+  if (may_ask && trust_level != TRUST_ULTIMATE)
+    /* It's only appropriate to show the statistics in an interactive
+       context.  */
+    show_statistics (dbs, fingerprint, email, user_id,
+                    already_verified ? NULL : sig_digest);
+
+  xfree (email);
+  xfree (fingerprint_pp);
+  xfree (fingerprint);
+  if (dbs)
+    closedbs (dbs);
+  xfree (sig_digest);
+
+  return trust_level;
+}
+
+/* Combine a trust level returned from the TOFU trust model with a
+   trust level returned by the PGP trust model.  This is primarily of
+   interest when the trust model is tofu+pgp (TM_TOFU_PGP).
+
+   This function ors together the upper bits (the values not covered
+   by TRUST_MASK, i.e., TRUST_FLAG_REVOKED, etc.).  */
+int
+tofu_wot_trust_combine (int tofu_base, int wot_base)
+{
+  int tofu = tofu_base & TRUST_MASK;
+  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);
+
+  /* We first consider negative trust policys.  These trump positive
+     trust policies.  */
+  if (tofu == TRUST_NEVER || wot == TRUST_NEVER)
+    /* TRUST_NEVER trumps everything else.  */
+    return upper | TRUST_NEVER;
+  if (tofu == TRUST_EXPIRED || wot == TRUST_EXPIRED)
+    /* TRUST_EXPIRED trumps everything but TRUST_NEVER.  */
+    return upper | TRUST_EXPIRED;
+
+  /* Now we only have positive or neutral trust policies.  We take
+     the max.  */
+  if (tofu == TRUST_ULTIMATE || wot == TRUST_ULTIMATE)
+    return upper | TRUST_ULTIMATE;
+  if (tofu == TRUST_FULLY || wot == TRUST_FULLY)
+    return upper | TRUST_FULLY;
+  if (tofu == TRUST_MARGINAL || wot == TRUST_MARGINAL)
+    return upper | TRUST_MARGINAL;
+  if (tofu == TRUST_UNDEFINED || wot == TRUST_UNDEFINED)
+    return upper | TRUST_UNDEFINED;
+  return upper | TRUST_UNKNOWN;
+}
+
+/* Return the validity (TRUST_NEVER, etc.) of the binding
+   <FINGERPRINT, USER_ID>.
+
+   PK is the primary key packet.
+
+   If MAY_ASK is 1 and the policy is TOFU_POLICY_ASK, then the user
+   will be prompted to choose a different policy.  If MAY_ASK is 0 and
+   the policy is TOFU_POLICY_ASK, then TRUST_UNKNOWN is returned.
+
+   Returns TRUST_UNDEFINED if an error occurs.  */
+int
+tofu_get_validity (PKT_public_key *pk, const char *user_id,
+                  int may_ask)
+{
+  struct dbs *dbs;
+  char *fingerprint = NULL;
+  char *email = NULL;
+  int trust_level = TRUST_UNDEFINED;
+
+  dbs = opendbs ();
+  if (! dbs)
+    {
+      log_error (_("error opening TOFU DB.\n"));
+      goto die;
+    }
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+
+  if (! *user_id)
+    {
+      log_debug ("user id is empty."
+                 "  Can't get TOFU validity for this binding.\n");
+      goto die;
+    }
+
+  email = email_from_user_id (user_id);
+
+  trust_level = get_trust (dbs, fingerprint, email, user_id, may_ask);
+  if (trust_level == _tofu_GET_TRUST_ERROR)
+    /* An error.  */
+    trust_level = TRUST_UNDEFINED;
+
+  if (may_ask && trust_level != TRUST_ULTIMATE)
+    show_statistics (dbs, fingerprint, email, user_id, NULL);
+
+ die:
+  xfree (email);
+  xfree (fingerprint);
+  if (dbs)
+    closedbs (dbs);
+
+  return trust_level;
+}
+
+/* Set the policy for all non-revoked user ids in the keyblock KB to
+   POLICY.
+
+   If no key is available with the specified key id, then this
+   function returns GPG_ERR_NO_PUBKEY.
+
+   Returns 0 on success and an error code otherwise.  */
+gpg_error_t
+tofu_set_policy (kbnode_t kb, enum tofu_policy policy)
+{
+  struct dbs *dbs;
+  PKT_public_key *pk;
+  char *fingerprint = NULL;
+
+  assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+  pk = kb->pkt->pkt.public_key;
+
+  dbs = opendbs ();
+  if (! dbs)
+    {
+      log_error (_("error opening TOFU DB.\n"));
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  if (DBG_TRUST)
+    log_debug ("Setting TOFU policy for %s to %s\n",
+              keystr (pk->keyid), tofu_policy_str (policy));
+  if (! (pk->main_keyid[0] == pk->keyid[0]
+        && pk->main_keyid[1] == pk->keyid[1]))
+    log_bug ("%s: Passed a subkey, but expecting a primary key.\n", __func__);
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+
+  for (; kb; kb = kb->next)
+    {
+      PKT_user_id *user_id;
+      char *email;
+
+      if (kb->pkt->pkttype != PKT_USER_ID)
+       continue;
+
+      user_id = kb->pkt->pkt.user_id;
+      if (user_id->is_revoked)
+       /* Skip revoked user ids.  (Don't skip expired user ids, the
+          expiry can be changed.)  */
+       continue;
+
+      email = email_from_user_id (user_id->name);
+
+      record_binding (dbs, fingerprint, email, user_id->name, policy, 1);
+
+      xfree (email);
+    }
+
+  xfree (fingerprint);
+  closedbs (dbs);
+
+  return 0;
+}
+
+/* Set the TOFU policy for all non-revoked user ids in the KEY with
+   the key id KEYID to POLICY.
+
+   If no key is available with the specified key id, then this
+   function returns GPG_ERR_NO_PUBKEY.
+
+   Returns 0 on success and an error code otherwise.  */
+gpg_error_t
+tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy)
+{
+  kbnode_t keyblock = get_pubkeyblock (keyid);
+  if (! keyblock)
+    return gpg_error (GPG_ERR_NO_PUBKEY);
+
+  return tofu_set_policy (keyblock, policy);
+}
+
+/* Return the TOFU policy for the specified binding in *POLICY.  If no
+   policy has been set for the binding, sets *POLICY to
+   TOFU_POLICY_NONE.
+
+   PK is a primary public key and USER_ID is a user id.
+
+   Returns 0 on success and an error code otherwise.  */
+gpg_error_t
+tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+                enum tofu_policy *policy)
+{
+  struct dbs *dbs;
+  char *fingerprint;
+  char *email;
+
+  /* Make sure PK is a primary key.  */
+  assert (pk->main_keyid[0] == pk->keyid[0]
+         && pk->main_keyid[1] == pk->keyid[1]);
+
+  dbs = opendbs ();
+  if (! dbs)
+    {
+      log_error (_("error opening TOFU DB.\n"));
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+
+  email = email_from_user_id (user_id->name);
+
+  *policy = get_policy (dbs, fingerprint, email, NULL);
+
+  xfree (email);
+  xfree (fingerprint);
+  closedbs (dbs);
+
+  if (*policy == _tofu_GET_POLICY_ERROR)
+    return gpg_error (GPG_ERR_GENERAL);
+  return 0;
+}
diff --git a/g10/tofu.h b/g10/tofu.h
new file mode 100644 (file)
index 0000000..7ee1083
--- /dev/null
@@ -0,0 +1,114 @@
+/* tofu.h - TOFU trust model.
+ * Copyright (C) 2015 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 G10_TOFU_H
+#define G10_TOFU_H
+
+#include <config.h>
+
+/* For each binding, we have a trust policy.  */
+enum tofu_policy
+  {
+    /* This value can be returned by tofu_get_policy to indicate that
+       there is no policy set for the specified binding.  */
+    TOFU_POLICY_NONE = 0,
+
+    /* We made a default policy decision.  This is only done if there
+       is no conflict with another binding (that is, the email address
+       is not part of another known key).  The default policy is
+       configurable (and specified using: --tofu-default-policy).
+
+       Note: when using the default policy, we save TOFU_POLICY_AUTO
+       with the binding, not the policy that was in effect.  This way,
+       if the user invokes gpg again, but with a different value for
+       --tofu-default-policy, a different decision is made.  */
+    TOFU_POLICY_AUTO = 1,
+
+    /* The user explicitly marked the binding as good.  In this case,
+       we return TRUST_FULLY.  */
+    TOFU_POLICY_GOOD = 2,
+
+    /* The user explicitly marked the binding as unknown.  In this
+       case, we return TRUST_UNKNOWN.  */
+    TOFU_POLICY_UNKNOWN = 3,
+
+    /* The user explicitly marked the binding as bad.  In this case,
+       we always return TRUST_NEVER.  */
+    TOFU_POLICY_BAD = 4,
+
+    /* The user deferred a definitive policy decision about the
+       binding (by selecting accept once or reject once).  The next
+       time we see this binding, we should ask the user what to
+       do.  */
+    TOFU_POLICY_ASK = 5,
+
+
+    /* Privat evalue used only within tofu.c.  */
+    _tofu_GET_POLICY_ERROR = 100
+  };
+
+/* Return a string representation of a trust policy.  Returns "???" if
+   POLICY is not valid.  */
+const char *tofu_policy_str (enum tofu_policy policy);
+
+/* Convert a binding policy (e.g., TOFU_POLICY_BAD) to a trust level
+   (e.g., TRUST_BAD) in light of the current configuration.  */
+int tofu_policy_to_trust_level (enum tofu_policy policy);
+
+/* Register the binding <PK, USER_ID> and the signature
+   described by SIGS_DIGEST and SIG_TIME, which it generated.  Origin
+   describes where the signed data came from, e.g., "email:claws"
+   (default: "unknown").  If MAY_ASK is 1, then this function may
+   interact with the user in the case of a conflict or if the
+   binding's policy is ask.  This function returns the binding's trust
+   level.  If an error occurs, it returns TRUST_UNKNOWN.  */
+int tofu_register (PKT_public_key *pk, const char *user_id,
+                  const byte *sigs_digest, int sigs_digest_len,
+                  time_t sig_time, const char *origin, int may_ask);
+
+/* Combine a trust level returned from the TOFU trust model with a
+   trust level returned by the PGP trust model.  This is primarily of
+   interest when the trust model is tofu+pgp (TM_TOFU_PGP).  */
+int tofu_wot_trust_combine (int tofu, int wot);
+
+/* Determine the validity (TRUST_NEVER, etc.) of the binding
+   <PK, USER_ID>.  If MAY_ASK is 1, then this function may
+   interact with the user.  If not, TRUST_UNKNOWN is returned.  If an
+   error occurs, TRUST_UNDEFINED is returned.  */
+int tofu_get_validity (PKT_public_key *pk, const char *user_id, int may_ask);
+
+/* Set the policy for all non-revoked user ids in the keyblock KB to
+   POLICY.  */
+gpg_error_t tofu_set_policy (kbnode_t kb, enum tofu_policy policy);
+
+/* Set the TOFU policy for all non-revoked users in the key with the
+   key id KEYID to POLICY.  */
+gpg_error_t tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy);
+
+/* Return the TOFU policy for the specified binding in *POLICY.  */
+gpg_error_t tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
+                            enum tofu_policy *policy);
+
+/* When doing a lot of DB activities (in particular, when listing
+   keys), this causes the DB to enter batch mode, which can
+   significantly speed up operations.  */
+void tofu_begin_batch_update (void);
+void tofu_end_batch_update (void);
+
+#endif /*G10_TOFU_H*/
index 316fe2f..f46aeea 100644 (file)
@@ -152,7 +152,7 @@ uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
     return                         _("[ expired]");
   else if(key)
     {
-      switch (get_validity(key,uid)&TRUST_MASK)
+      switch (get_validity (key, uid, NULL, 0) & TRUST_MASK)
         {
         case TRUST_UNKNOWN:   return _("[ unknown]");
         case TRUST_EXPIRED:   return _("[ expired]");
@@ -294,11 +294,12 @@ check_or_update_trustdb (void)
 
 /*
  * Return the validity information for PK.  If the namehash is not
- * NULL, the validity of the corresponsing user ID is returned,
+ * NULL, the validity of the corresponding user ID is returned,
  * otherwise, a reasonable value for the entire key is returned.
  */
 unsigned int
-get_validity (PKT_public_key *pk, PKT_user_id *uid)
+get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
+             int may_ask)
 {
   int rc;
   unsigned int validity;
@@ -330,7 +331,7 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid)
 #ifdef NO_TRUST_MODELS
   validity = TRUST_UNKNOWN;
 #else
-  validity = tdb_get_validity_core (pk, uid, main_pk);
+  validity = tdb_get_validity_core (pk, uid, main_pk, sig, may_ask);
 #endif
 
  leave:
@@ -359,7 +360,7 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
   if (!pk)
     return '?';  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (pk, uid);
+  trustlevel = get_validity (pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return 'r';
   return trust_letter (trustlevel);
@@ -374,7 +375,7 @@ get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
   if (!pk)
     return "err";  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (pk, uid);
+  trustlevel = get_validity (pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return _("revoked");
   return trust_value_to_string (trustlevel);
@@ -640,7 +641,7 @@ clean_sigs_from_uid (kbnode_t keyblock, kbnode_t uidnode,
    compacted.  To "compact" a user ID, we simply remove ALL signatures
    except the self-sig that caused the user ID to be remove-worthy.
    We don't actually remove the user ID packet itself since it might
-   be ressurected in a later merge.  Note that this function requires
+   be resurrected in a later merge.  Note that this function requires
    that the caller has already done a merge_keys_and_selfsig().
 
    TODO: change the import code to allow importing a uid with only a
@@ -703,7 +704,7 @@ void
 clean_one_uid (kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only,
                int *uids_cleaned, int *sigs_cleaned)
 {
-  int dummy;
+  int dummy = 0;
 
   assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
   assert (uidnode->pkt->pkttype==PKT_USER_ID);
index b16682d..af839d1 100644 (file)
@@ -40,6 +40,7 @@
 #include "i18n.h"
 #include "tdbio.h"
 #include "trustdb.h"
+#include "tofu.h"
 
 
 typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
@@ -228,13 +229,8 @@ add_utk (u32 *kid)
 {
   struct key_item *k;
 
-  for (k = utk_list; k; k = k->next)
-    {
-      if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
-        {
-          return 0;
-        }
-    }
+  if (tdb_keyid_is_utk (kid))
+    return 0;
 
   k = new_key_item ();
   k->kid[0] = kid[0];
@@ -316,6 +312,18 @@ verify_own_keys(void)
   return;
 }
 
+/* Returns whether KID is on the list of ultimately trusted keys.  */
+int
+tdb_keyid_is_utk (u32 *kid)
+{
+  struct key_item *k;
+
+  for (k = utk_list; k; k = k->next)
+    if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+      return 1;
+
+  return 0;
+}
 \f
 /*********************************************
  *********** TrustDB stuff *******************
@@ -379,6 +387,8 @@ trust_model_string(void)
     case TM_CLASSIC:  return "classic";
     case TM_PGP:      return "PGP";
     case TM_EXTERNAL: return "external";
+    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";
@@ -449,20 +459,23 @@ init_trustdb ()
       opt.trust_model=tdbio_read_model();
 
       /* Sanity check this ;) */
-      if(opt.trust_model!=TM_CLASSIC
-        && opt.trust_model!=TM_PGP
-        && opt.trust_model!=TM_EXTERNAL)
+      if(opt.trust_model != TM_CLASSIC
+        && opt.trust_model != TM_PGP
+        && opt.trust_model != TM_TOFU_PGP
+        && opt.trust_model != TM_TOFU
+        && opt.trust_model != TM_EXTERNAL)
        {
          log_info(_("unable to use unknown trust model (%d) - "
-                    "assuming %s trust model\n"),opt.trust_model,"PGP");
-         opt.trust_model=TM_PGP;
+                    "assuming %s trust model\n"),opt.trust_model,"pgp");
+         opt.trust_model = TM_PGP;
        }
 
       if(opt.verbose)
        log_info(_("using %s trust model\n"),trust_model_string());
     }
 
-  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+  if (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC
+      || opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
     {
       /* Verify the list of ultimately trusted keys and move the
         --trusted-keys list there as well. */
@@ -484,7 +497,8 @@ void
 check_trustdb ()
 {
   init_trustdb();
-  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+  if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
+      || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU)
     {
       if (opt.batch && !opt.answer_yes)
        {
@@ -520,7 +534,8 @@ void
 update_trustdb()
 {
   init_trustdb();
-  if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+  if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
+      || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU)
     validate_keys (1);
   else
     log_info (_("no need for a trustdb update with '%s' trust model\n"),
@@ -936,7 +951,8 @@ tdb_check_trustdb_stale (void)
     return;  /* No trustdb => can't be stale.  */
 
   if (!did_nextcheck
-      && (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC))
+      && (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
+          || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU))
     {
       ulong scheduled;
 
@@ -963,16 +979,28 @@ tdb_check_trustdb_stale (void)
 
 /*
  * Return the validity information for PK.  This is the core of
- * get_validity.
+ * get_validity.  If SIG is not NULL, then the trust is being
+ * evaluated in the context of the provided signature.  This is used
+ * by the TOFU code to record statistics.
  */
 unsigned int
 tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
-                       PKT_public_key *main_pk)
+                       PKT_public_key *main_pk,
+                      PKT_signature *sig,
+                      int may_ask)
 {
   TRUSTREC trec, vrec;
   gpg_error_t err;
   ulong recno;
-  unsigned int validity;
+#ifdef USE_TOFU
+  unsigned int tofu_validity = TRUST_UNKNOWN;
+#endif
+  unsigned int validity = TRUST_UNKNOWN;
+
+#ifndef USE_TOFU
+  (void)sig;
+  (void)may_ask;
+#endif
 
   init_trustdb ();
 
@@ -993,60 +1021,153 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
       goto leave;
     }
 
-  err = read_trust_record (main_pk, &trec);
-  if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+#ifdef USE_TOFU
+  if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
     {
-      tdbio_invalid ();
-      return 0;
-    }
-  if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
-    {
-      /* No record found.  */
-      validity = TRUST_UNKNOWN;
-      goto leave;
-    }
+      kbnode_t user_id_node = NULL; /* Silence -Wmaybe-uninitialized.  */
+      int user_ids = 0;
+      int user_ids_expired = 0;
 
-  /* Loop over all user IDs */
-  recno = trec.r.trust.validlist;
-  validity = 0;
-  while (recno)
-    {
-      read_record (recno, &vrec, RECTYPE_VALID);
+      /* If the caller didn't supply a user id then iterate over all
+        uids.  */
+      if (! uid)
+       user_id_node = get_pubkeyblock (main_pk->keyid);
 
-      if(uid)
+      while (uid
+            || (user_id_node = find_next_kbnode (user_id_node, PKT_USER_ID)))
        {
-         /* If a user ID is given we return the validity for that
-            user ID ONLY.  If the namehash is not found, then there
-            is no validity at all (i.e. the user ID wasn't
-            signed). */
-         if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+         unsigned int tl;
+         PKT_user_id *user_id;
+
+         if (uid)
+           user_id = uid;
+         else
+           user_id = user_id_node->pkt->pkt.user_id;
+
+         if (user_id->is_revoked || user_id->is_expired)
+           /* If the user id is revoked or expired, then skip it.  */
            {
-             validity=(vrec.r.valid.validity & TRUST_MASK);
-             break;
+             char *s;
+             if (user_id->is_revoked && user_id->is_expired)
+               s = "revoked and expired";
+             else if (user_id->is_revoked)
+               s = "revoked";
+             else
+               s = "expire";
+
+             log_info ("TOFU: Ignoring %s user id (%s)\n", s, user_id->name);
+
+             continue;
+           }
+
+         user_ids ++;
+
+         if (sig)
+           tl = tofu_register (main_pk, user_id->name,
+                               sig->digest, sig->digest_len,
+                               sig->timestamp, "unknown",
+                               may_ask);
+         else
+           tl = tofu_get_validity (main_pk, user_id->name, may_ask);
+
+         if (tl == TRUST_EXPIRED)
+           user_ids_expired ++;
+         else if (tl == TRUST_UNDEFINED || tl == TRUST_UNKNOWN)
+           ;
+         else if (tl == TRUST_NEVER)
+           tofu_validity = TRUST_NEVER;
+         else
+           {
+             assert (tl == TRUST_MARGINAL
+                     || tl == TRUST_FULLY
+                     || tl == TRUST_ULTIMATE);
+
+             if (tl > tofu_validity)
+               /* XXX: We we really want the max?  */
+               tofu_validity = tl;
            }
+
+         if (uid)
+           /* If the caller specified a user id, then we stop
+              now.  */
+           break;
        }
-      else
+    }
+#endif /*USE_TOFU*/
+
+  if (opt.trust_model == TM_TOFU_PGP
+      || opt.trust_model == TM_CLASSIC
+      || opt.trust_model == TM_PGP)
+    {
+      err = read_trust_record (main_pk, &trec);
+      if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
        {
-         /* If no namehash is given, we take the maximum validity
-            over all user IDs */
-         if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
-           validity = (vrec.r.valid.validity & TRUST_MASK);
+         tdbio_invalid ();
+         return 0;
+       }
+      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+       {
+         /* No record found.  */
+         validity = TRUST_UNKNOWN;
+         goto leave;
        }
 
-      recno = vrec.r.valid.next;
-    }
+      /* Loop over all user IDs */
+      recno = trec.r.trust.validlist;
+      validity = 0;
+      while (recno)
+       {
+         read_record (recno, &vrec, RECTYPE_VALID);
 
-  if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
-    {
-      validity |= TRUST_FLAG_DISABLED;
-      pk->flags.disabled = 1;
+         if(uid)
+           {
+             /* If a user ID is given we return the validity for that
+                user ID ONLY.  If the namehash is not found, then
+                there is no validity at all (i.e. the user ID wasn't
+                signed). */
+             if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+               {
+                 validity=(vrec.r.valid.validity & TRUST_MASK);
+                 break;
+               }
+           }
+         else
+           {
+             /* If no user ID is given, we take the maximum validity
+                over all user IDs */
+             if (validity < (vrec.r.valid.validity & TRUST_MASK))
+               validity = (vrec.r.valid.validity & TRUST_MASK);
+           }
+
+         recno = vrec.r.valid.next;
+       }
+
+      if ((trec.r.trust.ownertrust & TRUST_FLAG_DISABLED))
+       {
+         validity |= TRUST_FLAG_DISABLED;
+         pk->flags.disabled = 1;
+       }
+      else
+       pk->flags.disabled = 0;
+      pk->flags.disabled_valid = 1;
     }
-  else
-    pk->flags.disabled = 0;
-  pk->flags.disabled_valid = 1;
 
  leave:
-  if (pending_check_trustdb)
+#ifdef USE_TOFU
+  validity = tofu_wot_trust_combine (tofu_validity, validity);
+#else /*!USE_TOFU*/
+  validity &= TRUST_MASK;
+
+  if (validity == TRUST_NEVER)
+    /* TRUST_NEVER trumps everything else.  */
+    validity |= TRUST_NEVER;
+  if (validity == TRUST_EXPIRED)
+    /* TRUST_EXPIRED trumps everything but TRUST_NEVER.  */
+    validity |= TRUST_EXPIRED;
+#endif /*!USE_TOFU*/
+
+  if (opt.trust_model != TM_TOFU
+      && pending_check_trustdb)
     validity |= TRUST_FLAG_PENDING_CHECK;
 
   return validity;
@@ -1459,7 +1580,8 @@ validate_one_keyblock (KBNODE kb, struct key_item *klist,
              since we don't accept a regexp on the sig unless it's a
              trust sig. */
           if (kr && (!kr->trust_regexp
-                     || opt.trust_model != TM_PGP
+                     || !(opt.trust_model == TM_PGP
+                          || opt.trust_model == TM_TOFU_PGP)
                      || (uidnode
                          && check_regexp(kr->trust_regexp,
                                          uidnode->pkt->pkt.user_id->name))))
@@ -1469,7 +1591,8 @@ validate_one_keyblock (KBNODE kb, struct key_item *klist,
                  lesser trust sig or value.  I could make a decent
                  argument for any of these cases, but this seems to be
                  what PGP does, and I'd like to be compatible. -dms */
-              if (opt.trust_model == TM_PGP
+              if ((opt.trust_model == TM_PGP
+                   || opt.trust_model == TM_TOFU_PGP)
                   && sig->trust_depth
                   && pk->trust_timestamp <= sig->timestamp)
                {
@@ -1607,9 +1730,8 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
     }
   if (rc)
     {
-      log_error ("keydb_search_first failed: %s\n", gpg_strerror (rc));
-      xfree (keys);
-      return NULL;
+      log_error ("keydb_search(first) failed: %s\n", gpg_strerror (rc));
+      goto die;
     }
 
   desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
@@ -1617,15 +1739,11 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
     {
       PKT_public_key *pk;
 
-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-        continue;
-
       rc = keydb_get_keyblock (hd, &keyblock);
       if (rc)
         {
           log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
-          xfree (keys);
-          return NULL;
+         goto die;
         }
 
       if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
@@ -1676,18 +1794,21 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
       release_kbnode (keyblock);
       keyblock = NULL;
     }
-  while (!(rc = keydb_search (hd, &desc, 1, NULL))
-         || gpg_err_code (rc) == GPG_ERR_LEGACY_KEY);
+  while (!(rc = keydb_search (hd, &desc, 1, NULL)));
 
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     {
       log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc));
-      xfree (keys);
-      return NULL;
+      goto die;
     }
 
   keys[nkeys].keyblock = NULL;
   return keys;
+
+ die:
+  keys[nkeys].keyblock = NULL;
+  release_key_array (keys);
+  return NULL;
 }
 
 /* Caller must sync */
@@ -1769,19 +1890,22 @@ validate_keys (int interactive)
   u32 start_time, next_expire;
 
   /* Make sure we have all sigs cached.  TODO: This is going to
-     require some architectual re-thinking, as it is agonizingly slow.
+     require some architectural re-thinking, as it is agonizingly slow.
      Perhaps combine this with reset_trust_records(), or only check
      the caches on keys that are actually involved in the web of
      trust. */
   keydb_rebuild_caches(0);
 
+  kdb = keydb_new ();
+  if (!kdb)
+    return gpg_error_from_syserror ();
+
   start_time = make_timestamp ();
   next_expire = 0xffffffff; /* set next expire to the year 2106 */
   stored = new_key_hash_table ();
   used = new_key_hash_table ();
   full_trust = new_key_hash_table ();
 
-  kdb = keydb_new ();
   reset_trust_records();
 
   /* Fixme: Instead of always building a UTK list, we could just build it
@@ -1824,6 +1948,11 @@ validate_keys (int interactive)
       do_sync ();
     }
 
+  if (opt.trust_model == TM_TOFU)
+    /* In the TOFU trust model, we only need to save the ultimately
+       trusted keys.  */
+    goto leave;
+
   klist = utk_list;
 
   log_info(_("%d marginal(s) needed, %d complete(s) needed, %s trust model\n"),
@@ -1970,12 +2099,15 @@ validate_keys (int interactive)
  leave:
   keydb_release (kdb);
   release_key_array (keys);
-  release_key_items (klist);
+  if (klist != utk_list)
+    release_key_items (klist);
   release_key_hash_table (full_trust);
   release_key_hash_table (used);
   release_key_hash_table (stored);
   if (!rc && !quit) /* mark trustDB as checked */
     {
+      int rc2;
+
       if (next_expire == 0xffffffff || next_expire < start_time )
         tdbio_write_nextcheck (0);
       else
@@ -1985,11 +2117,12 @@ validate_keys (int interactive)
                     strtimestamp (next_expire));
         }
 
-      if(tdbio_update_version_record()!=0)
+      rc2 = tdbio_update_version_record ();
+      if (rc2)
        {
-         log_error(_("unable to update trustdb version record: "
-                     "write failed: %s\n"), gpg_strerror (rc));
-         tdbio_invalid();
+         log_error (_("unable to update trustdb version record: "
+                       "write failed: %s\n"), gpg_strerror (rc2));
+         tdbio_invalid ();
        }
 
       do_sync ();
index 771a821..718f779 100644 (file)
 #define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
 #define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
 
+/* Private value used in tofu.c - must be different from the trust
+   values.  */
+#define _tofu_GET_TRUST_ERROR 100
+
+/* Length of the hash used to select UIDs in keyedit.c.  */
 #define NAMEHASH_LEN  20
 
 
@@ -86,7 +91,8 @@ void revalidation_mark (void);
 void check_trustdb_stale (void);
 void check_or_update_trustdb (void);
 
-unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid);
+unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid,
+                          PKT_signature *sig, int may_ask);
 int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
 const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
 
@@ -105,6 +111,8 @@ void clean_key (kbnode_t keyblock, int noisy, int self_only,
 /*-- trustdb.c --*/
 void tdb_register_trusted_keyid (u32 *keyid);
 void tdb_register_trusted_key (const char *string);
+/* Returns whether KID is on the list of ultimately trusted keys.  */
+int tdb_keyid_is_utk (u32 *kid);
 void check_trustdb (void);
 void update_trustdb (void);
 int setup_trustdb( int level, const char *dbname );
@@ -120,7 +128,8 @@ void tdb_check_or_update (void);
 int tdb_cache_disabled_value (PKT_public_key *pk);
 
 unsigned int tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
-                                    PKT_public_key *main_pk);
+                                    PKT_public_key *main_pk,
+                                   PKT_signature *sig, int may_ask);
 
 void list_trust_path( const char *username );
 int enum_cert_paths( void **context, ulong *lid,
index 152cf36..e17d099 100644 (file)
@@ -37,7 +37,6 @@ g13_SOURCES = \
        create.c create.h \
        mount.c mount.h \
        mountinfo.c mountinfo.h \
-       call-gpg.c call-gpg.h \
        runner.c runner.h \
        backend.c backend.h \
        be-encfs.c be-encfs.h \
index 58ab590..91b290c 100644 (file)
@@ -33,7 +33,7 @@
 #include "keyblob.h"
 #include "backend.h"
 #include "utils.h"
-#include "call-gpg.h"
+#include "../common/call-gpg.h"
 
 /* Create a new blob with all the session keys and other meta
    information which are to be stored encrypted in the crypto
@@ -111,7 +111,9 @@ encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
   gpg_error_t err;
 
   /* FIXME:  For now we only implement OpenPGP.  */
-  err = gpg_encrypt_blob (ctrl, keyblob, keybloblen, keys,
+  err = gpg_encrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
+                          keyblob, keybloblen,
+                          keys,
                           r_encblob, r_encbloblen);
 
   return err;
@@ -119,7 +121,7 @@ encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
 
 
 /* Write a new file under the name FILENAME with the keyblob and an
-   appropriate header.  This fucntion is called with a lock file in
+   appropriate header.  This function is called with a lock file in
    place and after checking that the filename does not exists.  */
 static gpg_error_t
 write_keyblob (const char *filename,
index f27dca4..316b94a 100644 (file)
@@ -30,6 +30,7 @@
 #include "../common/util.h"
 #include "../common/status.h"
 #include "../common/session-env.h"
+#include "../common/strlist.h"
 
 
 /* Debug values and macros.  */
@@ -65,6 +66,9 @@ struct
      filename.  */
   const char *gpg_program;
 
+  /* GPG arguments.  XXX: Currently it is not possible to set them.  */
+  strlist_t gpg_arguments;
+
   /* Environment variables passed along to the engine.  */
   char *display;
   char *ttyname;
index e6c7613..7a8d775 100644 (file)
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -577,6 +577,16 @@ main ( int argc, char **argv)
        }
     }
 
+  /* XXX Construct GPG arguments.  */
+  {
+    strlist_t last;
+    last = append_to_strlist (&opt.gpg_arguments, "-z");
+    last = append_to_strlist (&last, "0");
+    last = append_to_strlist (&last, "--trust-model");
+    last = append_to_strlist (&last, "always");
+    (void) last;
+  }
+
   if (configfp)
     {
       fclose (configfp);
index 8d1c015..e9b9c1b 100644 (file)
@@ -34,7 +34,7 @@
 #include "backend.h"
 #include "utils.h"
 #include "../common/sysutils.h"
-#include "call-gpg.h"
+#include "../common/call-gpg.h"
 #include "mountinfo.h"
 #include "runner.h"
 #include "host2net.h"
@@ -202,7 +202,8 @@ decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
   gpg_error_t err;
 
   /* FIXME:  For now we only implement OpenPGP.  */
-  err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
+  err = gpg_decrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
+                          enckeyblob, enckeybloblen,
                           r_keyblob, r_keybloblen);
 
   return err;
index e2de8d9..085fb86 100644 (file)
@@ -118,7 +118,7 @@ mountinfo_del_mount (const char *container, const char *mountpoint,
   mtab_t m;
 
   /* If a container or mountpint is givem search the RID via the
-     standard find fucntion.  */
+     standard find function.  */
   if (container || mountpoint)
     {
       err = mountinfo_find_mount (container, mountpoint, &rid);
index ef72148..556605a 100644 (file)
@@ -54,7 +54,7 @@
 
 ** The OpenPGP and X.509 blobs
 
-   The OpenPGP and X.509 blobs are very similiar, things which are
+   The OpenPGP and X.509 blobs are very similar, things which are
    X.509 specific are noted like [X.509: xxx]
 
    - u32  Length of this blob (including these 4 bytes)
index 21d6038..eaf7565 100644 (file)
@@ -45,7 +45,7 @@ ftello (FILE *stream)
 
 
 
-/* Read a block at the current postion and return it in r_blob.
+/* Read a block at the current position and return it in r_blob.
    r_blob may be NULL to simply skip the current block.  */
 int
 _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
index 0d4800e..e91911c 100644 (file)
@@ -24,8 +24,8 @@
 #include <unistd.h>
 #include <assert.h>
 
-#include "../common/mischelp.h"
 #include "keybox-defs.h"
+#include "../common/mischelp.h"
 
 static KB_NAME kb_names;
 
@@ -228,7 +228,7 @@ keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
 
 
 /* Close the file of the resource identified by HD.  For consistent
-   results this fucntion closes the files of all handles pointing to
+   results this function closes the files of all handles pointing to
    the resource identified by HD.  */
 void
 _keybox_close_file (KEYBOX_HANDLE hd)
index fd8ffe4..741f2e8 100644 (file)
@@ -70,7 +70,7 @@ struct keydb_search_desc
   union {
     const char *name;
     unsigned char fpr[24];
-    u32 kid[2]; /* Note that this is in native endianess.  */
+    u32 kid[2]; /* Note that this is in native endianness.  */
     unsigned char grip[20];
   } u;
   int exact;    /* Use exactly this key ('!' suffix in gpg).  */
index cb07c97..f3cdb8c 100644 (file)
@@ -171,7 +171,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
 
 
 
-/* Return one of the flags WHAT in VALUE from teh blob BUFFER of
+/* Return one of the flags WHAT in VALUE from the blob BUFFER of
    LENGTH bytes.  Return 0 on success or an raw error code. */
 static gpg_err_code_t
 get_flag_from_image (const unsigned char *buffer, size_t length,
@@ -431,7 +431,7 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
   if (namelen < 1)
     return 0;
 
-  /* Note that for X.509 we start at index 1 becuase index 0 is used
+  /* Note that for X.509 we start at index 1 because index 0 is used
      for the issuer name.  */
   for (idx=!!x509 ;idx < nuids; idx++)
     {
index 4b14b2f..ef3e330 100644 (file)
@@ -80,7 +80,7 @@ create_tmp_file (const char *template,
 
 # ifdef USE_ONLY_8DOT3
   /* Here is another Windoze bug?:
-   * you cant rename("pubring.kbx.tmp", "pubring.kbx");
+   * you can't rename("pubring.kbx.tmp", "pubring.kbx");
    * but       rename("pubring.kbx.tmp", "pubring.aaa");
    * works.  So we replace ".kbx" by ".kb_" or ".k__".  Note that we
    * can't use ".bak" and ".tmp", because these suffixes are used by
@@ -603,7 +603,7 @@ keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
 
   ec = 0;
   if (fseeko (fp, off, SEEK_SET))
-    ec = gpg_error_from_syserror ();
+    ec = gpg_err_code_from_syserror ();
   else
     {
       unsigned char tmp[4];
index 09c6ec4..dc88448 100644 (file)
@@ -15,7 +15,6 @@ agent/cvt-openpgp.c
 common/exechelp-posix.c
 common/exechelp-w32.c
 common/exechelp-w32ce.c
-common/http.c
 common/simple-pwquery.c
 common/sysutils.c
 common/yesno.c
@@ -110,6 +109,7 @@ dirmngr/crlfetch.c
 dirmngr/dirmngr-client.c
 dirmngr/dirmngr.c
 dirmngr/dirmngr_ldap.c
+dirmngr/http.c
 dirmngr/ldap-wrapper-ce.c
 dirmngr/ldap-wrapper.c
 dirmngr/ldap.c
index 9835369..8f35c3b 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -1628,6 +1628,10 @@ msgstr "no s'ha trobat la clau «%s»: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "s'ha produït un error en llegir el bloc de claus: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "no s'ha trobat la clau «%s»: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(a no ser que especifiqueu la clau per la empremta digital)\n"
 
@@ -1850,6 +1854,19 @@ msgid "No fingerprint"
 msgstr "Empremta digital:"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "no s'ha trobat la clau secreta «%s»: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opcions d'importació no vàlides\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOM|usa NOM com a clau secreta predeterminada"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "La clau invàlida %08lX s'ha fet vàlida amb --allow-non-selfsigned-uid\n"
@@ -1984,6 +2001,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "crea eixida amb armadura ascii"
 
@@ -2197,12 +2217,49 @@ msgstr "mostra en quin anell de claus està una clau llistada"
 msgid "show expiration dates during signature listings"
 msgstr "No hi ha cap signatura corresponent en l'anell secret\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "desactiva una clau"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "el destinatari predeterminat és desconegut «%s»\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "el destinatari predeterminat és desconegut «%s»\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTA: es descarta el fitxer d'opcions predeterminades antic «%s»\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "error en crear l'anell «%s»: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2412,6 +2469,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "AVÍS: s'han donat destinataris (-r) sense usar xifratge de clau pública\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "l'algoritme de dispersió és invàlid «%s»\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "l'algoritme de dispersió és invàlid «%s»\n"
+
 msgid "--store [filename]"
 msgstr "--store [nom_del_fitxer]"
 
@@ -2508,6 +2573,14 @@ msgstr "no s'ha pogut crear l'armadura: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "l'algoritme de dispersió és invàlid «%s»\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "error en la creació de la contrasenya: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nom_del_fitxer]"
 
@@ -2812,6 +2885,20 @@ msgstr "s'està escrivint la clau secreta a «%s»\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "clau %08lX: clau secreta amb xifrat %d no vàlid - es descarta\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2955,6 +3042,10 @@ msgstr "s'ha creat l'anell «%s»\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "error en crear «%s»: %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "error en la lectura de «%s»: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "no s'ha pogut reconstruir la memòria cau de l'anell: %s\n"
@@ -3022,6 +3113,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "L'ID d'usuari «%s» està revocat."
 
@@ -3379,6 +3474,10 @@ msgstr "La clau està revocada."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Realment voleu signar tots els ID d'usuari? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Realment voleu signar tots els ID d'usuari? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Pista: Trieu els ID d'usuari que voleu signar\n"
 
@@ -3492,10 +3591,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "La clau no ha canviat, per tant no cal actualització.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "no s'ha trobat la clau secreta «%s»: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "error: l'empremta digital és invàlida\n"
 
@@ -3716,8 +3811,11 @@ msgstr ""
 "Esteu segur que voleu nominar aquesta clau com a revocador designat? (s/N): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Per favor, seleccioneu com a molt una clau secundària.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Esteu segur que voleu nominar aquesta clau com a revocador designat? (s/N): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3773,6 +3871,10 @@ msgid "No user ID with hash %s\n"
 msgstr "No hi ha cap ID amb l'índex %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "No hi ha cap ID amb l'índex %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "No hi ha cap ID amb l'índex %d\n"
 
@@ -4133,6 +4235,10 @@ msgstr "Nom i cognoms: "
 msgid "Invalid character in name\n"
 msgstr "Hi ha un caràcter invàlid en el camp *nom*\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "El nom no pot començar amb un dígit\n"
 
@@ -4583,10 +4689,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "AVÍS: el missatge xifrat ha estat manipulat!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "ha fallat el desxifratge: %s\n"
 
@@ -4789,6 +4891,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "la classe de signatura és desconeguda"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "El fitxer «%s» existeix. "
@@ -5275,6 +5381,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Aquesta és una clau de revocació sensible)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "La clau secreta està disponible.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Voleu crear un certificat de revocació per a aquesta clau? "
 
@@ -5309,6 +5420,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "no s'ha trobat la clau secreta «%s»: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Voleu crear un certificat de revocació per a aquesta clau? "
@@ -7419,7 +7541,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "error en la lectura de «%s»: %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "no s'ha trobat la clau secreta «%s»: %s\n"
 
 #, fuzzy, c-format
@@ -7492,6 +7614,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "no s'ha pogut connectar amb «%s»: %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "ha fallat l'actualització: %s\n"
@@ -7529,32 +7656,6 @@ msgstr "no es pot fer stat de «%s»: %s\n"
 msgid "error writing base64 encoding: %s\n"
 msgstr "s'ha produït un error mentre s'escrivia l'anell secret «%s»: %s\n"
 
-#, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: no s'ha pogut crear la taula de dispersió: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "la variable d'entorn GPG_AGENT_INFO és malformada\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "la versió %d del protocol de gpg-agent no està suportada\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "no s'ha pogut connectar amb «%s»: %s\n"
-
 # Suportats? ivb
 # A Softcatalà diuen molt «implementat». jm
 # Precissament acabem de parlar d'«implementat a la llista del GNOME
@@ -7652,7 +7753,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7970,8 +8071,9 @@ msgstr "error en la lectura de «%s»: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "no s'ha trobat la clau secreta «%s»: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8129,6 +8231,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "no s'ha pogut crear «%s»: %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: no s'ha pogut crear la taula de dispersió: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "no s'ha pogut inicialitzar la base de dades de confiança: %s\n"
@@ -8337,7 +8443,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8595,6 +8701,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "no s'ha pogut obrir l'anell"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Per favor, seleccioneu com a molt una clau secundària.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "la variable d'entorn GPG_AGENT_INFO és malformada\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "la versió %d del protocol de gpg-agent no està suportada\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "canvia entre el llistat de claus secretes i públiques"
 
@@ -8780,10 +8916,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Esteu segur de voler fer açò? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "error en llegir el bloc de claus secretes «%s»: %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Per favor, elimineu les seleccions de les claus secretes.\n"
 
@@ -9435,9 +9567,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "l'algoritme de xifratge és desconegut"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "no s'ha pogut obrir l'anell"
-
 #~ msgid "invalid packet"
 #~ msgstr "el paquet és invàlid"
 
index 9ae7333..06f7662 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -1517,6 +1517,11 @@ msgstr "klíč „%s“ nenalezen: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "chyba při čtení bloku klíče: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "klíč „%s“ nenalezen: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(dokud neurčíte klíč jeho otiskem)\n"
 
@@ -1711,6 +1716,20 @@ msgstr "chyba při získávání „%s“ přes %s: %s\n"
 msgid "No fingerprint"
 msgstr "Chybí otisk"
 
+#, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "tajný klíč „%s“ nenalezen: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "postrádám argument u volby „%.50s“\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NÁZEV|použít NÁZEV jako implicitní tajný klíč"
+
 # c-format
 #, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
@@ -1833,6 +1852,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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "vytvoř výstup zakódovaný pomocí ASCII"
 
@@ -2033,11 +2055,52 @@ msgstr "ukazovat název souboru s klíči při výpisu klíčů"
 msgid "show expiration dates during signature listings"
 msgstr "ukazovat data expirace během výpisu podpisů"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Dostupné klíče:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option '%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "neznámá volba „%s“\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command '%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "neznámý příkaz „%s“\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "Poznámka: starý implicitní soubor s možnostmi „%s“ ignorován\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "volba „%.50s“ není jednoznačná\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "chyba při vytváření souboru klíčů (keyring) „%s“: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt je příliš stará (potřebuji %s, mám %s)\n"
 
@@ -2234,6 +2297,16 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "VAROVÁNÍ: specifikován adresát (-r) bez použití šifrování s veřejným klíčem\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "řádek %d: zadáno neplatné datum\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "řádek %d: zadáno neplatné datum\n"
+
 msgid "--store [filename]"
 msgstr "--store [jméno souboru]"
 
@@ -2326,6 +2399,15 @@ msgstr "kódování do ASCII formátu selhalo: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "neplatný hashovací algoritmus „%s“\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "chyba při zavádění certifikátu „%s“: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[jméno souboru]"
 
@@ -2625,6 +2707,20 @@ msgstr "import tajných klíčů není povolen\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "klíč %s: tajný klíč s neplatnou šifrou %d – přeskočeno\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "klíč %s: chybí veřejný klíč – nemohu aplikovat revokační certifikát\n"
@@ -2751,6 +2847,11 @@ msgstr "soubor klíčů (keyring) „%s“ vytvořen\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "zdroj bloku klíče „%s“: %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "chyba při otevírání „%s“: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "selhalo obnovení vyrovnávací paměti klíčů: %s\n"
@@ -2823,6 +2924,10 @@ msgstr ""
 "podpis bez omezení na doménu.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Uživatelské ID „%s“ je revokováno."
 
@@ -3125,6 +3230,11 @@ msgstr "Klíč revokován."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Opravdu podepsat všechny id uživatele? (a/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Opravdu podepsat všechny id uživatele? (a/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Nápověda: Vyberte id uživatele k podepsání\n"
 
@@ -3223,10 +3333,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Klíč nebyl změněn, takže není potřeba jej aktualizovat.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "tajný klíč „%s“ nenalezen: %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "„%s“ není otisk\n"
 
@@ -3424,8 +3530,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "Jste si jistí, že tento klíč chcete pověřit revokací? (a/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Prosím, vyberte nejvýše jeden podklíč.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Jste si jistí, že tento klíč chcete pověřit revokací? (a/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Měním dobu expirace podklíče.\n"
@@ -3474,6 +3585,11 @@ msgstr "Neexistuje identifikátor uživatele s indexem %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Neexistuje uživatelské ID s hashem %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Neexistuje podklíč s indexem %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Neexistuje podklíč s indexem %d\n"
@@ -3816,6 +3932,10 @@ msgstr "Jméno a příjmení: "
 msgid "Invalid character in name\n"
 msgstr "Neplatný znak ve jméně\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Jméno nemůže začínat číslicí\n"
 
@@ -4244,10 +4364,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "VAROVÁNÍ: se zašifrovanou zprávou bylo manipulováno!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "vymazané heslo zapamatované pro ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "dešifrování selhalo: %s\n"
 
@@ -4437,6 +4553,11 @@ msgstr ""
 "U veřejného klíče ECDSA se očekává, že v kódování SEC bude délka násobkem 8 "
 "bitů\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Neznámý typ podpisu „%s“\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "Soubor „%s“ existuje. "
@@ -4880,6 +5001,11 @@ msgstr "Revokován:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Toto je citlivý revokační klíč)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Tajný klíč je dostupný.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Vytvořit pro tento klíč pověřený revokační certifikát? (a/N)"
 
@@ -4919,6 +5045,18 @@ msgstr ""
 "vložena dvojtečka. Před použitím tohoto revokačního certifikátu odstraňte\n"
 "tuto dvojtečku textovým editorem."
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "tajný klíč „%s“ nenalezen: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Vytvořit pro tento klíč revokační certifikát? (a/N) "
 
@@ -6930,7 +7068,7 @@ msgstr "chyba při získávání „%s“: status HTTP je %u\n"
 # Poslední argument je název protokolu
 #, fuzzy
 #| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "Přístup k CRL není možný kvůli vypnutému %s\n"
 
 #, c-format
@@ -6996,6 +7134,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "certifikát je příliš velký, než aby dával smysl\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "k dirmngr se nelze připojit: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "hledání selhalo: %s\n"
 
@@ -7029,31 +7171,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "chyba při zápisu kódování base64: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "alokace kontextu assuan selhala: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "dirmngr zjevně neběží\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "žádný dirmngr neběží – jeden bude spuštěn\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "špatně utvořená proměnná prostředí %s\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "verze %d protokolu dirmngr není podporována\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "k dirmngr se nelze připojit – zkusí se náhradní postup\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "k dirmngr se nelze připojit: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "nepodporovaný dotaz „%s“\n"
 
@@ -7139,7 +7256,7 @@ msgstr "|N|nevrací více jak N položek na jeden dotaz"
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|SOUBOR|pro HKP přes TLS použije certifikáty CA ze SOUBORU"
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 msgid ""
@@ -7435,7 +7552,7 @@ msgstr "odpověď serveru je příliš velká, limit je %d bajtů\n"
 
 #, fuzzy
 #| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
+msgid "OCSP request not possible due to Tor mode\n"
 msgstr "OCSP dotaz není možný, protože HTTP je zakázáno\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
@@ -7590,6 +7707,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "řídící strukturu nelze alokovat: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "alokace kontextu assuan selhala: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "inicializace serveru selhala: %s\n"
 
@@ -7786,7 +7907,7 @@ msgstr "Volby ovlivňující interaktivitu a vymáhání"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Volby ovlivňující bezpečnost"
 
 msgid "Configuration for HTTP servers"
@@ -8037,6 +8158,47 @@ msgstr ""
 "Syntaxe: gpg-check-pattern [volby] soubor_se_vzorem\n"
 "Prověří heslo zadané na vstupu proti souboru se vzory\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "vymazané heslo zapamatované pro ID: %s\n"
+
+#, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "nemohu otevřít soubor klíčů"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ msgstr "„%s“ nebylo možné otevřít: %s\n"
+
+#, fuzzy
+#~| msgid "invalid value\n"
+#~ msgid "invalid value '%s'\n"
+#~ msgstr "neplatná hodnota\n"
+
+#, fuzzy
+#~| msgid "error reading secret keyblock \"%s\": %s\n"
+#~ msgid "error looking up secret key \"%s\": %s\n"
+#~ msgstr "chyba při čtení bloku tajného klíče „%s“: %s\n"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Prosím, vyberte nejvýše jeden podklíč.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "dirmngr zjevně neběží\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "žádný dirmngr neběží – jeden bude spuštěn\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "špatně utvořená proměnná prostředí %s\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "verze %d protokolu dirmngr není podporována\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "k dirmngr se nelze připojit – zkusí se náhradní postup\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "exportovat klíče ve formátu postaveném na S-výrazech"
 
@@ -8589,9 +8751,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Opravdu to chcete udělat? (a/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "chyba při čtení bloku tajného klíče „%s“: %s\n"
-
 #~ msgid "update secret failed: %s\n"
 #~ msgstr "aktualizace tajného klíče selhala: %s\n"
 
@@ -9246,9 +9405,6 @@ msgstr ""
 #~ msgid "checksum error"
 #~ msgstr "chyba kontrolního součtu"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "nemohu otevřít soubor klíčů"
-
 #~ msgid "invalid packet"
 #~ msgstr "neplatný paket"
 
index 3b699db..dc74dff 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -1596,6 +1596,11 @@ msgstr "nøglen »%s« blev ikke fundet: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "fejl ved læsning af nøgleblok: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "nøglen »%s« blev ikke fundet: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(med mindre du angiver nøglen med fingeraftryk)\n"
 
@@ -1804,6 +1809,20 @@ msgid "No fingerprint"
 msgstr "Ingen fingeraftryk"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "hemmelig nøgle »%s« blev ikke fundet: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "manglende parameter for indstilling »%.50s«\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAME|brug NAVN som hemmelig standardnøgle"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Ugyldig nøgle %s gjort gyldig med --allow-non-selfsigned-uid\n"
 
@@ -1930,6 +1949,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "opret ascii-pansrede uddata"
 
@@ -2145,12 +2167,53 @@ msgstr "vis nøgleringsnavnet i nøglevisninger"
 msgid "show expiration dates during signature listings"
 msgstr "vis udløbsdatoer under underskriftvisninger"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Tilgængelige nøgler:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "ukendt tilvalg »%s«\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command `%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "ukendt kommando »%s«\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "BEMÆRK: Gammel standardfil for tilvalg »%s« blev ignoreret\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "tilvalg »%.50s« er tvetydigt\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "fejl ved oprettelse af nøglering »%s«: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt er for gammel (kræver %s, har %s)\n"
 
@@ -2352,6 +2415,16 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "ADVARSEL: modtagere (-r) angivet uden brug af offentlig nøglekryptering\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "linje %d: ugyldig algoritme\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "linje %d: ugyldig algoritme\n"
+
 msgid "--store [filename]"
 msgstr "--store [filnavn]"
 
@@ -2446,6 +2519,15 @@ msgstr "påklædning af panser mislykkedes: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "ugyldig hash-algoritme »%s«\n"
 
+#, fuzzy, c-format
+#| msgid "error storing certificate: %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "fejl ved lagring af certifikat: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[filnavn]"
 
@@ -2751,6 +2833,20 @@ msgstr "import af hemmelige nøgler er ikke tilladt\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "nøgle %s: hemmelig nøgle med ugyldig chiffer %d - udeladt\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2885,6 +2981,11 @@ msgstr "nøglering »%s« oprettet\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "nøgleblokressource »%s«: %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening `%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "fejl ved åbning af »%s«: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "kunne ikke genbygge nøgleringsmellemlager: %s\n"
@@ -2956,6 +3057,10 @@ msgstr ""
 "for ingen.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Bruger-id »%s« er tilbagekaldt."
 
@@ -3282,6 +3387,11 @@ msgstr "Nøglen er tilbagekaldt."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Vil du gerne underskrive alle bruger-id'er (j/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Vil du gerne underskrive alle bruger-id'er (j/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Fif: Vælg bruger-id'erne at underskrive\n"
 
@@ -3382,10 +3492,6 @@ msgstr "opdatering mislykkedes: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Nøgle ikke ændret så ingen opdatering krævet.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "hemmelig nøgle »%s« blev ikke fundet: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3597,8 +3703,15 @@ msgstr ""
 "Er du sikker på, at du ønsker at udpege denne nøgle som en dedikeret "
 "tilbagekalder? (j/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Vælg venligst højst en undernøgle.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Er du sikker på, at du ønsker at udpege denne nøgle som en dedikeret "
+"tilbagekalder? (j/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Ændrer udløbstidspunkt for en undernøgle.\n"
@@ -3648,6 +3761,11 @@ msgstr "Ingen bruger-id med indeks %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Ingen bruger-id med hash %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Ingen undernøgle med indeks %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Ingen undernøgle med indeks %d\n"
@@ -4003,6 +4121,10 @@ msgstr "Fødselsnavn: "
 msgid "Invalid character in name\n"
 msgstr "Ugyldige bogstaver i navn\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Navn må ikke starte med et tal\n"
 
@@ -4442,10 +4564,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "ADVARSEL: krypteret besked er blevet manipuleret!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "ryddet adgangsfrase mellemlagret med id: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "afkryptering mislykkedes: %s\n"
 
@@ -4645,6 +4763,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA kræver at hashlængden skal gå op i 8 bit\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Ukendt underskrifttype »%s«\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Filen »%s« findes. "
@@ -5121,6 +5244,11 @@ msgstr "Tilbagekaldes af:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Dette er en sensitiv tilbagekaldsnøgle)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Hemmelig nøgle er tilgængelig.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Opret et designet tilbagekaldscertifikat for denne nøgle? (j/N) "
 
@@ -5156,6 +5284,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "hemmelig nøgle »%s« blev ikke fundet: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Opret et tilbagekaldscertifikat for denne nøgle? (j/N) "
 
@@ -7297,7 +7437,7 @@ msgstr "fejl ved kørsel af »%s«: afslutningsstatus %d\n"
 
 #, fuzzy
 #| msgid "certificate `%s' not found: %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "certifikat »%s« blev ikke fundet: %s\n"
 
 #, fuzzy, c-format
@@ -7378,6 +7518,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "kan ikke forbinde til »%s«: %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "opdatering mislykkedes: %s\n"
@@ -7420,36 +7565,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "fejl ved skrivning af hemmelig nøglering »%s«: %s\n"
 
 #, fuzzy, c-format
-#| msgid "failed to create stream from socket: %s\n"
-msgid "failed to allocate assuan context: %s\n"
-msgstr "kunne ikke oprette strøm fra sokkel: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-#, fuzzy
-#| msgid "no running dirmngr - starting `%s'\n"
-msgid "no running dirmngr - starting one\n"
-msgstr "ingen kørende dirmngr - starter »%s«\n"
-
-#, fuzzy, c-format
-#| msgid "malformed DIRMNGR_INFO environment variable\n"
-msgid "malformed %s environment variable\n"
-msgstr "forkert udformet DIRMNGR_INFO-miljøvariabel\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "dirmngr-protokolversion %d er ikke understøttet\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "kan ikke forbinde til dirmngr - forsøger reserve\n"
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "kan ikke forbinde til »%s«: %s\n"
-
-#, fuzzy, c-format
 #| msgid "unsupported algorithm: %s"
 msgid "unsupported inquiry '%s'\n"
 msgstr "ikke understøttet algoritme: %s"
@@ -7552,7 +7667,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7900,8 +8015,10 @@ msgstr "fejl ved læsning fra %s: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Fejl: Privat DO er for lang (begrænsningen er %d tegn).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+#| msgid "certificate `%s' not found: %s\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "certifikat »%s« blev ikke fundet: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8085,6 +8202,11 @@ msgid "can't allocate control structure: %s\n"
 msgstr "kan ikke allokere outfile-streng: %s\n"
 
 #, fuzzy, c-format
+#| msgid "failed to create stream from socket: %s\n"
+msgid "failed to allocate assuan context: %s\n"
+msgstr "kunne ikke oprette strøm fra sokkel: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "kunne ikke initialisere TrustDB: %s\n"
@@ -8308,7 +8430,7 @@ msgstr "Tilvalg der kontrollerer interaktiviteten og tvang"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Tilvalg der kontrollerer sikkerheden"
 
 msgid "Configuration for HTTP servers"
@@ -8578,6 +8700,48 @@ msgstr ""
 "Syntaks: gpg-check-pattern [tilvalg] mønsterfil\n"
 "Kontroller en adgangsfrase angivet på stdin mod mønsterfilen\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "ryddet adgangsfrase mellemlagret med id: %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "kunne ikke gemme nøglen: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open `%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Vælg venligst højst en undernøgle.\n"
+
+#, fuzzy
+#~| msgid "no running dirmngr - starting `%s'\n"
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "ingen kørende dirmngr - starter »%s«\n"
+
+#, fuzzy
+#~| msgid "malformed DIRMNGR_INFO environment variable\n"
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "forkert udformet DIRMNGR_INFO-miljøvariabel\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "dirmngr-protokolversion %d er ikke understøttet\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "kan ikke forbinde til dirmngr - forsøger reserve\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "eksporter nøgler i et S-udtryksbaseret format"
 
@@ -8754,9 +8918,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Vil du virkelig gerne gøre dette? (j/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "fejl ved læsning af hemmelig nøgleblok »%s«: %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Fjern venligst markeringer fra de hemmelige nøgler.\n"
 
index 9a0adf3..7d3e301 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: 2015-10-06 12:50+0200\n"
+"PO-Revision-Date: 2015-12-03 17:23+0100\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -1502,6 +1502,10 @@ msgstr "Schlüssel \"%s\" nicht gefunden: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "Fehler beim Lesen des Schlüsselblocks: %s\n"
 
+#, c-format
+msgid "key \"%s\" not found\n"
+msgstr "Schlüssel \"%s\" nicht gefunden\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(es sei denn, Sie geben den Schlüssel mittels Fingerprint an)\n"
 
@@ -1703,6 +1707,18 @@ msgid "No fingerprint"
 msgstr "Kein Fingerabdruck vorhanden"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "Geheimer Schlüssel \"%s\" nicht gefunden: %s\n"
+
+#, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "(Prüfe das Argument der Option '%s')\n"
+
+#, c-format
+msgid "using \"%s\" as default secret key\n"
+msgstr "\"%s\" wird als voreingestellter geheimer Schlüssel benutzt\n"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Ungültiger Schlüssel %s, gültig gemacht per --allow-non-selfsigned-uid\n"
@@ -1822,6 +1838,11 @@ 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 "create ascii armored output"
 msgstr "Ausgabe mit ASCII-Hülle versehen"
 
@@ -2019,11 +2040,48 @@ msgstr "Anzeigen des Schlüsselbundes, in dem ein Schlüssel drin ist"
 msgid "show expiration dates during signature listings"
 msgstr "Das Ablaufdatum mit den Signaturen anlisten"
 
+msgid "available TOFU policies:\n"
+msgstr "Vorhandene TOFU Regeln:\n"
+
+#, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "Unbekannte TOFU Regel '%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr "(\"help\" um mögliche Werte anzuzeigen)\n"
+
+#, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "Unbekanntes TOFU DB Format '%s'\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "Hinweis: Alte voreingestellte Optionendatei '%s' wurde ignoriert\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+"WARNUNG: Der Wert '%s' der Option '%s' sollte eine lange Schlüssel-ID\n"
+"oder ein Fingerabdruck sein\n"
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr "Schlüsselangabe '%s' ist mehrdeutig\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr "'%s' paßt mindest auf:\n"
+
+#, c-format
+msgid "error searching the keyring: %s\n"
+msgstr "Fehler beim Suchen im Schlüsselbund: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 "Die Bibliothek \"libgcrypt\" ist zu alt (benötigt wird %s, vorhanden ist "
@@ -2223,6 +2281,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "WARNUNG: Empfänger (-r) angegeben ohne Verwendung von Public-Key-Verfahren\n"
 
+#, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "Option '%s' ohne gültige Standardschlüssel angegeben\n"
+
+#, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "Option '%s' ohne Verwendung der Option '%s' angegeben\n"
+
 msgid "--store [filename]"
 msgstr "--store [Dateiname]"
 
@@ -2319,6 +2385,16 @@ msgstr "Anbringen der ASCII-Hülle ist fehlgeschlagen: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "Ungültiges Hashverfahren '%s'\n"
 
+#, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "Fehler in der Schlüsselangabe '%s': %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+"'%s\" sieht nicht nach einer gültigen Schlüssel-ID, einem Fingerabdruck oder "
+"einem \"Keygrip\" aus\n"
+
 msgid "[filename]"
 msgstr "[Dateiname]"
 
@@ -2618,6 +2694,21 @@ msgstr ""
 "Schlüssel %s: geheimer Schlüssel mit ungültiger Verschlüsselung %d - "
 "übersprungen\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+"Um '%s' zu migrieren sollte für jede Smartcard \"%s\" aufgerufen werden.\n"
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2751,6 +2842,10 @@ msgid "keyblock resource '%s': %s\n"
 msgstr "Schlüsselblockhilfsmittel`%s': %s\n"
 
 #, c-format
+msgid "error opening key DB: %s\n"
+msgstr "Fehler beim Öffnen der Schlüsseldatenbank: %s\n"
+
+#, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "Schlüsselbund-Cache konnte nicht neu erzeugt werden: %s\n"
 
@@ -2823,6 +2918,10 @@ msgstr ""
 "oder nur die Eingabetaste für keine Domain\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr "Überspringe User-ID \"%s\" da es keine textbasierte ID ist.\n"
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "User-ID \"%s\" ist widerrufen."
 
@@ -3133,6 +3232,9 @@ msgstr "Schlüssel wurde widerrufen."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Wirklich alle User-IDs beglaubigen? (j/N) "
 
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Wirklich alle textbasierten User-IDs beglaubigen? (j/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Tip: Wählen Sie die User-IDs, die beglaubigt werden sollen\n"
 
@@ -3234,10 +3336,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Schlüssel ist nicht geändert worden, also ist kein Speichern nötig.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "Geheimer Schlüssel \"%s\" nicht gefunden: %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" ist kein Fingerabdruck\n"
 
@@ -3445,8 +3543,11 @@ msgstr ""
 "Möchten Sie diesen Schlüssel wirklich als vorgesehenen Widerrufer festlegen? "
 "(j/N): "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Bitte wählen Sie höchstens einen Unterschlüssel aus.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Möchten Sie wirklich die Verfallsdaten aller Unterschlüssel ändern? (j/N): "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Ändern des Verfallsdatums des Unterschlüssels.\n"
@@ -3498,6 +3599,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Keine User-ID mit Hash %s\n"
 
 #, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Kein Unterschlüssel mit Schlüssel-ID '%s'.\n"
+
+#, c-format
 msgid "No subkey with index %d\n"
 msgstr "Kein Unterschlüssel mit Index %d\n"
 
@@ -3839,6 +3944,10 @@ msgstr "Ihr Name (\"Vorname Nachname\"): "
 msgid "Invalid character in name\n"
 msgstr "Ungültiges Zeichen im Namen\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr "Die Zeichen '%s' und '%s' dürfen in einem Namen nicht vorkommen\n"
+
 msgid "Name may not start with a digit\n"
 msgstr "Der Name darf nicht mit einer Ziffer beginnen.\n"
 
@@ -4262,10 +4371,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "WARNUNG: Verschlüsselte Botschaft ist manipuliert worden!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "Passphrase aus dem Cache gelöscht.  Cache ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "Entschlüsselung fehlgeschlagen: %s\n"
 
@@ -4463,6 +4568,10 @@ msgstr ""
 "haben\n"
 
 #, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "Unbekanntes schwache Hashverfahren '%s'\n"
+
+#, c-format
 msgid "File '%s' exists. "
 msgstr "Datei '%s' existiert bereits. "
 
@@ -4936,6 +5045,9 @@ msgstr "Schlüssel soll widerrufen werden von:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Dies ist ein \"sensitiver\" Widerrufsschlüssel)\n"
 
+msgid "Secret key is not available.\n"
+msgstr "Geheimer Schlüssel ist nicht vorhanden.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr ""
 "Ein vorgesehenes Widerrufszertifikat für diesen Schlüssel erzeugen? (j/N) "
@@ -4979,6 +5091,17 @@ msgstr ""
 "unten eingefügt.  Vor dem Import dieses Widerrufszertifikats\n"
 "entfernen Sie bitte dieses Doppelpunkt mittels eines Texteditors."
 
+#, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "Geheimer Schlüssel \"%s\" nicht gefunden\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr "'%s' trifft auf mehrere geheime Schlüssel zu:\n"
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Ein Widerrufszertifikat für diesen Schlüssel erzeugen? (j/N) "
 
@@ -7034,8 +7157,8 @@ msgstr "Fehler beim Holen von `%s': %s\n"
 msgid "error retrieving '%s': http status %u\n"
 msgstr "Fehler beim Holen von `%s': HTTP Status %u\n"
 
-msgid "CRL access not possible due to TOR mode\n"
-msgstr "CRL Zugriff ist im TOR Modus nicht möglich\n"
+msgid "CRL access not possible due to Tor mode\n"
+msgstr "CRL Zugriff ist im Tor Modus nicht möglich\n"
 
 #, c-format
 msgid "certificate search not possible due to disabled %s\n"
@@ -7102,6 +7225,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "Zertifikat ist zu groß um Sinnvoll zu sein\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "Verbindung zum Dirmngr nicht möglich: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "Aufsuchen fehlgeschlagen: %s\n"
 
@@ -7135,31 +7262,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "Fehler beim Schreiben der Base-64 Darstellung: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "Fehler beim Bereitstellen eines Assuan Kontext: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "Offensichtlich ist kein Dirmngr vorhanden\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "Dirmngr läuft nicht - ein neuer wird gestartet\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "Fehlerhafte %s Variable\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "Dirmngr Protocol Version %d wird nicht unterstützt\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "Verbindung zum Dirmngr nicht möglich - Rückfallmethode wird versucht\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "Verbindung zum Dirmngr nicht möglich: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "Nicht unterstützte INQUIRY `%s'\n"
 
@@ -7245,8 +7347,8 @@ msgstr "|N|Nicht mehr als N Angaben in einer Anfrage zurückgeben"
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|DATEI|Benutze die CA Zertifikate in DATEI für HKP über TLS"
 
-msgid "route all network traffic via TOR"
-msgstr "Netzzugriff nur über TOR"
+msgid "route all network traffic via Tor"
+msgstr "Netzzugriff nur über Tor"
 
 msgid ""
 "@\n"
@@ -7541,8 +7643,8 @@ msgstr "Fehler beim Lesen vom Responder: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Antwort vom Server zu lang; die Grenze sind %d Bytes\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr "OCSP Anfrage ist im TOR Modus nicht möglich\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "OCSP Anfrage ist im Tor Modus nicht möglich\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr "OCSP Anfrage nicht möglich da HTTP abgeschaltet ist\n"
@@ -7696,6 +7798,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "Fehler beim Erzeugen der Kontrollstruktur: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "Fehler beim Bereitstellen eines Assuan Kontext: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "Fehler beim Initialisieren des Servers: %s\n"
 
@@ -7895,8 +8001,8 @@ msgstr "Optionen zum Einstellen der Ausgabeformate"
 msgid "Options controlling the interactivity and enforcement"
 msgstr "Optionen zur Einstellung der Interaktivität und Geltendmachung"
 
-msgid "Options controlling the use of TOR"
-msgstr "Optionen zur Benutzung von TOR"
+msgid "Options controlling the use of Tor"
+msgstr "Optionen zur Benutzung von Tor"
 
 msgid "Configuration for HTTP servers"
 msgstr "Konfiguration für HTTP Server"
@@ -8146,6 +8252,47 @@ msgstr ""
 "Syntax: gpg-check-pattern [optionen] Musterdatei\n"
 "Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "Passphrase aus dem Cache gelöscht.  Cache ID: %s\n"
+
+#, fuzzy
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "Fehler beim Öffnen der Schlüsseldatenbank.\n"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ msgstr "Datei `%s' kann nicht geöffnet werden: %s\n"
+
+#, fuzzy
+#~| msgid "invalid value\n"
+#~ msgid "invalid value '%s'\n"
+#~ msgstr "Ungültiger Wert.\n"
+
+#, fuzzy
+#~| msgid "error reading secret keyblock \"%s\": %s\n"
+#~ msgid "error looking up secret key \"%s\": %s\n"
+#~ msgstr "Fehler beim Lesen des geheimen Schlüsselblocks \"%s\": %s\n"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Bitte wählen Sie höchstens einen Unterschlüssel aus.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "Offensichtlich ist kein Dirmngr vorhanden\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "Dirmngr läuft nicht - ein neuer wird gestartet\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "Fehlerhafte %s Variable\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "Dirmngr Protocol Version %d wird nicht unterstützt\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr ""
+#~ "Verbindung zum Dirmngr nicht möglich - Rückfallmethode wird versucht\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "Exportiere Schlüssel in einem auf S-Ausdrücken basierenden Format"
 
@@ -8511,9 +8658,6 @@ msgstr ""
 #~ msgid "Key is protected.\n"
 #~ msgstr "Schlüssel ist geschützt.\n"
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "Fehler beim Lesen des geheimen Schlüsselblocks \"%s\": %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Bitte entfernen Sie die Auswahl von den geheimen Schlüsseln.\n"
 
index 1697cc1..6c79f4c 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -1565,6 +1565,10 @@ msgstr "
 msgid "error reading keyblock: %s\n"
 msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ ìðëïê êëåéäéþí: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "ôï êëåéäß '%s' äå âñÝèçêå: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(åêôüò åÜí ðñïóäéïñßóåôå Ýíá êëåéäß áðü áðïôýðùìá)\n"
 
@@ -1784,6 +1788,19 @@ msgid "No fingerprint"
 msgstr "áðåéêüíéóç ôïõ fingerprint"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "ôï ìõóôéêü êëåéäß `%s' äå âñÝèçêå: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "ìç Ýãêõñåò åðéëïãÝò åéãáãùãÞò\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|ÏÍÏÌÁ|÷ñÞóç ÏÍÏÌÁôïò óáí ðñïêáèïñéóìÝíï ìõóôéêü êëåéäß"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Ìç Ýãêõñï êëåéäß %08lX Ýãéíå Ýãêõñï áðü ôï --allow-non-selfsigned-uid\n"
@@ -1916,6 +1933,9 @@ msgstr "|
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "äçìéïõñãßá ascii èùñáêéóìÝíçò åîüäïõ"
 
@@ -2120,12 +2140,49 @@ msgstr "
 msgid "show expiration dates during signature listings"
 msgstr "Äåí âñÝèçêå áíôßóôïé÷ç õðïãñáöÞ óôç ìõóôéêÞ êëåéäïèÞêç\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "áðåíåñãïðïéåß Ýíá êëåéäß"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "Üãíùóôïò ðñïêáèïñéóìÝíïò ðáñáëÞðôçò `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "Üãíùóôïò ðñïêáèïñéóìÝíïò ðáñáëÞðôçò `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "ÓÇÌÅÉÙÓÇ: áãíïÞèçêå ôï ðáëéü áñ÷åßï ðñïêáèïñéóìÝíùí åðéëïãþí `%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "áäõíáìßá äçìéïõñãßáò ôçò êëåéäïèÞêçò `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2336,6 +2393,14 @@ msgstr ""
 "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: äþèçêáí ðáñáëÞðôåò (-r) ÷þñéò ÷ñÞóç êñõðôïãñÜöçóçò\n"
 "äçìïóßïõ êëåéäéïý\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "ìç Ýãêõñïò áëãüñéèìïò  hash `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "ìç Ýãêõñïò áëãüñéèìïò  hash `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [üíïìá áñ÷åßïõ]"
 
@@ -2432,6 +2497,14 @@ msgstr "
 msgid "invalid hash algorithm '%s'\n"
 msgstr "ìç Ýãêõñïò áëãüñéèìïò  hash `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "óöÜëìá óôç äçìéïõñãßá ôçò öñÜóçò êëåéäß: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[üíïìá áñ÷åßïõ]"
 
@@ -2735,6 +2808,20 @@ msgstr "
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "êëåéäß %08lX: ìõóôéêü êëåéäß ìå Üêõñï êñõðôáëã. %d - ðáñáëåßöèçêå\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2871,6 +2958,10 @@ msgstr "
 msgid "keyblock resource '%s': %s\n"
 msgstr "óöÜëìá êáôÜ ôç äçìéïõñãßá ôïõ `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "áðïôõ÷ßá åðáíáäüìçóçò ôçò cache êëåéäïèÞêçò: %s\n"
@@ -2939,6 +3030,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Ôï user ID \"%s\" áíáêáëåßôå."
 
@@ -3287,6 +3382,10 @@ msgstr "
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Óßãïõñá íá õðïãñáöïýí üëá ôá user ID; "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Óßãïõñá íá õðïãñáöïýí üëá ôá user ID; "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "ÓõìâïõëÞ: ÅðéëÝîôå ôï user ID ãéá õðïãñáöÞ\n"
 
@@ -3400,10 +3499,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Ôï êëåéäß äåí Üëëáîå ïðüôå äåí ÷ñåéÜæåôáé åíçìÝñùóç.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "ôï ìõóôéêü êëåéäß `%s' äå âñÝèçêå: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "óöÜëìá: ìç Ýãêõñï áðïôýðùìá\n"
 
@@ -3621,8 +3716,12 @@ msgstr ""
 "N): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Ðáñáêáëþ åðéëÝîôå ôï ðïëý Ýíá äåõôåñåýïí êëåéäß.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Åßóôå óßãïõñïé üôé èÝëåôå íá ïñßóåôå Ýíá êëåéäß óáí äéïñéóìÝíï áíáêëçôÞ; (y/"
+"N): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3679,6 +3778,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Äåí õðÜñ÷åé user ID ìå äåßêôç %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Äåí õðÜñ÷åé user ID ìå äåßêôç %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Äåí õðÜñ÷åé user ID ìå äåßêôç %d\n"
 
@@ -4033,6 +4136,10 @@ msgstr "
 msgid "Invalid character in name\n"
 msgstr "Ìç Ýãêõñïò ÷áñáêôÞñáò óôï üíïìá\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Ôï üíïìá äåí åðéôñÝðåôáé íá îåêéíÜ ìå áñéèìçôéêü øçößï\n"
 
@@ -4476,10 +4583,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ôï êñõðôïãñáöçìÝíï ìÞíõìá Ý÷åé ðåéñá÷èåß!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "áðïêñõðôïãñÜöçóç áðÝôõ÷å: %s\n"
 
@@ -4679,6 +4782,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "Üãíùóôç êëÜóç õðïãñáöÞò"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Ôï áñ÷åßï `%s' õðÜñ÷åé Þäç. "
@@ -5151,6 +5258,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Áõôü åßíáé Ýíá åõáßóèçôï êëåéäß áíÜêëçóçò)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Ôï ìõóôéêü êëåéäß åßíáé äéáèÝóéìï.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Äçìéïõñãßá åíüò ðéóôïðïéçôéêïý áíÜêëçóçò ãéá áõôü ôï êëåéäß; "
 
@@ -5185,6 +5297,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "ôï ìõóôéêü êëåéäß `%s' äå âñÝèçêå: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Äçìéïõñãßá åíüò ðéóôïðïéçôéêïý áíÜêëçóçò ãéá áõôü ôï êëåéäß; "
@@ -7253,7 +7376,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "ôï êëåéäß '%s' äå âñÝèçêå: %s\n"
 
 #, fuzzy, c-format
@@ -7324,6 +7447,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "áäõíáìßá óýíäåóçò óôï `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "ç åíçìÝñùóç áðÝôõ÷å: %s\n"
@@ -7362,32 +7490,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "áäõíáìßá åããñáöÞò ìõóôéêÞò êëåéäïèÞêçò `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: áäõíáìßá äçìéïõñãßáò hashtable: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "êáêïäéáôõðïìÝíç ìåôáâëçôÞ ðåñéâÜëëïíôïò GPG_AGENT_INFO\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "äåí õðïóôçñßæåôáé ç Ýêäïóç ðñùôïêüëëïõ %d ôïõ gpg-agent\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "áäõíáìßá óýíäåóçò óôï `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7479,7 +7581,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7791,8 +7893,9 @@ msgstr "
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "ôï êëåéäß '%s' äå âñÝèçêå: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7950,6 +8053,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "áäõíáìßá äçìéïõñãßáò ôïõ `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: áäõíáìßá äçìéïõñãßáò hashtable: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "áðïôõ÷ßá áñ÷éêïðïßçóçò ôçò TrustDB: %s\n"
@@ -8158,7 +8265,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8416,6 +8523,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "áäõíáìßá ðñüóâáóçò óôç êëåéäïèÞêç"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Ðáñáêáëþ åðéëÝîôå ôï ðïëý Ýíá äåõôåñåýïí êëåéäß.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "êáêïäéáôõðïìÝíç ìåôáâëçôÞ ðåñéâÜëëïíôïò GPG_AGENT_INFO\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "äåí õðïóôçñßæåôáé ç Ýêäïóç ðñùôïêüëëïõ %d ôïõ gpg-agent\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "áëëáãÞ ìåôáîý ôçò áðåéêüíéóçò ìõóôéêïý êáé äçìüóéïõ êëåéäéïý"
 
@@ -8600,10 +8737,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Óßãïõñá èÝëåôå íá êÜíåôå áõôü; "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ìõóôéêïý ìðëïê êëåéäéïý `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Ðáñáêáëþ áöáéñÝóôå ôéò åðéëïãÝò áðü ôá ìõóôéêÜ êëåéäéÜ.\n"
 
@@ -9243,9 +9376,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "Üãíùóôïò áëãüñéèìïò êñõðôïãñÜöçóçò"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "áäõíáìßá ðñüóâáóçò óôç êëåéäïèÞêç"
-
 #~ msgid "invalid packet"
 #~ msgstr "ìç Ýãêõñï ðáêÝôï"
 
index 93cf465..5439825 100644 (file)
--- a/po/eo.po
+++ b/po/eo.po
@@ -1572,6 +1572,10 @@ msgstr "
 msgid "error reading keyblock: %s\n"
 msgstr "eraro dum legado de þlosilbloko: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "þlosilo '%s' ne trovita: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr ""
 
@@ -1774,6 +1778,19 @@ msgid "No fingerprint"
 msgstr "Fingrospuro:"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "þlosilo '%s' ne trovita: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "nevalida kiraso"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOMO|uzi NOMOn kiel la implicitan sekretan þlosilon"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Nevalida þlosilo %08lX validigita per --always-trust\n"
 
@@ -1905,6 +1922,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "krei eligon en askia kiraso"
 
@@ -2107,11 +2127,48 @@ msgstr "montri, en kiu 
 msgid "show expiration dates during signature listings"
 msgstr "Mankas responda subskribo en sekreta þlosilaro\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "malþalti þlosilon"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "nekonata implicita ricevonto '%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "nekonata implicita ricevonto '%s'\n"
+
 #, fuzzy, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTO: mankas implicita opcio-dosiero '%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "eraro dum kreado de þlosilaro '%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2325,6 +2382,14 @@ msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "nevalida kompendi-metodo '%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "nevalida kompendi-metodo '%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [dosiero]"
 
@@ -2421,6 +2486,14 @@ msgstr "enkirasigo malsukcesis: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "nevalida kompendi-metodo '%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "eraro dum kreado de pasfrazo: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[dosiero]"
 
@@ -2723,6 +2796,20 @@ msgstr "skribas sekretan 
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "þlosilo %08lX: sekreta þlosilo sen publika þlosilo - ignorita\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2850,6 +2937,10 @@ msgstr "
 msgid "keyblock resource '%s': %s\n"
 msgstr "eraro dum kreado de '%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "eraro dum legado de '%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "malsukcesis rekonstrui þlosilaran staplon: %s\n"
@@ -2917,6 +3008,10 @@ msgstr ""
 msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
+#, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Uzantidentigilo \"%s\" estas revokita.\n"
@@ -3279,6 +3374,10 @@ msgstr "
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Æu vere subskribi æiujn uzantidentigilojn? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Æu vere subskribi æiujn uzantidentigilojn? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Sugesto: Elekti la uzantidentigilojn por subskribi\n"
 
@@ -3391,10 +3490,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Þlosilo ne þanøita, do aktualigo ne necesas.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "þlosilo '%s' ne trovita: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "%s: nevalida dosiero-versio %d\n"
 
@@ -3602,8 +3697,10 @@ msgid ""
 msgstr "Æu vi estas certa, ke vi ankoraý volas subskribi øin?\n"
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Bonvolu elekti maksimume unu flankan þlosilon.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Æu vi estas certa, ke vi ankoraý volas subskribi øin?\n"
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3658,6 +3755,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Mankas uzantidentigilo kun indekso %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Mankas uzantidentigilo kun indekso %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Mankas uzantidentigilo kun indekso %d\n"
 
@@ -4014,6 +4115,10 @@ msgstr "Vera nomo: "
 msgid "Invalid character in name\n"
 msgstr "Nevalida signo en nomo\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Nomo ne povas komenciøi per cifero\n"
 
@@ -4459,10 +4564,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "AVERTO: æifrita mesaøo estis manipulita!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "malæifrado malsukcesis: %s\n"
 
@@ -4659,6 +4760,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "nekonata klaso de subskribo"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Dosiero '%s' ekzistas. "
@@ -5120,6 +5225,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr ""
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Sekreta þlosilo estas havebla.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Æu krei revokatestilon por æi tiu subskribo? (j/N)"
 
@@ -5155,6 +5265,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "þlosilo '%s' ne trovita: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Æu krei revokatestilon por æi tiu subskribo? (j/N)"
@@ -7207,7 +7328,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "eraro dum legado de '%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "þlosilo '%s' ne trovita: %s\n"
 
 #, fuzzy, c-format
@@ -7279,6 +7400,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "ne povas konektiøi al '%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "aktualigo malsukcesis: %s\n"
@@ -7317,32 +7443,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "eraro dum skribado de sekreta þlosilaro '%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: malsukcesis krei haktabelon: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "malbona valoro de la media variablo GPG_AGENT_INFO\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "protokolversio %d de gpg-agent ne estas uzebla\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "ne povas konektiøi al '%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7434,7 +7534,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7744,8 +7844,9 @@ msgstr "eraro dum legado de '%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "þlosilo '%s' ne trovita: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7903,6 +8004,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "ne povas krei '%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: malsukcesis krei haktabelon: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
@@ -8111,7 +8216,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8368,6 +8473,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "ne povas malfermi la þlosilaron"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Bonvolu elekti maksimume unu flankan þlosilon.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "malbona valoro de la media variablo GPG_AGENT_INFO\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "protokolversio %d de gpg-agent ne estas uzebla\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "de sekreta aý publika listo iri al la alia"
 
@@ -8525,10 +8660,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Æu vi vere volas fari tion? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "eraro dum legado de sekreta þlosilbloko '%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Bonvolu malelekti la sekretajn þlosilojn.\n"
 
@@ -9096,9 +9227,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "nekonata æifrad-metodo"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "ne povas malfermi la þlosilaron"
-
 #~ msgid "invalid packet"
 #~ msgstr "nevalida paketo"
 
index 223b66e..532323b 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -1614,6 +1614,11 @@ msgstr "clave \"%s\" no encontrada: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "error leyendo bloque de claves: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "clave \"%s\" no encontrada: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(excepto si especifica la clave dando su huella digital)\n"
 
@@ -1823,6 +1828,20 @@ msgid "No fingerprint"
 msgstr "No hay huella dactilar"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "clave secreta \"%s\" no encontrada: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "falta parámetro para la opción \"%.50s\"\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOMBRE|usa NOMBRE como clave secreta por defecto"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Clave %s inválida hecha válida mediante --allow-non-selfsigned-uid\n"
 
@@ -1949,6 +1968,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "crea una salida ascii con armadura"
 
@@ -2171,12 +2193,53 @@ msgstr "mostrar nombre de los anillos de claves al listar claves"
 msgid "show expiration dates during signature listings"
 msgstr "mostrar fechas de caducidad al listar firmas"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Claves disponibles:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "opción desconocida `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command `%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "orden desconocida `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTA: se ignora el antiguo fichero de opciones predefinidas `%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "la opción \"%.50s\" es ambigua\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "error escribiendo anillo `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt demasiado antigua (necesito %s, tengo %s)\n"
 
@@ -2377,6 +2440,16 @@ msgstr "inicializaci
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr "AVISO: se indicaron receptores (-r) sin clave pública de cifrado\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "línea %d: algoritmo inválido\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "línea %d: algoritmo inválido\n"
+
 msgid "--store [filename]"
 msgstr "--store [nombre_fichero]"
 
@@ -2471,6 +2544,15 @@ msgstr "creaci
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritmo de distribución inválido `%s'\n"
 
+#, fuzzy, c-format
+#| msgid "error storing certificate: %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "error almacenando certificado: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nombre_fichero]"
 
@@ -2781,6 +2863,20 @@ msgstr "no se permite importar claves secretas\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "clave %s: clave secreta con cifrado inválido %d - omitida\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2914,6 +3010,11 @@ msgstr "anillo `%s' creado\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "recurso de bloque de claves: `%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening `%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "error abriendo `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "fallo reconstruyendo caché del anillo de claves: %s\n"
@@ -2984,6 +3085,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "Introduzca un dominio para restringir esta firma, o intro para nada.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "ID de usuario \"%s\" revocado."
 
@@ -3293,6 +3398,11 @@ msgstr "La clave est
 msgid "Really sign all user IDs? (y/N) "
 msgstr "¿Firmar realmente todos los IDs de usuario? (s/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "¿Firmar realmente todos los IDs de usuario? (s/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Sugerencia: seleccione los identificadores de usuario que firmar\n"
 
@@ -3394,10 +3504,6 @@ msgstr "actualizaci
 msgid "Key not changed so no update needed.\n"
 msgstr "Clave sin cambios, no se necesita actualización.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "clave secreta \"%s\" no encontrada: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3604,8 +3710,14 @@ msgid ""
 msgstr ""
 "¿Está seguro de querer elegir esta clave como revocador designado? (s/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Por favor, seleccione como máximo una clave secundaria.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"¿Está seguro de querer elegir esta clave como revocador designado? (s/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Cambiando fecha de caducidad de subclave.\n"
@@ -3654,6 +3766,11 @@ msgstr "No hay ning
 msgid "No user ID with hash %s\n"
 msgstr "No hay ID de usuario con hash %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "No existe una subclave con índice %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "No existe una subclave con índice %d\n"
@@ -4005,6 +4122,10 @@ msgstr "Nombre y apellidos: "
 msgid "Invalid character in name\n"
 msgstr "Caracter inválido en el nombre\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "El nombre no puede empezar con un número\n"
 
@@ -4442,10 +4563,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "ATENCIÓN: ¡el mensaje cifrado ha sido manipulado!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "borrada frase de paso en caché con ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "descifrado fallido: %s\n"
 
@@ -4643,6 +4760,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA necesita un resumen cuya longitud sea múltiplo de 8 bits\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Clase de firma desconocida `%s'\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "El fichero `%s' ya existe. "
@@ -5113,6 +5235,11 @@ msgstr "Ser
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Este es una clave de revocación confidencial)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Clave secreta disponible.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "¿Crear un certificado de revocación para esta clave? (s/N)"
 
@@ -5148,6 +5275,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "clave secreta \"%s\" no encontrada: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "¿Crear un certificado de revocación para esta clave? (s/N) "
 
@@ -7313,7 +7452,7 @@ msgstr "error ejecutando `%s': c
 
 #, fuzzy
 #| msgid "certificate `%s' not found: %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "certificado `%s' no encontrado: %s\n"
 
 #, fuzzy, c-format
@@ -7394,6 +7533,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "no se puede conectar con `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "actualización fallida: %s\n"
@@ -7437,36 +7581,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "error escribiendo anillo privado `%s': %s\n"
 
 #, fuzzy, c-format
-#| msgid "failed to create stream from socket: %s\n"
-msgid "failed to allocate assuan context: %s\n"
-msgstr "fallo al crear un flujo desde el socket: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-#, fuzzy
-#| msgid "no running dirmngr - starting `%s'\n"
-msgid "no running dirmngr - starting one\n"
-msgstr "no hay dirmngr en ejecución - iniciando `%s'\n"
-
-#, fuzzy, c-format
-#| msgid "malformed DIRMNGR_INFO environment variable\n"
-msgid "malformed %s environment variable\n"
-msgstr "variable de entorno DIRMNGR_INFO malformada\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "la versión del protocolo dirmngr %d no puede usarse\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "no puedo conectar con el dirmngr - intentando retirada\n"
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "no se puede conectar con `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "unsupported algorithm: %s"
 msgid "unsupported inquiry '%s'\n"
 msgstr "algoritmo no disponible: %s"
@@ -7569,7 +7683,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 # ordenes -> órdenes
@@ -7924,8 +8038,10 @@ msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 "Error: los datos privados son demasiado largos (límite de %d caracteres).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+#| msgid "certificate `%s' not found: %s\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "certificado `%s' no encontrado: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8109,6 +8225,11 @@ msgid "can't allocate control structure: %s\n"
 msgstr "no puedo reservar espacio para la cadena de salida: %s\n"
 
 #, fuzzy, c-format
+#| msgid "failed to create stream from socket: %s\n"
+msgid "failed to allocate assuan context: %s\n"
+msgstr "fallo al crear un flujo desde el socket: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "inicialización de la base de datos de confianza fallida: %s\n"
@@ -8333,7 +8454,7 @@ msgstr "Opciones que controlan la interactividad y obligaci
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Opciones que controlan la seguridad"
 
 msgid "Configuration for HTTP servers"
@@ -8618,6 +8739,58 @@ msgstr ""
 "Compara frase contraseña dada en entrada estándar con un fichero de "
 "patrones\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "borrada frase de paso en caché con ID: %s\n"
+
+# ¿y llavero?
+# Hombre... las claves son parecidas a las llaves pero no lo mismo
+# toda la literatura en castellano usa "anillos de claves" si un
+# programa nos habla del llavero ¿no puedo abrir el llavero? nos
+# miraremos en el bolsillo bastante desconcertados. No creo que se
+# trate de establecer una nomenclatura propia.
+# A lo mejor toda esa literatura está producida por gente que no sabía
+# cómo se dice llavero en inglés...
+# Si los ingleses dicen llavero en su idioma ¿por qué no vamos a poder
+# nosotros decir lo mismo en el nuestro?
+#, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "No se puede abrir el anillo de claves"
+
+#, fuzzy
+#~| msgid "failed to open `%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Por favor, seleccione como máximo una clave secundaria.\n"
+
+#, fuzzy
+#~| msgid "no running dirmngr - starting `%s'\n"
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "no hay dirmngr en ejecución - iniciando `%s'\n"
+
+#, fuzzy
+#~| msgid "malformed DIRMNGR_INFO environment variable\n"
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variable de entorno DIRMNGR_INFO malformada\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "la versión del protocolo dirmngr %d no puede usarse\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "no puedo conectar con el dirmngr - intentando retirada\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "exportar claves en formato basado en una expresión S"
 
@@ -8807,9 +8980,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "¿Realmente quiere hacer esto? (s/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "error leyendo bloque de clave secreta \"%s\": %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Por favor, quite las selecciones de las claves secretas.\n"
 
@@ -9520,19 +9690,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "Algoritmo de cifrado desconocido"
 
-# ¿y llavero?
-# Hombre... las claves son parecidas a las llaves pero no lo mismo
-# toda la literatura en castellano usa "anillos de claves" si un
-# programa nos habla del llavero ¿no puedo abrir el llavero? nos
-# miraremos en el bolsillo bastante desconcertados. No creo que se
-# trate de establecer una nomenclatura propia.
-# A lo mejor toda esa literatura está producida por gente que no sabía
-# cómo se dice llavero en inglés...
-# Si los ingleses dicen llavero en su idioma ¿por qué no vamos a poder
-# nosotros decir lo mismo en el nuestro?
-#~ msgid "can't open the keyring"
-#~ msgstr "No se puede abrir el anillo de claves"
-
 #~ msgid "invalid packet"
 #~ msgstr "paquete inválido"
 
index 2395dd0..3a883d6 100644 (file)
--- a/po/et.po
+++ b/po/et.po
@@ -1562,6 +1562,10 @@ msgstr "v
 msgid "error reading keyblock: %s\n"
 msgstr "viga võtmebloki lugemisel: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "võtit '%s' ei leitud: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(kui te just ei määra võtit sõrmejäljega)\n"
 
@@ -1776,6 +1780,19 @@ msgid "No fingerprint"
 msgstr "näita sõrmejälge"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "salajast võtit `%s' ei leitud: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "vigased impordi võtmed\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NIMI|kasuta NIME vaikimisi salajase võtmena"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Vigane võti %08lX muudeti kehtivaks võtme --allow-non-selfsigned-uid "
@@ -1909,6 +1926,9 @@ msgstr "|algo [failid]|tr
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "loo ascii pakendis väljund"
 
@@ -2110,12 +2130,49 @@ msgstr "n
 msgid "show expiration dates during signature listings"
 msgstr "Vastavat allkirja salajaste võtmete hoidlas pole\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "blokeeri võti"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "tundmatu vaikimisi saaja `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "tundmatu vaikimisi saaja `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "MÄRKUS: ignoreerin vana vaikimisi võtmete faili `%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "viga võtmehoidla `%s' loomisel: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2321,6 +2378,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "HOIATUS: määrati saajad (-r) aga ei kasutata avaliku võtme krüptograafiat\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "vigane räsialgoritm `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "vigane räsialgoritm `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [failinimi]"
 
@@ -2417,6 +2482,14 @@ msgstr "pakendamine eba
 msgid "invalid hash algorithm '%s'\n"
 msgstr "vigane räsialgoritm `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "viga parooli loomisel: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[failinimi]"
 
@@ -2721,6 +2794,20 @@ msgstr "kirjutan salajase v
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "võti %08lX: salajane võti vigase ¨ifriga %d - jätsin vahele\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2850,6 +2937,10 @@ msgstr "v
 msgid "keyblock resource '%s': %s\n"
 msgstr "viga `%s' loomisel: %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "viga `%s' lugemisel: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "võtmehoidla vahemälu uuesti loomine ebaõnnestus: %s\n"
@@ -2918,6 +3009,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Kasutaja ID \"%s\" on tühistatud."
 
@@ -3261,6 +3356,10 @@ msgstr "V
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Kas allkirjastan tõesti kõik kasutaja IDd? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Kas allkirjastan tõesti kõik kasutaja IDd? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Vihje: Valige allkirjastamiseks kasutaja\n"
 
@@ -3373,10 +3472,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Võtit ei muudetud, seega pole uuendamist vaja.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "salajast võtit `%s' ei leitud: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "viga: vigane sõrmejälg\n"
 
@@ -3586,8 +3681,11 @@ msgstr ""
 "Olete kindel, et soovite seda võtit seada määratud tühistajaks? (j/E): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "palun valige ülimalt üks sekundaarne võti.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Olete kindel, et soovite seda võtit seada määratud tühistajaks? (j/E): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3642,6 +3740,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Kasutaja ID numbriga %d puudub\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Kasutaja ID numbriga %d puudub\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Kasutaja ID numbriga %d puudub\n"
 
@@ -3994,6 +4096,10 @@ msgstr "P
 msgid "Invalid character in name\n"
 msgstr "Lubamatu sümbol nimes\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Nimi ei või alata numbriga\n"
 
@@ -4428,10 +4534,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "HOIATUS: krüpteeritud teadet on muudetud!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "lahtikrüpteerimine ebaõnnestus: %s\n"
 
@@ -4628,6 +4730,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "tundmatu allkirja klass"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Fail `%s' on olemas. "
@@ -5091,6 +5197,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(See on tundlik tühistamise võti)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Salajane võti on kasutatav.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Loon sellele võtmele tühistamise sertifikaadi? "
 
@@ -5127,6 +5238,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "salajast võtit `%s' ei leitud: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Loon sellele võtmele tühistamise sertifikaadi? "
@@ -7177,7 +7299,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "viga `%s' lugemisel: %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "võtit '%s' ei leitud: %s\n"
 
 #, fuzzy, c-format
@@ -7248,6 +7370,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "ei õnnestu luua ühendust serveriga `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "uuendamine ebaõnnestus: %s\n"
@@ -7286,32 +7413,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "viga salajase võtme võtmehoidlasse `%s' kirjutamisel: %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: paisktabeli loomine ebaõnnestus: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "vigane GPG_AGENT_INFO keskkonnamuutuja\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "gpg-agendi protokolli versioon %d ei ole toetatud\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "ei õnnestu luua ühendust serveriga `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7403,7 +7504,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7715,8 +7816,9 @@ msgstr "viga `%s' lugemisel: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "võtit '%s' ei leitud: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7874,6 +7976,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "`%s' ei õnnestu luua: %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: paisktabeli loomine ebaõnnestus: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n"
@@ -8082,7 +8188,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8340,6 +8446,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "võtmehoidlat ei õnnestu avada"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "palun valige ülimalt üks sekundaarne võti.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "vigane GPG_AGENT_INFO keskkonnamuutuja\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "gpg-agendi protokolli versioon %d ei ole toetatud\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "lülita salajaste või avalike võtmete loendi vahel"
 
@@ -8513,10 +8649,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Kas te tõesti soovite seda teha? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "viga salajase võtmebloki `%s' lugemisel: %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Palun eemaldage salajastelt võtmetelt valikud.\n"
 
@@ -9134,9 +9266,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "tundmatu ¨ifri algoritm"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "võtmehoidlat ei õnnestu avada"
-
 #~ msgid "invalid packet"
 #~ msgstr "vigane pakett"
 
index d223285..c3a6688 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -1581,6 +1581,10 @@ msgstr "avainta \"%s\" ei löydy: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "virhe luettaessa avainlohkoa: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "avainta \"%s\" ei löydy: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(ellet määritä avainta sormenjäljen perusteella)\n"
 
@@ -1791,6 +1795,19 @@ msgid "No fingerprint"
 msgstr "näytä sormenjälki"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "salaista avainta \"%s\" ei löydy: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "virheelliset tuontivalitsimet\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NIMI|käytä oletusarvoisesti salaista avainta NIMI"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Epäkelpo avain %08lX hyväksytty valitsimella --allow-non-selfsigned-uid\n"
@@ -1924,6 +1941,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "tuota ascii-koodattu tuloste"
 
@@ -2125,12 +2145,49 @@ msgstr "näytä mihin avainrenkaaseen tulostettu avain kuuluu"
 msgid "show expiration dates during signature listings"
 msgstr "Salaisesta avainrenkaasta ei löydy vastaavaa allekirjoitusta\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "poista avain käytöstä"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "tuntematon oletusvastaanottaja \"%s\"\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "tuntematon oletusvastaanottaja \"%s\"\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "HUOM: Vanhat oletusarvoiset asetukset löytyvät tiedostosta \"%s\"\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "virhe luotaessa avainrengasta \"%s\": %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2337,6 +2394,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "VAROITUS: vastaanottajia (-r) annettu käyttämättä julkisen avaimen salausta\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "virheellinen tiivistealgoritmi \"%s\"\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "virheellinen tiivistealgoritmi \"%s\"\n"
+
 msgid "--store [filename]"
 msgstr "--store [tiedostonimi]"
 
@@ -2433,6 +2498,14 @@ msgstr "ascii-koodaaminen epäonnistui: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "virheellinen tiivistealgoritmi \"%s\"\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "virhe luotaessa salasanaa: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[tiedostonimi]"
 
@@ -2738,6 +2811,20 @@ msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "avain %08lX: avaimella on epäkelpo salain %d - ohitetaan\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2869,6 +2956,10 @@ msgstr "avainrengas \"%s\" luotu\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "virhe luotaessa \"%s\": %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "avainrenkaan välimuistin uudelleenluominen epäonnistui: %s\n"
@@ -2938,6 +3029,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Käyttäjätunnus \"%s\" on mitätöity."
 
@@ -3282,6 +3377,10 @@ msgstr "Avain on mitätöity."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Varmastiko allekirjoita kaikki käyttäjätunnukset?"
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Varmastiko allekirjoita kaikki käyttäjätunnukset?"
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Vihje: Valitse allekirjoitettavat käyttäjätunnukset\n"
 
@@ -3394,10 +3493,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Päivitystä ei tarvita, koska avain ei ole muuttunut.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "salaista avainta \"%s\" ei löydy: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "virhe: sormenjälki on väärä\n"
 
@@ -3608,8 +3703,11 @@ msgstr ""
 "Haluatko varmasti nimittää tämän avaimen määrätyksi mitätöijäksi? (k/E): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Valitse korkeintaan yksi toissijainen avain, kiitos.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Haluatko varmasti nimittää tämän avaimen määrätyksi mitätöijäksi? (k/E): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3664,6 +3762,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Indeksillä %d ei löydy käyttäjätunnusta\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Indeksillä %d ei löydy käyttäjätunnusta\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Indeksillä %d ei löydy käyttäjätunnusta\n"
 
@@ -4022,6 +4124,10 @@ msgstr "Oikea nimi: "
 msgid "Invalid character in name\n"
 msgstr "Nimessä on epäkelpo merkki\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Nimi ei voi alkaa numerolla\n"
 
@@ -4461,10 +4567,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "VAROITUS: salattua viestiä on muokattu!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "avaus epäonnistui: %s\n"
 
@@ -4667,6 +4769,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "tuntematon allekirjoitusluokka"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Tiedosto \"%s\" on olemassa."
@@ -5140,6 +5246,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Tämä on arkaluonteinen mitätöintiavain)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Salainen avain on saatavilla.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Luo tälle avaimelle mitätöintivarmenne? "
 
@@ -5174,6 +5285,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "salaista avainta \"%s\" ei löydy: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Luo tälle avaimelle mitätöintivarmenne? "
@@ -7235,7 +7357,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "avainta \"%s\" ei löydy: %s\n"
 
 #, fuzzy, c-format
@@ -7306,6 +7428,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "yhteys kohteeseen \"%s\" ei onnistu: %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "päivitys epäonnistui: %s\n"
@@ -7344,32 +7471,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "virhe kirjoitettaessa salaiseen avainrenkaaseen \"%s\": %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: hajautustaulukon luonti ei onnistu: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "GPG_AGENT_INFO-ympäristömuuttuja on väärin muotoiltu\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "gpg-agent-protokollaversio %d ei ole tuettu\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "yhteys kohteeseen \"%s\" ei onnistu: %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7461,7 +7562,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7774,8 +7875,9 @@ msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "avainta \"%s\" ei löydy: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7933,6 +8035,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "tiedostoa \"%s\" ei voi luoda: %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: hajautustaulukon luonti ei onnistu: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "TrustDB:n alustaminen ei onnistu: %s\n"
@@ -8141,7 +8247,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8399,6 +8505,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "avainrenkaan avaaminen ei onnistu"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Valitse korkeintaan yksi toissijainen avain, kiitos.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "GPG_AGENT_INFO-ympäristömuuttuja on väärin muotoiltu\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "gpg-agent-protokollaversio %d ei ole tuettu\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "vaihda salaisten ja julkisten avainten luettelon välillä"
 
@@ -8578,10 +8714,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Haluatko varmasti tehdä tämän? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "virhe luettaessa salaista avainlohkoa \"%s\": %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Poista salaisten avainten valinnat, kiitos.\n"
 
@@ -9222,9 +9354,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "tuntematon salausalgoritmi"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "avainrenkaan avaaminen ei onnistu"
-
 #~ msgid "invalid packet"
 #~ msgstr "virheellinen paketti"
 
index 8141701..079a06d 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -1519,6 +1519,11 @@ msgstr "clef « %s » introuvable : %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "erreur de lecture du bloc de clef : %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "clef « %s » introuvable : %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(à moins d'indiquer la clef par son empreinte)\n"
 
@@ -1720,6 +1725,20 @@ msgid "No fingerprint"
 msgstr "Aucune empreinte"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "clef secrète « %s » introuvable : %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "argument manquant pour l'option « %.50s »\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOM|utiliser le NOM comme clef secrète par défaut"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "La clef incorrecte %s a été rendue valable par\n"
@@ -1844,6 +1863,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "créer une sortie ASCII avec armure"
 
@@ -2057,11 +2079,52 @@ msgstr "montrer le nom du porte-clefs en affichant les clefs"
 msgid "show expiration dates during signature listings"
 msgstr "montrer les dates d'expiration en affichant les signatures"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Clefs disponibles :\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option '%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "option « %s » inconnue\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command '%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "commande « %s » inconnue\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "Remarque : l'ancien fichier d'options par défaut « %s » a été ignoré\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "l'option « %.50s » est ambiguë\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "erreur de création du porte-clefs « %s » : %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt est trop ancienne (nécessaire : %s, utilisé : %s)\n"
 
@@ -2258,6 +2321,16 @@ msgstr ""
 "Attention : les destinataires (-r) indiqués n'utilisent pas\n"
 "            de clef publique pour le chiffrement\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "ligne %d : date donnée incorrect\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "ligne %d : date donnée incorrect\n"
+
 msgid "--store [filename]"
 msgstr "--store [fichier]"
 
@@ -2350,6 +2423,15 @@ msgstr "échec de construction d'une armure : %s \n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algorithme de hachage « %s » incorrect\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "erreur de chargement du certificat « %s » : %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[fichier]"
 
@@ -2648,6 +2730,20 @@ msgstr "impossible d'importer des clefs secrètes\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "clef %s : clef secrète avec chiffrement %d incorrect — ignorée\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2778,6 +2874,11 @@ msgstr "le porte-clefs « %s » a été créé\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "ressource de bloc de clef « %s » : %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "erreur d'ouverture de « %s » : %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "échec de reconstruction du cache de porte-clefs : %s\n"
@@ -2849,6 +2950,10 @@ msgstr ""
 "sur la touche entrée pour aucun domaine.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "L'identité « %s » est révoquée."
 
@@ -3157,6 +3262,11 @@ msgstr "La clef est révoquée."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Voulez-vous vraiment signer toutes les identités ? (o/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Voulez-vous vraiment signer toutes les identités ? (o/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Conseil : sélectionner les identités à signer\n"
 
@@ -3258,10 +3368,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "La clef n'a pas été modifiée donc la mise à jour est inutile.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "clef secrète « %s » introuvable : %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "« %s » n’est pas une empreinte\n"
 
@@ -3466,8 +3572,14 @@ msgid ""
 msgstr ""
 "Voulez-vous vraiment rendre cette clef comme révocateur désigné ? (o/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Veuillez sélectionner au plus une sous-clef.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Voulez-vous vraiment rendre cette clef comme révocateur désigné ? (o/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Modification de la date d'expiration d'une sous-clef.\n"
@@ -3518,6 +3630,11 @@ msgstr "Pas d'identité d'indice %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Pas d'identité avec le hachage %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Pas de sous-clef d'indice %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Pas de sous-clef d'indice %d\n"
@@ -3867,6 +3984,10 @@ msgstr "Nom réel : "
 msgid "Invalid character in name\n"
 msgstr "Caractère incorrect dans le nom\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Le nom ne doit pas commencer par un chiffre\n"
 
@@ -4308,10 +4429,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "Attention : le message chiffré a été manipulé.\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "phrase secrète effacée mise en cache avec l'identifiant : %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "échec du déchiffrement : %s\n"
 
@@ -4507,6 +4624,11 @@ msgstr ""
 "une clef publique ECDSA est censée être dans un encodage SEC multiple de "
 "8 bits\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Type de signature « %s » inconnu\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "Le fichier « %s » existe. "
@@ -4981,6 +5103,11 @@ msgstr "À révoquer par :\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(c'est une clef de révocation sensible)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "La clef secrète est disponible.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr ""
 "Faut-il créer un certificat de révocation désigné pour cette clef ? (o/N) "
@@ -5023,6 +5150,18 @@ msgstr ""
 "Supprimez ce deux-points avec un éditeur de texte avant\n"
 "d’utiliser ce certificat de révocation."
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "clef secrète « %s » introuvable : %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Faut-il créer un certificat de révocation pour cette clef ? (o/N) "
 
@@ -7127,7 +7266,7 @@ msgstr "erreur de récupération de « %s » : état HTTP %u\n"
 
 #, fuzzy
 #| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr ""
 "accès à la liste de révocations de certificat impossible car %s est "
 "désactivé\n"
@@ -7197,6 +7336,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "certificat trop grand pour être possible\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "impossible de se connecter au dirmngr : %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "échec de la recherche : %s\n"
 
@@ -7231,34 +7374,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "erreur d'écriture en encodage base64 : %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "échec d'allocation du contexte Assuan : %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "pas d'instance de dirmngr en cours d'exécution apparemment\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-"pas d'instance de dirmngr en cours d'exécution —\n"
-"démarrage d'une nouvelle instance\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "la variable d'environnement %s est mal définie\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "le protocole dirmngr version %d n'est pas pris en charge\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-"impossible de se connecter au dirmngr — essai avec la solution de repli\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "impossible de se connecter au dirmngr : %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "demande « %s » non prise en charge\n"
 
@@ -7352,7 +7467,7 @@ msgstr "|N|ne pas renvoyer plus de N éléments dans une requête"
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|FICHIER|utiliser les certificats de CA dans FICHIER pour HKP par TLS"
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 msgid ""
@@ -7652,7 +7767,7 @@ msgstr "réponse trop grande du serveur ; limitée à %d octets.\n"
 
 #, fuzzy
 #| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
+msgid "OCSP request not possible due to Tor mode\n"
 msgstr "requête OCSP impossible car HTTP est désactivé\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
@@ -7807,6 +7922,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "impossible d'allouer une structure de contrôle : %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "échec d'allocation du contexte Assuan : %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "impossible d'initialiser le serveur : %s\n"
 
@@ -8015,7 +8134,7 @@ msgstr "Options contrôlant l'interactivité et la mise en application"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Options contrôlant la sécurité"
 
 msgid "Configuration for HTTP servers"
@@ -8267,6 +8386,50 @@ msgstr ""
 "Vérifier une phrase secrète donnée sur l'entrée standard par rapport à "
 "ficmotif\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "phrase secrète effacée mise en cache avec l'identifiant : %s\n"
+
+#, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "impossible d'ouvrir le porte-clefs"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Veuillez sélectionner au plus une sous-clef.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "pas d'instance de dirmngr en cours d'exécution apparemment\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr ""
+#~ "pas d'instance de dirmngr en cours d'exécution —\n"
+#~ "démarrage d'une nouvelle instance\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "la variable d'environnement %s est mal définie\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "le protocole dirmngr version %d n'est pas pris en charge\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr ""
+#~ "impossible de se connecter au dirmngr — essai avec la solution de repli\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr ""
 #~ "exporter les clefs dans un format basé sur une expression symbolique"
@@ -8550,9 +8713,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Voulez-vous vraiment faire cela ? (o/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "erreur de lecture du bloc de clef secrète « %s » : %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Veuillez supprimer les sélections des clefs secrètes.\n"
 
@@ -9132,9 +9292,6 @@ msgstr ""
 #~ msgid "checksum error"
 #~ msgstr "erreur de somme de contrôle"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "impossible d'ouvrir le porte-clefs"
-
 #~ msgid "invalid packet"
 #~ msgstr "paquet incorrect"
 
index a13915e..f797ee2 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -1571,6 +1571,10 @@ msgstr "non se atopou a chave `%s': %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "erro ao le-lo bloque de chaves: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "non se atopou a chave `%s': %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(a menos que especifique a chave por pegada dactilar)\n"
 
@@ -1785,6 +1789,19 @@ msgid "No fingerprint"
 msgstr "Pegada dactilar:"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "non se atopou a chave secreta `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opcións de importación non válidas\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOME|empregar NOME coma chave secreta por defecto"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Chave %08lX non válida convertida en válida por --allow-non-selfsigned-uid\n"
@@ -1917,6 +1934,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "crear saída con armadura en ascii"
 
@@ -2118,12 +2138,49 @@ msgstr "amosar en que chaveiro est
 msgid "show expiration dates during signature listings"
 msgstr "Non hai unha sinatura correspondiente no chaveiro secreto\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "deshabilitar unha chave"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "destinatario por defecto `%s' descoñecido\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "destinatario por defecto `%s' descoñecido\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTA: ignórase o antigo ficheiro de opcións por defecto `%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "erro ao crea-lo chaveiro `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2331,6 +2388,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "AVISO: deronse destinatarios (-r) sen empregar cifrado de chave pública\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "algoritmo de hash non válido `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "algoritmo de hash non válido `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [ficheiro]"
 
@@ -2427,6 +2492,14 @@ msgstr "non se puido po
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritmo de hash non válido `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "erro ao crea-lo contrasinal: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[ficheiro]"
 
@@ -2734,6 +2807,20 @@ msgstr "gravando a chave secreta en `%s'\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "chave %08lX: chave secreta cunha cifra %d non válida - omitida\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2871,6 +2958,10 @@ msgstr "chaveiro `%s' creado\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "erro ao crear `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "erro lendo `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "fallo ao reconstruí-la caché de chaveiros: %s\n"
@@ -2938,6 +3029,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "O ID de usuario \"%s\" está revocado."
 
@@ -3285,6 +3380,10 @@ msgstr "A chave est
 msgid "Really sign all user IDs? (y/N) "
 msgstr "¿Seguro de que quere asinar tódolos IDs de usuario? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "¿Seguro de que quere asinar tódolos IDs de usuario? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Pista: seleccione os IDs de usuario que desexa asinar\n"
 
@@ -3399,10 +3498,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "A chave non cambiou, polo que non fai falla actualizar.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "non se atopou a chave secreta `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "erro: pegada dactilar non válida\n"
 
@@ -3619,8 +3714,11 @@ msgstr ""
 "¿Está seguro de que quere nomear esta chave coma revocador designado? (s/N): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Por favor, seleccione como máximo unha chave secundaria.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"¿Está seguro de que quere nomear esta chave coma revocador designado? (s/N): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3677,6 +3775,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Non hai ID de usuario con índice %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Non hai ID de usuario con índice %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Non hai ID de usuario con índice %d\n"
 
@@ -4032,6 +4134,10 @@ msgstr "Nome: "
 msgid "Invalid character in name\n"
 msgstr "Caracter non válido no nome\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "O nome non pode comezar cun díxito\n"
 
@@ -4474,10 +4580,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "AVISO: ¡a mensaxe cifrada foi manipulada!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "o descifrado fallou: %s\n"
 
@@ -4677,6 +4779,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "clase de sinatura descoñecida"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "O ficheiro `%s' xa existe. "
@@ -5147,6 +5253,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Esta é unha chave de revocación sensible)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "A chave secreta está disponible.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "¿Crear un certificado de revocación para esta sinatura? "
 
@@ -5181,6 +5292,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "non se atopou a chave secreta `%s': %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "¿Crear un certificado de revocación para esta sinatura? "
@@ -7256,7 +7378,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "erro lendo `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "non se atopou a chave `%s': %s\n"
 
 #, fuzzy, c-format
@@ -7329,6 +7451,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "non se puido conectar a `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "a actualización fallou: %s\n"
@@ -7367,32 +7494,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "erro escribindo no chaveiro secreto `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: fallo ao crear unha táboa hash: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "variable de ambiente GPG_AGENT_INFO mal formada\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "a versión %d do protocolo de gpg-agent non está soportada\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "non se puido conectar a `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7484,7 +7585,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7796,8 +7897,9 @@ msgstr "erro lendo `%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "non se atopou a chave `%s': %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7955,6 +8057,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "non se pode crear `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: fallo ao crear unha táboa hash: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "non se puido inicializa-la base de datos de confianzas: %s\n"
@@ -8164,7 +8270,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8424,6 +8530,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "non foi posible abri-lo chaveiro"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Por favor, seleccione como máximo unha chave secundaria.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variable de ambiente GPG_AGENT_INFO mal formada\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "a versión %d do protocolo de gpg-agent non está soportada\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "cambiar entre o listado de chaves públicas e secretas"
 
@@ -8603,10 +8739,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "¿Seguro que quere facer esto? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "erro ao le-lo bloque de chave secreta `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Por favor, quite as seleccións das chaves secretas.\n"
 
@@ -9250,9 +9382,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "algoritmo de cifrado descoñecido"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "non foi posible abri-lo chaveiro"
-
 #~ msgid "invalid packet"
 #~ msgstr "paquete non válido"
 
index 0092ec9..053e6e6 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -1562,6 +1562,10 @@ msgstr "\"%s\" kulcs nem tal
 msgid "error reading keyblock: %s\n"
 msgstr "Hiba a kulcsblokk olvasásakor: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "\"%s\" kulcs nem található: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(Kivéve, ha megad egy kulcsot az ujjlenyomatával.)\n"
 
@@ -1772,6 +1776,19 @@ msgid "No fingerprint"
 msgstr "megmutatja az ujjlenyomatot"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "\"%s\" titkos kulcs nem található: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "Érvénytelen import opciók!\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NÉV|NÉV használata alapértelmezett titkos kulcsként"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "%08lX érvénytelen kulcsot érvényesítettük az\n"
@@ -1905,6 +1922,9 @@ msgstr "|algo [f
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "ascii páncélozott kimenet létrehozása"
 
@@ -2106,12 +2126,49 @@ msgstr "mutatja a kilist
 msgid "show expiration dates during signature listings"
 msgstr "Nincs megfelelõ aláírás a titkoskulcs-karikán.\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "kulcs tiltása"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "Ismeretlen alapértelmezett címzett: \"%s\"\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "Ismeretlen alapértelmezett címzett: \"%s\"\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "MEGJEGYZÉS: Figyelmen kívül hagytam a régi opciókat (%s).\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "Hiba a(z) \"%s\" kulcskarika létrehozásakor: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2319,6 +2376,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "FIGYELEM: Címzett megadva (-r), de nincs nyilvános kulcsú titkosítás!\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "Érvénytelen kivonatoló algoritmus: %s\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "Érvénytelen kivonatoló algoritmus: %s\n"
+
 msgid "--store [filename]"
 msgstr "--store [fájlnév]"
 
@@ -2415,6 +2480,14 @@ msgstr "P
 msgid "invalid hash algorithm '%s'\n"
 msgstr "Érvénytelen kivonatoló algoritmus: %s\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "Hiba a jelszó létrehozásakor: %s.\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[fájlnév]"
 
@@ -2719,6 +2792,20 @@ msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr ""
 "%08lX kulcs: Titkos kulcs érvénytelen (%d) rejtjelezõvel - kihagytam.\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "%08lX kulcs: Nincs nyilvános kulcs - nem tudok visszavonni.\n"
@@ -2851,6 +2938,10 @@ msgstr "\"%s\" kulcskarik
 msgid "keyblock resource '%s': %s\n"
 msgstr "Hiba \"%s\" létrehozásakor: %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "Hiba \"%s\" olvasásakor: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "Nem tudtam újraépíteni a kulcskarika cache-ét: %s\n"
@@ -2919,6 +3010,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "\"%s\" felhasználói azonosítót visszavonták."
 
@@ -3260,6 +3355,10 @@ msgstr "A kulcsot visszavont
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Valóban aláírja az összes felhasználóazonosítót? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Valóban aláírja az összes felhasználóazonosítót? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Javaslat: Válassza ki az aláírni kívánt felhasználóazonosítókat!\n"
 
@@ -3372,10 +3471,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "A kulcs nem változott, nincs szükség frissítésre.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "\"%s\" titkos kulcs nem található: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "Hiba: Érvénytelen ujjlenyomat.\n"
 
@@ -3588,8 +3683,10 @@ msgid ""
 msgstr "Biztosan ez a kulcs legyen a kijelölt visszavonó? (i/N): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Maximum egy másodlagos kulcsot jelöljön ki, kérem!\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Biztosan ez a kulcs legyen a kijelölt visszavonó? (i/N): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3644,6 +3741,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Nincs %d indexû felhasználóazonosító!\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Nincs %d indexû felhasználóazonosító!\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Nincs %d indexû felhasználóazonosító!\n"
 
@@ -3998,6 +4099,10 @@ msgstr "Teljes n
 msgid "Invalid character in name\n"
 msgstr "Érvénytelen karakter a névben!\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "A név lehet, hogy nem kezdõdhet számmal!\n"
 
@@ -4443,10 +4548,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "FIGYELEM: A titkosított üzenetet manipulálták!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "Visszafejtés sikertelen: %s.\n"
 
@@ -4646,6 +4747,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "ismeretlen aláírásosztály"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "\"%s\" állomány létezik. "
@@ -5118,6 +5223,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Ez egy érzékeny visszavonó kulcs.)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Titkos kulcs rendelkezésre áll.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Csináljunk egy visszavonó igazolást ehhez a kulcshoz? "
 
@@ -5152,6 +5262,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "\"%s\" titkos kulcs nem található: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Csináljunk egy visszavonó igazolást ehhez a kulcshoz? "
@@ -7209,7 +7330,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "Hiba \"%s\" olvasásakor: %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "\"%s\" kulcs nem található: %s\n"
 
 #, fuzzy, c-format
@@ -7280,6 +7401,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "Nem tudok kapcsolódni \"%s\" objektumhoz: %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "Frissítés sikertelen: %s.\n"
@@ -7318,32 +7444,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "Hiba a(z) \"%s\" titkoskulcs-karika írásakor: %s.\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: Hashtábla létrehozása sikertelen: %s.\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "Nem megfelelõ formájú GPG_AGENT_INFO környezeti változó!\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "%d gpg-agent protokollverzió nem támogatott!\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "Nem tudok kapcsolódni \"%s\" objektumhoz: %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7435,7 +7535,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7747,8 +7847,9 @@ msgstr "Hiba \"%s\" olvas
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "\"%s\" kulcs nem található: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7906,6 +8007,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "Nem tudom létrehozni a(z) \"%s\" állományt: %s.\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: Hashtábla létrehozása sikertelen: %s.\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n"
@@ -8114,7 +8219,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8372,6 +8477,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "nem lehet megnyitni a kulcskarikát"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Maximum egy másodlagos kulcsot jelöljön ki, kérem!\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "Nem megfelelõ formájú GPG_AGENT_INFO környezeti változó!\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "%d gpg-agent protokollverzió nem támogatott!\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "váltás a titkos és a nyilvános kulcs listázása között"
 
@@ -8551,10 +8686,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Valóban ezt akarja? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "Hiba \"%s\" titkoskulcs-blokk olvasásakor: %s.\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Kérem, távolítsa el a kijelöléseket a titkos kulcsokról!\n"
 
@@ -9189,9 +9320,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "ismeretlen rejtjelezõ algoritmus"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "nem lehet megnyitni a kulcskarikát"
-
 #~ msgid "invalid packet"
 #~ msgstr "érvénytelen csomag"
 
index f38d773..2632e69 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -1568,6 +1568,10 @@ msgstr "kunci '%s' tidak ditemukan: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "gagal membaca keyblock: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "kunci '%s' tidak ditemukan: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(kecuali anda menspesifikasikan kunci dengan fingerprint)\n"
 
@@ -1777,6 +1781,19 @@ msgid "No fingerprint"
 msgstr "tampilkan fingerprint"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "kunci rahasia `%s' tidak ditemukan: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opsi impor tidak valid\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAMA|gunakan NAMA sebagai kunci rahasia baku"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "kunci tidak valid %08lX dibuat valid oleh --allow-non-selfsigned-uid\n"
 
@@ -1908,6 +1925,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "ciptakan output ascii"
 
@@ -2109,12 +2129,49 @@ msgstr "tampilkan keyring tempat kunci yang dipilih berada"
 msgid "show expiration dates during signature listings"
 msgstr "Tidak ada signature koresponden di ring rahasia\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "tiadakan kunci"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "penerima baku tidak dikenal `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "penerima baku tidak dikenal `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "CATATAN: file pilihan baku lama `%s' diabaikan\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "kesalahan menulis keyring `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2324,6 +2381,14 @@ msgstr ""
 "Peringatan: penerima yang disebutkan (-r) tanpa menggunakan enkripsi public "
 "key \n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "algoritma hash tidak valid `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "algoritma hash tidak valid `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [namafile]"
 
@@ -2420,6 +2485,14 @@ msgstr "gagal enarmoring: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritma hash tidak valid `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "kesalahan penciptaan passphrase: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[namafile]"
 
@@ -2723,6 +2796,20 @@ msgstr "menulis kunci rahasia ke `%s'\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "kunci %08lX: kunci rahasia dengan cipher tidak valid %d - dilewati\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2853,6 +2940,10 @@ msgstr "%s: keyring tercipta\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "kesalahan penciptaan : `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "kesalahan membaca `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "gagal membuat kembali cache keyring: %s\n"
@@ -2921,6 +3012,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "User ID \"%s\" dibatalkan."
 
@@ -3265,6 +3360,10 @@ msgstr "Kunci dibatalkan"
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Tandai ID seluruh user? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Tandai ID seluruh user? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Petunjuk: Pilih ID user untuk ditandai\n"
 
@@ -3377,10 +3476,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Kunci tidak berubah sehingga tidak perlu pembaharuan.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "kunci rahasia `%s' tidak ditemukan: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "kesalahan: fingerprint tidak valid\n"
 
@@ -3597,8 +3692,11 @@ msgstr ""
 "Anda yakin ingin menunjuk kunci inin sebagai pihak yang dibatalkan? (y/N):"
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Silakan pilih maksimum satu kunci sekunder.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Anda yakin ingin menunjuk kunci inin sebagai pihak yang dibatalkan? (y/N):"
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3653,6 +3751,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Tidak ada ID user dengan index %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Tidak ada ID user dengan index %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Tidak ada ID user dengan index %d\n"
 
@@ -4005,6 +4107,10 @@ msgstr "Nama sebenarnya: "
 msgid "Invalid character in name\n"
 msgstr "Karakter tidak valid dalam nama\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Nama tidak boleh dimulai dengan digit\n"
 
@@ -4443,10 +4549,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "PERINGATAN: pesan terenkripsi telah dimanipulasi!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "dekripsi gagal: %s\n"
 
@@ -4642,6 +4744,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "kelas signature tidak dikenal"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "File `%s' ada. "
@@ -5108,6 +5214,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Ini adalah kunci pembatalan sensitif)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Kunci rahasia tersedia.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Buat sertifikat pembatalan untuk kunci ini?"
 
@@ -5142,6 +5253,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "kunci rahasia `%s' tidak ditemukan: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Buat sertifikat pembatalan untuk kunci ini?"
@@ -7198,7 +7320,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "kesalahan membaca `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "kunci '%s' tidak ditemukan: %s\n"
 
 #, fuzzy, c-format
@@ -7269,6 +7391,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "tidak dapat terkoneksi ke `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "gagal memperbarui: %s\n"
@@ -7307,32 +7434,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "kesalahan menulis keyring rahasia `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: gagal membuat hashtable: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "variabel lingkungan GPG_AGENT_INFO salah bentuk\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "protokol gpg-agent versi %d tidak didukung\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "tidak dapat terkoneksi ke `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7424,7 +7525,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7736,8 +7837,9 @@ msgstr "kesalahan membaca `%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "kunci '%s' tidak ditemukan: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7895,6 +7997,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "tidak dapat membuat %s: %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: gagal membuat hashtable: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "gagal inisialisasi TrustDB: %s\n"
@@ -8103,7 +8209,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8361,6 +8467,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "tidak dapat membuka keyring"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Silakan pilih maksimum satu kunci sekunder.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variabel lingkungan GPG_AGENT_INFO salah bentuk\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "protokol gpg-agent versi %d tidak didukung\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "ubah tampilan kunci rahasia dan publik"
 
@@ -8545,10 +8681,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Apakah anda ingin melakukan hal ini? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "kesalahan membaca keyblock rahasia `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Silakan hapus pilihan dari kunci rahasia.\n"
 
@@ -9185,9 +9317,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "algoritma cipher tidak dikenal"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "tidak dapat membuka keyring"
-
 #~ msgid "invalid packet"
 #~ msgstr "paket tidak valid"
 
index 6dedcd1..bde95bb 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -1566,6 +1566,10 @@ msgstr "chiave `%s' non trovata: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "errore leggendo il keyblock: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "chiave `%s' non trovata: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(a meno che la chiave sia specificata con il fingerprint)\n"
 
@@ -1784,6 +1788,19 @@ msgid "No fingerprint"
 msgstr "mostra le impronte digitali"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "chiave segreta `%s' non trovata: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opzioni di importazione non valide\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOME|usa NOME come chiave segreta predefinita"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Chiave %08lX non valida resa valida da --allow-non-selfsigned-uid\n"
 
@@ -1915,6 +1932,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "crea un output ascii con armatura"
 
@@ -2116,6 +2136,21 @@ msgstr "mostra in quali portachiavi sono contenute le chiavi elencate"
 msgid "show expiration dates during signature listings"
 msgstr "Manca la firma corrispondente nel portachiavi segreto\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "disabilita una chiave"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "destinatario predefinito `%s' sconosciuto\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "destinatario predefinito `%s' sconosciuto\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
@@ -2123,6 +2158,28 @@ msgstr ""
 "NOTA: il vecchio file `%s' con le opzioni predefinite è stato ignorato\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "errore creando il portachiavi `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2330,6 +2387,14 @@ msgstr ""
 "ATTENZIONE: sono stati indicati dei destinatari (-r) senza usare la\n"
 "crittografia a chiave pubblica\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "algoritmo di hash non valido `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "algoritmo di hash non valido `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [nomefile]"
 
@@ -2426,6 +2491,14 @@ msgstr "creazione dell'armatura fallita: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritmo di hash non valido `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "errore nella creazione della passhprase: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nomefile]"
 
@@ -2729,6 +2802,20 @@ msgstr "scrittura della chiave segreta in `%s'\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "chiave %08lX: chiave segreta con cifrario %d non valido - saltata\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2862,6 +2949,10 @@ msgstr "portachiavi `%s' creato\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "errore creando `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "errore leggendo `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "rebuild della cache del portachiavi fallito: %s\n"
@@ -2930,6 +3021,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "L'user ID \"%s\" è stato revocato."
 
@@ -3272,6 +3367,10 @@ msgstr "La chiave 
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Firmo davvero tutti gli user ID? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Firmo davvero tutti gli user ID? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Suggerimento: seleziona gli user ID da firmare\n"
 
@@ -3384,10 +3483,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "La chiave non è cambiata quindi non sono necessari aggiornamenti.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "chiave segreta `%s' non trovata: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "errore: impronta digitale non valida\n"
 
@@ -3608,8 +3703,11 @@ msgstr ""
 "Sei sicuro di volere nominare questa chiave revocatrice designata? (s/N):"
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Seleziona al massimo una chiave secondaria.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Sei sicuro di volere nominare questa chiave revocatrice designata? (s/N):"
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3666,6 +3764,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Nessun user ID con l'indice %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Nessun user ID con l'indice %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Nessun user ID con l'indice %d\n"
 
@@ -4021,6 +4123,10 @@ msgstr "Nome e Cognome: "
 msgid "Invalid character in name\n"
 msgstr "Carattere non valido nel nome\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Il nome non può iniziare con una cifra\n"
 
@@ -4460,10 +4566,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "ATTENZIONE: il messaggio cifrato è stato manipolato!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "decifratura fallita: %s\n"
 
@@ -4660,6 +4762,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "classe della firma sconosciuta"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Il file `%s' esiste. "
@@ -5135,6 +5241,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Questa è una chiave di revoca sensibile)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "È disponibile una chiave segreta.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Creare un certificato di revoca per questa chiave? "
 
@@ -5169,6 +5280,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "chiave segreta `%s' non trovata: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Creare un certificato di revoca per questa chiave? "
@@ -7238,7 +7360,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "errore leggendo `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "chiave `%s' non trovata: %s\n"
 
 #, fuzzy, c-format
@@ -7309,6 +7431,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "impossibile connettersi a `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "aggiornamento fallito: %s\n"
@@ -7347,32 +7474,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "errore scrivendo il portachiavi segreto `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: creazione della tabella hash fallita: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "variabile di ambiente GPG_AGENT_INFO malformata\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "la versione %d del protocollo di gpg-agent non è gestita\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "impossibile connettersi a `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7464,7 +7565,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7777,8 +7878,9 @@ msgstr "errore leggendo `%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "chiave `%s' non trovata: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7936,6 +8038,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "impossibile creare `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: creazione della tabella hash fallita: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "inizializzazione del trustdb fallita: %s\n"
@@ -8144,7 +8250,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8402,6 +8508,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "impossibile aprire il portachiavi"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Seleziona al massimo una chiave secondaria.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variabile di ambiente GPG_AGENT_INFO malformata\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "la versione %d del protocollo di gpg-agent non è gestita\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "cambia tra visualizzare la chiave segreta e la chiave pubblica"
 
@@ -8586,10 +8722,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Vuoi veramente farlo?"
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "errore leggendo il keyblock segreto `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Togli le selezioni dalle chiavi segrete.\n"
 
@@ -9242,9 +9374,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "algoritmo di cifratura sconosciuto"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "impossibile aprire il portachiavi"
-
 #~ msgid "invalid packet"
 #~ msgstr "pacchetto non valido"
 
index a318b3c..c8e685c 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -8,9 +8,9 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gnupg 2.1.8\n"
+"Project-Id-Version: gnupg 2.1.9\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-09-15 15:12+0900\n"
+"PO-Revision-Date: 2015-10-13 11:32+0900\n"
 "Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
 "Language-Team: none\n"
 "Language: ja\n"
@@ -1461,6 +1461,11 @@ msgstr "鍵\"%s\"が見つかりません: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "鍵ブロックの読み込みエラー: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "鍵\"%s\"が見つかりません: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(フィンガー・プリントで鍵を指定してない限り)\n"
 
@@ -1650,6 +1655,20 @@ msgid "No fingerprint"
 msgstr "フィンガープリントがありません"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "秘密鍵\"%s\"が見つかりません: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "オプション\"%.50s\"に引数がありません\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAME|デフォルトの秘密鍵としてNAMEを用いる"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "--allow-non-selfsigned-uidで有効にされた無効な鍵%sです\n"
 
@@ -1768,6 +1787,9 @@ msgstr "メッセージ・ダイジェストを表示"
 msgid "run in server mode"
 msgstr "サーバ・モードで実行"
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "ASCII形式の外装を作成"
 
@@ -1955,11 +1977,52 @@ msgstr "鍵の一覧に鍵リングの名前を表示する"
 msgid "show expiration dates during signature listings"
 msgstr "署名の一覧時に有効期限の日付を表示する"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "利用可能な鍵:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option '%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "不明のオプション'%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command '%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "不明のコマンド'%s'\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "*注意*: 以前デフォルトだったオプション・ファイル'%s'は、無視されます\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "オプション\"%.50s\"はあいまいです\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "鍵リング'%s'の作成エラー: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt が古すぎます (必要 %s, 現在 %s)\n"
 
@@ -2151,6 +2214,16 @@ msgstr "信用データベースの初期化に失敗しました: %s\n"
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr "*警告*: 公開鍵暗号を使わずに、受取人 (-r) を指定しています\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "行 %d: 無効な日付が与えられました\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "行 %d: 無効な日付が与えられました\n"
+
 msgid "--store [filename]"
 msgstr "--store [ファイル名]"
 
@@ -2243,6 +2316,15 @@ msgstr "外装に失敗しました: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "無効なハッシュ・アルゴリズム'%s'です\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "証明書'%s'の読み込みエラー: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[ファイル名]"
 
@@ -2536,6 +2618,20 @@ msgstr "秘密鍵のインポートは禁止です\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "鍵%s: 無効な暗号方式%dの秘密鍵です - スキップします\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "鍵%s: 公開鍵がありません - 失効証明書を適用できません\n"
@@ -2660,6 +2756,11 @@ msgstr "鍵リング'%s'ができました\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "keyblock リソース'%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "'%s'を開く際、エラー: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "鍵リング・キャッシュの再構築に失敗しました: %s\n"
@@ -2728,6 +2829,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "署名を制限するドメインを入力するか、空行を入力してください。\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "ユーザID\"%s\"は、失効されています。"
 
@@ -3024,6 +3129,11 @@ msgstr "鍵は、失効されています。"
 msgid "Really sign all user IDs? (y/N) "
 msgstr "本当に全ユーザIDに署名しますか? (y/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "本当に全ユーザIDに署名しますか? (y/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "ヒント: まず署名するユーザIDを選択します\n"
 
@@ -3040,7 +3150,7 @@ msgstr "ユーザIDを少なくともひとつ選択してください。\n"
 
 #, c-format
 msgid "(Use the '%s' command.)\n"
-msgstr ""
+msgstr "('%s'コマンドを使用してください。)\n"
 
 msgid "You can't delete the last user ID!\n"
 msgstr "最後のユーザIDは削除できません!\n"
@@ -3121,10 +3231,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "鍵は無変更なので更新は不要です。\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "秘密鍵\"%s\"が見つかりません: %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\"はフィンガープリントではありません\n"
 
@@ -3322,8 +3428,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "本当にこの鍵を指名失効者に任命しますか? (y/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "高々1個の副鍵を選択してください。\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "本当にこの鍵を指名失効者に任命しますか? (y/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "副鍵の有効期限を変更します。\n"
@@ -3372,6 +3483,11 @@ msgstr "%d番のユーザIDはありません\n"
 msgid "No user ID with hash %s\n"
 msgstr "ハッシュ%sのユーザIDはありません\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "%d番の副鍵はありません\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "%d番の副鍵はありません\n"
@@ -3713,6 +3829,10 @@ msgstr "本名: "
 msgid "Invalid character in name\n"
 msgstr "名前に無効な文字があります\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "名前を数字で始めてはいけません\n"
 
@@ -4126,10 +4246,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "*警告*: 暗号化されたメッセージは改竄されています!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "保持したパスフレーズをクリアしました ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "復号に失敗しました: %s\n"
 
@@ -4318,6 +4434,11 @@ msgstr "不明のオプション'%s'\n"
 msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "ECDSAの公開鍵は8ビットの倍数のSECエンコーディングを期待します\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "不明の署名タイプ'%s'\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "ファイル'%s'は既に存在します。"
@@ -4757,6 +4878,11 @@ msgstr "失効者:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(これは、機密指定の失効鍵です)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "秘密鍵が使用できます。\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "この鍵に対する指名失効証明書を作成しますか? (y/N) "
 
@@ -4796,6 +4922,18 @@ msgstr ""
 "入されます。\n"
 "この失効証明書を使う前にはテクスト・エディタでこのコロンを削除してください。"
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "秘密鍵\"%s\"が見つかりません: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "この鍵に対する失効証明書を作成しますか? (y/N) "
 
@@ -6762,9 +6900,9 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "'%s'の取得エラー: httpステイタス %u\n"
 
 #, fuzzy
-#| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
-msgstr "CRLアクセスは停止された%sのため不可能です\n"
+#| msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
+msgstr "CRLアクセスはTORモードのため不可能です\n"
 
 #, c-format
 msgid "certificate search not possible due to disabled %s\n"
@@ -6830,6 +6968,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "証明書は意味のあるものとしては大きすぎます\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "dirmngrへ接続できません: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "検索に失敗しました: %s\n"
 
@@ -6863,31 +7005,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "base64エンコーディングの書き込みエラー: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "assuanコンテクストの確保に失敗しました: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "あきらかにdirmngrが動いていません\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "dirmngrが動いていません - 開始します\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "環境変数%sが破壊されています\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "dirmngrプロトコル・バージョン%dはサポートされていません\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "dirmngrに接続できません - フォールバックを試します\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "dirmngrへ接続できません: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "サポートされていない問い合わせ: '%s'\n"
 
@@ -6973,8 +7090,10 @@ msgstr "|N|一つのクエリでNを越えるのアイテムを返さない"
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|FILE|FILEにあるCA証明書をTLSでのHKPに使う"
 
-msgid "route all network traffic via TOR"
-msgstr ""
+#, fuzzy
+#| msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
+msgstr "ネットワーク・トラフィックをすべてTOR経由にする"
 
 msgid ""
 "@\n"
@@ -7267,9 +7386,9 @@ msgid "response from server too large; limit is %d bytes\n"
 msgstr "サーバからの応答がが長すぎます (上限%dバイト)。\n"
 
 #, fuzzy
-#| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr "HTTPが停止されているためOCSPリクエストが不可能です\n"
+#| msgid "OCSP request not possible due to TOR mode\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "TORモードのためOCSPリクエストが不可能です\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr "HTTPが停止されているためOCSPリクエストが不可能です\n"
@@ -7422,6 +7541,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "制御構造を確保できません: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "assuanコンテクストの確保に失敗しました: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "サーバの初期化に失敗しました: %s\n"
 
@@ -7618,9 +7741,9 @@ msgid "Options controlling the interactivity and enforcement"
 msgstr "インタラクティビティと強制を制御するオプション"
 
 #, fuzzy
-#| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
-msgstr "セキュリティを制御するオプション"
+#| msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
+msgstr "TORの使用を制御するオプション"
 
 msgid "Configuration for HTTP servers"
 msgstr "HTTPサーバのコンフィグレーション"
@@ -7650,7 +7773,7 @@ msgid "GPG for S/MIME"
 msgstr "S/MIME のためのGPG"
 
 msgid "Key Acquirer"
-msgstr ""
+msgstr "キー取得プログラム"
 
 msgid "PIN and Passphrase Entry"
 msgstr "PINとパスフレーズの入力"
@@ -7870,6 +7993,47 @@ msgstr ""
 "形式: gpg-check-pattern [オプション] パターンファイル\n"
 "パターンファイルに対して標準入力のパスフレーズを確認する\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "保持したパスフレーズをクリアしました ID: %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "鍵の保管に失敗しました: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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 "keyboxのロックのエラー: %s\n"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "高々1個の副鍵を選択してください。\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "あきらかにdirmngrが動いていません\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "dirmngrが動いていません - 開始します\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "環境変数%sが破壊されています\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "dirmngrプロトコル・バージョン%dはサポートされていません\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "dirmngrに接続できません - フォールバックを試します\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "S式ベースのフォーマットで鍵をエクスポートする"
 
index 043b18f..09f792b 100644 (file)
--- a/po/nb.po
+++ b/po/nb.po
@@ -1537,6 +1537,11 @@ msgstr "n
 msgid "error reading keyblock: %s\n"
 msgstr "feil ved lesing av nøkkelblokk: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "nøkkelen «%s» ble ikke funnet: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(med mindre du angir nøkkelen ved hjelp av fingeravtrykk)\n"
 
@@ -1745,6 +1750,19 @@ msgid "No fingerprint"
 msgstr "CA-fingeravtrykk: "
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "ugyldige listevalg\n"
+
+#, fuzzy, c-format
+#| msgid "unusable secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "ubrukelig hemmelig nøkkel"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Ugyldig nøkkel %s gjort gyldig av --allow-non-selfsigned-uid\n"
 
@@ -1875,6 +1893,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "lage ASCII-beskyttet output"
 
@@ -2100,12 +2121,50 @@ msgstr "vise navnet til n
 msgid "show expiration dates during signature listings"
 msgstr ""
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "utkoble en nøkkel"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "ukjent valg «%s»\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "ukjent valg «%s»\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "MERK: den gamle valgfila «%s» ble ignorert\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2307,6 +2366,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "ADVARSEL: mottakere (-r) angitt uten å bruke offentlig nøkkelkryptering\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "ugyldig hashalgoritme «%s»\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "ugyldig hashalgoritme «%s»\n"
+
 msgid "--store [filename]"
 msgstr "--store [filnavn]"
 
@@ -2402,6 +2469,14 @@ msgstr "enarmoring failed: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "ugyldig hashalgoritme «%s»\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[filnavn]"
 
@@ -2703,6 +2778,20 @@ msgstr "import av hemmelig n
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "nøkkel %s: hemmelig nøkkel med ugyldig cipher %d - hoppet over\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2832,6 +2921,10 @@ msgstr "n
 msgid "keyblock resource '%s': %s\n"
 msgstr "nøkkelblokkressurs «%s»: %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "feil med «%s»: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr ""
@@ -2898,6 +2991,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Brukerid «%s» er opphevet."
 
@@ -3195,6 +3292,11 @@ msgstr "N
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Virkelig signerere alle brukerider? (j/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Virkelig signerere alle brukerider? (j/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Tips: Velg brukeriden som skal signeres\n"
 
@@ -3293,10 +3395,6 @@ msgstr "oppdatering mislyktes: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Nøkkelen ble ikke endret, så ingen oppdatering er nødvendig.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3492,8 +3590,15 @@ msgstr ""
 "Er du fortsatt sikker på at du vil gjøre denne nøkkelen til en opphever? (j/"
 "N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Vennligst velg minst en undernøkkel.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Er du fortsatt sikker på at du vil gjøre denne nøkkelen til en opphever? (j/"
+"N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr ""
@@ -3542,6 +3647,11 @@ msgstr ""
 msgid "No user ID with hash %s\n"
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "Nothing to sign with key %s\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Ingenting å signere med nøkkelen %s\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr ""
@@ -3890,6 +4000,10 @@ msgstr "Fullt navn: "
 msgid "Invalid character in name\n"
 msgstr "Ugyldig tegn i navn\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Navnet kan ikke starte med et siffer\n"
 
@@ -4335,10 +4449,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr ""
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "dekryptering mislyktes: %s\n"
 
@@ -4531,6 +4641,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Ukjent signaturtype «%s»\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Fila «%s» finnes. "
@@ -4992,6 +5107,11 @@ msgstr ""
 msgid "(This is a sensitive revocation key)\n"
 msgstr ""
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Hemmelig nøkkel er tilgjengelig\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Lage et utpekt opphevingssertifikat for denne nøkkelen? (j/N) "
 
@@ -5027,6 +5147,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Lage et opphevingssertifikat for denne nøkkelen? (j/N) "
 
@@ -7053,7 +7185,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "feil ved lesing av «%s»: %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
 
 #, fuzzy, c-format
@@ -7122,6 +7254,10 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "kan ikke åpne nøkkelknippet"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "oppdatering mislyktes: %s\n"
@@ -7161,31 +7297,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "feil ved skriving av hemmelig nøkkelknippe «%s»: %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "klarte ikke å lagre nøkkelen: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr ""
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr ""
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "kan ikke åpne nøkkelknippet"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7278,7 +7389,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7598,8 +7709,9 @@ msgstr "feil ved lesing av 
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Feil: Privat DO for lang (grensa går ved %d tegn).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "hemmelig nøkkel «%s» ble ikke funnet: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7758,6 +7870,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "kan ikke opprette sikkerhetskopifil «%s»: %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "klarte ikke å lagre nøkkelen: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "klarte ikke å initialisere tillitsdatabasen: %s\n"
@@ -7963,7 +8079,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8220,6 +8336,28 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "klarte ikke å lagre nøkkelen: %s\n"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Vennligst velg minst en undernøkkel.\n"
+
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "veksle mellom hemmelig og offentlig nøkkellisting"
 
@@ -8351,9 +8489,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Vil du virkelig gjøre dette? (j/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "feil ved lesing av hemmelig nøkkelblokk «%s»: %s\n"
-
 #~ msgid "writing secret key stub to `%s'\n"
 #~ msgstr "skriver foreløpig hemmelig nøkkel til «%s»\n"
 
@@ -8750,9 +8885,6 @@ msgstr ""
 #~ msgid "unusable public key"
 #~ msgstr "ubrukelig offentlig nøkkel"
 
-#~ msgid "unusable secret key"
-#~ msgstr "ubrukelig hemmelig nøkkel"
-
 #~ msgid "keyserver error"
 #~ msgstr "feil med nøkkelserver"
 
index 2fd1116..5fd2922 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -1581,6 +1581,11 @@ msgstr "klucz ,,%s'' nie zosta
 msgid "error reading keyblock: %s\n"
 msgstr "b³±d odczytu bloku kluczy: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "klucz ,,%s'' nie zosta³ odnaleziony: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(chyba, ¿e klucz zostaje wybrany przez podanie odcisku)\n"
 
@@ -1788,6 +1793,20 @@ msgid "No fingerprint"
 msgstr "Brak odcisku"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "klucz prywatny ,,%s'' nie zosta³ odnaleziony: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "brak argumentu dla opcji ,,%.50s''\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAZWA|u¿ycie NAZWY jako domy¶lnego klucza tajnego"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Opcja --allow-non-selfsigned-uid wymusi³a uznanie za poprawny klucza %s.\n"
@@ -1915,6 +1934,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "opakowanie ASCII pliku wynikowego"
 
@@ -2148,12 +2170,53 @@ msgstr "pokazywanie nazwy zbioru kluczy na listach kluczy"
 msgid "show expiration dates during signature listings"
 msgstr "pokazywanie dat wyga¶niêcia przy wypisywaniu podpisów"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Dostêpne klucze:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "nieznana opcja ,,%s''\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command `%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "nieznane polecenie ,,%s''\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "UWAGA: stary domy¶lny plik opcji ,,%s'' zosta³ zignorowany\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "opcja ,,%.50s'' jest niejednoznaczna\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "b³±d tworzenia zbioru kluczy `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 "biblioteka libgcrypt jest zbyt stara (potrzebna %s, zainstalowana %s)\n"
@@ -2360,6 +2423,16 @@ msgstr "inicjowanie Bazy Zaufania nie powiod
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr "OSTRZE¯ENIE: podano adresatów (-r) w dzia³aniu które ich nie dotyczy\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "linia %d: niew³a¶ciwy algorytm\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "linia %d: niew³a¶ciwy algorytm\n"
+
 msgid "--store [filename]"
 msgstr "--store [plik]"
 
@@ -2454,6 +2527,15 @@ msgstr "opakowywanie ASCII nie powiod
 msgid "invalid hash algorithm '%s'\n"
 msgstr "niew³a¶ciwy algorytm skrótu ,,%s''\n"
 
+#, fuzzy, c-format
+#| msgid "error storing certificate: %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "b³±d zapisywania certyfikatu: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nazwa pliku]"
 
@@ -2758,6 +2840,20 @@ msgstr "wczytywanie kluczy tajnych nie jest dozwolone\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "klucz %s: klucz tajny z b³êdnym szyfrem %d - pominiêty\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2895,6 +2991,11 @@ msgstr "zbi
 msgid "keyblock resource '%s': %s\n"
 msgstr "zasób bloku klucza `%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening `%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "b³±d podczas otwierania ,,%s'': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "nie powiod³a siê odbudowa bufora bazy: %s\n"
@@ -2965,6 +3066,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "Proszê wpisaæ domenê ograniczaj±c± ten podpis lub Enter dla ¿adnej.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Identyfikator u¿ytkownika ,,%s'' zosta³ uniewa¿niony."
 
@@ -3292,6 +3397,11 @@ msgstr "Klucz uniewa
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Czy na pewno podpisaæ wszystkie identyfikatory u¿ytkownika? (t/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Czy na pewno podpisaæ wszystkie identyfikatory u¿ytkownika? (t/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Podpowied¼: wybierz identyfikatory u¿ytkownika do podpisania.\n"
 
@@ -3395,10 +3505,6 @@ msgstr "zapis zmian nie powi
 msgid "Key not changed so no update needed.\n"
 msgstr "Klucz nie zosta³ zmieniony wiêc zapis zmian nie jest konieczny.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "klucz prywatny ,,%s'' nie zosta³ odnaleziony: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3606,8 +3712,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "Czy na pewno chcesz wyznaczyæ ten klucz jako uniewa¿niaj±cy? (t/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Proszê wybraæ najwy¿ej jeden podklucz.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Czy na pewno chcesz wyznaczyæ ten klucz jako uniewa¿niaj±cy? (t/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Zmiana daty wa¿no¶ci podklucza.\n"
@@ -3657,6 +3768,11 @@ msgstr "Brak identyfikatora u
 msgid "No user ID with hash %s\n"
 msgstr "Brak identyfikatora u¿ytkownika o skrócie %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Brak podklucza o numerze %d.\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Brak podklucza o numerze %d.\n"
@@ -4012,6 +4128,10 @@ msgstr "Imi
 msgid "Invalid character in name\n"
 msgstr "Niew³a¶ciwy znak w imieniu lub nazwisku\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Imiê lub nazwisko nie mo¿e zaczynaæ siê od cyfry\n"
 
@@ -4461,10 +4581,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "OSTRZE¯ENIE: zaszyfrowana wiadomo¶æ by³a manipulowana!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "wyczyszczono has³o zapamiêtane z ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "b³±d odszyfrowywania: %s\n"
 
@@ -4667,6 +4783,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA wymaga d³ugo¶ci skrótu bêd±cego wielokrotno¶ci± 8 bitów\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Nieznany rodzaj podpisu ,,%s''\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Plik ,,%s'' ju¿ istnieje. "
@@ -5135,6 +5256,11 @@ msgstr "Zostanie uniewa
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(to jest czu³y klucz uniewa¿niaj±cy)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Dostêpny jest klucz tajny.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Stworzyæ certyfikat uniewa¿nienia tego klucza? (t/N) "
 
@@ -5170,6 +5296,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "klucz prywatny ,,%s'' nie zosta³ odnaleziony: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Stworzyæ certyfikat uniewa¿nienia tego klucza? (t/N) "
 
@@ -7320,7 +7458,7 @@ msgstr "b
 
 #, fuzzy
 #| msgid "certificate `%s' not found: %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "nie znaleziono certyfikatu ,,%s'': %s\n"
 
 #, fuzzy, c-format
@@ -7401,6 +7539,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "nie mo¿na siê po³±czyæ z ,,%s'': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "zapis zmian nie powiód³ siê: %s\n"
@@ -7443,36 +7586,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "b³±d podczas zapisu zbioru kluczy tajnych ,,%s'': %s\n"
 
 #, fuzzy, c-format
-#| msgid "failed to create stream from socket: %s\n"
-msgid "failed to allocate assuan context: %s\n"
-msgstr "nie uda³o siê utworzyæ strumienia z gniazda: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-#, fuzzy
-#| msgid "no running dirmngr - starting `%s'\n"
-msgid "no running dirmngr - starting one\n"
-msgstr "dirmngr nie dzia³a - uruchamianie ,,%s''\n"
-
-#, fuzzy, c-format
-#| msgid "malformed DIRMNGR_INFO environment variable\n"
-msgid "malformed %s environment variable\n"
-msgstr "z³y format zmiennej ¶rodowiskowej DIRMNGR_INFO\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "wersja %d protoko³u dirmngr nie jest obs³ugiwana\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "nie mo¿na po³±czyæ siê z dirmngr - próba fallbacku\n"
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "nie mo¿na siê po³±czyæ z ,,%s'': %s\n"
-
-#, fuzzy, c-format
 #| msgid "unsupported algorithm: %s"
 msgid "unsupported inquiry '%s'\n"
 msgstr "nieobs³ugiwany algorytm: %s"
@@ -7576,7 +7689,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7924,8 +8037,10 @@ msgstr "b
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "B³±d: prywatne DO zbyt d³ugie (limit to %d znaków).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+#| msgid "certificate `%s' not found: %s\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "nie znaleziono certyfikatu ,,%s'': %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8109,6 +8224,11 @@ msgid "can't allocate control structure: %s\n"
 msgstr "nie mo¿na przydzieliæ ³añcucha pliku wyj¶ciowego: %s\n"
 
 #, fuzzy, c-format
+#| msgid "failed to create stream from socket: %s\n"
+msgid "failed to allocate assuan context: %s\n"
+msgstr "nie uda³o siê utworzyæ strumienia z gniazda: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "inicjowanie Bazy Zaufania nie powiod³o siê: %s\n"
@@ -8335,7 +8455,7 @@ msgstr "Opcje steruj
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Opcje steruj±ce bezpieczeñstwem"
 
 msgid "Configuration for HTTP servers"
@@ -8605,6 +8725,48 @@ 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 "cleared passphrase cached with ID: %s\n"
+#~ msgstr "wyczyszczono has³o zapamiêtane z ID: %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "nie powiód³ siê zapis klucza: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open `%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Proszê wybraæ najwy¿ej jeden podklucz.\n"
+
+#, fuzzy
+#~| msgid "no running dirmngr - starting `%s'\n"
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "dirmngr nie dzia³a - uruchamianie ,,%s''\n"
+
+#, fuzzy
+#~| msgid "malformed DIRMNGR_INFO environment variable\n"
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "z³y format zmiennej ¶rodowiskowej DIRMNGR_INFO\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "wersja %d protoko³u dirmngr nie jest obs³ugiwana\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "nie mo¿na po³±czyæ siê z dirmngr - próba fallbacku\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "eksport kluczy w formacie opartym na S-wyra¿eniach"
 
@@ -8783,9 +8945,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Czy na pewno chcesz to zrobiæ? (t/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "b³±d odczytu bloku klucza tajnego ,,%s'': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Proszê usun±æ znacznik wyboru z kluczy prywatnych.\n"
 
index 91208b7..ad96dc8 100644 (file)
--- a/po/pt.po
+++ b/po/pt.po
@@ -1568,6 +1568,10 @@ msgstr "chave `%s' n
 msgid "error reading keyblock: %s\n"
 msgstr "erro na leitura do bloco de chave: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "chave `%s' não encontrada: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(a não ser que escolha a chave pela sua impressão digital)\n"
 
@@ -1776,6 +1780,19 @@ msgid "No fingerprint"
 msgstr "mostra impressão digital"
 
 #, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "chave `%s' não encontrada: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opções de importação inválidas\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NOME|usar NOME como chave secreta por omissão"
+
+#, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Chave inválida %08lX tornada válida por --allow-non-selfsigned-uid\n"
 
@@ -1907,6 +1924,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "criar saída com armadura ascii"
 
@@ -2112,12 +2132,49 @@ msgstr "mostrar em que porta-chave a chave est
 msgid "show expiration dates during signature listings"
 msgstr "Nenhuma assinatura correspondente no porta-chaves secreto\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "desactiva uma chave"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "destinatário por omissão desconhecido `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "destinatário por omissão desconhecido `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTA: o ficheiro antigo de opções por omissão `%s' foi ignorado\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "erro ao criar porta-chaves `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2325,6 +2382,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "AVISO: destinatários (-r) dados sem utilizar uma cifra de chave pública\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "algoritmo de dispersão inválido `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "algoritmo de dispersão inválido `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [nome_do_ficheiro]"
 
@@ -2421,6 +2486,14 @@ msgstr "cria
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritmo de dispersão inválido `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "erro na criação da frase secreta: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nome_do_ficheiro]"
 
@@ -2725,6 +2798,20 @@ msgstr "a escrever chave privada para `%s'\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "chave %08lX: chave secreta com cifra inválida %d - ignorada\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2858,6 +2945,10 @@ msgstr "porta-chaves `%s' criado\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "erro ao criar `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "erro na leitura de `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "falha ao criar 'cache' do porta-chaves: %s\n"
@@ -2926,6 +3017,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Utilizador \"%s\" está revocado."
 
@@ -3273,6 +3368,10 @@ msgstr "A chave est
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Realmente assinar todos os IDs de utilizador? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Realmente assinar todos os IDs de utilizador? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Sugestão: Selecione os IDs de utilizador para assinar\n"
 
@@ -3386,10 +3485,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Chave não alterada, nenhuma actualização é necessária.\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "chave `%s' não encontrada: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "%s: versão de ficheiro inválida %d\n"
 
@@ -3598,8 +3693,10 @@ msgid ""
 msgstr "não pode escolher uma chave como revogadora de si mesmo\n"
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Por favor seleccione no máximo uma chave secundária.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "não pode escolher uma chave como revogadora de si mesmo\n"
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3654,6 +3751,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Nenhum ID de utilizador com índice %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Nenhum ID de utilizador com índice %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Nenhum ID de utilizador com índice %d\n"
 
@@ -4010,6 +4111,10 @@ msgstr "Nome completo: "
 msgid "Invalid character in name\n"
 msgstr "Caracter inválido no nome\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "O nome não pode começar com um dígito\n"
 
@@ -4452,10 +4557,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "CUIDADO: a mensagem cifrada foi manipulada!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "decifragem falhou: %s\n"
 
@@ -4657,6 +4758,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "classe de assinatura desconhecida"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Arquivo `%s' já existe. "
@@ -5123,6 +5228,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr ""
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Chave secreta disponível.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Gerar um certificado de revogação para esta assinatura? (s/N)"
 
@@ -5158,6 +5268,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "chave `%s' não encontrada: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Gerar um certificado de revogação para esta assinatura? (s/N)"
@@ -7212,7 +7333,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "erro na leitura de `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "chave `%s' não encontrada: %s\n"
 
 #, fuzzy, c-format
@@ -7283,6 +7404,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "impossível ligar a `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "actualização falhou: %s\n"
@@ -7321,32 +7447,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "erro ao escrever no porta-chaves secreto `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: falha ao criar tabela de dispersão: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "variável de ambiente GPG_AGENT_INFO inválida\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "a versão %d do protocolo gpg-agent não é suportada\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "impossível ligar a `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7438,7 +7538,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7752,8 +7852,9 @@ msgstr "erro na leitura de `%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "chave `%s' não encontrada: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7910,6 +8011,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "impossível criar `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: falha ao criar tabela de dispersão: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "falha ao inicializar a base de dados de confiança: %s\n"
@@ -8120,7 +8225,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8377,6 +8482,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "não é possível abrir o porta-chaves"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Por favor seleccione no máximo uma chave secundária.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variável de ambiente GPG_AGENT_INFO inválida\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "a versão %d do protocolo gpg-agent não é suportada\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "alterna entre listagem de chave secreta e pública"
 
@@ -8543,10 +8678,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Você quer realmente fazer isso? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "erro na leitura do bloco de chave secreto `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Por favor remova as selecções das chaves secretas.\n"
 
@@ -9161,9 +9292,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "algoritmo de criptografia desconhecido"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "não é possível abrir o porta-chaves"
-
 #~ msgid "invalid packet"
 #~ msgstr "pacote inválido"
 
index c5eabf4..92cd9b6 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -1565,6 +1565,11 @@ msgstr "cheia \"%s\" nu a fost g
 msgid "error reading keyblock: %s\n"
 msgstr "eroare la citire keyblock: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "cheia \"%s\" nu a fost gãsitã: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(dacã nu specificaþi cheia prin amprentã)\n"
 
@@ -1775,6 +1780,19 @@ msgid "No fingerprint"
 msgstr "Amprenta CA: "
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "cheia secretã \"%s\" nu a fost gãsitã: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "opþiuni enumerare invalide\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NUME|foloseºte NUME ca cheie secretã implicitã"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "Cheia invalidã %s fãcutã validã de --allow-non-selfsigned-uid\n"
 
@@ -1905,6 +1923,9 @@ msgstr "|algo [fi
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "creazã ieºire în armurã ascii"
 
@@ -2139,12 +2160,50 @@ msgstr "arat
 msgid "show expiration dates during signature listings"
 msgstr "Nici o semnãturã corespunzãtoare în inelul secret\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "deactiveazã cheia"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "opþiune necunoscutã `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "opþiune necunoscutã `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "NOTÃ: fisier opþiuni implicite vechi `%s' ignorat\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "eroare la crearea inelului de chei `%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2351,6 +2410,14 @@ msgstr ""
 "AVERTISMENT: destinatari (-r) furnizaþi fãrã a folosi cifrare cu cheie "
 "publicã\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "algoritm hash invalid `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "algoritm hash invalid `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [nume_fiºier]"
 
@@ -2446,6 +2513,14 @@ msgstr "punerea armurii a e
 msgid "invalid hash algorithm '%s'\n"
 msgstr "algoritm hash invalid `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "eroare la obþinerea numãrului serial: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[nume_fiºier]"
 
@@ -2752,6 +2827,20 @@ msgstr "importul de chei secrete nu este permis\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "cheia %s: cheie secretã cu cifru invalid %d - sãritã\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2884,6 +2973,10 @@ msgstr "inelul de chei `%s' creat\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "resursã keyblock `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "eroare în `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "am eºuat sã reconstruiesc cache-ul inelului de chei: %s\n"
@@ -2955,6 +3048,10 @@ msgstr ""
 "apãsaþi enter pentru niciunul.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "ID utilizator \"%s\" a fost revocat."
 
@@ -3272,6 +3369,11 @@ msgstr "Cheia este revocat
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Semnaþi într-adevãr toate ID-urile utilizator? (d/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Semnaþi într-adevãr toate ID-urile utilizator? (d/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Sugestie: Selectaþi ID-ul utilizator de semnat\n"
 
@@ -3375,10 +3477,6 @@ msgstr "actualizarea a e
 msgid "Key not changed so no update needed.\n"
 msgstr "Cheia nu a fost schimbatã aºa cã nici o actualizare a fost necesarã.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "cheia secretã \"%s\" nu a fost gãsitã: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3590,8 +3688,15 @@ msgstr ""
 "Sunteþi sigur(ã) cã doriþi sã desemnaþi aceastã cheie ca ºi un revocator "
 "desemnat? (d/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Vã rugãm selectaþi cel mult o subcheie.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Sunteþi sigur(ã) cã doriþi sã desemnaþi aceastã cheie ca ºi un revocator "
+"desemnat? (d/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Schimb timpul de expirare pentru o subcheie.\n"
@@ -3644,6 +3749,11 @@ msgstr "Nici un ID utilizator cu indicele %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Nici un ID utilizator cu hash-ul %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Nici o subcheie cu indicele %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Nici o subcheie cu indicele %d\n"
@@ -3992,6 +4102,10 @@ msgstr "Nume real: "
 msgid "Invalid character in name\n"
 msgstr "Caracter invalid în nume\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Numele nu poate începe cu o cifrã\n"
 
@@ -4431,10 +4545,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "AVERTISMENT: mesajul cifrat a fost manipulat!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "decriptarea a eºuat: %s\n"
 
@@ -4633,6 +4743,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Tip de semnãturã necunoscut `%s'\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Fiºierul `%s' existã. "
@@ -5109,6 +5224,11 @@ msgstr "Pentru a fi revocat de:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Aceasta este o cheie de revocare senzitivã)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Cheia secretã este disponibilã.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Creaþi un certificat de revocare desemnat pentru aceastã cheie? (d/N) "
 
@@ -5144,6 +5264,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "cheia secretã \"%s\" nu a fost gãsitã: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Creaþi un certificat de revocare pentru aceastã cheie? (d/N) "
 
@@ -7218,7 +7350,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "eroare la citire `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "cheia secretã \"%s\" nu a fost gãsitã: %s\n"
 
 #, fuzzy, c-format
@@ -7289,6 +7421,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "nu mã pot conecta la `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "actualizarea a eºuat: %s\n"
@@ -7328,32 +7465,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "eroare la scrierea inelului de chei secret `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: am eºuat sã creez hashtable: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "variabila de mediu GPG_AGENT_INFO anormalã\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "gpg-agent versiune protocol %d nu este suportat\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "nu mã pot conecta la `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7447,7 +7558,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7773,8 +7884,9 @@ msgstr "eroare la citire `%s': %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Eroare DO personal pre lung (limita este de %d caractere).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "cheia secretã \"%s\" nu a fost gãsitã: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7933,6 +8045,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "nu pot crea fiºier de rezervã `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: am eºuat sã creez hashtable: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "am eºuat sã iniþializez TrustDB:%s\n"
@@ -8143,7 +8259,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8400,6 +8516,36 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "nu pot deschide inelul de chei"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Vã rugãm selectaþi cel mult o subcheie.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "variabila de mediu GPG_AGENT_INFO anormalã\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "gpg-agent versiune protocol %d nu este suportat\n"
+
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "comutã între listele de chei secrete ºi publice"
 
@@ -8572,9 +8718,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Doriþi într-adevãr sã faceþi acest lucru? (d/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "eroare la citire keyblock secret \"%s\": %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Vã rugãm ºtergeþi selecþiile din cheile secrete.\n"
 
@@ -9260,9 +9403,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "algoritm cifrare necunoscut"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "nu pot deschide inelul de chei"
-
 #~ msgid "invalid packet"
 #~ msgstr "pachet invalid"
 
index bdc1704..1744217 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -77,15 +77,13 @@ msgstr ""
 msgid ""
 "Please enter your PIN, so that the secret key can be unlocked for this "
 "session"
-msgstr ""
-"Введите PIN, чтобы сделать закрытый ключ доступным на протяжении этого сеанса"
+msgstr "Введите PIN, чтобы сделать секретный ключ доступным в этом сеансе"
 
 msgid ""
 "Please enter your passphrase, so that the secret key can be unlocked for "
 "this session"
 msgstr ""
-"Введите фразу-пароль, чтобы сделать закрытый ключ доступным на протяжении "
-"этого сеанса"
+"Введите фразу-пароль, чтобы сделать секретный ключ доступным в этом сеансе"
 
 msgid "PIN:"
 msgstr "PIN:"
@@ -186,8 +184,8 @@ msgid ""
 "Please enter a passphrase to protect the received secret key%%0A   %s%%0A   "
 "%s%%0Awithin gpg-agent's key storage"
 msgstr ""
-"Введите фразу-пароль для защиты полученного закрытого ключа%%0A   %s%%0A   %s"
-"%%0Aвнутри хранилища ключей агента gpg"
+"Введите фразу-пароль для защиты полученного секретного ключа%%0A   %s%%0A   "
+"%s%%0Aвнутри хранилища ключей агента gpg"
 
 #, c-format
 msgid "failed to create stream from socket: %s\n"
@@ -399,7 +397,7 @@ msgid ""
 "Secret key management for @GNUPG@\n"
 msgstr ""
 "Синтаксис: @GPG_AGENT@ [параметры] [команда [аргументы]]\n"
-"Управление закрытыми ключами для @GNUPG@\n"
+"Управление секретными ключами для @GNUPG@\n"
 
 #, c-format
 msgid "invalid debug-level '%s' given\n"
@@ -533,7 +531,7 @@ msgid ""
 "Secret key maintenance tool\n"
 msgstr ""
 "Синтаксис: gpg-protect-tool [параметры] [аргументы]\n"
-"Средство работы с закрытыми ключами\n"
+"Средство работы с секретными ключами\n"
 
 msgid "Please enter the passphrase to unprotect the PKCS#12 object."
 msgstr "Введите фразу-пароль для снятия защиты с объекта PKCS#12."
@@ -688,7 +686,7 @@ msgid "checking created signature failed: %s\n"
 msgstr "сбой проверки созданной подписи: %s\n"
 
 msgid "secret key parts are not available\n"
-msgstr "закрытая часть ключа недоступна\n"
+msgstr "секретная часть ключа недоступна\n"
 
 #, c-format
 msgid "public key algorithm %d (%s) is not supported\n"
@@ -946,7 +944,7 @@ msgid "Signature %d"
 msgstr "Подпись %d"
 
 msgid "Certificate chain valid"
-msgstr "ЦепоÑ\87ка Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cна"
+msgstr "ЦепоÑ\87ка Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82ов Ð´Ð¾Ñ\81Ñ\82овеÑ\80на"
 
 msgid "Root certificate trustworthy"
 msgstr "Корневой сертификат достоверен"
@@ -1474,6 +1472,11 @@ msgstr "ключ \"%s\" не найден: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "ошибка чтения блока ключей: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "ключ \"%s\" не найден: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(если только Вы не задали ключ отпечатком)\n"
 
@@ -1484,11 +1487,11 @@ msgid "Delete this key from the keyring? (y/N) "
 msgstr "Удалить данный ключ из таблицы? (y/N) "
 
 msgid "This is a secret key! - really delete? (y/N) "
-msgstr "Это закрытый ключ! - все равно удалить? (y/N) "
+msgstr "Это секретный ключ! - все равно удалить? (y/N) "
 
 #, c-format
 msgid "deleting secret %s failed: %s\n"
-msgstr "сбой при удалении закрытого %s: %s\n"
+msgstr "сбой при удалении секретного %s: %s\n"
 
 msgid "key"
 msgstr "ключа"
@@ -1505,7 +1508,7 @@ msgstr "сведения о доверии владельцу сброшены\n
 
 #, c-format
 msgid "there is a secret key for public key \"%s\"!\n"
-msgstr "имеется закрытый ключ для открытого ключа \"%s\"!\n"
+msgstr "имеется секретный ключ для открытого ключа \"%s\"!\n"
 
 msgid "use option \"--delete-secret-keys\" to delete it first.\n"
 msgstr "сначала удалите его командой \"--delete-secret-keys\".\n"
@@ -1635,7 +1638,7 @@ msgid "remove as much as possible from key during export"
 msgstr "при экспорте удалить из ключа как можно больше"
 
 msgid "exporting secret keys not allowed\n"
-msgstr "экспорт закрытых ключей не разрешен\n"
+msgstr "экспорт секретных ключей не разрешен\n"
 
 #, c-format
 msgid "key %s: PGP 2.x style key - skipped\n"
@@ -1666,10 +1669,24 @@ msgid "No fingerprint"
 msgstr "Нет отпечатка"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "закрытый ключ \"%s\" не найден: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "не хватает аргумента для параметра \"%.50s\"\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAME|использовать NAME как основной закрытый ключ"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
-"Ð\9fаÑ\80амеÑ\82Ñ\80 --allow-non-selfsigned-uid Ñ\81делал Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cный ключ %s "
-"дейÑ\81Ñ\82виÑ\82елÑ\8cным\n"
+"Ð\9fаÑ\80амеÑ\82Ñ\80 --allow-non-selfsigned-uid Ñ\81делал Ð½ÐµÐ´Ð¾Ñ\81Ñ\82овеÑ\80ный ключ %s "
+"доÑ\81Ñ\82овеÑ\80ным\n"
 
 #, c-format
 msgid "using subkey %s instead of primary key %s\n"
@@ -1709,7 +1726,7 @@ msgid "list keys and fingerprints"
 msgstr "вывести список ключей и их отпечатков"
 
 msgid "list secret keys"
-msgstr "вывести список закрытых ключей"
+msgstr "вывести список секретных ключей"
 
 msgid "generate a new key pair"
 msgstr "создать новую пару ключей"
@@ -1730,7 +1747,7 @@ msgid "remove keys from the public keyring"
 msgstr "удалить ключи из таблицы открытых ключей"
 
 msgid "remove keys from the secret keyring"
-msgstr "удалить ключи из таблицы закрытых ключей"
+msgstr "удалить ключи из таблицы секретных ключей"
 
 msgid "quickly sign a key"
 msgstr "быстро подписать ключ"
@@ -1786,6 +1803,9 @@ msgstr "вывести хэши сообщений"
 msgid "run in server mode"
 msgstr "запуск в режиме сервера"
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "вывод в текстовом формате"
 
@@ -1981,11 +2001,52 @@ msgstr "показать в списке ключей название табл
 msgid "show expiration dates during signature listings"
 msgstr "показать в списке подписей сроки действия"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Доступные ключи:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option '%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "неизвестный параметр '%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command '%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "неизвестная команда '%s'\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "Замечание: старый основной файл параметров '%s' проигнорирован\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "параметр \"%.50s\" неоднозначен\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "ошибка создания таблицы ключей '%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "слишком старая версия libcrypt (нужно %s, есть %s)\n"
 
@@ -2180,6 +2241,16 @@ msgstr ""
 "ВНИМАНИЕ: получатели (-r) заданы без использования шифрования с открытым "
 "ключом\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "строка %d: задана недопустимая дата\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "строка %d: задана недопустимая дата\n"
+
 msgid "--store [filename]"
 msgstr "--store [файл]"
 
@@ -2273,6 +2344,15 @@ msgstr "ошибка преобразования в текстовый форм
 msgid "invalid hash algorithm '%s'\n"
 msgstr "недопустимая хэш-функция '%s'\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "ошибка загрузки сертификата '%s': %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[файл]"
 
@@ -2385,15 +2465,15 @@ msgstr "          новых отзывов ключей: %lu\n"
 
 #, c-format
 msgid "      secret keys read: %lu\n"
-msgstr "    прочитано закрытых ключей: %lu\n"
+msgstr "    прочитано секретных ключей: %lu\n"
 
 #, c-format
 msgid "  secret keys imported: %lu\n"
-msgstr "импортировано закрытых ключей: %lu\n"
+msgstr "импортировано секретных ключей: %lu\n"
 
 #, c-format
 msgid " secret keys unchanged: %lu\n"
-msgstr " неизмененных закрытых ключей: %lu\n"
+msgstr " неизмененных секретных ключей: %lu\n"
 
 #, c-format
 msgid "          not imported: %lu\n"
@@ -2547,11 +2627,11 @@ msgstr "ключ %s: \"%s\" не изменен\n"
 
 #, c-format
 msgid "key %s: secret key imported\n"
-msgstr "ключ %s: импортирован закрытый ключ\n"
+msgstr "ключ %s: импортирован секретный ключ\n"
 
 #, c-format
 msgid "key %s: secret key already exists\n"
-msgstr "ключ %s: закрытый ключ уже имеется\n"
+msgstr "ключ %s: секретный ключ уже имеется\n"
 
 #, c-format
 msgid "key %s: error sending to agent: %s\n"
@@ -2559,14 +2639,28 @@ msgstr "ключ %s: ошибка отправки в агент: %s\n"
 
 #, c-format
 msgid "secret key %s: %s\n"
-msgstr "закрытый ключ %s: %s\n"
+msgstr "секретный ключ %s: %s\n"
 
 msgid "importing secret keys not allowed\n"
-msgstr "импорт закрытого ключа не допускается\n"
+msgstr "импорт секретного ключа не допускается\n"
 
 #, c-format
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
-msgstr "ключ %s: закрытый ключ с недопустимым шифром %d - пропущен\n"
+msgstr "ключ %s: секретный ключ с недопустимым шифром %d - пропущен\n"
+
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
 
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
@@ -2694,6 +2788,11 @@ msgstr "создана таблица ключей '%s'\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "источник блока ключей '%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "ошибка открытия '%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "сбой пересоставления буфера таблицы ключей: %s\n"
@@ -2765,6 +2864,10 @@ msgstr ""
 "строку, если нет ограничений.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "ID пользователя \"%s\" отозван."
 
@@ -3043,10 +3146,10 @@ msgid "compact unusable user IDs and remove all signatures from key"
 msgstr "сжать непригодные ID пользователей и удалить все подписи из ключа"
 
 msgid "Secret key is available.\n"
-msgstr "Ð\97акÑ\80Ñ\8bÑ\82ый ключ доступен.\n"
+msgstr "СекÑ\80еÑ\82ный ключ доступен.\n"
 
 msgid "Need the secret key to do this.\n"
-msgstr "Для данного действия нужен закрытый ключ.\n"
+msgstr "Для данного действия нужен секретный ключ.\n"
 
 msgid ""
 "* The 'sign' command may be prefixed with an 'l' for local signatures "
@@ -3064,6 +3167,11 @@ msgstr "Ключ отозван."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Действительно подписать все ID пользователя? (y/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Действительно подписать все ID пользователя? (y/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Подсказка: Выберите ID пользователей, которые нужно подписать\n"
 
@@ -3080,7 +3188,7 @@ msgstr "Вы должны выбрать хотя бы один ID пользо
 
 #, c-format
 msgid "(Use the '%s' command.)\n"
-msgstr ""
+msgstr "(Команда '%s'.)\n"
 
 msgid "You can't delete the last user ID!\n"
 msgstr "Вы не можете удалить последний ID пользователя!\n"
@@ -3163,10 +3271,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Ключ не изменялся - обновление не нужно.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "закрытый ключ \"%s\" не найден: %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" - не отпечаток\n"
 
@@ -3367,8 +3471,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "Вы уверены, что хотите назначить данный ключ отзывающим? (y/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Выделите не более одного подключа.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Вы уверены, что хотите назначить данный ключ отзывающим? (y/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Смена срока действия подключа.\n"
@@ -3417,6 +3526,11 @@ msgstr "Нет ID пользователя с индексом %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Нет ID пользователя с хэшем %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Нет подключа с индексом %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Нет подключа с индексом %d\n"
@@ -3463,7 +3577,7 @@ msgid "Really create the revocation certificates? (y/N) "
 msgstr "Действительно создать сертификат отзыва? (y/N) "
 
 msgid "no secret key\n"
-msgstr "нет закрытого ключа\n"
+msgstr "нет секретного ключа\n"
 
 #, c-format
 msgid "user ID \"%s\" is already revoked\n"
@@ -3758,6 +3872,10 @@ msgstr "Ваше полное имя: "
 msgid "Invalid character in name\n"
 msgstr "Недопустимый символ в имени\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Имя не должно начинаться с цифры\n"
 
@@ -3827,7 +3945,7 @@ msgid ""
 "You need a Passphrase to protect your secret key.\n"
 "\n"
 msgstr ""
-"Для защиты закрытого ключа необходима фраза-пароль.\n"
+"Для защиты секретного ключа необходима фраза-пароль.\n"
 "\n"
 
 msgid ""
@@ -3914,7 +4032,7 @@ msgid "error writing public keyring '%s': %s\n"
 msgstr "ошибка записи таблицы открытых ключей '%s': %s\n"
 
 msgid "public and secret key created and signed.\n"
-msgstr "открытый и закрытый ключи созданы и подписаны.\n"
+msgstr "открытый и секретный ключи созданы и подписаны.\n"
 
 msgid ""
 "Note that this key cannot be used for encryption.  You may want to use\n"
@@ -3941,10 +4059,10 @@ msgid "Note: creating subkeys for v3 keys is not OpenPGP compliant\n"
 msgstr "Замечание: создание подключей для ключей v3 не совместимо с OpenPGP\n"
 
 msgid "Secret parts of primary key are not available.\n"
-msgstr "Ð\97акÑ\80Ñ\8bÑ\82ые части первичного ключа отсутствуют.\n"
+msgstr "СекÑ\80еÑ\82ные части первичного ключа отсутствуют.\n"
 
 msgid "Secret parts of primary key are stored on-card.\n"
-msgstr "Ð\97акÑ\80Ñ\8bÑ\82ые части первичного ключа хранятся на карте.\n"
+msgstr "СекÑ\80еÑ\82ные части первичного ключа хранятся на карте.\n"
 
 msgid "Really create? (y/N) "
 msgstr "Действительно создать? (y/N) "
@@ -4178,10 +4296,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "Внимание: зашифрованное сообщение было изменено!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "в буфере сброшена фраза-пароль с индексом %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "сбой расшифровки: %s\n"
 
@@ -4371,6 +4485,11 @@ msgstr "неизвестный параметр '%s'\n"
 msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "Открытый ключ ECDSA бывает в кодировке SEC, кратной 8 битам\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Неизвестный тип подписи '%s'\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "Файл '%s' существует. "
@@ -4429,7 +4548,7 @@ msgid ""
 "%u-bit %s key, ID %s,\n"
 "created %s%s.\n"
 msgstr ""
-"Введите фразу-пароль для доступа к закрытому ключу сертификата OpenPGP:\n"
+"Введите фразу-пароль для доступа к секретному ключу сертификата OpenPGP:\n"
 "\"%.*s\"\n"
 "%u-битный ключ %s, ID %s,\n"
 "создан %s%s.\n"
@@ -4445,7 +4564,7 @@ msgid ""
 "You need a passphrase to unlock the secret key for\n"
 "user: \"%s\"\n"
 msgstr ""
-"Необходима фраза-пароль для доступа к закрытому ключу пользователя: \"%s\"\n"
+"Необходима фраза-пароль для доступа к секретному ключу пользователя: \"%s\"\n"
 
 #, c-format
 msgid "%u-bit %s key, ID %s, created %s"
@@ -4456,22 +4575,22 @@ msgid "         (subkey on main key ID %s)"
 msgstr "         (подключ на главном ключе %s)"
 
 msgid "Please enter the passphrase to unlock the OpenPGP secret key:"
-msgstr "Введите фразу-пароль для разблокировки закрытого ключа OpenPGP:"
+msgstr "Введите фразу-пароль для разблокировки секретного ключа OpenPGP:"
 
 msgid "Please enter the passphrase to import the OpenPGP secret key:"
-msgstr "Введите фразу-пароль для импорта закрытого ключа OpenPGP:"
+msgstr "Введите фразу-пароль для импорта секретного ключа OpenPGP:"
 
 msgid "Please enter the passphrase to export the OpenPGP secret subkey:"
-msgstr "Введите фразу-пароль для экспорта закрытого подключа OpenPGP:"
+msgstr "Введите фразу-пароль для экспорта секретного подключа OpenPGP:"
 
 msgid "Please enter the passphrase to export the OpenPGP secret key:"
-msgstr "Введите фразу-пароль для экспорта закрытого ключа OpenPGP:"
+msgstr "Введите фразу-пароль для экспорта секретного ключа OpenPGP:"
 
 msgid "Do you really want to permanently delete the OpenPGP secret subkey key:"
-msgstr "Вы действительно хотите навсегда удалить закрытый подключ OpenPGP:"
+msgstr "Вы действительно хотите навсегда удалить секретный подключ OpenPGP:"
 
 msgid "Do you really want to permanently delete the OpenPGP secret key:"
-msgstr "Вы действительно хотите навсегда удалить закрытый ключ OpenPGP:"
+msgstr "Вы действительно хотите навсегда удалить секретный ключ OpenPGP:"
 
 #, c-format
 msgid ""
@@ -4778,7 +4897,7 @@ msgstr "не могу открыть подписанные данные fd=%d:
 
 #, c-format
 msgid "anonymous recipient; trying secret key %s ...\n"
-msgstr "анонимный получатель; пробую закрытый ключ %s ...\n"
+msgstr "анонимный получатель; пробую секретный ключ %s ...\n"
 
 msgid "okay, we are the anonymous recipient.\n"
 msgstr "отлично, мы - анонимный получатель.\n"
@@ -4797,7 +4916,7 @@ msgstr ""
 
 #, c-format
 msgid "Note: secret key %s expired at %s\n"
-msgstr "Замечание: закрытый ключ %s просрочен с %s\n"
+msgstr "Замечание: секретный ключ %s просрочен с %s\n"
 
 msgid "Note: key has been revoked"
 msgstr "Замечание: ключ был отозван"
@@ -4816,6 +4935,11 @@ msgstr "Будет отозван:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Это особо важный ключ отзыва)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Закрытый ключ доступен.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Создать сертификат отзыва данного ключа? (y/N) "
 
@@ -4843,7 +4967,7 @@ msgid ""
 "a reason for the revocation."
 msgstr ""
 "Пользуйтесь им для отзыва этого ключа в случае раскрытия или потери\n"
-"закрытого ключа. Однако, если закрытый ключ доступен, лучше создать\n"
+"секретного ключа. Однако, если секретный ключ доступен, лучше создать\n"
 "новый сертификат с указанием причины отзыва."
 
 msgid ""
@@ -4855,6 +4979,18 @@ msgstr ""
 "вставлено двоеточие. Удалите это двоеточие в текстовом редакторе\n"
 "перед использованием этого сертификата отзыва."
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "закрытый ключ \"%s\" не найден: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Создать сертификат отзыва данного ключа? (y/N) "
 
@@ -5022,7 +5158,7 @@ msgid "skipped \"%s\": duplicated\n"
 msgstr "пропущено \"%s\": дубликат\n"
 
 msgid "skipped: secret key already present\n"
-msgstr "пропущено: закрытый ключ уже имеется\n"
+msgstr "пропущено: секретный ключ уже имеется\n"
 
 msgid "this is a PGP generated Elgamal key which is not secure for signatures!"
 msgstr ""
@@ -5264,8 +5400,8 @@ msgstr "требуется %d с ограниченным доверием, %d 
 msgid ""
 "depth: %d  valid: %3d  signed: %3d  trust: %d-, %dq, %dn, %dm, %df, %du\n"
 msgstr ""
-"глÑ\83бина: %d  Ð²ÐµÑ\80нÑ\8bÑ\85: %3d  Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81аннÑ\8bÑ\85: %3d  Ð´Ð¾Ð²ÐµÑ\80ие: %d-, %dq, %dn, %dm, "
-"%df, %du\n"
+"глÑ\83бина: %d  Ð´Ð¾Ñ\81Ñ\82овеÑ\80нÑ\8bÑ\85: %3d  Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81аннÑ\8bÑ\85: %3d  Ð´Ð¾Ð²ÐµÑ\80ие: %d-, %dq, %dn, "
+"%dm, %df, %du\n"
 
 #, c-format
 msgid "unable to update trustdb version record: write failed: %s\n"
@@ -5273,21 +5409,19 @@ msgstr ""
 "невозможно обновить запись о версии таблицы доверия: ошибка записи: %s\n"
 
 msgid "undefined"
-msgstr ""
+msgstr "неопределено"
 
-#, fuzzy
-#| msgid "never     "
 msgid "never"
-msgstr "никогда   "
+msgstr "никогда"
 
 msgid "marginal"
-msgstr ""
+msgstr "ограничено"
 
 msgid "full"
-msgstr ""
+msgstr "полное"
 
 msgid "ultimate"
-msgstr ""
+msgstr "абсолютное"
 
 #. TRANSLATORS: these strings are similar to those in
 #. trust_value_to_string(), but are a fixed length.  This is needed to
@@ -5298,34 +5432,28 @@ msgstr ""
 #. essentially a comment and need not be translated.  Either key and
 #. uid are both NULL, or neither are NULL.
 msgid "10 translator see trust.c:uid_trust_string_fixed"
-msgstr ""
+msgstr "12 translator see trust.c:uid_trust_string_fixed"
 
-#, fuzzy
-#| msgid "revoked"
 msgid "[ revoked]"
-msgstr "отозван"
+msgstr "[   отозван  ]"
 
-#, fuzzy
-#| msgid "expired"
 msgid "[ expired]"
-msgstr "просрочен"
+msgstr "[  просрочен ]"
 
-#, fuzzy
-#| msgid "unknown"
 msgid "[ unknown]"
-msgstr "неизвестно"
+msgstr "[ неизвестно ]"
 
 msgid "[  undef ]"
-msgstr ""
+msgstr "[неопределено]"
 
 msgid "[marginal]"
-msgstr ""
+msgstr "[ ограничено ]"
 
 msgid "[  full  ]"
-msgstr ""
+msgstr "[   полное   ]"
 
 msgid "[ultimate]"
-msgstr ""
+msgstr "[  абсолютно ]"
 
 msgid ""
 "the signature could not be verified.\n"
@@ -5710,16 +5838,16 @@ msgstr "сбой проверки списка отозванных сертиф
 
 #, c-format
 msgid "certificate with invalid validity: %s"
-msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81 Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cной Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cностью: %s"
+msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81 Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cной Ð´Ð¾Ñ\81Ñ\82овеÑ\80ностью: %s"
 
 msgid "certificate not yet valid"
-msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен"
+msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´Ð¾Ñ\81Ñ\82овеÑ\80ен"
 
 msgid "root certificate not yet valid"
-msgstr "коÑ\80невой Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен"
+msgstr "коÑ\80невой Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´Ð¾Ñ\81Ñ\82овеÑ\80ен"
 
 msgid "intermediate certificate not yet valid"
-msgstr "пÑ\80омежÑ\83Ñ\82оÑ\87нÑ\8bй Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен"
+msgstr "пÑ\80омежÑ\83Ñ\82оÑ\87нÑ\8bй Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐµÑ\89е Ð½Ðµ Ð´Ð¾Ñ\81Ñ\82овеÑ\80ен"
 
 msgid "certificate has expired"
 msgstr "сертификат просрочен"
@@ -5735,7 +5863,7 @@ msgid "required certificate attributes missing: %s%s%s"
 msgstr "сертификат не имеет требуемых атрибутов: %s%s%s"
 
 msgid "certificate with invalid validity"
-msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81 Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cной Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cностью"
+msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81 Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cной Ð´Ð¾Ñ\81Ñ\82овеÑ\80ностью"
 
 msgid "signature not created during lifetime of certificate"
 msgstr "подпись создана вне времени действия сертификата"
@@ -5853,7 +5981,7 @@ msgid ""
 "S/N %s, ID 0x%08lX,\n"
 "created %s, expires %s.\n"
 msgstr ""
-"Введите фразу-пароль для доступа к закрытому ключу сертификата X.509:\n"
+"Введите фразу-пароль для доступа к секретному ключу сертификата X.509:\n"
 "\"%s\"\n"
 "S/N %s, ID 0x%08lX,\n"
 "создан %s, истекает %s.\n"
@@ -6129,7 +6257,7 @@ msgid "never consult a CRL"
 msgstr "не сверять со списком отозванных сертификатов"
 
 msgid "check validity using OCSP"
-msgstr "пÑ\80овеÑ\80ка Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cности с помощью OCSP"
+msgstr "пÑ\80овеÑ\80ка Ð´Ð¾Ñ\81Ñ\82овеÑ\80ности с помощью OCSP"
 
 msgid "|N|number of certificates to include"
 msgstr "|N|число включаемых сертификатов"
@@ -6165,7 +6293,7 @@ msgid "|FILE|add keyring to the list of keyrings"
 msgstr "|FILE|добавить таблицу ключей в список таблиц ключей"
 
 msgid "|USER-ID|use USER-ID as default secret key"
-msgstr "|USER-ID|использовать USER-ID как основной закрытый ключ"
+msgstr "|USER-ID|использовать USER-ID как основной секретный ключ"
 
 msgid "|SPEC|use this keyserver to lookup keys"
 msgstr "|SPEC|искать ключи на данном сервере ключей"
@@ -6715,7 +6843,7 @@ msgstr "сбой проверки подписи списка отозванны
 #, c-format
 msgid "error checking validity of CRL issuer certificate: %s\n"
 msgstr ""
-"оÑ\88ибка Ð¿Ñ\80овеÑ\80ки Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cности сертификата издателя списка отозванных "
+"оÑ\88ибка Ð¿Ñ\80овеÑ\80ки Ð´Ð¾Ñ\81Ñ\82овеÑ\80ности сертификата издателя списка отозванных "
 "сертификатов: %s\n"
 
 #, c-format
@@ -6872,7 +7000,7 @@ msgstr "ошибка получения '%s': статус HTTP %u\n"
 
 #, fuzzy
 #| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr ""
 "Доступ к списку отозванных сертификатов невозможен\n"
 "из-за того, что не задействуется %s\n"
@@ -6927,7 +7055,7 @@ msgid ""
 msgstr ""
 "Синтаксис: dirmngr-client [параметры] [файл_сертификата|шаблон]\n"
 "Проверка сертификата X.509 по списку отозванных сертификатов или по OCSP\n"
-"Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 Ð²Ð¾Ð·Ð²Ñ\80аÑ\89аеÑ\82 0, ÐµÑ\81ли Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен, 1, ÐµÑ\81ли Ð½ÐµÐ´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен,\n"
+"Ð\9fÑ\80оÑ\86еÑ\81Ñ\81 Ð²Ð¾Ð·Ð²Ñ\80аÑ\89аеÑ\82 0, ÐµÑ\81ли Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ð´Ð¾Ñ\81Ñ\82овеÑ\80ен, 1, ÐµÑ\81ли Ð½ÐµÐ´Ð¾Ñ\81Ñ\82овеÑ\80ен,\n"
 "и другие коды ошибок при общих отказах\n"
 
 #, c-format
@@ -6942,6 +7070,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "сертификат слишком велик, чтобы иметь какой-то смысл\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "не могу подключиться к dirmngr: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "сбой при поиске: %s\n"
 
@@ -6957,7 +7089,7 @@ msgid "validation of certificate failed: %s\n"
 msgstr "сбой при проверке сертификата: %s\n"
 
 msgid "certificate is valid\n"
-msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елен\n"
+msgstr "Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ð´Ð¾Ñ\81Ñ\82овеÑ\80ен\n"
 
 msgid "certificate has been revoked\n"
 msgstr "сертификат был отозван\n"
@@ -6975,31 +7107,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "ошибка записи в кодировке base64: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "сбой размещения контекста Assuan: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "видимо, dirmngr не работает\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "dirmngr не выполняется - запуск\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "неправильная переменная окружения %s\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "протокол dirmngr версии %d не поддерживается\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "не могу подключиться к dirmngr - пробую запасной вариант\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "не могу подключиться к dirmngr: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "запрос '%s' не поддерживается\n"
 
@@ -7091,7 +7198,7 @@ msgstr ""
 "|FILE|использовать сертификаты удостоверяющего центра из файла FILE для HKP "
 "по TLS"
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 msgid ""
@@ -7386,7 +7493,7 @@ msgstr "слишком длинный ответ сервера; предел -
 
 #, fuzzy
 #| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
+msgid "OCSP request not possible due to Tor mode\n"
 msgstr "запрос OCSP невозможен из-за отключения HTTP\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
@@ -7540,6 +7647,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "сбой при выделении памяти под управляющую структуру: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "сбой размещения контекста Assuan: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "сбой инициализации сервера: %s\n"
 
@@ -7702,7 +7813,7 @@ msgid "do not allow the reuse of old passphrases"
 msgstr "не разрешать повторное использование старых фраз-паролей"
 
 msgid "|NAME|use NAME as default secret key"
-msgstr "|NAME|использовать NAME как основной закрытый ключ"
+msgstr "|NAME|использовать NAME как основной секретный ключ"
 
 msgid "|NAME|encrypt to user ID NAME as well"
 msgstr "|NAME|зашифровывать также для ID пользователя NAME"
@@ -7741,7 +7852,7 @@ msgstr "Параметры, управляющие интерактивност
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Параметры, управляющие безопасностью"
 
 msgid "Configuration for HTTP servers"
@@ -7772,7 +7883,7 @@ msgid "GPG for S/MIME"
 msgstr "GPG для S/MIME"
 
 msgid "Key Acquirer"
-msgstr ""
+msgstr "Диспетчер ключей"
 
 msgid "PIN and Passphrase Entry"
 msgstr "Ввод PIN и фраз-паролей"
@@ -7870,7 +7981,7 @@ msgid "program filename"
 msgstr "имя файла программы"
 
 msgid "secret key file (required)"
-msgstr "файл закрытого ключа (обязателен)"
+msgstr "файл секретного ключа (обязателен)"
 
 msgid "input file name (default stdin)"
 msgstr "имя входного файла (по умолчанию stdin)"
@@ -7993,6 +8104,47 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметры] файл_образцов\n"
 "Проверить фразу-пароль, поступающую из stdin, по файлу образцов\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "в буфере сброшена фраза-пароль с индексом %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "сбой сохранения ключа: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Выделите не более одного подключа.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "видимо, dirmngr не работает\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "dirmngr не выполняется - запуск\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "неправильная переменная окружения %s\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "протокол dirmngr версии %d не поддерживается\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "не могу подключиться к dirmngr - пробую запасной вариант\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "экспортировать ключи в формате на основе S-выражений"
 
index 2d65434..f23304b 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -1568,6 +1568,10 @@ msgstr "k
 msgid "error reading keyblock: %s\n"
 msgstr "chyba pri èítaní bloku kµúèa: %s\n"
 
+#, fuzzy, c-format
+msgid "key \"%s\" not found\n"
+msgstr "kµúè `%s' nebol nájdený: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(pokiaµ neurèíte kµúè jeho fingerprintom)\n"
 
@@ -1779,6 +1783,19 @@ msgstr "chyba pri vytv
 msgid "No fingerprint"
 msgstr "vypísa» fingerprint"
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "tajný kµúè `%s' nebol nájdený: %s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "neplatný parameter pre import\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|MENO|pou¾i MENO ako implicitný tajný kµúè"
+
 # c-format
 #, fuzzy, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
@@ -1913,6 +1930,9 @@ msgstr "|algo [s
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "vytvor výstup zakódovaný pomocou ASCII"
 
@@ -2122,12 +2142,49 @@ msgstr "uk
 msgid "show expiration dates during signature listings"
 msgstr "V súbore tajných kµúèov chýba zodpovedajúci podpis\n"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "nastavi» kµúè ako neplatný (disable)"
+
+#, fuzzy, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "neznámy implicitný adresát `%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "neznámy implicitný adresát `%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "POZNÁMKA: starý implicitný súbor s mo¾nos»ami `%s ignorovaný'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "chyba pri vytváraní súboru kµúèov (keyring)`%s': %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2333,6 +2390,14 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "VAROVANIE: daný adresát (-r) bez pou¾itia ¹ifrovania s verejným kµúèom\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "neplatný hashovací algoritmus `%s'\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "neplatný hashovací algoritmus `%s'\n"
+
 msgid "--store [filename]"
 msgstr "--store [meno súboru]"
 
@@ -2433,6 +2498,14 @@ msgstr "k
 msgid "invalid hash algorithm '%s'\n"
 msgstr "neplatný hashovací algoritmus `%s'\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "chyba pri vytváraní hesla: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[meno súboru]"
 
@@ -2738,6 +2811,20 @@ msgstr "zapisujem tajn
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "kµúè %08lX: tajný kµúè bez verejného kµúèa %d - preskoèené\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2871,6 +2958,10 @@ msgstr "s
 msgid "keyblock resource '%s': %s\n"
 msgstr "chyba pri vytváraní `%s': %s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "chyba pri èítaní `%s': %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "zlyhalo obnovenie vyrovnávacej pamäti kµúèov: %s\n"
@@ -2940,6 +3031,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr ""
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "U¾ívateµské ID \"%s\" je revokované."
 
@@ -3285,6 +3380,10 @@ msgstr "K
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Skutoène podpísa» v¹etky id u¾ívateµa? "
 
+#, fuzzy
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Skutoène podpísa» v¹etky id u¾ívateµa? "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Nápoveda: Vyberte id u¾ívateµa na podpísanie\n"
 
@@ -3397,10 +3496,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "kµúè nebol zmenený, tak¾e nie je potrebné ho aktualizova».\n"
 
 #, fuzzy, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "tajný kµúè `%s' nebol nájdený: %s\n"
-
-#, fuzzy, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "chyba: neplatný odtlaèok\n"
 
@@ -3609,8 +3704,10 @@ msgid ""
 msgstr "Ste si istý, ¾e chcete oznaèi» tento kµúè ako revokovací? (a/N): "
 
 #, fuzzy
-msgid "Please select at most one subkey.\n"
-msgstr "Prosím, vyberte najviac jeden sekundárny kµúè.\n"
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "Ste si istý, ¾e chcete oznaèi» tento kµúè ako revokovací? (a/N): "
 
 #, fuzzy
 msgid "Changing expiration time for a subkey.\n"
@@ -3665,6 +3762,10 @@ msgid "No user ID with hash %s\n"
 msgstr "Neexistuje identifikátor u¾ívateµa s indexom %d\n"
 
 #, fuzzy, c-format
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Neexistuje identifikátor u¾ívateµa s indexom %d\n"
+
+#, fuzzy, c-format
 msgid "No subkey with index %d\n"
 msgstr "Neexistuje identifikátor u¾ívateµa s indexom %d\n"
 
@@ -4019,6 +4120,10 @@ msgstr "Meno a priezvisko: "
 msgid "Invalid character in name\n"
 msgstr "Neplatný znak ve mene\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Meno nemô¾e zaèína» èíslicou\n"
 
@@ -4460,10 +4565,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "VAROVANIE: so za¹ifrovanou správou bolo manipulované!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "de¹ifrovanie zlyhalo: %s\n"
 
@@ -4663,6 +4764,10 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 
 #, fuzzy, c-format
+msgid "unknown weak digest '%s'\n"
+msgstr "neznáma trieda podpisu"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Súbor `%s' existuje. "
@@ -5130,6 +5235,11 @@ msgid "(This is a sensitive revocation key)\n"
 msgstr "(Toto je citlivý revokaèný kµúè)\n"
 
 #, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Tajný kµúè je dostupný.\n"
+
+#, fuzzy
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Vytvori» pre tento podpis revokaèný certifikát? "
 
@@ -5164,6 +5274,17 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+msgid "secret key \"%s\" not found\n"
+msgstr "tajný kµúè `%s' nebol nájdený: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 #, fuzzy
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Vytvori» pre tento podpis revokaèný certifikát? "
@@ -7226,7 +7347,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "chyba pri èítaní `%s': %s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "kµúè `%s' nebol nájdený: %s\n"
 
 #, fuzzy, c-format
@@ -7297,6 +7418,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "nemô¾em sa pripoji» k `%s': %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "aktualizácia zlyhala: %s\n"
@@ -7335,32 +7461,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "chyba pri zápise do súboru tajných kµúèov `%s': %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s: nepodarilo sa vytvori» hashovaciu tabuµku: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "zlý formát premennej prostredia GPG_AGENT_INFO\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "gpg-agent protokol verzie %d nie je podporovaný\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "nemô¾em sa pripoji» k `%s': %s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7452,7 +7552,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7765,8 +7865,9 @@ msgstr "chyba pri 
 msgid "response from server too large; limit is %d bytes\n"
 msgstr ""
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "kµúè `%s' nebol nájdený: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7924,6 +8025,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "nemô¾em vytvori» `%s': %s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s: nepodarilo sa vytvori» hashovaciu tabuµku: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "nemô¾em inicializova» databázu dôvery: %s\n"
@@ -8132,7 +8237,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8390,6 +8495,36 @@ msgid ""
 msgstr ""
 
 #, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "nemô¾em otvori» súbor kµúèov"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#, fuzzy
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Prosím, vyberte najviac jeden sekundárny kµúè.\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "zlý formát premennej prostredia GPG_AGENT_INFO\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "gpg-agent protokol verzie %d nie je podporovaný\n"
+
+#, fuzzy
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "prepnú» medzi vypísaním zoznamu tajných a verejných kµúèov"
 
@@ -8566,10 +8701,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Skutoène to chcete urobi»? "
 
-#, fuzzy
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "chyba pri èítaní bloku tajného kµúèa `%s': %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Prosím, odstráòte výber z tajných kµúèov.\n"
 
@@ -9201,9 +9332,6 @@ msgstr ""
 #~ msgid "unknown cipher algorithm"
 #~ msgstr "neznámy ¹ifrovací algoritmus"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "nemô¾em otvori» súbor kµúèov"
-
 #~ msgid "invalid packet"
 #~ msgstr "neplatný paket"
 
index 18fbda1..a589184 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -1626,6 +1626,11 @@ msgstr "nyckeln \"%s\" hittades inte: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "fel vid läsning av nyckelblock: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "nyckeln \"%s\" hittades inte: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(om du inte anger nyckeln med hjälp av fingeravtrycket)\n"
 
@@ -1835,6 +1840,20 @@ msgid "No fingerprint"
 msgstr "Inget fingeravtryck"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "hemliga nyckeln \"%s\" hittades inte: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "argument för flaggan \"%.50s\" saknas\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAMN|använd NAMN som förvald hemlig nyckel"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Ogiltiga nyckeln %s tvingades till giltig med --allow-non-selfsigned-uid\n"
@@ -1963,6 +1982,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "skapa utdata med ett ascii-skal"
 
@@ -2188,12 +2210,53 @@ msgstr "visa nyckelringens namn i nyckellistningar"
 msgid "show expiration dates during signature listings"
 msgstr "visa utgångsdatum under signaturlistningar"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Tillgängliga nycklar:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "okänd flagga \"%s\"\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command `%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "okänt kommando \"%s\"\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "OBS: den gamla inställningsfilen \"%s\" används inte\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "flagga \"%.50s\" är tvetydig\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "fel när nyckelringen \"%s\" skapades: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt är för gammalt (behöver %s, har %s)\n"
 
@@ -2406,6 +2469,16 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "VARNING: mottagare (-r) angivna utan att använda publik nyckel-kryptering\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "rad %d: ogiltig algoritm\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "rad %d: ogiltig algoritm\n"
+
 msgid "--store [filename]"
 msgstr "--store [filnamn]"
 
@@ -2501,6 +2574,15 @@ msgstr "misslyckades med att skapa ASCII-skal: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "ogiltig kontrollsummealgoritm \"%s\"\n"
 
+#, fuzzy, c-format
+#| msgid "error storing certificate: %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "fel vid lagring av certifikat: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[filnamn]"
 
@@ -2813,6 +2895,20 @@ msgstr "import av hemliga nycklar tillåts inte\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "nyckel %s: hemlig nyckel med ogiltigt chiffer %d - hoppade över\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "nyckel %s: ingen publik nyckel - kan inte verkställa spärrcertifikat\n"
@@ -2948,6 +3044,11 @@ msgstr "%s: nyckelring skapad\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "nyckelblockresurs \"%s\": %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening `%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "fel vid öppnandet av \"%s\": %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "misslyckades med att återskapa nyckelringscache: %s\n"
@@ -3018,6 +3119,10 @@ msgstr ""
 "Ange en domän för att begränsa denna signatur. eller Enter för ingen.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Användaridentiteten \"%s\" är spärrad."
 
@@ -3338,6 +3443,11 @@ msgstr "Nyckeln är spärrad."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Verkligen signera alla användaridentiteter? (j/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Verkligen signera alla användaridentiteter? (j/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Tips: Välj de användaridentiteter som du vill signera\n"
 
@@ -3440,10 +3550,6 @@ msgstr "uppdateringen misslyckades: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Nyckeln är oförändrad så det behövs ingen uppdatering.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "hemliga nyckeln \"%s\" hittades inte: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3655,8 +3761,15 @@ msgid ""
 msgstr ""
 "Är du säker på att du vill använda den här nyckeln för spärrning? (j/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Välj som mest en undernyckel.\n"
+# designated = angiven (utnämnd, utpekad, bestämd, utsedd, avsedd, angiven, designerad)
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Är du säker på att du vill använda den här nyckeln för spärrning? (j/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Ändrar utgångstid för en undernyckel.\n"
@@ -3708,6 +3821,11 @@ msgstr "Ingen användaridentitet med indexet %d\n"
 msgid "No user ID with hash %s\n"
 msgstr "Ingen användaridentitet med hashen %s\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Ingen undernyckel med indexet %d\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Ingen undernyckel med indexet %d\n"
@@ -4071,6 +4189,10 @@ msgstr "Namn: "
 msgid "Invalid character in name\n"
 msgstr "Ogiltigt tecken i namnet\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Namnet får inte börja med en siffra\n"
 
@@ -4519,10 +4641,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "VARNING: det krypterade meddelandet har ändrats!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "tömde mellanlagrad lösenfras med ID: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "dekrypteringen misslyckades: %s\n"
 
@@ -4726,6 +4844,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA kräver att hashlängden är delbar med 8 bitar\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Okänd signaturtyp \"%s\"\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "Filen \"%s\" finns. "
@@ -5205,6 +5328,11 @@ msgstr "Kommer att spärras av:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Detta är en känslig spärrnyckel)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Den hemliga nyckeln finns tillgänglig.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "Skapa ett spärrcertifikat för denna nyckel? (j/N) "
 
@@ -5246,6 +5374,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "hemliga nyckeln \"%s\" hittades inte: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Skapa ett spärrcertifikat för denna nyckel? (j/N) "
 
@@ -7431,7 +7571,7 @@ msgstr "fel vid körning av \"%s\": avslutsstatus %d\n"
 
 #, fuzzy
 #| msgid "certificate `%s' not found: %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "certifikatet \"%s\" hittades inte: %s\n"
 
 #, fuzzy, c-format
@@ -7512,6 +7652,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "kan inte ansluta till \"%s\": %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "uppdateringen misslyckades: %s\n"
@@ -7554,36 +7699,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "fel vid skrivning av hemliga nyckelringen \"%s\": %s\n"
 
 #, fuzzy, c-format
-#| msgid "failed to create stream from socket: %s\n"
-msgid "failed to allocate assuan context: %s\n"
-msgstr "misslyckades med att skapa flöde från uttag: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-#, fuzzy
-#| msgid "no running dirmngr - starting `%s'\n"
-msgid "no running dirmngr - starting one\n"
-msgstr "ingen körande dirmngr - startar \"%s\"\n"
-
-#, fuzzy, c-format
-#| msgid "malformed DIRMNGR_INFO environment variable\n"
-msgid "malformed %s environment variable\n"
-msgstr "miljövariabeln DIRMNGR_INFO är felformaterad\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "dirmngr-protokoll version %d stöds inte\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "kan inte ansluta till dirmngr - försöker falla tillbaka\n"
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "kan inte ansluta till \"%s\": %s\n"
-
-#, fuzzy, c-format
 #| msgid "unsupported algorithm: %s"
 msgid "unsupported inquiry '%s'\n"
 msgstr "algoritmen stöds inte: %s"
@@ -7686,7 +7801,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 # inställningar istället för flaggor?
@@ -8038,8 +8153,10 @@ msgstr "fel vid läsning från %s: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Fel: Privat DO för långt (gränsen är %d tecken).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+#| msgid "certificate `%s' not found: %s\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "certifikatet \"%s\" hittades inte: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8223,6 +8340,11 @@ msgid "can't allocate control structure: %s\n"
 msgstr "kan inte allokera utfilssträng: %s\n"
 
 #, fuzzy, c-format
+#| msgid "failed to create stream from socket: %s\n"
+msgid "failed to allocate assuan context: %s\n"
+msgstr "misslyckades med att skapa flöde från uttag: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "misslyckades med att initialisera tillitsdatabasen: %s\n"
@@ -8447,7 +8569,7 @@ msgstr "Flaggor som kontrollerar interaktivitet och framtvingande"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Flaggor som kontrollerar säkerheten"
 
 msgid "Configuration for HTTP servers"
@@ -8719,6 +8841,48 @@ msgstr ""
 "Syntax: gpg-check-pattern [flaggor] mönsterfil\n"
 "Kontrollera en lösenfras angiven på standard in mot mönsterfilen\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "tömde mellanlagrad lösenfras med ID: %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "misslyckades med att lagra nyckeln: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open `%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Välj som mest en undernyckel.\n"
+
+#, fuzzy
+#~| msgid "no running dirmngr - starting `%s'\n"
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "ingen körande dirmngr - startar \"%s\"\n"
+
+#, fuzzy
+#~| msgid "malformed DIRMNGR_INFO environment variable\n"
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "miljövariabeln DIRMNGR_INFO är felformaterad\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "dirmngr-protokoll version %d stöds inte\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "kan inte ansluta till dirmngr - försöker falla tillbaka\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "exportera nycklar i ett S-uttrycksbaserat format"
 
@@ -8901,9 +9065,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Vill du verkligen göra detta? (j/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "fel vid läsning av hemligt nyckelblock \"%s\": %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Tag bort markeringar från de hemliga nycklarna.\n"
 
index 50e9f05..7246154 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -1575,6 +1575,11 @@ msgstr "anahtar \"%s\" yok: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "anahtar bloğu okunurken hata: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "anahtar \"%s\" yok: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(anahtarı parmak izi ile belirtmedikçe)\n"
 
@@ -1782,6 +1787,20 @@ msgid "No fingerprint"
 msgstr "Parmak izi yok"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "gizli anahtar \"%s\" yok: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "\"%.50s\" seçeneği için değiştirge eksik\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|İSİM|öntanımlı gizli anahtar olarak İSİM kullanılır"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Geçersiz %s anahtarı --allow-non-selfsigned-uid kullanılarak geçerli oldu\n"
@@ -1909,6 +1928,9 @@ 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)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "ascii zırhlı çıktı oluşturur"
 
@@ -2128,12 +2150,52 @@ msgstr "anahtar zinciri ismini anahtar listelerinde gösterir"
 msgid "show expiration dates during signature listings"
 msgstr "imza listelemesi sırasında zamanaşımı tarihleri gösterilir"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "anahtarı iptal eder"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "`%s' seçeneği bilinmiyor\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command `%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "komut `%s' bilinmiyor\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "BİLGİ: eski öntanımlı seçenekler dosyası `%s' yoksayıldı\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "\"%.50s\" seçeneği belirsiz\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "`%s' anahtarlığı oluşturulurken hata: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt çok eski (%s lazım, sizinki %s)\n"
 
@@ -2339,6 +2401,16 @@ msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr ""
 "UYARI: alıcılar (-r) genel anahtar şifrelemesi kullanılmadan belirtilmiş\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "`%d. satır: algoritma geçersiz\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid algorithm\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "`%d. satır: algoritma geçersiz\n"
+
 msgid "--store [filename]"
 msgstr "--store [dosyaismi]"
 
@@ -2434,6 +2506,15 @@ msgstr "zırhlama başarısız: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "`%s' çittirim algoritması geçersiz\n"
 
+#, fuzzy, c-format
+#| msgid "error storing certificate: %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "serifika saklanırken hata: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[dosyaismi]"
 
@@ -2743,6 +2824,20 @@ msgstr "gizli anahtarı alımına izin verilmez\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "anahtar %s: geçersiz şifreli (%d) gizli anahtar - atlandı\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2882,6 +2977,11 @@ msgstr "`%s' anahtarlığı oluşturuldu\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "anahtar bloku özkaynağı `%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening `%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "'%s' açılırken hata: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "anahtar zinciri önbelleği yeniden oluşturulurken hata: %s\n"
@@ -2951,6 +3051,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "Bu imzayı kısıtlayacak bir etki alanı girin, yoksa <enter> tuşlayın.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Kullanıcı kimliği \"%s\" yürürlükten kaldırıldı."
 
@@ -3276,6 +3380,11 @@ msgstr "Anahtar yürürlükten kaldırıldı."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Tüm kullanıcı kimlikler gerçekten imzalanacak mı? (e/H ya da y/N)"
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Tüm kullanıcı kimlikler gerçekten imzalanacak mı? (e/H ya da y/N)"
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "İpucu: İmzalamak için bir kullanıcı kimliği seçiniz\n"
 
@@ -3388,10 +3497,6 @@ msgstr "güncelleme başarısız: %s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "Güncelleme gereği olmadığından anahtar değişmedi.\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "gizli anahtar \"%s\" yok: %s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3612,8 +3717,15 @@ msgstr ""
 "Bu anahtarın, yürürlükten kaldıran anahtar olmasını istediğinizden emin "
 "misiniz? (e/H ya da y/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Lütfen en fazla bir yardımcı anahtar seçin.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Bu anahtarın, yürürlükten kaldıran anahtar olmasını istediğinizden emin "
+"misiniz? (e/H ya da y/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Bir yardımcı anahtar için son kullanma tarihi değiştiriliyor.\n"
@@ -3664,6 +3776,11 @@ msgstr "%d endeksine sahip kullanıcı kimliği yok\n"
 msgid "No user ID with hash %s\n"
 msgstr "%s çittirmeli kullanıcı kimliği yok\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "%d indisli bir yardımcı anahtar yok\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "%d indisli bir yardımcı anahtar yok\n"
@@ -4023,6 +4140,10 @@ msgstr "Adınız ve Soyadınız: "
 msgid "Invalid character in name\n"
 msgstr "Ad ve soyadınızda geçersiz karakter var\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Ad ve soyadınız bir rakamla başlamamalı\n"
 
@@ -4471,10 +4592,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "UYARI: şifreli ileti tahrip edilmiş!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "şifre çözme başarısız: %s\n"
 
@@ -4673,6 +4790,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA sekizin katlarında bir çittirim uzunluğu gerektirir\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "imza türü `%s' bilinmiyor\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "\"%s\" dosyası var. "
@@ -5144,6 +5266,11 @@ msgstr "Yürürlükten kaldıran:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Bu bir duyarlı yürürlükten kaldırma anahtarı)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "Gizli anahtar mevcut.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr ""
 "Bu imza için bir yürürlükten kaldırma sertifikası oluşturulsun mu? (e/H ya "
@@ -5183,6 +5310,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "gizli anahtar \"%s\" yok: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr ""
 "Bu anahtar için bir yürürlükten kaldırma sertifikası oluşturulsun mu? (e/H "
@@ -7347,7 +7486,7 @@ msgstr "`%s' çalışırken hata: çıkış durumu: %d\n"
 
 #, fuzzy
 #| msgid "certificate `%s' not found: %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "sertifika \"%s\" yok: %s\n"
 
 #, fuzzy, c-format
@@ -7429,6 +7568,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "\"%s\" sunucusuna bağlanılamadı: %s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "güncelleme başarısız: %s\n"
@@ -7471,36 +7615,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "`%s' gizli anahtarlığa yazılırken hata oluştu: %s\n"
 
 #, fuzzy, c-format
-#| msgid "failed to create stream from socket: %s\n"
-msgid "failed to allocate assuan context: %s\n"
-msgstr "sokette akım oluşturulamadı: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-#, fuzzy
-#| msgid "no running dirmngr - starting `%s'\n"
-msgid "no running dirmngr - starting one\n"
-msgstr "çalışan dirmngr yok - `%s' başlatılıyor\n"
-
-#, fuzzy, c-format
-#| msgid "malformed DIRMNGR_INFO environment variable\n"
-msgid "malformed %s environment variable\n"
-msgstr "DIRMNGR_INFO ortam değişkeni hatalı\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "dirmngr protokolünün %d. sürümü desteklenmiyor\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "dirmngr'a bağlanılamıyor - son çareye başvuruluyor\n"
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "\"%s\" sunucusuna bağlanılamadı: %s\n"
-
-#, fuzzy, c-format
 #| msgid "unsupported algorithm: %s"
 msgid "unsupported inquiry '%s'\n"
 msgstr "desteklenmeyen algoritma: %s"
@@ -7603,7 +7717,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7951,8 +8065,10 @@ msgstr "%s okunurken hata: %s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "Hata: Özel DO çok uzun (sınır: %d karakter).\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+#| msgid "certificate `%s' not found: %s\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "sertifika \"%s\" yok: %s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -8136,6 +8252,11 @@ msgid "can't allocate control structure: %s\n"
 msgstr "dosya dışı dizge ayrılamıyor: %s\n"
 
 #, fuzzy, c-format
+#| msgid "failed to create stream from socket: %s\n"
+msgid "failed to allocate assuan context: %s\n"
+msgstr "sokette akım oluşturulamadı: %s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "\"TrustDB\" güvence veritabanı başlangıç aşamasında başarısız: %s\n"
@@ -8362,7 +8483,7 @@ msgstr "Etkileşimliliği ve zorlamayı denetleyen seçenekler"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "Güvenliği denetleyen seçenekler"
 
 msgid "Configuration for HTTP servers"
@@ -8634,6 +8755,45 @@ msgstr ""
 "Standart girdiden verilen anahtar parolasını örüntü dosyasıyla "
 "karşılaştırır\n"
 
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "anahtarın saklanması başarısız: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open `%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Lütfen en fazla bir yardımcı anahtar seçin.\n"
+
+#, fuzzy
+#~| msgid "no running dirmngr - starting `%s'\n"
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "çalışan dirmngr yok - `%s' başlatılıyor\n"
+
+#, fuzzy
+#~| msgid "malformed DIRMNGR_INFO environment variable\n"
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "DIRMNGR_INFO ortam değişkeni hatalı\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "dirmngr protokolünün %d. sürümü desteklenmiyor\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "dirmngr'a bağlanılamıyor - son çareye başvuruluyor\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "anahtarları bir S ifadesine dayalı biçimde ihraceder"
 
@@ -8812,9 +8972,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "Gerçekten bunu yapmak istiyor musunuz? (e/H ya da y/N) "
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "gizli anahtar bloğu \"%s\" okunurken hata oluştu: %s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "Lütfen gizli anahtarlardan seçilenleri silin.\n"
 
index 25284f0..af6f7b5 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -5,9 +5,9 @@
 # Yuri Chornoivan <yurchor@ukr.net>, 2011, 2014, 2015.
 msgid ""
 msgstr ""
-"Project-Id-Version: GNU gnupg 2.1.0-gitfe8619d\n"
+"Project-Id-Version: GNU gnupg 2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-02-18 19:09+0200\n"
+"PO-Revision-Date: 2015-10-23 19:33+0300\n"
 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 "Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
 "Language: uk\n"
@@ -34,36 +34,26 @@ msgstr "_Гаразд"
 msgid "|pinentry-label|_Cancel"
 msgstr "_Скасувати"
 
-#, fuzzy
-#| msgid "|pinentry-label|_OK"
 msgid "|pinentry-label|_Yes"
-msgstr "_Ð\93аÑ\80азд"
+msgstr "_Так"
 
-#, fuzzy
-#| msgid "|pinentry-label|_OK"
 msgid "|pinentry-label|_No"
-msgstr "_Ð\93аÑ\80азд"
+msgstr "_Ð\9dÑ\96"
 
 msgid "|pinentry-label|PIN:"
 msgstr "Пінкод:"
 
-#, fuzzy
-#| msgid "|pinentry-label|_Cancel"
 msgid "|pinentry-label|_Save in password manager"
-msgstr "_СкаÑ\81Ñ\83ваÑ\82и"
+msgstr "_Ð\97беÑ\80егÑ\82и Ñ\83 Ð·Ð°Ñ\81обÑ\96 ÐºÐµÑ\80Ñ\83ваннÑ\8f Ð¿Ð°Ñ\80олÑ\8fми"
 
-#, fuzzy
-#| msgid "Do you really want to permanently delete the OpenPGP secret key:"
 msgid "Do you really want to make your passphrase visible on the screen?"
-msgstr "СпÑ\80авдÑ\96 Ñ\85оÑ\87еÑ\82е Ð¾Ñ\81Ñ\82аÑ\82оÑ\87но Ð²Ð¸Ð»Ñ\83Ñ\87иÑ\82и Ð·Ð°ÐºÑ\80иÑ\82ий ÐºÐ»Ñ\8eÑ\87 OpenPGP:"
+msgstr "СпÑ\80авдÑ\96 Ñ\85оÑ\87еÑ\82е Ð·Ñ\80обиÑ\82и Ð¿Ð°Ñ\80олÑ\8c Ð²Ð¸Ð´Ð¸Ð¼Ð¸Ð¼ Ð½Ð° ÐµÐºÑ\80анÑ\96?"
 
 msgid "|pinentry-tt|Make passphrase visible"
-msgstr ""
+msgstr "Зробити пароль видимим"
 
-#, fuzzy
-#| msgid "Enter new passphrase"
 msgid "|pinentry-tt|Hide passphrase"
-msgstr "Ð\92кажÑ\96Ñ\82Ñ\8c Ð½Ð¾Ð²Ð¸Ð¹ пароль"
+msgstr "Ð\9fÑ\80иÑ\85оваÑ\82и пароль"
 
 #. TRANSLATORS: This string is displayed by Pinentry as the label
 #. for the quality bar.
@@ -96,7 +86,7 @@ msgstr ""
 "сеансу"
 
 msgid "PIN:"
-msgstr ""
+msgstr "Пінкод:"
 
 msgid "Passphrase:"
 msgstr "Пароль:"
@@ -290,8 +280,7 @@ msgstr[0] "У паролі має бути принаймні %u цифра аб
 msgstr[1] "У паролі має бути принаймні %u цифри або%%0Aспеціальних символи."
 msgstr[2] "У паролі має бути принаймні %u цифр або%%0Aспеціальних символів."
 
-#, fuzzy, c-format
-#| msgid "A passphrase may not be a known term or match%%0Acertain pattern."
+#, c-format
 msgid "A passphrase may not be a known term or match%%0Acertain pattern."
 msgstr ""
 "Паролем не повинно бути слово зі словника або слово%%0A, що відповідає "
@@ -353,10 +342,8 @@ msgstr "використовувати вказану програму SCdaemon"
 msgid "do not use the SCdaemon"
 msgstr "не використовувати SCdaemon"
 
-#, fuzzy
-#| msgid "|NAME|connect to host NAME"
 msgid "|NAME|accept some commands via NAME"
-msgstr "|NAME|встановити з’єднання з вузлом за вказаною назвою"
+msgstr "приймати певні команди через NAME"
 
 msgid "ignore requests to change the TTY"
 msgstr "ігнорувати запити щодо зміни TTY"
@@ -370,10 +357,8 @@ msgstr "вважати кешовані пінкоди за вказану кі
 msgid "do not use the PIN cache when signing"
 msgstr "не використовувати кеш пін-кодів для підписування"
 
-#, fuzzy
-#| msgid "do not allow the reuse of old passphrases"
 msgid "disallow the use of an external password cache"
-msgstr "не Ð´Ð¾Ð·Ð²Ð¾Ð»Ñ\8fÑ\82и Ð¿Ð¾Ð²Ñ\82оÑ\80не Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82аннÑ\8f Ñ\81Ñ\82аÑ\80иÑ\85 паролів"
+msgstr "забоÑ\80ониÑ\82и Ð²Ð¸ÐºÐ¾Ñ\80иÑ\81Ñ\82аннÑ\8f Ð·Ð¾Ð²Ð½Ñ\96Ñ\88нÑ\8cого ÐºÐµÑ\88Ñ\83 паролів"
 
 msgid "disallow clients to mark keys as \"trusted\""
 msgstr "заборонити клієнтам позначати ключі як надійні"
@@ -385,7 +370,7 @@ msgid "allow caller to override the pinentry"
 msgstr "дозволити функції виклику перевизначати pinentry"
 
 msgid "allow passphrase to be prompted through Emacs"
-msgstr ""
+msgstr "дозволити запит пароля з Emacs"
 
 msgid "enable ssh support"
 msgstr "увімкнути підтримку ssh"
@@ -668,12 +653,12 @@ msgstr "Змінити пароль"
 msgid "I'll change it later"
 msgstr "Я зміню його пізніше"
 
-#, fuzzy, c-format
-#| msgid "Do you really want to delete the selected keys? (y/N) "
+#, c-format
 msgid ""
 "Do you really want to delete the key identified by keygrip%%0A  %s%%0A  %%C"
 "%%0A?"
-msgstr "Справді бажаєте вилучити вибрані ключі? (y/N або т/Н) "
+msgstr ""
+"Справді хочете вилучити ключ, що визначається keygrip%%0A  %s%%0A  %%C%%0A?"
 
 msgid "Delete key"
 msgstr "Вилучити ключ"
@@ -832,7 +817,7 @@ msgstr "УВАГА: «%s%s» є застарілим параметром — в
 
 #, c-format
 msgid "unknown debug flag '%s' ignored\n"
-msgstr ""
+msgstr "невідомий прапорець діагностики «%s» проігноровано\n"
 
 #, c-format
 msgid "no running gpg-agent - starting '%s'\n"
@@ -1497,6 +1482,11 @@ msgstr "ключ «%s» не знайдено: %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "помилка під час спроби читання блокування ключа: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "ключ «%s» не знайдено: %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(якщо ключ не задано відбитком)\n"
 
@@ -1696,6 +1686,20 @@ msgid "No fingerprint"
 msgstr "Без відбитка"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "закритий ключ «%s» не знайдено: %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "не вказано аргументу до параметра «%.50s»\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|NAME|використовувати вказаний типовий закритий ключ"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr ""
 "Некоректний ключ %s визнано чинним через параметр --allow-non-selfsigned-"
@@ -1747,10 +1751,8 @@ msgstr "створити пару ключів"
 msgid "quickly generate a new key pair"
 msgstr "швидке створення пари ключів"
 
-#, fuzzy
-#| msgid "quickly generate a new key pair"
 msgid "quickly add a new user-id"
-msgstr "швидке створення пари ключів"
+msgstr "швидке додавання нового ідентифікатора користувача"
 
 msgid "full featured key pair generation"
 msgstr "повноцінне створення пари ключів"
@@ -1818,6 +1820,9 @@ msgstr "показати контрольні суми повідомлень"
 msgid "run in server mode"
 msgstr "запустити у режимі сервера"
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr "встановити правила TOFU для ключа (good, unknown, bad, ask, auto)"
+
 msgid "create ascii armored output"
 msgstr "створити дані у форматі ASCII"
 
@@ -2023,11 +2028,50 @@ msgstr "показувати назву сховища ключів у спис
 msgid "show expiration dates during signature listings"
 msgstr "показувати дати завершення строків дії у списку підписів"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "Доступні ключі:\n"
+
+#, c-format
+msgid "unknown TOFU policy '%s'\n"
+msgstr "невідомі правила TOFU «%s»\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "невідомий формат бази даних TOFU «%s»\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "ЗАУВАЖЕННЯ: застарілий файл типових параметрів «%s» проігноровано\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "параметр «%.50s» є неоднозначним\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "помилка під час спроби створення сховища ключів «%s»: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt занадто стара (потрібна — %s, маємо %s)\n"
 
@@ -2231,6 +2275,16 @@ msgstr ""
 "УВАГА: отримувачів (-r) вказано без використання шифрування відкритим "
 "ключем\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "рядок %d: вказано некоректну дату\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "рядок %d: вказано некоректну дату\n"
+
 msgid "--store [filename]"
 msgstr "--store [назва файла]"
 
@@ -2330,6 +2384,17 @@ msgstr "помилка перетворення у формат ASCII: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "некоректний алгоритм хешування «%s»\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "помилка під час спроби завантаження сертифіката «%s»: %s\n"
+
+#, fuzzy, c-format
+#| msgid ""
+#| "'%s' does not appear to be a valid key id, fingerprint or key grip.\n"
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr "«%s» не є коректним ідентифікатором ключа, відбитком або keygrip.\n"
+
 msgid "[filename]"
 msgstr "[назва файла]"
 
@@ -2626,6 +2691,20 @@ msgstr "імпортування закритих ключів забороне
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "ключ %s: закритий ключ з некоректним шифром %d — пропущено\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr ""
@@ -2754,6 +2833,11 @@ msgstr "створено сховище ключів «%s»\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "ресурс блоку ключів «%s»: %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "помилка під час відкриття «%s»: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "не вдалося перебудувати кеш сховища ключів: %s\n"
@@ -2825,6 +2909,10 @@ msgstr ""
 "такого домену немає.\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "Ідентифікатор користувача «%s» відкликано."
 
@@ -2994,10 +3082,8 @@ msgstr "зберегти і вийти"
 msgid "show key fingerprint"
 msgstr "показати відбиток ключа"
 
-#, fuzzy
-#| msgid "Enter the keygrip: "
 msgid "show the keygrip"
-msgstr "Ð\92кажÑ\96Ñ\82Ñ\8c keygrip: "
+msgstr "показаÑ\82и keygrip"
 
 msgid "list key and user IDs"
 msgstr "показати список ключів та ідентифікаторів користувача"
@@ -3136,6 +3222,11 @@ msgstr "Ключ відкликано."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "Підписати всі ідентифікатори користувача? (y/N або т/Н) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "Підписати всі ідентифікатори користувача? (y/N або т/Н) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "Підказка: виберіть ідентифікатори користувача для підписування\n"
 
@@ -3152,7 +3243,7 @@ msgstr "Вам слід вибрати принаймні один іденти
 
 #, c-format
 msgid "(Use the '%s' command.)\n"
-msgstr ""
+msgstr "(Скористайтеся командою «%s».)\n"
 
 msgid "You can't delete the last user ID!\n"
 msgstr "Не можна вилучати останній ідентифікатор користувача!\n"
@@ -3235,10 +3326,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "Ключ не змінено, отже оновлення непотрібне.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "закритий ключ «%s» не знайдено: %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "«%s» не є відбитком\n"
 
@@ -3442,8 +3529,15 @@ msgstr ""
 "Ви справді бажаєте призначити цей ключ як підписане відкликання? (y/N або т/"
 "Н) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "Будь ласка, виберіть не більше одного ключа.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr ""
+"Ви справді бажаєте призначити цей ключ як підписане відкликання? (y/N або т/"
+"Н) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "Зміна часу завершення строку дії для підключа.\n"
@@ -3494,6 +3588,11 @@ msgstr "Ідентифікатора користувача з індексом
 msgid "No user ID with hash %s\n"
 msgstr "Ідентифікатора користувача з хешем %s не існує\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "Підключа з індексом %d не існує\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "Підключа з індексом %d не існує\n"
@@ -3840,6 +3939,10 @@ msgstr "Справжнє ім’я: "
 msgid "Invalid character in name\n"
 msgstr "Некоректний символ у імені\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "Ім’я не може починатися з цифри\n"
 
@@ -4064,15 +4167,12 @@ msgstr "Критична примітка підпису: "
 msgid "Signature notation: "
 msgstr "Примітка підпису: "
 
-#, fuzzy
-#| msgid "1 bad signature\n"
 msgid "1 good signature\n"
-msgstr "1 Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¾Ð²ий підпис\n"
+msgstr "1 Ð´Ð¾Ð±Ñ\80ий підпис\n"
 
-#, fuzzy, c-format
-#| msgid "%d bad signatures\n"
+#, c-format
 msgid "%d good signatures\n"
-msgstr "%d Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¾Ð²их підписів\n"
+msgstr "%d Ð´Ð¾Ð±Ñ\80их підписів\n"
 
 #, c-format
 msgid "Warning: %lu key(s) skipped due to their large size\n"
@@ -4126,7 +4226,7 @@ msgid "%s: keyring created\n"
 msgstr "%s: створено сховище ключів\n"
 
 msgid "override proxy options set for dirmngr"
-msgstr ""
+msgstr "перевизначити параметри проксі, встановлені для dirmngr"
 
 msgid "include revoked keys in search results"
 msgstr "включити до результатів пошуку відкликані ключі"
@@ -4135,7 +4235,7 @@ msgid "include subkeys when searching by key ID"
 msgstr "включити підключі до пошуку за ідентифікатором ключа"
 
 msgid "override timeout options set for dirmngr"
-msgstr ""
+msgstr "перевизначити параметри часу очікування, встановлені для dirmngr"
 
 msgid "automatically retrieve keys when verifying signatures"
 msgstr "автоматично отримувати ключі під час перевірки підписів"
@@ -4272,10 +4372,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "УВАГА: зашифроване повідомлення було змінено!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "текстовий пароль кешовано з ідентифікатором: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "невдала спроба розшифрування: %s\n"
 
@@ -4467,6 +4563,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr ""
 "Відкритий ключ ECDSA має зберігатися у кодуванні SEC кратному 8-бітовому\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "Невідомий тип підпису «%s»\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "Файл «%s» існує. "
@@ -4918,6 +5019,9 @@ msgstr "Буде відкликано:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(Це критичний ключ відкликання)\n"
 
+msgid "Secret key is not available.\n"
+msgstr "Закритий ключ недоступний.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr ""
 "Створити підписаний сертифікат відкликання для цього ключа? (y/N або т/Н) "
@@ -4959,6 +5063,18 @@ msgstr ""
 "дефісами нижче додано двокрапку. Вилучіть цю двокрапку у текстовому\n"
 "редакторі, перш ніж скористатися цим сертифікатом відкликання."
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "закритий ключ «%s» не знайдено: %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "Створити сертифікат відкликання для цього ключа? (y/N або т/Н) "
 
@@ -5407,10 +5523,8 @@ msgstr "безмежна"
 #. It gets passed to atoi() so everything after the number is
 #. essentially a comment and need not be translated.  Either key and
 #. uid are both NULL, or neither are NULL.
-#, fuzzy
-#| msgid "10 translator see trustdb.c:uid_trust_string_fixed"
 msgid "10 translator see trust.c:uid_trust_string_fixed"
-msgstr "10 translator see trustdb.c:uid_trust_string_fixed"
+msgstr "10"
 
 msgid "[ revoked]"
 msgstr "[відклик.]"
@@ -6986,10 +7100,8 @@ msgstr "помилка отримання «%s»: %s\n"
 msgid "error retrieving '%s': http status %u\n"
 msgstr "помилка отримання «%s»: стан http %u\n"
 
-#, fuzzy
-#| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
-msgstr "Доступ до CRL неможливий через вимкнений %s\n"
+msgid "CRL access not possible due to Tor mode\n"
+msgstr "Доступ до CRL неможливий через увімкнений режим Tor\n"
 
 #, c-format
 msgid "certificate search not possible due to disabled %s\n"
@@ -7056,6 +7168,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "сертифікат занадто великий для використання\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "не вдалося встановити з’єднання з dirmngr: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "помилка пошуку: %s\n"
 
@@ -7089,33 +7205,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "помилка під час спроби запису у кодуванні base64: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "не вдалося розмістити контекст assuan: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "ймовірно, dirmngr не запущено\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "dirmngr не запущено — запускаємо\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "помилкове форматування змінної середовища %s\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "підтримки протоколу dirmngr версії %d не передбачено\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-"не вдалося встановити з’єднання з dirmngr — намагаємося скористатися "
-"резервним\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "не вдалося встановити з’єднання з dirmngr: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "непідтримуваний запит «%s»\n"
 
@@ -7201,8 +7290,8 @@ msgstr "|N|повертати не більше за вказану кількі
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|ФАЙЛ|використовувати сертифікати CA з файла ФАЙЛ для HKP крізь TLS"
 
-msgid "route all network traffic via TOR"
-msgstr ""
+msgid "route all network traffic via Tor"
+msgstr "маршрутизувати увесь обмін даними з мережею через Tor"
 
 msgid ""
 "@\n"
@@ -7498,10 +7587,8 @@ msgstr "помилка під час спроби читання даних з 
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "занадто об’ємна відповідь від сервера; верхня межа — %d байтів\n"
 
-#, fuzzy
-#| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr "запит за допомогою OCSP неможливий через вимикання протоколу HTTP\n"
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "запит за допомогою OCSP неможливий через увімкнений режим Tor\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr "запит за допомогою OCSP неможливий через вимикання протоколу HTTP\n"
@@ -7654,6 +7741,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "не вдалося розмістити структуру керування: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "не вдалося розмістити контекст assuan: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "не вдалося ініціалізувати сервер: %s\n"
 
@@ -7852,10 +7943,8 @@ msgstr "Параметри керування форматом виведенн
 msgid "Options controlling the interactivity and enforcement"
 msgstr "Параметри керування інтерактивністю та примусом"
 
-#, fuzzy
-#| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
-msgstr "Параметри керування захистом"
+msgid "Options controlling the use of Tor"
+msgstr "Параметри керування використанням Tor"
 
 msgid "Configuration for HTTP servers"
 msgstr "Налаштування для серверів HTTP"
@@ -7885,7 +7974,7 @@ msgid "GPG for S/MIME"
 msgstr "GPG для S/MIME"
 
 msgid "Key Acquirer"
-msgstr ""
+msgstr "Засіб запиту ключів"
 
 msgid "PIN and Passphrase Entry"
 msgstr "Введення пінкодів і паролів"
@@ -8106,6 +8195,60 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметри] файл_шаблонів\n"
 "Перевірити пароль, вказаний у stdin, за допомогою файла_шаблонів\n"
 
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "Не вдалося відкрити базу даних сховища ключів.\n"
+
+#~ msgid "Failed to parse '%s'.\n"
+#~ msgstr "Не вдалося обробити «%s».\n"
+
+#~ msgid "Failed to reset keyring handle.\n"
+#~ msgstr "Не вдалося скинути дескриптор сховища ключів.\n"
+
+#~ msgid "Key '%s' is not available\n"
+#~ msgstr "Ключ «%s» є недоступним\n"
+
+#~ msgid "Failed to find key '%s'\n"
+#~ msgstr "Не вдалося знайти ключ «%s»\n"
+
+#~ msgid "Failed to read key '%s' from the keyring\n"
+#~ msgstr "Не вдалося прочитати ключ «%s» зі сховища ключів\n"
+
+#~ msgid "Unknown weak digest '%s'\n"
+#~ msgstr "Невідома слабка контрольна сума «%s»\n"
+
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "Будь ласка, виберіть не більше одного ключа.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "ймовірно, dirmngr не запущено\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "dirmngr не запущено — запускаємо\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "помилкове форматування змінної середовища %s\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "підтримки протоколу dirmngr версії %d не передбачено\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr ""
+#~ "не вдалося встановити з’єднання з dirmngr — намагаємося скористатися "
+#~ "резервним\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "експортувати ключі у форматі, заснованому на S-виразах"
 
index 5287682..f2793db 100644 (file)
@@ -1555,6 +1555,11 @@ msgstr "密钥‘%s’找不到:%s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "读取密钥区块时发生错误:%s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "密钥‘%s’找不到:%s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(除非您用指纹指定密钥)\n"
 
@@ -1754,6 +1759,19 @@ msgid "No fingerprint"
 msgstr "CA 指纹:"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "找不到私钥“%s”:%s\n"
+
+#, fuzzy, c-format
+msgid "(check argument of option '%s')\n"
+msgstr "无效的列表选项\n"
+
+#, fuzzy, c-format
+#| msgid "unusable secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "不可用的私钥"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "--allow-non-selfsigned-uid 使无效密钥 %s 生效\n"
 
@@ -1884,6 +1902,9 @@ msgstr "|算法 [文件]|使用指定的散列算法打印报文散列值"
 msgid "run in server mode"
 msgstr ""
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "输出经 ASCII 封装"
 
@@ -2099,12 +2120,50 @@ msgstr "列出密钥时显示钥匙环的名称"
 msgid "show expiration dates during signature listings"
 msgstr "列出签名时显示过期日期"
 
+#, fuzzy
+msgid "available TOFU policies:\n"
+msgstr "禁用密钥"
+
+#, fuzzy, c-format
+#| msgid "unknown option `%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "未知的选项 '%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "未知的选项 '%s'\n"
+
 #, fuzzy, c-format
 #| msgid "NOTE: old default options file `%s' ignored\n"
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "注意:旧式的默认配置文件‘%s’已被忽略\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, c-format
+msgid "key specification '%s' is ambiguous\n"
+msgstr ""
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring `%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "建立钥匙环‘%s’时发生错误:%s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr ""
 
@@ -2305,6 +2364,14 @@ msgstr "初始化信任度数据库失败:%s\n"
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr "警告:给定了收件人(-r)但并未使用公钥加密\n"
 
+#, fuzzy, c-format
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "无效的‘%s’散列算法\n"
+
+#, fuzzy, c-format
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "无效的‘%s’散列算法\n"
+
 msgid "--store [filename]"
 msgstr "--store [文件名]"
 
@@ -2400,6 +2467,14 @@ msgstr "进行 ASCII 封装失败:%s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "无效的‘%s’散列算法\n"
 
+#, fuzzy, c-format
+msgid "error parsing key specification '%s': %s\n"
+msgstr "取得当前密钥信息时出错:%s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[文件名]"
 
@@ -2702,6 +2777,20 @@ msgstr "不允许导入私钥\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "密钥 %s:私钥使用了无效的加密算法 %d――已跳过\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "密钥 %s:没有公钥――无法应用吊销证书\n"
@@ -2833,6 +2922,10 @@ msgstr "钥匙环‘%s’已建立\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "密钥块资源‘%s’:%s\n"
 
+#, fuzzy, c-format
+msgid "error opening key DB: %s\n"
+msgstr "‘%s’中出错:%s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "重新建立钥匙环缓存失败: %s\n"
@@ -2901,6 +2994,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "请输入这份签名的限制域,如果没有请按回车。\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "用户标识“%s”已被吊销。"
 
@@ -3202,6 +3299,11 @@ msgstr "密钥已被吊销。"
 msgid "Really sign all user IDs? (y/N) "
 msgstr "真的为所有的用户标识签名吗?(y/N)"
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "真的为所有的用户标识签名吗?(y/N)"
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "提示:选择要添加签名的用户标识\n"
 
@@ -3301,10 +3403,6 @@ msgstr "更新失败:%s\n"
 msgid "Key not changed so no update needed.\n"
 msgstr "密钥没有变动所以不需要更新。\n"
 
-#, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "找不到私钥“%s”:%s\n"
-
 #, fuzzy, c-format
 #| msgid "invalid fingerprint"
 msgid "\"%s\" is not a fingerprint\n"
@@ -3511,8 +3609,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "您确定要将这把密钥设为指定吊销者吗?(y/N):"
 
-msgid "Please select at most one subkey.\n"
-msgstr "请至多选择一个子钥。\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "您确定要将这把密钥设为指定吊销者吗?(y/N):"
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "将要变更子钥的使用期限。\n"
@@ -3561,6 +3664,11 @@ msgstr "没有索引为 %d 的用户标识\n"
 msgid "No user ID with hash %s\n"
 msgstr "没有散列值为 %s 的用户标识\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "没有索引为 %d 的子钥\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "没有索引为 %d 的子钥\n"
@@ -3907,6 +4015,10 @@ msgstr "真实姓名:"
 msgid "Invalid character in name\n"
 msgstr "姓名含有无效的字符\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "姓名不可以用数字开头\n"
 
@@ -4338,10 +4450,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "警告:加密过的报文已经变造!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr ""
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "解密失败:%s\n"
 
@@ -4538,6 +4646,11 @@ msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "DSA 需要散列值长度为 8 位的倍数\n"
 
 #, fuzzy, c-format
+#| msgid "Unknown signature type `%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "未知的签名类型‘%s’\n"
+
+#, fuzzy, c-format
 #| msgid "File `%s' exists. "
 msgid "File '%s' exists. "
 msgstr "文件‘%s’已存在。 "
@@ -4987,6 +5100,11 @@ msgstr "将被吊销,吊销者:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(这是一把敏感的吊销密钥)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "私钥可用。\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "要为这把密钥建立一份指定吊销者证书吗?(y/N)"
 
@@ -5022,6 +5140,18 @@ msgid ""
 "before making use of this revocation certificate."
 msgstr ""
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "找不到私钥“%s”:%s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "要为这把密钥建立一份吊销证书吗?(y/N)"
 
@@ -7063,7 +7193,7 @@ msgid "error retrieving '%s': http status %u\n"
 msgstr "读取‘%s’时出错:%s\n"
 
 #, fuzzy
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "找不到私钥“%s”:%s\n"
 
 #, fuzzy, c-format
@@ -7134,6 +7264,11 @@ msgid "certificate too large to make any sense\n"
 msgstr ""
 
 #, fuzzy, c-format
+#| msgid "can't connect to `%s': %s\n"
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "无法连接至‘%s’:%s\n"
+
+#, fuzzy, c-format
 #| msgid "update failed: %s\n"
 msgid "lookup failed: %s\n"
 msgstr "更新失败:%s\n"
@@ -7173,32 +7308,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "写入私钥钥匙环‘%s’时发生错误: %s\n"
 
 #, fuzzy, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "%s:建立散列表失败:%s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr ""
-
-msgid "no running dirmngr - starting one\n"
-msgstr ""
-
-#, fuzzy, c-format
-msgid "malformed %s environment variable\n"
-msgstr "GPG_AGENT_INFO 环境变量格式错误\n"
-
-#, fuzzy, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "不支持 gpg-agent 协议版本 %d\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr ""
-
-#, fuzzy, c-format
-#| msgid "can't connect to `%s': %s\n"
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "无法连接至‘%s’:%s\n"
-
-#, fuzzy, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr ""
 "\n"
@@ -7291,7 +7400,7 @@ msgstr ""
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr ""
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 #, fuzzy
@@ -7614,8 +7723,9 @@ msgstr "读取‘%s’时出错:%s\n"
 msgid "response from server too large; limit is %d bytes\n"
 msgstr "错误:个人 DO 太长(至多 %d 个字符)。\n"
 
-msgid "OCSP request not possible due to TOR mode\n"
-msgstr ""
+#, fuzzy
+msgid "OCSP request not possible due to Tor mode\n"
+msgstr "找不到私钥“%s”:%s\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
 msgstr ""
@@ -7774,6 +7884,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "不能创建备份文件‘%s’:%s\n"
 
 #, fuzzy, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "%s:建立散列表失败:%s\n"
+
+#, fuzzy, c-format
 #| msgid "failed to initialize the TrustDB: %s\n"
 msgid "failed to initialize the server: %s\n"
 msgstr "初始化信任度数据库失败:%s\n"
@@ -7982,7 +8096,7 @@ msgstr ""
 msgid "Options controlling the interactivity and enforcement"
 msgstr ""
 
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr ""
 
 msgid "Configuration for HTTP servers"
@@ -8239,6 +8353,36 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#, fuzzy
+#~| msgid "can't open the keyring"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "无法打开钥匙环"
+
+#, fuzzy
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "请至多选择一个子钥。\n"
+
+#, fuzzy
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "GPG_AGENT_INFO 环境变量格式错误\n"
+
+#, fuzzy
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "不支持 gpg-agent 协议版本 %d\n"
+
 #~ msgid "toggle between the secret and public key listings"
 #~ msgstr "在私钥和公钥清单间切换"
 
@@ -8404,9 +8548,6 @@ msgstr ""
 #~ msgid "Do you really want to do this? (y/N) "
 #~ msgstr "您真的想要这么做吗?(y/N)"
 
-#~ msgid "error reading secret keyblock \"%s\": %s\n"
-#~ msgstr "读取私钥区块“%s”时出错:%s\n"
-
 #~ msgid "Please remove selections from the secret keys.\n"
 #~ msgstr "请从私钥中删除选择。\n"
 
@@ -9033,9 +9174,6 @@ msgstr ""
 #~ msgid "checksum error"
 #~ msgstr "校验和错误"
 
-#~ msgid "can't open the keyring"
-#~ msgstr "无法打开钥匙环"
-
 #~ msgid "invalid packet"
 #~ msgstr "无效包"
 
@@ -9114,9 +9252,6 @@ msgstr ""
 #~ msgid "unusable public key"
 #~ msgstr "不可用的公钥"
 
-#~ msgid "unusable secret key"
-#~ msgstr "不可用的私钥"
-
 #~ msgid "keyserver error"
 #~ msgstr "公钥服务器错误"
 
index 5330e33..2170e0b 100644 (file)
@@ -1467,6 +1467,11 @@ msgstr "找不到金鑰 \"%s\": %s\n"
 msgid "error reading keyblock: %s\n"
 msgstr "讀取金鑰區塊時出錯: %s\n"
 
+#, fuzzy, c-format
+#| msgid "key \"%s\" not found: %s\n"
+msgid "key \"%s\" not found\n"
+msgstr "找不到金鑰 \"%s\": %s\n"
+
 msgid "(unless you specify the key by fingerprint)\n"
 msgstr "(除非你用指紋指定了金鑰)\n"
 
@@ -1651,6 +1656,20 @@ msgid "No fingerprint"
 msgstr "沒有指紋"
 
 #, c-format
+msgid "secret key \"%s\" not found: %s\n"
+msgstr "找不到私鑰 \"%s\": %s\n"
+
+#, fuzzy, c-format
+#| msgid "missing argument for option \"%.50s\"\n"
+msgid "(check argument of option '%s')\n"
+msgstr "\"%.50s\" 選項遺失了引數\n"
+
+#, fuzzy, c-format
+#| msgid "|NAME|use NAME as default secret key"
+msgid "using \"%s\" as default secret key\n"
+msgstr "|名字|使用指定名字做為預設私鑰"
+
+#, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
 msgstr "無效的金鑰 %s 可以藉由 --allow-non-selfsigned-uid 而生效\n"
 
@@ -1771,6 +1790,9 @@ msgstr "印出訊息摘要"
 msgid "run in server mode"
 msgstr "以伺服器模式執行"
 
+msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgstr ""
+
 msgid "create ascii armored output"
 msgstr "建立以 ASCII 封裝過的輸出"
 
@@ -1956,11 +1978,52 @@ msgstr "在金鑰清單中顯示鑰匙圈名稱"
 msgid "show expiration dates during signature listings"
 msgstr "列出簽章時顯示有效期限"
 
+#, fuzzy
+#| msgid "Available keys:\n"
+msgid "available TOFU policies:\n"
+msgstr "可用金鑰:\n"
+
+#, fuzzy, c-format
+#| msgid "unknown option '%s'\n"
+msgid "unknown TOFU policy '%s'\n"
+msgstr "未知的選項 '%s'\n"
+
+msgid "(use \"help\" to list choices)\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "unknown command '%s'\n"
+msgid "unknown TOFU DB format '%s'\n"
+msgstr "未知的指令 '%s'\n"
+
 #, c-format
 msgid "Note: old default options file '%s' ignored\n"
 msgstr "請注意: 已忽略舊有的預設選項檔 '%s'\n"
 
 #, c-format
+msgid ""
+"Warning: value '%s' for option '%s' should be a long key ID or a "
+"fingerprint\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "option \"%.50s\" is ambiguous\n"
+msgid "key specification '%s' is ambiguous\n"
+msgstr "\"%.50s\" 選項不明確\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Two
+#. lines with fingerprints are printed after this message.
+#, c-format
+msgid "'%s' matches at least:\n"
+msgstr ""
+
+#, fuzzy, c-format
+#| msgid "error creating keyring '%s': %s\n"
+msgid "error searching the keyring: %s\n"
+msgstr "建立鑰匙圈 '%s' 時出錯: %s\n"
+
+#, c-format
 msgid "libgcrypt is too old (need %s, have %s)\n"
 msgstr "libgcrypt 太舊了 (需要 %s, 但是祇有 %s)\n"
 
@@ -2152,6 +2215,16 @@ msgstr "信任資料庫啟始失敗: %s\n"
 msgid "WARNING: recipients (-r) given without using public key encryption\n"
 msgstr "警告: 給定的收件者 (-r) 未使用公鑰加密\n"
 
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but no valid default keys given\n"
+msgstr "第 %d 列: 無效的給定日期\n"
+
+#, fuzzy, c-format
+#| msgid "line %d: invalid date given\n"
+msgid "option '%s' given, but option '%s' not given\n"
+msgstr "第 %d 列: 無效的給定日期\n"
+
 msgid "--store [filename]"
 msgstr "--store [檔名]"
 
@@ -2244,6 +2317,15 @@ msgstr "進行封裝失敗: %s\n"
 msgid "invalid hash algorithm '%s'\n"
 msgstr "無效的雜湊演算法 '%s'\n"
 
+#, fuzzy, c-format
+#| msgid "error loading certificate '%s': %s\n"
+msgid "error parsing key specification '%s': %s\n"
+msgstr "載入憑證 '%s' 時出錯: %s\n"
+
+#, c-format
+msgid "'%s' does not appear to be a valid key ID, fingerprint or keygrip\n"
+msgstr ""
+
 msgid "[filename]"
 msgstr "[檔名]"
 
@@ -2538,6 +2620,20 @@ msgstr "未允許匯入私鑰\n"
 msgid "key %s: secret key with invalid cipher %d - skipped\n"
 msgstr "金鑰 %s: 私鑰使用了無效的 %d 編密法 - 已跳過\n"
 
+#. TRANSLATORS: For smartcard, each private key on
+#. host has a reference (stub) to a smartcard and
+#. actual private key data is stored on the card.  A
+#. single smartcard can have up to three private key
+#. data.  Importing private key stub is always
+#. skipped in 2.1, and it returns
+#. GPG_ERR_NOT_PROCESSED.  Instead, user should be
+#. suggested to run 'gpg --card-status', then,
+#. references to a card will be automatically
+#. created again.
+#, c-format
+msgid "To migrate '%s', with each smartcard, run: %s\n"
+msgstr ""
+
 #, c-format
 msgid "key %s: no public key - can't apply revocation certificate\n"
 msgstr "金鑰 %s: 沒有公鑰 - 無法套用撤銷憑證\n"
@@ -2666,6 +2762,11 @@ msgstr "鑰匙圈 '%s' 已建立\n"
 msgid "keyblock resource '%s': %s\n"
 msgstr "金鑰區塊資源 '%s': %s\n"
 
+#, fuzzy, c-format
+#| msgid "error opening '%s': %s\n"
+msgid "error opening key DB: %s\n"
+msgstr "開啟 '%s' 時出錯: %s\n"
+
 #, c-format
 msgid "failed to rebuild keyring cache: %s\n"
 msgstr "重新建立鑰匙圈快取失敗: %s\n"
@@ -2734,6 +2835,10 @@ msgid "Please enter a domain to restrict this signature, or enter for none.\n"
 msgstr "請輸入約束此簽章的網域, 若無請直接按下 [Enter].\n"
 
 #, c-format
+msgid "Skipping user ID \"%s\", which is not a text ID.\n"
+msgstr ""
+
+#, c-format
 msgid "User ID \"%s\" is revoked."
 msgstr "使用者 ID \"%s\" 已撤銷."
 
@@ -3030,6 +3135,11 @@ msgstr "金鑰已撤銷."
 msgid "Really sign all user IDs? (y/N) "
 msgstr "真的要簽署所有的使用者 ID 嗎? (y/N) "
 
+#, fuzzy
+#| msgid "Really sign all user IDs? (y/N) "
+msgid "Really sign all text user IDs? (y/N) "
+msgstr "真的要簽署所有的使用者 ID 嗎? (y/N) "
+
 msgid "Hint: Select the user IDs to sign\n"
 msgstr "提示: 選擇使用者 ID 來加以簽署\n"
 
@@ -3126,10 +3236,6 @@ msgid "Key not changed so no update needed.\n"
 msgstr "金鑰沒有變更所以不需要更新.\n"
 
 #, c-format
-msgid "secret key \"%s\" not found: %s\n"
-msgstr "找不到私鑰 \"%s\": %s\n"
-
-#, c-format
 msgid "\"%s\" is not a fingerprint\n"
 msgstr "\"%s\" 不是指紋\n"
 
@@ -3330,8 +3436,13 @@ msgid ""
 "Are you sure you want to appoint this key as a designated revoker? (y/N) "
 msgstr "你確定要指派這把金鑰為指定撤銷者嗎? (y/N) "
 
-msgid "Please select at most one subkey.\n"
-msgstr "請至多選擇一把子鑰.\n"
+#, fuzzy
+#| msgid ""
+#| "Are you sure you want to appoint this key as a designated revoker? (y/N) "
+msgid ""
+"Are you sure you want to change the expiration time for multiple subkeys? (y/"
+"N) "
+msgstr "你確定要指派這把金鑰為指定撤銷者嗎? (y/N) "
 
 msgid "Changing expiration time for a subkey.\n"
 msgstr "正在變更子鑰的使用期限.\n"
@@ -3380,6 +3491,11 @@ msgstr "索引 %d 沒有對應到使用者 ID\n"
 msgid "No user ID with hash %s\n"
 msgstr "雜湊 %s 沒有對應到使用者 ID\n"
 
+#, fuzzy, c-format
+#| msgid "No subkey with index %d\n"
+msgid "No subkey with key ID '%s'.\n"
+msgstr "索引 %d 沒有對應到子鑰\n"
+
 #, c-format
 msgid "No subkey with index %d\n"
 msgstr "索引 %d 沒有對應到子鑰\n"
@@ -3718,6 +3834,10 @@ msgstr "真實姓名: "
 msgid "Invalid character in name\n"
 msgstr "姓名含有無效的字符\n"
 
+#, c-format
+msgid "The characters '%s' and '%s' may not appear in name\n"
+msgstr ""
+
 msgid "Name may not start with a digit\n"
 msgstr "姓名不可以用數字開頭\n"
 
@@ -4133,10 +4253,6 @@ msgid "WARNING: encrypted message has been manipulated!\n"
 msgstr "警告: 加密過的訊息已經被變造了!\n"
 
 #, c-format
-msgid "cleared passphrase cached with ID: %s\n"
-msgstr "清除此 ID 被快取住的密語: %s\n"
-
-#, c-format
 msgid "decryption failed: %s\n"
 msgstr "解密失敗: %s\n"
 
@@ -4320,6 +4436,11 @@ msgstr "未知的選項 '%s'\n"
 msgid "ECDSA public key is expected to be in SEC encoding multiple of 8 bits\n"
 msgstr "ECDSA 公鑰應該要是 8 位元倍數的 SEC 編碼\n"
 
+#, fuzzy, c-format
+#| msgid "Unknown signature type '%s'\n"
+msgid "unknown weak digest '%s'\n"
+msgstr "未知的簽章種類 '%s'\n"
+
 #, c-format
 msgid "File '%s' exists. "
 msgstr "檔案 '%s' 已存在. "
@@ -4758,6 +4879,11 @@ msgstr "將被撤銷:\n"
 msgid "(This is a sensitive revocation key)\n"
 msgstr "(這是把機密的撤銷金鑰)\n"
 
+#, fuzzy
+#| msgid "Secret key is available.\n"
+msgid "Secret key is not available.\n"
+msgstr "私鑰可用.\n"
+
 msgid "Create a designated revocation certificate for this key? (y/N) "
 msgstr "要為這把金鑰建立一份指定撤銷憑證嗎? (y/N) "
 
@@ -4798,6 +4924,18 @@ msgstr ""
 "真的要使用這份撤銷憑證前, 請先用文字編輯器把那個冒號移除,\n"
 "撤銷憑證才能使用."
 
+#, fuzzy, c-format
+#| msgid "secret key \"%s\" not found: %s\n"
+msgid "secret key \"%s\" not found\n"
+msgstr "找不到私鑰 \"%s\": %s\n"
+
+#. TRANSLATORS: The %s prints a key specification which
+#. for example has been given at the command line.  Several lines
+#. lines with secret key infos are printed after this message.
+#, c-format
+msgid "'%s' matches multiple secret keys:\n"
+msgstr ""
+
 msgid "Create a revocation certificate for this key? (y/N) "
 msgstr "要為這把金鑰建立一份撤銷憑證嗎? (y/N) "
 
@@ -6743,7 +6881,7 @@ msgstr "取回 '%s' 時出錯: http 狀態 %u\n"
 
 #, fuzzy
 #| msgid "CRL access not possible due to disabled %s\n"
-msgid "CRL access not possible due to TOR mode\n"
+msgid "CRL access not possible due to Tor mode\n"
 msgstr "不可能存取 CRL 因已停用 %s\n"
 
 #, c-format
@@ -6809,6 +6947,10 @@ msgid "certificate too large to make any sense\n"
 msgstr "憑證大到全然不合理的境界\n"
 
 #, c-format
+msgid "can't connect to the dirmngr: %s\n"
+msgstr "無法連接至 dirmngr: %s\n"
+
+#, c-format
 msgid "lookup failed: %s\n"
 msgstr "查找失敗: %s\n"
 
@@ -6842,31 +6984,6 @@ msgid "error writing base64 encoding: %s\n"
 msgstr "寫入 base64 編碼時出錯: %s\n"
 
 #, c-format
-msgid "failed to allocate assuan context: %s\n"
-msgstr "配置 assuan 脈絡失敗: %s\n"
-
-msgid "apparently no running dirmngr\n"
-msgstr "顯然沒有執行中的 dirmngr\n"
-
-msgid "no running dirmngr - starting one\n"
-msgstr "沒有執行中的 dirmngr - 正在啟動一個出來\n"
-
-#, c-format
-msgid "malformed %s environment variable\n"
-msgstr "格式不對的 %s 環境變數\n"
-
-#, c-format
-msgid "dirmngr protocol version %d is not supported\n"
-msgstr "未支援 dirmngr 協定版本 %d\n"
-
-msgid "can't connect to the dirmngr - trying fall back\n"
-msgstr "無法連線至 dirmngr - 正試著退回\n"
-
-#, c-format
-msgid "can't connect to the dirmngr: %s\n"
-msgstr "無法連接至 dirmngr: %s\n"
-
-#, c-format
 msgid "unsupported inquiry '%s'\n"
 msgstr "未支援的查詢 '%s'\n"
 
@@ -6952,7 +7069,7 @@ msgstr "|N|單次查詢不要傳回超過 N 筆項目"
 msgid "|FILE|use the CA certificates in FILE for HKP over TLS"
 msgstr "|檔案|在 HKP over TLS 的指定檔案中使用 CA 憑證"
 
-msgid "route all network traffic via TOR"
+msgid "route all network traffic via Tor"
 msgstr ""
 
 msgid ""
@@ -7247,7 +7364,7 @@ msgstr "來自伺服器的回應太大; 上限是 %d 位元組\n"
 
 #, fuzzy
 #| msgid "OCSP request not possible due to disabled HTTP\n"
-msgid "OCSP request not possible due to TOR mode\n"
+msgid "OCSP request not possible due to Tor mode\n"
 msgstr "因為已經停用 HTTP 而不可能有 OCSP 請求\n"
 
 msgid "OCSP request not possible due to disabled HTTP\n"
@@ -7401,6 +7518,10 @@ msgid "can't allocate control structure: %s\n"
 msgstr "無法配置控制結構: %s\n"
 
 #, c-format
+msgid "failed to allocate assuan context: %s\n"
+msgstr "配置 assuan 脈絡失敗: %s\n"
+
+#, c-format
 msgid "failed to initialize the server: %s\n"
 msgstr "伺服器啟始失敗: %s\n"
 
@@ -7597,7 +7718,7 @@ msgstr "控制著互動及強制執行的選項"
 
 #, fuzzy
 #| msgid "Options controlling the security"
-msgid "Options controlling the use of TOR"
+msgid "Options controlling the use of Tor"
 msgstr "控制著安全性的選項"
 
 msgid "Configuration for HTTP servers"
@@ -7848,6 +7969,47 @@ msgstr ""
 "語法: gpg-check-pattern [選項] 樣式檔案\n"
 "用樣式檔案來檢查由標準輸入給定的密語\n"
 
+#~ msgid "cleared passphrase cached with ID: %s\n"
+#~ msgstr "清除此 ID 被快取住的密語: %s\n"
+
+#, fuzzy
+#~| msgid "failed to store the key: %s\n"
+#~ msgid "Failed to open the keyring DB.\n"
+#~ msgstr "存放金鑰失敗: %s\n"
+
+#, fuzzy
+#~| msgid "failed to open '%s': %s\n"
+#~ msgid "Failed to parse '%s'.\n"
+#~ 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"
+
+#~ msgid "Please select at most one subkey.\n"
+#~ msgstr "請至多選擇一把子鑰.\n"
+
+#~ msgid "apparently no running dirmngr\n"
+#~ msgstr "顯然沒有執行中的 dirmngr\n"
+
+#~ msgid "no running dirmngr - starting one\n"
+#~ msgstr "沒有執行中的 dirmngr - 正在啟動一個出來\n"
+
+#~ msgid "malformed %s environment variable\n"
+#~ msgstr "格式不對的 %s 環境變數\n"
+
+#~ msgid "dirmngr protocol version %d is not supported\n"
+#~ msgstr "未支援 dirmngr 協定版本 %d\n"
+
+#~ msgid "can't connect to the dirmngr - trying fall back\n"
+#~ msgstr "無法連線至 dirmngr - 正試著退回\n"
+
 #~ msgid "export keys in an S-expression based format"
 #~ msgstr "匯出金鑰成以 S-表示式形式的格式"
 
index 1aebdd3..95a2561 100644 (file)
@@ -686,7 +686,7 @@ static int
 ct_get_status (int slot, unsigned int *status)
 {
   (void)slot;
-  /* The status we returned is wrong but we don't care becuase ctAPI
+  /* The status we returned is wrong but we don't care because ctAPI
      is not anymore required.  */
   *status = APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE;
   return 0;
@@ -2035,7 +2035,7 @@ open_pcsc_reader_wrapped (const char *portstr)
   int err;
   unsigned int dummy_status;
 
-  /* Note that we use the constant and not the fucntion because this
+  /* Note that we use the constant and not the function because this
      code won't be be used under Windows.  */
   const char *wrapperpgm = GNUPG_LIBEXECDIR "/gnupg-pcsc-wrapper";
 
@@ -2466,6 +2466,7 @@ static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
+  reader_table[slot].rdrname = NULL;
   reader_table[slot].used = 0;
   return 0;
 }
@@ -2619,7 +2620,8 @@ open_ccid_reader (const char *portstr)
     return -1;
   slotp = reader_table + slot;
 
-  err = ccid_open_reader (&slotp->ccid.handle, portstr);
+  err = ccid_open_reader (&slotp->ccid.handle, portstr,
+                          (const char **)&slotp->rdrname);
   if (err)
     {
       slotp->used = 0;
@@ -3156,7 +3158,7 @@ apdu_open_reader (const char *portstr)
    with remote readers only.  Note that the supplied CLOSEFNC will
    only be called once and the slot will not be valid afther this.
 
-   If PORTSTR is NULL we default to the first availabe port.
+   If PORTSTR is NULL we default to the first available port.
 */
 int
 apdu_open_remote_reader (const char *portstr,
@@ -3213,9 +3215,12 @@ apdu_close_reader (int slot)
   sw = apdu_disconnect (slot);
   if (sw)
     {
+      /*
+       * When the reader/token was removed it might come here.
+       * It should go through to call CLOSE_READER even if we got an error.
+       */
       if (DBG_READER)
-        log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
-      return sw;
+        log_debug ("apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
     }
   if (reader_table[slot].close_reader)
     {
@@ -4050,7 +4055,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
    The return value is the status word or -1 for an invalid SLOT or
    other non card related error.  If RETBUF is not NULL, it will
    receive an allocated buffer with the returned data.  The length of
-   that data will be put into *RETBUFLEN.  The caller is reponsible
+   that data will be put into *RETBUFLEN.  The caller is responsible
    for releasing the buffer even in case of errors.  */
 int
 apdu_send_le(int slot, int extended_mode,
@@ -4073,7 +4078,7 @@ apdu_send_le(int slot, int extended_mode,
    return value is the status word or -1 for an invalid SLOT or other
    non card related error.  If RETBUF is not NULL, it will receive an
    allocated buffer with the returned data.  The length of that data
-   will be put into *RETBUFLEN.  The caller is reponsible for
+   will be put into *RETBUFLEN.  The caller is responsible for
    releasing the buffer even in case of errors.  */
 int
 apdu_send (int slot, int extended_mode,
@@ -4326,3 +4331,10 @@ apdu_send_direct (int slot, size_t extended_length,
 
   return 0;
 }
+
+
+const char *
+apdu_get_reader_name (int slot)
+{
+  return reader_table[slot].rdrname;
+}
index 7e30f76..1694eac 100644 (file)
@@ -134,6 +134,6 @@ int apdu_send_direct (int slot, size_t extended_length,
                       const unsigned char *apdudata, size_t apdudatalen,
                       int handle_more,
                       unsigned char **retbuf, size_t *retbuflen);
-
+const char *apdu_get_reader_name (int slot);
 
 #endif /*APDU_H*/
index 379bcd1..b4bb55b 100644 (file)
@@ -47,11 +47,6 @@ struct app_ctx_s {
      operations the particular function pointer is set to NULL */
   unsigned int ref_count;
 
-  /* Flag indicating that a reset has been done for that application
-     and that this context is merely lingering and just should not be
-     reused.  */
-  int no_reuse;
-
   /* Used reader slot. */
   int slot;
 
index d43db5b..581c5dd 100644 (file)
@@ -1223,7 +1223,7 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
 /* Get the public key for KEYNO and store it as an S-expresion with
    the APP handle.  On error that field gets cleared.  If we already
    know about the public key we will just return.  Note that this does
-   not mean a key is available; this is soley indicated by the
+   not mean a key is available; this is solely indicated by the
    presence of the app->app_local->pk[KEYNO].key field.
 
    Note that GnuPG 1.x does not need this and it would be too time
@@ -1468,7 +1468,7 @@ get_public_key (app_t app, int keyno)
   xfree (buffer);
   xfree (mbuf);
   xfree (ebuf);
-  return 0;
+  return err;
 }
 #endif /* GNUPG_MAJOR_VERSION > 1 */
 
@@ -1548,7 +1548,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
   send_keypair_info (app, ctrl, 2);
   send_keypair_info (app, ctrl, 3);
   /* Note: We do not send the Cardholder Certificate, because that is
-     relativly long and for OpenPGP applications not really needed.  */
+     relatively long and for OpenPGP applications not really needed.  */
   return 0;
 }
 
@@ -1675,7 +1675,7 @@ check_pinpad_request (app_t app, pininfo_t *pininfo, int admin_pin)
 }
 
 
-/* Verify a CHV either using using the pinentry or if possibile by
+/* Verify a CHV either using using the pinentry or if possible by
    using a pinpad.  PINCB and PINCB_ARG describe the usual callback
    for the pinentry.  CHVNO must be either 1 or 2. SIGCOUNT is only
    used with CHV1.  PINVALUE is the address of a pointer which will
@@ -2793,8 +2793,8 @@ change_keyattr_from_string (app_t app,
   /* Because this function deletes the key we require the string
      "--force" in the data to make clear that something serious might
      happen.  */
-  sscanf (string, " --force %d %d %n", &key, &algo, &n);
-  if (n < 13)
+  sscanf (string, "--force %d %d %n", &key, &algo, &n);
+  if (n < 12)
     {
       err = gpg_error (GPG_ERR_INV_DATA);
       goto leave;
@@ -4114,9 +4114,12 @@ do_decipher (app_t app, const char *keyidstr,
   if (rc)
     return rc;
 
-  if (indatalen == 16 + 1 || indatalen == 32 + 1)
-    /* PSO:DECIPHER with symmetric key.  */
-    padind = -1;
+  if ((indatalen == 16 + 1 || indatalen == 32 + 1)
+      && ((char *)indata)[0] == 0x02)
+    {
+      /* PSO:DECIPHER with symmetric key.  */
+      padind = -1;
+    }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_RSA)
     {
       /* We might encounter a couple of leading zeroes in the
@@ -4172,6 +4175,27 @@ do_decipher (app_t app, const char *keyidstr,
     }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC)
     {
+      int old_format_len = 0;
+
+      if (app->app_local->keyattr[1].ecc.flags)
+        {
+          if (indatalen > 32 && (indatalen % 2))
+            { /*
+               * Skip the prefix.  It may be 0x40 (in new format), or MPI
+               * head of 0x00 (in old format).
+               */
+              indata = (const char *)indata + 1;
+              indatalen--;
+            }
+          else if (indatalen < 32)
+            { /*
+               * Old format trancated by MPI handling.
+               */
+              old_format_len = indatalen;
+              indatalen = 32;
+            }
+        }
+
       fixuplen = 7;
       fixbuf = xtrymalloc (fixuplen + indatalen);
       if (!fixbuf)
@@ -4185,7 +4209,16 @@ do_decipher (app_t app, const char *keyidstr,
       fixbuf[4] = (char)(indatalen+2);
       fixbuf[5] = '\x86';
       fixbuf[6] = (char)indatalen;
-      memcpy (fixbuf+fixuplen, indata, indatalen);
+      if (old_format_len)
+        {
+          memset (fixbuf+fixuplen, 0, 32 - old_format_len);
+          memcpy (fixbuf+fixuplen + 32 - old_format_len,
+                  indata, old_format_len);
+        }
+      else
+        {
+          memcpy (fixbuf+fixuplen, indata, indatalen);
+        }
       indata = fixbuf;
       indatalen = fixuplen + indatalen;
 
@@ -4211,6 +4244,21 @@ do_decipher (app_t app, const char *keyidstr,
                          indata, indatalen, le_value, padind,
                          outdata, outdatalen);
   xfree (fixbuf);
+  if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC
+      && app->app_local->keyattr[1].ecc.flags)
+    { /* Add the prefix 0x40 */
+      fixbuf = xtrymalloc (*outdatalen + 1);
+      if (!fixbuf)
+        {
+          xfree (*outdata);
+          return gpg_error_from_syserror ();
+        }
+      fixbuf[0] = 0x40;
+      memcpy (fixbuf+1, *outdata, *outdatalen);
+      xfree (*outdata);
+      *outdata = fixbuf;
+      *outdatalen = *outdatalen + 1;
+    }
 
   if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
       && app->app_local->manufacturer == 5
@@ -4632,7 +4680,7 @@ app_select_openpgp (app_t app)
         }
       xfree (relptr);
 
-      /* Some of the first cards accidently don't set the
+      /* Some of the first cards accidentally don't set the
          CHANGE_FORCE_CHV bit but allow it anyway. */
       if (app->card_version <= 0x0100 && manufacturer == 1)
         app->app_local->extcap.change_force_chv = 1;
index eb074ef..e4d9de0 100644 (file)
@@ -276,7 +276,7 @@ typedef struct aodf_object_s *aodf_object_t;
 struct app_local_s
 {
   /* The home DF. Note, that we don't yet support a multilevel
-     hierachy.  Thus we assume this is directly below the MF.  */
+     hierarchy.  Thus we assume this is directly below the MF.  */
   unsigned short home_df;
 
   /* The type of the card. */
index 5fa06b0..51464a2 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -39,7 +39,6 @@ static struct
   int initialized;
   npth_mutex_t lock;
   app_t app;        /* Application context in use or NULL. */
-  app_t last_app;   /* Last application object used as this slot or NULL. */
 } lock_table[10];
 
 
@@ -87,7 +86,6 @@ lock_reader (int slot, ctrl_t ctrl)
         }
       lock_table[slot].initialized = 1;
       lock_table[slot].app = NULL;
-      lock_table[slot].last_app = NULL;
     }
 
   res = npth_mutex_lock (&lock_table[slot].lock);
@@ -139,12 +137,6 @@ app_dump_state (void)
             if (lock_table[slot].app->apptype)
               log_printf (" type='%s'", lock_table[slot].app->apptype);
           }
-        if (lock_table[slot].last_app)
-          {
-            log_printf (" lastapp=%p", lock_table[slot].last_app);
-            if (lock_table[slot].last_app->apptype)
-              log_printf (" type='%s'", lock_table[slot].last_app->apptype);
-          }
         log_printf ("\n");
       }
 }
@@ -167,32 +159,48 @@ is_app_allowed (const char *name)
 void
 application_notify_card_reset (int slot)
 {
-  app_t app;
-
   if (slot < 0 || slot >= DIM (lock_table))
     return;
 
   /* FIXME: We are ignoring any error value here.  */
   lock_reader (slot, NULL);
 
-  /* Mark application as non-reusable.  */
+  /* Release the APP, as it's not reusable any more.  */
   if (lock_table[slot].app)
-    lock_table[slot].app->no_reuse = 1;
+    {
+      deallocate_app (lock_table[slot].app);
+      lock_table[slot].app = NULL;
+    }
 
-  /* Deallocate a saved application for that slot, so that we won't
-     try to reuse it.  If there is no saved application, set a flag so
-     that we won't save the current state. */
-  app = lock_table[slot].last_app;
+  unlock_reader (slot);
+}
 
-  if (app)
+
+/*
+ * This function is called with lock held.
+ */
+static gpg_error_t
+check_conflict (int slot, const char *name)
+{
+  app_t app = lock_table[slot].app;
+
+  if (!app || !name || (app->apptype && !ascii_strcasecmp (app->apptype, name)))
+    return 0;
+
+  if (!app->ref_count)
     {
-      lock_table[slot].last_app = NULL;
+      lock_table[slot].app = NULL;
       deallocate_app (app);
+      return 0;
+    }
+  else
+    {
+      log_info ("application '%s' in use by reader %d - can't switch\n",
+                app->apptype? app->apptype : "<null>", slot);
+      return gpg_error (GPG_ERR_CONFLICT);
     }
-  unlock_reader (slot);
 }
 
-
 /* This function is used by the serialno command to check for an
    application conflict which may appear if the serialno command is
    used to request a specific application and the connection has
@@ -200,18 +208,18 @@ application_notify_card_reset (int slot)
 gpg_error_t
 check_application_conflict (ctrl_t ctrl, int slot, const char *name)
 {
-  app_t app;
-
-  (void)ctrl;
+  gpg_error_t err;
 
   if (slot < 0 || slot >= DIM (lock_table))
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
-  if (app && app->apptype && name)
-    if ( ascii_strcasecmp (app->apptype, name))
-      return gpg_error (GPG_ERR_CONFLICT);
-  return 0;
+  err = lock_reader (slot, ctrl);
+  if (err)
+    return err;
+
+  err = check_conflict (slot, name);
+  unlock_reader (slot);
+  return err;
 }
 
 
@@ -240,50 +248,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
     return err;
 
   /* First check whether we already have an application to share. */
-  app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
-  if (app && name)
-    if (!app->apptype || ascii_strcasecmp (app->apptype, name))
-      {
-        unlock_reader (slot);
-        if (app->apptype)
-          log_info ("application '%s' in use by reader %d - can't switch\n",
-                    app->apptype, slot);
-        return gpg_error (GPG_ERR_CONFLICT);
-      }
-
-  /* Don't use a non-reusable marked application.  */
-  if (app && app->no_reuse)
+  err = check_conflict (slot, name);
+  if (err)
     {
       unlock_reader (slot);
-      log_info ("lingering application '%s' in use by reader %d"
-                " - can't switch\n",
-                app->apptype? app->apptype:"?", slot);
-      return gpg_error (GPG_ERR_CONFLICT);
+      return err;
     }
 
-  /* If we don't have an app, check whether we have a saved
-     application for that slot.  This is useful so that a card does
-     not get reset even if only one session is using the card - this
-     way the PIN cache and other cached data are preserved.  */
-  if (!app && lock_table[slot].initialized && lock_table[slot].last_app)
-    {
-      app = lock_table[slot].last_app;
-      if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) )
-        {
-          /* Yes, we can reuse this application - either the caller
-             requested an unspecific one or the requested one matches
-             the saved one. */
-          lock_table[slot].app = app;
-          lock_table[slot].last_app = NULL;
-        }
-      else
-        {
-          /* No, this saved application can't be used - deallocate it. */
-          lock_table[slot].last_app = NULL;
-          deallocate_app (app);
-          app = NULL;
-        }
-    }
+  app = lock_table[slot].app;
 
   /* If we can reuse an application, bump the reference count and
      return it.  */
@@ -493,18 +465,10 @@ release_application (app_t app)
       return;
     }
 
-  if (lock_table[slot].last_app)
-    deallocate_app (lock_table[slot].last_app);
-  if (app->no_reuse)
-    {
-      /* If we shall not re-use the application we can't save it for
-         later use. */
-      deallocate_app (app);
-      lock_table[slot].last_app = NULL;
-    }
-  else
-    lock_table[slot].last_app = lock_table[slot].app;
-  lock_table[slot].app = NULL;
+  /* We don't deallocate app here.  Instead, we keep it.  This is
+     useful so that a card does not get reset even if only one session
+     is using the card - this way the PIN cache and other cached data
+     are preserved.  */
   unlock_reader (slot);
 }
 
@@ -915,7 +879,7 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
 }
 
 
-/* Perform a GET CHALLENGE operation.  This fucntion is special as it
+/* Perform a GET CHALLENGE operation.  This function is special as it
    directly accesses the card without any application specific
    wrapper. */
 gpg_error_t
index 5a1a243..7f83f80 100644 (file)
@@ -1542,7 +1542,8 @@ ccid_vendor_specific_init (ccid_driver_t handle)
 /* Open the reader with the internal number READERNO and return a
    pointer to be used as handle in HANDLE.  Returns 0 on success. */
 int
-ccid_open_reader (ccid_driver_t *handle, const char *readerid)
+ccid_open_reader (ccid_driver_t *handle, const char *readerid,
+                  const char **rdrname_p)
 {
   int rc = 0;
   struct usb_device *dev = NULL;
@@ -1661,6 +1662,9 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
       free (*handle);
       *handle = NULL;
     }
+  else
+    if (rdrname_p)
+      *rdrname_p = (*handle)->rid;
 
   return rc;
 }
@@ -1839,6 +1843,11 @@ 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. */
@@ -1913,26 +1922,26 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
                            5000 /* ms timeout */);
       if (rc == msglen)
         return 0;
-#ifdef ENODEV
-      if (rc == -(ENODEV))
+#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 = ENODEV;
+          errno = LIBUSB_ERRNO_NO_SUCH_DEVICE;
           rc = -1;
         }
-#endif /*ENODEV*/
+#endif /*LIBUSB_ERRNO_NO_SUCH_DEVICE*/
 
       if (rc == -1)
         {
           DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
-#ifdef ENODEV
-          if (errno == ENODEV)
+#ifdef LIBUSB_ERRNO_NO_SUCH_DEVICE
+          if (errno == LIBUSB_ERRNO_NO_SUCH_DEVICE)
             {
               handle->enodev_seen = 1;
               return CCID_DRIVER_ERR_NO_READER;
             }
-#endif /*ENODEV*/
+#endif /*LIBUSB_ERRNO_NO_SUCH_DEVICE*/
         }
       else
         DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
@@ -2312,7 +2321,7 @@ ccid_poll (ccid_driver_t handle)
     }
   else if (msg[0] == RDR_to_PC_HardwareError)
     {
-      DEBUGOUT ("hardware error occured\n");
+      DEBUGOUT ("hardware error occurred\n");
     }
   else
     {
@@ -3127,7 +3136,7 @@ ccid_transceive (ccid_driver_t handle,
             }
 
           if (!!(tpdu[1] & 0x40) != handle->t1_nr)
-            { /* Reponse does not match our sequence number. */
+            { /* Response does not match our sequence number. */
               msg = send_buffer;
               tpdu = msg + hdrlen;
               tpdu[0] = nad_byte;
@@ -3554,7 +3563,7 @@ ccid_transceive_secure (ccid_driver_t handle,
       handle->t1_ns ^= 1;
 
       if (!!(tpdu[1] & 0x40) != handle->t1_nr)
-        { /* Reponse does not match our sequence number. */
+        { /* Response does not match our sequence number. */
           DEBUGOUT ("I-block with wrong seqno received\n");
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
@@ -3594,7 +3603,7 @@ ccid_transceive_secure (ccid_driver_t handle,
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
       else if (!!(tpdu[1] & 0x10) == handle->t1_ns)
-        { /* Reponse does not match our sequence number. */
+        { /* Response does not match our sequence number. */
           DEBUGOUT ("R-block with wrong seqno received on more bit\n");
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
@@ -3730,7 +3739,7 @@ main (int argc, char **argv)
         break;
     }
 
-  rc = ccid_open_reader (&ccid, argc? *argv:NULL);
+  rc = ccid_open_reader (&ccid, argc? *argv:NULL, NULL);
   if (rc)
     return 1;
 
index e62ad5c..be8a5ce 100644 (file)
@@ -111,7 +111,8 @@ typedef struct ccid_driver_s *ccid_driver_t;
 
 int ccid_set_debug_level (int level);
 char *ccid_get_reader_list (void);
-int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
+int ccid_open_reader (ccid_driver_t *handle, const char *readerid,
+                      const char **rdrname_p);
 int ccid_set_progress_cb (ccid_driver_t handle,
                           void (*cb)(void *, const char *, int, int, int),
                           void *cb_arg);
index 41a150b..ba830de 100644 (file)
@@ -529,7 +529,7 @@ open_card (ctrl_t ctrl, const char *apptype)
 static const char hlp_serialno[] =
   "SERIALNO [<apptype>]\n"
   "\n"
-  "Return the serial number of the card using a status reponse.  This\n"
+  "Return the serial number of the card using a status response.  This\n"
   "function should be used to check for the presence of a card.\n"
   "\n"
   "If APPTYPE is given, an application of that type is selected and an\n"
@@ -667,9 +667,18 @@ cmd_learn (assuan_context_t ctx, char *line)
      knows about this card */
   if (!only_keypairinfo)
     {
+      int slot;
+      const char *reader;
       char *serial;
       time_t stamp;
 
+      slot = vreader_slot (ctrl->server_local->vreader_idx);
+      reader = apdu_get_reader_name (slot);
+      if (!reader)
+        return out_of_core ();
+      send_status_direct (ctrl, "READER", reader);
+      /* No need to free the string of READER.  */
+
       rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
       if (rc)
         return rc;
@@ -1138,7 +1147,7 @@ static const char hlp_getattr[] =
   "returned through status message, see the LEARN command for details.\n"
   "\n"
   "However, the current implementation assumes that Name is not escaped;\n"
-  "this works as long as noone uses arbitrary escaping. \n"
+  "this works as long as no one uses arbitrary escaping. \n"
   "\n"
   "Note, that this function may even be used on a locked card.";
 static gpg_error_t
@@ -1176,7 +1185,7 @@ static const char hlp_setattr[] =
   "application.  NAME and VALUE must be percent and '+' escaped.\n"
   "\n"
   "However, the current implementation assumes that NAME is not\n"
-  "escaped; this works as long as noone uses arbitrary escaping.\n"
+  "escaped; this works as long as no one uses arbitrary escaping.\n"
   "\n"
   "A PIN will be requested for most NAMEs.  See the corresponding\n"
   "setattr function of the actually used application (app-*.c) for\n"
@@ -1478,7 +1487,7 @@ static const char hlp_passwd[] =
   "PASSWD [--reset] [--nullpin] <chvno>\n"
   "\n"
   "Change the PIN or, if --reset is given, reset the retry counter of\n"
-  "the card holder verfication vector CHVNO.  The option --nullpin is\n"
+  "the card holder verification vector CHVNO.  The option --nullpin is\n"
   "used for TCOS cards to set the initial PIN.  The format of CHVNO\n"
   "depends on the card application.";
 static gpg_error_t
@@ -1828,7 +1837,7 @@ static const char hlp_apdu[] =
   "  S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1\n"
   "\n"
   "Using the option --more handles the card status word MORE_DATA\n"
-  "(61xx) and concatenates all reponses to one block.\n"
+  "(61xx) and concatenates all responses to one block.\n"
   "\n"
   "Using the option \"--exlen\" the returned APDU may use extended\n"
   "length up to N bytes.  If N is not given a default value is used\n"
index 3c43a4c..515e21f 100644 (file)
@@ -291,7 +291,7 @@ iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo)
 }
 
 /* Perform a VERIFY command on SLOT using the card holder verification
-   vector CHVNO with a CHV of lenght CHVLEN.  Returns 0 on success. */
+   vector CHVNO with a CHV of length CHVLEN.  Returns 0 on success. */
 gpg_error_t
 iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
 {
index 0f92efe..e8218ca 100644 (file)
@@ -1082,7 +1082,6 @@ create_server_socket (const char *name, char **r_redir_name,
   unaddr = xmalloc (sizeof (*unaddr));
   addr = (struct sockaddr*)unaddr;
 
-#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */
   {
     int redirected;
 
@@ -1102,16 +1101,6 @@ create_server_socket (const char *name, char **r_redir_name,
           log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
       }
   }
-#else /* Assuan < 2.1.4 */
-  memset (unaddr, 0, sizeof *unaddr);
-  unaddr->sun_family = AF_UNIX;
-  if (strlen (name) + 1 >= sizeof (unaddr->sun_path))
-    {
-      log_error (_("socket name '%s' is too long\n"), name);
-      scd_exit (2);
-    }
-  strcpy (unaddr->sun_path, name);
-#endif /* Assuan < 2.1.4 */
 
   len = SUN_LEN (unaddr);
 
index 4a67d61..43781ab 100644 (file)
@@ -540,7 +540,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
 
 \f
 /* Create a reader for the given file descriptor.  Depending on the
-   control information an input decoding is automagically choosen.
+   control information an input decoding is automagically chosen.
    The function returns a Base64Context object which must be passed to
    the gpgme_destroy_reader function.  The created KsbaReader object
    is also returned, but the caller must not call the
@@ -621,7 +621,7 @@ gpgsm_destroy_reader (Base64Context ctx)
 \f
 /* Create a writer for the given STREAM.  Depending on
    the control information an output encoding is automagically
-   choosen.  The function returns a Base64Context object which must be
+   chosen.  The function returns a Base64Context object which must be
    passed to the gpgme_destroy_writer function.  The created
    KsbaWriter object is also returned, but the caller must not call
    the ksba_reader_release function on it. */
index 4b2ec33..c1457b6 100644 (file)
@@ -578,7 +578,7 @@ store_serialno (const char *line)
 }
 
 
-/* Callback for the gpgsm_agent_serialno fucntion.  */
+/* Callback for the gpgsm_agent_serialno function.  */
 static gpg_error_t
 scd_serialno_status_cb (void *opaque, const char *line)
 {
@@ -630,7 +630,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 
 
 \f
-/* Callback for the gpgsm_agent_serialno fucntion.  */
+/* Callback for the gpgsm_agent_serialno function.  */
 static gpg_error_t
 scd_keypairinfo_status_cb (void *opaque, const char *line)
 {
index bfb80fb..b06397f 100644 (file)
@@ -239,7 +239,7 @@ start_dirmngr (ctrl_t ctrl)
   dirmngr_ctx_locked = 1;
 
   err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
-  /* We do not check ERR but the existance of a context because the
+  /* We do not check ERR but the existence of a context because the
      error might come from a failed command send to the dirmngr.
      Fixme: Why don't we close the drimngr context if we encountered
      an error in prepare_dirmngr?  */
index 579ca9e..d43147e 100644 (file)
@@ -1784,7 +1784,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
           /* Note that it is possible for the last certificate in the
              chain (i.e. our target certificate) that it has not yet
              been stored in the keybox and thus the flag can't be set.
-             We ignore this error becuase it will later be stored
+             We ignore this error because it will later be stored
              anyway.  */
           err = keydb_set_cert_flags (ci->cert, 1, KEYBOX_FLAG_BLOB, 0,
                                       KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
@@ -2079,7 +2079,7 @@ get_regtp_ca_info (ctrl_t ctrl, ksba_cert_t cert, int *chainlen)
      until we have found the root.  Because we are only interested in
      German Bundesnetzagentur (former RegTP) derived certificates 3
      levels are enough.  (The German signature law demands a 3 tier
-     hierachy; thus there is only one CA between the EE and the Root
+     hierarchy; thus there is only one CA between the EE and the Root
      CA.)  */
   memset (&array, 0, sizeof array);
 
index f32a27c..0cc492a 100644 (file)
@@ -652,7 +652,7 @@ struct format_name_cookie
 };
 
 /* The writer function for the memory stream. */
-static ssize_t
+static gpgrt_ssize_t
 format_name_writer (void *cookie, const void *buffer, size_t size)
 {
   struct format_name_cookie *c = cookie;
@@ -696,7 +696,7 @@ format_name_writer (void *cookie, const void *buffer, size_t size)
   c->len += size;
   p[c->len] = 0; /* Terminate string. */
 
-  return (ssize_t)size;
+  return (gpgrt_ssize_t)size;
 }
 
 
index 0774591..2c6550c 100644 (file)
@@ -917,38 +917,53 @@ create_request (ctrl_t ctrl,
 
   /* Set key usage flags.  */
   use = get_parameter_uint (para, pKEYUSAGE);
-  if (use == GCRY_PK_USAGE_SIGN)
+  if (use)
     {
-      /* For signing only we encode the bits:
-         KSBA_KEYUSAGE_DIGITAL_SIGNATURE
-         KSBA_KEYUSAGE_NON_REPUDIATION */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x06\xC0", 4);
-    }
-  else if (use == GCRY_PK_USAGE_ENCR)
-    {
-      /* For encrypt only we encode the bits:
-         KSBA_KEYUSAGE_KEY_ENCIPHERMENT
-         KSBA_KEYUSAGE_DATA_ENCIPHERMENT */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x04\x30", 4);
-    }
-  else if (use == GCRY_PK_USAGE_CERT)
-    {
-      /* For certify only we encode the bits:
-         KSBA_KEYUSAGE_KEY_CERT_SIGN
-         KSBA_KEYUSAGE_CRL_SIGN */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x01\x06", 4);
-    }
-  else
-    err = 0; /* Both or none given: don't request one. */
-  if (err)
-    {
-      log_error ("error setting the key usage: %s\n",
-                 gpg_strerror (err));
-      rc = err;
-      goto leave;
+      unsigned int mask, pos;
+      unsigned char der[4];
+
+      der[0] = 0x03;
+      der[1] = 0x02;
+      der[2] = 0;
+      der[3] = 0;
+      if ((use & GCRY_PK_USAGE_SIGN))
+        {
+          /* For signing only we encode the bits:
+             KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+             KSBA_KEYUSAGE_NON_REPUDIATION  = 0b11 -> 0b11000000 */
+          der[3] |= 0xc0;
+        }
+      if ((use & GCRY_PK_USAGE_ENCR))
+        {
+          /* For encrypt only we encode the bits:
+             KSBA_KEYUSAGE_KEY_ENCIPHERMENT
+             KSBA_KEYUSAGE_DATA_ENCIPHERMENT = 0b1100 -> 0b00110000 */
+          der[3] |= 0x30;
+        }
+      if ((use & GCRY_PK_USAGE_CERT))
+        {
+          /* For certify only we encode the bits:
+             KSBA_KEYUSAGE_KEY_CERT_SIGN
+             KSBA_KEYUSAGE_CRL_SIGN      = 0b1100000 -> 0b00000110 */
+          der[3] |= 0x06;
+        }
+
+      /* Count number of unused bits.  */
+      for (mask=1, pos=0; pos < 8 * sizeof mask; pos++, mask <<= 1)
+        {
+          if ((der[3] & mask))
+            break;
+          der[2]++;
+        }
+
+      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1, der, 4);
+      if (err)
+        {
+          log_error ("error setting the key usage: %s\n",
+                     gpg_strerror (err));
+          rc = err;
+          goto leave;
+        }
     }
 
 
index 977494c..262781c 100644 (file)
@@ -214,7 +214,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aExport, "export", N_("export certificates")),
 
   /* We use -raw and not -p1 for pkcs#1 secret key export so that it
-     won't accidently be used in case -p12 was intended.  */
+     won't accidentally be used in case -p12 was intended.  */
   ARGPARSE_c (aExportSecretKeyP12, "export-secret-key-p12", "@"),
   ARGPARSE_c (aExportSecretKeyP8,  "export-secret-key-p8", "@"),
   ARGPARSE_c (aExportSecretKeyRaw, "export-secret-key-raw", "@"),
@@ -1487,7 +1487,7 @@ main ( int argc, char **argv)
     log_info (_("WARNING: program may create a core file!\n"));
 
 /*   if (opt.qualsig_approval && !opt.quiet) */
-/*     log_info (_("This software has offically been approved to " */
+/*     log_info (_("This software has officially been approved to " */
 /*                 "create and verify\n" */
 /*                 "qualified signatures according to German law.\n")); */
 
@@ -1524,7 +1524,7 @@ main ( int argc, char **argv)
 
   set_debug ();
 
-  /* Although we alwasy use gpgsm_exit, we better install a regualr
+  /* Although we always use gpgsm_exit, we better install a regualr
      exit handler so that at least the secure memory gets wiped
      out. */
   if (atexit (emergency_cleanup))
index 3635525..b2ad839 100644 (file)
@@ -747,7 +747,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
       goto leave;
     }
 
-  /* GnuPG 2.0.4 accidently created binary P12 files with the string
+  /* GnuPG 2.0.4 accidentally created binary P12 files with the string
      "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
      We fix that here.  */
   if (p12buflen > 29 && !memcmp (p12buffer, "The passphrase is ", 18))
index b3363c4..02b353a 100644 (file)
@@ -478,7 +478,7 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
   return s? s: "";
 }
 
-/* Switch the handle into ephemeral mode and return the orginal value. */
+/* Switch the handle into ephemeral mode and return the original value. */
 int
 keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
 {
index c70de8a..0e94753 100644 (file)
@@ -273,7 +273,7 @@ parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
                         -- two bytes in INPUT.
 
    Create a new buffer with the content of that octet string.  INPUT
-   is the orginal buffer with a length as stored at LENGTH.  Returns
+   is the original buffer with a length as stored at LENGTH.  Returns
    NULL on error or a new malloced buffer with the length of this new
    buffer stored at LENGTH and the number of bytes parsed from input
    are added to the value stored at INPUT_CONSUMED.  INPUT_CONSUMED is
@@ -679,7 +679,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
   unsigned char *plain = NULL;
   int bad_pass = 0;
   unsigned char *cram_buffer = NULL;
-  size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
+  size_t consumed = 0; /* Number of bytes consumed from the original buffer. */
   int is_3des = 0;
   int is_pbes2 = 0;
   gcry_mpi_t *result = NULL;
@@ -1193,7 +1193,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
   gcry_mpi_t *result = NULL;
   int result_count, i;
   unsigned char *cram_buffer = NULL;
-  size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
+  size_t consumed = 0; /* Number of bytes consumed from the original buffer. */
   int is_pbes2 = 0;
 
   where = "start";
index 56f537e..bae03a4 100644 (file)
@@ -184,7 +184,7 @@ gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert, char *country)
 
 /* We know that CERT is a qualified certificate.  Ask the user for
    consent to actually create a signature using this certificate.
-   Returns: 0 for yes, GPG_ERR_CANCEL for no or any otehr error
+   Returns: 0 for yes, GPG_ERR_CANCEL for no or any other error
    code. */
 gpg_error_t
 gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert)
index cdf4a6e..f0512ef 100644 (file)
@@ -55,8 +55,8 @@ struct server_local_s {
 
 
 /* Cookie definition for assuan data line output.  */
-static ssize_t data_line_cookie_write (void *cookie,
-                                       const void *buffer, size_t size);
+static gpgrt_ssize_t data_line_cookie_write (void *cookie,
+                                             const void *buffer, size_t size);
 static int data_line_cookie_close (void *cookie);
 static es_cookie_io_functions_t data_line_cookie_functions =
   {
@@ -129,7 +129,7 @@ has_option (const char *line, const char *name)
 
 /* A write handler used by es_fopencookie to write assuan data
    lines.  */
-static ssize_t
+static gpgrt_ssize_t
 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
 {
   assuan_context_t ctx = cookie;
@@ -140,7 +140,7 @@ data_line_cookie_write (void *cookie, const void *buffer, size_t size)
       return -1;
     }
 
-  return size;
+  return (gpgrt_ssize_t)size;
 }
 
 static int
@@ -425,7 +425,7 @@ static const char hlp_signer[] =
   "used, the signing will then not be done for this key.  If the policy\n"
   "is not to sign at all if not all signer keys are valid, the client\n"
   "has to take care of this.  All SIGNER commands are cumulative until\n"
-  "a RESET but they are *not* reset by an SIGN command becuase it can\n"
+  "a RESET but they are *not* reset by an SIGN command because it can\n"
   "be expected that set of signers are used for more than one sign\n"
   "operation.";
 static gpg_error_t
index 95bb92c..914de8c 100644 (file)
@@ -25,6 +25,12 @@ required_pgms = ../../g10/gpg2 ../../agent/gpg-agent \
 
 TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= LC_ALL=C
 
+if SQLITE3
+sqlite3_dependent_tests = tofu.test
+else
+sqlite3_dependent_tests =
+endif
+
 # Note: version.test needs to be the first test to run and finish.test
 # the last one
 TESTS = version.test mds.test \
@@ -38,7 +44,10 @@ TESTS = version.test mds.test \
        armdetachm.test detachm.test genkey1024.test \
        conventional.test conventional-mdc.test \
        multisig.test verify.test armor.test \
-       import.test ecc.test 4gb-packet.test finish.test
+       import.test ecc.test 4gb-packet.test \
+       $(sqlite3_dependent_tests) \
+       gpgtar.test use-exact-key.test \
+       finish.test
 
 
 TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
@@ -46,7 +55,9 @@ TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.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 \
-            bug1223-good.asc bug1223-bogus.asc 4gb-packet.asc
+            bug1223-good.asc bug1223-bogus.asc 4gb-packet.asc \
+            tofu-keys.asc tofu-keys-secret.asc \
+            tofu-2183839A-1.txt tofu-BC15C85A-1.txt tofu-EE37CF96-1.txt
 
 data_files = data-500 data-9000 data-32000 data-80000 plain-large
 
@@ -70,7 +81,12 @@ priv_keys = privkeys/50B2D4FA4122C212611048BC5FC31BD44393626E.asc \
            privkeys/C905D0AB6AE9655C5A35975939997BBF3325D6DD.asc \
            privkeys/B2BAA7144303DF19BB6FDE23781DD3FDD97918D4.asc \
            privkeys/CF60965BF51F67CF80DECE853E0D2D343468571D.asc \
-           privkeys/DF00E361D34F80868D06879AC21D7A7D4E4FAD76.asc
+           privkeys/DF00E361D34F80868D06879AC21D7A7D4E4FAD76.asc \
+           privkeys/00FE67F28A52A8AA08FFAED20AF832DA916D1985.asc \
+           privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc \
+           privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc \
+           privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc \
+           privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc
 
 
 sample_keys = samplekeys/ecc-sample-1-pub.asc \
@@ -85,7 +101,8 @@ sample_keys = samplekeys/ecc-sample-1-pub.asc \
              samplekeys/dda252ebb8ebe1af-2.asc \
              samplekeys/whats-new-in-2.1.asc \
              samplekeys/e2e-p256-1-clr.asc \
-             samplekeys/e2e-p256-1-prt.asc
+             samplekeys/e2e-p256-1-prt.asc \
+             samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc
 
 EXTRA_DIST = defs.inc pinentry.sh $(TESTS) $(TEST_FILES) ChangeLog-2011 \
             mkdemodirs signdemokey $(priv_keys) $(sample_keys)
@@ -95,10 +112,10 @@ CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
             *.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
+            gnupg-test.stop random_seed gpg-agent.log tofu.db
 
 clean-local:
-       -rm -rf private-keys-v1.d openpgp-revocs.d
+       -rm -rf private-keys-v1.d openpgp-revocs.d tofu.d gpgtar.d
 
 
 # We need to depend on a couple of programs so that the tests don't
index 744e11e..031fc0e 100755 (executable)
@@ -31,5 +31,14 @@ for ciph in `all_cipher_algos`; do
     cmp z y || error "$ciph/$i: mismatch"
   done
 done
-
 progress_end
+
+#info Checking sign+symencrypt
+for i in $plain_files $data_files; do
+    echo "Hier spricht HAL" | $GPG --passphrase-fd 0 $s2k -cs -o x --yes $i
+    echo "Hier spricht HAL" | $GPG --passphrase-fd 0 $s2k     -o y --yes x
+    cmp $i y || error "$i: mismatch in sign+symenc"
+done
+
+
+# eof
diff --git a/tests/openpgp/gpgtar.test b/tests/openpgp/gpgtar.test
new file mode 100755 (executable)
index 0000000..acfaf3f
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+#set -x
+
+# Make sure $srcdir is set.
+if test "x$srcdir" = x
+then
+    echo srcdir environment variable not set!
+    exit 1
+fi
+
+. $srcdir/defs.inc || exit 3
+
+set -e
+
+# Make sure $GNUPGHOME is set.
+if test "x$GNUPGHOME" = x
+then
+    echo "GNUPGHOME not set."
+    exit 1
+fi
+
+TESTFILES="$plain_files $data_files"
+
+TESTDIR=gpgtar.d
+FILELIST="${TESTDIR}/filelist"
+GPG=../../g10/gpg2
+GPGARGS="--trust-model=always"
+
+GPGTAR="../../tools/gpgtar"
+GPGZIP="sh ../../tools/gpg-zip"
+
+for TOOL in "$GPGTAR" "$GPGZIP"
+do
+    rm -rf -- "${TESTDIR}"
+    mkdir "${TESTDIR}"
+
+    $TOOL --gpg "$GPG" --gpg-args "$GPGARGS" \
+          --encrypt --recipient "$usrname2" \
+         --output "${TESTDIR}/test.tar.pgp" $TESTFILES
+
+    $TOOL --gpg "$GPG" --gpg-args "$GPGARGS" \
+          --list-archive "${TESTDIR}/test.tar.pgp" \
+          >"$FILELIST"
+    for F in $TESTFILES
+    do
+       grep -qe "\\b${F}\\b" "$FILELIST"
+    done
+
+    $TOOL --gpg "$GPG"  --gpg-args "$GPGARGS" \
+          --tar-args --directory="${TESTDIR}" \
+          --decrypt "${TESTDIR}/test.tar.pgp"
+    for F in $TESTFILES
+    do
+       diff -q "$F" "${TESTDIR}/$F"
+    done
+done
+
+# Success!
+
+exit 0
diff --git a/tests/openpgp/privkeys/00FE67F28A52A8AA08FFAED20AF832DA916D1985.asc b/tests/openpgp/privkeys/00FE67F28A52A8AA08FFAED20AF832DA916D1985.asc
new file mode 100644 (file)
index 0000000..71d9eb9
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjEyOToAqCYxh+c0mGKVkNRLiSe19rSb
+OgLVJcL6dH1EnawO6klyypIbrDom7DNNTlp7TMlwQ+UsKbmT8jwkU08/awg6W9Wq
+5LCABUStYrVcwJJlf3p4lBru0BSRlaKuIslpk5Powfj2lPXX6o1eRHsnxk9FTD+M
+GcWkhfL9HF+Rq8vPcicpKDE6ZTM6AQABKSgxOmQxMjg6NPUmd199hJrT8TOzgIRl
+vkfedZRLziNM3yBO2nvEjMxKH3uJxKHh/VUg/VLo72On/HIyiQeeDVYcuLJGTm7e
+degk/9C85hT5K4VUF9+LXXDX1Vz/jQdZxq+JwUE/AdlAEC9fkFQzc0ftI832mgjR
+OASwMVphqYUQERz00ve+NDUpKDE6cDY1OgDJoHlM5kAfmQ3HQsykH2QoWnxA6mTa
+aiCn4XIPEsrXCiwObiwWBj3I+w2OTWbodzxWldxBsaYyVCM3bKR6eldFKSgxOnE2
+NToA1X6NuSiiTP6lQcAqnoPC37LE6PUeoohF05hVoRotOm+/sIcve7ZrgVBvELEr
+q6ZU8fUeCUQoMc2ztQEHyC+0eykoMTp1NjQ6HOTajn4vJZPXy/q5sNWhQ7pZDHeJ
+clqSismtIwvuCV3wMAQMIUr+OWTlGHOCYa8FnBn7PbE6TevGdDEE8CQcfCkpKQ==
+=AhP7
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc b/tests/openpgp/privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc
new file mode 100644 (file)
index 0000000..688b182
--- /dev/null
@@ -0,0 +1,23 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDIxOnByb3RlY3RlZC1wcml2YXRlLWtleSgzOnJzYSgxOm4xMjk6AOnl30hwc47r
+LL9QH6g0TX1BEPdWMV4Ou6+rQOErIMAr1AOlUzpjwJllvQqf2OHnQWaTr9kbNLn7
+XUEUhjkH3uHDYMHMdyAb7YJrk3ECDqnmr34VV/F/H5BH7D6AiFktl1SpUTczPxBx
+vPNlJ4joPmTm+ahfg+zL+4pVu6tIhM0LKSgxOmUzOgEAASkoOTpwcm90ZWN0ZWQx
+NDpvcGVucGdwLW5hdGl2ZSgxOTpvcGVucGdwLXByaXZhdGUta2V5KDc6dmVyc2lv
+bjE6NCkoNDphbGdvMzpSU0EpKDQ6c2tleTE6XzEyOToA6eXfSHBzjussv1AfqDRN
+fUEQ91YxXg67r6tA4SsgwCvUA6VTOmPAmWW9Cp/Y4edBZpOv2Rs0uftdQRSGOQfe
+4cNgwcx3IBvtgmuTcQIOqeavfhVX8X8fkEfsPoCIWS2XVKlRNzM/EHG882UniOg+
+ZOb5qF+D7Mv7ilW7q0iEzQsxOl8zOgEAATE6XzEyODpfHMTxVhkHswZdPZ3B7pLc
+LktR6NDmaKNVyhP1/G2y95+dY+s2QT4eosp+uYWeR0XHCqNla7TDND41qrzyEAtH
+iAF3OoydMK4lb0lqfKORRI4tr017wgMxRBLs82Gk5ehtI7AwSca7WvaoAJwKZp42
+th4MOeykeGRRMagJI420QTE6XzY1OgDzN2Pz0dRD20hHKF6eiqAZYaZhmA7pKWuW
+jHCVXO9s6zGfn0Ds+kTQJltOxU/AULATN/ffXqTtXSiprxNUvwnbMTpfNjU6APYx
+GOABYcWOpJn35eSoisB04QtOgT5OpAl/dLbeaJ+Yh9KtrY6wLf/mX03FgE+YbkIf
+TmeB6tDf4RYbXCYyKJExOl82NDo5wagaIbek0F5TRtmqdVk1weEk/0XXdyG/mNIA
+4l/qt/LHcduBN46qHYEKnKhyDMCBDwlSRf455FG8Oi1x+JMYKSg0OmNzdW01OjQx
+MDUyKSgxMDpwcm90ZWN0aW9uNDpub25lKSkpKSk=
+=hX0p
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc b/tests/openpgp/privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc
new file mode 100644 (file)
index 0000000..e69c27c
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjEyOToAx9HkS9EewRBeMrB/4u8wPapd
+l6spEli/46To7WcmBhmvEZJdG0ZQatYNvgkREqOadsgd49onjYaCkBSJtrJrSUOS
++Mo56Ff/52ejToFyfuZs6Ky0UGm9tvKEJw3aZiGNAZ5Pyvp+Jf+xLDwvj0xHHAj8
+lEEhOSrIrGvq4yx/+nUpKDE6ZTM6AQABKSgxOmQxMjg6DfYRUGbNEko1eq8wUEfM
+BBL6NRWlaf2/coVcLPIvCvASdlTWoog4KC7KiQOTKM07hp8Wz4u3hcDnMG/u60/u
+BPHPHCZThYlpGLVMhQwI46NZtMcRSNBp1rhJ5dt/FEcSFvseJOgce4PD/96bB3+c
+dbnvKcWM7ncRLj0wVfBzKeEpKDE6cDY1OgDanvj9klp9UkAgNwRxswOgiFOlGBsz
+J4dpCZHzWDCjYUd3eGWieynAnfuvctGTaMyB5xT7RwruntbgeRgPpejZKSgxOnE2
+NToA6fv/DFn2WVRAODQVQQGGxsvO2cM847IFJu96BbbxOLaZJ536RE980c2a9q/9
+B4hOYzKV4B4NI03u5/BqoOY8/SkoMTp1NjQ6ZIvWN1fksXhQMypVTLg8R81igqS3
+GXKmQ+KrVEfTIHnXKxH7tyfDeJSS6nfpfARhAe2mP3TIrbjX+9PR+QmkgykpKQ==
+=dUou
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc b/tests/openpgp/privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc
new file mode 100644 (file)
index 0000000..8a4fbf6
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjEyOToA5Hj2C3jzD8OGtLaw7+P2gYdA
+fR4s4YS3/AK+kYYtbm5EX4srysyUbylbQDQXUvRzw4FPkjXbboF6KjHw8icNWHCa
+zwSfPTfCDvi0JIildkfNqwBzCmNDRn++X8rvAeDCEJ/BtfcgfgmDTElSJOd+3B4X
+wnmtnBW54KlR42PLobspKDE6ZTM6AQABKSgxOmQxMjg6AkvpIaKimXAwf3G1m1nl
++LEDKdo55gosry8XToQakvdeXyUerCkplTS1uax8smOQUvrIPYvvnQZ7S9wuPli3
+FWH6l/O+2Cgdti99xTSPeJRBeCuf2vv3bAgu/0tyB8MZgRRM9j5NJCeGO7o4DwRg
+UkLWX2+R5p4daI2LRUfmV4EpKDE6cDY1OgDr3h6mXHrLT4qSNexzz8BAvK/PlHMA
+MAJcy76lXSkl92+c4BcpjFDr5Vpaq/VXoLC4L/IlnEEqY967pAycdLH7KSgxOnE2
+NToA9/lAf6hJ4dHQ6ux5BH8DImq2OjW+sK3tIzzf6fpVkPjDuqOYidm+OL2SFCJa
+ymSWdVq2gQYbkcdRXdGKVJWDQSkoMTp1NjQ6NeHBLEuc/VX+h3ifO1jyMlh+9nZs
+HLkQzUyi2HnrXJ224cjvgc312wvtBQMUyLARWuEuMVMAwWofjX+GZXLz0ikpKQ==
+=Rw+Y
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc b/tests/openpgp/privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc
new file mode 100644 (file)
index 0000000..224ce95
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6cnNhKDE6bjEyOToAvkUCG0xYaTIkZiTwd1wCUF8a
+Q2+YdrBGjSfzCyB8DzbPozYA29eOAayDg9RuesQGISmFQ6YRSINsAogdNfZmKu8j
+VMp/2mRQR6necW4OKkdtdnAI8B6Qaj/clBJt990RahXcrXG13fa0n72TpRbxmUUs
+Y4KRpbCRm44rR9AAWPspKDE6ZTM6AQABKSgxOmQxMjg6IvI/yc3C60dXYh9kvzd6
+AVMGWt5zTVFhE+oDfMaxooW5q0tu6vHzViFeYmcxB4FbctnSbTNiN0RUIT7oxpGE
+AAumKRejGAaMwiKZz3bMV05l0LI0Yn10GzXsLtRx+iKzpUxThZETRU43BJeMqP5/
+rVqdQAu47pClgTwQWn6bXNkpKDE6cDY1OgDXtvl8CYDL/Q+9qZDCyItE5j7X4wRV
+en939fdDepuYAgsLLc7yqnDUOzajXWyx6PxygpnRs5cwmo2zbtZyyWKFKSgxOnE2
+NToA4c2I2FZT8gQLl9E3LF8TkBACZzsGb/t3mBUhYNSNZ7W6R/AkZARLI3IZOto5
+xhBrxfQayRISS2PBk390z3JlfykoMTp1NjQ6TamsumtzX7waNMzurt48kluI5Zy9
+isGpweGpp1T+4L+DiXMMAbhFW60gdqqo4+vzkn2M/M/8BPrKCw1TlDn3TSkpKQ==
+=lYo+
+-----END PGP ARMORED FILE-----
diff --git a/tests/openpgp/samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc b/tests/openpgp/samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc
new file mode 100644 (file)
index 0000000..a4772d4
--- /dev/null
@@ -0,0 +1,45 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mI0EVl9ZyAEEAL5FAhtMWGkyJGYk8HdcAlBfGkNvmHawRo0n8wsgfA82z6M2ANvX
+jgGsg4PUbnrEBiEphUOmEUiDbAKIHTX2ZirvI1TKf9pkUEep3nFuDipHbXZwCPAe
+kGo/3JQSbffdEWoV3K1xtd32tJ+9k6UW8ZlFLGOCkaWwkZuOK0fQAFj7ABEBAAG0
+I0JhcnJldHQgQnJvd24gPGJhcnJldHRAZXhhbXBsZS5vcmc+iLkEEwEIACMFAlZf
+WcgCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRC8Bnryi8kBEe5MA/9x
+kAkLHRAw7ctTqp+ecHiOrqdXWbt9xJ0EHQX2M1wkWjqAHLEGIfPDGmO0G8MmwZhu
+mAQetr258lPrcUOZ86xhpy9dacLRFf+Uk0R3nYSbYHFFht64NQFv2dvH6XaR1DfS
+6tnmu0L0BY3qN0BZJHZcVn5mUA8cvOwqSUDKB8k6ebiNBFZfWcgBBADH0eRL0R7B
+EF4ysH/i7zA9ql2XqykSWL/jpOjtZyYGGa8Rkl0bRlBq1g2+CRESo5p2yB3j2ieN
+hoKQFIm2smtJQ5L4yjnoV//nZ6NOgXJ+5mzorLRQab228oQnDdpmIY0Bnk/K+n4l
+/7EsPC+PTEccCPyUQSE5Ksisa+rjLH/6dQARAQABiJ8EGAEIAAkFAlZfWcgCGwwA
+CgkQvAZ68ovJARH0kQP+IMq61Zg+kBU6eL9eKZErcMtMWuddi1KCi8gAe8V7ZmcU
+8sIjKcKewDBgxmYz5siZzf993f4D0aqC/2XrNLnkuQ2P6XzpKZI2CKZXpbJH2eB0
+1F347MjDBA7P3vTwdzfVYklD3MAFC3Q42VGjbCx+OwVcODPZNfWAycQcYBvXS9G4
+jQRWX1rrAQQAqCYxh+c0mGKVkNRLiSe19rSbOgLVJcL6dH1EnawO6klyypIbrDom
+7DNNTlp7TMlwQ+UsKbmT8jwkU08/awg6W9Wq5LCABUStYrVcwJJlf3p4lBru0BSR
+laKuIslpk5Powfj2lPXX6o1eRHsnxk9FTD+MGcWkhfL9HF+Rq8vPcicAEQEAAYkB
+PQQYAQgACQUCVl9a6wIbAgCoCRC8Bnryi8kBEZ0gBBkBCAAGBQJWX1rrAAoJEBFB
+v3/193uDNhkEAIdnkbx6fKxEG6SX/GS/tBRFvvICDt9yGOJd+jmMPZoUODfd0Gkl
+sO7FHRDLL2nyXgz2vhiRBDuboeG8h3oi8QPSi+cg7+EwpVMVFKpEOrtdUVXCR+oo
+TLzD6z4dvdmE3+u6qrtKzkz5CsJ9CrEa0khR0b/We7GFQIpVyoD9NtNiQIkD/RX/
+oNkRG87K2TlTiObMJl7hB1Bk7Sm/E5Pl3knoCkjyo2vkmdK/bVlGBNimDlPh/r1a
+ab/HTeBFjP+pMhqoLZZ8sp4gZ88wsG7AE9FxtRxQEuJKEKAz6rYFK+zl2bfSlSAn
+KL1g5PAQujyLkq8qLJHrZn1imUIsBE6eOyiOWQi2uI0EVl9blQEEAOR49gt48w/D
+hrS2sO/j9oGHQH0eLOGEt/wCvpGGLW5uRF+LK8rMlG8pW0A0F1L0c8OBT5I1226B
+eiox8PInDVhwms8Enz03wg74tCSIpXZHzasAcwpjQ0Z/vl/K7wHgwhCfwbX3IH4J
+g0xJUiTnftweF8J5rZwVueCpUeNjy6G7ABEBAAGInwQYAQgACQUCVl9blQIbDAAK
+CRC8Bnryi8kBESPWA/4gTmke4A3gieDvSRWCzQ5IFkr7B+4niPy6Qitlwmvy7Wdr
+xNSlZJpSN1UBBurIH4wcPV7nlKMuv60eb00llaBSH1HgAfcbyv35EC39Cgz5Ffaf
+7f6EgIPjMGw9Ca1VNEWsfZnPfTz/JPiYzjjyC6N7nhfav4XjXxdicDHUz1pJubiN
+BFZfbpwBBADp5d9IcHOO6yy/UB+oNE19QRD3VjFeDruvq0DhKyDAK9QDpVM6Y8CZ
+Zb0Kn9jh50Fmk6/ZGzS5+11BFIY5B97hw2DBzHcgG+2Ca5NxAg6p5q9+FVfxfx+Q
+R+w+gIhZLZdUqVE3Mz8QcbzzZSeI6D5k5vmoX4Psy/uKVburSITNCwARAQABiQE9
+BBgBCAAJBQJWX26cAhsCAKgJELwGevKLyQERnSAEGQEIAAYFAlZfbpwACgkQvKQ8
+RB6pdHlhowQA2zOO2inuV/Z4Hl5PCDljiChFrKlddXkkdD7vXbdRh2XrQXMttmWW
+9a2NoeYsI4GyRb0T9fT0c7hDgY1NY3k+UHB+ex33xH7X6YADW8mY01q2zJqec9IY
+P2eBAHZrHImlBGStWX+VVHGtZwsDvR/gxkZkYnN1GFPN2ll0z81O0CjjWAP/delj
+0OY6Vc00SxfKJPb1ralpLIEMgRJWOayISHt6J4L1EGVVFs3gs9dqBQQ++65Iw55L
+m4+nieZzExTvSvYVBRbdWBgIJ1mFElHEy2KfeWzMA88pTMBssmH3xIGlkub/guWc
+OZSqAC5pVGPYCcXie7mx1k+5DrnQUgaf11zdvzI=
+=Htgs
+-----END PGP PUBLIC KEY BLOCK-----
index 0d9490a..20d9f51 100644 (file)
@@ -13,3 +13,4 @@ dda252ebb8ebe1af-2.asc rsa4096 key 2 with a long keyid collision.
 whats-new-in-2.1.asc   Collection of sample keys.
 e2e-p256-1-clr.asc     Google End-end-End test key (no protection)
 e2e-p256-1-prt.asc     Ditto, but protected with passphrase "a".
+E657FB607BB4F21C90BB6651BC067AF28BC90111.asc Key with subkeys (no protection)
diff --git a/tests/openpgp/tofu-2183839A-1.txt b/tests/openpgp/tofu-2183839A-1.txt
new file mode 100644 (file)
index 0000000..521b3bb
Binary files /dev/null and b/tests/openpgp/tofu-2183839A-1.txt differ
diff --git a/tests/openpgp/tofu-BC15C85A-1.txt b/tests/openpgp/tofu-BC15C85A-1.txt
new file mode 100644 (file)
index 0000000..88cc649
--- /dev/null
@@ -0,0 +1,9 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owGbwMvMwMF46tzNaXtET0QxnmZPYgj9/c+Sq2MOCwMjBwMbKxOIy8DFKQBTo/SK
+hWFThVuj19r3R/6VzQkpaZuQx7s3r9BQ46v8KXkjb58dSjmXyr7enlCzb7dg1zE7
+aynbc6YTF+wXZI4IlAgPuLJhUeSXo0+WllxbFXUz39407cv15TcXThLj+3tFkSnZ
+YFXwM9+nfAoHpt6I/ZY96SJT3XFZKzO1jeZNJhZsV4Vfrjp0UmnH3E4A
+=X9WM
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/tofu-EE37CF96-1.txt b/tests/openpgp/tofu-EE37CF96-1.txt
new file mode 100644 (file)
index 0000000..33a38db
--- /dev/null
@@ -0,0 +1,9 @@
+-----BEGIN PGP MESSAGE-----
+Version: GnuPG v2
+
+owGbwMvMwMEY0Tqz9J35+WmMp9mTGEJ//xPk6pjDwsDIwcDGygTiMnBxCsDULFZm
+/sk4S36iQ6FuZZPMPdOSe/rZOxNThTmzvJN4l1qe9XGdlLhtpumfzh0uhRnzT2Xc
+jmra+ZdN9+XBhml//i7v6XrfuWu56OuEI/fXH0i3P5HELb+j++6SO85VemLq/tvO
+hNvWtddvuZ7+z2JJaqnP4wiu2t+sEze/MWKZ9zz+u2FV6a3OIyJxjwA=
+=JMtb
+-----END PGP MESSAGE-----
diff --git a/tests/openpgp/tofu-keys-secret.asc b/tests/openpgp/tofu-keys-secret.asc
new file mode 100755 (executable)
index 0000000..68e0d20
--- /dev/null
@@ -0,0 +1,95 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v2
+
+lgAAAgYEVfv86AEEAN20yizZgtnQaJPUV++9Z+rRg4XzjWpLvmiWMpTsn8qhjpyS
+kAa4/4P4/MRWVvSXiRC1uJ7T59Sbm/KFs8TdKaqIMuON3QYjztxm2NmDMA/f5FTv
+RuLkgKAEpwGOqI1Zvm3uleH8hkx0n45tHxCI3bLCfW+12lZxJCGNDBnhvj+5ABEB
+AAH+BwMCeYHLsHWjaoTufvOw6/xINpFQV8JcwSc+RaEIfmIwEwO242+vUEZefkia
+yMMJTd20C144zMr/3Tsx/+c8ULAbR/NBtuG49jsGWFJH2uN/5pi40x2S/afJuwru
+0co5xQSnpZtM4v9mvFM517IROhHY1pl6KpK87pZm5JHGB4525DpAYJ7vTTmHE2NW
+e5jr7a7SpXwTU7dKHbLxY+kofH7DLvMX6KjOJ/kDLIqnK3AeCwfhXkkRRP8UI/0J
+pZEPUyImag6FryRdoZJPTPX7TMWM4zrdnT6xOffIe1REpo59LVkvg6TiPtnlnuY8
+Y9NVZ+mWz0RHtxFh1b70G6D5C5Mdi/iGUAAfTwNhjdnmYsN1qKxcO533qlj/rXHn
+6uxauiR4d+7Ioy2RsPpY2FqTkgymhBLn6ZcYvzwEXaAygLUs8HmzPuiVm5Ls5UXn
+VKaRMc+DBQPz3W3CuMWsHAyKsg4ibp/6MSf0klYHUG8WVXI4tLGOkbg5HbQTVGVz
+dGluZyAoaW5zZWN1cmUhKYi9BBMBCAAnBQJV+/zoAhsDBQkB4TOABQsJCAcCBhUI
+CQoLAgQWAgMBAh4BAheAAAoJEFiFmXXuN8+WqPYEAIW+qAoFnc2emFnx/b+vKW9X
+1g3NLmsLyUUBI34GCh+sGa6C0SptdKc68uvKUc6daBiHuoukN4F+1rYUuNG8WNMs
+V/JwGPKVADPIFrgGiotMW770ZnzZsoqGWvwUnyrlaUI6AYHe4Uj9YAmnmi647A/u
+UxcI1H20M3dENSUyiS1zngAAAgUEVfv86AEEAMgaJrwhFOhEmHHgqyzx2KFzG4SD
+F6jyAg1CIVKmiLSBfNXWa43vJwfxLo7vbT1wy0iiJF8+ALD/ghppmZb9NpsiUC+X
+xT4ublOSvRgN+527WdUX8ym0EXxjpuSSW+hVZZwUP0K0fBdIVaVCawJGEp5Lc/mX
+KnjmXvLQxWSQYgB9ABEBAAH+BwMCtE0VqaVadDju5hPxFcvSTjNkKwGVZZgQBWVZ
+sYj/Sd/Pbc90xb3TSf/VQGVQhKei+GBmUPYOPqStOP30pJvK0SBxkJ2BYb876RJC
+lj48lkTGFPZwhw69BZq6QA5nfBm41V+W6iakdyEww6g1Q93AyzuAirBJraR+oQ6Q
+beqo52TtYAhpAQbUBsQ/1VO/1zx8eHOG298kYpU2Jo7Te81d03rWcSaDbJqcEmsI
+jJe1ccvQ8oU+k6ttbY3xTiKYWfJCxEaOcYpO4z1/94CPFYv1D5rJqJ/C0/SPmS4t
+4ZMqenEhsAGhMgPLKXNmQadQA2WBOATsSxmKCcC9LNjw1YudXPiLfHEnBKGQSbRF
+sZ2xZqRm7wRTQ/eXAJGGiQ41owstwSUAcFTGIhHunw9dy41CdgnZIEQCxb7R8tBv
+isRlG0cIpO5159LB3NECR4++xBB02nq6lOjysKDmYuWYuQakD1u9L6R+LQBVTxYL
+/iEK8wyf18n/iKUEGAEIAA8FAlX7/OgCGwwFCQHhM4AACgkQWIWZde43z5ZTvAP9
+EWGZu97aZhjIbD18Y2HjbXQn4L6iyeDMuM++Tsnnn57li+HLUAX8ieRHy1l/VE3t
+HhdcqRqAsrxnkGAWKMlYYZS9WHDzrffxtQlszOwpAOWdNDsWsPdbko95XvLatoqk
+t9KxB19sLao6eCBKwB9muMs10i86P+Cehwh97n/UNGOWAAACBgRV+/07AQQAxCWd
+rsUW2IhexMxOvMi32Z63bOEC5JkEy8tntGYwk54I2XGXRebdutMrXqh0nKO7p23k
+gfWjRp1dpbSp20AzdIkwsRlAjOuqhZ3Q6t+kP6xWtxAQI8YZ6lQ0VeZC0dTBllr3
+UlY4tw0emLcScNsGuDVUPYhQoJBMkk4oNw+wWfUAEQEAAf4HAwJNRwdntiqzHO76
+GxxlNilWuwitCGbGwZfmo8K8m2uAMzSKsxUp16rcLVvfQsEzS6rDhF4VbJQyLvZJ
+LDkXB0/DFbPVrxG8byJ2i6WKUzsqcevM29OXOmFfH1NVuVi5oUWbwCR6ctsNQSL7
+Bje0E6+6pme9YQtKgUIBzc2Dw+nq6WjfLc0aEc+rrXzWsJKEUKkjnaUa/AeAVYyO
+rTOk5fLrw6vy/sKsuScvLNvQUrr7U+g69gpk53Cyw2WILlADxbysg2CDMDsDmXk/
+sK6zikAgDjQTRaOJkX4BzCBoqZRaDbLMfze6kA6cwQqDTsUELy1ziH56FjRXuBqj
+D4IziA0/XE8gyMRtoMYXmF0pKBQh0RLoudorcPQE9PCFvKaXmASA80nMeBoYxlIm
+kPMBkkkwiXU4irc1m8phlcrZjYE12pxzWgSYBEwTbbzNe2EcFKf+H1vp9DXqZSua
+wLdiUx6JrSHGzoPl3XFAQXNFoOEGvlFN9nH+tBNUZXN0aW5nIChpbnNlY3VyZSEp
+iL0EEwEIACcFAlX7/TsCGwMFCQHhM4AFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AA
+CgkQys7ZlrwVyFq0NgP/cazey0+qJrTaQ0Z6eab1p8PMFE8BpcegrokxfJn61zo7
+JECjQW+htoOBBIQH32mtqjO/J/SbiBDp3xNcdabCnkphW4jkcgn+FoUbLA3GFk9f
+xtElNDGXHcQNimvhhxfrEr2Mi1yo2rKShiIO0N2yySXCJJIC9CXpDCAIhNdEYeCe
+AAACBQRV+/07AQQA3BJN5N1RI6uesA03xwTW1ABTV4tbjLROKLlTPbxb+TjWQAfQ
+lztbSavzjTO6wPPmHnGv2sXPiH2guET+thKAw1WchItKx+MiT8nnsBJHl950mqI8
+uTHGljkQBuKARVl1ELS3do6CQvGyG+5qHyl3crpED152Q5C/F53b4EfgNXEAEQEA
+Af4HAwL449o07unvl+6XONg4R9pVE0Qp0xCL5CmjhwlL8lUuGTvjciN+lXD6k7VH
+Xj9Wu86alkKZQKyZxESPtsRR5dGWgrvhmUrvPftRmO4PV7A5AS0yi54CQGaWSnOL
+nqVkENUs85Pq1LLfnM8MRIdGpS9225bwsAoB/eJk7zKNRGOUlzCDGW3f12aemyrR
+2RHGVPOvn6SVb8r8RkqCDMApR0j76cTMDiMyaGByi93y8qhXiu88Y+J/+fK5wQis
+FwPJGZVCqNTiglclgrNG4+z8G4SUvkA6W5yDiZyftN67TXqxJKKBXFS5gzWujPti
+boDzivsY9sP4Mkoc94TAmJeaLtNrqHy4UMo/m9YBmuP4hRJ7TCKmvVN4hZCN2mvJ
+4S1vi4Z9GnyxJAbxq9Gb1UA9glVAVt6bQVYO6ySIp4W29xFnoRUm4i0tCovWBn9x
+MWSkG5SLznbh2tKLN0uJGzh4G8xo2fdfx6tWy2x0gw95T5WDg7S2oe6IpQQYAQgA
+DwUCVfv9OwIbDAUJAeEzgAAKCRDKztmWvBXIWqexA/9nZUXs9BGcwpodhqjGY+H9
+/IUJua95jti9t0BleEu+h0R9O+XDEE/77IK9ET4f0t9WMfMhPO7ZIgUxFutB/Z7U
+MuyVteIvGxF/TTbQAKuCrnLYuPWkGiYjR9e0ZDbgmKrRZ/jwhdaxF0IHrR1PJLUn
+vO97qfZC7097/urCsWDMo5YAAAIGBFX8ElYBBACfcdcAcR6BJ2Ba3/HnQR1S0rG3
+8bWq8Rdtt072hDd16oQCNFpQs5WQNruCCpobmB6yOmjKJv8Cf9mxBdcQDxobcw6M
+lHPWZl04SoQKQOa5h6ptITxr+UFFFqfh7AZ7ZtDYaFfBqQX9fvdOX99C18SIcCcN
+0rHoxXfG7D/AaHEysQARAQAB/gcDAj0P/+idN7Q87sZYs1aBo3OqKKdl+a51tcgd
+80HdoEQWyIwOStl9+XleUHyrU5f9kni1I2NCrl+hLyPGaT8dGJinH103fgsGvY/L
+Z2lg5gsPdfb5U5Kyn8MfgAuAEVh0XiLOAVZf4tVjcn3jGW9VM/cDHQI9uwz0MtN0
+xxj1iw151/ydtFt4Qw+Ljh0cwBauiHSaG8rhfObJGbKpXNBJG6QfaGBlOAErO1my
+fr7UgWbul6xCZe/t7Um2rp5GxTJsN+AwDDLqSbwCzmArXRJiEnL5qaw891HuXTIC
++lxtGNxP6bqe+4Bg/T+MIjJVWzx9avGR2WweSKBqbsyRkmZQCIkWDmp/g9t17ujo
+RrzNUT60Y0gMhJOQxZcgdXJtlT/X0RvP+tGAiVEAlvpQ+9RTzqvf4sZAPndpE4PY
+dKXJF5Pua9cWU+UceQV/Nr+JAlLzNWOlwSOJUVGsQ+RzeFJyB2D5xoG6tRI9idYU
+V+vcNGRpJzsXO6S0E1Rlc3RpbmcgKGluc2VjdXJlISmIvQQTAQgAJwUCVfwSVgIb
+AwUJAeEzgAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA8WpFfIYODmknrA/96
+90yhjN3ELmWSJetKzvt7MlUS0j6UkA5VvDObCmAm+bDrQSGdwDJj6gu88b4biNEx
+Cz/Dmo67R9Z+gLE6LGvzYCPZ+GE/ZQ9VMo/AeUEZO44Aa7vRwnYFU0VmMJUeGQbC
+Je4JnLjF/+0yIgh/CtwFL3J/+9eayf6e6L/9WhUZ5J4AAAIGBFX8ElYBBADXznv8
+7J5i/EN8dMtjzx99LXtJdSJ3iJfp69d5V1FygvsDSlMZVekflWKF2ipHRulxLXea
+8mH0salQviQ32qPAyfCWpELLL2srTVezj6ntKVF9hZruQ2d1KBVV+syq6nSY9Eg8
+0mHizvIV5cR2b2X/X6qybJrwhW10oWh+cuLg6QARAQAB/gcDAkwZfkpx6rGW7qkb
+iuwl3c6d1o2x9HeiZG8fZ8UGU5n0Nx4bp4a60j/d+bJowww8sPRcJ+8mi/dNi9dC
+1Dls2CmmOP8U2DsPT189d+JiqlXUumhRyTo5ptglMrHkrMp489QpyCIUhW6HVopI
+ppdOJGE0kTJ7pRx0fevz3la5553IyglJ9iUqgxz2+9XlvDhSplz8zVhyZd5UPW94
+hi+vHCDf3TSakMFFZEVPCQaMunB7urI1wXx/mOT5BTSOp1PVq4SE5TtC2/GrHBU6
+/5wuqyhlT3oH+jF/GfvZQgattnkaFn/JY77/mfTCzyQb1/2iQMO8uTe8KjWAKd5h
+AoCcgxoX0rqSxe7YS2Obl1v0icWbg4wvI8WUAv5pRL7EMVcuUugrb40rWzOiJzYY
+IwEmO+tp08Ev+arbjEMzk+IXLTr3wDip/2oHHU3P2OSi46iLdueUvVnnNXff0H4e
+mqT2zlJQoPCbYMaKxL0yxvFnZLfCWolLOJaIpQQYAQgADwUCVfwSVgIbDAUJAeEz
+gAAKCRA8WpFfIYODmqzxBACNLC9j2EJvoiKhRMAUJTGCQvDWNWAI/2Ln/61Ftqu5
++OoOI0N7uL1LjWNHrhS/PMKwcIu9iZn/uQV/OGj9YuKw58WeyKkTIEnD7bU5aUQk
+8jdRITPnr/InyHvs21P9hh18MZvDk9L9rL+uwK+9BkeL0MDL3wlAG57Fay9OXgY1
+CQ==
+=2SlE
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/tests/openpgp/tofu-keys.asc b/tests/openpgp/tofu-keys.asc
new file mode 100755 (executable)
index 0000000..2de1cf7
--- /dev/null
@@ -0,0 +1,47 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mI0EVfv86AEEAN20yizZgtnQaJPUV++9Z+rRg4XzjWpLvmiWMpTsn8qhjpySkAa4
+/4P4/MRWVvSXiRC1uJ7T59Sbm/KFs8TdKaqIMuON3QYjztxm2NmDMA/f5FTvRuLk
+gKAEpwGOqI1Zvm3uleH8hkx0n45tHxCI3bLCfW+12lZxJCGNDBnhvj+5ABEBAAG0
+E1Rlc3RpbmcgKGluc2VjdXJlISmIvQQTAQgAJwUCVfv86AIbAwUJAeEzgAULCQgH
+AgYVCAkKCwIEFgIDAQIeAQIXgAAKCRBYhZl17jfPlqj2BACFvqgKBZ3NnphZ8f2/
+rylvV9YNzS5rC8lFASN+BgofrBmugtEqbXSnOvLrylHOnWgYh7qLpDeBfta2FLjR
+vFjTLFfycBjylQAzyBa4BoqLTFu+9GZ82bKKhlr8FJ8q5WlCOgGB3uFI/WAJp5ou
+uOwP7lMXCNR9tDN3RDUlMoktc7iNBFX7/OgBBADIGia8IRToRJhx4Kss8dihcxuE
+gxeo8gINQiFSpoi0gXzV1muN7ycH8S6O7209cMtIoiRfPgCw/4IaaZmW/TabIlAv
+l8U+Lm5Tkr0YDfudu1nVF/MptBF8Y6bkklvoVWWcFD9CtHwXSFWlQmsCRhKeS3P5
+lyp45l7y0MVkkGIAfQARAQABiKUEGAEIAA8FAlX7/OgCGwwFCQHhM4AACgkQWIWZ
+de43z5ZTvAP9EWGZu97aZhjIbD18Y2HjbXQn4L6iyeDMuM++Tsnnn57li+HLUAX8
+ieRHy1l/VE3tHhdcqRqAsrxnkGAWKMlYYZS9WHDzrffxtQlszOwpAOWdNDsWsPdb
+ko95XvLatoqkt9KxB19sLao6eCBKwB9muMs10i86P+Cehwh97n/UNGOYjQRV+/07
+AQQAxCWdrsUW2IhexMxOvMi32Z63bOEC5JkEy8tntGYwk54I2XGXRebdutMrXqh0
+nKO7p23kgfWjRp1dpbSp20AzdIkwsRlAjOuqhZ3Q6t+kP6xWtxAQI8YZ6lQ0VeZC
+0dTBllr3UlY4tw0emLcScNsGuDVUPYhQoJBMkk4oNw+wWfUAEQEAAbQTVGVzdGlu
+ZyAoaW5zZWN1cmUhKYi9BBMBCAAnBQJV+/07AhsDBQkB4TOABQsJCAcCBhUICQoL
+AgQWAgMBAh4BAheAAAoJEMrO2Za8FchatDYD/3Gs3stPqia02kNGenmm9afDzBRP
+AaXHoK6JMXyZ+tc6OyRAo0FvobaDgQSEB99praozvyf0m4gQ6d8TXHWmwp5KYVuI
+5HIJ/haFGywNxhZPX8bRJTQxlx3EDYpr4YcX6xK9jItcqNqykoYiDtDdssklwiSS
+AvQl6QwgCITXRGHguI0EVfv9OwEEANwSTeTdUSOrnrANN8cE1tQAU1eLW4y0Tii5
+Uz28W/k41kAH0Jc7W0mr840zusDz5h5xr9rFz4h9oLhE/rYSgMNVnISLSsfjIk/J
+57ASR5fedJqiPLkxxpY5EAbigEVZdRC0t3aOgkLxshvuah8pd3K6RA9edkOQvxed
+2+BH4DVxABEBAAGIpQQYAQgADwUCVfv9OwIbDAUJAeEzgAAKCRDKztmWvBXIWqex
+A/9nZUXs9BGcwpodhqjGY+H9/IUJua95jti9t0BleEu+h0R9O+XDEE/77IK9ET4f
+0t9WMfMhPO7ZIgUxFutB/Z7UMuyVteIvGxF/TTbQAKuCrnLYuPWkGiYjR9e0ZDbg
+mKrRZ/jwhdaxF0IHrR1PJLUnvO97qfZC7097/urCsWDMo5iNBFX8ElYBBACfcdcA
+cR6BJ2Ba3/HnQR1S0rG38bWq8Rdtt072hDd16oQCNFpQs5WQNruCCpobmB6yOmjK
+Jv8Cf9mxBdcQDxobcw6MlHPWZl04SoQKQOa5h6ptITxr+UFFFqfh7AZ7ZtDYaFfB
+qQX9fvdOX99C18SIcCcN0rHoxXfG7D/AaHEysQARAQABtBNUZXN0aW5nIChpbnNl
+Y3VyZSEpiL0EEwEIACcFAlX8ElYCGwMFCQHhM4AFCwkIBwIGFQgJCgsCBBYCAwEC
+HgECF4AACgkQPFqRXyGDg5pJ6wP/evdMoYzdxC5lkiXrSs77ezJVEtI+lJAOVbwz
+mwpgJvmw60EhncAyY+oLvPG+G4jRMQs/w5qOu0fWfoCxOixr82Aj2fhhP2UPVTKP
+wHlBGTuOAGu70cJ2BVNFZjCVHhkGwiXuCZy4xf/tMiIIfwrcBS9yf/vXmsn+nui/
+/VoVGeS4jQRV/BJWAQQA1857/OyeYvxDfHTLY88ffS17SXUid4iX6evXeVdRcoL7
+A0pTGVXpH5VihdoqR0bpcS13mvJh9LGpUL4kN9qjwMnwlqRCyy9rK01Xs4+p7SlR
+fYWa7kNndSgVVfrMqup0mPRIPNJh4s7yFeXEdm9l/1+qsmya8IVtdKFofnLi4OkA
+EQEAAYilBBgBCAAPBQJV/BJWAhsMBQkB4TOAAAoJEDxakV8hg4OarPEEAI0sL2PY
+Qm+iIqFEwBQlMYJC8NY1YAj/Yuf/rUW2q7n46g4jQ3u4vUuNY0euFL88wrBwi72J
+mf+5BX84aP1i4rDnxZ7IqRMgScPttTlpRCTyN1EhM+ev8ifIe+zbU/2GHXwxm8OT
+0v2sv67Ar70GR4vQwMvfCUAbnsVrL05eBjUJ
+=Btw1
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/openpgp/tofu.test b/tests/openpgp/tofu.test
new file mode 100755 (executable)
index 0000000..18c1756
--- /dev/null
@@ -0,0 +1,245 @@
+#!/bin/sh
+
+. $srcdir/defs.inc || exit 3
+
+# set -x
+
+KEYS="2183839A BC15C85A EE37CF96"
+
+# Make sure $srcdir is set.
+if test "x$srcdir" = x
+then
+    echo srcdir environment variable not set!
+    exit 1
+fi
+
+# Make sure $GNUPGHOME is set.
+if test "x$GNUPGHOME" = x
+then
+    echo "GNUPGHOME not set."
+    exit 1
+fi
+
+# Import the test keys.
+$GPG --import $srcdir/tofu-keys.asc
+
+# Make sure the keys are imported.
+for k in $KEYS
+do
+    if ! $GPG --list-keys $k >/dev/null 2>&1
+    then
+       echo Missing key $k
+       exit 1
+    fi
+done
+
+format=auto
+
+debug()
+{
+    echo "$@" >&2
+}
+
+debug_exec()
+{
+    debug "Running GNUPGHOME=$GNUPGHOME $@"
+    ${@:+"$@"}
+}
+
+# $1 is the keyid of the policy to lookup.  Any remaining arguments
+# are simply passed to GPG.
+#
+# This function only supports keys with a single user id.
+getpolicy()
+{
+    keyid=$1
+    if test x$keyid = x
+    then
+       echo No keyid supplied!
+       exit 1
+    fi
+    shift
+
+    policy=$(debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
+                 --with-colons $@ --list-keys "$keyid" \
+                   | awk -F: '/^uid:/ { print $18 }')
+    if test $(echo "$policy" | wc -l) -ne 1
+    then
+       echo "Got: $policy" >&2
+       echo "error"
+    else
+       case $policy in
+           auto|good|unknown|bad|ask) echo $policy ;;
+           *) echo "error" ;;
+       esac
+    fi
+}
+
+# $1 is the key id
+# $2 is the expected policy
+# The rest are additional options to pass to gpg.
+checkpolicy()
+{
+    debug
+    debug "checkpolicy($@)"
+
+    keyid=$1
+    shift
+    expected_policy=$1
+    shift
+    policy=$(getpolicy "$keyid" ${@:+"$@"})
+    if test "x$policy" != "x$expected_policy"
+    then
+       echo "$keyid: Expected policy to be \`$expected_policy', but got \`$policy'."
+       exit 1
+    fi
+}
+
+# $1 is the keyid of the trust level to lookup.  Any remaining
+# arguments are simply passed to GPG.
+#
+# This function only supports keys with a single user id.
+gettrust()
+{
+    keyid=$1
+    if test x$keyid = x
+    then
+       echo No keyid supplied!
+       exit 1
+    fi
+    shift
+
+    trust=$(debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
+                --with-colons $@ --list-keys "$keyid" \
+                   | awk -F: '/^pub:/ { print $2 }')
+    if test $(echo "$trust" | wc -l) -ne 1
+    then
+       echo "error"
+    else
+       case $trust in
+           [oidreqnmfuws-]) echo $trust ;;
+           *) echo "Bad trust value: $trust" >&2; echo "error" ;;
+       esac
+    fi
+}
+
+# $1 is the key id
+# $2 is the expected trust level
+# The rest are additional options to pass to gpg.
+checktrust()
+{
+    debug
+    debug "checktrust($@)"
+
+    keyid=$1
+    shift
+    expected_trust=$1
+    shift
+    trust=$(gettrust "$keyid" ${@:+"$@"})
+    if test "x$trust" != "x$expected_trust"
+    then
+       echo "$keyid: Expected trust to be \`$expected_trust', but got \`$trust'."
+       exit 1
+    fi
+}
+
+# Set key $1's policy to $2.  Any remaining arguments are passed as
+# options to gpg.
+setpolicy()
+{
+    debug
+    debug "setpolicy($@)"
+
+    keyid=$1
+    shift
+    policy=$1
+    shift
+
+    debug_exec $GPG --tofu-db-format=$format \
+        --trust-model=tofu ${@:+"$@"} --tofu-policy $policy $keyid
+}
+
+for format in split flat
+do
+    debug
+    debug "Testing with db format $format"
+
+    # Carefully remove the TOFU db.
+    test -e $GNUPGHOME/tofu.db && rm $GNUPGHOME/tofu.db
+    test -e $GNUPGHOME/tofu.d/email && rm -r $GNUPGHOME/tofu.d/email
+    test -e $GNUPGHOME/tofu.d/key && rm -r $GNUPGHOME/tofu.d/key
+    # This will fail if the directory is not empty.
+    test -e $GNUPGHOME/tofu.d && rmdir $GNUPGHOME/tofu.d
+
+    # Verify a message.  There should be no conflict and the trust policy
+    # should be set to auto.
+    debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
+        --verify $srcdir/tofu-2183839A-1.txt
+
+    checkpolicy 2183839A auto
+
+    trust=$(gettrust 2183839A)
+    debug "default trust = $trust"
+    if test "x$trust" != xm
+    then
+       echo "Wrong default trust.  Got: \`$trust', expected \`m'"
+       exit 1
+    fi
+
+    # Trust should be derived lazily.  Thus, if the policy is set to auto
+    # and we change --tofu-default-policy, then the trust should change as
+    # well.  Try it.
+    checktrust 2183839A f --tofu-default-policy=good
+    checktrust 2183839A - --tofu-default-policy=unknown
+    checktrust 2183839A n --tofu-default-policy=bad
+
+    # Change the policy to something other than auto and make sure the
+    # policy and the trust are correct.
+    for policy in good unknown bad
+    do
+       if test $policy = good
+       then
+           expected_trust='f'
+       elif test $policy = unknown
+       then
+           expected_trust='-'
+       else
+           expected_trust='n'
+       fi
+
+       debug
+       debug "Setting TOFU policy to $policy"
+       setpolicy 2183839A $policy
+
+       # Since we have a fixed policy, the trust level shouldn't
+       # change if we change the default policy.
+       for default_policy in auto good unknown bad ask
+       do
+           checkpolicy 2183839A $policy --tofu-default-policy=$default_policy
+           checktrust 2183839A $expected_trust \
+                      --tofu-default-policy=$default_policy
+       done
+    done
+
+    # BC15C85A conflicts with 2183839A.  On conflict, this will set
+    # BC15C85A to ask.  If 2183839A is auto (it's not, it's bad), then
+    # it will be set to ask.
+    debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
+        --verify $srcdir/tofu-BC15C85A-1.txt
+    checkpolicy BC15C85A ask
+    checkpolicy 2183839A bad
+
+    # EE37CF96 conflicts with 2183839A and BC15C85A.  We change
+    # BC15C85A's policy to auto and leave 2183839A's policy at bad.
+    # This conflict should cause BC15C85A's policy to be changed to
+    # ask (since it is auto), but not affect 2183839A's policy.
+    setpolicy BC15C85A auto
+    checkpolicy BC15C85A auto
+    debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
+        --verify $srcdir/tofu-EE37CF96-1.txt
+    checkpolicy BC15C85A ask
+    checkpolicy 2183839A bad
+    checkpolicy EE37CF96 ask
+done
+
+exit 0
diff --git a/tests/openpgp/use-exact-key.test b/tests/openpgp/use-exact-key.test
new file mode 100755 (executable)
index 0000000..cbbd009
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+. $srcdir/defs.inc || exit 3
+
+# set -x
+
+# Make sure $srcdir is set.
+if test "x$srcdir" = x
+then
+    echo srcdir environment variable not set!
+    exit 1
+fi
+
+# Import the sample key
+#
+# pub   1024R/8BC90111 2015-12-02
+#       Key fingerprint = E657 FB60 7BB4 F21C 90BB  6651 BC06 7AF2 8BC9 0111
+# uid       [ultimate] Barrett Brown <barrett@example.org>
+# sub   1024R/3E880CFF 2015-12-02 (encryption)
+# sub   1024R/F5F77B83 2015-12-02 (signing)
+# sub   1024R/45117079 2015-12-02 (encryption)
+# sub   1024R/1EA97479 2015-12-02 (signing)
+info "Importing public key."
+if $GPG --import $srcdir/samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc
+then
+    :
+else
+    error "$k: import failed"
+fi
+
+# By default, the most recent, valid signing subkey (1EA97479).
+for x in 8BC90111 3E880CFF F5F77B83 45117079 1EA97479
+do
+    if ! echo | $GPG -s -u "$x" | $GPG --verify --status-fd=1 \
+            | grep -q 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479'
+    then
+        echo | $GPG -s -u "$x" | $GPG --verify --status-fd=2
+        error "Unexpected key used for signing (not the signing subkey, specified \"$x\")."
+        exit 1
+    fi
+done
+
+# But, if we request a particular signing key, we should get it.
+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 "
+    then
+        echo | $GPG -s -u "$x!" | $GPG --verify --status-fd=2
+        error "Unexpected key used for signing (specified: \"$x!\")."
+        exit 1
+    fi
+done
+
+exit 0
index 057bcf0..cb3ffa8 100755 (executable)
@@ -74,7 +74,12 @@ for i in 50B2D4FA4122C212611048BC5FC31BD44393626E \
          0D6F6AD4C4C803B25470F9104E9F4E6A4CA64255 \
          FD692BD59D6640A84C8422573D469F84F3B98E53 \
          76F7E2B35832976B50A27A282D9B87E44577EB66 \
-         A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD ; do
+         A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \
+         00FE67F28A52A8AA08FFAED20AF832DA916D1985 \
+         1DF48228FEFF3EC2481B106E0ACA8C465C662CC5 \
+         A2832820DC9F40751BDCD375BB0945BA33EC6B4C \
+         ADE710D74409777B7729A7653373D820F67892E0 \
+         CEFC51AF91F68A2904FBFF62C4F075A4785B803F; do
    $GPG --dearmor < $srcdir/privkeys/$i.asc > private-keys-v1.d/$i.key
 done
 
index 496b1a6..a793cca 100644 (file)
@@ -142,9 +142,9 @@ gpgtar_SOURCES = \
        gpgtar-extract.c \
        gpgtar-list.c \
        no-libgcrypt.c
-gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS)
-#gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS)
-gpgtar_LDADD = $(common_libs) $(GPG_ERROR_LIBS) \
+gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) $(LIBASSUAN_CFLAGS)
+gpgtar_LDADD = $(libcommonpth) $(GPG_ERROR_LIBS) \
+               $(NPTH_LIBS) $(LIBASSUAN_LIBS) \
                $(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS)
 
 
index 83f6550..fbf30a2 100644 (file)
@@ -319,7 +319,7 @@ get_regerror (int errcode, regex_t *compiled)
 
 /* Parse the pattern given in the memory aread DATA/DATALEN and return
    a new pattern array.  The end of the array is indicated by a NULL
-   entry.  On error an error message is printed and the fucntion
+   entry.  On error an error message is printed and the function
    returns NULL.  Note that the function modifies DATA and assumes
    that data is nul terminated (even if this is one byte past
    DATALEN).  */
@@ -446,7 +446,7 @@ match_p (const char *string, pattern_t *patarray)
 }
 
 
-/* Actual processing of the input.  This fucntion does not return an
+/* Actual processing of the input.  This function does not return an
    error code but exits as soon as a match has been found.  */
 static void
 process (FILE *fp, pattern_t *patarray)
index d27b1f9..a6b4238 100644 (file)
@@ -94,7 +94,8 @@ while test $# -gt 0 ; do
       exit 0
       ;;
     --gpg)
-      GPG=$1
+      GPG=$2
+      shift
       shift
       ;;
     --gpg-args)
@@ -103,7 +104,8 @@ while test $# -gt 0 ; do
       shift
       ;;
     --tar)
-      TAR=$1
+      TAR=$2
+      shift
       shift
       ;;
     --tar-args)
@@ -126,8 +128,8 @@ while test $# -gt 0 ; do
 done
 
 if test x$create = xyes ; then
-#   echo "$TAR -cf - "$@" | $GPG --set-filename x.tar $gpg_args" 1>&2
-   $TAR -cf - "$@" | $GPG --set-filename x.tar $gpg_args
+#   echo "$TAR $tar_args -cf - "$@" | $GPG --set-filename x.tar $gpg_args" 1>&2
+   $TAR $tar_args -cf - "$@" | $GPG --set-filename x.tar $gpg_args
 elif test x$list = xyes ; then
 #   echo "cat \"$1\" | $GPG $gpg_args | $TAR $tar_args -tf -" 1>&2
    cat "$1" | $GPG $gpg_args | $TAR $tar_args -tf -
index e736162..5e4bd58 100644 (file)
@@ -906,9 +906,9 @@ static gc_option_t gc_options_dirmngr[] =
      "dirmngr", "force loading of outdated CRLs",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
 
-   { "TOR",
+   { "Tor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
-     "gnupg", N_("Options controlling the use of TOR") },
+     "gnupg", N_("Options controlling the use of Tor") },
    { "use-tor", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      "dirmngr", "route all network traffic via TOR",
       GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
@@ -1271,7 +1271,7 @@ gc_component_reload (int component)
 \f
 /* More or less Robust version of dgettext.  It has the side effect of
    switching the codeset to utf-8 because this is what we want to
-   output.  In theory it is posible to keep the orginal code set and
+   output.  In theory it is posible to keep the original code set and
    switch back for regular disgnostic output (redefine "_(" for that)
    but given the natur of this tool, being something invoked from
    other pograms, it does not make much sense.  */
@@ -3300,7 +3300,7 @@ gc_component_change_options (int component, estream_t in, estream_t out)
       int i;
       int saved_errno = errno;
 
-      /* An error occured or a dry-run is requested.  */
+      /* An error occurred or a dry-run is requested.  */
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
          if (src_filename[i])
index d22c5ac..f12c5f4 100644 (file)
@@ -75,7 +75,7 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, int *algorithm_id,
   id = 0;
 
   /* Loop over all records until we have found the subkey
-     corresponsing to the fingerprint. Inm general the first record
+     corresponding to the fingerprint. In general the first record
      should be the pub record, but we don't rely on that.  Given that
      we only need to look at one key, it is sufficient to compare the
      keyid so that we don't need to look at "fpr" records. */
@@ -248,7 +248,7 @@ main (int argc, char **argv)
   int algorithm_id;
   pkdbuf_t *pkdbuf;
   size_t pkdbuf_n;
-  char *command;
+  char *command = NULL;
   FILE *fp;
   int ret;
   gcry_error_t err;
@@ -263,21 +263,50 @@ main (int argc, char **argv)
   algorithm_id = 0;  /* (avoid cc warning) */
   identifier = NULL; /* (avoid cc warning) */
 
-  assert (argc == 2);
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage: %s KEYID\n", argv[0]);
+      exit (1);
+    }
+  if (strcmp (argv[1], "--help") == 0)
+    {
+      fprintf (stderr, "Usage: %s KEYID\n", argv[0]);
+      fprintf (stderr, "\n");
+      fprintf (stderr,
+               "Convert a gpg key to a format appropriate for inclusion in an\n"
+               "ssh authorized_keys file.\n");
+      exit (0);
+    }
 
   keyid = argv[1];
 
-  ret = asprintf (&command,
-                 "gpg --list-keys --with-colons --with-key-data '%s'",
-                 keyid);
-  assert (ret > 0);
+  asprintf (&command,
+            "gpg2 --list-keys --with-colons --with-key-data '%s'",
+            keyid);
+  if (! command)
+    {
+      fprintf (stderr, "Out of memory.\n");
+      exit (1);
+    }
 
   fp = popen (command, "r");
-  assert (fp);
+  if (! fp)
+    {
+      fprintf (stderr, "Failed to running: '%s'\n", command);
+      exit (1);
+    }
 
   err = retrieve_key_material (fp, keyid, &algorithm_id, &pkdbuf, &pkdbuf_n);
-  assert (! err);
-  assert ((algorithm_id == 1) || (algorithm_id == 17));
+  if (err)
+    {
+      fprintf (stderr, "Error looking up key: %s\n", gpg_strerror (err));
+      exit (1);
+    }
+  if (! ((algorithm_id == 1) || (algorithm_id == 17)))
+    {
+      fprintf (stderr, "Unsupported algorithm: %d\n", algorithm_id);
+      exit (1);
+    }
 
   if (algorithm_id == 1)
     {
index b9c18a2..98bbad0 100644 (file)
@@ -624,7 +624,7 @@ parse_message (FILE *fp)
   if (!msg)
     die ("can't open parser: %s", strerror (errno));
 
-  /* Fixme: We should not use fgets becuase it can't cope with
+  /* Fixme: We should not use fgets because it can't cope with
      embedded nul characters. */
   while (fgets (line, sizeof (line), fp))
     {
index fad6d57..cc82889 100644 (file)
@@ -36,6 +36,7 @@
 #include <assert.h>
 
 #include "i18n.h"
+#include "../common/call-gpg.h"
 #include "../common/sysutils.h"
 #include "gpgtar.h"
 
@@ -739,14 +740,15 @@ write_eof_mark (estream_t stream)
 /* Create a new tarball using the names in the array INPATTERN.  If
    INPATTERN is NULL take the pattern as null terminated strings from
    stdin.  */
-void
-gpgtar_create (char **inpattern)
+gpg_error_t
+gpgtar_create (char **inpattern, int encrypt)
 {
   gpg_error_t err = 0;
   struct scanctrl_s scanctrl_buffer;
   scanctrl_t scanctrl = &scanctrl_buffer;
   tar_header_t hdr, *start_tail;
   estream_t outstream = NULL;
+  estream_t cipher_stream = NULL;
   int eof_seen = 0;
 
   if (!inpattern)
@@ -863,6 +865,17 @@ gpgtar_create (char **inpattern)
   if (outstream == es_stdout)
     es_set_binary (es_stdout);
 
+  if (encrypt)
+    {
+      cipher_stream = outstream;
+      outstream = es_fopenmem (0, "rwb");
+      if (! outstream)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
   for (hdr = scanctrl->flist; hdr; hdr = hdr->next)
     {
       err = write_file (outstream, hdr);
@@ -870,15 +883,41 @@ gpgtar_create (char **inpattern)
         goto leave;
     }
   err = write_eof_mark (outstream);
+  if (err)
+    goto leave;
+
+  if (encrypt)
+    {
+      err = es_fseek (outstream, 0, SEEK_SET);
+      if (err)
+        goto leave;
+
+      err = gpg_encrypt_stream (NULL,
+                                opt.gpg_program,
+                                opt.gpg_arguments,
+                                outstream,
+                                opt.recipients,
+                                cipher_stream);
+      if (err)
+        goto leave;
+    }
 
  leave:
   if (!err)
     {
+      gpg_error_t first_err;
       if (outstream != es_stdout)
-        err = es_fclose (outstream);
+        first_err = es_fclose (outstream);
       else
-        err = es_fflush (outstream);
+        first_err = es_fflush (outstream);
       outstream = NULL;
+      if (cipher_stream != es_stdout)
+        err = es_fclose (cipher_stream);
+      else
+        err = es_fflush (cipher_stream);
+      cipher_stream = NULL;
+      if (! err)
+        err = first_err;
     }
   if (err)
     {
@@ -886,6 +925,8 @@ gpgtar_create (char **inpattern)
                  es_fname_get (outstream), gpg_strerror (err));
       if (outstream && outstream != es_stdout)
         es_fclose (outstream);
+      if (cipher_stream && cipher_stream != es_stdout)
+        es_fclose (cipher_stream);
       if (opt.outfile)
         gnupg_remove (opt.outfile);
     }
@@ -895,4 +936,5 @@ gpgtar_create (char **inpattern)
       scanctrl->flist = hdr->next;
       xfree (hdr);
     }
+  return err;
 }
index 6e506d9..728737d 100644 (file)
@@ -28,6 +28,7 @@
 #include <assert.h>
 
 #include "i18n.h"
+#include "../common/call-gpg.h"
 #include "../common/sysutils.h"
 #include "gpgtar.h"
 
@@ -52,7 +53,10 @@ extract_regular (estream_t stream, const char *dirname,
   else
     err = 0;
 
-  outfp = es_fopen (fname, "wb");
+  if (opt.dry_run)
+    outfp = es_fopenmem (0, "wb");
+  else
+    outfp = es_fopen (fname, "wb");
   if (!outfp)
     {
       err = gpg_error_from_syserror ();
@@ -119,7 +123,7 @@ extract_directory (const char *dirname, tar_header_t hdr)
 
  /* Note that we don't need to care about EEXIST because we always
      extract into a new hierarchy.  */
-  if (gnupg_mkdir (fname, "-rwx------"))
+  if (! opt.dry_run && gnupg_mkdir (fname, "-rwx------"))
     {
       err = gpg_error_from_syserror ();
       if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -264,11 +268,12 @@ create_directory (const char *dirprefix)
 
 
 \f
-void
-gpgtar_extract (const char *filename)
+gpg_error_t
+gpgtar_extract (const char *filename, int decrypt)
 {
   gpg_error_t err;
   estream_t stream;
+  estream_t cipher_stream = NULL;
   tar_header_t header = NULL;
   const char *dirprefix = NULL;
   char *dirname = NULL;
@@ -283,7 +288,7 @@ gpgtar_extract (const char *filename)
         {
           err = gpg_error_from_syserror ();
           log_error ("error opening '%s': %s\n", filename, gpg_strerror (err));
-          return;
+          return err;
         }
     }
   else
@@ -292,31 +297,55 @@ gpgtar_extract (const char *filename)
   if (stream == es_stdin)
     es_set_binary (es_stdin);
 
-  if (filename)
+  if (decrypt)
     {
-      dirprefix = strrchr (filename, '/');
-      if (dirprefix)
-        dirprefix++;
-      else
-        dirprefix = filename;
+      cipher_stream = stream;
+      stream = es_fopenmem (0, "rwb");
+      if (! stream)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      err = gpg_decrypt_stream (NULL, opt.gpg_program, opt.gpg_arguments,
+                                cipher_stream, stream);
+      if (err)
+        goto leave;
+
+      err = es_fseek (stream, 0, SEEK_SET);
+      if (err)
+        goto leave;
     }
-  else if (opt.filename)
+
+  if (opt.directory)
+    dirname = xtrystrdup (opt.directory);
+  else
     {
-      dirprefix = strrchr (opt.filename, '/');
-      if (dirprefix)
-        dirprefix++;
-      else
-        dirprefix = opt.filename;
-    }
+      if (filename)
+        {
+          dirprefix = strrchr (filename, '/');
+          if (dirprefix)
+            dirprefix++;
+          else
+            dirprefix = filename;
+        }
+      else if (opt.filename)
+        {
+          dirprefix = strrchr (opt.filename, '/');
+          if (dirprefix)
+            dirprefix++;
+          else
+            dirprefix = opt.filename;
+        }
 
-  if (!dirprefix || !*dirprefix)
-    dirprefix = "GPGARCH";
+      if (!dirprefix || !*dirprefix)
+        dirprefix = "GPGARCH";
 
-  dirname = create_directory (dirprefix);
-  if (!dirname)
-    {
-      err = gpg_error (GPG_ERR_GENERAL);
-      goto leave;
+      dirname = create_directory (dirprefix);
+      if (!dirname)
+        {
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave;
+        }
     }
 
   if (opt.verbose)
@@ -324,11 +353,12 @@ gpgtar_extract (const char *filename)
 
   for (;;)
     {
-      header = gpgtar_read_header (stream);
-      if (!header)
+      err = gpgtar_read_header (stream, &header);
+      if (err || header == NULL)
         goto leave;
 
-      if (extract (stream, dirname, header))
+      err = extract (stream, dirname, header);
+      if (err)
         goto leave;
       xfree (header);
       header = NULL;
@@ -340,5 +370,7 @@ gpgtar_extract (const char *filename)
   xfree (dirname);
   if (stream != es_stdin)
     es_fclose (stream);
-  return;
+  if (stream != cipher_stream)
+    es_fclose (cipher_stream);
+  return err;
 }
index d525d24..cb2ca5d 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "i18n.h"
 #include "gpgtar.h"
+#include "../common/call-gpg.h"
 
 
 \f
@@ -168,10 +169,11 @@ parse_header (const void *record, const char *filename)
 
 \f
 /* Read the next block, assming it is a tar header.  Returns a header
-   object on success or NULL one error.  In case of an error an error
+   object on success in R_HEADER, or an error.  If the stream is
+   consumed, R_HEADER is set to NULL.  In case of an error an error
    message has been printed.  */
-static tar_header_t
-read_header (estream_t stream)
+static gpg_error_t
+read_header (estream_t stream, tar_header_t *r_header)
 {
   gpg_error_t err;
   char record[RECORDSIZE];
@@ -179,7 +181,7 @@ read_header (estream_t stream)
 
   err = read_record (stream, record);
   if (err)
-    return NULL;
+    return err;
 
   for (i=0; i < RECORDSIZE && !record[i]; i++)
     ;
@@ -189,8 +191,8 @@ read_header (estream_t stream)
          end of archive mark.  */
       err = read_record (stream, record);
       if (err)
-        return NULL;
-      
+        return err;
+
       for (i=0; i < RECORDSIZE && !record[i]; i++)
         ;
       if (i != RECORDSIZE)
@@ -199,11 +201,13 @@ read_header (estream_t stream)
       else
         {
           /* End of archive - FIXME: we might want to check for garbage.  */
-          return NULL;
+          *r_header = NULL;
+          return 0;
         }
     }
 
-  return parse_header (record, es_fname_get (stream));
+  *r_header = parse_header (record, es_fname_get (stream));
+  return *r_header ? 0 : gpg_error_from_syserror ();
 }
 
 
@@ -266,12 +270,13 @@ print_header (tar_header_t header, estream_t out)
 \f
 /* List the tarball FILENAME or, if FILENAME is NULL, the tarball read
    from stdin.  */
-void
-gpgtar_list (const char *filename)
+gpg_error_t
+gpgtar_list (const char *filename, int decrypt)
 {
   gpg_error_t err;
   estream_t stream;
-  tar_header_t header;
+  estream_t cipher_stream = NULL;
+  tar_header_t header = NULL;
 
   if (filename)
     {
@@ -283,7 +288,7 @@ gpgtar_list (const char *filename)
         {
           err = gpg_error_from_syserror ();
           log_error ("error opening '%s': %s\n", filename, gpg_strerror (err));
-          return;
+          return err;
         }
     }
   else
@@ -292,14 +297,33 @@ gpgtar_list (const char *filename)
   if (stream == es_stdin)
     es_set_binary (es_stdin);
 
+  if (decrypt)
+    {
+      cipher_stream = stream;
+      stream = es_fopenmem (0, "rwb");
+      if (! stream)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      err = gpg_decrypt_stream (NULL, opt.gpg_program, opt.gpg_arguments,
+                                cipher_stream, stream);
+      if (err)
+        goto leave;
+
+      err = es_fseek (stream, 0, SEEK_SET);
+      if (err)
+        goto leave;
+    }
+
   for (;;)
     {
-      header = read_header (stream);
-      if (!header)
+      err = read_header (stream, &header);
+      if (err || header == NULL)
         goto leave;
-      
+
       print_header (header, es_stdout);
-      
+
       if (skip_data (stream, header))
         goto leave;
       xfree (header);
@@ -311,14 +335,15 @@ gpgtar_list (const char *filename)
   xfree (header);
   if (stream != es_stdin)
     es_fclose (stream);
-  return;
+  if (stream != cipher_stream)
+    es_fclose (cipher_stream);
+  return err;
 }
 
-tar_header_t
-gpgtar_read_header (estream_t stream)
+gpg_error_t
+gpgtar_read_header (estream_t stream, tar_header_t *r_header)
 {
-  /*FIXME: Change to return an error code.  */
-  return read_header (stream);
+  return read_header (stream, r_header);
 }
 
 void
index e9a25fb..a09d2f0 100644 (file)
    gpg.  So here we go.  */
 
 #include <config.h>
+#include <assuan.h>
+#include <ctype.h>
 #include <errno.h>
+#include <npth.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "util.h"
 #include "i18n.h"
 #include "sysutils.h"
+#include "../common/asshelp.h"
 #include "../common/openpgpdefs.h"
 #include "../common/init.h"
+#include "../common/strlist.h"
 
 #include "gpgtar.h"
 
@@ -55,17 +60,26 @@ enum cmd_and_opt_values
     oRecipient = 'r',
     oUser       = 'u',
     oOutput    = 'o',
+    oDirectory  = 'C',
     oQuiet      = 'q',
     oVerbose   = 'v',
     oFilesFrom  = 'T',
     oNoVerbose = 500,
 
     aSignEncrypt,
+    oGpgProgram,
     oSkipCrypto,
     oOpenPGP,
     oCMS,
     oSetFilename,
-    oNull
+    oNull,
+
+    /* Compatibility with gpg-zip.  */
+    oGpgArgs,
+    oTarArgs,
+
+    /* Debugging.  */
+    oDryRun,
   };
 
 
@@ -87,23 +101,38 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oQuiet,        "quiet",  N_("be somewhat more quiet")),
+  ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
   ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")),
+  ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
   ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
+  ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
+  ARGPARSE_s_n (oCMS, "cms", "@"),
+
+  ARGPARSE_group (302, N_("@\nTar options:\n ")),
+
+  ARGPARSE_s_s (oDirectory, "directory",
+                N_("|DIRECTORY|extract files into DIRECTORY")),
   ARGPARSE_s_s (oFilesFrom, "files-from",
                 N_("|FILE|get names to create from FILE")),
   ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
-  ARGPARSE_s_n (oOpenPGP, "openpgp", "@"),
-  ARGPARSE_s_n (oCMS, "cms", "@"),
+
+  ARGPARSE_s_s (oGpgArgs, "gpg-args", "@"),
+  ARGPARSE_s_s (oTarArgs, "tar-args", "@"),
 
   ARGPARSE_end ()
 };
 
 
-\f
-static void tar_and_encrypt (char **inpattern);
-static void decrypt_and_untar (const char *fname);
-static void decrypt_and_list (const char *fname);
+/* The list of commands and options for tar that we understand. */
+static ARGPARSE_OPTS tar_opts[] = {
+  ARGPARSE_s_s (oDirectory, "directory",
+                N_("|DIRECTORY|extract files into DIRECTORY")),
+  ARGPARSE_s_s (oFilesFrom, "files-from",
+                N_("|FILE|get names to create from FILE")),
+  ARGPARSE_s_n (oNull, "null", N_("-T reads null-terminated names")),
 
+  ARGPARSE_end ()
+};
 
 
 \f
@@ -155,59 +184,161 @@ set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
 
   *ret_cmd = cmd;
 }
+\f
+/* Shell-like argument splitting.
 
+   For compatibility with gpg-zip we accept arguments for GnuPG and
+   tar given as a string argument to '--gpg-args' and '--tar-args'.
+   gpg-zip was implemented as a Bourne Shell script, and therefore, we
+   need to split the string the same way the shell would.  */
+static int
+shell_parse_stringlist (const char *str, strlist_t *r_list)
+{
+  strlist_t list = NULL;
+  const char *s = str;
+  char quoted = 0;
+  char arg[1024];
+  char *p = arg;
+#define addchar(c) \
+  do { if (p - arg + 2 < sizeof arg) *p++ = (c); else return 1; } while (0)
+#define addargument()                           \
+  do {                                          \
+    if (p > arg)                                \
+      {                                         \
+        *p = 0;                                 \
+        append_to_strlist (&list, arg);         \
+        p = arg;                                \
+      }                                         \
+  } while (0)
+
+#define unquoted       0
+#define singlequote    '\''
+#define doublequote    '"'
+
+  for (; *s; s++)
+    {
+      switch (quoted)
+        {
+        case unquoted:
+          if (isspace (*s))
+            addargument ();
+          else if (*s == singlequote || *s == doublequote)
+            quoted = *s;
+          else
+            addchar (*s);
+          break;
 
-\f
-/* gpgtar main. */
-int
-main (int argc, char **argv)
+        case singlequote:
+          if (*s == singlequote)
+            quoted = unquoted;
+          else
+            addchar (*s);
+          break;
+
+        case doublequote:
+          assert (s > str || !"cannot be quoted at first char");
+          if (*s == doublequote && *(s - 1) != '\\')
+            quoted = unquoted;
+          else
+            addchar (*s);
+          break;
+
+        default:
+          assert (! "reached");
+        }
+    }
+
+  /* Append the last argument.  */
+  addargument ();
+
+#undef doublequote
+#undef singlequote
+#undef unquoted
+#undef addargument
+#undef addchar
+  *r_list = list;
+  return 0;
+}
+
+
+/* Like shell_parse_stringlist, but returns an argv vector
+   instead of a strlist.  */
+static int
+shell_parse_argv (const char *s, int *r_argc, char ***r_argv)
 {
-  ARGPARSE_ARGS pargs;
-  const char *fname;
-  int no_more_options = 0;
-  enum cmd_and_opt_values cmd = 0;
-  int skip_crypto = 0;
-  const char *files_from = NULL;
-  int null_names = 0;
+  int i;
+  strlist_t list;
 
-  assert (sizeof (struct ustar_raw_header) == 512);
+  if (shell_parse_stringlist (s, &list))
+    return 1;
 
-  gnupg_reopen_std (GPGTAR_NAME);
-  set_strusage (my_strusage);
-  log_set_prefix (GPGTAR_NAME, 1);
+  *r_argc = strlist_length (list);
+  *r_argv = xtrycalloc (*r_argc, sizeof **r_argv);
+  if (*r_argv == NULL)
+    return 1;
 
-  /* Make sure that our subsystems are ready.  */
-  i18n_init();
-  init_common_subsystems (&argc, &argv);
+  for (i = 0; list; i++)
+    (*r_argv)[i] = list->d, list = list->next;
+  return 0;
+}
+\f
+/* Define Assuan hooks for NPTH.  */
 
-  /* Parse the command line. */
-  pargs.argc  = &argc;
-  pargs.argv  = &argv;
-  pargs.flags = ARGPARSE_FLAG_KEEP;
-  while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
+ASSUAN_SYSTEM_NPTH_IMPL;
+
+\f
+/* Global flags.  */
+enum cmd_and_opt_values cmd = 0;
+int skip_crypto = 0;
+const char *files_from = NULL;
+int null_names = 0;
+
+
+/* Command line parsing.  */
+static void
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+  int no_more_options = 0;
+
+  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
     {
-      switch (pargs.r_opt)
+      switch (pargs->r_opt)
         {
-        case oOutput:    opt.outfile = pargs.r.ret_str; break;
-        case oSetFilename: opt.filename = pargs.r.ret_str; break;
+        case oOutput:    opt.outfile = pargs->r.ret_str; break;
+        case oDirectory: opt.directory = pargs->r.ret_str; break;
+        case oSetFilename: opt.filename = pargs->r.ret_str; break;
        case oQuiet:     opt.quiet = 1; break;
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; break;
-        case oFilesFrom: files_from = pargs.r.ret_str; break;
+        case oFilesFrom: files_from = pargs->r.ret_str; break;
         case oNull: null_names = 1; break;
 
        case aList:
         case aDecrypt:
         case aEncrypt:
         case aSign:
-          set_cmd (&cmd, pargs.r_opt);
+          set_cmd (&cmd, pargs->r_opt);
          break;
 
+        case oRecipient:
+          add_to_strlist (&opt.recipients, pargs->r.ret_str);
+          break;
+
+        case oUser:
+          log_info ("note: ignoring option --user\n");
+          opt.user = pargs->r.ret_str;
+          break;
+
         case oSymmetric:
+          log_info ("note: ignoring option --symmetric\n");
           set_cmd (&cmd, aEncrypt);
           opt.symmetric = 1;
           break;
 
+        case oGpgProgram:
+          opt.gpg_program = pargs->r.ret_str;
+          break;
+
         case oSkipCrypto:
           skip_crypto = 1;
           break;
@@ -215,9 +346,83 @@ main (int argc, char **argv)
         case oOpenPGP: /* Dummy option for now.  */ break;
         case oCMS:     /* Dummy option for now.  */ break;
 
-        default: pargs.err = 2; break;
+        case oGpgArgs:;
+          {
+            strlist_t list;
+            if (shell_parse_stringlist (pargs->r.ret_str, &list))
+              log_error ("failed to parse gpg arguments '%s'\n",
+                         pargs->r.ret_str);
+            else
+              {
+                if (opt.gpg_arguments)
+                  strlist_last (opt.gpg_arguments)->next = list;
+                else
+                  opt.gpg_arguments = list;
+              }
+          }
+          break;
+
+        case oTarArgs:;
+          {
+            int tar_argc;
+            char **tar_argv;
+
+            if (shell_parse_argv (pargs->r.ret_str, &tar_argc, &tar_argv))
+              log_error ("failed to parse tar arguments '%s'\n",
+                         pargs->r.ret_str);
+            else
+              {
+                ARGPARSE_ARGS tar_args;
+                tar_args.argc = &tar_argc;
+                tar_args.argv = &tar_argv;
+                tar_args.flags = ARGPARSE_FLAG_ARG0;
+                parse_arguments (&tar_args, tar_opts);
+                if (tar_args.err)
+                  log_error ("unsupported tar arguments '%s'\n",
+                             pargs->r.ret_str);
+                pargs->err = tar_args.err;
+              }
+          }
+          break;
+
+        case oDryRun:
+          opt.dry_run = 1;
+          break;
+
+        default: pargs->err = 2; break;
        }
     }
+}
+
+\f
+/* gpgtar main. */
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  const char *fname;
+  ARGPARSE_ARGS pargs;
+
+  assert (sizeof (struct ustar_raw_header) == 512);
+
+  gnupg_reopen_std (GPGTAR_NAME);
+  set_strusage (my_strusage);
+  log_set_prefix (GPGTAR_NAME, 1);
+
+  /* Make sure that our subsystems are ready.  */
+  i18n_init();
+  init_common_subsystems (&argc, &argv);
+  npth_init ();
+  assuan_set_assuan_log_prefix (log_get_prefix (NULL));
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
+  assuan_sock_init ();
+
+  /* Parse the command line. */
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags = ARGPARSE_FLAG_KEEP;
+  parse_arguments (&pargs, opts);
 
   if ((files_from && !null_names) || (!files_from && null_names))
     log_error ("--files-from and --null may only be used in conjunction\n");
@@ -237,6 +442,10 @@ main (int argc, char **argv)
           log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
     }
 
+  if (opt.verbose > 1)
+    opt.debug_level = 1024;
+  setup_libassuan_logging (&opt.debug_level);
+
   switch (cmd)
     {
     case aList:
@@ -247,10 +456,9 @@ main (int argc, char **argv)
         log_info ("note: ignoring option --set-filename\n");
       if (files_from)
         log_info ("note: ignoring option --files-from\n");
-      if (skip_crypto)
-        gpgtar_list (fname);
-      else
-        decrypt_and_list (fname);
+      err = gpgtar_list (fname, !skip_crypto);
+      if (err && log_get_errorcount (0) == 0)
+        log_error ("listing archive failed: %s\n", gpg_strerror (err));
       break;
 
     case aEncrypt:
@@ -259,10 +467,9 @@ main (int argc, char **argv)
         usage (1);
       if (opt.filename)
         log_info ("note: ignoring option --set-filename\n");
-      if (skip_crypto)
-        gpgtar_create (null_names? NULL :argv);
-      else
-        tar_and_encrypt (null_names? NULL : argv);
+      err = gpgtar_create (null_names? NULL :argv, !skip_crypto);
+      if (err && log_get_errorcount (0) == 0)
+        log_error ("creating archive failed: %s\n", gpg_strerror (err));
       break;
 
     case aDecrypt:
@@ -273,10 +480,9 @@ main (int argc, char **argv)
       if (files_from)
         log_info ("note: ignoring option --files-from\n");
       fname = argc ? *argv : NULL;
-      if (skip_crypto)
-        gpgtar_extract (fname);
-      else
-        decrypt_and_untar (fname);
+      err = gpgtar_extract (fname, !skip_crypto);
+      if (err && log_get_errorcount (0) == 0)
+        log_error ("extracting archive failed: %s\n", gpg_strerror (err));
       break;
 
     default:
@@ -341,7 +547,7 @@ write_record (estream_t stream, const void *record)
 
 
 /* Return true if FP is an unarmored OpenPGP message.  Note that this
-   fucntion reads a few bytes from FP but pushes them back.  */
+   function reads a few bytes from FP but pushes them back.  */
 #if 0
 static int
 openpgp_message_p (estream_t fp)
@@ -378,31 +584,3 @@ openpgp_message_p (estream_t fp)
   return 0;
 }
 #endif
-
-
-
-\f
-static void
-tar_and_encrypt (char **inpattern)
-{
-  (void)inpattern;
-  log_error ("tar_and_encrypt has not yet been implemented\n");
-}
-
-
-\f
-static void
-decrypt_and_untar (const char *fname)
-{
-  (void)fname;
-  log_error ("decrypt_and_untar has not yet been implemented\n");
-}
-
-
-\f
-static void
-decrypt_and_list (const char *fname)
-{
-  (void)fname;
-  log_error ("decrypt_and_list has not yet been implemented\n");
-}
index 08dfcf8..eadbcac 100644 (file)
 #define GPGTAR_H
 
 #include "../common/util.h"
+#include "../common/strlist.h"
 
 /* We keep all global options in the structure OPT.  */
 struct
 {
   int verbose;
+  unsigned int debug_level;
   int quiet;
+  int dry_run;
+  const char *gpg_program;
+  strlist_t gpg_arguments;
   const char *outfile;
+  strlist_t recipients;
+  const char *user;
   int symmetric;
   const char *filename;
+  const char *directory;
 } opt;
 
 
@@ -111,14 +119,14 @@ gpg_error_t read_record (estream_t stream, void *record);
 gpg_error_t write_record (estream_t stream, const void *record);
 
 /*-- gpgtar-create.c --*/
-void gpgtar_create (char **inpattern);
+gpg_error_t gpgtar_create (char **inpattern, int encrypt);
 
 /*-- gpgtar-extract.c --*/
-void gpgtar_extract (const char *filename);
+gpg_error_t gpgtar_extract (const char *filename, int decrypt);
 
 /*-- gpgtar-list.c --*/
-void gpgtar_list (const char *filename);
-tar_header_t gpgtar_read_header (estream_t stream);
+gpg_error_t gpgtar_list (const char *filename, int decrypt);
+gpg_error_t gpgtar_read_header (estream_t stream, tar_header_t *r_header);
 void gpgtar_print_header (tar_header_t header, estream_t out);
 
 
index 285e084..f911bd2 100644 (file)
@@ -514,7 +514,7 @@ rfc822parse_finish (rfc822parse_t msg)
  * part.
  *
  * WHICH gives the mode:
- *  -1 := Take the last occurence
+ *  -1 := Take the last occurrence
  *   n := Take the n-th  one.
  *
  * Returns a newly allocated buffer or NULL on error.  errno is set in
@@ -954,7 +954,7 @@ parse_field (HDR_LINE hdr)
  * Find and parse a header field.
  * WHICH indicates what to do if there are multiple instance of the same
  * field (like "Received"); the following value are defined:
- *  -1 := Take the last occurence
+ *  -1 := Take the last occurrence
  *   0 := Reserved
  *   n := Take the n-th one.
  * Returns a handle for further operations on the parse context of the field
index 3b73cf4..4b90cd2 100644 (file)
@@ -49,7 +49,7 @@
    The possible exit status codes:
 
    0   Success
-   1   Some error occured
+   1   Some error occurred
    2   No valid passphrase was provided
    3   The operation was canceled by the user