Merge branch 'STABLE-BRANCH-2-2' into master
authorWerner Koch <wk@gnupg.org>
Sun, 13 May 2018 11:29:40 +0000 (13:29 +0200)
committerWerner Koch <wk@gnupg.org>
Sun, 13 May 2018 11:29:40 +0000 (13:29 +0200)
--

Resolved Conflicts:
NEWS  - removed
configure.ac - removed

Signed-off-by: Werner Koch <wk@gnupg.org>
22 files changed:
1  2 
agent/command.c
common/exechelp-w32.c
common/miscellaneous.c
configure.ac
dirmngr/crlcache.c
dirmngr/dirmngr.c
dirmngr/http.c
doc/DETAILS
doc/Makefile.am
doc/gpg.texi
g10/card-util.c
g10/filter.h
g10/getkey.c
g10/gpg.c
g10/import.c
g10/keydb.h
g10/keyedit.c
g10/keylist.c
g10/mainproc.c
g10/options.h
g10/packet.h
g10/pkclist.c

diff --combined agent/command.c
@@@ -843,7 -843,7 +843,7 @@@ static const char hlp_genkey[] 
    "\n"
    "  C: GENKEY\n"
    "  S: INQUIRE KEYPARAM\n"
 -  "  C: D (genkey (rsa (nbits  2048)))\n"
 +  "  C: D (genkey (rsa (nbits 3072)))\n"
    "  C: END\n"
    "  S: D (public-key\n"
    "  S: D   (rsa (n 326487324683264) (e 10001)))\n"
@@@ -2825,6 -2825,7 +2825,7 @@@ static const char hlp_getinfo[] 
    "  std_env_names   - List the names of the standard environment.\n"
    "  std_session_env - List the standard session environment.\n"
    "  std_startup_env - List the standard startup environment.\n"
+   "  getenv NAME     - Return value of envvar NAME.\n"
    "  connections     - Return number of active connections.\n"
    "  jent_active     - Returns OK if Libgcrypt's JENT is active.\n"
    "  restricted      - Returns OK if the connection is in restricted mode.\n"
@@@ -2961,6 -2962,23 +2962,23 @@@ cmd_getinfo (assuan_context_t ctx, cha
              }
          }
      }
+   else if (!strncmp (line, "getenv", 6)
+            && (line[6] == ' ' || line[6] == '\t' || !line[6]))
+     {
+       line += 6;
+       while (*line == ' ' || *line == '\t')
+         line++;
+       if (!*line)
+         rc = gpg_error (GPG_ERR_MISSING_VALUE);
+       else
+         {
+           const char *s = getenv (line);
+           if (!s)
+             rc = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
+           else
+             rc = assuan_send_data (ctx, s, strlen (s));
+         }
+     }
    else if (!strcmp (line, "connections"))
      {
        char numbuf[20];
@@@ -3333,7 -3351,7 +3351,7 @@@ start_command_handler (ctrl_t ctrl, gnu
  
    for (;;)
      {
 -      pid_t client_pid;
 +      assuan_peercred_t client_creds;
  
        rc = assuan_accept (ctx);
        if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
            break;
          }
  
 -      client_pid = assuan_get_pid (ctx);
 -      ctrl->server_local->connect_from_self = (client_pid == getpid ());
 -      if (client_pid != ASSUAN_INVALID_PID)
 -        ctrl->client_pid = (unsigned long)client_pid;
 +      rc = assuan_get_peercred (ctx, &client_creds);
 +      if (rc)
 +        {
 +          log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc));
 +          client_creds->pid = assuan_get_pid (ctx);
 +          ctrl->client_uid = -1;
 +        }
 +      ctrl->server_local->connect_from_self =
 +        (client_creds->pid == getpid ());
 +      if (client_creds->pid != ASSUAN_INVALID_PID)
 +        ctrl->client_pid = (unsigned long)client_creds->pid;
        else
          ctrl->client_pid = 0;
 +      ctrl->client_uid = client_creds->uid;
  
        rc = assuan_process (ctx);
        if (rc)
diff --combined common/exechelp-w32.c
@@@ -1,6 -1,6 +1,6 @@@
  /* exechelp-w32.c - Fork and exec helpers for W32.
 - * Copyright (C) 2004, 2007, 2008, 2009,
 - *               2010 Free Software Foundation, Inc.
 + * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
 + * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
   *
   * This file is part of GnuPG.
   *
@@@ -26,7 -26,6 +26,7 @@@
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, see <https://www.gnu.org/licenses/>.
 + * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+)
   */
  
  #include <config.h>
@@@ -556,7 -555,7 +556,7 @@@ gnupg_spawn_process (const char *pgmnam
    memset (&si, 0, sizeof si);
    si.cb = sizeof (si);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
    si.hStdInput  = inpipe[0]  == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
    si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
    si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
diff --combined common/miscellaneous.c
@@@ -45,14 -45,14 +45,14 @@@ my_gcry_logger (void *dummy, int level
    /* Map the log levels.  */
    switch (level)
      {
 -    case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break;
 -    case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break;
 -    case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break;
 -    case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break;
 -    case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break;
 -    case GCRY_LOG_BUG:  level = GPGRT_LOG_BUG; break;
 -    case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break;
 -    default:            level = GPGRT_LOG_ERROR; break;
 +    case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break;
 +    case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break;
 +    case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break;
 +    case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break;
 +    case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break;
 +    case GCRY_LOG_BUG:  level = GPGRT_LOGLVL_BUG; break;
 +    case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break;
 +    default:            level = GPGRT_LOGLVL_ERROR; break;
      }
    log_logv (level, fmt, arg_ptr);
  }
@@@ -401,6 -401,7 +401,7 @@@ is_file_compressed (const char *s, int 
          *ret_rc = gpg_error_from_syserror ();
          return 0;
      }
+     iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
  
      if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) {
          *ret_rc = 0;
diff --combined configure.ac
@@@ -27,8 -27,8 +27,8 @@@ min_automake_version="1.14
  # another commit and push so that the git magic is able to work.
  m4_define([mym4_package],[gnupg])
  m4_define([mym4_major], [2])
 -m4_define([mym4_minor], [2])
 -m4_define([mym4_micro], [8])
 +m4_define([mym4_minor], [3])
 +m4_define([mym4_micro], [0])
  
  # 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
@@@ -51,7 -51,7 +51,7 @@@ AC_INIT([mym4_package],[mym4_version], 
  
  # When changing the SWDB tag please also adjust the hard coded tags in
  # build-aux/speedo.mk and Makefile.am
 -AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg22", [swdb tag for this branch])
 +AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
  
  NEED_GPG_ERROR_VERSION=1.24
  
@@@ -116,8 -116,8 +116,8 @@@ use_tls_library=n
  large_secmem=no
  show_tor_support=no
  
 -
 -GNUPG_BUILD_PROGRAM(gpg, yes)
 +# gpg is a required part and can't be disabled anymore.
 +build_gpg=yes
  GNUPG_BUILD_PROGRAM(gpgsm, yes)
  # The agent is a required part and can't be disabled anymore.
  build_agent=yes
  AC_DEFINE_UNQUOTED(SECMEM_BUFFER_SIZE,$SECMEM_BUFFER_SIZE,
                     [Size of secure memory buffer])
  
 +AC_MSG_CHECKING([calibrated passphrase-stretching (s2k) duration])
 +AC_ARG_WITH(agent-s2k-calibration,
 +              AC_HELP_STRING([--with-agent-s2k-calibration=MSEC],
 +                             [calibrate passphrase stretching (s2k) to MSEC milliseconds]),
 +              agent_s2k_calibration=$withval, agent_s2k_calibration=100)
 +AC_MSG_RESULT($agent_s2k_calibration milliseconds)
 +AC_DEFINE_UNQUOTED(AGENT_S2K_CALIBRATION, $agent_s2k_calibration,
 +                   [Agent s2k calibration time (ms)])
 +
  AC_MSG_CHECKING([whether to enable trust models])
  AC_ARG_ENABLE(trust-models,
                AC_HELP_STRING([--disable-trust-models],
@@@ -557,12 -548,9 +557,12 @@@ AH_BOTTOM(
  # endif
  #endif
  
 -/* Provide the es_ macro for estream.  */
 +/* Enable the es_ macros from gpgrt.  */
  #define GPGRT_ENABLE_ES_MACROS 1
  
 +/* Enable the log_ macros from gpgrt.  */
 +#define GPGRT_ENABLE_LOG_MACROS 1
 +
  /* Tell libgcrypt not to use its own libgpg-error implementation. */
  #define USE_LIBGPG_ERROR 1
  
@@@ -614,7 -602,7 +614,7 @@@ AC_PROG_RANLI
  AC_CHECK_TOOL(AR, ar, :)
  AC_PATH_PROG(PERL,"perl")
  AC_CHECK_TOOL(WINDRES, windres, :)
 -AC_PATH_PROG(YAT2M, "yat2m")
 +AC_PATH_PROG(YAT2M, "yat2m", "./yat2m" )
  AC_ARG_VAR(YAT2M, [tool to convert texi to man pages])
  AM_CONDITIONAL(HAVE_YAT2M, test -n "$ac_cv_path_YAT2M")
  AC_ISC_POSIX
@@@ -665,7 -653,6 +665,6 @@@ case "${host}" i
          have_dosish_system=yes
          have_w32_system=yes
          require_iconv=no
-         use_ldapwrapper=no  # Fixme: Do this only for CE.
          require_pipe_to_unblock_pselect=no
          case "${host}" in
            *-mingw32ce*)
@@@ -976,6 -963,17 +975,17 @@@ els
  *** we need the support of the New Portable Threads Library.
  ***]])
  fi
+ #
+ # Enable debugging of nPth
+ #
+ AC_ARG_ENABLE(npth-debug,
+    AC_HELP_STRING([--enable-npth-debug],
+                   [build with debug version of npth]),
+                   [if test $enableval = yes ; then
+                      AC_DEFINE(NPTH_ENABLE_DEBUG,1,
+                               [Build with debug version of nPth])
+                   fi])
  
  
  #
@@@ -1625,7 -1623,7 +1635,7 @@@ if test "$GCC" = yes; the
            AC_MSG_RESULT($_gcc_wopt)
          fi
          if test x"$_gcc_wopt" = xyes ; then
 -          mycflags="$mycflags -W -Wno-sign-compare"
 +          mycflags="$mycflags -W -Wno-sign-compare -Wno-format-zero-length"
            mycflags="$mycflags -Wno-missing-field-initializers"
          fi
  
@@@ -1700,19 -1698,6 +1710,19 @@@ AC_ARG_ENABLE(optimization
                     fi])
  
  #
 +# log_debug has certain requirements which might hamper portability.
 +# Thus we use an option to enable it.
 +#
 +AC_MSG_CHECKING([whether to enable log_clock])
 +AC_ARG_ENABLE(log_clock,
 +              AC_HELP_STRING([--enable-log-clock],
 +                             [enable log_clock timestamps]),
 +              enable_log_clock=$enableval, enable_log_clock=no)
 +AC_MSG_RESULT($enable_log_clock)
 +if test "$enable_log_clock" = yes ; then
 +  AC_DEFINE(ENABLE_LOG_CLOCK,1,[Defined to use log_clock timestamps])
 +fi
 +
  # Add -Werror to CFLAGS.  This hack can be used to avoid problems with
  # misbehaving autoconf tests in case the user supplied -Werror.
  #
diff --combined dirmngr/crlcache.c
     idea anyway to limit the number of opened cache files. */
  #define MAX_OPEN_DB_FILES 5
  
