Merge branch 'STABLE-BRANCH-2-2' into master
authorWerner Koch <wk@gnupg.org>
Tue, 27 Mar 2018 06:48:00 +0000 (08:48 +0200)
committerWerner Koch <wk@gnupg.org>
Tue, 27 Mar 2018 06:48:00 +0000 (08:48 +0200)
21 files changed:
1  2 
agent/agent.h
agent/command-ssh.c
agent/command.c
agent/cvt-openpgp.c
configure.ac
doc/Makefile.am
doc/gpg.texi
doc/gpgsm.texi
g10/call-agent.c
g10/card-util.c
g10/gpg.c
g10/gpg.h
g10/keyedit.c
g10/misc.c
g10/options.h
g10/parse-packet.c
g10/tdbdump.c
scd/apdu.c
scd/app-openpgp.c
sm/gpgsm.c
sm/gpgsm.h

diff --combined agent/agent.h
@@@ -230,7 -230,6 +230,7 @@@ struct server_control_
    char *lc_ctype;
    char *lc_messages;
    unsigned long client_pid;
 +  int client_uid;
  
    /* The current pinentry mode.  */
    pinentry_mode_t pinentry_mode;
@@@ -453,9 -452,9 +453,9 @@@ void initialize_module_cache (void)
  void deinitialize_module_cache (void);
  void agent_cache_housekeeping (void);
  void agent_flush_cache (void);
- int agent_put_cache (const char *key, cache_mode_t cache_mode,
+ int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
                       const char *data, int ttl);
- char *agent_get_cache (const char *key, cache_mode_t cache_mode);
+ char *agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode);
  void agent_store_cache_hit (const char *key);
  
  
diff --combined agent/command-ssh.c
@@@ -258,11 -258,6 +258,11 @@@ static gpg_error_t ssh_signature_encode
  static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
  
  
 +struct peer_info_s
 +{
 +  unsigned long pid;
 +  int uid;
 +};
  
  /* Global variables.  */
  
@@@ -3145,7 -3140,7 +3145,7 @@@ ssh_identity_register (ctrl_t ctrl, ssh
      goto out;
  
    /* Cache this passphrase. */
-   err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
+   err = agent_put_cache (ctrl, key_grip, CACHE_MODE_SSH, pi->pin, ttl);
    if (err)
      goto out;
  
@@@ -3589,11 -3584,10 +3589,11 @@@ ssh_request_process (ctrl_t ctrl, estre
  
  
  /* Return the peer's pid.  */
 -static unsigned long
 -get_client_pid (int fd)
 +static void
 +get_client_info (int fd, struct peer_info_s *out)
  {
 -  pid_t client_pid = (pid_t)0;
 +  pid_t client_pid = (pid_t)(-1);
 +  uid_t client_uid = (uid_t)-1;
  
  #ifdef SO_PEERCRED
    {
        {
  #if defined (HAVE_STRUCT_SOCKPEERCRED_PID) || defined (HAVE_STRUCT_UCRED_PID)
          client_pid = cr.pid;
 +        client_uid = cr.uid;
  #elif defined (HAVE_STRUCT_UCRED_CR_PID)
          client_pid = cr.cr_pid;
 +        client_pid = cr.cr_uid;
  #else
  #error "Unknown SO_PEERCRED struct"
  #endif
      socklen_t len = sizeof (pid_t);
  
      getsockopt (fd, SOL_LOCAL, LOCAL_PEERPID, &client_pid, &len);
 +#if defined (LOCAL_PEERCRED)
 +    {
 +      struct xucred cr;
 +      len = sizeof (struct xucred);
 +
 +      if (!getsockopt (fd, SOL_LOCAL, LOCAL_PEERCRED, &cr, &len))
 +      client_uid = cr.cr_uid;
 +    }
 +#endif
    }
  #elif defined (LOCAL_PEEREID)
    {
  
      if (getsockopt (fd, 0, LOCAL_PEEREID, &unp, &unpl) != -1)
        client_pid = unp.unp_pid;
 +      client_uid = unp.unp_euid;
    }
  #elif defined (HAVE_GETPEERUCRED)
    {
  
      if (getpeerucred (fd, &ucred) != -1)
        {
 -        client_pid= ucred_getpid (ucred);
 +        client_pid = ucred_getpid (ucred);
 +      client_uid = ucred_geteuid (ucred);
          ucred_free (ucred);
        }
    }
    (void)fd;
  #endif
  
 -  return (unsigned long)client_pid;
 +  out->pid = (client_pid == (pid_t)(-1)? 0 : (unsigned long)client_pid);
 +  out->uid = (int)client_uid;
  }
  
  
@@@ -3668,15 -3648,12 +3668,15 @@@ start_command_handler_ssh (ctrl_t ctrl
    estream_t stream_sock = NULL;
    gpg_error_t err;
    int ret;
 +  struct peer_info_s peer_info;
  
    err = agent_copy_startup_env (ctrl);
    if (err)
      goto out;
  
 -  ctrl->client_pid = get_client_pid (FD2INT(sock_client));
 +  get_client_info (FD2INT(sock_client), &peer_info);
 +  ctrl->client_pid = peer_info.pid;
 +  ctrl->client_uid = peer_info.uid;
  
    /* Create stream from socket.  */
    stream_sock = es_fdopen (FD2INT(sock_client), "r+");
diff --combined agent/command.c
@@@ -199,14 -199,14 +199,14 @@@ clear_nonce_cache (ctrl_t ctrl
  {
    if (ctrl->server_local->last_cache_nonce)
      {
-       agent_put_cache (ctrl->server_local->last_cache_nonce,
+       agent_put_cache (ctrl, ctrl->server_local->last_cache_nonce,
                         CACHE_MODE_NONCE, NULL, 0);
        xfree (ctrl->server_local->last_cache_nonce);
        ctrl->server_local->last_cache_nonce = NULL;
      }
    if (ctrl->server_local->last_passwd_nonce)
      {
-       agent_put_cache (ctrl->server_local->last_passwd_nonce,
+       agent_put_cache (ctrl, ctrl->server_local->last_passwd_nonce,
                         CACHE_MODE_NONCE, NULL, 0);
        xfree (ctrl->server_local->last_passwd_nonce);
        ctrl->server_local->last_passwd_nonce = NULL;
@@@ -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"
@@@ -930,7 -930,7 +930,7 @@@ cmd_genkey (assuan_context_t ctx, char 
  
      }
    else if (passwd_nonce)
-     newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
+     newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
  
    rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
                       newpasswd, opt_preset, &outbuf);
@@@ -1179,7 -1179,7 +1179,7 @@@ do_one_keyinfo (ctrl_t ctrl, const unsi
    /* Here we have a little race by doing the cache check separately
       from the retrieval function.  Given that the cache flag is only a
       hint, it should not really matter.  */
-   pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL);
+   pw = agent_get_cache (ctrl, hexgrip, CACHE_MODE_NORMAL);
    cached = pw ? "1" : "-";
    xfree (pw);
  
@@@ -1484,7 -1484,7 +1484,7 @@@ cmd_get_passphrase (assuan_context_t ct
    if (!strcmp (desc, "X"))
      desc = NULL;
  
-   pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL;
+   pw = cacheid ? agent_get_cache (ctrl, cacheid, CACHE_MODE_USER) : NULL;
    if (pw)
      {
        rc = send_back_passphrase (ctx, opt_data, pw);
            if (!rc)
              {
                if (cacheid)
-                 agent_put_cache (cacheid, CACHE_MODE_USER, response, 0);
+                 agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
                rc = send_back_passphrase (ctx, opt_data, response);
              }
            xfree (response);
@@@ -1593,7 -1593,8 +1593,8 @@@ cmd_clear_passphrase (assuan_context_t 
    if (!*cacheid || strlen (cacheid) > 50)
      return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
  
-   agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
+   agent_put_cache (ctrl, cacheid,
+                    opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
                     NULL, 0);
  
    agent_clear_passphrase (ctrl, cacheid,
@@@ -1770,7 -1771,7 +1771,7 @@@ cmd_passwd (assuan_context_t ctx, char 
                passwd_nonce = bin2hex (buf, 12, NULL);
              }
            if (passwd_nonce
-               && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
+               && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
                                     passphrase, CACHE_TTL_NONCE))
              {
                assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
        char *newpass = NULL;
  
        if (passwd_nonce)
-         newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
+         newpass = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
        err = agent_protect_and_store (ctrl, s_skey, &newpass);
        if (!err && passphrase)
          {
                cache_nonce = bin2hex (buf, 12, NULL);
              }
            if (cache_nonce
-               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+               && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
                                     passphrase, CACHE_TTL_NONCE))
              {
                assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
                    passwd_nonce = bin2hex (buf, 12, NULL);
                  }
                if (passwd_nonce
-                   && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
+                   && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
                                         newpass, CACHE_TTL_NONCE))
                  {
                    assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
          {
          char hexgrip[40+1];
          bin2hex(grip, 20, hexgrip);
-         err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
+         err = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, newpass,
                                   ctrl->cache_ttl_opt_preset);
          }
        xfree (newpass);
@@@ -1939,7 -1940,7 +1940,7 @@@ cmd_preset_passphrase (assuan_context_
  
    if (!rc)
      {
-       rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
+       rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl);
        if (opt_inquire)
        xfree (passphrase);
      }
@@@ -2174,7 -2175,7 +2175,7 @@@ cmd_import_key (assuan_context_t ctx, c
                cache_nonce = bin2hex (buf, 12, NULL);
              }
            if (cache_nonce
-               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+               && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
                                     passphrase, CACHE_TTL_NONCE))
              assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
          }
@@@ -2336,7 -2337,7 +2337,7 @@@ cmd_export_key (assuan_context_t ctx, c
                cache_nonce = bin2hex (buf, 12, NULL);
              }
            if (cache_nonce
-               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+               && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
                                     passphrase, CACHE_TTL_NONCE))
              {
                assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
@@@ -3101,6 -3102,21 +3102,21 @@@ option_handler (assuan_context_t ctx, c
          ctrl->s2k_count = 0;
          }
      }
+   else if (!strcmp (key, "pretend-request-origin"))
+     {
+       log_assert (!ctrl->restricted);
+       switch (parse_request_origin (value))
+         {
+         case REQUEST_ORIGIN_LOCAL:   ctrl->restricted = 0; break;
+         case REQUEST_ORIGIN_REMOTE:  ctrl->restricted = 1; break;
+         case REQUEST_ORIGIN_BROWSER: ctrl->restricted = 2; break;
+         default:
+           err = gpg_error (GPG_ERR_INV_VALUE);
+           /* Better pretend to be remote in case of a bad value.  */
+           ctrl->restricted = 1;
+           break;
+         }
+     }
    else
      err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
  
@@@ -3317,7 -3333,7 +3333,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 agent/cvt-openpgp.c
@@@ -878,11 -878,11 +878,11 @@@ convert_from_openpgp_main (ctrl_t ctrl
    log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
    log_debug ("XXX is_protected=%d\n", is_protected);
    log_debug ("XXX protect_algo=%d\n", protect_algo);
 -  log_printhex ("XXX iv", iv, ivlen);
 +  log_printhex (iv, ivlen, "XXX iv");
    log_debug ("XXX ivlen=%d\n", ivlen);
    log_debug ("XXX s2k_mode=%d\n", s2k_mode);
    log_debug ("XXX s2k_algo=%d\n", s2k_algo);
 -  log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
 +  log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt");
    log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
    log_debug ("XXX curve='%s'\n", curve);
    for (idx=0; skey[idx]; idx++)
          {
            char *cache_value;
  
-           cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+           cache_value = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
            if (cache_value)
              {
                if (strlen (cache_value) < pi->max_length)
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], [6])
 +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,8 -602,9 +614,8 @@@ 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
  AC_SYS_LARGEFILE
  GNUPG_CHECK_USTAR
@@@ -650,7 -639,7 +650,7 @@@ have_android_system=n
  use_simple_gettext=no
  use_ldapwrapper=yes
  mmap_needed=yes
- require_pipe_to_unblock_pselect=no
+ require_pipe_to_unblock_pselect=yes
  case "${host}" in
      *-mingw32*)
          # special stuff for Windoze NT
          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*)
              have_w32ce_system=yes
@@@ -1623,7 -1613,7 +1624,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
  
@@@ -1698,19 -1688,6 +1699,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 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,7 -43,7 +43,7 @@@ 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 \
@@@ -85,7 -85,7 +85,7 @@@ DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPA
  AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css
  
  YAT2M_OPTIONS = -I $(srcdir) \
-         --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.1"
+         --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.2"
  
  myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
                dirmngr.texi scdaemon.texi tools.texi wks.texi
@@@ -112,8 -112,16 +112,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 -154,12 +146,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
@@@ -1126,7 -1126,9 +1126,9 @@@ all affected self-signatures is set on
  @opindex passwd
  Change the passphrase of the secret key belonging to the certificate
  specified as @var{user-id}.  This is a shortcut for the sub-command
- @code{passwd} of the edit key menu.
+ @code{passwd} of the edit key menu.  When using together with the
+ option @option{--dry-run} this will not actually change the passphrase
+ but check that the current passphrase is correct.
  
  @end table
  
@@@ -2213,8 -2215,8 +2215,8 @@@ handy in case where an encrypted messag
  @opindex skip-hidden-recipients
  @opindex no-skip-hidden-recipients
  During decryption skip all anonymous recipients.  This option helps in
- the case that people use the hidden recipients feature to hide there
- own encrypt-to key from others.  If oneself has many secret keys this
+ the case that people use the hidden recipients feature to hide their
+ own encrypt-to key from others.  If one has many secret keys this
  may lead to a major annoyance because all keys are tried in turn to
  decrypt something which was not really intended for it.  The drawback
  of this option is that it is currently not possible to decrypt a
@@@ -2257,16 -2259,6 +2259,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
@@@ -2604,16 -2596,6 +2606,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
@@@ -2645,16 -2627,6 +2647,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
@@@ -2861,12 -2833,6 +2863,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
@@@ -3019,28 -2985,17 +3021,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
@@@ -3062,9 -3017,8 +3064,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 --request-origin @var{origin}
+ @opindex request-origin
+ Tell gpg to assume that the operation ultimately originated at
+ @var{origin}.  Depending on the origin certain restrictions are applied
+ and the Pinentry may include an extra note on the origin.  Supported
+ values for @var{origin} are: @code{local} which is the default,
+ @code{remote} to indicate a remote origin or @code{browser} for an
+ operation requested by a web browser.
  @item --command-fd @var{n}
  @opindex command-fd
  This is a replacement for the deprecated shared-memory IPC mode.
diff --combined doc/gpgsm.texi
@@@ -765,6 -765,15 +765,15 @@@ are
    Pinentry the user is not prompted again if he enters a bad password.
  @end table
  
+ @item --request-origin @var{origin}
+ @opindex request-origin
+ Tell gpgsm to assume that the operation ultimately originated at
+ @var{origin}.  Depending on the origin certain restrictions are applied
+ and the Pinentry may include an extra note on the origin.  Supported
+ values for @var{origin} are: @code{local} which is the default,
+ @code{remote} to indicate a remote origin or @code{browser} for an
+ operation requested by a web browser.
  @item --no-common-certs-import
  @opindex no-common-certs-import
  Suppress the import of common certificates on keybox creation.
@@@ -843,9 -852,15 +852,9 @@@ purposes
  
  Note that even if a certificate is listed in this file, this does not
  mean that the certificate is trusted; in general the certificates listed
 -in this file need to be listed also in @file{trustlist.txt}.
 -
 -This is a global file an installed in the data directory
 -(e.g. @file{@value{DATADIR}/qualified.txt}).  GnuPG installs a suitable
 -file with root certificates as used in Germany.  As new Root-CA
 -certificates may be issued over time, these entries may need to be
 -updated; new distributions of this software should come with an updated
 -list but it is still the responsibility of the Administrator to check
 -that this list is correct.
 +in this file need to be listed also in @file{trustlist.txt}. This is a global
 +file an installed in the sysconf directory (e.g.
 +@file{@value{SYSCONFDIR}/qualified.txt}).
  
  Every time @command{gpgsm} uses a certificate for signing or verification
  this file will be consulted to check whether the certificate under
@@@ -1067,7 -1082,7 +1076,7 @@@ key. The algorithm must be capable of s
  parameter.  The only supported value for @var{algo} is @samp{rsa}.
  
  @item Key-Length: @var{nbits}
 -The requested length of a generated key in bits.  Defaults to 2048.
 +The requested length of a generated key in bits.  Defaults to 3072.
  
  @item Key-Grip: @var{hexstring}
  This is optional and used to generate a CSR or certificate for an
diff --combined g10/call-agent.c
@@@ -195,7 -195,7 +195,7 @@@ warn_version_mismatch (assuan_context_
    err = get_assuan_server_version (ctx, mode, &serverversion);
    if (err)
      log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
 -             GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
 +             GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
               _("error getting version from '%s': %s\n"),
               servername, gpg_strerror (err));
    else if (compare_version_strings (serverversion, myversion) < 0)
@@@ -289,6 -289,23 +289,23 @@@ start_agent (ctrl_t ctrl, int flag_for_
                  }
              }
  
+           /* Pass on the request origin.  */
+           if (opt.request_origin)
+             {
+               char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+                                      str_request_origin (opt.request_origin));
+               rc = assuan_transact (agent_ctx, tmp,
+                                NULL, NULL, NULL, NULL, NULL, NULL);
+               xfree (tmp);
+               if (rc)
+                 {
+                   log_error ("setting request origin '%s' failed: %s\n",
+                              str_request_origin (opt.request_origin),
+                              gpg_strerror (rc));
+                   write_status_error ("set_request_origin", rc);
+                 }
+             }
            /* In DE_VS mode under Windows we require that the JENT RNG
             * is active.  */
  #ifdef HAVE_W32_SYSTEM
@@@ -591,6 -608,8 +608,8 @@@ learn_status_cb (void *opaque, const ch
                      parm->extcap.ki = abool;
                    else if (!strcmp (p, "aac"))
                      parm->extcap.aac = abool;
+                   else if (!strcmp (p, "kdf"))
+                     parm->extcap.kdf = abool;
                    else if (!strcmp (p, "si"))
                      parm->status_indicator = strtoul (p2, NULL, 10);
                  }
@@@ -1493,7 -1512,7 +1512,7 @@@ agent_probe_any_secret_key (ctrl_t ctrl
    char *p;
    kbnode_t kbctx, node;
    int nkeys;
 -  unsigned char grip[20];
 +  unsigned char grip[KEYGRIP_LEN];
  
    err = start_agent (ctrl, 0);
    if (err)
@@@ -1873,16 -1892,10 +1892,16 @@@ agent_pksign (ctrl_t ctrl, const char *
    snprintf (line, sizeof line, "PKSIGN%s%s",
              cache_nonce? " -- ":"",
              cache_nonce? cache_nonce:"");
 +
 +  if (DBG_CLOCK)
 +    log_clock ("enter signing");
    err = assuan_transact (agent_ctx, line,
                           put_membuf_cb, &data,
                           default_inq_cb, &dfltparm,
                           NULL, NULL);
 +  if (DBG_CLOCK)
 +    log_clock ("leave signing");
 +
    if (err)
      xfree (get_membuf (&data, NULL));
    else
diff --combined g10/card-util.c
@@@ -552,9 -552,9 +552,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])
  
  /* Print all available information for specific card with SERIALNO.
     Print all available information for current card when SERIALNO is NULL.
-    Or print llfor all cards when SERIALNO is "all".  */
+    Or print for all cards when SERIALNO is "all".  */
  void
  card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
  {
@@@ -1118,7 -1118,7 +1118,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;
@@@ -1152,8 -1152,7 +1152,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);
@@@ -1347,11 -1345,12 +1347,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")
 +     );
  }
  
  
@@@ -1411,12 -1410,8 +1411,12 @@@ ask_card_keyattr (int keyno, unsigned i
              }
            else
              {
 +              char name[30];
 +
 +              snprintf (name, sizeof name, "rsa%u", req_nbits);
                tty_printf (_("The card will now be re-configured"
 -                            " to generate a key of %u bits\n"), req_nbits);
 +                            " to generate a key of type: %s\n"),
 +                          name);
                show_keysize_warning ();
                return req_nbits;
              }