+ #ifndef O_BINARY
+ # define O_BINARY 0
+ #endif
  
  static const char oidstr_crlNumber[] = "2.5.29.20";
  /* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
@@@ -1139,7 -1142,7 +1142,7 @@@ lock_db_file (crl_cache_t cache, crl_ca
        xfree (fname);
        return NULL;
      }
-   fd = open (fname, O_RDONLY);
+   fd = open (fname, O_RDONLY | O_BINARY);
    if (fd == -1)
      {
        log_error (_("error opening cache file '%s': %s\n"),
@@@ -1346,7 -1349,7 +1349,7 @@@ cache_isvalid (ctrl_t ctrl, const char 
          {
            log_error (_("WARNING: invalid cache record length for S/N "));
            log_printf ("0x");
 -          log_printhex ("", sn, snlen);
 +          log_printhex (sn, snlen, "");
          }
        else if (opt.verbose)
          {
@@@ -2051,7 -2054,7 +2054,7 @@@ crl_cache_insert (ctrl_t ctrl, const ch
        }
    }
  
-   fd_cdb = open (fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+   fd_cdb = open (fname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
    if (fd_cdb == -1)
      {
        err = gpg_error_from_errno (errno);
diff --combined dirmngr/dirmngr.c
@@@ -787,12 -787,12 +787,12 @@@ my_ntbtls_log_handler (void *opaque, in
    (void)opaque;
  
    if (level == -1)
 -    log_logv_with_prefix (GPGRT_LOG_INFO, "ntbtls: ", fmt, argv);
 +    log_logv_prefix (GPGRT_LOGLVL_INFO, "ntbtls: ", fmt, argv);
    else
      {
        char prefix[10+20];
        snprintf (prefix, sizeof prefix, "ntbtls(%d): ", level);
 -      log_logv_with_prefix (GPGRT_LOG_DEBUG, prefix, fmt, argv);
 +      log_logv_prefix (GPGRT_LOGLVL_DEBUG, prefix, fmt, argv);
      }
  }
  #endif
@@@ -1203,14 -1203,6 +1203,14 @@@ main (int argc, char **argv
            current_logfile = xstrdup (logfile);
          }
  
 +      if (debug_wait)
 +        {
 +          log_debug ("waiting for debugger - my pid is %u .....\n",
 +                     (unsigned int)getpid());
 +          gnupg_sleep (debug_wait);
 +          log_debug ("... okay\n");
 +        }
 +
  #ifndef HAVE_W32_SYSTEM
        if (strchr (socket_name, ':'))
          {
@@@ -2243,7 -2235,8 +2243,8 @@@ handle_connections (assuan_fd_t listen_
        npth_timersub (&abstime, &curtime, &timeout);
  
  #ifndef HAVE_W32_SYSTEM
-       ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
+       ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
+                           npth_sigev_sigmask());
        saved_errno = errno;
  
        while (npth_sigev_get_pending(&signo))
diff --combined dirmngr/http.c
@@@ -318,6 -318,9 +318,9 @@@ static gpg_error_t (*tls_callback) (htt
  /* The list of files with trusted CA certificates.  */
  static strlist_t tls_ca_certlist;
  
+ /* The list of files with extra trusted CA certificates.  */
+ static strlist_t cfg_ca_certlist;
  /* The global callback for net activity.  */
  static void (*netactivity_cb)(void);
  
@@@ -596,6 -599,35 +599,35 @@@ http_register_tls_ca (const char *fname
  }
  
  
+ /* Register a CA certificate for future use.  The certificate is
+  * expected to be in FNAME.  PEM format is assume if FNAME has a
+  * suffix of ".pem".  If FNAME is NULL the list of CA files is
+  * removed.  This is a variant of http_register_tls_ca which puts the
+  * certificate into a separate list enabled using HTTP_FLAG_TRUST_CFG.  */
+ void
+ http_register_cfg_ca (const char *fname)
+ {
+   strlist_t sl;
+   if (!fname)
+     {
+       free_strlist (cfg_ca_certlist);
+       cfg_ca_certlist = NULL;
+     }
+   else
+     {
+       /* Warn if we can't access right now, but register it anyway in
+          case it becomes accessible later */
+       if (access (fname, F_OK))
+         log_info (_("can't access '%s': %s\n"), fname,
+                   gpg_strerror (gpg_error_from_syserror()));
+       sl = add_to_strlist (&cfg_ca_certlist, fname);
+       if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
+         sl->flags = 1;
+     }
+ }
  /* Register a callback which is called every time the HTTP mode has
   * made a successful connection to some server.  */
  void