@@@ -1797,6 -1792,7 +1797,7 @@@ factory_reset (void
          scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
          scd apdu 00 e6 00 00
          scd apdu 00 44 00 00
+         scd reset
          /echo Card has been reset to factory defaults
  
        but tries to find out something about the card first.
    else if (err)
      {
        log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
-       return;
+       goto leave;
      }
  
    if (!termstate)
           command because there is no machinery in scdaemon to catch
           the verify command and ask for the PIN when the "APDU"
           command is used. */
+       /* Here, the length of dummy wrong PIN is 32-byte, also
+          supporting authentication with KDF DO.  */
        for (i=0; i < 4; i++)
-         send_apdu ("00200081084040404040404040", "VERIFY", 0xffff);
+         send_apdu ("0020008120"
+                    "40404040404040404040404040404040"
+                    "40404040404040404040404040404040", "VERIFY", 0xffff);
        for (i=0; i < 4; i++)
-         send_apdu ("00200083084040404040404040", "VERIFY", 0xffff);
+         send_apdu ("0020008320"
+                    "40404040404040404040404040404040"
+                    "40404040404040404040404040404040", "VERIFY", 0xffff);
  
        /* Send terminate datafile command.  */
        err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
  
    /* Finally we reset the card reader once more.  */
    err = send_apdu (NULL, "RESET", 0);
-   if (err)
-     goto leave;
+   /* Then, connect the card again.  */
+   if (!err)
+     {
+       char *serialno0;
+       err = agent_scd_serialno (&serialno0, NULL);
+       if (!err)
+         xfree (serialno0);
+     }
  
   leave:
    xfree (answer);
  }
  
  
+ #define USER_PIN_DEFAULT "123456"
+ #define ADMIN_PIN_DEFAULT "12345678"
+ #define KDF_DATA_LENGTH 110
+ /* Generate KDF data.  */
+ static gpg_error_t
+ gen_kdf_data (unsigned char *data)
+ {
+   const unsigned char h0[] = { 0x81, 0x01, 0x03,
+                                0x82, 0x01, 0x08,
+                                0x83, 0x04 };
+   const unsigned char h1[] = { 0x84, 0x08 };
+   const unsigned char h2[] = { 0x85, 0x08 };
+   const unsigned char h3[] = { 0x86, 0x08 };
+   const unsigned char h4[] = { 0x87, 0x20 };
+   const unsigned char h5[] = { 0x88, 0x20 };
+   unsigned char *p, *salt_user, *salt_admin;
+   unsigned char s2k_char;
+   unsigned int iterations;
+   unsigned char count_4byte[4];
+   gpg_error_t err = 0;
+   p = data;
+   s2k_char = encode_s2k_iterations (0);
+   iterations = S2K_DECODE_COUNT (s2k_char);
+   count_4byte[0] = (iterations >> 24) & 0xff;
+   count_4byte[1] = (iterations >> 16) & 0xff;
+   count_4byte[2] = (iterations >>  8) & 0xff;
+   count_4byte[3] = (iterations & 0xff);
+   memcpy (p, h0, sizeof h0);
+   p += sizeof h0;
+   memcpy (p, count_4byte, sizeof count_4byte);
+   p += sizeof count_4byte;
+   memcpy (p, h1, sizeof h1);
+   salt_user = (p += sizeof h1);
+   gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+   p += 8;
+   memcpy (p, h2, sizeof h2);
+   p += sizeof h2;
+   gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+   p += 8;
+   memcpy (p, h3, sizeof h3);
+   salt_admin = (p += sizeof h3);
+   gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+   p += 8;
+   memcpy (p, h4, sizeof h4);
+   p += sizeof h4;
+   err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
+                          GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
+                          salt_user, 8, iterations, 32, p);
+   p += 32;
+   if (!err)
+     {
+       memcpy (p, h5, sizeof h5);
+       p += sizeof h5;
+       err = gcry_kdf_derive (ADMIN_PIN_DEFAULT, strlen (ADMIN_PIN_DEFAULT),
+                              GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
+                              salt_admin, 8, iterations, 32, p);
+     }
+   return err;
+ }
+ /* Setup KDF data object which is used for PIN authentication.  */
+ static void
+ kdf_setup (void)
+ {
+   struct agent_card_info_s info;
+   gpg_error_t err;
+   unsigned char kdf_data[KDF_DATA_LENGTH];
+   memset (&info, 0, sizeof info);
+   err = agent_scd_getattr ("EXTCAP", &info);
+   if (err)
+     {
+       log_error (_("error getting card info: %s\n"), gpg_strerror (err));
+       return;
+     }
+   if (!info.extcap.kdf)
+     {
+       log_error (_("This command is not supported by this card\n"));
+       goto leave;
+     }
+   if (!(err = gen_kdf_data (kdf_data))
+       && !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL)))
+     err = agent_scd_getattr ("KDF", &info);
+   if (err)
+     log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
+  leave:
+   agent_release_card_info (&info);
+ }
  \f
  /* Data used by the command parser.  This needs to be outside of the
     function scope to allow readline based command completion.  */
@@@ -1896,7 -2004,7 +2009,7 @@@ enum cmdid
      cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
      cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
      cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
-     cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET,
+     cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
      cmdINVCMD
    };
  
@@@ -1921,8 -2029,7 +2034,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")},
      { "verify"  , cmdVERIFY, 0, N_("verify the PIN and list all data")},
      { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
      { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
+     { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
      /* Note, that we do not announce these command yet. */
      { "privatedo", cmdPRIVATEDO, 0, NULL },
      { "readcert", cmdREADCERT, 0, NULL },
@@@ -2213,6 -2321,10 +2327,10 @@@ card_edit (ctrl_t ctrl, strlist_t comma
            factory_reset ();
            break;
  
+         case cmdKDFSETUP:
+           kdf_setup ();
+           break;
          case cmdQUIT:
            goto leave;
  
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,
      oDisableSignerUID,
      oSender,
      oKeyOrigin,
+     oRequestOrigin,
  
      oNoop
    };
@@@ -598,7 -593,6 +599,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_s (oPassphraseFile,  "passphrase-file", "@"),
    ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
    ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+   ARGPARSE_s_s (oRequestOrigin,   "request-origin", "@"),
    ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
    ARGPARSE_s_s (oCommandFile, "command-file", "@"),
    ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
    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", "@"),
  
@@@ -958,8 -946,6 +960,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) );
@@@ -1022,18 -1008,6 +1024,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
@@@ -1054,7 -1028,7 +1056,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,
@@@ -1148,7 -1115,6 +1150,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)))
          {
@@@ -1280,10 -1245,6 +1282,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));
  }
  
  
@@@ -2164,7 -2125,6 +2166,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;
  
@@@ -2328,14 -2286,12 +2330,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;
                log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
            break;
  
+           case oRequestOrigin:
+           opt.request_origin = parse_request_origin (pargs.r.ret_str);
+           if (opt.request_origin == -1)
+               log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
+           break;
          case oCommandFD:
              opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
            if (! gnupg_fd_valid (opt.command_fd))
          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;
        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
diff --combined g10/gpg.h
+++ b/g10/gpg.h
     correct value and may be of advantage if we ever have to do
     special things. */
  
+ #ifdef HAVE_W32_SYSTEM
+ # define WIN32_LEAN_AND_MEAN 1
+ #endif
  #ifdef GPG_ERR_SOURCE_DEFAULT
  #error GPG_ERR_SOURCE_DEFAULT already defined
  #endif
  #define MAX_EXTERN_MPI_BITS 16384
  
  /* The maximum length of a binary fingerprints.  This is used to
 -   provide a static buffer and will be increased if we need to support
 -   longer fingerprints.
 -   Warning: At some places we still use 20 instead of this macro. */
 -#define MAX_FINGERPRINT_LEN 20
 + * provide a static buffer and will be increased if we need to support
 + * longer fingerprints.  Warning: At some places we have some
 + * assumption on a 20 byte fingerprint.
 + * Watch out for FIXME(fingerprint) */
 +#define MAX_FINGERPRINT_LEN 32
  
  /* The maximum length of a formatted fingerprint as returned by
 -   format_hexfingerprint().  */
 -#define MAX_FORMATTED_FINGERPRINT_LEN 50
 + * format_hexfingerprint().  */
 +#define MAX_FORMATTED_FINGERPRINT_LEN 59
  
  
  /*
diff --combined g10/keyedit.c
@@@ -1134,15 -1134,17 +1134,17 @@@ change_passphrase (ctrl_t ctrl, kbnode_
            if (err)
              goto leave;
  
+           /* Note that when using --dry-run we don't change the
+            * passphrase but merely verify the current passphrase.  */
            desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
-           err = agent_passwd (ctrl, hexgrip, desc, 0,
+           err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
                                &cache_nonce, &passwd_nonce);
            xfree (desc);
  
            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));
@@@ -3064,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");
@@@ -3343,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/misc.c
@@@ -42,6 -42,7 +42,7 @@@
  #include <time.h>
  #include <process.h>
  #ifdef HAVE_WINSOCK2_H
+ # define WIN32_LEAN_AND_MEAN 1
  # include <winsock2.h>
  #endif
  #include <windows.h>
  #include "../common/zb32.h"
  
  
 +/* FIXME: Libgcrypt 1.9 will support EAX.  Until we kame this a
 + * requirement we hardwire the enum used for EAX.  */
 +#define MY_GCRY_CIPHER_MODE_EAX 14
 +
 +
  #ifdef ENABLE_SELINUX_HACKS
  /* A object and a global variable to keep track of files marked as
     secured. */
@@@ -401,7 -397,7 +402,7 @@@ print_further_info (const char *format
  
    log_info (_("(further info: "));
    va_start (arg_ptr, format);
 -  log_logv (GPGRT_LOG_CONT, format, arg_ptr);
 +  log_logv (GPGRT_LOGLVL_CONT, format, arg_ptr);
    va_end (arg_ptr);
    log_printf (")\n");
  }