@@@ -680,6 -712,7 +712,7 @@@ http_session_release (http_session_t se
   * Valid values for FLAGS are:
   *   HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca
   *   HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system
+  *   HTTP_FLAG_TRUST_CFG - Also use CAs set with http_register_cfg_ca
   *   HTTP_FLAG_NO_CRL    - Do not consult CRLs for https.
   */
  gpg_error_t
@@@ -793,6 -826,21 +826,21 @@@ http_session_new (http_session_t *r_ses
  #endif /* gnutls >= 3.0.20 */
        }
  
+     /* Add other configured certificates to the session.  */
+     if ((flags & HTTP_FLAG_TRUST_CFG))
+       {
+         for (sl = cfg_ca_certlist; sl; sl = sl->next)
+           {
+             rc = gnutls_certificate_set_x509_trust_file
+               (sess->certcred, sl->d,
+                (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
+             if (rc < 0)
+               log_info ("setting extra CA from file '%s' failed: %s\n",
+                         sl->d, gnutls_strerror (rc));
+           }
+       }
      rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
      if (rc < 0)
        {
@@@ -1053,7 -1101,7 +1101,7 @@@ http_start_data (http_t hd
    if (!hd->in_data)
      {
        if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
 -        log_debug_with_string ("\r\n", "http.c:request-header:");
 +        log_debug_string ("\r\n", "http.c:request-header:");
        es_fputs ("\r\n", hd->fp_write);
        es_fflush (hd->fp_write);
        hd->in_data = 1;
@@@ -1688,9 -1736,19 +1736,19 @@@ send_request (http_t hd, const char *ht
  #ifdef USE_TLS
    if (hd->uri->use_tls && !hd->session->tls_session)
      {
-       log_error ("TLS requested but no GNUTLS context available\n");
+       log_error ("TLS requested but no TLS context available\n");
        return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
      }
+   if (opt_debug)
+     log_debug ("Using TLS library: %s %s\n",
+ # if HTTP_USE_NTBTLS
+                "NTBTLS", ntbtls_check_version (NULL)
+ # elif HTTP_USE_GNUTLS
+                "GNUTLS", gnutls_check_version (NULL)
+ # else
+                "?", "?"
+ # endif /*HTTP_USE_*TLS*/
+                );
  #endif /*USE_TLS*/
  
    if ((hd->flags & HTTP_FLAG_FORCE_TOR))
          return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
  
        if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
 -        log_debug_with_string (request, "http.c:request:");
 +        log_debug_string (request, "http.c:request:");
  
        cookie = xtrycalloc (1, sizeof *cookie);
        if (! cookie)
      }
  
    if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
 -    log_debug_with_string (request, "http.c:request:");
 +    log_debug_string (request, "http.c:request:");
  
    /* First setup estream so that we can write even the first line
       using estream.  This is also required for the sake of gnutls. */
        for (;headers; headers=headers->next)
          {
            if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
 -            log_debug_with_string (headers->d, "http.c:request-header:");
 +            log_debug_string (headers->d, "http.c:request-header:");
            if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
                || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
              {
@@@ -2446,7 -2504,7 +2504,7 @@@ parse_response (http_t hd
        return GPG_ERR_EOF;
  
        if (opt_debug || (hd->flags & HTTP_FLAG_LOG_RESP))
 -        log_debug_with_string (line, "http.c:response:\n");
 +        log_debug_string (line, "http.c:response:\n");
      }
    while (!*line);
  
diff --combined doc/DETAILS
@@@ -105,6 -105,19 +105,19 @@@ described here
      certificate (i.e. for the trust anchor) and an 'f' for all other
      valid certificates.
  
+     In "sig" records, this field may have one of these values as first
+     character:
+     - ! :: Signature is good.
+     - - :: Signature is bad.
+     - ? :: No public key to verify signature or public key is not usable.
+     - % :: Other error verifying a signature
+     More values may be added later.  The field may also be empty if
+     gpg has been invoked in a non-checking mode (--list-sigs) or in a
+     fast checking mode.  Since 2.2.7 '?' will also be printed by the
+     command --list-sigs if the key is not in the local keyring.
  *** Field 3 - Key length
  
      The length of key in bits.
      gpg's --edit-key menu does.
  
      For "sig" records, this is the fingerprint of the key that issued
-     the signature.  Note that this is only filled in if the signature
+     the signature.  Note that this may only be filled if the signature
      verified correctly.  Note also that for various technical reasons,
      this fingerprint is only available if --no-sig-cache is used.
+     Since 2.2.7 this field will also be set if the key is missing but
+     the signature carries an issuer fingerprint as meta data.
  
  *** Field 14 - Flag field
  
  
  *** Field 18 - Compliance flags
  
 -    Space separated list of asserted compliance modes for this key.
 +    Space separated list of asserted compliance modes and
 +    screening result for this key.
  
      Valid values are:
  
      - 8  :: The key is compliant with RFC4880bis
      - 23 :: The key is compliant with compliance mode "de-vs".
 +    - 6001 :: Screening hit on the ROCA vulnerability.
  
  *** Field 19 - Last update
  
@@@ -437,14 -450,17 +452,17 @@@ pkd:0:1024:B665B1435F4C2 .... FF26ABB
      available.  This is the case with CMS and might eventually also be
      available for OpenPGP.
  
- *** ERRSIG  <keyid>  <pkalgo> <hashalgo> <sig_class> <time> <rc>
+ *** ERRSIG  <keyid>  <pkalgo> <hashalgo> <sig_class> <time> <rc> <fpr>
      It was not possible to check the signature.  This may be caused by
      a missing public key or an unsupported algorithm.  A RC of 4
      indicates unknown algorithm, a 9 indicates a missing public
      key. The other fields give more information about this signature.
      sig_class is a 2 byte hex-value.  The fingerprint may be used
-     instead of the keyid if it is available.  This is the case with
-     gpgsm and might eventually also be available for OpenPGP.
+     instead of the long_keyid_or_fpr if it is available.  This is the
+     case with gpgsm and might eventually also be available for
+     OpenPGP.  The ERRSIG line has FPR filed which is only available
+     since 2.2.7; that FPR may either be missing or - if the signature
+     has no fingerprint as meta data.
  
      Note, that TIME may either be the number of seconds since Epoch or
      an ISO 8601 string.  The latter can be detected by the presence of
      actual key used for descryption.  <fpr2> is the fingerprint of the
      primary key.  <otrust> is the letter with the ownertrust; this is
      in general a 'u' which stands for ultimately trusted.
 -*** DECRYPTION_INFO <mdc_method> <sym_algo>
 +*** DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>]
      Print information about the symmetric encryption algorithm and the
      MDC method.  This will be emitted even if the decryption fails.
 +    For an AEAD algorithm AEAD_ALGO is not 0.
  
  *** DECRYPTION_FAILED
      The symmetric decryption failed - one reason could be a wrong
      --override-session-key.  It is not an indication that the
      decryption will or has succeeded.
  
 -*** BEGIN_ENCRYPTION  <mdc_method> <sym_algo>
 +*** BEGIN_ENCRYPTION  <mdc_method> <sym_algo> [<aead_algo>]
      Mark the start of the actual encryption process.
 +    MDC_METHOD shall be 0 if an AEAD_ALGO is not 0.  Users should
 +    however ignore MDC_METHOD if AEAD_ALGO is not 0.
  
  *** END_ENCRYPTION
      Mark the end of the actual encryption process.
      The used key has been revoked by its owner.  No arguments yet.
  
  *** NO_PUBKEY  <long keyid>
-     The public key is not available
+     The public key is not available.  Note the arg should in general
+     not be used because it is better to take it from the ERRSIG
+     status line which is printed right before this one.
  
  *** NO_SECKEY  <long keyid>
      The secret key is not available
diff --combined doc/Makefile.am
@@@ -22,7 -22,7 +22,7 @@@ AM_CPPFLAGS 
  include $(top_srcdir)/am/cmacros.am
  
  examples = examples/README examples/scd-event examples/trustlist.txt  \
 -         examples/vsnfd.prf examples/debug.prf                        \
 +         examples/vsnfd.prf examples/debug.prf examples/qualified.txt \
           examples/systemd-user/README                                 \
           examples/systemd-user/dirmngr.service                        \
           examples/systemd-user/dirmngr.socket                         \
@@@ -43,13 -43,14 +43,14 @@@ helpfiles = help.txt help.be.txt help.c
  
  profiles =
  
 -EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem qualified.txt \
 +EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \
             gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
             gnupg-module-overview.png gnupg-module-overview.pdf \
               gnupg-card-architecture.png gnupg-card-architecture.pdf \
               FAQ gnupg7.texi mkdefsinc.c defsincdate \
               opt-homedir.texi see-also-note.texi specify-user-id.texi \
-            gpgv.texi yat2m.c ChangeLog-2011 whats-new-in-2.1.txt
+            gpgv.texi yat2m.c ChangeLog-2011 whats-new-in-2.1.txt \
+              trust-values.texi
  
  BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
                  gnupg-card-architecture.png gnupg-card-architecture.pdf \
@@@ -112,8 -113,16 +113,8 @@@ DISTCLEANFILES = gnupg.tmp gnupg.ops ya
                   gnupg-module-overview.eps \
                 $(myman_pages) gnupg.7
  
 -if HAVE_YAT2M
 -YAT2M_CMD = $(YAT2M)
 -YAT2M_DEP = $(YAT2M)
 -else
 -YAT2M_CMD = ./yat2m
 -YAT2M_DEP = yat2m
 -
  yat2m: yat2m.c
        $(CC_FOR_BUILD) -o $@ $(srcdir)/yat2m.c
 -endif
  
  mkdefsinc: mkdefsinc.c Makefile ../config.h
        $(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \
@@@ -146,12 -155,12 +147,12 @@@ yat2m-stamp: $(myman_sources) defs.in
        @touch yat2m-stamp.tmp
        incd="`test -f defsincdate || echo '$(srcdir)/'`defsincdate"; \
        for file in $(myman_sources) ; do \
 -              $(YAT2M_CMD) $(YAT2M_OPTIONS) --store \
 +              $(YAT2M) $(YAT2M_OPTIONS) --store \
                    --date "`cat $$incd 2>/dev/null`" \
                  `test -f '$$file' || echo '$(srcdir)/'`$$file ; done
        @mv -f yat2m-stamp.tmp $@
  
 -yat2m-stamp: $(YAT2M_DEP)
 +yat2m-stamp: $(YAT2M)
  
  $(myman_pages) gnupg.7 : yat2m-stamp defs.inc
        @if test -f $@; then :; else \
diff --combined doc/gpg.texi
@@@ -214,7 -214,10 +214,10 @@@ symmetric cipher used is @value{GPGSYME
  @option{--encrypt} (for a message that may be decrypted via a secret key
  or a passphrase), or @option{--sign} and @option{--encrypt} together
  (for a signed message that may be decrypted via a secret key or a
- passphrase).
+ passphrase).  @command{@gpgname} caches the passphrase used for
+ symmetric encryption so that a decrypt operation may not require that
+ the user needs to enter the passphrase.  The option
+ @option{--no-symkey-cache} can be used to disable this feature.
  
  @item --store
  @opindex store
@@@ -1037,38 -1040,13 +1040,13 @@@ signing
  
  @c man:.RS
  The listing shows you the key with its secondary keys and all user
- ids.  The primary user id is indicated by a dot, and selected keys or
- user ids are indicated by an asterisk.  The trust
- value is displayed with the primary key: the first is the assigned owner
- trust and the second is the calculated trust value. Letters are used for
- the values:
+ IDs.  The primary user ID is indicated by a dot, and selected keys or
+ user IDs are indicated by an asterisk.  The trust
+ value is displayed with the primary key: "trust" is the assigned owner
+ trust and "validity" is the calculated validity of the key.  Validity
+ values are also displayed for all user IDs.
+ For possible values of trust, @pxref{trust-values}.
  @c man:.RE
- @table @asis
-   @item -
-   No ownertrust assigned / not yet calculated.
-   @item e
-   Trust
-   calculation has failed; probably due to an expired key.
-   @item q
-   Not enough information for calculation.
-   @item n
-   Never trust this key.
-   @item m
-   Marginally trusted.
-   @item f
-   Fully trusted.
-   @item u
-   Ultimately trusted.
- @end table
  @c ******** End Edit-key Options **********
  
  @item --sign-key @var{name}
@@@ -2268,16 -2246,6 +2246,16 @@@ works properly with such messages, ther
  maximum file size that will be generated before processing is forced to
  stop by the OS limits. Defaults to 0, which means "no limit".
  
 +@item --chunk-size @var{n}
 +@opindex chunk-size
 +The AEAD encryption mode encrypts the data in chunks so that a
 +receiving side can check for transmission errors or tampering at the
 +end of each chunk and does not need to delay this until all data has
 +been received.  The used chunk size is 2^@var{n} byte.  The lowest
 +allowed value for @var{n} is 6 (64 byte) and the largest is 62 (4
 +EiB). The default value for @var{n} is 30 which creates chunks not
 +larger than 1 GiB.
 +
  @item --input-size-hint @var{n}
  @opindex input-size-hint
  This option can be used to tell GPG the size of the input data in
@@@ -2615,16 -2583,6 +2593,16 @@@ is the default
  @itemx --no-force-v4-certs
  These options are obsolete and have no effect since GnuPG 2.1.
  
 +@item --force-aead
 +@opindex force-aead
 +Force the use of AEAD encryption over MDC encryption.  AEAD is a
 +modern and faster way to do authenticated encrytion than the old MDC
 +method.  See also options @option{--aead-algo} and
 +@option{--chunk-size}.
 +
 +This option requires the use of option @option{--rfc4880bis} to
 +declare that a not yet standardized feature is used.
 +
  @item --force-mdc
  @opindex force-mdc
  Force the use of encryption with a modification detection code. This
@@@ -2656,16 -2614,6 +2634,16 @@@ preferences, as GPG will only select a
  all recipients.  The most highly ranked cipher in this list is also
  used for the @option{--symmetric} encryption command.
  
 +@item --personal-aead-preferences @var{string}
 +@opindex personal-aead-preferences
 +Set the list of personal AEAD preferences to @var{string}.  Use
 +@command{@gpgname --version} to get a list of available algorithms,
 +and use @code{none} to set no preference at all.  This allows the user
 +to safely override the algorithm chosen by the recipient key
 +preferences, as GPG will only select an algorithm that is usable by
 +all recipients.  The most highly ranked cipher in this list is also
 +used for the @option{--symmetric} encryption command.
 +
  @item --personal-digest-preferences @var{string}
  @opindex personal-digest-preferences
  Set the list of personal digest preferences to @var{string}.  Use
@@@ -2872,12 -2820,6 +2850,12 @@@ Set all useful debugging flags
  Set stdout into line buffered mode.  This option is only honored when
  given on the command line.
  
 +@item --debug-set-iobuf-size @var{n}
 +@opindex debug-iolbf
 +Change the buffer size of the IOBUFs to @var{n} kilobyte.  Using 0
 +prints the current size.  Note well: This is a maintainer only option
 +and may thus be changed or removed at any time without notice.
 +
  @item --faked-system-time @var{epoch}
  @opindex faked-system-time
  This option is only useful for testing; it sets the system time back or
@@@ -3030,28 -2972,17 +3008,28 @@@ Use @var{name} as cipher algorithm. Run
  command @option{--version} yields a list of supported algorithms. If
  this is not used the cipher algorithm is selected from the preferences
  stored with the key. In general, you do not want to use this option as
 -it allows you to violate the OpenPGP standard.
 +it allows you to violate the OpenPGP standard.  The option
  @option{--personal-cipher-preferences} is the safe way to accomplish the
  same thing.
  
 +@item --aead-algo @var{name}
 +@opindex aead-algo
 +Specify that the AEAD algorithm @var{name} is to be used.  This is
 +useful for symmetric encryption where no key preference are available
 +to select the AEAD algorithm.  Runing @command{@gpgname} with option
 +@option{--version} shows the available AEAD algorithms.  In general,
 +you do not want to use this option as it allows you to violate the
 +OpenPGP standard.  The option @option{--personal-aead-preferences} is
 +the safe way to accomplish the same thing.
 +
  @item --digest-algo @var{name}
  @opindex digest-algo
  Use @var{name} as the message digest algorithm. Running the program
 -with the command @option{--version} yields a list of supported algorithms. In
 -general, you do not want to use this option as it allows you to
 -violate the OpenPGP standard. @option{--personal-digest-preferences} is the
 -safe way to accomplish the same thing.
 +with the command @option{--version} yields a list of supported
 +algorithms. In general, you do not want to use this option as it
 +allows you to violate the OpenPGP standard.  The option
 +@option{--personal-digest-preferences} is the safe way to accomplish
 +the same thing.
  
  @item --compress-algo @var{name}
  @opindex compress-algo
@@@ -3073,9 -3004,8 +3051,9 @@@ significant in low memory situations. N
  versions) only supports ZIP compression. Using any algorithm other
  than ZIP or "none" will make the message unreadable with PGP. In
  general, you do not want to use this option as it allows you to
 -violate the OpenPGP standard. @option{--personal-compress-preferences} is the
 -safe way to accomplish the same thing.
 +violate the OpenPGP standard.  The option
 +@option{--personal-compress-preferences} is the safe way to accomplish
 +the same thing.
  
  @item --cert-digest-algo @var{name}
  @opindex cert-digest-algo
    Pinentry the user is not prompted again if he enters a bad password.
  @end table
  
+ @item --no-symkey-cache
+ @opindex no-symkey-cache
+ Disable the passphrase cache used for symmetrical en- and decryption.
+ This cache is based on the message specific salt value
+ (cf. @option{--s2k-mode}).
  @item --request-origin @var{origin}
  @opindex request-origin
  Tell gpg to assume that the operation ultimately originated at
@@@ -3302,8 -3238,14 +3286,14 @@@ print the public key data
  Same as @option{--list-keys}, but the signatures are listed too.  This
  command has the same effect as using @option{--list-keys} with
  @option{--with-sig-list}.  Note that in contrast to
- @option{--check-signatures} the key signatures are not verified.
+ @option{--check-signatures} the key signatures are not verified.  This
+ command can be used to create a list of signing keys missing in the
+ lcoal keyring; for example:
  
+ @example
+       gpg --list-sigs --with-colons USERID | \
+         awk -F: '$1=="sig" && $2=="?" @{if($13)@{print $13@}else@{print $5@}@}'
+ @end example
  
  @item --fast-list-mode
  @opindex fast-list-mode
@@@ -3831,6 -3773,10 +3821,10 @@@ which is equivalent t
  imports only the user ids of a key containing the strings "Alfa"
  or "Alpha" but not the string "test".
  
+ @mansect trust values
+ @ifset isman
+ @include trust-values.texi
+ @end ifset
  
  @mansect return value
  @chapheading RETURN VALUE
diff --combined g10/card-util.c
@@@ -553,9 -553,9 +553,9 @@@ current_card_status (ctrl_t ctrl, estre
  
        print_isoname (fp, "Name of cardholder: ", "name", info.disp_name);
        print_name (fp, "Language prefs ...: ", info.disp_lang);
 -      tty_fprintf (fp,    "Sex ..............: %s\n",
 -                   info.disp_sex == 1? _("male"):
 -                   info.disp_sex == 2? _("female") : _("unspecified"));
 +      tty_fprintf (fp, "Salutation .......: %s\n",
 +                   info.disp_sex == 1? _("Mr."):
 +                   info.disp_sex == 2? _("Mrs.") : "");
        print_name (fp, "URL of public key : ", info.pubkey_url);
        print_name (fp, "Login data .......: ", info.login_data);
        if (info.private_do[0])
          {
            tty_fprintf (fp, "      created ....: %s\n",
                         isotimestamp (info.fpr3time));
-           print_keygrip (fp, info.grp2);
+           print_keygrip (fp, info.grp3);
          }
        tty_fprintf (fp, "General key info..: ");
  
@@@ -1119,7 -1119,7 +1119,7 @@@ change_sex (void
    int rc;
  
    data = cpr_get ("cardedit.change_sex",
 -                  _("Sex ((M)ale, (F)emale or space): "));
 +                  _("Salutation (M = Mr., F = Mrs., or space): "));
    if (!data)
      return -1;
    trim_spaces (data);
  
    rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL );
    if (rc)
 -    log_error ("error setting sex: %s\n", gpg_strerror (rc));
 +    log_error ("error setting salutation: %s\n", gpg_strerror (rc));
    xfree (data);
    write_sc_op_status (rc);
    return rc;
@@@ -1153,8 -1153,7 +1153,8 @@@ change_cafpr (int fprno
    char *data;
    const char *s;
    int i, c, rc;
 -  unsigned char fpr[20];
 +  unsigned char fpr[MAX_FINGERPRINT_LEN];
 +  int fprlen;
  
    data = cpr_get ("cardedit.change_cafpr", _("CA fingerprint: "));
    if (!data)
    trim_spaces (data);
    cpr_kill_prompt ();
  
 -  for (i=0, s=data; i < 20 && *s; )
 +  for (i=0, s=data; i < MAX_FINGERPRINT_LEN && *s; )
      {
        while (spacep(s))
          s++;
        fpr[i++] = c;
        s += 2;
      }
 +  fprlen = i;
    xfree (data);
 -  if (i != 20 || *s)
 +  if ((fprlen != 20 && fprlen != 32) || *s)
      {
        tty_printf (_("Error: invalid formatted fingerprint.\n"));
        return -1;
  
    rc = agent_scd_setattr (fprno==1?"CA-FPR-1":
                            fprno==2?"CA-FPR-2":
 -                          fprno==3?"CA-FPR-3":"x", fpr, 20, NULL );
 +                          fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL );
    if (rc)
      log_error ("error setting cafpr: %s\n", gpg_strerror (rc));
    write_sc_op_status (rc);
@@@ -1348,11 -1346,12 +1348,11 @@@ show_keysize_warning (void
      return;
    shown = 1;
    tty_printf
 -    (_("Note: There is no guarantee that the card "
 -       "supports the requested size.\n"
 -       "      If the key generation does not succeed, "
 -       "please check the\n"
 -       "      documentation of your card to see what "
 -       "sizes are allowed.\n"));
 +    (_("Note: There is no guarantee that the card supports the requested\n"
 +       "      key type or size.  If the key generation does not succeed,\n"
 +       "      please check the documentation of your card to see which\n"
 +       "      key types and sizes are supported.\n")
 +     );
  }
  
  
@@@ -2135,8 -2134,7 +2135,8 @@@ static struc
      { "fetch"   , cmdFETCH , 0, N_("fetch the key specified in the card URL")},
      { "login"   , cmdLOGIN , 1, N_("change the login name")},
      { "lang"    , cmdLANG  , 1, N_("change the language preferences")},
 -    { "sex"     , cmdSEX   , 1, N_("change card holder's sex")},
 +    { "salutation",cmdSEX  , 1, N_("change card holder's salutation")},
 +    { "sex"       ,cmdSEX  , 1, NULL },  /* Backward compatibility.  */
      { "cafpr"   , cmdCAFPR , 1, N_("change a CA fingerprint")},
      { "forcesig", cmdFORCESIG, 1, N_("toggle the signature force PIN flag")},
      { "generate", cmdGENERATE, 1, N_("generate new keys")},
diff --combined g10/filter.h
@@@ -88,52 -88,15 +88,52 @@@ struct compress_filter_context_s 
  typedef struct compress_filter_context_s compress_filter_context_t;
  
  
 -typedef struct {
 -    DEK *dek;
 -    u32 datalen;
 -    gcry_cipher_hd_t cipher_hd;
 -    unsigned int wrote_header : 1;
 -    unsigned int short_blklen_warn : 1;
 -    unsigned long short_blklen_count;
 -    gcry_md_hd_t mdc_hash;
 -    byte enchash[20];
 +typedef struct
 +{
 +  /* Object with the key and algo */
 +  DEK *dek;
 +
 +  /* Length of the data to encrypt if known - 32 bit because OpenPGP
 +   * requires partial encoding for a larger data size.  */
 +  u32 datalen;
 +
 +  /* The current cipher handle.  */
 +  gcry_cipher_hd_t cipher_hd;
 +
 +  /* Various processing flags.  */
 +  unsigned int wrote_header : 1;
 +  unsigned int short_blklen_warn : 1;
 +  unsigned long short_blklen_count;
 +
 +  /* The encoded chunk byte for AEAD.  */
 +  byte chunkbyte;
 +
 +  /* The decoded CHUNKBYTE.  */
 +  uint64_t chunksize;
 +
 +  /* The chunk index for AEAD.  */
 +  uint64_t chunkindex;
 +
 +  /* The number of bytes in the current chunk.  */
 +  uint64_t chunklen;
 +
 +  /* The total count of encrypted plaintext octets.  Note that we
 +   * don't care about encrypting more than 16 Exabyte. */
 +  uint64_t total;
 +
 +  /* The hash context and a buffer used for MDC.  */
 +  gcry_md_hd_t mdc_hash;
 +  byte enchash[20];
 +
 +  /* The start IV for AEAD encryption.   */
 +  byte startiv[16];
 +
 +  /* Using a large buffer for encryption makes processing easier and
 +   * also makes sure the data is well aligned.  */
 +  char *buffer;
 +  size_t bufsize;  /* Allocated length.  */
 +  size_t buflen;   /* Used length.       */
 +
  } cipher_filter_context_t;
  
  
@@@ -177,17 -140,14 +177,18 @@@ void        unarmor_pump_release (Unarm
  int         unarmor_pump (UnarmorPump x, int c);
  
  /*-- compress.c --*/
- void push_compress_filter(iobuf_t out,compress_filter_context_t *zfx,int algo);
- void push_compress_filter2(iobuf_t out,compress_filter_context_t *zfx,
-                          int algo,int rel);
+ gpg_error_t push_compress_filter (iobuf_t out, compress_filter_context_t *zfx,
+                                   int algo);
+ gpg_error_t push_compress_filter2 (iobuf_t out,compress_filter_context_t *zfx,
+                                    int algo, int rel);
  
  /*-- cipher.c --*/
 -int cipher_filter( void *opaque, int control,
 -                 iobuf_t chain, byte *buf, size_t *ret_len);
 +int cipher_filter_cfb (void *opaque, int control,
 +                       iobuf_t chain, byte *buf, size_t *ret_len);
 +
 +/*-- cipher-aead.c --*/
 +int cipher_filter_aead (void *opaque, int control,
 +                        iobuf_t chain, byte *buf, size_t *ret_len);
  
  /*-- textfilter.c --*/
  int text_filter( void *opaque, int control,
diff --combined g10/getkey.c
@@@ -2445,8 -2445,8 +2445,8 @@@ fixup_uidnode (KBNODE uidnode, KBNODE s
  {
    PKT_user_id *uid = uidnode->pkt->pkt.user_id;
    PKT_signature *sig = signode->pkt->pkt.signature;
 -  const byte *p, *sym, *hash, *zip;
 -  size_t n, nsym, nhash, nzip;
 +  const byte *p, *sym, *aead, *hash, *zip;
 +  size_t n, nsym, naead, nhash, nzip;
  
    sig->flags.chosen_selfsig = 1;/* We chose this one. */
    uid->created = 0;           /* Not created == invalid. */
    p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
    sym = p;
    nsym = p ? n : 0;
 +  p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n);
 +  aead = p;
 +  naead = p ? n : 0;
    p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
    hash = p;
    nhash = p ? n : 0;
    nzip = p ? n : 0;
    if (uid->prefs)
      xfree (uid->prefs);
 -  n = nsym + nhash + nzip;
 +  n = nsym + naead + nhash + nzip;
    if (!n)
      uid->prefs = NULL;
    else
          uid->prefs[n].type = PREFTYPE_SYM;
          uid->prefs[n].value = *sym++;
        }
 +      for (; naead; naead--, n++)
 +      {
 +        uid->prefs[n].type = PREFTYPE_AEAD;
 +        uid->prefs[n].value = *aead++;
 +      }
        for (; nhash; nhash--, n++)
        {
          uid->prefs[n].type = PREFTYPE_HASH;
    if (p && n && (p[0] & 0x01))
      uid->flags.mdc = 1;
  
 +  /* See whether we have the AEAD feature.  */
 +  uid->flags.aead = 0;
 +  p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
 +  if (p && n && (p[0] & 0x01))
 +    uid->flags.aead = 1;
 +
    /* And the keyserver modify flag.  */
    uid->flags.ks_modify = 1;
    p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
@@@ -3373,7 -3359,6 +3373,7 @@@ merge_selfsigs (ctrl_t ctrl, kbnode_t k
    PKT_public_key *main_pk;
    prefitem_t *prefs;
    unsigned int mdc_feature;
 +  unsigned int aead_feature;
  
    if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
      {
     * all preferences.
     * Do a similar thing for the MDC feature flag.  */
    prefs = NULL;
 -  mdc_feature = 0;
 +  mdc_feature = aead_feature = 0;
    for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
      {
        if (k->pkt->pkttype == PKT_USER_ID
        {
          prefs = k->pkt->pkt.user_id->prefs;
          mdc_feature = k->pkt->pkt.user_id->flags.mdc;
 +        aead_feature = k->pkt->pkt.user_id->flags.aead;
          break;
        }
      }
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
          pk->flags.mdc = mdc_feature;
 +        pk->flags.aead = aead_feature;
        }
      }
  }
@@@ -4136,15 -4119,20 +4136,20 @@@ get_seckey_default_or_card (ctrl_t ctrl
   *********************************************/
  
  /* Return a string with a printable representation of the user_id.
-  * this string must be freed by xfree.   */
+  * this string must be freed by xfree.  If R_NOUID is not NULL it is
+  * set to true if a user id was not found; otherwise to false.  */
  static char *
- get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len)
+ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
+                     int *r_nouid)
  {
    user_id_db_t r;
    keyid_list_t a;
    int pass = 0;
    char *p;
  
+   if (r_nouid)
+     *r_nouid = 0;
    /* Try it two times; second pass reads from the database.  */
    do
      {
    else
      p = xasprintf ("%s [?]", keystr (keyid));
  
+   if (r_nouid)
+     *r_nouid = 1;
    if (r_len)
      *r_len = strlen (p);
    return p;
  char *
  get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
  {
-   char *p = get_user_id_string (ctrl, keyid, 0, NULL);
+   char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL);
    char *p2 = utf8_to_native (p, strlen (p), 0);
    xfree (p);
    return p2;
  char *
  get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
  {
-   return get_user_id_string (ctrl, keyid, 1, NULL);
+   return get_user_id_string (ctrl, keyid, 1, NULL, NULL);
  }
  
  
  /* Please try to use get_user_byfpr instead of this one.  */
  char *
- get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn)
+ get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid)
  {
-   return get_user_id_string (ctrl, keyid, 2, rn);
+   return get_user_id_string (ctrl, keyid, 2, rn, r_nouid);
  }
  
  
@@@ -4227,7 -4217,7 +4234,7 @@@ char 
  get_user_id_native (ctrl_t ctrl, u32 *keyid)
  {
    size_t rn;
-   char *p = get_user_id (ctrl, keyid, &rn);
+   char *p = get_user_id (ctrl, keyid, &rn, NULL);
    char *p2 = utf8_to_native (p, rn, 0);
    xfree (p);
    return p2;
diff --combined g10/gpg.c
+++ b/g10/gpg.c
@@@ -105,7 -105,6 +105,7 @@@ enum cmd_and_opt_value
      oBatch      = 500,
      oMaxOutput,
      oInputSizeHint,
 +    oChunkSize,
      oSigNotation,
      oCertNotation,
      oShowNotation,
      oWithSubkeyFingerprint,
      oWithICAOSpelling,
      oWithKeygrip,
 +    oWithKeyScreening,
      oWithSecret,
      oWithWKDHash,
      oWithColons,
      oDebugLevel,
      oDebugAll,
      oDebugIOLBF,
 +    oDebugSetIobufSize,
      oStatusFD,
      oStatusFile,
      oAttributeFD,
      oRFC2440Text,
      oNoRFC2440Text,
      oCipherAlgo,
 +    oAEADAlgo,
      oDigestAlgo,
      oCertDigestAlgo,
      oCompressAlgo,
      oNoForceMDC,
      oDisableMDC,
      oNoDisableMDC,
 +    oForceAEAD,
      oS2KMode,
      oS2KDigest,
      oS2KCipher,
      oDefaultPreferenceList,
      oDefaultKeyserverURL,
      oPersonalCipherPreferences,
 +    oPersonalAEADPreferences,
      oPersonalDigestPreferences,
      oPersonalCompressPreferences,
      oAgentProgram,
      oSender,
      oKeyOrigin,
      oRequestOrigin,
+     oNoSymkeyCache,
  
      oNoop
    };
@@@ -599,7 -594,6 +600,7 @@@ static ARGPARSE_OPTS opts[] = 
    ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
    ARGPARSE_p_u (oMaxOutput, "max-output", "@"),
    ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"),
 +  ARGPARSE_s_i (oChunkSize, "chunk-size", "@"),
  
    ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
    ARGPARSE_s_n (oQuiet,         "quiet",   "@"),
    ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"),
    ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"),
  
 +  ARGPARSE_s_n (oForceAEAD, "force-aead", "@"),
 +
    ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
  
    ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
    ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
    ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
    ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"),
 +  ARGPARSE_s_u (oDebugSetIobufSize, "debug-set-iobuf-size", "@"),
    ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
    ARGPARSE_s_s (oStatusFile, "status-file", "@"),
    ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"),
    ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"),
    ARGPARSE_s_i (oS2KCount, "s2k-count", "@"),
    ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
 +  ARGPARSE_s_s (oAEADAlgo,   "aead-algo", "@"),
    ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
    ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
    ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"),
    ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
    ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
    ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
 +  ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
    ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
    ARGPARSE_s_n (oWithWKDHash,     "with-wkd-hash", "@"),
    ARGPARSE_s_n (oWithKeyOrigin,   "with-key-origin", "@"),
    ARGPARSE_s_s (oDefaultPreferenceList,  "default-preference-list", "@"),
    ARGPARSE_s_s (oDefaultKeyserverURL,  "default-keyserver-url", "@"),
    ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"),
 +  ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"),
    ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"),
    ARGPARSE_s_s (oPersonalCompressPreferences,
                                           "personal-compress-preferences", "@"),
    /* Aliases.  I constantly mistype these, and assume other people do
       as well. */
    ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"),
 +  ARGPARSE_s_s (oPersonalAEADPreferences,   "personal-aead-prefs", "@"),
    ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"),
    ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
  
    ARGPARSE_s_s (oAutoKeyLocate, "auto-key-locate", "@"),
    ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
    ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
+   ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
  
    /* Dummy options with warnings.  */
    ARGPARSE_s_n (oUseAgent,      "use-agent", "@"),
@@@ -960,8 -948,6 +962,8 @@@ int g10_errors_seen = 0
  
  static int utf8_strings = 0;
  static int maybe_setuid = 1;
 +static unsigned int opt_set_iobuf_size;
 +static unsigned int opt_set_iobuf_size_used;
  
  static char *build_list( const char *text, char letter,
                         const char *(*mapf)(int), int (*chkf)(int) );
@@@ -1024,18 -1010,6 +1026,18 @@@ build_list_cipher_algo_name (int algo
  }
  
  static int
 +build_list_aead_test_algo (int algo)
 +{
 +  return openpgp_aead_test_algo (algo);
 +}
 +
 +static const char *
 +build_list_aead_algo_name (int algo)
 +{
 +  return openpgp_aead_algo_name (algo);
 +}
 +
 +static int
  build_list_md_test_algo (int algo)
  {
    /* By default we do not accept MD5 based signatures.  To avoid
@@@ -1056,7 -1030,7 +1058,7 @@@ build_list_md_algo_name (int algo
  static const char *
  my_strusage( int level )
  {
 -  static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry;
 +  static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry;
    const char *p;
  
      switch( level ) {
        p = ciphers;
        break;
        case 36:
 +      if (!aeads)
 +          aeads = build_list ("AEAD: ", 'A',
 +                              build_list_aead_algo_name,
 +                              build_list_aead_test_algo);
 +      p = aeads;
 +      break;
 +      case 37:
        if( !digests )
            digests = build_list(_("Hash: "), 'H',
                                   build_list_md_algo_name,
                                   build_list_md_test_algo );
        p = digests;
        break;
 -      case 37:
 +      case 38:
        if( !zips )
            zips = build_list(_("Compression: "),'Z',
                                compress_algo_to_string,
@@@ -1150,7 -1117,6 +1152,7 @@@ build_list (const char *text, char lett
    membuf_t mb;
    int indent;
    int i, j, len;
 +  int limit;
    const char *s;
    char *string;
  
    len = 0;
    init_membuf (&mb, 512);
  
 -  for (i=0; i <= 110; i++ )
 +  limit = (letter == 'A')? 4 : 110;
 +  for (i=0; i <= limit; i++ )
      {
        if (!chkf (i) && (s = mapf (i)))
          {
@@@ -1283,10 -1248,6 +1285,10 @@@ set_debug (const char *level
  
    if (opt.debug)
      parse_debug_flag (NULL, &opt.debug, debug_flags);
 +
 +  if (opt_set_iobuf_size || opt_set_iobuf_size_used)
 +    log_debug ("iobuf buffer size is %uk\n",
 +               iobuf_set_buffer_size (opt_set_iobuf_size));
  }
  
  
@@@ -2167,7 -2128,6 +2169,7 @@@ set_compliance_option (enum cmd_and_opt
        opt.escape_from = 1;
        opt.not_dash_escaped = 0;
        opt.def_cipher_algo = 0;
 +      opt.def_aead_algo = 0;
        opt.def_digest_algo = 0;
        opt.cert_digest_algo = 0;
        opt.compress_algo = -1;
        opt.escape_from = 0;
        opt.not_dash_escaped = 0;
        opt.def_cipher_algo = 0;
 +      opt.def_aead_algo = 0;
        opt.def_digest_algo = 0;
        opt.cert_digest_algo = 0;
        opt.compress_algo = -1;
        set_compliance_option (oOpenPGP);
        opt.compliance = CO_DE_VS;
        opt.force_mdc = 1;
 +      opt.def_aead_algo = 0;
        /* Fixme: Change other options.  */
        break;
  
@@@ -2331,14 -2289,12 +2333,14 @@@ main (int argc, char **argv
      const char *trustdb_name = NULL;
  #endif /*!NO_TRUST_MODELS*/
      char *def_cipher_string = NULL;
 +    char *def_aead_string = NULL;
      char *def_digest_string = NULL;
      char *compress_algo_string = NULL;
      char *cert_digest_string = NULL;
      char *s2k_cipher_string = NULL;
      char *s2k_digest_string = NULL;
      char *pers_cipher_list = NULL;
 +    char *pers_aead_list = NULL;
      char *pers_digest_list = NULL;
      char *pers_compress_list = NULL;
      int eyes_only=0;
      opt.bz2_compress_level = -1; /* defaults to standard compress level */
      /* note: if you change these lines, look at oOpenPGP */
      opt.def_cipher_algo = 0;
 +    opt.def_aead_algo = 0;
      opt.def_digest_algo = 0;
      opt.cert_digest_algo = 0;
      opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */
              opt.input_size_hint = string_to_u64 (pargs.r.ret_str);
              break;
  
 +          case oChunkSize:
 +            opt.chunk_size = pargs.r.ret_int;
 +            break;
 +
          case oQuiet: opt.quiet = 1; break;
          case oNoTTY: tty_no_terminal(1); break;
          case oDryRun: opt.dry_run = 1; break;
  
            case oDebugIOLBF: break; /* Already set in pre-parse step.  */
  
 +          case oDebugSetIobufSize:
 +            opt_set_iobuf_size = pargs.r.ret_ulong;
 +            opt_set_iobuf_size_used = 1;
 +            break;
 +
          case oStatusFD:
              set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
              break;
              opt.with_keygrip = 1;
              break;
  
 +        case oWithKeyScreening:
 +            opt.with_key_screening = 1;
 +            break;
 +
          case oWithSecret:
              opt.with_secret = 1;
              break;
          case oDisableMDC: opt.disable_mdc = 1; break;
          case oNoDisableMDC: opt.disable_mdc = 0; break;
  
 +        case oForceAEAD: opt.force_aead = 1; break;
 +
            case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
  
          case oS2KMode:   opt.s2k_mode = pargs.r.ret_int; break;
          case oCipherAlgo:
              def_cipher_string = xstrdup(pargs.r.ret_str);
              break;
 +        case oAEADAlgo:
 +            def_aead_string = xstrdup (pargs.r.ret_str);
 +            break;
          case oDigestAlgo:
              def_digest_string = xstrdup(pargs.r.ret_str);
              break;
            case oPersonalCipherPreferences:
            pers_cipher_list=pargs.r.ret_str;
            break;
 +          case oPersonalAEADPreferences:
 +          pers_aead_list = pargs.r.ret_str;
 +          break;
            case oPersonalDigestPreferences:
            pers_digest_list=pargs.r.ret_str;
            break;
              break;
  
            case oNoAutostart: opt.autostart = 0; break;
+           case oNoSymkeyCache: opt.no_symkey_cache = 1; break;
  
          case oDefaultNewKeyAlgo:
              opt.def_new_key_algo = pargs.r.ret_str;
        if ( openpgp_cipher_test_algo (opt.def_cipher_algo) )
            log_error(_("selected cipher algorithm is invalid\n"));
      }
 +    if (def_aead_string)
 +      {
 +      opt.def_aead_algo = string_to_aead_algo (def_aead_string);
 +      xfree (def_aead_string); def_aead_string = NULL;
 +      if (openpgp_aead_test_algo (opt.def_aead_algo))
 +          log_error(_("selected AEAD algorithm is invalid\n"));
 +      }
      if( def_digest_string ) {
        opt.def_digest_algo = string_to_digest_algo (def_digest_string);
        xfree(def_digest_string); def_digest_string = NULL;
         keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM))
        log_error(_("invalid personal cipher preferences\n"));
  
 +    if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD))
 +      log_error(_("invalid personal AEAD preferences\n"));
 +
      if(pers_digest_list &&
         keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH))
        log_error(_("invalid personal digest preferences\n"));
         keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP))
        log_error(_("invalid personal compress preferences\n"));
  
 +    /* Check chunk size.  Please fix also the man page if you chnage
 +     * the default.  The limits are given by the specs.  */
 +    if (!opt.chunk_size)
 +      opt.chunk_size = 30; /* Default to 1 GiB chunks.  */
 +    else if (opt.chunk_size < 6)
 +      {
 +        opt.chunk_size = 6;
 +        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
 +      }
 +    else if (opt.chunk_size > 62)
 +      {
 +        opt.chunk_size = 62;
 +        log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
 +      }
 +
      /* We don't support all possible commands with multifile yet */
      if(multifile)
        {
      /* Check our chosen algorithms against the list of legal
         algorithms. */
  
 -    if(!GNUPG)
 +    if(!GNUPG && !opt.flags.rfc4880bis)
        {
        const char *badalg=NULL;
        preftype_t badtype=PREFTYPE_NONE;
            badalg = openpgp_cipher_algo_name (opt.def_cipher_algo);
            badtype = PREFTYPE_SYM;
          }
 +      else if(opt.def_aead_algo
 +         && !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL))
 +        {
 +          badalg = openpgp_aead_algo_name (opt.def_aead_algo);
 +          badtype = PREFTYPE_AEAD;
 +        }
        else if(opt.def_digest_algo
                && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL))
          {
                         badalg,
                            gnupg_compliance_option_string (opt.compliance));
                break;
 +            case PREFTYPE_AEAD:
 +              log_info (_("AEAD algorithm '%s'"
 +                            " may not be used in %s mode\n"),
 +                          badalg,
 +                          gnupg_compliance_option_string (opt.compliance));
 +              break;
              case PREFTYPE_HASH:
                log_info (_("digest algorithm '%s'"
                              " may not be used in %s mode\n"),
       * is not.  This is us being nice to the user informing her early
       * that the chosen algorithms are not available.  We also check
       * and enforce this right before the actual operation.  */
 +    /* FIXME: We also need to check the AEAD algo. */
      if (opt.def_cipher_algo
        && ! gnupg_cipher_is_allowed (opt.compliance,
                                      cmd == aEncr
@@@ -5214,7 -5111,7 +5217,7 @@@ g10_exit( int rc 
    /* If we had an error but not printed an error message, do it now.
     * Note that write_status_failure will never print a second failure
     * status line. */
-   if (log_get_errorcount (0))
+   if (rc)
      write_status_failure ("gpg-exit", gpg_error (GPG_ERR_GENERAL));
  
    gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
diff --combined g10/import.c
@@@ -767,7 -767,7 +767,7 @@@ valid_keyblock_packet (int pkttype
   * Meta data (ring trust packets) are only considered of WITH_META is set.
   * PENDING_PKT should be initialized to NULL and not changed by the caller.
   * Return: 0 = okay, -1 no more blocks or another errorcode.
-  *         The int at at R_V3KEY counts the number of unsupported v3
+  *         The int at R_V3KEY counts the number of unsupported v3
   *         keyblocks.
   */
  static int
@@@ -856,7 -856,9 +856,9 @@@ read_block( IOBUF a, int with_meta
              {
                compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
                pkt->pkt.compressed->buf = NULL;
-               push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1);
+               if (push_compress_filter2 (a, cfx,
+                                            pkt->pkt.compressed->algorithm, 1))
+                   xfree (cfx); /* e.g. in case of compression_algo NONE.  */
              }
            free_packet (pkt, &parsectx);
            init_packet(pkt);
@@@ -1113,24 -1115,6 +1115,24 @@@ check_prefs (ctrl_t ctrl, kbnode_t keyb
                      problem=1;
                    }
                }
 +            else if(prefs->type==PREFTYPE_AEAD)
 +              {
 +                if (openpgp_aead_test_algo (prefs->value))
 +                  {
 +                      /* FIXME: The test below is wrong.  We should
 +                       * check if ...algo_name yields a "?" and
 +                       * only in that case use NUM.  */
 +                    const char *algo =
 +                        (openpgp_aead_test_algo (prefs->value)
 +                         ? num
 +                         : openpgp_aead_algo_name (prefs->value));
 +                    if(!problem)
 +                      check_prefs_warning(pk);
 +                    log_info(_("         \"%s\": preference for AEAD"
 +                               " algorithm %s\n"), user, algo);
 +                    problem=1;
 +                  }
 +              }
              else if(prefs->type==PREFTYPE_HASH)
                {
                  if(openpgp_md_test_algo(prefs->value))
@@@ -2273,7 -2257,6 +2275,7 @@@ transfer_secret_keys (ctrl_t ctrl, stru
          {
            char countbuf[35];
  
 +          /* FIXME: Support AEAD */
            /* Note that the IVLEN may be zero if we are working on a
               dummy key.  We can't express that in an S-expression and
               thus we send dummy data for the IV.  */
diff --combined g10/keydb.h
@@@ -235,7 -235,6 +235,7 @@@ int  algo_available( preftype_t preftyp
  int  select_algo_from_prefs( PK_LIST pk_list, int preftype,
                             int request, const union pref_hint *hint);
  int  select_mdc_from_pklist (PK_LIST pk_list);
 +aead_algo_t select_aead_from_pklist (pk_list_t pk_list);
  void warn_missing_mdc_from_pklist (PK_LIST pk_list);
  void warn_missing_aes_from_pklist (PK_LIST pk_list);
  
@@@ -405,10 -404,10 +405,10 @@@ void setup_main_keyids (kbnode_t keyblo
     data structures.  */
  void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
  
- char*get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
- char*get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
- char*get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn);
- char*get_user_id_native (ctrl_t ctrl, u32 *keyid);
+ char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
+ char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
+ char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
+ char *get_user_id_native (ctrl_t ctrl, u32 *keyid);
  char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn);
  char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr);
  
diff --combined g10/keyedit.c
@@@ -264,7 -264,7 +264,7 @@@ keyedit_print_one_sig (ctrl_t ctrl, est
        else
        {
          size_t n;
-         char *p = get_user_id (ctrl, sig->keyid, &n);
+         char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
          tty_print_utf8_string2 (fp, p, n,
                                  opt.screen_columns - keystrlen () - 26 -
                                  ((opt.
@@@ -1144,7 -1144,7 +1144,7 @@@ change_passphrase (ctrl_t ctrl, kbnode_
            if (err)
              log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
                        || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
 -                     ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
 +                     ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
                       _("key %s: error changing passphrase: %s\n"),
                         keystr_with_sub (keyid, subid),
                         gpg_strerror (err));
@@@ -3066,23 -3066,6 +3066,23 @@@ show_prefs (PKT_user_id * uid, PKT_sign
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
        tty_printf ("\n     ");
 +      tty_printf (_("AEAD: "));
 +      for (i = any = 0; prefs[i].type; i++)
 +      {
 +        if (prefs[i].type == PREFTYPE_AEAD)
 +          {
 +            if (any)
 +              tty_printf (", ");
 +            any = 1;
 +            /* We don't want to display strings for experimental algos */
 +            if (!openpgp_aead_test_algo (prefs[i].value)
 +                && prefs[i].value < 100)
 +              tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
 +            else
 +              tty_printf ("[%d]", prefs[i].value);
 +          }
 +      }
 +      tty_printf ("\n     ");
        tty_printf (_("Digest: "));
        for (i = any = 0; prefs[i].type; i++)
        {
            }
          tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
        }
 -      if (uid->flags.mdc || !uid->flags.ks_modify)
 +      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
        {
          tty_printf ("\n     ");
          tty_printf (_("Features: "));
              tty_printf ("MDC");
              any = 1;
            }
 +        if (!uid->flags.aead)
 +          {
 +            if (any)
 +              tty_printf (", ");
 +            tty_printf ("AEAD");
 +          }
          if (!uid->flags.ks_modify)
            {
              if (any)
        for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
 +                    prefs[i].type == PREFTYPE_AEAD ? 'A' :
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
        }
        if (uid->flags.mdc)
        tty_printf (" [mdc]");
 +      if (uid->flags.aead)
 +      tty_printf (" [aead]");
        if (!uid->flags.ks_modify)
        tty_printf (" [no-ks-modify]");
        tty_printf ("\n");
@@@ -3345,8 -3319,6 +3345,8 @@@ show_key_with_all_names_colon (ctrl_t c
                }
              if (uid->flags.mdc)
                es_fputs (",mdc", fp);
 +            if (uid->flags.aead)
 +              es_fputs (",aead", fp);
              if (!uid->flags.ks_modify)
                es_fputs (",no-ks-modify", fp);
            }
diff --combined g10/keylist.c
@@@ -45,7 -45,6 +45,7 @@@
  #include "../common/zb32.h"
  #include "tofu.h"
  #include "../common/compliance.h"
 +#include "../common/pkscreening.h"
  
  
  static void list_all (ctrl_t, int, int);
@@@ -697,37 -696,6 +697,37 @@@ print_key_data (PKT_public_key * pk
      }
  }
  
 +
 +/* Various public key screenings.  (Right now just ROCA).  With
 + * COLON_MODE set the output is formatted for use in the compliance
 + * field of a colon listing.
 + */
 +static void
 +print_pk_screening (PKT_public_key *pk, int colon_mode)
 +{
 +  gpg_error_t err;
 +
 +  if (is_RSA (pk->pubkey_algo) && pubkey_get_npkey (pk->pubkey_algo))
 +    {
 +      err = screen_key_for_roca (pk->pkey[0]);
 +      if (!err)
 +        ;
 +      else if (gpg_err_code (err) == GPG_ERR_TRUE)
 +        {
 +          if (colon_mode)
 +            es_fprintf (es_stdout, colon_mode > 1? " %d":"%d", 6001);
 +          else
 +            es_fprintf (es_stdout,
 +                        "      Screening: ROCA vulnerability detected\n");
 +        }
 +      else if (!colon_mode)
 +        es_fprintf (es_stdout, "      Screening: [ROCA check failed: %s]\n",
 +                    gpg_strerror (err));
 +    }
 +
 +}
 +
 +
  static void
  print_capabilities (ctrl_t ctrl, PKT_public_key *pk, KBNODE keyblock)
  {
@@@ -954,9 -922,6 +954,9 @@@ list_keyblock_print (ctrl_t ctrl, kbnod
    if (opt.with_key_data)
      print_key_data (pk);
  
 +  if (opt.with_key_screening)
 +    print_pk_screening (pk, 0);
 +
    if (opt.with_key_origin
        && (pk->keyorg || pk->keyupdate || pk->updateurl))
      {
              es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
          if (opt.with_key_data)
            print_key_data (pk2);
 +          if (opt.with_key_screening)
 +            print_pk_screening (pk2, 0);
        }
        else if (opt.list_sigs
               && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
          else if (!opt.fast_list_mode)
            {
              size_t n;
-             char *p = get_user_id (ctrl, sig->keyid, &n);
+             char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
              print_utf8_buffer (es_stdout, p, n);
              xfree (p);
            }
@@@ -1264,9 -1227,6 +1264,9 @@@ print_compliance_flags (PKT_public_key 
                  gnupg_status_compliance_flag (CO_DE_VS));
        any++;
      }
 +
 +  if (opt.with_key_screening)
 +    print_pk_screening (pk, 1+any);
  }
  
  
@@@ -1553,6 -1513,7 +1553,7 @@@ list_keyblock_colon (ctrl_t ctrl, kbnod
          byte fparray[MAX_FINGERPRINT_LEN];
            char *siguid;
            size_t siguidlen;
+           char *issuer_fpr = NULL;
  
          if (sig->sig_class == 0x20 || sig->sig_class == 0x28
              || sig->sig_class == 0x30)
          else
            {
              rc = 0;
-             sigrc = ' ';
+             sigrc = ' '; /* Note the fix-up below in --list-sigs mode.  */
            }
  
          if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode)
-             siguid = get_user_id (ctrl, sig->keyid, &siguidlen);
+             {
+               int nouid;
+               siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid);
+               if (!opt.check_sigs && nouid)
+                 sigrc = '?';  /* No key in local keyring.  */
+             }
            else
              {
                siguid = NULL;
              for (i = 0; i < fplen; i++)
                es_fprintf (es_stdout, "%02X", fparray[i]);
            }
+           else if ((issuer_fpr = issuer_fpr_string (sig)))
+             es_fputs (issuer_fpr, es_stdout);
  
          es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo);
  
  
          /* fixme: check or list other sigs here */
            xfree (siguid);
+           xfree (issuer_fpr);
        }
      }
  
@@@ -1946,9 -1915,6 +1955,9 @@@ print_card_serialno (const char *serial
   * pub   dsa2048 2007-12-31 [SC] [expires: 2018-12-31]
   *       80615870F5BAD690333686D0F2AD85AC1E42B367
   *
 + * pub   rsa2048 2017-12-31 [SC] [expires: 2028-12-31]
 + *       80615870F5BAD690333686D0F2AD85AC1E42B3671122334455
 + *
   * Some global options may result in a different output format.  If
   * SECRET is set, "sec" or "ssb" is used instead of "pub" or "sub" and
   * depending on the value a flag character is shown:
diff --combined g10/mainproc.c
@@@ -245,116 -245,46 +245,116 @@@ add_signature (CTX c, PACKET *pkt
    return 1;
  }
  
 -static int
 +static gpg_error_t
  symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
  {
 +  gpg_error_t err;
    gcry_cipher_hd_t hd;
 +  unsigned int noncelen, keylen;
 +  enum gcry_cipher_modes ciphermode;
 +
 +  if (dek->use_aead)
 +    {
 +      err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen);
 +      if (err)
 +        return err;
 +    }
 +  else
 +    {
 +      ciphermode = GCRY_CIPHER_MODE_CFB;
 +      noncelen = 0;
 +    }
  
 -  if(slen < 17 || slen > 33)
 +  /* Check that the session key has a size of 16 to 32 bytes.  */
 +  if ((dek->use_aead && (slen < (noncelen + 16 + 16)
 +                         || slen > (noncelen + 32 + 16)))
 +      || (!dek->use_aead && (slen < 17 || slen > 33)))
      {
        log_error ( _("weird size for an encrypted session key (%d)\n"),
                  (int)slen);
 -      return GPG_ERR_BAD_KEY;
 +      return gpg_error (GPG_ERR_BAD_KEY);
      }
  
 -  if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
 -      BUG ();
 -  if (gcry_cipher_setkey ( hd, dek->key, dek->keylen ))
 -    BUG ();
 -  gcry_cipher_setiv ( hd, NULL, 0 );
 -  gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 );
 -  gcry_cipher_close ( hd );
 -
 -  /* Now we replace the dek components with the real session key to
 -     decrypt the contents of the sequencing packet. */
 -
 -  dek->keylen=slen-1;
 -  dek->algo=seskey[0];
 +  err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE);
 +  if (!err)
 +    err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
 +  if (!err)
 +    err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen);
 +  if (err)
 +    goto leave;
  
 -  if(dek->keylen > DIM(dek->key))
 -    BUG ();
 +  if (dek->use_aead)
 +    {
 +      byte ad[4];
 +
 +      ad[0] = (0xc0 | PKT_SYMKEY_ENC);
 +      ad[1] = 5;
 +      ad[2] = dek->algo;
 +      ad[3] = dek->use_aead;
 +      err = gcry_cipher_authenticate (hd, ad, 4);
 +      if (err)
 +        goto leave;
 +      gcry_cipher_final (hd);
 +      keylen = slen - noncelen - 16;
 +      err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0);
 +      if (err)
 +        goto leave;
 +      err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16);
 +      if (err)
 +        goto leave;
 +      /* Now we replace the dek components with the real session key to
 +       * decrypt the contents of the sequencing packet. */
 +      if (keylen > DIM(dek->key))
 +        {
 +          err = gpg_error (GPG_ERR_TOO_LARGE);
 +          goto leave;
 +        }
 +      dek->keylen = keylen;
 +      memcpy (dek->key, seskey + noncelen, dek->keylen);
 +    }
 +  else
 +    {
 +      gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 );
 +      /* Here we can only test whether the algo given in decrypted
 +       * session key is a valid OpenPGP algo.  With 11 defined
 +       * symmetric algorithms we will miss 4.3% of wrong passphrases
 +       * here.  The actual checking is done later during bulk
 +       * decryption; we can't bring this check forward easily.  We
 +       * need to use the GPG_ERR_CHECKSUM so that we won't run into
 +       * the gnupg < 2.2 bug compatible case which would terminate the
 +       * process on GPG_ERR_CIPHER_ALGO.  Note that with AEAD (above)
 +       * we will have a reliable test here.  */
 +      if (openpgp_cipher_test_algo (seskey[0]))
 +        {
 +          err = gpg_error (GPG_ERR_CHECKSUM);
 +          goto leave;
 +        }
  
 -  memcpy(dek->key, seskey + 1, dek->keylen);
 +      /* Now we replace the dek components with the real session key to
 +       * decrypt the contents of the sequencing packet. */
 +      keylen = slen-1;
 +      if (keylen > DIM(dek->key))
 +        {
 +          err = gpg_error (GPG_ERR_TOO_LARGE);
 +          goto leave;
 +        }
 +      dek->algo = seskey[0];
 +      dek->keylen = keylen;
 +      memcpy (dek->key, seskey + 1, dek->keylen);
 +    }
  
    /*log_hexdump( "thekey", dek->key, dek->keylen );*/
  
 -  return 0;
 + leave:
 +  gcry_cipher_close (hd);
 +  return err;
  }
  
  
  static void
  proc_symkey_enc (CTX c, PACKET *pkt)
  {
 +  gpg_error_t err;
    PKT_symkey_enc *enc;
  
    enc = pkt->pkt.symkey_enc;
      {
        int algo = enc->cipher_algo;
        const char *s = openpgp_cipher_algo_name (algo);
 +      const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo)
 +                       /**/           : "CFB");
  
        if (!openpgp_cipher_test_algo (algo))
          {
            if (!opt.quiet)
              {
                if (enc->seskeylen)
 -                log_info (_("%s encrypted session key\n"), s );
 +                log_info (_("%s.%s encrypted session key\n"), s, a );
                else
 -                log_info (_("%s encrypted data\n"), s );
 +                log_info (_("%s.%s encrypted data\n"), s, a );
              }
          }
        else
 -        log_error (_("encrypted with unknown algorithm %d\n"), algo);
 +        log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a);
  
        if (openpgp_md_test_algo (enc->s2k.hash_algo))
          {
            if (c->dek)
              {
                c->dek->symmetric = 1;
 +              c->dek->use_aead = enc->aead_algo;
  
                /* FIXME: This doesn't work perfectly if a symmetric key
                   comes before a public key in the message - if the
                   come later. */
                if (enc->seskeylen)
                  {
 -                  if (symkey_decrypt_seskey (c->dek,
 -                                             enc->seskey, enc->seskeylen))
 +                  err = symkey_decrypt_seskey (c->dek,
 +                                               enc->seskey, enc->seskeylen);
 +                  if (err)
                      {
 +                      log_info ("decryption of the symmetrically encrypted"
 +                                 " session key failed: %s\n",
 +                                 gpg_strerror (err));
 +                      if (gpg_err_code (err) != GPG_ERR_BAD_KEY
 +                          && gpg_err_code (err) != GPG_ERR_CHECKSUM)
 +                        log_fatal ("process terminated to be bug compatible"
 +                                   " with GnuPG <= 2.2\n");
 +                      if (c->dek->s2k_cacheid[0])
 +                        {
 +                          if (opt.debug)
 +                            log_debug ("cleared passphrase cached with ID:"
 +                                       " %s\n", c->dek->s2k_cacheid);
 +                          passphrase_clear_cache (c->dek->s2k_cacheid);
 +                        }
                        xfree (c->dek);
                        c->dek = NULL;
                      }
@@@ -738,7 -650,6 +738,7 @@@ proc_encrypted (CTX c, PACKET *pkt
    else if (!result
             && !opt.ignore_mdc_error
             && !pkt->pkt.encrypted->mdc_method
 +           && !pkt->pkt.encrypted->aead_algo
             && openpgp_cipher_get_algo_blklen (c->dek->algo) != 8
             && c->dek->algo != CIPHER_ALGO_TWOFISH)
      {
        write_status (STATUS_DECRYPTION_FAILED);
      }
    else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE
 +                       && !pkt->pkt.encrypted->aead_algo
                         && opt.ignore_mdc_error))
      {
 +      /* All is fine or for an MDC message the MDC failed but the
 +       * --ignore-mdc-error option is active.  For compatibility
 +       * reasons we issue GOODMDC also for AEAD messages.  */
        write_status (STATUS_DECRYPTION_OKAY);
        if (opt.verbose > 1)
          log_info(_("decryption okay\n"));
 -      if (pkt->pkt.encrypted->mdc_method && !result)
 +
 +      if (pkt->pkt.encrypted->aead_algo)
 +        write_status (STATUS_GOODMDC);
 +      else if (pkt->pkt.encrypted->mdc_method && !result)
          write_status (STATUS_GOODMDC);
        else if (!opt.no_mdc_warn)
          log_info (_("WARNING: message was not integrity protected\n"));
      }
 -  else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE)
 +  else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE
 +           || gpg_err_code (result) == GPG_ERR_TRUNCATED)
      {
        glo_ctrl.lasterr = result;
        log_error (_("WARNING: encrypted message has been manipulated!\n"));
    else
      {
        if ((gpg_err_code (result) == GPG_ERR_BAD_KEY
 +         || gpg_err_code (result) == GPG_ERR_CHECKSUM
           || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO)
            && *c->dek->s2k_cacheid != '\0')
          {
@@@ -1307,7 -1209,7 +1307,7 @@@ list_node (CTX c, kbnode_t node
        }
        else if (!opt.fast_list_mode)
          {
-           p = get_user_id (c->ctrl, sig->keyid, &n);
+           p = get_user_id (c->ctrl, sig->keyid, &n, NULL);
            es_write_sanitized (es_stdout, p, n,
                                opt.with_colons?":":NULL, NULL );
            xfree (p);
@@@ -1491,8 -1393,7 +1491,8 @@@ do_proc_packets (ctrl_t ctrl, CTX c, io
              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;
 +            case PKT_ENCRYPTED_MDC:
 +            case PKT_ENCRYPTED_AEAD:proc_encrypted (c, pkt); break;
              case PKT_COMPRESSED:    rc = proc_compressed (c, pkt); break;
              default: newpkt = 0; break;
            }
              case PKT_PUBKEY_ENC:
              case PKT_ENCRYPTED:
              case PKT_ENCRYPTED_MDC:
 +            case PKT_ENCRYPTED_AEAD:
                write_status_text( STATUS_UNEXPECTED, "0" );
                rc = GPG_ERR_UNEXPECTED;
                goto leave;
              case PKT_SYMKEY_ENC:  proc_symkey_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_ENCRYPTED_MDC:
 +            case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
              case PKT_PLAINTEXT:   proc_plaintext (c, pkt); break;
              case PKT_COMPRESSED:  rc = proc_compressed (c, pkt); break;
              case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (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;
 +            case PKT_ENCRYPTED_MDC:
 +            case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
              case PKT_PLAINTEXT:   proc_plaintext (c, pkt); break;
              case PKT_COMPRESSED:  rc = proc_compressed (c, pkt); break;
              case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break;
@@@ -1710,21 -1608,40 +1710,40 @@@ akl_has_wkd_method (void
  }
  
  
- /* Return the ISSUER fingerprint string in human readbale format if
-  * available.  Caller must release the string.  */
- static char *
- issuer_fpr_string (PKT_signature *sig)
+ /* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
+  * Returns NULL if not available.  The returned buffer is valid as
+  * long as SIG is not modified.  */
+ static const byte *
+ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
  {
    const byte *p;
    size_t n;
  
    p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
    if (p && n == 21 && p[0] == 4)
-     return bin2hex (p+1, n-1, NULL);
+     {
+       *r_len = n - 1;
+       return p+1;
+     }
+   *r_len = 0;
    return NULL;
  }
  
  
+ /* Return the ISSUER fingerprint string in human readbale format if
+  * available.  Caller must release the string.  */
+ /* FIXME: Move to another file.  */
+ char *
+ issuer_fpr_string (PKT_signature *sig)
+ {
+   const byte *p;
+   size_t n;
+   p = issuer_fpr_raw (sig, &n);
+   return p? bin2hex (p, n, NULL) : NULL;
+ }
  static void
  print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un,
                            PKT_signature *sig, int rc)
@@@ -1761,7 -1678,7 +1780,7 @@@ check_sig_and_print (CTX c, kbnode_t no
    int rc;
    int is_expkey = 0;
    int is_revkey = 0;
-   char *issuer_fpr;
+   char *issuer_fpr = NULL;
    PKT_public_key *pk = NULL;  /* The public key for the signature or NULL. */
    int tried_ks_by_fpr;
  
      write_status_text (STATUS_NEWSIG, NULL);
  
    astr = openpgp_pk_algo_name ( sig->pubkey_algo );
-   if ((issuer_fpr = issuer_fpr_string (sig)))
+   issuer_fpr = issuer_fpr_string (sig);
+   if (issuer_fpr)
      {
        log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp));
        log_info (_("               using %s key %s\n"),
                  astr? astr: "?", issuer_fpr);
  
-       xfree (issuer_fpr);
      }
    else if (!keystrlen () || keystrlen () > 8)
      {
        const byte *p;
        size_t n;
  
-       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
-       if (p && n == 21 && p[0] == 4)
+       p = issuer_fpr_raw (sig, &n);
+       if (p)
          {
            /* v4 packet with a SHA-1 fingerprint.  */
            free_public_key (pk);
            pk = NULL;
            glo_ctrl.in_auto_key_retrieve++;
-           res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver, 1);
+           res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1);
            tried_ks_by_fpr = 1;
            glo_ctrl.in_auto_key_retrieve--;
            if (!res)
      }
    else
      {
-       char buf[50];
-       snprintf (buf, sizeof buf, "%08lX%08lX %d %d %02x %lu %d",
-                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
-                 sig->pubkey_algo, sig->digest_algo,
-                 sig->sig_class, (ulong)sig->timestamp, gpg_err_code (rc));
-       write_status_text (STATUS_ERRSIG, buf);
+       write_status_printf (STATUS_ERRSIG, "%08lX%08lX %d %d %02x %lu %d %s",
+                            (ulong)sig->keyid[0], (ulong)sig->keyid[1],
+                            sig->pubkey_algo, sig->digest_algo,
+                            sig->sig_class, (ulong)sig->timestamp,
+                            gpg_err_code (rc),
+                            issuer_fpr? issuer_fpr:"-");
        if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
          {
-           buf[16] = 0;
-           write_status_text (STATUS_NO_PUBKEY, buf);
+           write_status_printf (STATUS_NO_PUBKEY, "%08lX%08lX",
+                                (ulong)sig->keyid[0], (ulong)sig->keyid[1]);
        }
        if (gpg_err_code (rc) != GPG_ERR_NOT_PROCESSED)
          log_error (_("Can't check signature: %s\n"), gpg_strerror (rc));
      }
  
+   free_public_key (pk);
+   xfree (issuer_fpr);
    return rc;
  }
  
diff --combined g10/options.h
@@@ -62,9 -62,6 +62,9 @@@ struc
     * progress info and to decide on how to allocate buffers.  */
    uint64_t input_size_hint;
  
 +  /* The AEAD chunk size expressed as a power of 2.  */
 +  int chunk_size;
 +
    int dry_run;
    int autostart;
    int list_only;
@@@ -85,7 -82,6 +85,7 @@@
    int with_fingerprint; /* Option --with-fingerprint active.  */
    int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active.  */
    int with_keygrip;     /* Option --with-keygrip active.  */
 +  int with_key_screening;/* Option --with-key-screening active.  */
    int with_tofu_info;   /* Option --with-tofu_info active.  */
    int with_secret;      /* Option --with-secret active.  */
    int with_wkd_hash;    /* Option --with-wkd-hash.  */
    int no_armor;
    int list_packets; /* Option --list-packets active.  */
    int def_cipher_algo;
 +  int def_aead_algo;
    int force_mdc;
    int disable_mdc;
 +  int force_aead;
    int def_digest_algo;
    int cert_digest_algo;
    int compress_algo;
    const char *def_preference_list;
    const char *def_keyserver_url;
    prefitem_t *personal_cipher_prefs;
 +  prefitem_t *personal_aead_prefs;
    prefitem_t *personal_digest_prefs;
    prefitem_t *personal_compress_prefs;
    struct weakhash *weak_digests;
      unsigned int allow_weak_digest_algos:1;
      unsigned int large_rsa:1;
      unsigned int disable_signer_uid:1;
-     /* Flag to enbale experimental features from RFC4880bis.  */
+     /* Flag to enable experimental features from RFC4880bis.  */
      unsigned int rfc4880bis:1;
    } flags;
  
  
    int unwrap_encryption;
    int only_sign_text_ids;
+   int no_symkey_cache;   /* Disable the cache used for --symmetric.  */
  } opt;
  
  /* CTRL is used to keep some global variables we currently can't
@@@ -323,6 -318,7 +325,6 @@@ struct 
  #define DBG_TRUST  (opt.debug & DBG_TRUST_VALUE)
  #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
  #define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
 -#define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
  #define DBG_CLOCK   (opt.debug & DBG_CLOCK_VALUE)
  #define DBG_LOOKUP  (opt.debug & DBG_LOOKUP_VALUE)
  #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
diff --combined g10/packet.h
@@@ -72,8 -72,7 +72,8 @@@ typedef enum 
      PREFTYPE_NONE = 0,
      PREFTYPE_SYM = 1,
      PREFTYPE_HASH = 2,
 -    PREFTYPE_ZIP = 3
 +    PREFTYPE_ZIP = 3,
 +    PREFTYPE_AEAD = 4
  } preftype_t;
  
  typedef struct {
@@@ -94,14 -93,12 +94,14 @@@ typedef struc
  /* A symmetric-key encrypted session key packet as defined in RFC
     4880, Section 5.3.  All fields are serialized.  */
  typedef struct {
 -  /* RFC 4880: this must be 4.  */
 +  /* We support version 4 (rfc4880) and 5 (rfc4880bis).  */
    byte version;
 -  /* The cipher algorithm used to encrypt the session key.  (This may
 -     be different from the algorithm that is used to encrypt the SED
 -     packet.)  */
 +  /* The cipher algorithm used to encrypt the session key.  Note that
 +   * this may be different from the algorithm that is used to encrypt
 +   * bulk data.  */
    byte cipher_algo;
 +  /* The AEAD algorithm or 0 for CFB encryption.  */
 +  byte aead_algo;
    /* The string-to-key specifier.  */
    STRING2KEY s2k;
    /* The length of SESKEY in bytes or 0 if this packet does not
       S2K function on the password is the session key. See RFC 4880,
       Section 5.3.)  */
    byte seskeylen;
 -  /* The session key as encrypted by the S2K specifier.  */
 +  /* The session key as encrypted by the S2K specifier.  For AEAD this
 +   * includes the nonce and the authentication tag.  */
    byte seskey[1];
  } PKT_symkey_enc;
  
@@@ -294,7 -290,6 +294,7 @@@ typedef struc
    struct
    {
      unsigned int mdc:1;
 +    unsigned int aead:1;
      unsigned int ks_modify:1;
      unsigned int compacted:1;
      unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */
@@@ -391,7 -386,6 +391,7 @@@ typedef struc
    struct
    {
      unsigned int mdc:1;           /* MDC feature set.  */
 +    unsigned int aead:1;          /* AEAD feature set.  */
      unsigned int disabled_valid:1;/* The next flag is valid.  */
      unsigned int disabled:1;      /* The key has been disabled.  */
      unsigned int primary:1;       /* This is a primary key.  */
@@@ -462,13 -456,12 +462,13 @@@ typedef struct 
  typedef struct {
    /* Remaining length of encrypted data. */
    u32  len;
 -  /* When encrypting, the first block size bytes of data are random
 -     data and the following 2 bytes are copies of the last two bytes
 -     of the random data (RFC 4880, Section 5.7).  This provides a
 -     simple check that the key is correct.  extralen is the size of
 -     this extra data.  This is used by build_packet when writing out
 -     the packet's header. */
 +  /* When encrypting in CFB mode, the first block size bytes of data
 +   * are random data and the following 2 bytes are copies of the last
 +   * two bytes of the random data (RFC 4880, Section 5.7).  This
 +   * provides a simple check that the key is correct.  EXTRALEN is the
 +   * size of this extra data or, in AEAD mode, the length of the
 +   * headers and the tags.  This is used by build_packet when writing
 +   * out the packet's header. */
    int  extralen;
    /* Whether the serialized version of the packet used / should use
       the new format.  */
       Note: this is ignored when encrypting.  */
    byte is_partial;
    /* If 0, MDC is disabled.  Otherwise, the MDC method that was used
 -     (currently, only DIGEST_ALGO_SHA1 is supported).  */
 +     (only DIGEST_ALGO_SHA1 has ever been defined).  */
    byte mdc_method;
 +  /* If 0, AEAD is not used.  Otherwise, the used AEAD algorithm.
 +   * MDC_METHOD (above) shall be zero if AEAD is used.  */
 +  byte aead_algo;
 +  /* The cipher algo for/from the AEAD packet.  0 for other encryption
 +   * packets. */
 +  byte cipher_algo;
 +  /* The chunk byte from the AEAD packet.  */
 +  byte chunkbyte;
 +
    /* An iobuf holding the data to be decrypted.  (This is not used for
       encryption!)  */
    iobuf_t buf;
@@@ -620,6 -604,8 +620,8 @@@ int proc_signature_packets_by_fd (ctrl_
  int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
  int list_packets( iobuf_t a );
  
+ char *issuer_fpr_string (PKT_signature *sig);
  /*-- parse-packet.c --*/
  
  /* Sets the packet list mode to MODE (i.e., whether we are dumping a
diff --combined g10/pkclist.c
@@@ -1149,7 -1149,7 +1149,7 @@@ build_pk_list (ctrl_t ctrl, strlist_t r
                    else
                      {
                        size_t n;
-                       char *p = get_user_id (ctrl, keyid, &n );
+                       char *p = get_user_id (ctrl, keyid, &n, NULL);
                        tty_print_utf8_string ( p, n );
                        xfree(p);
                      }
@@@ -1468,12 -1468,9 +1468,12 @@@ select_algo_from_prefs(PK_LIST pk_list
             support.  All this doesn't mean IDEA is actually
             available, of course. */
            implicit=CIPHER_ALGO_3DES;
 -
          break;
  
 +      case PREFTYPE_AEAD:
 +          /* No implicit algo.  */
 +          break;
 +
        case PREFTYPE_HASH:
          /* While I am including this code for completeness, note
             that currently --pgp2 mode locks the hash at MD5, so this
        prefs=NULL;
        if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
        prefs=opt.personal_cipher_prefs;
 +      else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs)
 +      prefs=opt.personal_aead_prefs;
        else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
        prefs=opt.personal_digest_prefs;
        else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)
@@@ -1651,32 -1646,6 +1651,32 @@@ select_mdc_from_pklist (PK_LIST pk_list
  }
  
  
 +/* Select the AEAD flag from the pk_list.  We can only use AEAD if all
 + * recipients support this feature.  Returns the AEAD to be used or 0
 + * if AEAD shall not be used.  */
 +aead_algo_t
 +select_aead_from_pklist (PK_LIST pk_list)
 +{
 +  pk_list_t pkr;
 +  int aead;
 +
 +  if (!pk_list)
 +    return 0;
 +
 +  for (pkr = pk_list; pkr; pkr = pkr->next)
 +    {
 +      if (pkr->pk->user_id) /* selected by user ID */
 +        aead = pkr->pk->user_id->flags.aead;
 +      else
 +        aead = pkr->pk->flags.aead;
 +      if (!aead)
 +        return 0;  /* At least one recipient does not support it. */
 +    }
 +
 +  return default_aead_algo (); /* Yes, AEAD can be used. */
 +}
 +
 +
  /* Print a warning for all keys in PK_LIST missing the MDC feature. */
  void
  warn_missing_mdc_from_pklist (PK_LIST pk_list)