@@@ -587,80 -583,6 +588,80 @@@ openpgp_cipher_algo_name (cipher_algo_
  }
  
  
 +/* Return 0 if ALGO is supported.  Return an error if not. */
 +gpg_error_t
 +openpgp_aead_test_algo (aead_algo_t algo)
 +{
 +  /* FIXME: We currently have no easy way to test whether libgcrypt
 +   * implements a mode.  The only way we can do this is to open a
 +   * cipher context with that mode and close it immediately.  That is
 +   * a bit costly.  So we look at the libgcrypt version and assume
 +   * nothing has been patched out.  */
 +  switch (algo)
 +    {
 +    case AEAD_ALGO_NONE:
 +      break;
 +
 +    case AEAD_ALGO_EAX:
 +#if GCRYPT_VERSION_NUMBER < 0x010900
 +      break;
 +#else
 +      return 0;
 +#endif
 +
 +    case AEAD_ALGO_OCB:
 +      return 0;
 +    }
 +
 +  return gpg_error (GPG_ERR_INV_CIPHER_MODE);
 +}
 +
 +
 +/* Map the OpenPGP AEAD algorithm with ID ALGO to a string
 + * representation of the algorithm name.  For unknown algorithm IDs
 + * this function returns "?".  */
 +const char *
 +openpgp_aead_algo_name (aead_algo_t algo)
 +{
 +  switch (algo)
 +    {
 +    case AEAD_ALGO_NONE:  break;
 +    case AEAD_ALGO_EAX:   return "EAX";
 +    case AEAD_ALGO_OCB:   return "OCB";
 +    }
 +
 +  return "?";
 +}
 +
 +
 +/* Return information for the AEAD algorithm ALGO.  The corresponding
 + * Libgcrypt ciphermode is stored at R_MODE and the required number of
 + * octets for the nonce at R_NONCELEN.  On error and error code is
 + * returned.  Note that the taglen is always 128 bits.  */
 +gpg_error_t
 +openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode,
 +                        unsigned int *r_noncelen)
 +{
 +  switch (algo)
 +    {
 +    case AEAD_ALGO_OCB:
 +      *r_mode = GCRY_CIPHER_MODE_OCB;
 +      *r_noncelen = 15;
 +      break;
 +
 +    case AEAD_ALGO_EAX:
 +      *r_mode = MY_GCRY_CIPHER_MODE_EAX;
 +      *r_noncelen = 16;
 +      break;
 +
 +    default:
 +      log_error ("unsupported AEAD algo %d\n", algo);
 +      return gpg_error (GPG_ERR_INV_CIPHER_MODE);
 +    }
 +  return 0;
 +}
 +
 +
  /* Return 0 if ALGO is a supported OpenPGP public key algorithm.  */
  int
  openpgp_pk_test_algo (pubkey_algo_t algo)
@@@ -1191,39 -1113,6 +1192,39 @@@ string_to_cipher_algo (const char *stri
    return val;
  }
  
 +
 +/*
 + * Map an AEAD mode string to a an AEAD algorithm number as defined by
 + * rrc4880bis.  Also support the "An" syntax as used by the preference
 + * strings.
 + */
 +aead_algo_t
 +string_to_aead_algo (const char *string)
 +{
 +  int result;
 +
 +  if (!string)
 +    result = 0;
 +  if (!ascii_strcasecmp (string, "EAX"))
 +    result = 1;
 +  else if (!ascii_strcasecmp (string, "OCB"))
 +    result = 2;
 +  else if ((string[0]=='A' || string[0]=='a'))
 +    {
 +      char *endptr;
 +
 +      string++;
 +      result = strtol (string, &endptr, 10);
 +      if (!*string || *endptr || result < 1 || result > 2)
 +        result = 0;
 +    }
 +  else
 +    result = 0;
 +
 +  return result;
 +}
 +
 +
  /*
   * Wrapper around gcry_md_map_name to provide a fallback using the
   * "Hn" syntax as used by the preference strings.
@@@ -1340,18 -1229,6 +1341,18 @@@ default_cipher_algo(void
      return opt.s2k_cipher_algo;
  }
  
 +
 +aead_algo_t
 +default_aead_algo(void)
 +{
 +  if(opt.def_aead_algo)
 +    return opt.def_aead_algo;
 +  else if(opt.personal_aead_prefs)
 +    return opt.personal_aead_prefs[0].value;
 +  else
 +    return DEFAULT_AEAD_ALGO;
 +}
 +
  /* There is no default_digest_algo function, but see
     sign.c:hash_for() */
  
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;
  
    int passphrase_repeat;
    int pinentry_mode;
+   int request_origin;
  
    int unwrap_encryption;
    int only_sign_text_ids;
@@@ -322,6 -316,7 +323,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/parse-packet.c
@@@ -1,6 -1,7 +1,6 @@@
  /* parse-packet.c  - read packets
 - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
 - *               2007, 2009, 2010 Free Software Foundation, Inc.
 - * Copyright (C) 2014 Werner Koch
 + * Copyright (C) 1998-2007, 2009-2010 Free Software Foundation, Inc.
 + * Copyright (C) 2014, 2018 Werner Koch
   * Copyright (C) 2015 g10 Code GmbH
   *
   * This file is part of GnuPG.
@@@ -17,7 -18,6 +17,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: GPL-3.0+
   */
  
  #include <config.h>
@@@ -82,9 -82,6 +82,9 @@@ static int parse_compressed (IOBUF inp
                             PACKET * packet, int new_ctb);
  static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
                            PACKET * packet, int new_ctb, int partial);
 +static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype,
 +                                         unsigned long pktlen, PACKET *packet,
 +                                         int partial);
  static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
                      PACKET * packet, int new_ctb);
  static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
@@@ -639,7 -636,6 +639,7 @@@ parse (parse_packet_ctx_t ctx, PACKET *
              case PKT_PLAINTEXT:
              case PKT_ENCRYPTED:
              case PKT_ENCRYPTED_MDC:
 +            case PKT_ENCRYPTED_AEAD:
              case PKT_COMPRESSED:
                iobuf_set_partial_body_length_mode (inp, c & 0xff);
                pktlen = 0;     /* To indicate partial length.  */
      case PKT_MDC:
        rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb);
        break;
 +    case PKT_ENCRYPTED_AEAD:
 +      rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial);
 +      break;
      case PKT_GPG_CONTROL:
        rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial);
        break;
@@@ -971,10 -964,10 +971,10 @@@ skip_packet (IOBUF inp, int pkttype, un
  }
  
  
- /* Read PKTLEN bytes form INP and return them in a newly allocated
-    buffer.  In case of an error (including reading fewer than PKTLEN
-    bytes from INP before EOF is returned), NULL is returned and an
-    error message is logged.  */
+ /* Read PKTLEN bytes from INP and return them in a newly allocated
+  * buffer.  In case of an error (including reading fewer than PKTLEN
+  * bytes from INP before EOF is returned), NULL is returned and an
+  * error message is logged.  */
  static void *
  read_rest (IOBUF inp, size_t pktlen)
  {
@@@ -1105,17 -1098,19 +1105,17 @@@ parse_symkeyenc (IOBUF inp, int pkttype
  {
    PKT_symkey_enc *k;
    int rc = 0;
 -  int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
 +  int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen;
  
    if (pktlen < 4)
 -    {
 -      log_error ("packet(%d) too short\n", pkttype);
 -      if (list_mode)
 -        es_fprintf (listfp, ":symkey enc packet: [too short]\n");
 -      rc = gpg_error (GPG_ERR_INV_PACKET);
 -      goto leave;
 -    }
 +    goto too_short;
    version = iobuf_get_noeof (inp);
    pktlen--;
 -  if (version != 4)
 +  if (version == 4)
 +    ;
 +  else if (version == 5)
 +    ;
 +  else
      {
        log_error ("packet(%d) with unknown version %d\n", pkttype, version);
        if (list_mode)
      }
    cipher_algo = iobuf_get_noeof (inp);
    pktlen--;
 +  if (version == 5)
 +    {
 +      aead_algo = iobuf_get_noeof (inp);
 +      pktlen--;
 +    }
 +  else
 +    aead_algo = 0;
 +  if (pktlen < 2)
 +    goto too_short;
    s2kmode = iobuf_get_noeof (inp);
    pktlen--;
    hash_algo = iobuf_get_noeof (inp);
                                              + seskeylen - 1);
    k->version = version;
    k->cipher_algo = cipher_algo;
 +  k->aead_algo = aead_algo;
    k->s2k.mode = s2kmode;
    k->s2k.hash_algo = hash_algo;
    if (s2kmode == 1 || s2kmode == 3)
    if (list_mode)
      {
        es_fprintf (listfp,
 -                  ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
 -                  version, cipher_algo, s2kmode, hash_algo);
 +                  ":symkey enc packet: version %d, cipher %d, aead %d,"
 +                  " s2k %d, hash %d",
 +                  version, cipher_algo, aead_algo, s2kmode, hash_algo);
        if (seskeylen)
 -      es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
 +        {
 +          /* To compute the size of the session key we need to know
 +           * the size of the AEAD nonce which we may not know.  Thus
 +           * we show only the seize of the entire encrypted session
 +           * key.  */
 +          if (aead_algo)
 +            es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen);
 +          else
 +            es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
 +        }
        es_fprintf (listfp, "\n");
        if (s2kmode == 1 || s2kmode == 3)
        {
   leave:
    iobuf_skip_rest (inp, pktlen, 0);
    return rc;
 +
 + too_short:
 +  log_error ("packet(%d) too short\n", pkttype);
 +  if (list_mode)
 +    es_fprintf (listfp, ":symkey enc packet: [too short]\n");
 +  rc = gpg_error (GPG_ERR_INV_PACKET);
 +  goto leave;
  }
  
  
@@@ -1424,11 -1392,6 +1424,11 @@@ dump_sig_subpkt (int hashed, int type, 
        for (i = 0; i < length; i++)
        es_fprintf (listfp, " %d", buffer[i]);
        break;
 +    case SIGSUBPKT_PREF_AEAD:
 +      es_fputs ("pref-aead-algos:", listfp);
 +      for (i = 0; i < length; i++)
 +        es_fprintf (listfp, " %d", buffer[i]);
 +      break;
      case SIGSUBPKT_REV_KEY:
        es_fputs ("revocation key: ", listfp);
        if (length < 22)
@@@ -1591,7 -1554,6 +1591,7 @@@ parse_one_sig_subpkt (const byte * buff
      case SIGSUBPKT_KEY_FLAGS:
      case SIGSUBPKT_KS_FLAGS:
      case SIGSUBPKT_PREF_SYM:
 +    case SIGSUBPKT_PREF_AEAD:
      case SIGSUBPKT_PREF_HASH:
      case SIGSUBPKT_PREF_COMPR:
      case SIGSUBPKT_POLICY:
@@@ -1674,7 -1636,6 +1674,7 @@@ can_handle_critical (const byte * buffe
      case SIGSUBPKT_ISSUER:    /* issuer key ID */
      case SIGSUBPKT_ISSUER_FPR:        /* issuer fingerprint */
      case SIGSUBPKT_PREF_SYM:
 +    case SIGSUBPKT_PREF_AEAD:
      case SIGSUBPKT_PREF_HASH:
      case SIGSUBPKT_PREF_COMPR:
      case SIGSUBPKT_KEY_FLAGS:
@@@ -1741,6 -1702,8 +1741,8 @@@ enum_sig_subpkt (const subpktarea_t * p
        }
        if (buflen < n)
        goto too_short;
+       if (!buflen)
+         goto no_type_byte;
        type = *buffer;
        if (type & 0x80)
        {
    if (start)
      *start = -1;
    return NULL;
+  no_type_byte:
+   if (opt.verbose)
+     log_info ("type octet missing in subpacket\n");
+   if (start)
+     *start = -1;
+   return NULL;
  }
  
  
@@@ -3200,9 -3170,6 +3209,9 @@@ parse_encrypted (IOBUF inp, int pkttype
    ed->buf = NULL;
    ed->new_ctb = new_ctb;
    ed->is_partial = partial;
 +  ed->aead_algo = 0;
 +  ed->cipher_algo = 0; /* Only used with AEAD.  */
 +  ed->chunkbyte = 0;   /* Only used with AEAD.  */
    if (pkttype == PKT_ENCRYPTED_MDC)
      {
        /* Fixme: add some pktlen sanity checks.  */
@@@ -3294,81 -3261,6 +3303,81 @@@ parse_mdc (IOBUF inp, int pkttype, unsi
  }
  
  
 +static gpg_error_t
 +parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen,
 +                      PACKET *pkt, int partial)
 +{
 +  int rc = 0;
 +  PKT_encrypted *ed;
 +  unsigned long orig_pktlen = pktlen;
 +  int version;
 +
 +  ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted);
 +  if (!ed)
 +    return gpg_error_from_syserror ();
 +  ed->len = 0;
 +  ed->extralen = 0;  /* (only used in build_packet.)  */
 +  ed->buf = NULL;
 +  ed->new_ctb = 1;   /* (packet number requires a new CTB anyway.)  */
 +  ed->is_partial = partial;
 +  ed->mdc_method = 0;
 +  /* A basic sanity check.  We need one version byte, one algo byte,
 +   * one aead algo byte, one chunkbyte, at least 15 byte IV.  */
 +  if (orig_pktlen && pktlen < 19)
 +    {
 +      log_error ("packet(%d) too short\n", pkttype);
 +      if (list_mode)
 +        es_fputs (":aead encrypted packet: [too short]\n", listfp);
 +      rc = gpg_error (GPG_ERR_INV_PACKET);
 +      iobuf_skip_rest (inp, pktlen, partial);
 +      goto leave;
 +    }
 +
 +  version = iobuf_get_noeof (inp);
 +  if (orig_pktlen)
 +    pktlen--;
 +  if (version != 1)
 +    {
 +      log_error ("aead encrypted packet with unknown version %d\n",
 +                 version);
 +      if (list_mode)
 +        es_fputs (":aead encrypted packet: [unknown version]\n", listfp);
 +      /*skip_rest(inp, pktlen); should we really do this? */
 +      rc = gpg_error (GPG_ERR_INV_PACKET);
 +      goto leave;
 +    }
 +
 +  ed->cipher_algo = iobuf_get_noeof (inp);
 +  if (orig_pktlen)
 +    pktlen--;
 +  ed->aead_algo = iobuf_get_noeof (inp);
 +  if (orig_pktlen)
 +    pktlen--;
 +  ed->chunkbyte = iobuf_get_noeof (inp);
 +  if (orig_pktlen)
 +    pktlen--;
 +
 +  /* Store the remaining length of the encrypted data.  We read the
 +   * rest during decryption.  */
 +  ed->len = pktlen;
 +
 +  if (list_mode)
 +    {
 +      es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n",
 +                  ed->cipher_algo, ed->aead_algo, ed->chunkbyte);
 +      if (orig_pktlen)
 +      es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen);
 +      else
 +      es_fprintf (listfp, "\tlength: unknown\n");
 +    }
 +
 +  ed->buf = inp;
 +
 + leave:
 +  return rc;
 +}
 +
 +
  /*
   * This packet is internally generated by us (in armor.c) to transfer
   * some information to the lower layer.  To make sure that this packet
diff --combined g10/tdbdump.c
@@@ -129,7 -129,7 +129,7 @@@ import_ownertrust (ctrl_t ctrl, const c
      char *p;
      size_t n, fprlen;
      unsigned int otrust;
 -    byte fpr[20];
 +    byte fpr[MAX_FINGERPRINT_LEN];
      int any = 0;
      int rc;
  
            continue;
        }
        fprlen = p - line;
 -      if( fprlen != 32 && fprlen != 40 ) {
 +      if( fprlen != 32 && fprlen != 40 && fprlen != 64) {
            log_error (_("error in '%s': %s\n"),
                         fname, _("invalid fingerprint") );
            continue;
        }
        if( !otrust )
            continue; /* no otrust defined - no need to update or insert */
 -      /* convert the ascii fingerprint to binary */
 -      for(p=line, fprlen=0; fprlen < 20 && *p != ':'; p += 2 )
 -          fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
 -      while (fprlen < 20)
 +      /* Convert the ascii fingerprint to binary */
 +      for(p=line, fprlen=0;
 +            fprlen < MAX_FINGERPRINT_LEN && *p != ':';
 +            p += 2 )
 +          fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
 +      while (fprlen < MAX_FINGERPRINT_LEN)
            fpr[fprlen++] = 0;
  
-       rc = tdbio_search_trust_byfpr (fpr, &rec);
+       rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec);
        if( !rc ) { /* found: update */
            if (rec.r.trust.ownertrust != otrust)
                {
diff --combined scd/apdu.c
@@@ -119,6 -119,7 +119,7 @@@ struct reader_table_s 
      pcsc_dword_t modify_ioctl;
      int pinmin;
      int pinmax;
+     pcsc_dword_t current_state;
    } pcsc;
  #ifdef USE_G10CODE_RAPDU
    struct {
@@@ -228,6 -229,7 +229,7 @@@ static npth_mutex_t reader_table_lock
  #define PCSC_E_READER_UNAVAILABLE      0x80100017
  #define PCSC_E_NO_SERVICE              0x8010001D
  #define PCSC_E_SERVICE_STOPPED         0x8010001E
+ #define PCSC_W_RESET_CARD              0x80100068
  #define PCSC_W_REMOVED_CARD            0x80100069
  
  /* Fix pcsc-lite ABI incompatibility.  */
@@@ -453,6 -455,7 +455,7 @@@ new_reader_slot (void
    reader_table[reader].pcsc.modify_ioctl = 0;
    reader_table[reader].pcsc.pinmin = -1;
    reader_table[reader].pcsc.pinmax = -1;
+   reader_table[reader].pcsc.current_state = PCSC_STATE_UNAWARE;
  
    return reader;
  }
@@@ -470,7 -473,7 +473,7 @@@ dump_reader_status (int slot
    if (reader_table[slot].atrlen)
      {
        log_info ("slot %d: ATR=", slot);
 -      log_printhex ("", reader_table[slot].atr, reader_table[slot].atrlen);
 +      log_printhex (reader_table[slot].atr, reader_table[slot].atrlen, "");
      }
  }
  
@@@ -496,7 -499,6 +499,7 @@@ host_sw_string (long err
      case SW_HOST_ABORTED: return "aborted";
      case SW_HOST_NO_PINPAD: return "no pinpad";
      case SW_HOST_ALREADY_CONNECTED: return "already connected";
 +    case SW_HOST_CANCELLED: return "cancelled";
      default: return "unknown host status error";
      }
  }
@@@ -603,7 -605,7 +606,7 @@@ pcsc_error_to_sw (long ec
      {
      case 0:  rc = 0; break;
  
 -    case PCSC_E_CANCELLED:           rc = SW_HOST_ABORTED; break;
 +    case PCSC_E_CANCELLED:           rc = SW_HOST_CANCELLED; break;
      case PCSC_E_NO_MEMORY:           rc = SW_HOST_OUT_OF_CORE; break;
      case PCSC_E_TIMEOUT:             rc = SW_HOST_CARD_IO_ERROR; break;
      case PCSC_E_NO_SERVICE:
@@@ -653,12 -655,12 +656,12 @@@ pcsc_get_status (int slot, unsigned in
    (void)on_wire;
    memset (rdrstates, 0, sizeof *rdrstates);
    rdrstates[0].reader = reader_table[slot].rdrname;
-   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
+   rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
    err = pcsc_get_status_change (reader_table[slot].pcsc.context,
                                  0,
                                  rdrstates, 1);
    if (err == PCSC_E_TIMEOUT)
-     err = 0; /* Timeout is no error error here. */
+     err = 0; /* Timeout is no error here.  */
    if (err)
      {
        log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
        return pcsc_error_to_sw (err);
      }
  
-   /*   log_debug  */
-   /*     ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
-   /*      (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
+   if ((rdrstates[0].event_state & PCSC_STATE_CHANGED))
+     reader_table[slot].pcsc.current_state =
+       (rdrstates[0].event_state & ~PCSC_STATE_CHANGED);
+   if (DBG_CARD_IO)
+     log_debug
+       ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n",
+        (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"",
+        (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"",
+        (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"",
+        (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"",
+        (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"",
+        (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"",
+        (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"",
+        (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"",
+        (rdrstates[0].event_state & PCSC_STATE_INUSE)? " inuse":"",
+        (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" );
  
    *status = 0;
-   if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
+   if ( (reader_table[slot].pcsc.current_state & PCSC_STATE_PRESENT) )
      {
        *status |= APDU_CARD_PRESENT;
-       if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+       if ( !(reader_table[slot].pcsc.current_state & PCSC_STATE_MUTE) )
          *status |= APDU_CARD_ACTIVE;
      }
  #ifndef HAVE_W32_SYSTEM
       mode.  */
    if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
         == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
-        && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
+        && !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE) )
      *status |= APDU_CARD_USABLE;
  #else
    /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
      *status |= APDU_CARD_USABLE;
  #endif
  
-   return 0;
+   if (!on_wire && (rdrstates[0].event_state & PCSC_STATE_CHANGED))
+     /* Event like sleep/resume occurs, which requires RESET.  */
+     return SW_HOST_NO_READER;
+   else
+     return 0;
  }
  
  
@@@ -725,7 -736,7 +737,7 @@@ pcsc_send_apdu (int slot, unsigned cha
      return err;
  
    if (DBG_CARD_IO)
 -    log_printhex ("  PCSC_data:", apdu, apdulen);
 +    log_printhex (apdu, apdulen, "  PCSC_data:");
  
    if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
        send_pci.protocol = PCSC_PROTOCOL_T1;
      log_error ("pcsc_transmit failed: %s (0x%lx)\n",
                 pcsc_error_string (err), err);
  
+   /* Handle fatal errors which require shutdown of reader.  */
+   if (err == PCSC_E_NOT_TRANSACTED || err == PCSC_W_RESET_CARD
+       || err == PCSC_W_REMOVED_CARD)
+     {
+       reader_table[slot].pcsc.current_state = PCSC_STATE_UNAWARE;
+       scd_kick_the_loop ();
+     }
    return pcsc_error_to_sw (err);
  }
  
@@@ -1421,7 -1440,7 +1441,7 @@@ send_apdu_ccid (int slot, unsigned cha
      return err;
  
    if (DBG_CARD_IO)
 -    log_printhex (" raw apdu:", apdu, apdulen);
 +    log_printhex (apdu, apdulen, " raw apdu:");
  
    maxbuflen = *buflen;
    if (pininfo)
@@@ -1690,7 -1709,7 +1710,7 @@@ my_rapdu_send_apdu (int slot, unsigned 
  
    *buflen = 0;
    if (DBG_CARD_IO)
 -    log_printhex ("  APDU_data:", apdu, apdulen);
 +    log_printhex (apdu, apdulen, "  APDU_data:");
  
    if (apdulen < 4)
      {
@@@ -2823,7 -2842,7 +2843,7 @@@ send_le (int slot, int class, int ins, 
        log_debug (" response: sw=%04X  datalen=%d\n",
                   sw, (unsigned int)resultlen);
        if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
 -        log_printhex ("    dump: ", result, resultlen);
 +        log_printhex (result, resultlen, "    dump: ");
      }
  
    if (sw == SW_SUCCESS || sw == SW_EOF_REACHED)
                log_debug ("     more: sw=%04X  datalen=%d\n",
                           sw, (unsigned int)resultlen);
                if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
 -                log_printhex ("     dump: ", result, resultlen);
 +                log_printhex (result, resultlen, "     dump: ");
              }
  
            if ((sw & 0xff00) == SW_MORE_DATA
    xfree (result_buffer);
  
    if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
 -    log_printhex ("      dump: ", *retbuf, *retbuflen);
 +    log_printhex (*retbuf, *retbuflen, "      dump: ");
  
    return sw;
  }
@@@ -3102,7 -3121,7 +3122,7 @@@ apdu_send_direct (int slot, size_t exte
        log_debug (" response: sw=%04X  datalen=%d\n",
                   sw, (unsigned int)resultlen);
        if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
 -        log_printhex ("     dump: ", result, resultlen);
 +        log_printhex (result, resultlen, "     dump: ");
      }
  
    if (handle_more && (sw & 0xff00) == SW_MORE_DATA)
                log_debug ("     more: sw=%04X  datalen=%d\n",
                           sw, (unsigned int)resultlen);
                if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
 -                log_printhex ("     dump: ", result, resultlen);
 +                log_printhex (result, resultlen, "     dump: ");
              }
  
            if ((sw & 0xff00) == SW_MORE_DATA
      }
  
    if (DBG_CARD_IO && retbuf)
 -    log_printhex ("      dump: ", *retbuf, *retbuflen);
 +    log_printhex (*retbuf, *retbuflen, "      dump: ");
  
    return 0;
  }
diff --combined scd/app-openpgp.c
@@@ -98,7 -98,7 +98,7 @@@ static struct 
    { 0x0065, 1,    0, 1, 0, 0, 0, 0, "Cardholder Related Data"},
    { 0x005B, 0, 0x65, 0, 0, 0, 0, 0, "Name" },
    { 0x5F2D, 0, 0x65, 0, 0, 0, 0, 0, "Language preferences" },
 -  { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Sex" },
 +  { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Salutation" },
    { 0x006E, 1,    0, 1, 0, 0, 0, 0, "Application Related Data" },
    { 0x004F, 0, 0x6E, 1, 0, 0, 0, 0, "AID" },
    { 0x0073, 1,    0, 1, 0, 0, 0, 0, "Discretionary Data Objects" },
@@@ -563,7 -563,7 +563,7 @@@ dump_all_do (int slot
            if (data_objects[i].binary)
              {
                log_info ("DO '%s': ", data_objects[i].desc);
 -              log_printhex ("", buffer, buflen);
 +              log_printhex (buffer, buflen, "");
              }
            else
              log_info ("DO '%s': '%.*s'\n",
                            if (valuelen > 200)
                              log_info ("[%u]\n", (unsigned int)valuelen);
                            else
 -                            log_printhex ("", value, valuelen);
 +                            log_printhex (value, valuelen, "");
                          }
                        else
                          log_info ("DO '%s': '%.*s'\n",
@@@ -1018,7 -1018,7 +1018,7 @@@ do_getattr (app_t app, ctrl_t ctrl, con
  
        snprintf (tmp, sizeof tmp,
                  "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d "
-                 "sm=%d si=%u dec=%d bt=%d",
+                 "sm=%d si=%u dec=%d bt=%d kdf=%d",
                  app->app_local->extcap.get_challenge,
                  app->app_local->extcap.key_import,
                  app->app_local->extcap.change_force_chv,
                   : 0),
                  app->app_local->status_indicator,
                  app->app_local->extcap.has_decrypt,
-                 app->app_local->extcap.has_button);
+                 app->app_local->extcap.has_button,
+                 app->app_local->extcap.kdf_do);
        send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
        return 0;
      }
@@@ -5047,7 -5048,7 +5048,7 @@@ parse_algorithm_attribute (app_t app, i
        curve = ecc_curve (buffer + 1, oidlen);
  
        if (!curve)
 -        log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1);
 +        log_printhex (buffer+1, buflen-1, "Curve with OID not supported: ");
        else
          {
            app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
          }
      }
    else if (opt.verbose)
 -    log_printhex ("", buffer, buflen);
 +    log_printhex (buffer, buflen, "");
  
    xfree (relptr);
  }
@@@ -5107,7 -5108,7 +5108,7 @@@ app_select_openpgp (app_t app
        if (opt.verbose)
          {
            log_info ("AID: ");
 -          log_printhex ("", buffer, buflen);
 +          log_printhex (buffer, buflen, "");
          }
  
        app->card_version = buffer[6] << 8;
            if (opt.verbose)
              {
                log_info ("Historical Bytes: ");
 -              log_printhex ("", buffer, buflen);
 +              log_printhex (buffer, buflen, "");
              }
            parse_historical (app->app_local, buffer, buflen);
            xfree (relptr);
diff --combined sm/gpgsm.c
@@@ -125,6 -125,7 +125,7 @@@ enum cmd_and_opt_values 
  
    oPassphraseFD,
    oPinentryMode,
+   oRequestOrigin,
  
    oAssumeArmor,
    oAssumeBase64,
    oWithMD5Fingerprint,
    oWithKeygrip,
    oWithSecret,
 +  oWithKeyScreening,
    oAnswerYes,
    oAnswerNo,
    oKeyring,
@@@ -255,6 -255,7 +256,7 @@@ static ARGPARSE_OPTS opts[] = 
  
    ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
    ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+   ARGPARSE_s_s (oRequestOrigin,   "request-origin", "@"),
  
    ARGPARSE_s_n (oAssumeArmor, "assume-armor",
                  N_("assume input is in PEM format")),
    ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
    ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
    ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
 +  ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
    ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
    ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
    ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
@@@ -1162,6 -1162,12 +1164,12 @@@ main ( int argc, char **argv
              log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
          break;
  
+         case oRequestOrigin:
+           opt.request_origin = parse_request_origin (pargs.r.ret_str);
+           if (opt.request_origin == -1)
+             log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
+           break;
            /* Input encoding selection.  */
          case oAssumeArmor:
            ctrl.autodetect_encoding = 0;
            opt.with_keygrip = 1;
            break;
  
 +        case oWithKeyScreening:
 +          opt.with_key_screening = 1;
 +          break;
 +
          case oOptions:
            /* config files may not be nested (silently ignore them) */
            if (!configfp)
          /* The next one is an info only item and should match what
             proc_parameters actually implements.  */
          es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
 -                   "RSA-2048");
 -        es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg");
 +                   "RSA-3072");
  
        }
        break;
diff --combined sm/gpgsm.h
@@@ -85,9 -85,8 +85,10 @@@ struc
  
    int with_keygrip; /* Option --with-keygrip active.  */
  
 +  int with_key_screening; /* Option  --with-key-screening active.  */
 +
    int pinentry_mode;
+   int request_origin;
  
    int armor;        /* force base64 armoring (see also ctrl.with_base64) */
    int no_armor;     /* don't try to figure out whether data is base64 armored*/
@@@ -260,7 -259,6 +261,7 @@@ unsigned long gpgsm_get_short_fingerpri
  unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
  char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert);
  int  gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits);
 +gcry_mpi_t gpgsm_get_rsa_modulus (ksba_cert_t cert);
  char *gpgsm_get_certid (ksba_cert_t cert);