diff --git a/NEWS b/NEWS
index c13006e9c..a3058e931 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5147 +1,5148 @@
 Noteworthy changes in version 2.2.42 (unreleased)
 -------------------------------------------------
 
   * gpg: Set default expiration date to 3 years.  [T2701]
 
   * gpg: Support OCB encryption.  [T6263]
 
   * gpg: New command --quick-update-pref.  [rGf16c946be7]
 
   * gpg: New list-options show-pref and show-pref-verbose.
     [rGb6ba7054a0]
 
   * gpg: Add modes 16 and 30 to --gen-random.
 
   * gpg: Emit status line and proper diagnostics for write errors.
     [T6528]
 
   * gpg: Make progress work for large files on Windows.  [T6534]
 
   * gpgsm: Support ECC certificates.  [T6253]
 
-  * gpg: Make progress work for large files on Windows.  [T6534]
+  * gpgsm: Print PROGRESS status lines.  Add new --input-size-hint.
+    [T6534]
 
   * gpgsm: Also announce AES256-CBC in signatures.  [rGaa397fdcdb21]
 
   Release-info: https://dev.gnupg.org/T6307
 
 
 Noteworthy changes in version 2.2.41 (2022-12-09)
 -------------------------------------------------
 
   * gpg: Add a notation to encryption subkeys in de-vs mode.  [T6279]
 
   * gpg: Fix trusted introducer for mbox only user-ids.  [T6238]
 
   * gpg: Report an error via status-fd for receiving a key from the
     agent.  [T5151]
 
   * gpg: Make --require-compliance work without the --status-fd
     option.  [r11f3232716]
 
   * gpg: Improve signature verification speed by a factor of more than
     four.  Double detached signing speed.  [T5826]
 
   * gpg: New --export-filter export-revocs.  [rGedbe30c152]
 
   * gpg: Import stray revocation certificates to improve WKD
     usability.  [rGbd825ead36af]
 
   * wkd: New option --add-revocs for gpg-wks-client.  [rG2f4492f3be]
 
   * wkd: Ignore expired user-ids in gpg-wks-client.  [T6292]
 
   * scd: Support the Telesec Signature Card v2.0.  [T6252]
 
   * Fix build regression depending on libgpg-error version.  [T6244]
 
   Release-info: https://dev.gnupg.org/T6280
 
 
 Noteworthy changes in version 2.2.40 (2022-10-10)
 -------------------------------------------------
 
   * gpg: Do not consider unknown public keys as non-compliant while
     decrypting.  [T6205]
 
   * gpg: Avoid to emit a compliance mode line if Libgcrypt is
     non-compliant.  [T6221]
 
   * gpg: In de-vs mode use AES-128 instead of 3-DES as implicit
     preference.  [T6063]
 
   * gpgsm: Fix reporting of bad passphrase error during PKCS#11
     import.  [T5713,T6037]
 
   * dirmngr: Fix CRL Distribution Point fallback to other schemes.
     [rG289fbc550d]
 
   * dirmngr: New LDAP server flag "areconly" (A-record-only).
     [rG6300035ba1]
 
   * dirmngr: Fix upload of multiple keys for an LDAP server specified
     using the colon format.  [rG32ce7ac0c6]
 
   * dirmngr: Use LDAP schema v2 when a Base DN is specified.  [T6047]
 
   * wkd: New command --mirror for gpg-wks-client.  [T6224]
 
   Release-info: https://dev.gnupg.org/T6181
 
 
 Noteworthy changes in version 2.2.39 (2022-09-02)
 -------------------------------------------------
 
   * agent: Fix regression in 2.2.37 related to non-extended format
     private keys.  [T6176]
 
   Release-info: https://dev.gnupg.org/T6175
 
 
 Noteworthy changes in version 2.2.38 (2022-09-01)
 -------------------------------------------------
 
   * gpg: Make --require-compliance work for sign+encrypt.  [T6174]
 
   * gpg: Fix an encoding problem under Windows in the printed
     timezone.  [T5073]
 
   * gpg: Emit a FAILURE status for --require-compliance errors.
     [rGe05fb5ca37]
 
   * dirmngr: Avoid caching expired certificates.  [T6142]
 
   Release-info: https://dev.gnupg.org/T6159
 
 
 Noteworthy changes in version 2.2.37 (2022-08-24)
 -------------------------------------------------
 
   * gpg: In de-vs mode use SHA-256 instead of SHA-1 as implicit
     preference.  [T6043, T6063]
 
   * gpg: Actually show symmetric+pubkey encrypted data as de-vs
     compliant.  Add extra compliance checks for symkey_enc packets.
     [T6119]
 
   * gpg: Request keygrip of key to be added via command-fd interface.
     [T5771]
 
   * gpg: Look up user ID to revoke by UID hash.  [T5936]
 
   * gpg: Fix wrong error message for "keytocard".  [T6122]
 
   * gpg: --card-status shows the application type for non-openpgp
     cards again.  [rG8e393e2592]
 
   * gpg: The options --auto-key-import and --include-key-block are
     again listed by gpgconf.  [T6138]
 
   * gpgsm: New option --compatibility-flags.  [rG77b6896f7a]
 
   * agent: New options --no-user-trustlist and --sys-trustlist-name.
     [T5990]
 
   * agent: Track and update the Display-S/N of cards so that the
     "please insert card" prompt may now show more information.  Use
     "gpg --card-status" to update stored card meta data.  [T6135]
 
   * scd:openpgp: Fix problem with ECC algorithm attributes on
     Yubikeys.  [rG225c66f13b87]
 
   * scd:openpgp: Fix problem with Yubikey 5.4 firmware.  [T6070]
 
   * dirmngr: Ask keyservers to provide the key fingerprints.  [T5741]
 
   * ssh: Allow authentication as used by OpenSSH's PQ crypto support.
     [T5935]
 
   * wkd: Fix path traversal attack in gpg-wks-server.  Add the mail
     address to the pending request data.  [rGc1489ca0e1, T6098]
 
   * gpgconf: Improve registry dumping.  [rG6bc9592318]
 
   * Silence warnings from AllowSetForegroundWindow.  [rG6583abedf3]
 
   Release-info: https://dev.gnupg.org/T6105
 
 
 Noteworthy changes in version 2.2.36 (2022-07-06)
 -------------------------------------------------
 
   * g10: Fix possibly garbled status messages in NOTATION_DATA.  This
     bug could trick GPGME and other parsers to accept faked status
     lines.  [T6027, CVE-2022-34903]
 
   * gpg: Handle leading zeroes in Ed25519 private keys and reverse
     change regarding Ed25519 SOS encoding as introduced with 2.2.34.
     [T5120]
 
   * gpg: Allow Unicode file names for iobuf_cancel under Windows.
 
   * gpgsm: Improve pkcs#12 import.  [T6037,T5793,T4921,T4757]
 
   * scd,p15: Fix reading certificates w/o length info.
 
   * scd,p15: Improve the displayed S/N for Technology Nexus cards.
 
   * scd,openpgp: Add workaround for ECC attribute on Yubikey. [T5963]
 
   * scd: Fix use of SCardListReaders for PC/SC.  [T5979]
 
   * gpgconf: New short options -X and -V.
 
   * Make sure to always set CONFIDENTIAL flag in Assuan.  [T5977]
 
   Release-info: https://dev.gnupg.org/T5949
 
 
 Noteworthy changes in version 2.2.35 (2022-04-25)
 -------------------------------------------------
 
   * gpg,gpgsm: New option --require-compliance.  [17890d4318]
 
   * gpgtar: New option --with-log.  [rGce69d55f70]
 
   * gpg: Threefold decryption speedup for large files.
     [T5820,rG9116fd1e9a]
 
   * gpgtar: Support file names longer than MAX_PATH.  [rG5492079def]
 
   * scdaemon: Add support for GeNUA cards.  [rG44ec383cde]
 
   * gpg: Allow decryption of symmetric encrypted data even for
     non-compliant cipher.  [rGe081a601f7]
 
   * gpg: Avoid possible race condition in --edit-card/factory-reset.
     [T5831]
 
   * gpg: Emit an ERROR status as hint for a bad passphrase.  [T5943]
 
   * gpg: Avoid NULL-ptr access due to corrupted packets.  [T5940]
 
   * gpgsm: Fix parsing of certain PKCS#12 files.  [T5793]
 
   * gpgtar: Use a pipe for decryption and thus avoid memory
     exhaustion.  [rGd431feb307]
 
   * scdaemon: Use extended mode for pkcs#15 already for rsa2048.
     [rGa2db490de5]
 
   * dirmngr: Make WKD lookups work for resolvers not handling SRV
     records.  [T4729]
 
   * dirmngr: Escape more characters in WKD requests.  [T5902]
 
   * gpgconf: Silence warnings from parsing the option files.  [T5874]
 
   * Improve removing of stale lockfiles under Unix.  [T5884]
 
   Release-info: https://dev.gnupg.org/T5928
 
 
 Noteworthy changes in version 2.2.34 (2022-02-07)
 -------------------------------------------------
 
   * gpgconf: Backport the improved option reading and writing code
     from 2.3.  [rG7a3a1ef370,T4788]
 
   * gpgconf: Do not list ignored options and mark forced options as
     read-only.  [T5732]
 
   * gpgconf: Correctly show registry entries with --show-configs.
     [T5724]
 
   * gpgconf: Add command aliases -L, -K, and -R.  [rGf16c535eee]
 
   * gpgconf: Tweak the use of the ldapserver option.  [T5801]
 
   * gpgconf: Make "--launch gpg-agent" work again.  [rG5a7ed6dd8f]
 
   * gpg: Accept Ed25519 private keys in modernized encoding.  [T5120]
 
   * gpg: Fix adding the list of ultimate trusted keys.  [T5742]
 
   * gpgsm: New option --ignore-cert-with-oid.  [rGbcf446b70c]
 
   * dirmngr: Avoid initial delay on the first keyserver access in
     presence of --no-use-tor.  [rGdde88897e2]
 
   * scdaemon: Also prefer Yubikeys if no reader port is given.
     [rG38c666ec3f]
 
   * agent: Make missing strings translatable and update German and
     Japanese translations.  [T4777]
 
   * ssh: Fix adding an ed25519 key with a zero length comment.  [T5794]
 
   * gpgtar: Create and handle extended headers to support long file
     names.  [T5754]
 
   * Fix the creation of socket directories under Windows for non-ascii
     account names.  [rG7d1215cb9c]
 
   * Improve the registry HKCU->HKLM fallback.  [rG96db487a4d]
 
   * Prettify the --help output of most commands.
 
   Release-info: https://dev.gnupg.org/T5703
   See-also: gnupg-announce/2022q1/000470.html
 
 
 Noteworthy changes in version 2.2.33 (2021-11-23)
 -------------------------------------------------
 
   * gpg: New option --min-rsa-length.  [rG6ee01c1d26]
 
   * gpg: New option --forbid-gen-key.  [rG985fb25c46]
 
   * gpg: New option --override-compliance-check.  [T5655]
 
   * gpgconf: New command --show-configs.  [rG8fe3f57643]
 
   * agent,dirmngr: New option --steal-socket.  [rG6507c6ab10]
 
   * scd: Improve the selection of the default PC/SC reader.  [T5644]
 
   * gpg: Fix printing of binary notations.  [T5667]
 
   * gpg: Remove stale ultimately trusted keys from the trustdb.  [T5685]
 
   * gpgsm: Detect circular chains in --list-chain.  [rGc9343bec83]
 
   * gpgconf: Create the local option file even if the global file
     exists.  [T5650]
 
   * dirmngr: Make reading resolv.conf more robust.  [T5657]
 
   * gpg-wks-server: Fix created file permissions.  [rGf54feb4470]
 
   * scd: Support longer data for ssh-agent authentication with openpgp
     cards.  [T5682]
 
   * Support gpgconf.ctl for NetBSD and Solaris.  [T5656,T5671]
 
   * Silence "Garbled console data" warning under Windows in most
     cases.
 
   * Silence warning about the rootdir under Unices w/o a mounted /proc
     file system.
 
   * Fix possible build problems about missing include files.  [T5592]
 
   * i18n: Replace the term "PIN-Cache" by "Passswort-Cache" in the
     German translation. [rgf453d52e53]
 
   * i18n: Update the Russian translation.
 
   Release-info: https://dev.gnupg.org/T5641
   See-also: gnupg-announce/2021q4/000467.html
 
 
 Noteworthy changes in version 2.2.32 (2021-10-06)
 -------------------------------------------------
 
   * dirmngr: Fix Let's Encrypt certificate chain validation.  [T5639]
 
   * dirmngr: New option --ignore-cert.  [323a20399d]
 
   * gpg: Fix --list-packets for AEAD packets with unknown key.  [T5584]
 
   Release-info: https://dev.gnupg.org/T5601
   See-also: gnupg-announce/2021q4/000465.html
 
 
 Noteworthy changes in version 2.2.31 (2021-09-15)
 -------------------------------------------------
 
   * agent: Fix a regression in GET_PASSPHRASE.  [#5577]
 
   * scd: Fix an assertion failure in close_pcsc_reader.  [67e1834ad4]
 
   * scd: Add support for PC/SC in "GETINFO reader_list".
 
   Release-info: https://dev.gnupg.org/T5571
   See-also: gnupg-announce/2021q3/000464.html
 
 
 Noteworthy changes in version 2.2.30 (2021-08-26)
 -------------------------------------------------
 
   * gpg: Extended gpg-check-pattern to support accept rules,
     conjunctions, and case-sensitive matching.  [5ca15e58b2]
 
   * agent: New option --pinentry-formatted-passphrase.  [#5553]
 
   * agent: New option --check-sym-passphrase-pattern.  [#5517]
 
   * agent: Use the sysconfdir for the pattern files.  [5ed8e598fa]
 
   * agent: Add "checkpin" inquiry for use by pinentry.  [#5532]
 
   * wkd: Fix client issue with leading or trailing spaces in
     user-ids.  [576e429d41]
 
   * Pass XDG_SESSION_TYPE and QT_QPA_PLATFORM envvars to Pinentry.
     [#3659]
 
   * Under Windows use LOCAL_APPDATA for the socket directory.  [#5537]
 
   Release-info: https://dev.gnupg.org/T5519
   See-also: gnupg-announce/2021q3/000463.html
 
 
 Noteworthy changes in version 2.2.29 (2021-07-04)
 -------------------------------------------------
 
   * Fix regression in 2.2.28 for Yubikey NEO.  [#5487]
 
   * Change the default keyserver to keyserver.ubuntu.com.  This is a
     temporary change due to the shutdown of the SKS keyserver pools.
     [47c4e3e00a]
 
   * gpg: Let --fetch-key return an exit code on failure.  [#5376]
 
   * dirmngr: Fix regression in KS_GET for mail address pattern.
     [#5497]
 
   * Add fallback in case the Windows console can't cope with Unicode.
     [#5491]
 
   * Improve initialization of SPR532 in the CCID driver and make the
     driver more robust.  [#5297,b90c55fa66db]
 
   * Make test suite work in presence of a broken Libgcrypt
     installation.  [#5502]
 
   * Make configure option --disable-ldap work again.
 
   Release-info: https://dev.gnupg.org/T5498
   See-also: gnupg-announce/2021q3/000461.html
 
 
 Noteworthy changes in version 2.2.28 (2021-06-10)
 -------------------------------------------------
 
   * gpg: Auto import keys specified with --trusted-keys.
     [e7251be84c79]
 
   * gpg: Allow decryption w/o public key but with correct card
     inserted.  [e53f6037283e]
 
   * gpg: Allow fingerprint based lookup with --locate-external-key.
     [2af217ecd7e4]
 
   * gpg: Lookup a missing public key of the current card via LDAP.
     [b59af0e2a05a]
 
   * gpg: New option --force-sign-key.  [#4584]
 
   * gpg: Use a more descriptive password prompt for symmetric
     decryption.  [03f83bcda5d1]
 
   * gpg: Do not use the self-sigs-only option for LDAP keyserver
     imports.  [#5387]
 
   * gpg: Keep temp files when opening images via xdg-open.
     [0441ed6e1c]
 
   * gpg: Fix mailbox based search via AKL keyserver method.
     [22fe23f46d31]
 
   * gpg: Fix sending an OpenPGP key with umlaut to an LDAP keyserver.
     [7bf8530e75d0]
 
   * gpg: Allow ECDH with a smartcard returning only the x-coordinate.
     [b203325ce1]
 
   * gpgsm: New option --ldapserver as an alias for --keyserver.  Note
     that configuring servers in gpgsm and gpg is deprecated; please
     use the dirmngr configuration options.
 
   * gpgsm: Support AES-GCM decryption.  [b722fd755c77]
 
   * gpgsm: Support decryption of password protected files.
     [6f31acac767f]
 
   * gpgsm: Lock keyboxes also during a search to fix lockups on
     Windows.  [#4505]
 
   * agent: Skip unknown unknown ssh curves seen on
     cards. [bbf4bd3bfcb5]
 
   * scdaemon: New option --pcsc-shared.  [5eec40f3d827]
 
   * scdaemon: Backport PKCS#15 card support from GnuPG 2.3
     [7637d39fe20e]
 
   * scdaemon: Fix CCID driver for SCM SPR332/SPR532.  [#5297]
 
   * scdaemon: Fix possible PC/SC removed card problem.  [9d83bfb63968]
 
   * scdaemon: Fix unblock PIN by a Reset Code with KDF.  [#5413]
 
   * scdaemon: Support compressed points.  [96577e2e46e4]
 
   * scdaemon: Prettify S/N for Yubikeys and fix reading for early
     Yubikey 5 tokens.  [f8588369bcb0,#5442]
 
   * dirmngr: New option --ldapserver to avoid the need for the
     separate dirmngr_ldapservers.conf file.
 
   * dirmngr: The dirmngr_ldap wrapper has been rewritten to properly
     support ldap-over-tls and starttls for X.509 certificates and
     CRLs.  [39815c023f03]
 
   * dirmngr: OpenPGP LDAP keyservers may now also be configured using
     the same syntax as used for X.509 and CRL LDAP servers.  This
     avoids the former cumbersome quoting rules and adds a flexible set
     of flags to control the connection.  [2b4cddf9086f]
 
   * dirmngr: The "ldaps" scheme of an OpenPGP keyserver URL is now
     interpreted as ldap-with-starttls on port 389.  To use the
     non-standardized ldap-over-tls the new LDAP configuration method
     of the new attribute "gpgNtds" needs to be used.  [55f46b33df08]
 
   * dirmngr: Return the fingerprint as search result also for LDAP
     OpenPGP keyservers.  This requires the modernized LDAP schema.
     [#5441]
 
   * dirmngr: An OpenPGP LDAP search by a mailbox now ignores revoked
     keys.  [b6f8cd7eef4b]
 
   * gpgconf: Make runtime changes with non-default homedir work.
     [c8f0b02936c7]
 
   * gpgconf: Do not translate an empty string to the PO file's meta
     data.  [#5363]
 
   * gpgconf: Fix argv overflow if --homedir is used.  [#5366]
 
   * gpgconf: Return a new pseudo option "compliance_de_vs".
     [9feffc03f364]
 
   * gpgtar: Fix file size computation under Windows.  [198b240b1955]
 
   * Full Unicode support for the Windows command line.  [#4398]
 
   * Fix problem with Windows Job objects and auto start of our
     daemons.  [#4333]
 
   * i18n: In German always use "Passwort" instead of "Passphrase" in
     prompts.
 
   Release-info: https://dev.gnupg.org/T5482
   See-also: gnupg-announce/2021q2/000460.html
 
 
 Noteworthy changes in version 2.2.27 (2021-01-11)
 -------------------------------------------------
 
  * gpg: Fix regression in 2.2.24 for gnupg_remove function under
    Windows.  [#5230]
 
  * gpgconf: Fix case with neither local nor global gpg.conf.  [9f37d3e6f3]
 
  * gpgconf: Fix description of two new options.  [#5221]
 
  * Build Windows installer without timestamps.  Note that the
    Authenticode signatures still carry a timestamp.
 
   Release-info: https://dev.gnupg.org/T5234
   See-also: gnupg-announce/2021q1/000452.html
 
 
 Noteworthy changes in version 2.2.26 (2020-12-21)
 -------------------------------------------------
 
   * gpg: New AKL method "ntds".  [559efd23e9]
 
   * gpg: Fix --trusted-key with fingerprint arg.  [8a2e5025eb]
 
   * scd: Fix writing of ECC keys to an OpenPGP card.  [#5163]
 
   * scd: Make an USB error fix specific to SPR532 readers.  [#5167]
 
   * dirmngr: With new LDAP keyservers store the new attributes.  Never
     store the useless pgpSignerID.  Fix a long standing bug storing
     some keys on an ldap server.  [0e88c73bc9,e47de85382]
 
   * dirmngr: Support the new Active Direcory LDAP schema for
     keyservers.  [ac8ece9266]
 
   * dirmngr: Allow LDAP OpenPGP searches via fingerprint.
     [c75fd75532]
 
   * dirmngr: Do not block other threads during keyserver LDAP calls.
     [15bfd189c0]
 
   * Support global configuration files.  [#4788,a028f24136]
 
   * Fix the iconv fallback handling to UTF-8.  [#5038]
 
   Release-info: https://dev.gnupg.org/T5153
   See-also: gnupg-announce/2020q4/000451.html
 
 
 Noteworthy changes in version 2.2.25 (2020-11-23)
 -------------------------------------------------
 
   * scd: Fix regression in 2.2.24 requiring gpg --card-status before
     signing or decrypting.  [#5065]
 
   * gpgsm: Using Libksba 1.5.0 signatures with a rarely used
     combination of attributes can now be verified.  [#5146]
 
   Release-info: https://dev.gnupg.org/T5140
   See-also: gnupg-announce/2020q4/000450.html
 
 
 Noteworthy changes in version 2.2.24 (2020-11-17)
 -------------------------------------------------
 
   * Allow Unicode file names on Windows almost everywhere.  Note that
     it is still not possible to use Unicode strings on the command
     line.  This change also fixes a regression in 2.2.22 related to
     non-ascii file names.  [#5098]
 
   * Fix localized time printing on Windows.  [#5073]
 
   * gpg: New command --quick-revoke-sig.  [#5093]
 
   * gpg: Do not use weak digest algos if selected by recipient
     preference during sign+encrypt.  [4c181d51a6]
 
   * gpg: Switch to AES256 for symmetric encryption in de-vs mode.
     [166e779634]
 
   * gpg: Silence weak digest warnings with --quiet.  [#4893]
 
   * gpg: Print new status line CANCELED_BY_USER for a cancel during
     symmetric encryption.  [f05d1772c4]
 
   * gpg: Fix the encrypt+sign hash algo preference selection for
     ECDSA.  This is in particular needed for keys created from
     existing smartcard based keys.  [aeed0b93ff]
 
   * agent: Fix secret key import of GnuPG 2.3 generated Ed25519 keys.
     [#5114]
 
   * agent: Keep some permissions of private-keys-v1.d.  [#2312]
 
   * dirmngr: Align sks-keyservers.netCA.pem use between ntbtls and
     gnutls builds.  [e4f3b74c91]
 
   * dirmngr: Fix the pool keyserver case for a single host in the
     pool.  [72e04b03b1a7]
 
   * scd: Fix the use case of verify_chv2 by CHECKPIN.  [61aea64b3c]
 
   * scd: Various improvements to the ccid-driver.  [#4616,#5065]
 
   * scd: Minor fixes for Yubikey [25bec16d0b]
 
   * gpgconf: New option --show-versions.
 
   * w32: Install gpg-check-pattern and example profiles.  Install
     Windows subsystem variant of gpgconf (gpgconf-w32).
 
   * i18n: Complete overhaul and completion of the Italian translation.
     Thanks to Denis Renzi.
 
   * Require Libgcrypt 1.8 because 1.7 has long reached end-of-life.
 
   Release-info: https://dev.gnupg.org/T5052
   See-also: gnupg-announce/2020q4/000449.html
 
 
 Noteworthy changes in version 2.2.23 (2020-09-03)
 -------------------------------------------------
 
   * gpg: Fix AEAD preference list overflow.  [#5050]
 
   * gpg: Fix a possible segv in the key cleaning code.
 
   * gpgsm: Fix a minor RFC2253 parser bug.  [#5037]
 
   * scdaemon: Fix a PIN verify failure on certain OpenPGP card
     implementations.  Regression in 2.2.22.  [#5039]
 
   * po: Fix bug in the Hungarian translation.  Updates for the Czech,
     Polish, and Ukrainian translations.
 
   Release-info: https://dev.gnupg.org/T5045
   See-also: gnupg-announce/2020q3/000448.html
 
 
 Noteworthy changes in version 2.2.22 (2020-08-27)
 -------------------------------------------------
 
   * gpg: Change the default key algorithm to rsa3072.
 
   * gpg: Add regular expression support for Trust Signatures on all
     platforms.  [#4843]
 
   * gpg: Fix regression in 2.2.21 with non-default --passphrase-repeat
     option.  [#4991]
 
   * gpg: Ignore --personal-digest-prefs for ECDSA keys.  [#5021]
 
   * gpgsm: Make rsaPSS a de-vs compliant scheme.
 
   * gpgsm: Show also the SHA256 fingerprint in key listings.
 
   * gpgsm: Do not require a default keyring for --gpgconf-list.  [#4867]
 
   * gpg-agent: Default to extended key format and record the creation
     time of keys.  Add new option --disable-extended-key-format.
 
   * gpg-agent: Support the WAYLAND_DISPLAY envvar.  [#5016]
 
   * gpg-agent: Allow using --gpgconf-list even if HOME does not
     exist.  [#4866]
 
   * gpg-agent: Make the Pinentry work even if the envvar TERM is set
     to the empty string.  [#4137]
 
   * scdaemon: Add a workaround for Gnuk tokens <= 2.15 which wrongly
     incremented the error counter when using the "verify" command of
     "gpg --edit-key" with only the signature key being present.
 
   * dirmngr: Better handle systems with disabled IPv6.  [#4977]
 
   * gpgpslit: Install tool.  It was not installed in the past to avoid
     conflicts with the version installed by GnuPG 1.4.  [#5023]
 
   * gpgtar: Handle Unicode file names on Windows correctly (requires
     libgpg-error 1.39).  [#4083]
 
   * gpgtar: Make --files-from and --null work as documented.  [#5027]
 
   * Build the Windows installer with the new Ntbtls 0.2.0 so that TLS
     connections succeed for servers demanding GCM.
 
   Release-info: https://dev.gnupg.org/T5030
   See-also: gnupg-announce/2020q3/000447.html
 
 
 Noteworthy changes in version 2.2.21 (2020-07-09)
 -------------------------------------------------
 
   * gpg: Improve symmetric decryption speed by about 25%.
     See commit 144b95cc9d.
 
   * gpg: Support decryption of AEAD encrypted data packets.
 
   * gpg: Add option --no-include-key-block. [#4856]
 
   * gpg: Allow for extra padding in ECDH.  [#4908]
 
   * gpg: Only a single pinentry is shown for symmetric encryption if
     the pinentry supports this.  [#4971]
 
   * gpg: Print a note if no keys are given to --delete-key.  [#4959]
 
   * gpg,gpgsm: The ridiculous passphrase quality bar is not anymore
     shown.  [#2103]
 
   * gpgsm: Certificates without a CRL distribution point are now
     considered valid without looking up a CRL.  The new option
     --enable-issuer-based-crl-check can be used to revert to the
     former behaviour.
 
   * gpgsm: Support rsaPSS signature verification.  [#4538]
 
   * gpgsm: Unless CRL checking is disabled lookup a missing issuer
     certificate using the certificate's authorityInfoAccess.  [#4898]
 
   * gpgsm: Print the certificate's serial number also in decimal
     notation.
 
   * gpgsm: Fix possible NULL-deref in messages of --gen-key.  [#4895]
 
   * scd: Support the CardOS 5 based D-Trust Card 3.1.
 
   * dirmngr: Allow http URLs with "LOOKUP --url".
 
   * wkd: Take name of sendmail from configure.  Fixes an OpenBSD
     specific bug.  [#4886]
 
   Release-info: https://dev.gnupg.org/T4897
   See-also: gnupg-announce/2020q3/000446.html
 
 
 Noteworthy changes in version 2.2.20 (2020-03-20)
 -------------------------------------------------
 
   * Protect the error counter against overflow to guarantee that the
     tools can't be tricked into returning success after an error.
 
   * gpg: Make really sure that --verify-files always returns an error.
 
   * gpg: Fix key listing --with-secret if a pattern is given.  [#4061]
 
   * gpg: Fix detection of certain keys used as default-key.  [#4810]
 
   * gpg: Fix default-key selection when a card is available.  [#4850]
 
   * gpg: Fix key expiration and key usage for keys created with a
     creation date of zero.  [4670]
 
   * gpgsm: Fix import of some CR,LF terminated certificates.  [#4847]
 
   * gpg: New options --include-key-block and --auto-key-import to
     allow encrypted replies after an initial signed message.  [#4856]
 
   * gpg: Allow the use of a fingerprint with --trusted-key. [#4855]
 
   * gpg: New property "fpr" for use by --export-filter.
 
   * scdaemon: Disable the pinpad if a KDF DO is used.  [#4832]
 
   * dirmngr: Improve finding OCSP certificates.  [#4536]
 
   * Avoid build problems with LTO or gcc-10. [#4831]
 
   Release-info: https://dev.gnupg.org/T4860
   See-also: gnupg-announce/2020q1/000444.html
 
 
 Noteworthy changes in version 2.2.19 (2019-12-07)
 -------------------------------------------------
 
   * gpg: Fix double free when decrypting for hidden recipients.
     Regression in 2.2.18.  [#4762].
 
   * gpg: Use auto-key-locate for encryption even for mail addressed
     given with angle brackets.  [#4726]
 
   * gpgsm: Add special case for certain expired intermediate
     certificates.  [#4696]
 
   Release-info: https://dev.gnupg.org/T4768
   See-also: gnupg-announce/2019q4/000443.html
 
 
 Noteworthy changes in version 2.2.18 (2019-11-25)
 -------------------------------------------------
 
   * gpg: Changed the way keys are detected on a smartcards; this
     allows the use of non-OpenPGP cards.  In the case of a not very
     likely regression the new option --use-only-openpgp-card is
     available.  [#4681]
 
   * gpg: The commands --full-gen-key and --quick-gen-key now allow
     direct key generation from supported cards.  [#4681]
 
   * gpg: Prepare against chosen-prefix SHA-1 collisions in key
     signatures.  This change removes all SHA-1 based key signature
     newer than 2019-01-19 from the web-of-trust.  Note that this
     includes all key signature created with dsa1024 keys.  The new
     option --allow-weak-key-signatues can be used to override the new
     and safer behaviour.  [#4755,CVE-2019-14855]
 
   * gpg: Improve performance for import of large keyblocks.  [#4592]
 
   * gpg: Implement a keybox compression run.  [#4644]
 
   * gpg: Show warnings from dirmngr about redirect and certificate
     problems (details require --verbose as usual).
 
   * gpg: Allow to pass the empty string for the passphrase if the
     '--passphase=' syntax is used.  [#4633]
 
   * gpg: Fix printing of the KDF object attributes.
 
   * gpg: Avoid surprises with --locate-external-key and certain
     --auto-key-locate settings.  [#4662]
 
   * gpg: Improve selection of best matching key.  [#4713]
 
   * gpg: Delete key binding signature when deleting a subkey.
     [#4665,#4457]
 
   * gpg: Fix a potential loss of key signatures during import with
     self-sigs-only active.  [#4628]
 
   * gpg: Silence "marked as ultimately trusted" diagnostics if
     option --quiet is used.  [#4634]
 
   * gpg: Silence some diagnostics during in key listsing even with
     option --verbose.  [#4627]
 
   * gpg, gpgsm: Change parsing of agent's pkdecrypt results.  [#4652]
 
   * gpgsm: Support AES-256 keys.
 
   * gpgsm: Fix a bug in triggering a keybox compression run if
     --faked-system-time is used.
 
   * dirmngr: System CA certificates are no longer used for the SKS
     pool if GNUTLS instead of NTBTLS is used as TLS library.  [#4594]
 
   * dirmngr: On Windows detect usability of IPv4 and IPv6 interfaces
     to avoid long timeouts.  [#4165]
 
   * scd: Fix BWI value for APDU level transfers to make Gemalto Ezio
     Shield and Trustica Cryptoucan work.  [#4654,#4566]
 
   * wkd: gpg-wks-client --install-key now installs the required policy
     file.
 
   Release-info: https://dev.gnupg.org/T4684
   See-also: gnupg-announce/2019q4/000442.html
 
 
 Noteworthy changes in version 2.2.17 (2019-07-09)
 -------------------------------------------------
 
   * gpg: Ignore all key-signatures received from keyservers.  This
     change is required to mitigate a DoS due to keys flooded with
     faked key-signatures.  The old behaviour can be achieved by adding
       keyserver-options no-self-sigs-only,no-import-clean
     to your gpg.conf.  [#4607]
 
   * gpg: If an imported keyblocks is too large to be stored in the
     keybox (pubring.kbx) do not error out but fallback to an import
     using the options "self-sigs-only,import-clean".  [#4591]
 
   * gpg: New command --locate-external-key which can be used to
     refresh keys from the Web Key Directory or via other methods
     configured with --auto-key-locate.
 
   * gpg: New import option "self-sigs-only".
 
   * gpg: In --auto-key-retrieve prefer WKD over keyservers.  [#4595]
 
   * dirmngr: Support the "openpgpkey" subdomain feature from
     draft-koch-openpgp-webkey-service-07. [#4590].
 
   * dirmngr: Add an exception for the "openpgpkey" subdomain to the
     CSRF protection.  [#4603]
 
   * dirmngr: Fix endless loop due to http errors 503 and 504.  [#4600]
 
   * dirmngr: Fix TLS bug during redirection of HKP requests.  [#4566]
 
   * gpgconf: Fix a race condition when killing components.  [#4577]
 
   Release-info: https://dev.gnupg.org/T4606
   See-also: gnupg-announce/2019q3/000439.html
 
 
 Noteworthy changes in version 2.2.16 (2019-05-28)
 -------------------------------------------------
 
   * gpg,gpgsm: Fix deadlock on Windows due to a keybox sharing
     violation.  [#4505]
 
   * gpg: Allow deletion of subkeys with --delete-key.  This finally
     makes the bang-suffix work as expected for that command.  [#4457]
 
   * gpg: Replace SHA-1 by SHA-256 in self-signatures when updating
     them with --quick-set-expire or --quick-set-primary-uid. [#4508]
 
   * gpg: Improve the photo image viewer selection.  [#4334]
 
   * gpg: Fix decryption with --use-embedded-filename.  [#4500]
 
   * gpg: Remove hints on using the --keyserver option.  [#4512]
 
   * gpg: Fix export of certain secret keys with comments.  [#4490]
 
   * gpg: Reject too long user-ids in --quick-gen-key.  [#4532]
 
   * gpg: Fix a double free in the best key selection code.  [#4462]
 
   * gpg: Fix the key generation dialog for switching back from EdDSA
     to ECDSA.
 
   * gpg: Use AES-192 with SHA-384 to comply with RFC-6637.
 
   * gpg: Use only the addrspec from the Signer's UID subpacket to
     mitigate a problem with another implementation.
 
   * gpg: Skip invalid packets during a keyring listing and sync
     diagnostics with the output.
 
   * gpgsm: Avoid confusing diagnostic when signing with the default
     key.  [#4535]
 
   * agent: Do not delete any secret key in --dry-run mode.
 
   * agent: Fix failures on 64 bit big-endian boxes related to URIs in
     a keyfile.  [#4501]
 
   * agent: Stop scdaemon after a reload with disable-scdaemon newly
     configured.  [#4326]
 
   * dirmngr: Improve caching algorithm for WKD domains.
 
   * dirmngr: Support other hash algorithms than SHA-1 for OCSP.  [#3966]
 
   * gpgconf: Make --homedir work for --launch.  [#4496]
 
   * gpgconf: Before --launch check for a valid config file.  [#4497]
 
   * wkd: Do not import more than 5 keys from one WKD address.
 
   * wkd: Accept keys which are stored in armored format in the
     directory.
 
   * The installer for Windows now comes with signed binaries.
 
   Release-info: https://dev.gnupg.org/T4509
   See-also: gnupg-announce/2019q2/000438.html
 
 
 Noteworthy changes in version 2.2.15 (2019-03-26)
 -------------------------------------------------
 
   * sm: Fix --logger-fd and --status-fd on Windows for non-standard
     file descriptors.
 
   * sm: Allow decryption even if expired keys are configured.  [#4431]
 
   * agent: Change command KEYINFO to print ssh fingerprints with other
     hash algos.
 
   * dirmngr: Fix build problems on Solaris due to the use of reserved
     symbol names.  [#4420]
 
   * wkd: New commands --print-wkd-hash and --print-wkd-url for
     gpg-wks-client.
 
   Release-info: https://dev.gnupg.org/T4434
   See-also: gnupg-announce/2019q1/000436.html
 
 
 Noteworthy changes in version 2.2.14 (2019-03-19)
 -------------------------------------------------
 
   * gpg: Allow import of PGP desktop exported secret keys.  Also avoid
    importing secret keys if the secret keyblock is not valid.  [#4392]
 
   * gpg: Do not error out on version 5 keys in the local keyring.
 
   * gpg: Make invalid primary key algo obvious in key listings.
 
   * sm: Do not mark a certificate in a key listing as de-vs compliant
     if its use for a signature will not be possible.
 
   * sm: Fix certificate creation with key on card.
 
   * sm: Create rsa3072 bit certificates by default.
 
   * sm: Print Yubikey attestation extensions with --dump-cert.
 
   * agent: Fix cancellation handling for scdaemon.
 
   * agent: Support --mode=ssh option for CLEAR_PASSPHRASE.  [#4340]
 
   * scd: Fix flushing of the CA-FPR DOs in app-openpgp.
 
   * scd: Avoid a conflict error with the "undefined" app.
 
   * dirmngr: Add CSRF protection exception for protonmail.
 
   * dirmngr: Fix build problems with gcc 9 in libdns.
 
   * gpgconf: New option --show-socket for use with --launch.
 
   * gpgtar: Make option -C work for archive creation.
 
   Release-info: https://dev.gnupg.org/T4412
   See-also: gnupg-announce/2019q1/000435.html
 
 
 Noteworthy changes in version 2.2.13 (2019-02-12)
 -------------------------------------------------
 
   * gpg: Implement key lookup via keygrip (using the & prefix).
 
   * gpg: Allow generating Ed25519 key from existing key.
 
   * gpg: Emit an ERROR status line if no key was found with -k.
 
   * gpg: Stop early when trying to create a primary Elgamal key.  [#4329]
 
   * gpgsm: Print the card's key algorithms along with their keygrips
     in interactive key generation.
 
   * agent: Clear bogus pinentry cache in the error case.  [#4348]
 
   * scd: Support "acknowledge button" feature.
 
   * scd: Fix for USB INTERRUPT transfer.  [#4308]
 
   * wks: Do no use compression for the the encrypted challenge and
     response.
 
   Release-info: https://dev.gnupg.org/T4290
   See-also: gnupg-announce/2019q1/000434.html
 
 
 Noteworthy changes in version 2.2.12 (2018-12-14)
 -------------------------------------------------
 
   * tools: New commands --install-key and --remove-key for
     gpg-wks-client.  This allows to prepare a Web Key Directory on a
     local file system for later upload to a web server.
 
   * gpg: New --list-option "show-only-fpr-mbox".  This makes the use
     of the new gpg-wks-client --install-key command easier on Windows.
 
   * gpg: Improve processing speed when --skip-verify is used.
 
   * gpg: Fix a bug where a LF was accidentally written to the console.
 
   * gpg: --card-status now shows whether a card has the new KDF
     feature enabled.
 
   * agent: New runtime option --s2k-calibration=MSEC.  New configure
     option --with-agent-s2k-calibration=MSEC.  [#3399]
 
   * dirmngr: Try another keyserver from the pool on receiving a 502,
     503, or 504 error.  [#4175]
 
   * dirmngr: Avoid possible CSRF attacks via http redirects.  A HTTP
     query will not anymore follow a 3xx redirect unless the Location
     header gives the same host.  If the host is different only the
     host and port is taken from the Location header and the original
     path and query parts are kept.
 
   * dirmngr: New command FLUSHCRL to flush all CRLS from disk and
     memory.  [#3967]
 
   * New simplified Chinese translation (zh_CN).
 
   Release-info: https://dev.gnupg.org/T4289
   See-also: gnupg-announce/2018q4/000433.html
 
 
 Noteworthy changes in version 2.2.11 (2018-11-06)
 -------------------------------------------------
 
   * gpgsm: Fix CRL loading when intermediate certicates are not yet
     trusted.
 
   * gpgsm: Fix an error message about the digest algo.  [#4219]
 
   * gpg: Fix a wrong warning due to new sign usage check introduced
     with 2.2.9.  [#4014]
 
   * gpg: Print the "data source" even for an unsuccessful keyserver
     query.
 
   * gpg: Do not store the TOFU trust model in the trustdb.  This
     allows to enable or disable a TOFO model without triggering a
     trustdb rebuild.  [#4134]
 
   * scd: Fix cases of "Bad PIN" after using "forcesig".  [#4177]
 
   * agent: Fix possible hang in the ssh handler.  [#4221]
 
   * dirmngr: Tack the unmodified mail address to a WKD request.  See
     commit a2bd4a64e5b057f291a60a9499f881dd47745e2f for details.
 
   * dirmngr: Tweak diagnostic about missing LDAP server file.
 
   * dirmngr: In verbose mode print the OCSP responder id.
 
   * dirmngr: Fix parsing of the LDAP port.  [#4230]
 
   * wks: Add option --directory/-C to the server.  Always build the
     server on Unix systems.
 
   * wks: Add option --with-colons to the client.  Support sites which
     use the policy file instead of the submission-address file.
 
   * Fix EBADF when gpg et al. are called by broken CGI scripts.
 
   * Fix some minor memory leaks and bugs.
 
   Release-info: https://dev.gnupg.org/T4233
   See-also: gnupg-announce/2018q4/000432.html
 
 
 Noteworthy changes in version 2.2.10 (2018-08-30)
 -------------------------------------------------
 
   * gpg: Refresh expired keys originating from the WKD.  [#2917]
 
   * gpg: Use a 256 KiB limit for a WKD imported key.
 
   * gpg: New option --known-notation.  [#4060]
 
   * scd: Add support for the Trustica Cryptoucan reader.
 
   * agent: Speed up starting during on-demand launching.  [#3490]
 
   * dirmngr: Validate SRV records in WKD queries.
 
   Release-info: https://dev.gnupg.org/T4112
   See-also: gnupg-announce/2018q3/000428.html
 
 
 Noteworthy changes in version 2.2.9 (2018-07-12)
 ------------------------------------------------
 
   * dirmngr: Fix recursive resolver mode and other bugs in the libdns
     code.  [#3374,#3803,#3610]
 
   * dirmngr: When using libgpg-error 1.32 or later a GnuPG build with
     NTBTLS support (e.g. the standard Windows installer) does not
     anymore block for dozens of seconds before returning data.
 
   * gpg: Fix bug in --show-keys which actually imported revocation
     certificates.  [#4017]
 
   * gpg: Ignore too long user-ID and comment packets.  [#4022]
 
   * gpg: Fix crash due to bad German translation.  Improved printf
     format compile time check.
 
   * gpg: Handle missing ISSUER sub packet gracefully in the presence of
     the new ISSUER_FPR.  [#4046]
 
   * gpg: Allow decryption using several passphrases in most cases.
     [#3795,#4050]
 
   * gpg: Command --show-keys now enables the list options
     show-unusable-uids, show-unusable-subkeys, show-notations and
     show-policy-urls by default.
 
   * gpg: Command --show-keys now prints revocation certificates. [#4018]
 
   * gpg: Add revocation reason to the "rev" and "rvs" records of the
     option --with-colons.  [#1173]
 
   * gpg: Export option export-clean does now remove certain expired
     subkeys; export-minimal removes all expired subkeys.  [#3622]
 
   * gpg: New "usage" property for the drop-subkey filters.  [#4019]
 
   Release-info: https://dev.gnupg.org/T4036
   See-also: gnupg-announce/2018q3/000427.html
 
 
 Noteworthy changes in version 2.2.8 (2018-06-08)
 ------------------------------------------------
 
   * gpg: Decryption of messages not using the MDC mode will now lead
     to a hard failure even if a legacy cipher algorithm was used.  The
     option --ignore-mdc-error can be used to turn this failure into a
     warning.  Take care: Never use that option unconditionally or
     without a prior warning.
 
   * gpg: The MDC encryption mode is now always used regardless of the
     cipher algorithm or any preferences.  For testing --rfc2440 can be
     used to create a message without an MDC.
 
   * gpg: Sanitize the diagnostic output of the original file name in
     verbose mode.  [#4012,CVE-2018-12020]
 
   * gpg: Detect suspicious multiple plaintext packets in a more
     reliable way.  [#4000]
 
   * gpg: Fix the duplicate key signature detection code.  [#3994]
 
   * gpg: The options --no-mdc-warn, --force-mdc, --no-force-mdc,
     --disable-mdc and --no-disable-mdc have no more effect.
 
   * gpg: New command --show-keys.
 
   * agent: Add DBUS_SESSION_BUS_ADDRESS and a few other envvars to the
     list of startup environment variables.  [#3947]
 
   See-also: gnupg-announce/2018q2/000425.html
 
 
 Noteworthy changes in version 2.2.7 (2018-05-02)
 ------------------------------------------------
 
   * gpg: New option --no-symkey-cache to disable the passphrase cache
     for symmetrical en- and decryption.
 
   * gpg: The ERRSIG status now prints the fingerprint if that is part
     of the signature.
 
   * gpg: Relax emitting of FAILURE status lines
 
   * gpg: Add a status flag to "sig" lines printed with --list-sigs.
 
   * gpg: Fix "Too many open files" when using --multifile.  [#3951]
 
   * ssh: Return an error for unknown ssh-agent flags.  [#3880]
 
   * dirmngr: Fix a regression since 2.1.16 which caused corrupted CRL
     caches under Windows.  [#2448,#3923]
 
   * dirmngr: Fix a CNAME problem with pools and TLS.  Also use a fixed
     mapping of keys.gnupg.net to sks-keyservers.net.  [#3755]
 
   * dirmngr: Try resurrecting dead hosts earlier (from 3 to 1.5 hours).
 
   * dirmngr: Fallback to CRL if no default OCSP responder is configured.
 
   * dirmngr: Implement CRL fetching via https.  Here a redirection to
     http is explictly allowed.
 
   * dirmngr: Make LDAP searching and CRL fetching work under Windows.
     This stopped working with 2.1.  [#3937]
 
   * agent,dirmngr: New sub-command "getenv" for "getinfo" to ease
     debugging.
 
   See-also: gnupg-announce/2018q2/000424.html
 
 
 Noteworthy changes in version 2.2.6 (2018-04-09)
 ------------------------------------------------
 
   * gpg,gpgsm: New option --request-origin to pretend requests coming
     from a browser or a remote site.
 
   * gpg: Fix race condition on trustdb.gpg updates due to too early
     released lock.  [#3839]
 
   * gpg: Emit FAILURE status lines in almost all cases.  [#3872]
 
   * gpg: Implement --dry-run for --passwd to make checking a key's
     passphrase straightforward.
 
   * gpg: Make sure to only accept a certification capable key for key
     signatures.  [#3844]
 
   * gpg: Better user interaction in --card-edit for the factory-reset
     sub-command.
 
   * gpg: Improve changing key attributes in --card-edit by adding an
     explicit "key-attr" sub-command.  [#3781]
 
   * gpg: Print the keygrips in the --card-status.
 
   * gpg: Improve the OpenPGP card's factory-reset.  [7f765a98fd]
 
   * scd: Support KDF DO setup.  [#3823]
 
   * scd: Fix some issues with PC/SC on Windows.  [#3825]
 
   * scd: Fix suspend/resume handling in the CCID driver.
 
   * scd: Fix a race condition in the CCID driver leading to a segv for
     some readers.  [#5121]
 
   * agent: Evict cached passphrases also via a timer.  [#3829]
 
   * agent: Use separate passphrase caches depending on the request
     origin.  [#3858]
 
   * ssh: Support signature flags.  [#3880]
 
   * dirmngr: Handle failures related to missing IPv6 support
     gracefully.  [#3331]
 
   * Fix corner cases related to specified home directory with
     drive letter on Windows.  [#3720]
 
   * Allow the use of UNC directory names as homedir.  [#3818]
 
   See-also: gnupg-announce/2018q2/000421.html
 
 
 Noteworthy changes in version 2.2.5 (2018-02-22)
 ------------------------------------------------
 
   * gpg: Allow the use of the "cv25519" and "ed25519" short names in
     addition to the canonical curve names in --batch --gen-key.
 
   * gpg: Make sure to print all secret keys with option --list-only
     and --decrypt.  [#3718]
 
   * gpg: Fix the use of future-default with --quick-add-key for
     signing keys.  [#3747]
 
   * gpg: Select a secret key by checking availability under gpg-agent.
     [#1967]
 
   * gpg: Fix reversed prompt texts for --only-sign-text-ids.  [#3787]
 
   * gpg,gpgsm: Fix detection of bogus keybox blobs on 32 bit systems.
     [#3770]
 
   * gpgsm: Fix regression since 2.1 in --export-secret-key-raw which
     got $d mod (q-1)$ wrong.  Note that most tools automatically fixup
     that parameter anyway.
 
   * ssh: Fix a regression in getting the client'd PID on *BSD and
     macOS.
 
   * scd: Support the KDF Data Object of the OpenPGP card 3.3.  [#3152]
 
   * scd: Fix a regression in the internal CCID driver for certain card
     readers.  [#3508]
 
   * scd: Fix a problem on NetBSD killing scdaemon on gpg-agent
     shutdown.  [#3778]
 
   * dirmngr: Improve returned error description on failure of DNS
     resolving.  [#3756]
 
   * wks: Implement command --install-key for gpg-wks-server.
 
   * Add option STATIC=1 to the Speedo build system to allow a build
     with statically linked versions of the core GnuPG libraries.  Also
     use --enable-wks-tools by default by Speedo builds for Unix.
 
   See-also: gnupg-announce/2018q1/000420.html
 
 
 Noteworthy changes in version 2.2.4 (2017-12-20)
 ------------------------------------------------
 
   * gpg: Change default preferences to prefer SHA512.
 
   * gpg: Print a warning when more than 150 MiB are encrypted using a
     cipher with 64 bit block size.
 
   * gpg: Print a warning if the MDC feature has not been used for a
     message.
 
   * gpg: Fix regular expression of domain addresses in trust
     signatures. [#2923]
 
   * agent: New option --auto-expand-secmem to help with high numbers
     of concurrent connections.  Requires libgcrypt 1.8.2 for having
     an effect.  [#3530]
 
   * dirmngr: Cache responses of WKD queries.
 
   * gpgconf: Add option --status-fd.
 
   * wks: Add commands --check and --remove-key to gpg-wks-server.
 
   * Increase the backlog parameter of the daemons to 64 and add
     option --listen-backlog.
 
   * New configure option --enable-run-gnupg-user-socket to first try a
     socket directory which is not removed by systemd at session end.
 
   See-also: gnupg-announce/2017q4/000419.html
 
 
 Noteworthy changes in version 2.2.3 (2017-11-20)
 ------------------------------------------------
 
   * gpgsm: Fix initial keybox creation on Windows. [#3507]
 
   * dirmngr: Fix crash in case of a CRL loading error. [#3510]
 
   * Fix the name of the Windows registry key. [Git#4f5afaf1fd]
 
   * gpgtar: Fix wrong behaviour of --set-filename. [#3500]
 
   * gpg: Silence AKL retrieval messages. [#3504]
 
   * agent: Use clock or clock_gettime for calibration. [#3056]
 
   * agent: Improve robustness of the shutdown pending
     state. [Git#7ffedfab89]
 
   See-also: gnupg-announce/2017q4/000417.html
 
 
 Noteworthy changes in version 2.2.2 (2017-11-07)
 ------------------------------------------------
 
   * gpg: Avoid duplicate key imports by concurrently running gpg
     processes. [#3446]
 
   * gpg: Fix creating on-disk subkey with on-card primary key. [#3280]
 
   * gpg: Fix validity retrieval for multiple keyrings. [Debian#878812]
 
   * gpg: Fix --dry-run and import option show-only for secret keys.
 
   * gpg: Print "sec" or "sbb" for secret keys with import option
     import-show. [#3431]
 
   * gpg: Make import less verbose. [#3397]
 
   * gpg: Add alias "Key-Grip" for parameter "Keygrip" and new
     parameter "Subkey-Grip" to unattended key generation.  [#3478]
 
   * gpg: Improve "factory-reset" command for OpenPGP cards.  [#3286]
 
   * gpg: Ease switching Gnuk tokens into ECC mode by using the magic
     keysize value 25519.
 
   * gpgsm: Fix --with-colon listing in crt records for fields > 12.
 
   * gpgsm: Do not expect X.509 keyids to be unique.  [#1644]
 
   * agent: Fix stucked Pinentry when using --max-passphrase-days. [#3190]
 
   * agent: New option --s2k-count.  [#3276 (workaround)]
 
   * dirmngr: Do not follow https-to-http redirects. [#3436]
 
   * dirmngr: Reduce default LDAP timeout from 100 to 15 seconds. [#3487]
 
   * gpgconf: Ignore non-installed components for commands
     --apply-profile and --apply-defaults. [#3313]
 
   * Add configure option --enable-werror.  [#2423]
 
   See-also: gnupg-announce/2017q4/000416.html
 
 
 Noteworthy changes in version 2.2.1 (2017-09-19)
 ------------------------------------------------
 
   * gpg: Fix formatting of the user id in batch mode key generation
     if only "name-email" is given.
 
   * gpgv: Fix annoying "not suitable for" warnings.
 
   * wks: Convey only the newest user id to the provider.  This is the
     case if different names are used with the same addr-spec.
 
   * wks: Create a complying user id for provider policy mailbox-only.
 
   * wks: Add workaround for posteo.de.
 
   * scd: Fix the use of large ECC keys with an OpenPGP card.
 
   * dirmngr: Use system provided root certificates if no specific HKP
     certificates are configured.  If build with GNUTLS, this was
     already the case.
 
   See-also: gnupg-announce/2017q3/000415.html
 
 
 Noteworthy changes in version 2.2.0 (2017-08-28)
 ------------------------------------------------
 
   This is the new long term stable branch.  This branch will only see
   bug fixes and no new features.
 
   * gpg: Reverted change in 2.1.23 so that --no-auto-key-retrieve is
     again the default.
 
   * Fixed a few minor bugs.
 
   See-also: gnupg-announce/2017q3/000413.html
 
 
 Noteworthy changes in version 2.1.23 (2017-08-09)
 -------------------------------------------------
 
   * gpg: "gpg" is now installed as "gpg" and not anymore as "gpg2".
     If needed, the new configure option --enable-gpg-is-gpg2 can be
     used to revert this.
 
   * gpg: Options --auto-key-retrieve and --auto-key-locate "local,wkd"
     are now used by default.  Note: this enables keyserver and Web Key
     Directory operators to notice when a signature from a locally
     non-available key is being verified for the first time or when
     you intend to encrypt to a mail address without having the key
     locally.  This new behaviour will eventually make key discovery
     much easier and mostly automatic.  Disable this by adding
       no-auto-key-retrieve
       auto-key-locate local
     to your gpg.conf.
 
   * agent: Option --no-grab is now the default.  The new option --grab
     allows to revert this.
 
   * gpg: New import option "show-only".
 
   * gpg: New option --disable-dirmngr to entirely disable network
     access for gpg.
 
   * gpg,gpgsm: Tweaked DE-VS compliance behaviour.
 
   * New configure flag --enable-all-tests to run more extensive tests
     during "make check".
 
   * gpgsm: The keygrip is now always printed in colon mode as
     documented in the man page.
 
   * Fixed connection timeout problem under Windows.
 
   See-also: gnupg-announce/2017q3/000412.html
 
 
 Noteworthy changes in version 2.1.22 (2017-07-28)
 -------------------------------------------------
 
   * gpg: Extend command --quick-set-expire to allow for setting the
     expiration time of subkeys.
 
   * gpg: By default try to repair keys during import.  New sub-option
     no-repair-keys for --import-options.
 
   * gpg,gpgsm: Improved checking and reporting of DE-VS compliance.
 
   * gpg: New options --key-origin and --with-key-origin.  Store the
     time of the last key update from keyservers, WKD, or DANE.
 
   * agent: New option --ssh-fingerprint-digest.
 
   * dimngr: Lower timeouts on keyserver connection attempts and made
     it configurable.
 
   * dirmngr: Tor will now automatically be detected and used.  The
     option --no-use-tor disables Tor detection.
 
   * dirmngr: Now detects a changed /etc/resolv.conf.
 
   * agent,dirmngr: Initiate shutdown on removal of the GnuPG home
     directory.
 
   * gpg: Avoid caching passphrase for failed symmetric encryption.
 
   * agent: Support for unprotected ssh keys.
 
   * dirmngr: Fixed name resolving on systems using only v6
     nameservers.
 
   * dirmngr: Allow the use of TLS over http proxies.
 
   * w32: Change directory of the daemons after startup.
 
   * wks: New man pages for client and server.
 
   * Many other bug fixes.
 
   See-also: gnupg-announce/2017q3/000411.html
 
 
 Noteworthy changes in version 2.1.21 (2017-05-15)
 -------------------------------------------------
 
   * gpg,gpgsm: Fix corruption of old style keyring.gpg files.  This
     bug was introduced with version 2.1.20.  Note that the default
     pubring.kbx format was not affected.
 
   * gpg,dirmngr: Removed the skeleton config file support.  The
     system's standard methods for providing default configuration
     files should be used instead.
 
   * w32: The Windows installer now allows installation of GnuPG
     without Administrator permissions.
 
   * gpg: Fixed import filter property match bug.
 
   * scd: Removed Linux support for Cardman 4040 PCMCIA reader.
 
   * scd: Fixed some corner case bugs in resume/suspend handling.
 
   * Many minor bug fixes and code cleanup.
 
   See-also: gnupg-announce/2017q2/000405.html
 
 
 Noteworthy changes in version 2.1.20 (2017-04-03)
 -------------------------------------------------
 
   * gpg: New properties 'expired', 'revoked', and 'disabled' for the
     import and export filters.
 
   * gpg: New command --quick-set-primary-uid.
 
   * gpg: New compliance field for the --with-colon key listing.
 
   * gpg: Changed the key parser to generalize the processing of local
     meta data packets.
 
   * gpg: Fixed assertion failure in the TOFU trust model.
 
   * gpg: Fixed exporting of zero length user ID packets.
 
   * scd: Improved support for multiple readers.
 
   * scd: Fixed timeout handling for key generation.
 
   * agent: New option --enable-extended-key-format.
 
   * dirmngr: Do not add a keyserver to a new dirmngr.conf.  Dirmngr
     uses a default keyserver.
 
   * dimngr: Do not treat TLS warning alerts as severe error when
     building with GNUTLS.
 
   * dirmngr: Actually take /etc/hosts in account.
 
   * wks: Fixed client problems on Windows.  Published keys are now set
     to world-readable.
 
   * tests: Fixed creation of temporary directories.
 
   * A socket directory for a non standard GNUGHOME is now created on
     the fly under /run/user.  Thus "gpgconf --create-socketdir" is now
     optional.  The use of "gpgconf --remove-socketdir" to clean up
     obsolete socket directories is however recommended to avoid
     cluttering /run/user with useless directories.
 
   * Fixed build problems on some platforms.
 
   See-also: gnupg-announce/2017q2/000404.html
 
 
 Noteworthy changes in version 2.1.19 (2017-03-01)
 -------------------------------------------------
 
   * gpg: Print a warning if Tor mode is requested but the Tor daemon
     is not running.
 
   * gpg: New status code DECRYPTION_KEY to print the actual private
     key used for decryption.
 
   * gpgv: New options --log-file and --debug.
 
   * gpg-agent: Revamp the prompts to ask for card PINs.
 
   * scd: Support for multiple card readers.
 
   * scd: Removed option --debug-disable-ticker.  Ticker is used
     only when it is required to watch removal of device/card.
 
   * scd: Improved detection of card inserting and removal.
 
   * dirmngr: New option --disable-ipv4.
 
   * dirmngr: New option --no-use-tor to explicitly disable the use of
     Tor.
 
   * dirmngr: The option --allow-version-check is now required even if
     the option --use-tor is also used.
 
   * dirmngr: Handle a missing nsswitch.conf gracefully.
 
   * dirmngr: Avoid PTR lookups for keyserver pools.  The are only done
     for the debug command "keyserver --hosttable".
 
   * dirmngr: Rework the internal certificate cache to support classes
     of certificates.  Load system provided certificates on startup.
     Add options --tls, --no-crl, and --systrust to the "VALIDATE"
     command.
 
   * dirmngr: Add support for the ntbtls library.
 
   * wks: Create mails with a "WKS-Phase" header.  Fix detection of
     Draft-2 mode.
 
   * The Windows installer is now build with limited TLS support.
 
   * Many other bug fixes and new regression tests.
 
   See-also: gnupg-announce/2017q1/000402.html
 
 
 Noteworthy changes in version 2.1.18 (2017-01-23)
 -------------------------------------------------
 
   * gpg: Remove bogus subkey signature while cleaning a key (with
     export-clean, import-clean, or --edit-key's sub-command clean)
 
   * gpg: Allow freezing the clock with --faked-system-time.
 
   * gpg: New --export-option flag "backup", new --import-option flag
     "restore".
 
   * gpg-agent: Fixed long delay due to a regression in the progress
     callback code.
 
   * scd: Lots of code cleanup and internal changes.
 
   * scd: Improved the internal CCID driver.
 
   * dirmngr: Fixed problem with the DNS glue code (removal of the
     trailing dot in domain names).
 
   * dirmngr: Make sure that Tor is actually enabled after changing the
     conf file and sending SIGHUP or "gpgconf --reload dirmngr".
 
   * dirmngr: Fixed Tor access to IPv6 addresses.  Note that current
     versions of Tor may require that the flag "IPv6Traffic" is used
     with the option "SocksPort" in torrc to actually allow IPv6
     traffic.
 
   * dirmngr: Fixed HKP for literally given IPv6 addresses.
 
   * dirmngr: Enabled reverse DNS lookups via Tor.
 
   * dirmngr: Added experimental SRV record lookup for WKD.
     See commit 88dc3af3d4ae1afe1d5e136bc4c38bc4e7d4cd10 for details.
 
   * dirmngr: For HKP use "pgpkey-hkps" and "pgpkey-hkp" in SRV record
     lookups.  Avoid SRV record lookup when a port is explicitly
     specified.  This fixes a regression from the 1.4 and 2.0 behavior.
 
   * dirmngr: Gracefully handle a missing /etc/nsswitch.conf.  Ignore
     negation terms (e.g. "[!UNAVAIL=return]" instead of bailing out.
 
   * dirmngr: Better debug output for flags "dns" and "network".
 
   * dirmngr: On reload mark all known HKP servers alive.
 
   * gpgconf: Allow keyword "all" for --launch, --kill, and --reload.
 
   * tools: gpg-wks-client now ignores a missing policy file on the
     server.
 
   * Avoid unnecessary ambiguity error message in the option parsing.
 
   * Further improvements of the regression test suite.
 
   * Fixed building with --disable-libdns configure option.
 
   * Fixed a crash running the tests on 32 bit architectures.
 
   * Fixed spurious failures on BSD system in the spawn functions.
     This affected for example gpg-wks-client and gpgconf.
 
   See-also: gnupg-announce/2017q1/000401.html
 
 
 Noteworthy changes in version 2.1.17 (2016-12-20)
 -------------------------------------------------
 
  * gpg: By default new keys expire after 2 years.
 
  * gpg: New command --quick-set-expire to conveniently change the
    expiration date of keys.
 
  * gpg: Option and command names have been changed for easier
    comprehension.  The old names are still available as aliases.
 
  * gpg: Improved the TOFU trust model.
 
  * gpg: New option --default-new-key-algo.
 
  * scd: Support OpenPGP card V3 for RSA.
 
  * dirmngr: Support for the ADNS library has been removed.  Instead
    William Ahern's Libdns is now source included and used on all
    platforms.  This enables Tor support on all platforms.  The new
    option --standard-resolver can be used to disable this code at
    runtime.  In case of build problems the new configure option
    --disable-libdns can be used to build without Libdns.
 
  * dirmngr: Lazily launch ldap reaper thread.
 
  * tools: New options --check and --status-fd for gpg-wks-client.
 
  * The UTF-8 byte order mark is now skipped when reading conf files.
 
  * Fixed many bugs and regressions.
 
  * Major improvements to the test suite.  For example it is possible
    to run the external test suite of GPGME.
 
  See-also: gnupg-announce/2016q4/000400.html
 
 
 Noteworthy changes in version 2.1.16 (2016-11-18)
 -------------------------------------------------
 
  * gpg: New algorithm for selecting the best ranked public key when
    using a mail address with -r, -R, or --locate-key.
 
  * gpg: New option --with-tofu-info to print a new "tfs" record in
    colon formatted key listings.
 
  * gpg: New option --compliance as an alternative way to specify
    options like --rfc2440, --rfc4880, et al.
 
  * gpg: Many changes to the TOFU implementation.
 
  * gpg: Improve usability of --quick-gen-key.
 
  * gpg: In --verbose mode print a diagnostic when a pinentry is
    launched.
 
  * gpg: Remove code which warns for old versions of gnome-keyring.
 
  * gpg: New option --override-session-key-fd.
 
  * gpg: Option --output does now work with --verify.
 
  * gpgv: New option --output to allow saving the verified data.
 
  * gpgv: New option --enable-special-filenames.
 
  * agent, dirmngr: New --supervised mode for use by systemd and alike.
 
  * agent: By default listen on all available sockets using standard
    names.
 
  * agent: Invoke scdaemon with --homedir.
 
  * dirmngr: On Linux now detects the removal of its own socket and
    terminates.
 
  * scd: Support ECC key generation.
 
  * scd: Support more card readers.
 
  * dirmngr: New option --allow-version-check to download a software
    version database in the background.
 
  * dirmngr: Use system provided CAs if no --hkp-cacert is given.
 
  * dirmngr: Use a default keyserver if none is explicitly set
 
  * gpgconf: New command --query-swdb to check software versions
    against an copy of an online database.
 
  * gpgconf: Print the socket directory with --list-dirs.
 
  * tools: The WKS tools now support draft version -02.
 
  * tools: Always build gpg-wks-client and install under libexec.
 
  * tools: New option --supported for gpg-wks-client.
 
  * The log-file option now accepts a value "socket://" to log to the
    socket named "S.log" in the standard socket directory.
 
  * Provide fake pinentries for use by tests cases of downstream
    developers.
 
  * Fixed many bugs and regressions.
 
  * Many changes and improvements for the test suite.
 
  See-also: gnupg-announce/2016q4/000398.html
 
 
 Noteworthy changes in version 2.1.15 (2016-08-18)
 -------------------------------------------------
 
  * gpg: Remove the --tofu-db-format option and support for the split
    TOFU database.
 
  * gpg: Add option --sender to prepare for coming features.
 
  * gpg: Add option --input-size-hint to help progress indicators.
 
  * gpg: Extend the PROGRESS status line with the counted unit.
 
  * gpg: Avoid publishing the GnuPG version by default with --armor.
 
  * gpg: Properly ignore legacy keys in the keyring cache.
 
  * gpg: Always print fingerprint records in --with-colons mode.
 
  * gpg: Make sure that keygrips are printed for each subkey in
    --with-colons mode.
 
  * gpg: New import filter "drop-sig".
 
  * gpgsm: Fix a bug in the machine-readable key listing.
 
  * gpg,gpgsm: Block signals during keyring updates to limits the
    effects of a Ctrl-C at the wrong time.
 
  * g13: Add command --umount and other fixes for dm-crypt.
 
  * agent: Fix regression in SIGTERM handling.
 
  * agent: Cleanup of the ssh-agent code.
 
  * agent: Allow import of overly long keys.
 
  * scd: Fix problems with card removal.
 
  * dirmngr: Remove all code for running as a system service.
 
  * tools: Make gpg-wks-client conforming to the specs.
 
  * tests: Improve the output of the new regression test tool.
 
  * tests: Distribute the standalone test runner.
 
  * tests: Run each test in a clean environment.
 
  * Spelling and grammar fixes.
 
  See-also: gnupg-announce/2016q3/000396.html
 
 
 Noteworthy changes in version 2.1.14 (2016-07-14)
 -------------------------------------------------
 
  * gpg: Removed options --print-dane-records and --print-pka-records.
    The new export options "export-pka" and "export-dane" can instead
    be used with the export command.
 
  * gpg: New options --import-filter and --export-filter.
 
  * gpg: New import options "import-show" and "import-export".
 
  * gpg: New option --no-keyring.
 
  * gpg: New command --quick-revuid.
 
  * gpg: New options -f/--recipient-file and -F/--hidden-recipient-file
    to directly specify encryption keys.
 
  * gpg: New option --mimemode to indicate that the content is a MIME
    part.  Does only enable --textmode right now.
 
  * gpg: New option --rfc4880bis to allow experiments with proposed
    changes to the current OpenPGP specs.
 
  * gpg: Fix regression in the "fetch" sub-command of --card-edit.
 
  * gpg: Fix regression since 2.1 in option --try-all-secrets.
 
  * gpgv: Change default options for extra security.
 
  * gpgsm: No more root certificates are installed by default.
 
  * agent: "updatestartuptty" does now affect more environment
    variables.
 
  * scd: The option --homedir does now work with scdaemon.
 
  * scd: Support some more GEMPlus card readers.
 
  * gpgtar: Fix handling of '-' as file name.
 
  * gpgtar: New commands --create and --extract.
 
  * gpgconf: Tweak for --list-dirs to better support shell scripts.
 
  * tools: Add programs gpg-wks-client and gpg-wks-server to implement
    a Web Key Service.  The configure option --enable-wks-tools is
    required to build them; they should be considered Beta software.
 
  * tests: Complete rework of the openpgp part of the test suite.  The
    test scripts have been changed from Bourne shell scripts to Scheme
    programs.  A customized scheme interpreter (gpgscm) is included.
    This change was triggered by the need to run the test suite on
    non-Unix platforms.
 
  * The rendering of the man pages has been improved.
 
  See-also: gnupg-announce/2016q3/000393.html
 
 
 Noteworthy changes in version 2.1.13 (2016-06-16)
 -------------------------------------------------
 
  * gpg: New command --quick-addkey.  Extend the --quick-gen-key
    command.
 
  * gpg: New --keyid-format "none" which is now also the default.
 
  * gpg: New option --with-subkey-fingerprint.
 
  * gpg: Include Signer's UID subpacket in signatures if the secret key
    has been specified using a mail address and the new option
    --disable-signer-uid is not used.
 
  * gpg: Allow unattended deletion of a secret key.
 
  * gpg: Allow export of non-passphrase protected secret keys.
 
  * gpg: New status lines KEY_CONSIDERED and NOTATION_FLAGS.
 
  * gpg: Change status line TOFU_STATS_LONG to use '~' as
    a non-breaking-space character.
 
  * gpg: Speedup key listings in Tofu mode.
 
  * gpg: Make sure that the current and total values of a PROGRESS
    status line are small enough.
 
  * gpgsm: Allow the use of AES192 and SERPENT ciphers.
 
  * dirmngr: Adjust WKD lookup to current specs.
 
  * dirmngr: Fallback to LDAP v3 if v2 is is not supported.
 
  * gpgconf: New commands --create-socketdir and --remove-socketdir,
    new option --homedir.
 
  * If a /run/user/$UID directory exists, that directory is now used
    for IPC sockets instead of the GNUPGHOME directory.  This fixes
    problems with NFS and too long socket names and thus avoids the
    need for redirection files.
 
  * The Speedo build systems now uses the new versions.gnupg.org server
    to retrieve the default package versions.
 
  * Fix detection of libusb on FreeBSD.
 
  * Speedup fd closing after a fork.
 
  See-also: gnupg-announce/2016q2/000390.html
 
 
 Noteworthy changes in version 2.1.12 (2016-05-04)
 -------------------------------------------------
 
  * gpg: New --edit-key sub-command "change-usage" for testing
    purposes.
 
  * gpg: Out of order key-signatures are now systematically detected
    and fixed by --edit-key.
 
  * gpg: Improved detection of non-armored messages.
 
  * gpg: Removed the extra prompt needed to create Curve25519 keys.
 
  * gpg: Improved user ID selection for --quick-sign-key.
 
  * gpg: Use the root CAs provided by the system with --fetch-key.
 
  * gpg: Add support for the experimental Web Key Directory key
    location service.
 
  * gpg: Improve formatting of Tofu messages and emit new Tofu specific
    status lines.
 
  * gpgsm: Add option --pinentry-mode to support a loopback pinentry.
 
  * gpgsm: A new pubring.kbx is now created with the header blob so
    that gpg can detect that the keybox format needs to be used.
 
  * agent: Add read support for the new private key protection format
    openpgp-s2k-ocb-aes.
 
  * agent: Add read support for the new extended private key format.
 
  * agent: Default to --allow-loopback-pinentry and add option
    --no-allow-loopback-pinentry.
 
  * scd: Changed to use the new libusb 1.0 API for the internal CCID
    driver.
 
  * dirmngr: The dirmngr-client does now auto-detect the PEM format.
 
  * g13: Add experimental support for dm-crypt.
 
  * w32: Tofu support is now available with the Speedo build method.
 
  * w32: Removed the need for libiconv.dll.
 
  * The man pages for gpg and gpgv are now installed under the correct
    name (gpg2 or gpg - depending on a configure option).
 
  * Lots of internal cleanups and bug fixes.
 
  See-also: gnupg-announce/2016q2/000387.html
 
 
 Noteworthy changes in version 2.1.11 (2016-01-26)
 -------------------------------------------------
 
  * gpg: New command --export-ssh-key to replace the gpgkey2ssh tool.
 
  * gpg: Allow to generate mail address only keys with --gen-key.
 
  * gpg: "--list-options show-usage" is now the default.
 
  * gpg: Make lookup of DNS CERT records holding an URL work.
 
  * gpg: Emit PROGRESS status lines during key generation.
 
  * gpg: Don't check for ambigious or non-matching key specification in
    the config file or given to --encrypt-to.  This feature will return
    in 2.3.x.
 
  * gpg: Lock keybox files while updating them.
 
  * gpg: Solve rare error on Windows during keyring and Keybox updates.
 
  * gpg: Fix possible keyring corruption. (bug#2193)
 
  * gpg: Fix regression of "bkuptocard" sub-command in --edit-key and
    remove "checkbkupkey" sub-command introduced with 2.1.  (bug#2169)
 
  * gpg: Fix internal error in gpgv when using default keyid-format.
 
  * gpg: Fix --auto-key-retrieve to work with dirmngr.conf configured
    keyservers. (bug#2147).
 
  * agent: New option --pinentry-timeout.
 
  * scd: Improve unplugging of USB readers under Windows.
 
  * scd: Fix regression for generating RSA keys on card.
 
  * dirmmgr: All configured keyservers are now searched.
 
  * dirmngr: Install CA certificate for hkps.pool.sks-keyservers.net.
    Use this certiticate even if --hkp-cacert is not used.
 
  * gpgtar: Add actual encryption code.  gpgtar does now fully replace
    gpg-zip.
 
  * gpgtar: Fix filename encoding problem on Windows.
 
  * Print a warning if a GnuPG component is using an older version of
    gpg-agent, dirmngr, or scdaemon.
 
  See-also: gnupg-announce/2016q1/000383.html
 
 
 Noteworthy changes in version 2.1.10 (2015-12-04)
 -------------------------------------------------
 
  * gpg: New trust models "tofu" and "tofu+pgp".
 
  * gpg: New command --tofu-policy.  New options --tofu-default-policy
    and --tofu-db-format.
 
  * gpg: New option --weak-digest to specify hash algorithms which
    should be considered weak.
 
  * gpg: Allow the use of multiple --default-key options; take the last
    available key.
 
  * gpg: New option --encrypt-to-default-key.
 
  * gpg: New option --unwrap to only strip the encryption layer.
 
  * gpg: New option --only-sign-text-ids to exclude photo IDs from key
    signing.
 
  * gpg: Check for ambigious or non-matching key specification in the
    config file or given to --encrypt-to.
 
  * gpg: Show the used card reader with --card-status.
 
  * gpg: Print export statistics and an EXPORTED status line.
 
  * gpg: Allow selecting subkeys by keyid in --edit-key.
 
  * gpg: Allow updating the expiration time of multiple subkeys at
    once.
 
  * dirmngr: New option --use-tor.  For full support this requires
    libassuan version 2.4.2 and a patched version of libadns
    (e.g. adns-1.4-g10-7 as used by the standard Windows installer).
 
  * dirmngr: New option --nameserver to specify the nameserver used in
    Tor mode.
 
  * dirmngr: Keyservers may again be specified by IP address.
 
  * dirmngr: Fixed problems in resolving keyserver pools.
 
  * dirmngr: Fixed handling of premature termination of TLS streams so
    that large numbers of keys can be refreshed via hkps.
 
  * gpg: Fixed a regression in --locate-key [since 2.1.9].
 
  * gpg: Fixed another bug for keyrings with legacy keys.
 
  * gpgsm: Allow combinations of usage flags in --gen-key.
 
  * Make tilde expansion work with most options.
 
  * Many other cleanups and bug fixes.
 
  See-also: gnupg-announce/2015q4/000381.html
 
 
 Noteworthy changes in version 2.1.9 (2015-10-09)
 ------------------------------------------------
 
  * gpg: Allow fetching keys via OpenPGP DANE (--auto-key-locate).  New
    option --print-dane-records.  [Update: --print-dane-records replaced
    in 2.1.4.]
 
  * gpg: Fix for a problem with PGP-2 keys in a keyring.
 
  * gpg: Fail with an error instead of a warning if a modern cipher
    algorithm is used without a MDC.
 
  * agent: New option --pinentry-invisible-char.
 
  * agent: Always do a RSA signature verification after creation.
 
  * agent: Fix a regression in ssh-add-ing Ed25519 keys.
 
  * agent: Fix ssh fingerprint computation for nistp384 and EdDSA.
 
  * agent: Fix crash during passphrase entry on some platforms.
 
  * scd: Change timeout to fix problems with some 2.1 cards.
 
  * dirmngr: Displayed name is now Key Acquirer.
 
  * dirmngr: Add option --keyserver.  Deprecate that option for gpg.
    Install a dirmngr.conf file from a skeleton for new installations.
 
  See-also: gnupg-announce/2015q4/000380.html
 
 
 Noteworthy changes in version 2.1.8 (2015-09-10)
 ------------------------------------------------
 
  * gpg: Sending very large keys to the keyservers works again.
 
  * gpg: Validity strings in key listings are now again translatable.
 
  * gpg: Emit FAILURE status lines to help GPGME.
 
  * gpg: Does not anymore link to Libksba to reduce dependencies.
 
  * gpgsm: Export of secret keys via Assuan is now possible.
 
  * agent: Raise the maximum passphrase length from 100 to 255 bytes.
 
  * agent: Fix regression using EdDSA keys with ssh.
 
  * Does not anymore use a build timestamp by default.
 
  * The fallback encoding for broken locale settings changed
    from Latin-1 to UTF-8.
 
  * Many code cleanups and improved internal documentation.
 
  * Various minor bug fixes.
 
  See-also: gnupg-announce/2015q3/000379.html
 
 
 Noteworthy changes in version 2.1.7 (2015-08-11)
 ------------------------------------------------
 
  * gpg: Support encryption with Curve25519 if Libgcrypt 1.7 is used.
 
  * gpg: In the --edit-key menu: Removed the need for "toggle", changed
    how secret keys are indicated, new commands "fpr *" and "grip".
 
  * gpg: More fixes related to legacy keys in a keyring.
 
  * gpgv: Does now also work with a "trustedkeys.kbx" file.
 
  * scd: Support some feature from the OpenPGP card 3.0 specs.
 
  * scd: Improved ECC support
 
  * agent: New option --force for the DELETE_KEY command.
 
  * w32: Look for the Pinentry at more places.
 
  * Dropped deprecated gpgsm-gencert.sh
 
  * Various other bug fixes.
 
  See-also: gnupg-announce/2015q3/000371.html
 
 
 Noteworthy changes in version 2.1.6 (2015-07-01)
 ------------------------------------------------
 
  * agent: New option --verify for the PASSWD command.
 
  * gpgsm: Add command option "offline" as an alternative to
    --disable-dirmngr.
 
  * gpg: Do not prompt multiple times for a password in pinentry
    loopback mode.
 
  * Allow the use of debug category names with --debug.
 
  * Using gpg-agent and gpg/gpgsm with different locales will now show
    the correct translations in Pinentry.
 
  * gpg: Improve speed of --list-sigs and --check-sigs.
 
  * gpg: Make --list-options show-sig-subpackets work again.
 
  * gpg: Fix an export problem for old keyrings with PGP-2 keys.
 
  * scd: Support PIN-pads on more readers.
 
  * dirmngr: Properly cleanup zombie LDAP helper processes and avoid
    hangs on dirmngr shutdown.
 
  * Various other bug fixes.
 
  See-also: gnupg-announce/2015q3/000370.html
 
 
 Noteworthy changes in version 2.1.5 (2015-06-11)
 ------------------------------------------------
 
  * Support for an external passphrase cache.
 
  * Support for the forthcoming version 3 OpenPGP smartcard.
 
  * Manuals now show the actual used file names.
 
  * Prepared for improved integration with Emacs.
 
  * Code cleanups and minor bug fixes.
 
  See-also: gnupg-announce/2015q2/000369.html
 
 
 Noteworthy changes in version 2.1.4 (2015-05-12)
 ------------------------------------------------
 
  * gpg: Add command --quick-adduid to non-interactively add a new user
    id to an existing key.
 
  * gpg: Do no enable honor-keyserver-url by default.  Make it work if
    enabled.
 
  * gpg: Display the serial number in the --card-status output again.
 
  * agent: Support for external password managers.
    Add option --no-allow-external-cache.
 
  * scdaemon: Improved handling of extended APDUs.
 
  * Make HTTP proxies work again.
 
  * All network access including DNS as been moved to Dirmngr.
 
  * Allow building without LDAP support.
 
  * Fixed lots of smaller bugs.
 
  See-also: gnupg-announce/2015q2/000366.html
 
 
 Noteworthy changes in version 2.1.3 (2015-04-11)
 ------------------------------------------------
 
  * gpg: LDAP keyservers are now supported by 2.1.
 
  * gpg: New option --with-icao-spelling.
 
  * gpg: New option --print-pka-records.  Changed the PKA method to use
    CERT records and hashed names.  [Update: --print-pka-records
    replaced in 2.1.14.]
 
  * gpg: New command --list-gcrypt-config.  New parameter "curve"
    for --list-config.
 
  * gpg: Print a NEWSIG status line like gpgsm always did.
 
  * gpg: Print MPI values with --list-packets and --verbose.
 
  * gpg: Write correct MPI lengths with ECC keys.
 
  * gpg: Skip legacy PGP-2 keys while searching.
 
  * gpg: Improved searching for mail addresses when using a keybox.
 
  * gpgsm: Changed default algos to AES-128 and SHA-256.
 
  * gpgtar: Fixed extracting files with sizes of a multiple of 512.
 
  * dirmngr: Fixed SNI handling for hkps pools.
 
  * dirmngr: extra-certs and trusted-certs are now always loaded from
    the sysconfig dir instead of the homedir.
 
  * Fixed possible problems due to compiler optimization, two minor
    regressions, and other bugs.
 
  See-also: gnupg-announce/2015q2/000365.html
 
 
 Noteworthy changes in version 2.1.2 (2015-02-11)
 ------------------------------------------------
 
  * gpg: The parameter 'Passphrase' for batch key generation works
    again.
 
  * gpg: Using a passphrase option in batch mode now has the expected
    effect on --quick-gen-key.
 
  * gpg: Improved reporting of unsupported PGP-2 keys.
 
  * gpg: Added support for algo names when generating keys using
    --command-fd.
 
  * gpg: Fixed DoS based on bogus and overlong key packets.
 
  * agent: When setting --default-cache-ttl the value
    for --max-cache-ttl is adjusted to be not lower than the former.
 
  * agent: Fixed problems with the new --extra-socket.
 
  * agent: Made --allow-loopback-pinentry changeable with gpgconf.
 
  * agent: Fixed importing of unprotected openpgp keys.
 
  * agent: Now tries to use a fallback pinentry if the standard
    pinentry is not installed.
 
  * scd: Added support for ECDH.
 
  * Fixed several bugs related to bogus keyrings and improved some
    other code.
 
  See-also: gnupg-announce/2015q1/000361.html
 
 
 Noteworthy changes in version 2.1.1 (2014-12-16)
 ------------------------------------------------
 
  * gpg: Detect faulty use of --verify on detached signatures.
 
  * gpg: New import option "keep-ownertrust".
 
  * gpg: New sub-command "factory-reset" for --card-edit.
 
  * gpg: A stub key for smartcards is now created by --card-status.
 
  * gpg: Fixed regression in --refresh-keys.
 
  * gpg: Fixed regresion in %g and %p codes for --sig-notation.
 
  * gpg: Fixed best matching hash algo detection for ECDSA and EdDSA.
 
  * gpg: Improved perceived speed of secret key listisngs.
 
  * gpg: Print number of skipped PGP-2 keys on import.
 
  * gpg: Removed the option aliases --throw-keyid and --notation-data;
    use --throw-keyids and --set-notation instead.
 
  * gpg: New import option "keep-ownertrust".
 
  * gpg: Skip too large keys during import.
 
  * gpg,gpgsm: New option --no-autostart to avoid starting gpg-agent or
    dirmngr.
 
  * gpg-agent: New option --extra-socket to provide a restricted
    command set for use with remote clients.
 
  * gpgconf --kill does not anymore start a service only to kill it.
 
  * gpg-pconnect-agent: Add convenience option --uiserver.
 
  * Fixed keyserver access for Windows.
 
  * Fixed build problems on Mac OS X
 
  * The Windows installer does now install development files
 
  * More translations (but most of them are not complete).
 
  * To support remotely mounted home directories, the IPC sockets may
    now be redirected.  This feature requires Libassuan 2.2.0.
 
  * Improved portability and the usual bunch of bug fixes.
 
  See-also: gnupg-announce/2014q4/000360.html
 
 
 Noteworthy changes in version 2.1.0 (2014-11-06)
 ------------------------------------------------
 
  This release introduces a lot of changes.  Most of them are internal
  and thus not user visible.  However, some long standing behavior has
  slightly changed and it is strongly suggested that an existing
  "~/.gnupg" directory is backed up before this version is used.
 
  A verbose description of the major new features and changes can be
  found in the file doc/whats-new-in-2.1.txt.
 
  * gpg: All support for v3 (PGP 2) keys has been dropped.  All
    signatures are now created as v4 signatures.  v3 keys will be
    removed from the keyring.
 
  * gpg: With pinentry-0.9.0 the passphrase "enter again" prompt shows
    up in the same window as the "new passphrase" prompt.
 
  * gpg: Allow importing keys with duplicated long key ids.
 
  * dirmngr: May now be build without support for LDAP.
 
  * For a complete list of changes see the lists of changes for the
    2.1.0 beta versions below.  Note that all relevant fixes from
    versions 2.0.14 to 2.0.26 are also applied to this version.
 
 
  [Noteworthy changes in version 2.1.0-beta864 (2014-10-03)]
 
  * gpg: Removed the GPG_AGENT_INFO related code.  GnuPG does now
    always use a fixed socket name in its home directory.
 
  * gpg: Renamed --gen-key to --full-gen-key and re-added a --gen-key
    command with less choices.
 
  * gpg: Use SHA-256 for all signature types also on RSA keys.
 
  * gpg: Default keyring is now created with a .kbx suffix.
 
  * gpg: Add a shortcut to the key capabilies menu (e.g. "=e" sets the
    encryption capabilities).
 
  * gpg: Fixed obsolete options parsing.
 
  * Further improvements for the alternative speedo build system.
 
 
  [Noteworthy changes in version 2.1.0-beta834 (2014-09-18)]
 
  * gpg: Improved passphrase caching.
 
  * gpg: Switched to algorithm number 22 for EdDSA.
 
  * gpg: Removed CAST5 from the default preferences.
 
  * gpg: Order SHA-1 last in the hash preferences.
 
  * gpg: Changed default cipher for --symmetric to AES-128.
 
  * gpg: Fixed export of ECC keys and import of EdDSA keys.
 
  * dirmngr: Fixed the KS_FETCH command.
 
  * The speedo build system now downloads related packages and works
    for non-Windows platforms.
 
 
  [Noteworthy changes in version 2.1.0-beta783 (2014-08-14)]
 
  * gpg: Add command --quick-gen-key.
 
  * gpg: Make --quick-sign-key promote local key signatures.
 
  * gpg: Added "show-usage" sub-option to --list-options.
 
  * gpg: Screen keyserver responses to avoid importing unwanted keys
    from rogue servers.
 
  * gpg: Removed the option --pgp2 and --rfc1991 and the ability to
    create PGP-2 compatible messages.
 
  * gpg: Removed options --compress-keys and --compress-sigs.
 
  * gpg: Cap attribute packets at 16MB.
 
  * gpg: Improved output of --list-packets.
 
  * gpg: Make with-colons output of --search-keys work again.
 
  * gpgsm: Auto-create the ".gnupg" directory like gpg does.
 
  * agent: Fold new passphrase warning prompts into one.
 
  * scdaemon: Add support for the Smartcard-HSM card.
 
  * scdaemon: Remove the use of the pcsc-wrapper.
 
 
  [Noteworthy changes in version 2.1.0-beta751 (2014-07-03)]
 
  * gpg: Create revocation certificates during key generation.
 
  * gpg: Create exported secret keys and revocation certifciates with
    mode 0700
 
  * gpg: The validity of user ids is now shown by default.  To revert
    this add "list-options no-show-uid-validity" to gpg.conf.
 
  * gpg: Make export of secret keys work again.
 
  * gpg: The output of --list-packets does now print the offset of the
    packet and information about the packet header.
 
  * gpg: Avoid DoS due to garbled compressed data packets. [CVE-2014-4617]
 
  * gpg: Print more specific reason codes with the INV_RECP status.
 
  * gpg: Cap RSA and Elgamal keysize at 4096 bit also for unattended
    key generation.
 
  * scdaemon: Support reader Gemalto IDBridge CT30 and pinpad of SCT
    cyberJack go.
 
  * The speedo build system has been improved.  It is now also possible
    to build a partly working installer for Windows.
 
 
  [Noteworthy changes in version 2.1.0-beta442 (2014-06-05)]
 
  * gpg: Changed the format of key listings.  To revert to the old
    format the option --legacy-list-mode is available.
 
  * gpg: Add experimental signature support using curve Ed25519 and
    with a patched Libgcrypt also encryption support with Curve25519.
    [Update: this encryption support has been removed from 2.1.0 until
    we have agreed on a suitable format.]
 
  * gpg: Allow use of Brainpool curves.
 
  * gpg: Accepts a space separated fingerprint as user ID.  This
    allows to copy and paste the fingerprint from the key listing.
 
  * gpg: The hash algorithm is now printed for signature records in key
    listings.
 
  * gpg: Reject signatures made using the MD5 hash algorithm unless the
    new option --allow-weak-digest-algos or --pgp2 are given.
 
  * gpg: Print a warning if the Gnome-Keyring-Daemon intercepts the
    communication with the gpg-agent.
 
  * gpg: New option --pinentry-mode.
 
  * gpg: Fixed decryption using an OpenPGP card.
 
  * gpg: Fixed bug with deeply nested compressed packets.
 
  * gpg: Only the major version number is by default included in the
    armored output.
 
  * gpg: Do not create a trustdb file if --trust-model=always is used.
 
  * gpg: Protect against rogue keyservers sending secret keys.
 
  * gpg: The format of the fallback key listing ("gpg KEYFILE") is now
    more aligned to the regular key listing ("gpg -k").
 
  * gpg: The option--show-session-key prints its output now before the
    decryption of the bulk message starts.
 
  * gpg: New %U expando for the photo viewer.
 
  * gpg,gpgsm: New option --with-secret.
 
  * gpgsm: By default the users are now asked via the Pinentry whether
    they trust an X.509 root key.  To prohibit interactive marking of
    such keys, the new option --no-allow-mark-trusted may be used.
 
  * gpgsm: New commands to export a secret RSA key in PKCS#1 or PKCS#8
    format.
 
  * gpgsm: Improved handling of re-issued CA certificates.
 
  * agent: The included ssh agent does now support ECDSA keys.
 
  * agent: New option --enable-putty-support to allow gpg-agent on
    Windows to act as a Pageant replacement with full smartcard support.
 
  * scdaemon: New option --enable-pinpad-varlen.
 
  * scdaemon: Various fixes for pinpad equipped card readers.
 
  * scdaemon: Rename option --disable-pinpad (was --disable-keypad).
 
  * scdaemon: Better support fo CCID readers.  Now, internal CCID
    driver supports readers with no auto configuration feature.
 
  * dirmngr: Removed support for the original HKP keyserver which is
    not anymore used by any site.
 
  * dirmngr: Improved support for keyserver pools.
 
  * tools: New option --dirmngr for gpg-connect-agent.
 
  * The GNU Pth library has been replaced by the new nPth library.
 
  * Support installation as portable application under Windows.
 
  * All kind of other improvements - see the git log.
 
 
  [Noteworthy changes in version 2.1.0beta3 (2011-12-20)]
 
  * gpg: Fixed regression in the secret key export function.
 
  * gpg: Allow generation of card keys up to 4096 bit.
 
  * gpgsm: Preliminary support for the validation model "steed".
 
  * gpgsm: Improved certificate creation.
 
  * agent: Support the SSH confirm flag.
 
  * agent: New option to select a passphrase mode.  The loopback
    mode may be used to bypass Pinentry.
 
  * agent: The Assuan commands KILLAGENT and KILLSCD are working again.
 
  * scdaemon: Does not anymore block after changing a card (regression
    fix).
 
  * tools: gpg-connect-agent does now proberly display the help output
    for "SCD HELP" commands.
 
 
  [Noteworthy changes in version 2.1.0beta2 (2011-03-08)]
 
  * gpg: ECC support as described by draft-jivsov-openpgp-ecc-06.txt
    [Update: now known as RFC-6637].
 
  * gpg: Print "AES128" instead of "AES".  This change introduces a
    little incompatibility for tools using "gpg --list-config".  We
    hope that these tools are written robust enough to accept this new
    algorithm name as well.
 
  * gpgsm: New feature to create certificates from a parameter file.
    Add prompt to the --gen-key UI to create self-signed certificates.
 
  * agent: TMPDIR is now also honored when creating a socket using
    the --no-standard-socket option and with symcryptrun's temp files.
 
  * scdaemon: Fixed a bug where scdaemon sends a signal to gpg-agent
    running in non-daemon mode.
 
  * dirmngr: Fixed CRL loading under W32 (bug#1010).
 
  * Dirmngr has taken over the function of the keyserver helpers.  Thus
    we now have a specified direct interface to keyservers via Dirmngr.
    LDAP, DNS and mail backends are not yet implemented.
 
  * Fixed TTY management for pinentries and session variable update
    problem.
 
 
  [Noteworthy changes in version 2.1.0beta1 (2010-10-26)]
 
  * gpg: secring.gpg is not anymore used but all secret key operations
    are delegated to gpg-agent.  The import command moves secret keys
    to the agent.
 
  * gpg: The OpenPGP import command is now able to merge secret keys.
 
  * gpg: Encrypted OpenPGP messages with trailing data (e.g. other
    OpenPGP packets) are now correctly parsed.
 
  * gpg: Given sufficient permissions Dirmngr is started automagically.
 
  * gpg: Fixed output of "gpgconf --check-options".
 
  * gpg: Removed options --export-options(export-secret-subkey-passwd)
    and --simple-sk-checksum.
 
  * gpg: New options --try-secret-key.
 
  * gpg: Support DNS lookups for SRV, PKA and CERT on W32.
 
  * gpgsm: The --audit-log feature is now more complete.
 
  * gpgsm: The default for --include-cert is now to include all
    certificates in the chain except for the root certificate.
 
  * gpgsm: New option --ignore-cert-extension.
 
  * g13: The G13 tool for disk encryption key management has been
    added.
 
  * agent: If the agent's --use-standard-socket option is active, all
    tools try to start and daemonize the agent on the fly.  In the past
    this was only supported on W32; on non-W32 systems the new
    configure option --disable-standard-socket may now be used to
    disable this new default.
 
  * agent: New and changed passphrases are now created with an
    iteration count requiring about 100ms of CPU work.
 
  * dirmngr: Dirmngr is now a part of this package.  It is now also
    expected to run as a system service and the configuration
    directories are changed to the GnuPG name space. [Update: 2.1.0
    starts dirmngr on demand as user daemon.]
 
  * Support for Windows CE. [Update: This has not been tested for the
    2.1.0 release]
 
  * Numerical values may now be used as an alternative to the
    debug-level keywords.
 
  See-also: gnupg-announce/2014q4/000358.html
 
 
 Version 2.0.28 (2015-06-02)
 Version 2.0.27 (2015-02-18)
 Version 2.0.26 (2014-08-12)
 Version 2.0.25 (2014-06-30)
 Version 2.0.24 (2014-06-24)
 Version 2.0.23 (2014-06-03)
 Version 2.0.22 (2013-10-04)
 Version 2.0.21 (2013-08-19)
 Version 2.0.20 (2013-05-10)
 Version 2.0.19 (2012-03-27)
 Version 2.0.18 (2011-08-04)
 Version 2.0.17 (2011-01-13)
 Version 2.0.16 (2010-07-19)
 Version 2.0.15 (2010-03-09)
 Version 2.0.14 (2009-12-21)
 
 
 Noteworthy changes in version 2.0.13 (2009-09-04)
 -------------------------------------------------
 
  * GPG now generates 2048 bit RSA keys by default.  The default hash
    algorithm preferences has changed to prefer SHA-256 over SHA-1.
    2048 bit DSA keys are now generated to use a 256 bit hash algorithm
 
  * The envvars XMODIFIERS, GTK_IM_MODULE and QT_IM_MODULE are now
    passed to the Pinentry to make SCIM work.
 
  * The GPGSM command --gen-key features a --batch mode and implements
    all features of gpgsm-gencert.sh in standard mode.
 
  * New option --re-import for GPGSM's IMPORT server command.
 
  * Enhanced writing of existing keys to OpenPGP v2 cards.
 
  * Add hack to the internal CCID driver to allow the use of some
    Omnikey based card readers with 2048 bit keys.
 
  * GPG now repeatly asks the user to insert the requested OpenPGP
    card.  This can be disabled with --limit-card-insert-tries=1.
 
  * Minor bug fixes.
 
  See-also: gnupg-announce/2009q3/000294.html
 
 
 Noteworthy changes in version 2.0.12 (2009-06-17)
 -------------------------------------------------
 
  * GPGSM now always lists ephemeral certificates if specified by
    fingerprint or keygrip.
 
  * New command "KEYINFO" for GPG_AGENT.  GPGSM now also returns
    information about smartcards.
 
  * Made sure not to leak file descriptors if running gpg-agent with a
    command.  Restore the signal mask to solve a problem in Mono.
 
  * Changed order of the confirmation questions for root certificates
    and store negative answers in trustlist.txt.
 
  * Better synchronization of concurrent smartcard sessions.
 
  * Support 2048 bit OpenPGP cards.
 
  * Support Telesec Netkey 3 cards.
 
  * The gpg-protect-tool now uses gpg-agent via libassuan.  Under
    Windows the Pinentry will now be put into the foreground.
 
  * Changed code to avoid a possible Mac OS X system freeze.
 
  See-also: gnupg-announce/2009q2/000288.html
 
 
 Noteworthy changes in version 2.0.11 (2009-03-03)
 -------------------------------------------------
 
  * Fixed a problem in SCDAEMON which caused unexpected card resets.
 
  * SCDAEMON is now aware of the Geldkarte.
 
  * The SCDAEMON option --allow-admin is now used by default.
 
  * GPGCONF now restarts SCdaemon if necessary.
 
  * The default cipher algorithm in GPGSM is now again 3DES.  This is
    due to interoperability problems with Outlook 2003 which still
    can't cope with AES.
 
  See-also: gnupg-announce/2009q1/000287.html
 
 
 Noteworthy changes in version 2.0.10 (2009-01-12)
 -------------------------------------------------
 
  * [gpg] New keyserver helper gpg2keys_kdns as generic DNS CERT
    lookup.  Run with --help for a short description.  Requires the
    ADNS library.
 
  * [gpg] New mechanisms "local" and "nodefault" for --auto-key-locate.
    Fixed a few problems with this option.
 
  * [gpg] New command --locate-keys.
 
  * [gpg] New options --with-sig-list and --with-sig-check.
 
  * [gpg] The option "-sat" is no longer an alias for --clearsign.
 
  * [gpg] The option --fixed-list-mode is now implicitly used and obsolete.
 
  * [gpg] New control statement %ask-passphrase for the unattended key
    generation.
 
  * [gpg] The algorithm to compute the SIG_ID status has been changed.
 
  * [gpgsm] Now uses AES by default.
 
  * [gpgsm] Made --output option work with --export-secret-key-p12.
 
  * [gpg-agent] Terminate process if the own listening socket is not
    anymore served by ourself.
 
  * [scdaemon] Made it more robust on W32.
 
  * [gpg-connect-agent] Accept commands given as command line arguments.
 
  * [w32] Initialized the socket subsystem for all keyserver helpers.
 
  * [w32] The sysconf directory has been moved from a subdirectory of
    the installation directory to %CSIDL_COMMON_APPDATA%/GNU/etc/gnupg.
 
  * [w32] The gnupg2.nls directory is not anymore used.  The standard
    locale directory is now used.
 
  * [w32] Fixed a race condition between gpg and gpgsm in the use of
    temporary file names.
 
  * The gpg-preset-passphrase mechanism works again.  An arbitrary
    string may now be used for a custom cache ID.
 
  * Admin PINs are cached again (bug in 2.0.9).
 
  * Support for version 2 OpenPGP cards.
 
  * Libgcrypt 1.4 is now required.
 
  See-also: gnupg-announce/2009q1/000284.html
 
 
 Noteworthy changes in version 2.0.9 (2008-03-26)
 ------------------------------------------------
 
  * Gpgsm always tries to locate missing certificates from a running
    Dirmngr's cache.
 
  * Tweaks for Windows.
 
  * The Admin PIN for OpenPGP cards may now be entered with the pinpad.
 
  * Improved certificate chain construction.
 
  * Extended the PKITS framework.
 
  * Fixed a bug in the ambigious name detection.
 
  * Fixed possible memory corruption while importing OpenPGP keys (bug
    introduced with 2.0.8). [CVE-2008-1530]
 
  * Minor bug fixes.
 
 
 
 Noteworthy changes in version 2.0.8 (2007-12-20)
 ------------------------------------------------
 
  * Enhanced gpg-connect-agent with a small scripting language.
 
  * New option --list-config for gpgconf.
 
  * Fixed a crash in gpgconf.
 
  * Gpg-agent now supports the passphrase quality bar of the latest
    Pinentry.
 
  * The envvars XAUTHORITY and PINENTRY_USER_DATA are now passed to the
    Pinentry.
 
  * Fixed the auto creation of the key stub for smartcards.
 
  * Fixed a rare bug in decryption using the OpenPGP card.
 
  * Creating DSA2 keys is now possible.
 
  * New option --extra-digest-algo for gpgsm to allow verification of
    broken signatures.
 
  * Allow encryption with legacy Elgamal sign+encrypt keys with option
    --rfc2440.
 
  * Windows is now a supported platform.
 
  * Made sure that under Windows the file permissions of the socket are
    taken into account.  This required a change of our socket emulation
    code and changed the IPC protocol under Windows.
 
  See-also: gnupg-announce/2007q4/000267.html
 
 
 Noteworthy changes in version 2.0.7 (2007-09-10)
 ------------------------------------------------
 
  * Fixed encryption problem if duplicate certificates are in the
    keybox.
 
  * Made it work on Windows Vista.  Note that the entire Windows port
    is still considered Beta.
 
  * Add new options min-passphrase-nonalpha, check-passphrase-pattern,
    enforce-passphrase-constraints and max-passphrase-days to
    gpg-agent.
 
  * Add command --check-components to gpgconf.  Gpgconf now uses the
    installed versions of the programs and does not anymore search via
    PATH for them.
 
  See-also: gnupg-announce/2007q3/000259.html
 
 
 Noteworthy changes in version 2.0.6 (2007-08-16)
 ------------------------------------------------
 
  * GPGSM does now grok --default-key.
 
  * GPGCONF is now aware of --default-key and --encrypt-to.
 
  * GPGSM does again correctly print the serial number as well the the
    various keyids.  This was broken since 2.0.4.
 
  * New option --validation-model and support for the chain-model.
 
  * Improved Windows support.
 
  See-also: gnupg-announce/2007q3/000258.html
 
 
 Noteworthy changes in version 2.0.5 (2007-07-05)
 ------------------------------------------------
 
  * Switched license to GPLv3.
 
  * Basic support for Windows.  Run "./autogen.sh --build-w32" to build
    it.  As usual the mingw cross compiling toolchain is required.
 
  * Fixed bug when using the --p12-charset without --armor.
 
  * The command --gen-key may now be used instead of the
    gpgsm-gencert.sh script.
 
  * Changed key generation to reveal less information about the
    machine.  Bug fixes for gpg2's card key generation.
 
  See-also: gnupg-announce/2007q3/000255.html
 
 
 Noteworthy changes in version 2.0.4 (2007-05-09)
 ------------------------------------------------
 
  * The server mode key listing commands are now also working for
    systems without the funopen/fopencookie API.
 
  * PKCS#12 import now tries several encodings in case the passphrase
    was not utf-8 encoded.  New option --p12-charset for gpgsm.
 
  * Improved the libgcrypt logging support in all modules.
 
  See-also: gnupg-announce/2007q2/000254.html
 
 
 Noteworthy changes in version 2.0.3 (2007-03-08)
 ------------------------------------------------
 
  * By default, do not allow processing multiple plaintexts in a single
    stream.  Many programs that called GnuPG were assuming that GnuPG
    did not permit this, and were thus not using the plaintext boundary
    status tags that GnuPG provides.  This change makes GnuPG reject
    such messages by default which makes those programs safe again.
    --allow-multiple-messages returns to the old behavior. [CVE-2007-1263].
 
  * New --verify-option show-primary-uid-only.
 
  * gpgconf may now reads a global configuration file to select which
    options are changeable by a frontend.  The new applygnupgdefaults
    tool may be used by an admin to set default options for all users.
 
  * The PIN pad of the Cherry XX44 keyboard is now supported.  The
    DINSIG and the NKS applications are now also aware of PIN pads.
 
  See-also: gnupg-announce/2007q1/000252.html
 
 
 Noteworthy changes in version 2.0.2 (2007-01-31)
 ------------------------------------------------
 
  * Fixed a serious and exploitable bug in processing encrypted
    packages. [CVE-2006-6235].
 
  * Added --passphrase-repeat to set the number of times GPG will
    prompt for a new passphrase to be repeated.  This is useful to help
    memorize a new passphrase.  The default is 1 repetition.
 
  * Using a PIN pad does now also work for the signing key.
 
  * A warning is displayed by gpg-agent if a new passphrase is too
    short.  New option --min-passphrase-len defaults to 8.
 
  * The status code BEGIN_SIGNING now shows the used hash algorithms.
 
  See-also: gnupg-announce/2007q1/000249.html
 
 
 Noteworthy changes in version 2.0.1 (2006-11-28)
 ------------------------------------------------
 
  * Experimental support for the PIN pads of the SPR 532 and the Kaan
    Advanced card readers.  Add "disable-keypad" scdaemon.conf if you
    don't want it.  Does currently only work for the OpenPGP card and
    its authentication and decrypt keys.
 
  * Fixed build problems on some some platforms and crashes on amd64.
 
  * Fixed a buffer overflow in gpg2. [bug#728,CVE-2006-6169]
 
  See-also: gnupg-announce/2006q4/000242.html
 
 
 Noteworthy changes in version 2.0.0 (2006-11-11)
 ------------------------------------------------
 
  * First stable version of a GnuPG integrating OpenPGP and S/MIME.
 
  See-also: gnupg-announce/2006q4/000239.html
 
 
 Noteworthy changes in version 1.9.95 (2006-11-06)
 -------------------------------------------------
 
  * Minor bug fixes.
 
 
 Noteworthy changes in version 1.9.94 (2006-10-24)
 -------------------------------------------------
 
  * Keys for gpgsm may now be specified using a keygrip.  A keygrip is
    indicated by a prefixing it with an ampersand.
 
  * gpgconf now supports switching the CMS cipher algo (e.g. to AES).
 
  * New command --gpgconf-test for all major tools. This may be used to
    check whether the configuration file is sane.
 
 
 Noteworthy changes in version 1.9.93 (2006-10-18)
 -------------------------------------------------
 
  * In --with-validation mode gpgsm will now also ask whether a root
    certificate should be trusted.
 
  * Link to Pth only if really necessary.
 
  * Fixed a pubring corruption bug in gpg2 occurring when importing
    signatures or keys with insane lengths.
 
  * Fixed v3 keyID calculation bug in gpg2.
 
  * More tweaks for certificates without extensions.
 
 
 Noteworthy changes in version 1.9.92 (2006-10-11)
 -------------------------------------------------
 
  * Bug fixes.
 
  See-also: gnupg-announce/2006q4/000236.html
 
 
 Noteworthy changes in version 1.9.91 (2006-10-04)
 -------------------------------------------------
 
  * New "relax" flag for trustlist.txt to allow root CA certificates
    without BasicContraints.
 
  * [gpg2] Removed the -k PGP 2 compatibility hack.  -k is now an
    alias for --list-keys.
 
  * [gpg2] Print a warning if "-sat" is used instead of "--clearsign".
 
 
 Noteworthy changes in version 1.9.90 (2006-09-25)
 -------------------------------------------------
 
  * Made readline work for gpg.
 
  * Cleanups und minor bug fixes.
 
  * Included translations from gnupg 1.4.5.
 
 
 Noteworthy changes in version 1.9.23 (2006-09-18)
 -------------------------------------------------
 
  * Regular man pages for most tools are now build directly from the
    Texinfo source.
 
  * The gpg code from 1.4.5 has been fully merged into this release.
    The configure option --enable-gpg is still required to build this
    gpg part.  For production use of OpenPGP the gpg version 1.4.5 is
    still recommended.  Note, that gpg will be installed under the name
    gpg2 to allow coexisting with an 1.4.x gpg.
 
  * API change in gpg-agent's pkdecrypt command.  Thus an older gpgsm
    may not be used with the current gpg-agent.
 
  * The scdaemon will now call a script on reader status changes.
 
  * gpgsm now allows file descriptor passing for "INPUT", "OUTPUT" and
    "MESSAGE".
 
  * The gpgsm server may now output a key listing to the output file
    handle. This needs to be enabled using "OPTION list-to-output=1".
 
  * The --output option of gpgsm has now an effect on list-keys.
 
  * New gpgsm commands --dump-chain and list-chain.
 
  * gpg-connect-agent has new options to utilize descriptor passing.
 
  * A global trustlist may now be used.  See doc/examples/trustlist.txt.
 
  * When creating a new pubring.kbx keybox common certificates are
    imported.
 
 
 Noteworthy changes in version 1.9.22 (2006-07-27)
 -------------------------------------------------
 
  * Enhanced pkcs#12 support to allow import from simple keyBags.
 
  * Exporting to pkcs#12 now create bag attributes so that Mozilla is
    able to import the files.
 
  * Fixed uploading of certain keys to the smart card.
 
 
 Noteworthy changes in version 1.9.21 (2006-06-20)
 -------------------------------------------------
 
  * New command APDU for scdaemon to allow using it for general card
    access.  Might be used through gpg-connect-agent by using the SCD
    prefix command.
 
  * Support for the CardMan 4040 PCMCIA reader (Linux 2.6.15 required).
 
  * Scdaemon does not anymore reset cards at the end of a connection.
 
  * Kludge to allow use of Bundesnetzagentur issued X.509 certificates.
 
  * Added --hash=xxx option to scdaemon's PKSIGN command.
 
  * Pkcs#12 files are now created with a MAC.  This is for better
    interoperability.
 
  * Collected bug fixes and minor other changes.
 
 
 Noteworthy changes in version 1.9.20 (2005-12-20)
 -------------------------------------------------
 
  * Importing pkcs#12 files created be recent versions of Mozilla works
    again.
 
  * Basic support for qualified signatures.
 
  * New debug tool gpgparsemail.
 
 
 Noteworthy changes in version 1.9.19 (2005-09-12)
 -------------------------------------------------
 
  * The Belgian eID card is now supported for signatures and ssh.
    Other pkcs#15 cards should work as well.
 
  * Fixed bug in --export-secret-key-p12 so that certificates are again
    included.
 
 
 Noteworthy changes in version 1.9.18 (2005-08-01)
 -------------------------------------------------
 
  * [gpgsm] Now allows for more than one email address as well as URIs
    and dnsNames in certificate request generation.  A keygrip may be
    given to create a request from an existing key.
 
  * A couple of minor bug fixes.
 
 
 Noteworthy changes in version 1.9.17 (2005-06-20)
 -------------------------------------------------
 
  * gpg-connect-agent has now features to handle Assuan INQUIRE
    commands.
 
  * Internal changes for OpenPGP cards. New Assuan command WRITEKEY.
 
  * GNU Pth is now a hard requirement.
 
  * [scdaemon] Support for OpenSC has been removed.  Instead a new and
    straightforward pkcs#15 modules has been written.  As of now it
    does allows only signing using TCOS cards but we are going to
    enhance it to match all the old capabilities.
 
  * [gpg-agent] New option --write-env-file and Assuan command
    UPDATESTARTUPTTY.
 
  * [gpg-agent] New option --default-cache-ttl-ssh to set the TTL for
    SSH passphrase caching independent from the other passphrases.
 
 
 Noteworthy changes in version 1.9.16 (2005-04-21)
 -------------------------------------------------
 
  * gpg-agent does now support the ssh-agent protocol and thus allows
    to use the pinentry as well as the OpenPGP smartcard with ssh.
 
  * New tool gpg-connect-agent as a general client for the gpg-agent.
 
  * New tool symcryptrun as a wrapper for certain encryption tools.
 
  * The gpg tool is not anymore build by default because those gpg
    versions available in the gnupg 1.4 series are far more matured.
 
 
 Noteworthy changes in version 1.9.15 (2005-01-13)
 -------------------------------------------------
 
  * Fixed passphrase caching bug.
 
  * Better support for CCID readers; the reader from Cherry RS 6700 USB
    does now work.
 
 
 Noteworthy changes in version 1.9.14 (2004-12-22)
 -------------------------------------------------
 
  * [gpg-agent] New option --use-standard-socket to allow the use of a
    fixed socket.  gpgsm falls back to this socket if GPG_AGENT_INFO
    has not been set.
 
  * Ported to MS Windows with some functional limitations.
 
  * New tool gpg-preset-passphrase.
 
 
 Noteworthy changes in version 1.9.13 (2004-12-03)
 -------------------------------------------------
 
  * [gpgsm] New option --prefer-system-dirmngr.
 
  * Minor cleanups and debugging aids.
 
 
 Noteworthy changes in version 1.9.12 (2004-10-22)
 -------------------------------------------------
 
  * [scdaemon] Partly rewrote the PC/SC code.
 
  * Removed the sc-investigate tool.  It is now in a separate package
    available at ftp://ftp.g10code.com/g10code/gscutils/ .
 
  * [gpg-agent] Fixed logging problem.
 
 
 Noteworthy changes in version 1.9.11 (2004-10-01)
 -------------------------------------------------
 
  * When using --import along with --with-validation, the imported
    certificates are validated and only imported if they are fully
    valid.
 
  * [gpg-agent] New option --max-cache-ttl.
 
  * [gpg-agent] When used without --daemon or --server, gpg-agent now
    check whether a agent is already running and usable.
 
  * Fixed some i18n problems.
 
 
 Noteworthy changes in version 1.9.10 (2004-07-22)
 -------------------------------------------------
 
  * Fixed a serious bug in the checking of trusted root certificates.
 
  * New configure option --enable-agent-pnly allows to build and
    install just the agent.
 
  * Fixed a problem with the log file handling.
 
 
 Noteworthy changes in version 1.9.9 (2004-06-08)
 ------------------------------------------------
 
  * [gpg-agent] The new option --allow-mark-trusted is now required to
    allow gpg-agent to add a key to the trustlist.txt after user
    confirmation.
 
  * Creating PKCS#10 requests does now honor the key usage.
 
 
 Noteworthy changes in version 1.9.8 (2004-04-29)
 ------------------------------------------------
 
  * [scdaemon] Overhauled the internal CCID driver.
 
  * [scdaemon] Status files named ~/.gnupg/reader_<n>.status are now
    written when using the internal CCID driver.
 
  * [gpgsm] New commands --dump-{,secret,external}-keys to show a very
    detailed view of the certificates.
 
  * The keybox gets now compressed after 3 hours and ephemeral
    stored certificates are deleted after about a day.
 
  * [gpg] Usability fixes for --card-edit.  Note, that this has already
    been ported back to gnupg-1.3
 
 
 Noteworthy changes in version 1.9.7 (2004-04-06)
 ------------------------------------------------
 
  * Instrumented the modules for gpgconf.
 
  * Added support for DINSIG card applications.
 
  * Include the smimeCapabilities attribute with signed messages.
 
  * Now uses the gettext domain "gnupg2" to avoid conflicts with gnupg
    versions < 1.9.
 
 
 Noteworthy changes in version 1.9.6 (2004-03-06)
 ------------------------------------------------
 
  * Code cleanups and bug fixes.
 
 
 Noteworthy changes in version 1.9.5 (2004-02-21)
 ------------------------------------------------
 
  * gpg-protect-tool gets now installed into libexec as it ought to be.
    Cleaned up the build system to better comply with the coding
    standards.
 
  * [gpgsm] The --import command is now able to autodetect pkcs#12
    files and import secret and private keys from this file format.
    A new command --export-secret-key-p12 is provided to allow
    exporting of secret keys in PKCS\#12 format.
 
  * [gpgsm] The pinentry will now present a description of the key for
    whom the passphrase is requested.
 
  * [gpgsm] New option --with-validation to check the validity of key
    while listing it.
 
  * New option --debug-level={none,basic,advanced,expert,guru} to map
    the debug flags to sensitive levels on a per program base.
 
 
 Noteworthy changes in version 1.9.4 (2004-01-30)
 ------------------------------------------------
 
  * Added support for the Telesec NKS 2.0 card application.
 
  * Added simple tool addgnupghome to create .gnupg directories from
    /etc/skel/.gnupg.
 
  * Various minor bug fixes and cleanups; mainly gpgsm and gpg-agent
    related.
 
 
 Noteworthy changes in version 1.9.3 (2003-12-23)
 ------------------------------------------------
 
  * New gpgsm options --{enable,disable}-ocsp to validate keys using
    OCSP. This option requires a not yet released DirMngr version.
    Default is disabled.
 
  * The --log-file option may now be used to print logs to a socket.
    Prefix the socket name with "socket://" to enable this.  This does
    not work on all systems and falls back to stderr if there is a
    problem with the socket.
 
  * The options --encrypt-to and --no-encrypt-to now work the same in
    gpgsm as in gpg.  Note, they are also used in server mode.
 
  * Duplicated recipients are now silently removed in gpgsm.
 
 
 Noteworthy changes in version 1.9.2 (2003-11-17)
 ------------------------------------------------
 
  * On card key generation is no longer done using the --gen-key
    command but from the menu provided by the new --card-edit command.
 
  * PINs are now properly cached and there are only 2 PINs visible.
    The 3rd PIN (CHV2) is internally synchronized with the regular PIN.
 
  * All kind of other internal stuff.
 
 
 Noteworthy changes in version 1.9.1 (2003-09-06)
 ------------------------------------------------
 
  * Support for OpenSC is back. scdaemon supports a --disable-opensc to
    disable OpenSC use at runtime, so that PC/SC or ct-API can still be
    used directly.
 
  * Rudimentary support for the SCR335 smartcard reader using an
    internal driver.  Requires current libusb from CVS.
 
  * Bug fixes.
 
 
 Noteworthy changes in version 1.9.0 (2003-08-05)
 ------------------------------------------------
 
       ====== PLEASE SEE README-alpha =======
 
  * gpg has been renamed to gpg2 and gpgv to gpgv2.  This is a
    temporary change to allow co-existing with stable gpg versions.
 
  * ~/.gnupg/gpg.conf-1.9.0 is fist tried as config file before the
    usual gpg.conf.
 
  * Removed the -k, -kv and -kvv commands.  -k is now an alias to
    --list-keys.  New command -K as alias for --list-secret-keys.
 
  * Removed --run-as-shm-coprocess feature.
 
  * gpg does now also use libgcrypt, libgpg-error is required.
 
  * New gpgsm commands --call-dirmngr and --call-protect-tool.
 
  * Changing a passphrase is now possible using "gpgsm --passwd"
 
  * The content-type attribute is now recognized and created.
 
  * The agent does now reread certain options on receiving a HUP.
 
  * The pinentry is now forked for each request so that clients with
    different environments are supported.  When running in daemon mode
    and --keep-display is not used the DISPLAY variable is ignored.
 
  * Merged stuff from the newpg branch and started this new
    development branch.
 
 
 Version 1.4.19 (2015-02-27)
 Version 1.4.18 (2014-06-30)
 Version 1.4.17 (2014-06-23)
 Version 1.4.16 (2013-12-18)
 Version 1.4.15 (2013-10-04)
 Version 1.4.14 (2013-07-25)
 Version 1.4.13 (2012-12-20)
 Version 1.4.12 (2012-01-30)
 Version 1.4.11 (2010-10-18)
 Version 1.4.10 (2009-09-02)
 Version 1.4.9 (2008-03-26)
 Version 1.4.8 (2007-12-20)
 Version 1.4.7 (2007-03-05)
 Version 1.4.6 (2006-12-06)
 Version 1.4.5 (2006-08-01)
 Version 1.4.4 (2006-06-25)
 Version 1.4.3 (2006-04-03)
 Version 1.4.2 (2005-07-26)
 Version 1.4.1 (2005-03-15)
 Version 1.4.0 (2004-12-16)
 
 
 Noteworthy changes in version 1.3.2 (2003-05-27)
 ------------------------------------------------
 
     * New "--gnupg" option (set by default) that disables --openpgp,
       and the various --pgpX emulation options.  This replaces
       --no-openpgp, and --no-pgpX, and also means that GnuPG has
       finally grown a --gnupg option to make GnuPG act like GnuPG.
 
     * A bug in key validation has been fixed.  This bug only affects
       keys with more than one user ID (photo IDs do not count here),
       and results in all user IDs on a given key being treated with
       the validity of the most-valid user ID on that key.
 
     * Notation names that do not contain a '@' are no longer allowed
       unless --expert is set.  This is to help prevent pollution of
       the (as yet unused) IETF notation namespace.
 
     * Multiple trust models are now supported via the --trust-model
       option.  The options are "pgp" (web-of-trust plus trust
       signatures), "classic" (web-of-trust only), and "always"
       (identical to the --always-trust option).
 
     * The --personal-{cipher|digest|compression}-preferences are now
       consulted to get default algorithms before resorting to the
       last-ditch defaults of --s2k-cipher-algo, SHA1, and ZIP
       respectively.  This allows a user to set algorithms to use in a
       safe manner so they are used when legal to do so, without
       forcing them on for all messages.
 
     * New --primary-keyring option to designate the keyring that the
       user wants new keys imported into.
 
     * --s2k-digest-algo is now used for all password mangling.
       Earlier versions used both --s2k-digest-algo and --digest-algo
       for passphrase mangling.
 
     * Handling of --hidden-recipient or --throw-keyid messages is now
       easier - the user only needs to give their passphrase once, and
       GnuPG will try it against all of the available secret keys.
 
     * Care is taken to prevent compiler optimization from removing
       memory wiping code.
 
     * New option --no-mangle-dos-filenames so that filenames are not
       truncated in the W32 version.
 
     * A "convert-from-106" script has been added.  This is a simple
       script that automates the conversion from a 1.0.6 or earlier
       version of GnuPG to a 1.0.7 or later version.
 
     * Disabled keys are now skipped when selecting keys for
       encryption.  If you are using the --with-colons key listings to
       detect disabled keys, please see doc/DETAILS for a minor format
       change in this release.
 
     * Minor trustdb changes to make the trust calculations match
       common usage.
 
     * New command "revuid" in the --edit-key menu to revoke a user ID.
       This is a simpler interface to the old method (which still
       works) of revoking the user ID self-signature.
 
     * Status VALIDSIG does now also print the primary key's
       fingerprint, as well as the signature version, pubkey algorithm,
       hash algorithm, and signature class.
 
     * Add read-only support for the SHA-256 hash, and optional
       read-only support for the SHA-384 and SHA-512 hashes.
 
     * New option --enable-progress-filter for use with frontends.
 
     * DNS SRV records are used in HKP keyserver lookups to allow
       administrators to load balance and select keyserver ports
       automatically.  This is as specified in
       draft-shaw-openpgp-hkp-00.txt.
 
     * When using the "keyid!" syntax during a key export, only that
       specified key is exported.  If the key in question is a subkey,
       the primary key plus only that subkey is exported.
 
     * configure --disable-xxx options to disable individual algorithms
       at build time.  This can be used to build a smaller gpg binary
       for embedded uses where space is tight.  See the README file for
       the algorithms that can be used with this option, or use
       --enable-minimal to build the smallest gpg possible (disables
       all optional algorithms, disables keyserver access, and disables
       photo IDs).
 
     * The keyserver no-modify flag on a key can now be displayed and
       modified.
 
     * Note that the TIGER/192 digest algorithm is in the process of
       being dropped from the OpenPGP standard.  While this release of
       GnuPG still contains it, it is disabled by default.  To ensure
       you will still be able to use your messages with future versions
       of GnuPG and other OpenPGP programs, please do not use this
       algorithm.
 
     See-also: gnupg-announce/2003q2/000153.html
 
 
 Noteworthy changes in version 1.3.1 (2002-11-12)
 ------------------------------------------------
 
     * Trust signature support.  This is based on the Maurer trust
       model where a user can specify the trust level along with the
       signature with multiple levels so users can delegate
       certification ability to other users, possibly restricted by a
       regular expression on the user ID.  Note that full trust
       signature support requires a regular expression parsing library.
       The regexp code from glibc 2.3.1 is included for those platforms
       that don't have working regexp functions available.  The
       configure option --disable-regex may be used to disable any
       regular expression code, which will make GnuPG ignore any trust
       signature with a regular expression included.
 
     * Two new commands --hidden-recipient (-R) and --hidden-encrypt-to
       encrypt to a user, but hide the identity of that user.  This is
       the same functionality as --throw-keyid, but can be used on a
       per-user basis.
 
     * Full algorithm names (e.g. "3DES", "SHA1", "ZIP") can now be
       used interchangeably with the short algorithm names (e.g. "S2",
       "H2", "Z1") anywhere algorithm names are used in GnuPG.
 
 
 Noteworthy changes in version 1.3.0 (2002-10-18)
 ------------------------------------------------
 
     * The last piece of internal keyserver support has been removed,
       and now all keyserver access is done via the keyserver plugins.
       There is also a newer keyserver protocol used between GnuPG and
       the plugins, so plugins from earlier versions of GnuPG may not
       work properly.
 
     * The HKP keyserver plugin supports the new machine-readable key
       listing format for those keyservers that provide it.
 
     * When using a HKP keyserver with multiple DNS records (such as
       wwwkeys.pgp.net which has the addresses of multiple servers
       around the world), try all records until one succeeds.  Note
       that it depends on the LDAP library used whether the LDAP
       keyserver plugin does this as well.
 
     * The library dependencies for OpenLDAP seem to change fairly
       frequently, and GnuPG's configure script cannot guess all the
       combinations.  Use ./configure LDAPLIBS="-L libdir -l libs" to
       override the script and use the libraries selected.
 
     * Secret keys generated with --export-secret-subkeys are now
       indicated in key listings with a '#' after the "sec", and in
       --with-colons listings by showing no capabilities (no lowercase
       characters).
 
     * --trusted-key has been un-obsoleted, as it is useful for adding
       ultimately trusted keys from the config file.  It is identical
       to using --edit and "trust" to change a key to ultimately
       trusted.
 
     * Translations other than de are no longer distributed with the
       development branch.  This is due to the frequent text changes
       during development, which cause the translations to rapidly go
       out of date.
 
 
 Version 1.2.8 (2006-12-07)
 Version 1.2.7 (2004-12-27)
 Version 1.2.6 (2004-08-25)
 Version 1.2.5 (2004-07-26)
 Version 1.2.4 (2003-12-23)
 Version 1.2.3 (2003-08-21)
 Version 1.2.2 (2003-05-01)
 Version 1.2.1 (2002-10-25)
 Version 1.2.0 (2002-09-21)
 
 
 Noteworthy changes in version 1.1.92 (2002-09-11)
 -------------------------------------------------
 
     * [IMPORTANT] The default configuration file is now
       ~/.gnupg/gpg.conf.  If an old ~/.gnupg/options is found it will
       still be used.  This change is required to have a more
       consistent naming scheme with forthcoming tools.
 
     * The use of MDCs have increased.  A MDC will be used if the
       recipients directly request it, if the recipients have AES,
       AES192, AES256, or TWOFISH in their cipher preferences, or if
       the chosen cipher has a blocksize not equal to 64 bits
       (currently this is also AES, AES192, AES256, and TWOFISH).
 
     * GnuPG will no longer automatically disable compression when
       processing an already-compressed file unless a MDC is being
       used.  This is to give the message a certain amount of
       resistance to the chosen-ciphertext attack while communicating
       with other programs (most commonly PGP earlier than version 7.x)
       that do not support MDCs.
 
     * The option --interactive now has the desired effect when
       importing keys.
 
     * The file permission and ownership checks on files have been
       clarified.  Specifically, the homedir (usually ~/.gnupg) is
       checked to protect everything within it.  If the user specifies
       keyrings outside this homedir, they are presumed to be shared
       keyrings and therefore *not* checked.  Configuration files
       specified with the --options option and the IDEA cipher
       extension specified with --load-extension are checked, along
       with their enclosing directories.
 
     * The configure option --with-static-rnd=auto allows to build gpg
       with all available entropy gathering modules included.  At
       runtime the best usable one will be selected from the list
       linux, egd, unix.  This is also the default for systems lacking
       a /dev/random device.
 
     * The default character set is now taken from the current locale;
       it can still be overridden by the --charset option.  Using the
       option -vvv shows the used character set.
 
     * [REMOVED] --emulate-checksum-bug and --emulate-3des-s2k-bug have
       been removed.
 
 
 Noteworthy changes in version 1.1.91 (2002-08-04)
 -------------------------------------------------
 
     * All modules are now linked statically; the --load-extension
       option is in general not useful anymore.  The only exception is
       to specify the deprecated idea cipher.
 
     * The IDEA plugin has changed.  Previous versions of the IDEA
       plugin will no longer work with GnuPG.  However, the current
       version of the plugin will work with earlier GnuPG versions.
 
     * When using --batch with one of the --delete-key commands, the
       key must be specified by fingerprint.  See the man page for
       details.
 
     * There are now various ways to restrict the ability GnuPG has to
       exec external programs (for the keyserver helpers or photo ID
       viewers).  Read the README file for the complete list.
 
     * New export option to leave off attribute packets (photo IDs)
       during export.  This is useful when exporting to HKP keyservers
       which do not understand attribute packets.
 
     * New import option to repair during import the HKP keyserver
       mangling multiple subkeys bug.  Note that this cannot completely
       repair the damaged key as some crucial data is removed by the
       keyserver, but it does at least give you back one subkey.  This
       is on by default for keyserver --recv-keys, and off by default
       for regular --import.
 
     * The keyserver helper programs now live in
       /usr/[local/]libexec/gnupg by default.  If you are upgrading
       from 1.0.7, you might want to delete your old copies in
       /usr/[local/]bin.  If you use an OS that does not use libexec
       for whatever reason, use configure --libexecdir=/usr/local/lib
       to place the keyserver helpers there.
 
     * The LDAP keyserver handler now works properly with very old
       (version 1) LDAP keyservers.
 
 
 Noteworthy changes in version 1.1.90 (2002-07-01)
 -------------------------------------------------
 
     * New commands: --personal-cipher-preferences,
       --personal-digest-preferences, and
       --personal-compress-preferences allow the user to specify which
       algorithms are to be preferred.  Note that this does not permit
       using an algorithm that is not present in the recipient's
       preferences (which would violate the OpenPGP standard).  This
       just allows sorting the preferences differently.
 
     * New "group" command to refer to several keys with one name.
 
     * A warning is issued if the user forces the use of an algorithm
       that is not listed in the recipient's preferences.
 
     * Full revocation key (aka "designated revoker") support.
 
     * The preferred hash algorithms on a key are consulted when
       encrypting a signed message to that key.  Note that this is
       disabled by default by a SHA1 preference in
       --personal-digest-preferences.
 
     * --cert-digest-algo allows the user to specify the hash algorithm
       to use when signing a key rather than the default SHA1 (or MD5
       for PGP2 keys).  Do not use this feature unless you fully
       understand the implications of this.
 
     * --pgp7 mode automatically sets all necessary options to ensure
       that the resulting message will be usable by a user of PGP 7.x.
 
     * New --attribute-fd command for frontends and scripts to get the
       contents of attribute packets (i.e. photos)
 
     * In expert mode, the user can now re-sign a v3 key with a v4
       self-signature.  This does not change the v3 key into a v4 key,
       but it does allow the user to use preferences, primary ID flags,
       etc.
 
     * Significantly improved photo ID support on non-unixlike
       platforms.
 
     * The version number has jumped ahead to 1.1.90 to skip over the
       old version 1.1 and to get ready for the upcoming 1.2.
 
     * ElGamal sign and encrypt is not anymore allowed in the key
       generation dialog unless in expert mode.  RSA sign and encrypt
       has been added with the same restrictions.
 
     * [W32] Keyserver access does work with Windows NT.
 
 
 Noteworthy changes in version 1.0.7 (2002-04-29)
 ------------------------------------------------
 
     * Secret keys are now stored and exported in a new format which
       uses SHA-1 for integrity checks.  This format renders the
       Rosa/Klima attack useless.  Other OpenPGP implementations might
       not yet support this, so the option --simple-sk-checksum creates
       the old vulnerable format.
 
     * The default cipher algorithm for encryption is now CAST5,
       default hash algorithm is SHA-1.  This will give us better
       interoperability with other OpenPGP implementations.
 
     * Symmetric encrypted messages now use a fixed file size if
       possible.  This is a tradeoff: it breaks PGP 5, but fixes PGP 2,
       6, and 7.  Note this was only an issue with RFC-1991 style
       symmetric messages.
 
     * Photographic user ID support.  This uses an external program to
       view the images.
 
     * Enhanced keyserver support via keyserver "plugins".  GnuPG comes
       with plugins for the NAI LDAP keyserver as well as the HKP email
       keyserver.  It retains internal support for the HKP HTTP
       keyserver.
 
     * Nonrevocable signatures are now supported.  If a user signs a
       key nonrevocably, this signature cannot be taken back so be
       careful!
 
     * Multiple signature classes are usable when signing a key to
       specify how carefully the key information (fingerprint, photo
       ID, etc) was checked.
 
     * --pgp2 mode automatically sets all necessary options to ensure
       that the resulting message will be usable by a user of PGP 2.x.
 
     * --pgp6 mode automatically sets all necessary options to ensure
       that the resulting message will be usable by a user of PGP 6.x.
 
     * Signatures may now be given an expiration date.  When signing a
       key with an expiration date, the user is prompted whether they
       want their signature to expire at the same time.
 
     * Revocation keys (designated revokers) are now supported if
       present.  There is currently no way to designate new keys as
       designated revokers.
 
     * Permissions on the .gnupg directory and its files are checked
       for safety.
 
     * --expert mode enables certain silly things such as signing a
       revoked user id, expired key, or revoked key.
 
     * Some fixes to build cleanly under Cygwin32.
 
     * New tool gpgsplit to split OpenPGP data formats into packets.
 
     * New option --preserve-permissions.
 
     * Subkeys created in the future are not used for encryption or
       signing unless the new option --ignore-valid-from is used.
 
     * Revoked user-IDs are not listed unless signatures are listed too
       or we are in verbose mode.
 
     * There is no default comment string with ascii armors anymore
       except for revocation certificates and --enarmor mode.
 
     * The command "primary" in the edit menu can be used to change the
       primary UID, "setpref" and "updpref" can be used to change the
       preferences.
 
     * Fixed the preference handling; since 1.0.5 they were erroneously
       matched against against the latest user ID and not the given one.
 
     * RSA key generation.
 
     * Merged Stefan's patches for RISC OS in.  See comments in
       scripts/build-riscos.
 
     * It is now possible to sign and conventional encrypt a message (-cs).
 
     * The MDC feature flag is supported and can be set by using
       the "updpref" edit command.
 
     * The status messages GOODSIG and BADSIG are now returning the primary
       UID, encoded using %XX escaping (but with spaces left as spaces,
       so that it should not break too much)
 
     * Support for GDBM based keyrings has been removed.
 
     * The entire keyring management has been revamped.
 
     * The way signature stati are store has changed so that v3
       signatures can be supported. To increase the speed of many
       operations for existing keyrings you can use the new
       --rebuild-keydb-caches command.
 
     * The entire key validation process (trustdb) has been revamped.
       See the man page entries for --update-trustdb, --check-trustdb
       and --no-auto-check-trustdb.
 
     * --trusted-keys is again obsolete, --edit can be used to set the
       ownertrust of any key to ultimately trusted.
 
     * A subkey is never used to sign keys.
 
     * Read only keyrings are now handled as expected.
 
     See-also: gnupg-announce/2002q2/000135.html
 
 
 Noteworthy changes in version 1.0.6 (2001-05-29)
 ------------------------------------------------
 
     * Security fix for a format string bug in the tty code.
 
     * Fixed format string bugs in all PO files.
 
     * Removed Russian translation due to too many bugs.  The FTP
       server has an unofficial but better translation in the contrib
       directory.
 
     * Fixed expire time calculation and keyserver access.
 
     * The usual set of minor bug fixes and enhancements.
 
     * non-writable keyrings are now correctly handled.
 
     See-also: gnupg-announce/2001q2/000123.html
 
 
 Noteworthy changes in version 1.0.5 (2001-04-29)
 ------------------------------------------------
 
     * WARNING: The semantics of --verify have changed to address a
       problem with detached signature detection. --verify now ignores
       signed material given on stdin unless this is requested by using
       a "-" as the name for the file with the signed material.  Please
       check all your detached signature handling applications and make
       sure that they don't pipe the signed material to stdin without
       using a filename together with "-" on the the command line.
 
     * WARNING: Corrected hash calculation for input data larger than
       512M - it was just wrong, so you might notice bad signature in
       some very big files.  It may be wise to keep an old copy of
       GnuPG around.
 
     * Secret keys are no longer imported unless you use the new option
       --allow-secret-key-import.  This is a kludge and future versions will
       handle it in another way.
 
     * New command "showpref" in the --edit-key menu to show an easier
       to understand preference listing.
 
     * There is now the notation of a primary user ID.  For example, it
       is printed with a signature verification as the first user ID;
       revoked user IDs are not printed there anymore.  In general the
       primary user ID is the one with the latest self-signature.
 
     * New --charset=utf-8 to bypass all internal conversions.
 
     * Large File Support (LFS) is now working.
 
     * New options: --ignore-crc-error, --no-sig-create-check,
       --no-sig-cache, --fixed-list-mode, --no-expensive-trust-checks,
       --enable-special-filenames and --use-agent.  See man page.
 
     * New command --pipemode, which can be used to run gpg as a
       co-process.  Currently only the verification of detached
       signatures are working.  See doc/DETAILS.
 
     * Keyserver support for the W32 version.
 
     * Rewritten key selection code so that GnuPG can better cope with
       multiple subkeys, expire dates and so.  The drawback is that it
       is slower.
 
     * A whole lot of bug fixes.
 
     * The verification status of self-signatures are now cached. To
       increase the speed of key list operations for existing keys you
       can do the following in your GnuPG homedir (~/.gnupg):
          cp pubring.gpg pubring.gpg.save && gpg --export-all >x && \
          rm pubring.gpg && gpg --import x
       Only v4 keys (i.e not the old RSA keys) benefit from this caching.
 
     * New translations: Estonian, Turkish.
 
     See-also: gnupg-announce/2001q2/000122.html
 
 
 Noteworthy changes in version 1.0.4 (2000-10-17)
 ------------------------------------------------
 
     * Fixed a serious bug which could lead to false signature verification
       results when more than one signature is fed to gpg.  This is the
       primary reason for releasing this version.
 
     * New utility gpgv which is a stripped down version of gpg to
       be used to verify signatures against a list of trusted keys.
 
     * Rijndael (AES) is now supported and listed with top preference.
 
     * --with-colons now works with --print-md[s].
 
     See-also: gnupg-announce/2000q4/000082.html
 
 
 Noteworthy changes in version 1.0.3 (2000-09-18)
 ------------------------------------------------
 
     * Fixed problems with piping to/from other MS-Windows software
 
     * Expiration time of the primary key can be changed again.
 
     * Revoked user IDs are now marked in the output of --list-key
 
     * New options --show-session-key and --override-session-key
       to help the British folks to somewhat minimize the danger
       of this Orwellian RIP bill.
 
     * New options --merge-only and --try-all-secrets.
 
     * New configuration option --with-egd-socket.
 
     * The --trusted-key option is back after it left us with 0.9.5
 
     * RSA is supported. Key generation does not yet work but will come
       soon.
 
     * CAST5 and SHA-1 are now the default algorithms to protect the key
       and for symmetric-only encryption. This should solve a couple
       of compatibility problems because the old algorithms are optional
       according to RFC2440
 
     * Twofish and MDC enhanced encryption is now used.  PGP 7 supports
       this.  Older versions of GnuPG don't support it, so they should be
       upgraded to at least 1.0.2
 
     See-also: gnupg-announce/2000q3/000075.html
 
 
 Noteworthy changes in version 1.0.2 (2000-07-12)
 ----------------------------------------------
 
     * Fixed expiration handling of encryption keys.
 
     * Add an experimental feature to do unattended key generation.
 
     * The user is now asked for the reason of revocation as required
       by the new OpenPGP draft.
 
     * There is a ~/.gnupg/random_seed file now which saves the
       state of the internal RNG and increases system performance
       somewhat.  This way the full entropy source is only used in
       cases were it is really required.
       Use the option --no-random-seed-file to disable this feature.
 
     * New options --ignore-time-conflict and --lock-never.
 
     * Some fixes for the W32 version.
 
     * The entropy.dll is not anymore used by the W32 version but replaced
       by code derived from Cryptlib.
 
     * Encryption is now much faster: About 2 times for 1k bit keys
       and 8 times for 4k keys.
 
     * New encryption keys are generated in a way which allows a much
       faster decryption.
 
     * New command --export-secret-subkeys which outputs the
       the _primary_ key with it's secret parts deleted.  This is
       useful for automated decryption/signature creation as it
       allows to keep the real secret primary key offline and
       thereby protecting the key certificates and allowing to
       create revocations for the subkeys.  See the FAQ for a
       procedure to install such secret keys.
 
     * Keygeneration now writes to the first writeable keyring or
       as default to the one in the homedirectory.  Prior versions
       ignored all --keyring options.
 
     * New option --command-fd to take user input from a file descriptor;
       to be used with --status-fd by software which uses GnuPG as a backend.
 
     * There is a new status PROGRESS which is used to show progress during
       key generation.
 
     * Support for the new MDC encryption packets.  To create them either
       --force-mdc must be use or cipher algorithm with a blocksize other
       than 64 bits is to be used.  --openpgp currently disables MDC packets
       entirely.  This option should not yet be used.
 
     * New option --no-auto-key-retrieve to disable retrieving of
       a missing public key from a keyserver, when a keyserver has been set.
 
     * Danish translation
 
     See-also: gnupg-announce/2000q3/000069.html
 
 
 Noteworthy changes in version 1.0.1 (1999-12-16)
 -----------------------------------
 
     * New command --verify-files.  New option --fast-list-mode.
 
     * $http_proxy is now used when --honor-http-proxy is set.
 
     * Fixed some minor bugs and the problem with conventional encrypted
       packets which did use the gpg v3 partial length headers.
 
     * Add Indonesian and Portugese translations.
 
     * Fixed a bug with symmetric-only encryption using the non-default 3DES.
       The option --emulate-3des-s2k-bug may be used to decrypt documents
       which have been encrypted this way; this should be done immediately
       as this workaround will be remove in 1.1
 
     * Can now handle (but not display) PGP's photo IDs. I don't know the
       format of that packet but after stripping a few bytes from the start
       it looks like a JPEG (at least my test data).  Handling of this
       package is required because otherwise it would mix up the
       self signatures and you can't import those keys.
 
     * Passing non-ascii user IDs on the commandline should now work in all
       cases.
 
     * New keys are now generated with an additional preference to Blowfish.
 
     * Removed the GNU Privacy Handbook from the distribution as it will go
       into a separate one.
 
     See-also: gnupg-announce/1999q4/000050.html
 
 
 Noteworthy changes in version 1.0.0 (1999-09-07)
 -----------------------------------
 
     * Add a very preliminary version of the GNU Privacy Handbook to
       the distribution (lynx doc/gph/index.html).
 
     * Changed the version number to GnuPG 2001 ;-)
 
     See-also: gnupg-announce/1999q3/000037.html
 
 
 Noteworthy changes in version 0.9.11 (1999-09-03)
 ------------------------------------
 
     * UTF-8 strings are now correctly printed (if --charset is set correctly).
       Output of --with-colons remains C-style escaped UTF-8.
 
     * Workaround for a problem with PGP 5 detached signature in textmode.
 
     * Fixed a problem when importing new subkeys (duplicated signatures).
 
     See-also: gnupg-announce/1999q3/000036.html
 
 
 Noteworthy changes in version 0.9.10 (1999-07-23)
 ------------------------------------
 
     * Some strange new options to help pgpgpg
 
     * Cleaned up the dox a bit.
 
     See-also: gnupg-announce/1999q3/000034.html
 
 
 Noteworthy changes in version 0.9.9
 -----------------------------------
 
     * New options --[no-]utf8-strings.
 
     * New edit-menu commands "enable" and "disable" for entire keys.
 
     * You will be asked for a filename if gpg cannot deduce one.
 
     * Changes to support libtool which is needed for the development
       of libgcrypt.
 
     * New script tools/lspgpot to help transferring assigned
       trustvalues from PGP to GnuPG.
 
     * New commands --lsign-key and made --sign-key a shortcut for --edit
       and sign.
 
     * New options (#122--126 ;-) --[no-]default-recipient[-self],
       --disable-{cipher,pubkey}-algo. See the man page.
 
     * Enhanced info output in case of multiple recipients and fixed exit code.
 
     * New option --allow-non-selfsigned-uid to work around a problem with
       the German IN way of separating signing and encryption keys.
 
     See-also: gnupg-announce/1999q3/000028.html
 
 
 Noteworthy changes in version 0.9.8 (1999-06-26)
 -----------------------------------
 
     * New subcommand "delsig" in the edit menu.
 
     * The name of the output file is not anymore the one which is
       embedded in the processed message, but the used filename with
       the extension stripped.  To revert to the old behaviour you can
       use the option --use-embedded-filename.
 
     * Another hack to cope with pgp2 generated detached signatures.
 
     * latin-2 character set works (--charset=iso-8859-2).
 
     * New option --with-key-data to list the public key parameters.
       New option -N to insert notations and a --set-policy-url.
       A couple of other options to allow reseting of options.
 
     * Better support for HPUX.
 
     See-also: gnupg-announce/1999q2/000016.html
 
 
 Noteworthy changes in version 0.9.7 (1999-05-23)
 -----------------------------------
 
     * Add some work arounds for a bugs in pgp 2 which led to bad signatures
       when used with canonical texts in some cases.
 
     * Enhanced some status outputs.
 
     See-also: gnupg-announce/1999q2/000000.html
 
 
 Noteworthy changes in version 0.9.6 (1999-05-06)
 -----------------------------------
 
     * Twofish is now statically linked by default. The experimental 128 bit
       version is now disabled.	Full support will be available as soon as
       the OpenPGP WG has decided on an interpretation of rfc2440.
 
     * Dropped support for the ancient Blowfish160 which is not OpenPGP.
 
     * Merged gpgm and gpg into one binary.
 
     * Add "revsig" and "revkey" commands to the edit menu.  It is now
       possible to revoke signature and subkeys.
 
 
 Noteworthy changes in version 0.9.5 (1999-03-20)
 -----------------------------------
 
     * New command "lsign" in the keyedit menu to create non-exportable
       signatures.  Removed --trusted-keys option.
 
     * A bunch of changes to the key validation code.
 
     * --list-trust-path now has an optional --with-colons format.
 
     * New command --recv-keys to import keys from an keyserver.
 
 
 Noteworthy changes in version 0.9.4 (1999-03-08)
 -----------------------------------
 
     * New configure option --enable-static-rnd=[egd|linux|unix|none]
       to select a random gathering module for static linking.
 
     * The original text is now verbatim copied to a cleartext signed message.
 
     * Bugfixes but there are still a couple of bugs.
 
 
 Noteworthy changes in version 0.9.3 (1999-02-19)
 -----------------------------------
 
     * Changed the internal design of getkey which now allows a
       efficient lookup of multiple keys and add a word match mode.
 
     * New options --[no-]encrypt-to.
 
     * Some changes to the configure stuff.  Switched to automake 1.4.
       Removed intl/ from CVS, autogen.sh now uses gettextize.
 
     * Preferences now include Twofish. Removed preference to Blowfish with
       a special hack to suppress the "not listed in preferences" warning;
       this is to allow us to switch completely to Twofish in the near future.
 
     * Changed the locking stuff.
 
     * Print all user ids of a good signature.
 
 
 Noteworthy changes in version 0.9.2 (1999-01-01)
 -----------------------------------
 
     * add some additional time warp checks.
 
     * Option --keyserver and command --send-keys to utilize HKP servers.
 
     * Upgraded to zlib 1.1.3 and fixed an inflate bug
 
     * More cleanup on the cleartext signatures.
 
 
 Noteworthy changes in version 0.9.1 (1999-01-01)
 -----------------------------------
 
     * Polish language support.
 
     * When querying the passphrase, the key ID of the primary key is
       displayed along with the one of the used secondary key.
 
     * Fixed a bug occurring when decrypting pgp 5 encrypted messages,
       fixed an infinite loop bug in the 3DES code and in the code
       which looks for trusted signatures.
 
     * Fixed a bug in the mpi library which caused signatures not to
       compare okay.
 
     * Rewrote the handling of cleartext signatures; the code is now
       better maintainable (I hope so).
 
     * New status output VALIDSIG only for valid signatures together
       with the fingerprint of the signer's key.
 
 
 Noteworthy changes in version 0.9.0 (1998-12-23)
 -----------------------------------
 
     * --export does now only exports rfc2440 compatible keys; the
       old behaviour is available with --export-all.
       Generation of v3 ElGamal (sign and encrypt) keys is not longer
       supported.
 
     * Fixed the uncompress bug.
 
     * Rewrote the rndunix module. There are two environment variables
       used for debugging now: GNUPG_RNDUNIX_DBG give the file to write
       debugging information (use "-" for stdout) and if GNUPG_RNDUNIX_DBGALL
       is set, all programs which are only tried are also printed.
 
     * New option --escape-from-lines to "dash-escape" "From " lines to
       prevent mailers to change them to ">From ".  This is not enabled by
       default because it is not in compliance with rfc2440 - however, you
       should turn it on.
 
 
 Noteworthy changes in version 0.4.5 (1998-12-08)
 -----------------------------------
 
     * The keyrings and the trustdb is now locked, so that
       other GnuPG processes won't damage these files.  You
       may want to put the option --lock-once into your options file.
 
     * The latest self-signatures are now used; this enables --import
       to see updated preferences etc.
 
     * Import of subkeys should now work.
 
     * Random gathering modules may now be loaded as extensions. Add
       such a module for most Unices but it is very experimental!
 
     * Brazilian language support.
 
 
 Noteworthy changes in version 0.4.4 (1998-11-20)
 -----------------------------------
 
     * Fixed the way the key expiration time is stored. If you have
       an expiration time on your key you should fix it with --edit-key
       and the command "expire".  I apologize for this inconvenience.
 
     * Add option --charset to support "koi8-r" encoding of user ids.
       (Not yet tested).
 
     * Preferences should now work again. You should run
       "gpgm --check-trustdb \*" to rebuild all preferences.
 
     * Checking of certificates should now work but this needs a lot
       of testing.  Key validation values are now cached in the
       trustdb; they should be recalculated as needed, but you may
       use --check-trustdb or --update-trustdb to do this.
 
     * Spanish translation by Urko Lusa.
 
     * Patch files are from now on signed.  See the man page
       for the new option --not-dash-escaped.
 
     * New syntax: --edit-key <userID> [<commands>]
       If you run it without --batch the commands are executed and then
       you are put into normal mode unless you use "quit" or "save" as
       one of the commands.  When in batch mode, the program quits after
       the last command, so you have to use "save" if you did some changes.
       It does not yet work completely, but may be used to list so the
       keys etc.
 
 
 Noteworthy changes in version 0.4.3 (1998-11-08)
 -----------------------------------
 
     * Fixed the gettext configure bug.
 
     * Kludge for RSA keys: keyid and length of a RSA key are
       correctly reported, but you get an error if you try to use
       this key (If you do not have the non-US version).
 
     * Experimental support for keyrings stored in a GDBM database.
       This is *much* faster than a standard keyring.  You will notice
       that the import gets slower with time; the reason is that all
       new keys are used to verify signatures of previous inserted
       keys.  Use "--keyring gnupg-gdbm:<name-of-gdbm-file>".  This is
       not (yet) supported for secret keys.
 
     * A Russian language file in the distribution (alternatives are in
       the contrib directory of the FTP servers)
 
     * commandline option processing now works as expected for GNU programs
       with the exception that you can't mix options and normal arguments.
 
     * Now --list-key lists all matching keys.  This is needed in some
       other places too.
 
 
 Noteworthy changes in version 0.4.2 (1998-10-18)
 -----------------------------------
 
     * This is only a snapshot: There are still a few bugs.
 
     * Fixed this huge memory leak.
 
     * Redesigned the trust database:  You should run "gpgm --check-trustdb".
       New command --update-trustdb, which adds new key from the public
       keyring into your trustdb
 
     * Fixed a bug in the armor code, leading to invalid packet errors.
       (a workaround for this was to use --no-armor).  The shorten line
       length (64 instead of 72) fixes a problem with pgp5 and keyservers.
 
     * comment packets are not anymore generated. "--export" filters
       them out.  One Exception:  The comment packets in a secret keyring
       are still used because they carry the factorization of the public
       prime product.
 
     * --import now only looks for KEYBLOCK headers, so you can now simply
       remove the "- " in front of such a header if someone accidentally signed
       such a message or the keyblock is part of a cleartext signed message.
 
     * --with-colons now lists the key expiration time and not anymore
       the valid period.
 
     * Some keyblocks created with old releases have a wrong sequence
       of packets, so that the keyservers don't accept these keys.
       Simply using "--edit-key" fixes the problem.
 
     * New option --force-v3-sigs to generate signed messages which are
       compatible to PGP 5.
 
     * Add some code to support DLD (for non ELF systems) - but this is
       not tested because my BSD box is currently broken.
 
     * New command "expire" in the edit-key menu.
 
 
 
 Noteworthy changes in version 0.4.1 (1998-10-07)
 -----------------------------------
 
     * A secondary key is used when the primary key is specified but cannot
       be used for the operation (if it is a sign-only key).
 
     * GNUPG can now handle concatenated armored messages:  There is still a
       bug if different kinds of messages are mixed.
 
     * Iterated+Salted passphrases now work.  If want to be sure that PGP5
       is able to handle them you may want to use the options
 	"--s2k-mode 3 --s2k-cipher-algo cast5 --s2k-digest-algo sha1"
       when changing a passphrase.
 
     * doc/OpenPGP talks about OpenPGP compliance, doc/HACKING gives
       a few hints about the internal structure.
 
     * Checked gnupg against the August 1998 draft (07) and I believe
       it is in compliance with this document (except for one point).
 
     * Fixed some bugs in the import merging code and rewrote some
       code for the trustdb.
 
 
 Noteworthy changes in version 0.4.0 (1998-09-18)
 -----------------------------------
 
     * Triple DES is now supported.  Michael Roth did this piece of
       needed work.  We have now all the coded needed to be OpenPGP
       compliant.
 
     * Added a simple rpm spec file (see INSTALL).
 
     * detached and armored signatures are now using "PGP SIGNATURE",
       except when --rfc1991 is used.
 
     * All times which are not in the yyyy-mm-dd format are now printed
       in local time.
 
 
 Noteworthy changes in version 0.3.5 (1998-09-14)
 -----------------------------------
 
     * New option --throw-keyid to create anonymous enciphered messages.
       If gpg detects such a message it tires all available secret keys
       in turn so decode it.  This is a gnupg extension and not in OpenPGP
       but it has been discussed there and afaik some products use this
       scheme too (Suggested by Nimrod Zimmerman).
 
     * Fixed a bug with 5 byte length headers.
 
     * --delete-[secret-]key is now also available in gpgm.
 
     * cleartext signatures are not anymore converted to LF only.
 
     * Fixed a trustdb problem.	Run "gpgm --check-trustdb" to fix old
       trust dbs.
 
     * Building in another directory should now work.
 
     * Weak key detection mechanism (Niklas Hernaeus).
 
 
 Noteworthy changes in version 0.3.4 (1998-08-11)
 -----------------------------------
 
     * New options --comment and --set-filename; see g10/OPTIONS
 
     * yes/no, y/n localized.
 
     * Fixed some bugs.
 
 
 Noteworthy changes in version 0.3.3 (1998-08-08)
 -----------------------------------
 
     * IMPORTANT: I found yet another bug in the way the secret keys
       are encrypted - I did it the way pgp 2.x did it, but OpenPGP
       and pgp 5.x specify another (in some aspects simpler) method.
       To convert your secret keys you have to do this:
 	1. Build the new release but don't install it and keep
 	   a copy of the old program.
 	2. Disable the network, make sure that you are the only
 	   user, be sure that there are no Trojan horses etc ....
 	3. Use your old gpg (version 0.3.1 or 0.3.2) and set the
 	   passphrases of ALL your secret keys to empty!
 	   (gpg --change-passphrase your-user-id).
 	4. Save your ownertrusts (see the next point)
 	5. rm ~/.gnupg/trustdb.gpg
 	6. install the new version of gpg (0.3.3)
 	7. For every secret key call "gpg --edit-key your-user-id",
 	   enter "passwd" at the prompt, follow the instructions and
 	   change your password back, enter "save" to store it.
 	8. Restore the ownertrust (see next point).
 
     * The format of the trust database has changed; you must delete
       the old one, so gnupg can create a new one.
       IMPORTANT: Use version 0.3.1 or .2 to save your assigned ownertrusts
       ("gpgm --list-ownertrust >saved-trust"); then build this new version
       and restore the ownertrust with this new version
       ("gpgm --import-ownertrust saved-trust").  Please note that
       --list-ownertrust has been renamed to --export-ownertrust in this
       release and it does now only export defined ownertrusts.
 
     * The command --edit-key now provides a commandline driven menu
       which can be used for various tasks.  --sign-key is only an
       an alias to --edit-key and maybe removed in future: use the
       command "sign" of this new menu - you can select which user ids
       you want to sign.
 
     * Alternate user ids can now be created an signed.
 
     * Owner trust values can now be changed with --edit-key (trust)
 
     * GNUPG can now run as a coprocess; this enables sophisticated
       frontends.  tools/shmtest.c is a simple sample implementation.
       This needs some more work: all tty_xxx() are to be replaced
       by cpr_xxx() and some changes in the display logics is needed.
 
     * Removed options --gen-prime and --gen-random.
 
     * Removed option --add-key; use --edit-key instead.
 
     * Removed option --change-passphrase; use --edit-key instead.
 
     * Signatures are now checked even if the output file could not
       be created. Command "--verify" tries to find the detached data.
 
     * gpg now disables core dumps.
 
     * compress and symmetric cipher preferences are now used.
       Because there is no 3DES yet, this is replaced by Blowfish.
 
     * We have added the Twofish as an experimental cipher algorithm.
       Many thanks to Matthew Skala for doing this work.
       Twofish is the AES submission from Schneier et al.; see
       "www.counterpane.com/twofish.html" for more information.
 
     * Started with a help system: If you enter a question mark at some
       prompt; you should get a specific help for this prompt.
 
     * There is no more backup copy of the secret keyring.
 
     * A lot of new bugs. I think this release is not as stable as
       the previous one.
 
 
 Noteworthy changes in version 0.3.2 (1998-07-09)
 -----------------------------------
 
     * Fixed some bugs when using --textmode (-seat)
 
     * Now displays the trust status of a positive verified message.
 
     * Keyrings are now scanned in the sequence they are added with
       --[secret-]keyring.  Note that the default keyring is implicitly
       added as the very first one unless --no-default-keyring is used.
 
     * Fixed setuid and dlopen bug.
 
 
 Noteworthy changes in version 0.3.1 (1998-07-06)
 -----------------------------------
 
     * Partial headers are now written in the OpenPGP format if
       a key in a v4 packet is used.
 
     * Removed some unused options, removed the gnupg.sig stuff.
 
     * Key lookup by name now returns a key which can be used for
       the desired action.
 
     * New options --list-ownertrust (gpgm) to make a backup copy
       of the ownertrust values you assigned.
 
     * clear signature headers are now in compliance with OpenPGP.
 
 
 Noteworthy changes in version 0.3.0 (1998-06-25)
 -----------------------------------
 
     * New option --emulate-checksum-bug.  If your passphrase does not
       work anymore, use this option and --change-passphrase to rewrite
       your passphrase.
 
     * More complete v4 key support: Preferences and expiration time
       is set into the self signature.
 
     * Key generation defaults to DSA/ElGamal keys, so that new keys are
       interoperable with pgp5
 
     * DSA key generation is faster and key generation does not anymore
       remove entropy from the random generator (the primes are public
       parameters, so there is really no need for a cryptographic secure
       prime number generator which we had used).
 
     * A complete new structure for representing the key parameters.
 
     * Removed most public key knowledge into the cipher library.
 
     * Support for dynamic loading of new algorithms.
 
     * Moved tiger to an extension module.
 
 
 Noteworthy changes in version 0.2.19 (1998-05-29)
 ------------------------------------
 
     * Replaced /dev/urandom in checks with new tool mk-tdata.
 
     * Some assembler file cleanups; some more functions for the Alpha.
 
     * Tiger has now the OpenPGP assigned number 6.  Because the OID has
       changed, old signatures using this algorithm can't be verified.
 
     * gnupg now encrypts the compressed packed and not any longer in the
       reverse order; anyway it can decrypt both versions. Thanks to Tom
       for telling me this (not security related) bug.
 
     * --add-key works and you are now able to generate subkeys.
 
     * It is now possible to generate ElGamal keys in v4 packets to create
       valid OpenPGP keys.
 
     * Some new features for better integration into MUAs.
 
 
 Noteworthy changes in version 0.2.18 (1998-05-15)
 ------------------------------------
 
     * Splitted cipher/random.c, add new option "--disable-dev-random"
       to configure to support the development of a random source for
       other systems. Prepared sourcefiles rand-unix.c, rand-w32.c
       and rand-dummy.c (which is used to allow compilation on systems
       without a random source).
 
     * Fixed a small bug in the key generation (it was possible that 48 bits
       of a key were not taken from the random pool)
 
     * Add key generation for DSA and v4 signatures.
 
     * Add a function trap_unaligned(), so that a SIGBUS is issued on
       Alphas and not the slow emulation code is used. And success: rmd160
       raised a SIGBUS.
 
     * Enhanced the formatting facility of argparse and changed the use of
       \r,\v to @ because gettext does not like it.
 
     * New option "--compress-algo 1" to allow the creation of compressed
       messages which are readable by PGP and "--print-md" (gpgm) to make
       speed measurement easier.
 
 
 Noteworthy changes in version 0.2.17 (1998-05-04)
 ------------------------------------
 
     * Comment packets are now of private type 61.
 
     * Passphrase code still used a 160 bit blowfish key, added a
       silly workaround. Please change your passphrase again - sorry.
 
     * Conventional encryption now uses a type 3 packet to describe the
       used algorithms.
 
     * The new algorithm number for Blowfish is 20, 16 is still used for
       encryption only; for signing it is only used when it is in a v3 packet,
       so that GNUPG keys are still valid.
 
 
 Noteworthy changes in version 0.2.16 (1998-04-28)
 ------------------------------------
 
     * Add experimental support for the TIGER/192 message digest algorithm.
       (But there is only a dummy ASN OID).
 
     * Standard cipher is now Blowfish with 128 bit key in OpenPGP's CFB
       mode. I renamed the old cipher to Blowfish160. Because the OpenPGP
       group refused to assign me a number for Blowfish160, I have to
       drop support for this in the future. You should use
       "--change-passphrase" to recode your current passphrase with 128
       bit Blowfish.
 
 
 Noteworthy changes in version 0.2.15 (1998-04-09)
 ------------------------------------
 
     * Fixed a bug with the old checksum calculation for secret keys.
       If you run the program without --batch, a warning does inform
       you if your secret key needs to be converted; simply use
       --change-passphrase to recalculate the checksum. Please do this
       soon, as the compatible mode will be removed sometime in the future.
 
     * CAST5 works (using the PGP's special CFB mode).
 
     * Again somewhat more PGP 5 compatible.
 
     * Some new test cases
 
 Noteworthy changes in version 0.2.14 (1998-04-02)
 ------------------------------------
 
     * Changed the internal handling of keyrings.
 
     * Add support to list PGP 5 keyrings with subkeys
 
     * Timestamps of signatures are now verified.
 
     * A expiration time can now be specified during key generation.
 
     * Some speedups for Blowfish and SHA-1, rewrote SHA-1 transform.
       Reduced the amount of random bytes needed for key generation in
       some cases.
 
 
 Noteworthy changes in version 0.2.13 (1998-03-10)
 ------------------------------------
 
     * Verify of DSA signatures works.
 
     * Re-implemented the slower random number generator.
 
 
 Noteworthy changes in version 0.2.12 (1998-03-07)
 ------------------------------------
 
     * --delete-key checks that there is no secret key. The new
       option --delete-secret-key maybe used to delete a secret key.
 
     * "-kv" now works as expected. Options "--list-{keys,sigs]"
       and "--check-sigs" are now working.
 
     * New options "--verify" and "--decrypt" to better support integration
       into MUAs (partly done for Mutt).
 
     * New option "--with-colons" to make parsing of key lists easier.
 
 Noteworthy changes in version 0.2.11 (1998-03-02)
 ------------------------------------
 
     * GPG now asks for a recipient's name if option "-r" is not used.
 
     * If there is no good trust path, the program asks whether to use
       the public keys anyway.
 
     * "--delete-key" works for public keys. What semantics shall I use
       when there is a secret key too? Delete the secret key or leave him
       and auto-regenerate the public key, next time the secret key is used?
 
 Noteworthy changes in version 0.2.10 (1998-02-27)
 ------------------------------------
 
     * Code for the alpha is much faster (about 20 times); the data
       was misaligned and the kernel traps this, so nearly all time
       was used by system to trap the misalignments and to write
       syslog messages. Shame on me and thanks to Ralph for
       pointing me at this while drinking some beer yesterday.
 
     * Changed some configure options and add an option
       --disable-m-guard to remove the memory checking code
       and to compile everything with optimization on.
 
     * New environment variable GNUPGHOME, which can be used to set
       another homedir than ~/.gnupg.  Changed default homedir for
       Windoze version to c:/gnupg.
 
     * Fixed detached signatures; detached PGP signatures caused a SEGV.
 
     * The Windoze version works (as usual w/o a strong RNG).
 
 
 Noteworthy changes in version 0.2.9 (1998-02-26)
 -----------------------------------
 
     * Fixed FreeBSD bug.
 
     * Added a simple man page.
 
     * Switched to automake1.2f and a newer gettext.
 
 Noteworthy changes in version 0.2.8 (1998-02-24)
 -----------------------------------
 
     * Changed the name to GNUPG, the binaries are called gpg and gpgm.
       You must rename rename the directory "~/.g10" to ~/.gnupg/, rename
       {pub,sec}ring.g10 to {pub,sec}ring.gpg, trustdb.g10 to trustdb.gpg
       and g10.sig to gnupg.sig.
 
     * New or changed passphrases are now salted.
 
 
 Noteworthy changes in version 0.2.7 (1998-02-18)
 -----------------------------------
 
     * New command "gen-revoke" to create a key revocation certificate.
 
     * New option "homedir" to set the homedir (which defaults to "~/.g10").
       This directory is created if it does not exists (only the last
       part of the name and not the complete hierarchy)
 
     * Command "import" works. (Try: "finger gcrypt@ftp.guug.de|g10 --import")
 
     * New commands "dearmor/enarmor" for g10maint.  These are mainly
       used for internal test purposes.
 
     * Option --version now conforming to the GNU standards and lists
       the available ciphers, message digests and public key algorithms.
 
     * Assembler code for m68k (not tested).
 
     * "make check" works.
 
 Noteworthy changes in version 0.2.6 (1998-02-13)
 -----------------------------------
 
     * Option "--export" works.
 
 
 Noteworthy changes in version 0.2.5 (1998-02-12)
 -----------------------------------
 
     * Added zlib for systems which don't have it.
       Use "./configure --with-zlib" to link with the static version.
 
     * Generalized some more functions and rewrote the encoding of
       message digests into MPIs.
 
     * Enhanced the checkit script
 
 
 Noteworthy changes in version 0.2.4 (1998-02-11)
 -----------------------------------
 
     * nearly doubled the speed of the ElGamal signature verification.
 
     * backup copies of keyrings are created.
 
     * assembler stuff for Pentium; gives about 15% better performance.
 
     * fixed a lot of bugs.
 
 
 Noteworthy changes in version 0.2.3 (1998-02-09)
 -----------------------------------
 
     * Found a bug in the calculation of ELG fingerprints. This is now
       fixed, but all existing fingerprints and keyids for ELG keys
       are not any more valid.
 
     * armor should now work; including clear signed text.
 
     * moved some options to the new program g10maint
 
     * It's now 64 bit clean and runs fine on an alpha--linux.
 
     * Key generation is much faster now.  I fixed this by using not
       so strong random number for the primes (this was a bug because the
       ElGamal primes are public parameters and it does not make sense
       to generate them from strong random).  The real secret is the x value
       which is still generated from strong (okay: /dev/random) random bits.
 
     * added option "--status-fd": see g10/OPTIONS
 
     * We have secure memory on systems which support mlock().
       It is not complete yet, because we do not have signal handler
       which does a cleanup in very case.
       We should also check the ulimit for the user in the case
       that the admin does not have set a limit on locked pages.
 
     * started with internationalization support.
 
     * The logic to handle the web of trust is now implemented. It is
       has some bugs; but I'm going to change the algorithm anyway.
       It works by calculating the trustlevel on the fly.  It may ask
       you to provide trust parameters if the calculated trust probability
       is too low.  I will write a paper which discusses this new approach.
 
     * a couple of changes to the configure script.
 
     * New option "--quick-random" which uses a much quicker random
       number generator.  Keys generated while this option is in effect
       are flags with "INSECURE!" in the user-id.  This is a development
       only option.
 
     * Read support for new version packets (OpenPGP).
 
     * Comment packets are now of correct OpenPGP type 16. Old comment
       packets written by G10 are detected because they always start with
       a hash which is an invalid version byte.
 
     * The string "(INSECURE!)" is appended to a new user-id if this
       is generated on a system without a good random number generator.
 
 
 Version 0.2.2 (1998-02-09)
 Version 0.2.1 (1998-01-28)
 Version 0.2.0 (1998-01-25)
 Version 0.1.3 (1998-01-12)
 Version 0.1.2 (1998-01-07)
 Version 0.1.1 (1998-01-07)
 Version 0.1.0 (1998-01-05)
 Version 0.0.0 (1997-12-20)
 
 
  Copyright (C) 1998-2017 Free Software Foundation, Inc.
  Copyright (C) 1997-2017 Werner Koch
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
  modifications, as long as this notice is preserved.
 
  This file is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index 82450d2b1..ce689cffd 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -1,1712 +1,1722 @@
 @c Copyright (C) 2002 Free Software Foundation, Inc.
 @c This is part of the GnuPG manual.
 @c For copying conditions, see the file gnupg.texi.
 
 @include defs.inc
 
 @node Invoking GPGSM
 @chapter Invoking GPGSM
 @cindex GPGSM command options
 @cindex command options
 @cindex options, GPGSM command
 
 @manpage gpgsm.1
 @ifset manverb
 .B gpgsm
 \- CMS encryption and signing tool
 @end ifset
 
 @mansect synopsis
 @ifset manverb
 .B  gpgsm
 .RB [ \-\-homedir
 .IR dir ]
 .RB [ \-\-options
 .IR file ]
 .RI [ options ]
 .I command
 .RI [ args ]
 @end ifset
 
 
 @mansect description
 @command{gpgsm} is a tool similar to @command{gpg} to provide digital
 encryption and signing services on X.509 certificates and the CMS
 protocol.  It is mainly used as a backend for S/MIME mail processing.
 @command{gpgsm} includes a full featured certificate management and
 complies with all rules defined for the German Sphinx project.
 
 @manpause
 @xref{Option Index}, for an index to @command{GPGSM}'s commands and options.
 @mancont
 
 @menu
 * GPGSM Commands::        List of all commands.
 * GPGSM Options::         List of all options.
 * GPGSM Configuration::   Configuration files.
 * GPGSM Examples::        Some usage examples.
 
 Developer information:
 * Unattended Usage::      Using @command{gpgsm} from other programs.
 * GPGSM Protocol::        The protocol the server mode uses.
 @end menu
 
 @c *******************************************
 @c ***************            ****************
 @c ***************  COMMANDS  ****************
 @c ***************            ****************
 @c *******************************************
 @mansect commands
 @node GPGSM Commands
 @section Commands
 
 Commands are not distinguished from options except for the fact that
 only one command is allowed.
 
 @menu
 * General GPGSM Commands::        Commands not specific to the functionality.
 * Operational GPGSM Commands::    Commands to select the type of operation.
 * Certificate Management::        How to manage certificates.
 @end menu
 
 
 @c *******************************************
 @c **********  GENERAL COMMANDS  *************
 @c *******************************************
 @node General GPGSM Commands
 @subsection Commands not specific to the function
 
 @table @gnupgtabopt
 @item --version
 @opindex version
 Print the program version and licensing information.  Note that you
 cannot abbreviate this command.
 
 @item --help, -h
 @opindex help
 Print a usage message summarizing the most useful command-line options.
 Note that you cannot abbreviate this command.
 
 @item --warranty
 @opindex warranty
 Print warranty information.  Note that you cannot abbreviate this
 command.
 
 @item --dump-options
 @opindex dump-options
 Print a list of all available options and commands.  Note that you cannot
 abbreviate this command.
 @end table
 
 
 @c *******************************************
 @c ********  OPERATIONAL COMMANDS  ***********
 @c *******************************************
 @node Operational GPGSM Commands
 @subsection Commands to select the type of operation
 
 @table @gnupgtabopt
 @item --encrypt
 @opindex encrypt
 Perform an encryption.  The keys the data is encrypted to must be set
 using the option @option{--recipient}.
 
 @item --decrypt
 @opindex decrypt
 Perform a decryption; the type of input is automatically determined.  It
 may either be in binary form or PEM encoded; automatic determination of
 base-64 encoding is not done.
 
 @item --sign
 @opindex sign
 Create a digital signature.  The key used is either the fist one found
 in the keybox or those set with the @option{--local-user} option.
 
 @item --verify
 @opindex verify
 Check a signature file for validity.  Depending on the arguments a
 detached signature may also be checked.
 
 @item --server
 @opindex server
 Run in server mode and wait for commands on the @code{stdin}.
 
 @item --call-dirmngr @var{command} [@var{args}]
 @opindex call-dirmngr
 Behave as a Dirmngr client issuing the request @var{command} with the
 optional list of @var{args}.  The output of the Dirmngr is printed
 stdout.  Please note that file names given as arguments should have an
 absolute file name (i.e. commencing with @code{/}) because they are
 passed verbatim to the Dirmngr and the working directory of the
 Dirmngr might not be the same as the one of this client.  Currently it
 is not possible to pass data via stdin to the Dirmngr.  @var{command}
 should not contain spaces.
 
 This is command is required for certain maintaining tasks of the dirmngr
 where a dirmngr must be able to call back to @command{gpgsm}.  See the Dirmngr
 manual for details.
 
 @item --call-protect-tool @var{arguments}
 @opindex call-protect-tool
 Certain maintenance operations are done by an external program call
 @command{gpg-protect-tool}; this is usually not installed in a directory
 listed in the PATH variable.  This command provides a simple wrapper to
 access this tool.  @var{arguments} are passed verbatim to this command;
 use @samp{--help} to get a list of supported operations.
 
 
 @end table
 
 
 @c *******************************************
 @c *******  CERTIFICATE MANAGEMENT  **********
 @c *******************************************
 @node Certificate Management
 @subsection How to manage the certificates and keys
 
 @table @gnupgtabopt
 @item --generate-key
 @opindex generate-key
 @itemx --gen-key
 @opindex gen-key
 This command allows the creation of a certificate signing request or a
 self-signed certificate.  It is commonly used along with the
 @option{--output} option to save the created CSR or certificate into a
 file.  If used with the @option{--batch} a parameter file is used to
 create the CSR or certificate and it is further possible to create
 non-self-signed certificates.
 
 @item --list-keys
 @itemx -k
 @opindex list-keys
 List all available certificates stored in the local key database.
 Note that the displayed data might be reformatted for better human
 readability and illegal characters are replaced by safe substitutes.
 
 @item --list-secret-keys
 @itemx -K
 @opindex list-secret-keys
 List all available certificates for which a corresponding a secret key
 is available.
 
 @item --list-external-keys @var{pattern}
 @opindex list-keys
 List certificates matching @var{pattern} using an external server.  This
 utilizes the @code{dirmngr} service.
 
 @item --list-chain
 @opindex list-chain
 Same as @option{--list-keys} but also prints all keys making up the chain.
 
 
 @item --dump-cert
 @itemx --dump-keys
 @opindex dump-cert
 @opindex dump-keys
 List all available certificates stored in the local key database using a
 format useful mainly for debugging.
 
 @item --dump-chain
 @opindex dump-chain
 Same as @option{--dump-keys} but also prints all keys making up the chain.
 
 @item --dump-secret-keys
 @opindex dump-secret-keys
 List all available certificates for which a corresponding a secret key
 is available using a format useful mainly for debugging.
 
 @item --dump-external-keys @var{pattern}
 @opindex dump-external-keys
 List certificates matching @var{pattern} using an external server.
 This utilizes the @code{dirmngr} service.  It uses a format useful
 mainly for debugging.
 
 @item --keydb-clear-some-cert-flags
 @opindex keydb-clear-some-cert-flags
 This is a debugging aid to reset certain flags in the key database
 which are used to cache certain certificate stati.  It is especially
 useful if a bad CRL or a weird running OCSP responder did accidentally
 revoke certificate.  There is no security issue with this command
 because @command{gpgsm} always make sure that the validity of a certificate is
 checked right before it is used.
 
 @item --delete-keys @var{pattern}
 @opindex delete-keys
 Delete the keys matching @var{pattern}.  Note that there is no command
 to delete the secret part of the key directly.  In case you need to do
 this, you should run the command @code{gpgsm --dump-secret-keys KEYID}
 before you delete the key, copy the string of hex-digits in the
 ``keygrip'' line and delete the file consisting of these hex-digits
 and the suffix @code{.key} from the @file{private-keys-v1.d} directory
 below our GnuPG home directory (usually @file{~/.gnupg}).
 
 @item --export [@var{pattern}]
 @opindex export
 Export all certificates stored in the Keybox or those specified by the
 optional @var{pattern}. Those pattern consist of a list of user ids
 (@pxref{how-to-specify-a-user-id}).  When used along with the
 @option{--armor} option a few informational lines are prepended before
 each block.  There is one limitation: As there is no commonly agreed
 upon way to pack more than one certificate into an ASN.1 structure,
 the binary export (i.e. without using @option{armor}) works only for
 the export of one certificate.  Thus it is required to specify a
 @var{pattern} which yields exactly one certificate.  Ephemeral
 certificate are only exported if all @var{pattern} are given as
 fingerprints or keygrips.
 
 @item --export-secret-key-p12 @var{key-id}
 @opindex export-secret-key-p12
 Export the private key and the certificate identified by @var{key-id}
 using the PKCS#12 format.  When used with the @code{--armor} option a few
 informational lines are prepended to the output.  Note, that the PKCS#12
 format is not very secure and proper transport security should be used
 to convey the exported key.  (@xref{option --p12-charset}.)
 
 @item --export-secret-key-p8 @var{key-id}
 @itemx --export-secret-key-raw @var{key-id}
 @opindex export-secret-key-p8
 @opindex export-secret-key-raw
 Export the private key of the certificate identified by @var{key-id}
 with any encryption stripped.  The @code{...-raw} command exports in
 PKCS#1 format; the @code{...-p8} command exports in PKCS#8 format.
 When used with the @code{--armor} option a few informational lines are
 prepended to the output.  These commands are useful to prepare a key
 for use on a TLS server.
 
 @item --import [@var{files}]
 @opindex import
 Import the certificates from the PEM or binary encoded files as well as
 from signed-only messages.  This command may also be used to import a
 secret key from a PKCS#12 file.
 
 @item --learn-card
 @opindex learn-card
 Read information about the private keys from the smartcard and import
 the certificates from there.  This command utilizes the @command{gpg-agent}
 and in turn the @command{scdaemon}.
 
 @item --change-passphrase @var{user_id}
 @opindex change-passphrase
 @itemx --passwd @var{user_id}
 @opindex passwd
 Change the passphrase of the private key belonging to the certificate
 specified as @var{user_id}.  Note, that changing the passphrase/PIN of a
 smartcard is not yet supported.
 
 @end table
 
 
 @c *******************************************
 @c ***************            ****************
 @c ***************  OPTIONS   ****************
 @c ***************            ****************
 @c *******************************************
 @mansect options
 @node GPGSM Options
 @section Option Summary
 
 @command{GPGSM} features a bunch of options to control the exact behaviour
 and to change the default configuration.
 
 @menu
 * Configuration Options::   How to change the configuration.
 * Certificate Options::     Certificate related options.
 * Input and Output::        Input and Output.
 * CMS Options::             How to change how the CMS is created.
 * Esoteric Options::        Doing things one usually do not want to do.
 @end menu
 
 
 @c *******************************************
 @c ********  CONFIGURATION OPTIONS  **********
 @c *******************************************
 @node Configuration Options
 @subsection How to change the configuration
 
 These options are used to change the configuration and are usually found
 in the option file.
 
 @table @gnupgtabopt
 
 @anchor{gpgsm-option --options}
 @item --options @var{file}
 @opindex options
 Reads configuration from @var{file} instead of from the default
 per-user configuration file.  The default configuration file is named
 @file{gpgsm.conf} and expected in the @file{.gnupg} directory directly
 below the home directory of the user.
 
 @include opt-homedir.texi
 
 
 @item -v
 @item --verbose
 @opindex v
 @opindex verbose
 Outputs additional information while running.
 You can increase the verbosity by giving several
 verbose commands to @command{gpgsm}, such as @samp{-vv}.
 
 @item --keyserver @var{string}
 @opindex keyserver
 This is a deprecated option.  It was used to add an LDAP server to use
 for X.509 certificate and CRL lookup.  The alias @option{--ldapserver}
 existed from version 2.2.28 to 2.2.33 but is now entirely ignored.
 
 LDAP servers must be given in the configuration for @command{dirmngr}.
 
 
 @item --policy-file @var{filename}
 @opindex policy-file
 Change the default name of the policy file to @var{filename}.
 
 @item --agent-program @var{file}
 @opindex agent-program
 Specify an agent program to be used for secret key operations.  The
 default value is determined by running the command @command{gpgconf}.
 Note that the pipe symbol (@code{|}) is used for a regression test
 suite hack and may thus not be used in the file name.
 
 @item --dirmngr-program @var{file}
 @opindex dirmngr-program
 Specify a dirmngr program to be used for @acronym{CRL} checks.  The
 default value is @file{@value{BINDIR}/dirmngr}.
 
 @item --prefer-system-dirmngr
 @opindex prefer-system-dirmngr
 This option is obsolete and ignored.
 
 @item --disable-dirmngr
 Entirely disable the use of the Dirmngr.
 
 @item --no-autostart
 @opindex no-autostart
 Do not start the gpg-agent or the dirmngr if it has not yet been
 started and its service is required.  This option is mostly useful on
 machines where the connection to gpg-agent has been redirected to
 another machines.  If dirmngr is required on the remote machine, it
 may be started manually using @command{gpgconf --launch dirmngr}.
 
 @item --no-secmem-warning
 @opindex no-secmem-warning
 Do not print a warning when the so called "secure memory" cannot be used.
 
 @item --log-file @var{file}
 @opindex log-file
 When running in server mode, append all logging output to @var{file}.
 Use @file{socket://} to log to socket.
 
 @end table
 
 
 @c *******************************************
 @c ********  CERTIFICATE OPTIONS  ************
 @c *******************************************
 @node Certificate Options
 @subsection Certificate related options
 
 @table @gnupgtabopt
 
 @item  --enable-policy-checks
 @itemx --disable-policy-checks
 @opindex enable-policy-checks
 @opindex disable-policy-checks
 By default policy checks are enabled.  These options may be used to
 change it.
 
 @item  --enable-crl-checks
 @itemx --disable-crl-checks
 @opindex enable-crl-checks
 @opindex disable-crl-checks
 By default the @acronym{CRL} checks are enabled and the DirMngr is
 used to check for revoked certificates.  The disable option is most
 useful with an off-line network connection to suppress this check and
 also to avoid that new certificates introduce a web bug by including a
 certificate specific CRL DP.  The disable option also disables an
 issuer certificate lookup via the authorityInfoAccess property of the
 certificate; the @option{--enable-issuer-key-retrieve} can be used
 to make use of that property anyway.
 
 @item  --enable-trusted-cert-crl-check
 @itemx --disable-trusted-cert-crl-check
 @opindex enable-trusted-cert-crl-check
 @opindex disable-trusted-cert-crl-check
 By default the @acronym{CRL} for trusted root certificates are checked
 like for any other certificates.  This allows a CA to revoke its own
 certificates voluntary without the need of putting all ever issued
 certificates into a CRL.  The disable option may be used to switch this
 extra check off.  Due to the caching done by the Dirmngr, there will not be
 any noticeable performance gain.  Note, that this also disables possible
 OCSP checks for trusted root certificates.  A more specific way of
 disabling this check is by adding the ``relax'' keyword to the root CA
 line of the @file{trustlist.txt}
 
 
 @item --force-crl-refresh
 @opindex force-crl-refresh
 Tell the dirmngr to reload the CRL for each request.  For better
 performance, the dirmngr will actually optimize this by suppressing
 the loading for short time intervals (e.g. 30 minutes). This option
 is useful to make sure that a fresh CRL is available for certificates
 hold in the keybox.  The suggested way of doing this is by using it
 along with the option @option{--with-validation} for a key listing
 command.  This option should not be used in a configuration file.
 
 @item --enable-issuer-based-crl-check
 @opindex enable-issuer-based-crl-check
 Run a CRL check even for certificates which do not have any CRL
 distribution point.  This requires that a suitable LDAP server has
 been configured in Dirmngr and that the CRL can be found using the
 issuer.  This option reverts to what GnuPG did up to version 2.2.20.
 This option is in general not useful.
 
 @item  --enable-ocsp
 @itemx --disable-ocsp
 @opindex enable-ocsp
 @opindex disable-ocsp
 By default @acronym{OCSP} checks are disabled.  The enable option may
 be used to enable OCSP checks via Dirmngr.  If @acronym{CRL} checks
 are also enabled, CRLs will be used as a fallback if for some reason an
 OCSP request will not succeed.  Note, that you have to allow OCSP
 requests in Dirmngr's configuration too (option
 @option{--allow-ocsp}) and configure Dirmngr properly.  If you do not do
 so you will get the error code @samp{Not supported}.
 
 @item --auto-issuer-key-retrieve
 @opindex auto-issuer-key-retrieve
 If a required certificate is missing while validating the chain of
 certificates, try to load that certificate from an external location.
 This usually means that Dirmngr is employed to search for the
 certificate.  Note that this option makes a "web bug" like behavior
 possible.  LDAP server operators can see which keys you request, so by
 sending you a message signed by a brand new key (which you naturally
 will not have on your local keybox), the operator can tell both your IP
 address and the time when you verified the signature.
 
 
 @anchor{gpgsm-option --validation-model}
 @item --validation-model @var{name}
 @opindex validation-model
 This option changes the default validation model.  The only possible
 values are "shell" (which is the default), "chain" which forces the
 use of the chain model and "steed" for a new simplified model.  The
 chain model is also used if an option in the @file{trustlist.txt} or
 an attribute of the certificate requests it.  However the standard
 model (shell) is in that case always tried first.
 
 @item --ignore-cert-extension @var{oid}
 @opindex ignore-cert-extension
 Add @var{oid} to the list of ignored certificate extensions.  The
 @var{oid} is expected to be in dotted decimal form, like
 @code{2.5.29.3}.  This option may be used more than once.  Critical
 flagged certificate extensions matching one of the OIDs in the list
 are treated as if they are actually handled and thus the certificate
 will not be rejected due to an unknown critical extension.  Use this
 option with care because extensions are usually flagged as critical
 for a reason.
 
 @end table
 
 @c *******************************************
 @c ***********  INPUT AND OUTPUT  ************
 @c *******************************************
 @node Input and Output
 @subsection Input and Output
 
 @table @gnupgtabopt
 @item --armor
 @itemx -a
 @opindex armor
 Create PEM encoded output.  Default is binary output.
 
 @item --base64
 @opindex base64
 Create Base-64 encoded output; i.e. PEM without the header lines.
 
 @item --assume-armor
 @opindex assume-armor
 Assume the input data is PEM encoded.  Default is to autodetect the
 encoding but this is may fail.
 
 @item --assume-base64
 @opindex assume-base64
 Assume the input data is plain base-64 encoded.
 
 @item --assume-binary
 @opindex assume-binary
 Assume the input data is binary encoded.
 
+@item --input-size-hint @var{n}
+@opindex input-size-hint
+This option can be used to tell GPGSM the size of the input data in
+bytes.  @var{n} must be a positive base-10 number.  It is used by the
+@option{--status-fd} line ``PROGRESS'' to provide a value for
+``total'' if that is not available by other means.
+
 @anchor{option --p12-charset}
 @item --p12-charset @var{name}
 @opindex p12-charset
 @command{gpgsm} uses the UTF-8 encoding when encoding passphrases for
 PKCS#12 files.  This option may be used to force the passphrase to be
 encoded in the specified encoding @var{name}.  This is useful if the
 application used to import the key uses a different encoding and thus
 will not be able to import a file generated by @command{gpgsm}.  Commonly
 used values for @var{name} are @code{Latin1} and @code{CP850}.  Note
 that @command{gpgsm} itself automagically imports any file with a
 passphrase encoded to the most commonly used encodings.
 
 
 @item --default-key @var{user_id}
 @opindex default-key
 Use @var{user_id} as the standard key for signing.  This key is used if
 no other key has been defined as a signing key.  Note, that the first
 @option{--local-users} option also sets this key if it has not yet been
 set; however @option{--default-key} always overrides this.
 
 
 @item --local-user @var{user_id}
 @item -u @var{user_id}
 @opindex local-user
 Set the user(s) to be used for signing.  The default is the first
 secret key found in the database.
 
 
 @item --recipient @var{name}
 @itemx -r
 @opindex recipient
 Encrypt to the user id @var{name}.  There are several ways a user id
 may be given (@pxref{how-to-specify-a-user-id}).
 
 
 @item --output @var{file}
 @itemx -o @var{file}
 @opindex output
 Write output to @var{file}.  The default is to write it to stdout.
 
 
 @anchor{gpgsm-option --with-key-data}
 @item --with-key-data
 @opindex with-key-data
 Displays extra information with the @code{--list-keys} commands.  Especially
 a line tagged @code{grp} is printed which tells you the keygrip of a
 key.  This string is for example used as the file name of the
 secret key.  Implies @code{--with-colons}.
 
 @anchor{gpgsm-option --with-validation}
 @item --with-validation
 @opindex with-validation
 When doing a key listing, do a full validation check for each key and
 print the result.  This is usually a slow operation because it
 requires a CRL lookup and other operations.
 
 When used along with @option{--import}, a validation of the certificate to
 import is done and only imported if it succeeds the test.  Note that
 this does not affect an already available certificate in the DB.
 This option is therefore useful to simply verify a certificate.
 
 
 @item --with-md5-fingerprint
 For standard key listings, also print the MD5 fingerprint of the
 certificate.
 
 @item --with-keygrip
 Include the keygrip in standard key listings.  Note that the keygrip is
 always listed in @option{--with-colons} mode.
 
 @item --with-secret
 @opindex with-secret
 Include info about the presence of a secret key in public key listings
 done with @code{--with-colons}.
 
 @end table
 
 @c *******************************************
 @c *************  CMS OPTIONS  ***************
 @c *******************************************
 @node CMS Options
 @subsection How to change how the CMS is created
 
 @table @gnupgtabopt
 @item --include-certs @var{n}
 @opindex include-certs
 Using @var{n} of -2 includes all certificate except for the root cert,
 -1 includes all certs, 0 does not include any certs, 1 includes only the
 signers cert and all other positive values include up to @var{n}
 certificates starting with the signer cert.  The default is -2.
 
 @item --cipher-algo @var{oid}
 @opindex cipher-algo
 Use the cipher algorithm with the ASN.1 object identifier @var{oid} for
 encryption.  For convenience the strings @code{3DES}, @code{AES} and
 @code{AES256} may be used instead of their OIDs.  The default is
 @code{AES} (2.16.840.1.101.3.4.1.2).
 
 @item --digest-algo @code{name}
 Use @code{name} as the message digest algorithm.  Usually this
 algorithm is deduced from the respective signing certificate.  This
 option forces the use of the given algorithm and may lead to severe
 interoperability problems.
 
 @end table
 
 
 
 @c *******************************************
 @c ********  ESOTERIC OPTIONS  ***************
 @c *******************************************
 @node Esoteric Options
 @subsection Doing things one usually do not want to do
 
 
 @table @gnupgtabopt
 
 @item --extra-digest-algo @var{name}
 @opindex extra-digest-algo
 Sometimes signatures are broken in that they announce a different digest
 algorithm than actually used.  @command{gpgsm} uses a one-pass data
 processing model and thus needs to rely on the announced digest
 algorithms to properly hash the data.  As a workaround this option may
 be used to tell @command{gpgsm} to also hash the data using the algorithm
 @var{name}; this slows processing down a little bit but allows verification of
 such broken signatures.  If @command{gpgsm} prints an error like
 ``digest algo 8 has not been enabled'' you may want to try this option,
 with @samp{SHA256} for @var{name}.
 
 @item --compliance @var{string}
 @opindex compliance
 Set the compliance mode.  Valid values are shown when using "help" for
 @var{string}.
 
 @item --min-rsa-length @var{n}
 @opindex min-rsa-length
 This option adjusts the compliance mode "de-vs" for stricter key size
 requirements.  For example, a value of 3000 turns rsa2048 and dsa2048
 keys into non-VS-NfD compliant keys.
 
 @item --require-compliance
 @opindex require-compliance
 To check that data has been encrypted according to the rules of the
 current compliance mode, a gpgsm user needs to evaluate the status
 lines.  This is allows frontends to handle compliance check in a more
 flexible way.  However, for scripted use the required evaluation of
 the status-line requires quite some effort; this option can be used
 instead to make sure that the gpgsm process exits with a failure if
 the compliance rules are not fulfilled.  Note that this option has
 currently an effect only in "de-vs" mode.
 
 @item --ignore-cert-with-oid @var{oid}
 @opindex ignore-cert-with-oid
 Add @var{oid} to the list of OIDs to be checked while reading
 certificates from smartcards. The @var{oid} is expected to be in
 dotted decimal form, like @code{2.5.29.3}.  This option may be used
 more than once.  As of now certificates with an extended key usage
 matching one of those OIDs are ignored during a @option{--learn-card}
 operation and not imported.  This option can help to keep the local
 key database clear of unneeded certificates stored on smartcards.
 
 @item --faked-system-time @var{epoch}
 @opindex faked-system-time
 This option is only useful for testing; it sets the system time back or
 forth to @var{epoch} which is the number of seconds elapsed since the year
 1970.  Alternatively @var{epoch} may be given as a full ISO time string
 (e.g. "20070924T154812").
 
 @item --with-ephemeral-keys
 @opindex with-ephemeral-keys
 Include ephemeral flagged keys in the output of key listings.  Note
 that they are included anyway if the key specification for a listing
 is given as fingerprint or keygrip.
 
 @item --compatibility-flags @var{flags}
 @opindex compatibility-flags
 Set compatibility flags to work around problems due to non-compliant
 certificates or data.  The @var{flags} are given as a comma separated
 list of flag names and are OR-ed together.  The special flag "none"
 clears the list and allows to start over with an empty list.  To get a
 list of available flags the sole word "help" can be used.
 
 @item --debug-level @var{level}
 @opindex debug-level
 Select the debug level for investigating problems. @var{level} may be
 a numeric value or by a keyword:
 
 @table @code
 @item none
 No debugging at all.  A value of less than 1 may be used instead of
 the keyword.
 @item basic
 Some basic debug messages.  A value between 1 and 2 may be used
 instead of the keyword.
 @item advanced
 More verbose debug messages.  A value between 3 and 5 may be used
 instead of the keyword.
 @item expert
 Even more detailed messages.  A value between 6 and 8 may be used
 instead of the keyword.
 @item guru
 All of the debug messages you can get. A value greater than 8 may be
 used instead of the keyword.  The creation of hash tracing files is
 only enabled if the keyword is used.
 @end table
 
 How these messages are mapped to the actual debugging flags is not
 specified and may change with newer releases of this program. They are
 however carefully selected to best aid in debugging.
 
 @item --debug @var{flags}
 @opindex debug
 This option is only useful for debugging and the behaviour may change
 at any time without notice; using @code{--debug-levels} is the
 preferred method to select the debug verbosity.  FLAGS are bit encoded
 and may be given in usual C-Syntax. The currently defined bits are:
 
 @table @code
 @item 0  (1)
 X.509 or OpenPGP protocol related data
 @item 1  (2)
 values of big number integers
 @item 2  (4)
 low level crypto operations
 @item 5  (32)
 memory allocation
 @item 6  (64)
 caching
 @item 7  (128)
 show memory statistics
 @item 9  (512)
 write hashed data to files named @code{dbgmd-000*}
 @item 10 (1024)
 trace Assuan protocol
 @end table
 
 Note, that all flags set using this option may get overridden by
 @code{--debug-level}.
 
 @item --debug-all
 @opindex debug-all
 Same as @code{--debug=0xffffffff}
 
 @item --debug-allow-core-dump
 @opindex debug-allow-core-dump
 Usually @command{gpgsm} tries to avoid dumping core by well written code and by
 disabling core dumps for security reasons.  However, bugs are pretty
 durable beasts and to squash them it is sometimes useful to have a core
 dump.  This option enables core dumps unless the Bad Thing happened
 before the option parsing.
 
 @item --debug-no-chain-validation
 @opindex debug-no-chain-validation
 This is actually not a debugging option but only useful as such.  It
 lets @command{gpgsm} bypass all certificate chain validation checks.
 
 @item --debug-ignore-expiration
 @opindex debug-ignore-expiration
 This is actually not a debugging option but only useful as such.  It
 lets @command{gpgsm} ignore all notAfter dates, this is used by the regression
 tests.
 
 @item --passphrase-fd @code{n}
 @opindex passphrase-fd
 Read the passphrase from file descriptor @code{n}. Only the first line
 will be read from file descriptor @code{n}. If you use 0 for @code{n},
 the passphrase will be read from STDIN. This can only be used if only
 one passphrase is supplied.
 
 Note that this passphrase is only used if the option @option{--batch}
 has also been given.
 
 @item --pinentry-mode @code{mode}
 @opindex pinentry-mode
 Set the pinentry mode to @code{mode}.  Allowed values for @code{mode}
 are:
 @table @asis
   @item default
   Use the default of the agent, which is @code{ask}.
   @item ask
   Force the use of the Pinentry.
   @item cancel
   Emulate use of Pinentry's cancel button.
   @item error
   Return a Pinentry error (``No Pinentry'').
   @item loopback
   Redirect Pinentry queries to the caller.  Note that in contrast to
   Pinentry the user is not prompted again if he enters a bad password.
 @end table
 
 @item --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.
 
 @end table
 
 All the long options may also be given in the configuration file after
 stripping off the two leading dashes.
 
 @c *******************************************
 @c ***************            ****************
 @c ***************  USER ID   ****************
 @c ***************            ****************
 @c *******************************************
 @mansect how to specify a user id
 @ifset isman
 @include specify-user-id.texi
 @end ifset
 
 @c *******************************************
 @c ***************            ****************
 @c ***************   FILES    ****************
 @c ***************            ****************
 @c *******************************************
 @mansect files
 @node GPGSM Configuration
 @section Configuration files
 
 There are a few configuration files to control certain aspects of
 @command{gpgsm}'s operation. Unless noted, they are expected in the
 current home directory (@pxref{option --homedir}).
 
 @table @file
 
 @item gpgsm.conf
 @efindex gpgsm.conf
 This is the standard configuration file read by @command{gpgsm} on
 startup.  It may contain any valid long option; the leading two dashes
 may not be entered and the option may not be abbreviated.  This default
 name may be changed on the command line (@pxref{gpgsm-option --options}).
 You should backup this file.
 
 
 @item policies.txt
 @efindex policies.txt
 This is a list of allowed CA policies.  This file should list the
 object identifiers of the policies line by line.  Empty lines and
 lines starting with a hash mark are ignored.  Policies missing in this
 file and not marked as critical in the certificate will print only a
 warning; certificates with policies marked as critical and not listed
 in this file will fail the signature verification.  You should backup
 this file.
 
 For example, to allow only the policy 2.289.9.9, the file should look
 like this:
 
 @c man:.RS
 @example
 # Allowed policies
 2.289.9.9
 @end example
 @c man:.RE
 
 @item qualified.txt
 @efindex qualified.txt
 This is the list of root certificates used for qualified certificates.
 They are defined as certificates capable of creating legally binding
 signatures in the same way as handwritten signatures are.  Comments
 start with a hash mark and empty lines are ignored.  Lines do have a
 length limit but this is not a serious limitation as the format of the
 entries is fixed and checked by @command{gpgsm}: A non-comment line starts with
 optional whitespace, followed by exactly 40 hex characters, white space
 and a lowercased 2 letter country code.  Additional data delimited with
 by a white space is current ignored but might late be used for other
 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.
 
 Every time @command{gpgsm} uses a certificate for signing or verification
 this file will be consulted to check whether the certificate under
 question has ultimately been issued by one of these CAs.  If this is the
 case the user will be informed that the verified signature represents a
 legally binding (``qualified'') signature.  When creating a signature
 using such a certificate an extra prompt will be issued to let the user
 confirm that such a legally binding signature shall really be created.
 
 Because this software has not yet been approved for use with such
 certificates, appropriate notices will be shown to indicate this fact.
 
 @item help.txt
 @efindex help.txt
 This is plain text file with a few help entries used with
 @command{pinentry} as well as a large list of help items for
 @command{gpg} and @command{gpgsm}.  The standard file has English help
 texts; to install localized versions use filenames like @file{help.LL.txt}
 with LL denoting the locale.  GnuPG comes with a set of predefined help
 files in the data directory (e.g. @file{@value{DATADIR}/gnupg/help.de.txt})
 and allows overriding of any help item by help files stored in the
 system configuration directory (e.g. @file{@value{SYSCONFDIR}/help.de.txt}).
 For a reference of the help file's syntax, please see the installed
 @file{help.txt} file.
 
 
 @item com-certs.pem
 @efindex com-certs.pem
 This file is a collection of common certificates used to populated a
 newly created @file{pubring.kbx}.  An administrator may replace this
 file with a custom one.  The format is a concatenation of PEM encoded
 X.509 certificates.  This global file is installed in the data directory
 (e.g. @file{@value{DATADIR}/com-certs.pem}).
 
 @end table
 
 @c man:.RE
 Note that on larger installations, it is useful to put predefined files
 into the directory @file{/etc/skel/.gnupg/} so that newly created users
 start up with a working configuration.  For existing users a small
 helper script is provided to create these files (@pxref{addgnupghome}).
 
 For internal purposes @command{gpgsm} creates and maintains a few other files;
 they all live in the current home directory (@pxref{option
 --homedir}).  Only @command{gpgsm} may modify these files.
 
 
 @table @file
 @item pubring.kbx
 @efindex pubring.kbx
 This a database file storing the certificates as well as meta
 information.  For debugging purposes the tool @command{kbxutil} may be
 used to show the internal structure of this file.  You should backup
 this file.
 
 @item random_seed
 @efindex random_seed
 This content of this file is used to maintain the internal state of the
 random number generator across invocations.  The same file is used by
 other programs of this software too.
 
 @item S.gpg-agent
 @efindex S.gpg-agent
 If this file exists
 @command{gpgsm} will first try to connect to this socket for
 accessing @command{gpg-agent} before starting a new @command{gpg-agent}
 instance.  Under Windows this socket (which in reality be a plain file
 describing a regular TCP listening port) is the standard way of
 connecting the @command{gpg-agent}.
 
 @end table
 
 
 @c *******************************************
 @c ***************            ****************
 @c ***************  EXAMPLES  ****************
 @c ***************            ****************
 @c *******************************************
 @mansect examples
 @node GPGSM Examples
 @section Examples
 
 @example
 $ gpgsm -er goo@@bar.net <plaintext >ciphertext
 @end example
 
 
 @c *******************************************
 @c ***************              **************
 @c ***************  UNATTENDED  **************
 @c ***************              **************
 @c *******************************************
 @manpause
 @node Unattended Usage
 @section Unattended Usage
 
 @command{gpgsm} is often used as a backend engine by other software.  To help
 with this a machine interface has been defined to have an unambiguous
 way to do this.  This is most likely used with the @code{--server} command
 but may also be used in the standard operation mode by using the
 @code{--status-fd} option.
 
 @menu
 * Automated signature checking::  Automated signature checking.
 * CSR and certificate creation::  CSR and certificate creation.
 @end menu
 
 @node Automated signature checking
 @subsection Automated signature checking
 
 It is very important to understand the semantics used with signature
 verification.  Checking a signature is not as simple as it may sound and
 so the operation is a bit complicated.  In most cases it is required
 to look at several status lines.  Here is a table of all cases a signed
 message may have:
 
 @table @asis
 @item The signature is valid
 This does mean that the signature has been successfully verified, the
 certificates are all sane.  However there are two subcases with
 important information:  One of the certificates may have expired or a
 signature of a message itself as expired.  It is a sound practise to
 consider such a signature still as valid but additional information
 should be displayed.  Depending on the subcase @command{gpgsm} will issue
 these status codes:
   @table @asis
   @item signature valid and nothing did expire
   @code{GOODSIG}, @code{VALIDSIG}, @code{TRUST_FULLY}
   @item signature valid but at least one certificate has expired
   @code{EXPKEYSIG}, @code{VALIDSIG}, @code{TRUST_FULLY}
   @item signature valid but expired
   @code{EXPSIG}, @code{VALIDSIG}, @code{TRUST_FULLY}
   Note, that this case is currently not implemented.
   @end table
 
 @item The signature is invalid
 This means that the signature verification failed (this is an indication
 of a transfer error, a program error or tampering with the message).
 @command{gpgsm} issues one of these status codes sequences:
   @table @code
   @item  @code{BADSIG}
   @item  @code{GOODSIG}, @code{VALIDSIG} @code{TRUST_NEVER}
   @end table
 
 @item Error verifying a signature
 For some reason the signature could not be verified, i.e. it cannot be
 decided whether the signature is valid or invalid.  A common reason for
 this is a missing certificate.
 
 @end table
 
 @node CSR and certificate creation
 @subsection CSR and certificate creation
 
 The command @option{--generate-key} may be used along with the option
 @option{--batch} to either create a certificate signing request (CSR)
 or an X.509 certificate.  This is controlled by a parameter file; the
 format of this file is as follows:
 
 @itemize @bullet
 @item Text only, line length is limited to about 1000 characters.
 @item UTF-8 encoding must be used to specify non-ASCII characters.
 @item Empty lines are ignored.
 @item Leading and trailing while space is ignored.
 @item A hash sign as the first non white space character indicates
 a comment line.
 @item Control statements are indicated by a leading percent sign, the
 arguments are separated by white space from the keyword.
 @item Parameters are specified by a keyword, followed by a colon.  Arguments
 are separated by white space.
 @item The first parameter must be @samp{Key-Type}, control statements
 may be placed anywhere.
 @item
 The order of the parameters does not matter except for @samp{Key-Type}
 which must be the first parameter.  The parameters are only used for
 the generated CSR/certificate; parameters from previous sets are not
 used.  Some syntactically checks may be performed.
 @item
 Key generation takes place when either the end of the parameter file
 is reached, the next @samp{Key-Type} parameter is encountered or at the
 control statement @samp{%commit} is encountered.
 @end itemize
 
 @noindent
 Control statements:
 
 @table @asis
 
 @item %echo @var{text}
 Print @var{text} as diagnostic.
 
 @item %dry-run
 Suppress actual key generation (useful for syntax checking).
 
 @item %commit
 Perform the key generation.  Note that an implicit commit is done at
 the next @asis{Key-Type} parameter.
 
 @c  %certfile <filename>
 @c      [Not yet implemented!]
 @c	Do not write the certificate to the keyDB but to <filename>.
 @c      This must be given before the first
 @c	commit to take place, duplicate specification of the same filename
 @c	is ignored, the last filename before a commit is used.
 @c	The filename is used until a new filename is used (at commit points)
 @c	and all keys are written to that file.	If a new filename is given,
 @c	this file is created (and overwrites an existing one).
 @c	Both control statements must be given.
 @end table
 
 @noindent
 General Parameters:
 
 @table @asis
 
 @item Key-Type: @var{algo}
 Starts a new parameter block by giving the type of the primary
 key. The algorithm must be capable of signing.  This is a required
 parameter.  The supported values for @var{algo} are @samp{rsa},
 @samp{ecdsa}, and @samp{eddsa}.
 
 @item Key-Length: @var{nbits}
 The requested length of a generated key in bits.  Defaults to
 3072. The value is ignored for ECC algorithms.
 
 @item Key-Grip: @var{hexstring}
 This is optional and used to generate a CSR or certificate for an
 already existing key.  Key-Length will be ignored when given.
 
 @item Key-Usage: @var{usage-list}
 Space or comma delimited list of key usage, allowed values are
 @samp{encrypt}, @samp{sign} and @samp{cert}.  This is used to generate
 the keyUsage extension.  Please make sure that the algorithm is
 capable of this usage.  Default is to allow encrypt and sign.
 
 @item Name-DN: @var{subject-name}
 This is the Distinguished Name (DN) of the subject in RFC-2253 format.
 
 @item Name-Email: @var{string}
 This is an email address for the altSubjectName.  This parameter is
 optional but may occur several times to add several email addresses to
 a certificate.
 
 @item Name-DNS: @var{string}
 The is an DNS name for the altSubjectName.  This parameter is optional
 but may occur several times to add several DNS names to a certificate.
 
 @item Name-URI: @var{string}
 This is an URI for the altSubjectName.  This parameter is optional but
 may occur several times to add several URIs to a certificate.
 @end table
 
 @noindent
 Additional parameters used to create a certificate (in contrast to a
 certificate signing request):
 
 @table @asis
 
 @item Serial: @var{sn}
 If this parameter is given an X.509 certificate will be generated.
 @var{sn} is expected to be a hex string representing an unsigned
 integer of arbitrary length.  The special value @samp{random} can be
 used to create a 64 bit random serial number.
 
 @item Issuer-DN: @var{issuer-name}
 This is the DN name of the issuer in RFC-2253 format.  If it is not set
 it will default to the subject DN and a special GnuPG extension will
 be included in the certificate to mark it as a standalone certificate.
 
 @item Creation-Date: @var{iso-date}
 @itemx Not-Before: @var{iso-date}
 Set the notBefore date of the certificate.  Either a date like
 @samp{1986-04-26} or @samp{1986-04-26 12:00} or a standard ISO
 timestamp like @samp{19860426T042640} may be used.  The time is
 considered to be UTC.  If it is not given the current date is used.
 
 @item Expire-Date: @var{iso-date}
 @itemx Not-After: @var{iso-date}
 Set the notAfter date of the certificate.  Either a date like
 @samp{2063-04-05} or @samp{2063-04-05 17:00} or a standard ISO
 timestamp like @samp{20630405T170000} may be used.  The time is
 considered to be UTC.  If it is not given a default value in the not
 too far future is used.
 
 @item Signing-Key: @var{keygrip}
 This gives the keygrip of the key used to sign the certificate.  If it
 is not given a self-signed certificate will be created.  For
 compatibility with future versions, it is suggested to prefix the
 keygrip with a @samp{&}.
 
 @item Hash-Algo: @var{hash-algo}
 Use @var{hash-algo} for this CSR or certificate.  The supported hash
 algorithms are: @samp{sha1}, @samp{sha256}, @samp{sha384} and
 @samp{sha512}; they may also be specified with uppercase letters.  The
 default is @samp{sha256}.
 
 @item Authority-Key-Id: @var{hexstring}
 Insert the decoded value of @var{hexstring} as authorityKeyIdentifier.
 If this is not given and an ECC algorithm is used the public part of
 the certified public key is used as authorityKeyIdentifier.  To
 inhibit any authorityKeyIdentifier use the special value @code{none}
 for @var{hexstring}.
 
 @item Subject-Key-Id: @var{hexstring}
 Insert the decoded value of @var{hexstring} as subjectKeyIdentifier.
 If this is not given and an ECC algorithm is used the public part of
 the signing key is used as authorityKeyIdentifier.  To inhibit any
 subjectKeyIdentifier use the special value @code{none} for
 @var{hexstring}.
 
 @end table
 
 @c *******************************************
 @c ***************           *****************
 @c ***************  ASSSUAN  *****************
 @c ***************           *****************
 @c *******************************************
 @node GPGSM Protocol
 @section The Protocol the Server Mode Uses
 
 Description of the protocol used to access @command{GPGSM}.
 @command{GPGSM} does implement the Assuan protocol and in addition
 provides a regular command line interface which exhibits a full client
 to this protocol (but uses internal linking).  To start
 @command{gpgsm} as a server the command line the option
 @code{--server} must be used.  Additional options are provided to
 select the communication method (i.e. the name of the socket).
 
 We assume that the connection has already been established; see the
 Assuan manual for details.
 
 @menu
 * GPGSM ENCRYPT::         Encrypting a message.
 * GPGSM DECRYPT::         Decrypting a message.
 * GPGSM SIGN::            Signing a message.
 * GPGSM VERIFY::          Verifying a message.
 * GPGSM GENKEY::          Generating a key.
 * GPGSM LISTKEYS::        List available keys.
 * GPGSM EXPORT::          Export certificates.
 * GPGSM IMPORT::          Import certificates.
 * GPGSM DELETE::          Delete certificates.
 * GPGSM GETAUDITLOG::     Retrieve an audit log.
 * GPGSM GETINFO::         Information about the process
 * GPGSM OPTION::          Session options.
 @end menu
 
 
 @node GPGSM ENCRYPT
 @subsection Encrypting a Message
 
 Before encryption can be done the recipient must be set using the
 command:
 
 @example
   RECIPIENT @var{userID}
 @end example
 
 Set the recipient for the encryption.  @var{userID} should be the
 internal representation of the key; the server may accept any other way
 of specification.  If this is a valid and trusted recipient the server
 does respond with OK, otherwise the return is an ERR with the reason why
 the recipient cannot be used, the encryption will then not be done for
 this recipient.  If the policy is not to encrypt at all if not all
 recipients are valid, the client has to take care of this.  All
 @code{RECIPIENT} commands are cumulative until a @code{RESET} or an
 successful @code{ENCRYPT} command.
 
 @example
   INPUT FD[=@var{n}] [--armor|--base64|--binary]
 @end example
 
 Set the file descriptor for the message to be encrypted to @var{n}.
 Obviously the pipe must be open at that point, the server establishes
 its own end.  If the server returns an error the client should consider
 this session failed.  If @var{n} is not given, this commands uses the
 last file descriptor passed to the application.
 @xref{fun-assuan_sendfd, ,the assuan_sendfd function,assuan,the Libassuan
 manual}, on how to do descriptor passing.
 
 The @code{--armor} option may be used to advise the server that the
 input data is in @acronym{PEM} format, @code{--base64} advises that a
 raw base-64 encoding is used, @code{--binary} advises of raw binary
 input (@acronym{BER}).  If none of these options is used, the server
 tries to figure out the used encoding, but this may not always be
 correct.
 
 @example
   OUTPUT FD[=@var{n}] [--armor|--base64]
 @end example
 
 Set the file descriptor to be used for the output (i.e. the encrypted
 message). Obviously the pipe must be open at that point, the server
 establishes its own end.  If the server returns an error the client
 should consider this session failed.
 
 The option @option{--armor} encodes the output in @acronym{PEM} format, the
 @option{--base64} option applies just a base-64 encoding.  No option
 creates binary output (@acronym{BER}).
 
 The actual encryption is done using the command
 
 @example
   ENCRYPT
 @end example
 
 It takes the plaintext from the @code{INPUT} command, writes to the
 ciphertext to the file descriptor set with the @code{OUTPUT} command,
 take the recipients from all the recipients set so far.  If this command
 fails the clients should try to delete all output currently done or
 otherwise mark it as invalid.  @command{GPGSM} does ensure that there
 will not be any
 security problem with leftover data on the output in this case.
 
 This command should in general not fail, as all necessary checks have
 been done while setting the recipients.  The input and output pipes are
 closed.
 
 
 @node GPGSM DECRYPT
 @subsection Decrypting a message
 
 Input and output FDs are set the same way as in encryption, but
 @code{INPUT} refers to the ciphertext and @code{OUTPUT} to the plaintext. There
 is no need to set recipients.  @command{GPGSM} automatically strips any
 @acronym{S/MIME} headers from the input, so it is valid to pass an
 entire MIME part to the INPUT pipe.
 
 The decryption is done by using the command
 
 @example
   DECRYPT
 @end example
 
 It performs the decrypt operation after doing some check on the internal
 state (e.g. that all needed data has been set).  Because it utilizes
 the GPG-Agent for the session key decryption, there is no need to ask
 the client for a protecting passphrase - GpgAgent takes care of this by
 requesting this from the user.
 
 
 @node GPGSM SIGN
 @subsection Signing a Message
 
 Signing is usually done with these commands:
 
 @example
   INPUT FD[=@var{n}] [--armor|--base64|--binary]
 @end example
 
 This tells @command{GPGSM} to read the data to sign from file descriptor @var{n}.
 
 @example
   OUTPUT FD[=@var{m}] [--armor|--base64]
 @end example
 
 Write the output to file descriptor @var{m}.  If a detached signature is
 requested, only the signature is written.
 
 @example
   SIGN [--detached]
 @end example
 
 Sign the data set with the @code{INPUT} command and write it to the sink set by
 @code{OUTPUT}.  With @code{--detached}, a detached signature is created
 (surprise).
 
 The key used for signing is the default one or the one specified in
 the configuration file.  To get finer control over the keys, it is
 possible to use the command
 
 @example
   SIGNER @var{userID}
 @end example
 
 to set the signer's key.  @var{userID} should be the
 internal representation of the key; the server may accept any other way
 of specification.  If this is a valid and trusted recipient the server
 does respond with OK, otherwise the return is an ERR with the reason why
 the key cannot be used, the signature will then not be created using
 this key.  If the policy is not to sign at all if not all
 keys are valid, the client has to take care of this.  All
 @code{SIGNER} commands are cumulative until a @code{RESET} is done.
 Note that a @code{SIGN} does not reset this list of signers which is in
 contrast to the @code{RECIPIENT} command.
 
 
 @node GPGSM VERIFY
 @subsection Verifying a Message
 
 To verify a message the command:
 
 @example
   VERIFY
 @end example
 
 is used. It does a verify operation on the message send to the input FD.
 The result is written out using status lines.  If an output FD was
 given, the signed text will be written to that.  If the signature is a
 detached one, the server will inquire about the signed material and the
 client must provide it.
 
 @node GPGSM GENKEY
 @subsection Generating a Key
 
 This is used to generate a new keypair, store the secret part in the
 @acronym{PSE} and the public key in the key database.  We will probably
 add optional commands to allow the client to select whether a hardware
 token is used to store the key.  Configuration options to
 @command{GPGSM} can be used to restrict the use of this command.
 
 @example
   GENKEY
 @end example
 
 @command{GPGSM} checks whether this command is allowed and then does an
 INQUIRY to get the key parameters, the client should then send the
 key parameters in the native format:
 
 @example
     S: INQUIRE KEY_PARAM native
     C: D foo:fgfgfg
     C: D bar
     C: END
 @end example
 
 Please note that the server may send Status info lines while reading the
 data lines from the client.  After this the key generation takes place
 and the server eventually does send an ERR or OK response.  Status lines
 may be issued as a progress indicator.
 
 
 @node GPGSM LISTKEYS
 @subsection List available keys
 @anchor{gpgsm-cmd listkeys}
 
 To list the keys in the internal database or using an external key
 provider, the command:
 
 @example
   LISTKEYS  @var{pattern}
 @end example
 
 is used.  To allow multiple patterns (which are ORed during the search)
 quoting is required: Spaces are to be translated into "+" or into "%20";
 in turn this requires that the usual escape quoting rules are done.
 
 @example
   LISTSECRETKEYS @var{pattern}
 @end example
 
 Lists only the keys where a secret key is available.
 
 The list commands are affected by the option
 
 @example
   OPTION list-mode=@var{mode}
 @end example
 
 where mode may be:
 @table @code
 @item 0
 Use default (which is usually the same as 1).
 @item 1
 List only the internal keys.
 @item 2
 List only the external keys.
 @item 3
 List internal and external keys.
 @end table
 
 Note that options are valid for the entire session.
 
 
 @node GPGSM EXPORT
 @subsection Export certificates
 
 To export certificate from the internal key database the command:
 
 @example
   EXPORT [--data [--armor] [--base64]] [--] @var{pattern}
 @end example
 
 is used.  To allow multiple patterns (which are ORed) quoting is
 required: Spaces are to be translated into "+" or into "%20"; in turn
 this requires that the usual escape quoting rules are done.
 
 If the @option{--data} option has not been given, the format of the
 output depends on what was set with the @code{OUTPUT} command.  When using
 @acronym{PEM} encoding a few informational lines are prepended.
 
 If the @option{--data} has been given, a target set via @code{OUTPUT} is
 ignored and the data is returned inline using standard
 @code{D}-lines. This avoids the need for an extra file descriptor.  In
 this case the options @option{--armor} and @option{--base64} may be used
 in the same way as with the @code{OUTPUT} command.
 
 
 @node GPGSM IMPORT
 @subsection Import certificates
 
 To import certificates into the internal key database, the command
 
 @example
   IMPORT [--re-import]
 @end example
 
 is used.  The data is expected on the file descriptor set with the
 @code{INPUT} command.  Certain checks are performed on the
 certificate.  Note that the code will also handle PKCS#12 files and
 import private keys; a helper program is used for that.
 
 With the option @option{--re-import} the input data is expected to a be
 a linefeed separated list of fingerprints.  The command will re-import
 the corresponding certificates; that is they are made permanent by
 removing their ephemeral flag.
 
 
 @node GPGSM DELETE
 @subsection Delete certificates
 
 To delete a certificate the command
 
 @example
   DELKEYS @var{pattern}
 @end example
 
 is used.  To allow multiple patterns (which are ORed) quoting is
 required: Spaces are to be translated into "+" or into "%20"; in turn
 this requires that the usual escape quoting rules are done.
 
 The certificates must be specified unambiguously otherwise an error is
 returned.
 
 @node GPGSM GETAUDITLOG
 @subsection Retrieve an audit log
 @anchor{gpgsm-cmd getauditlog}
 
 This command is used to retrieve an audit log.
 
 @example
 GETAUDITLOG [--data] [--html]
 @end example
 
 If @option{--data} is used, the audit log is send using D-lines
 instead of being sent to the file descriptor given by an @code{OUTPUT}
 command.  If @option{--html} is used, the output is formatted as an
 XHTML block. This is designed to be incorporated into a HTML
 document.
 
 
 @node GPGSM GETINFO
 @subsection  Return information about the process
 
 This is a multipurpose function to return a variety of information.
 
 @example
 GETINFO @var{what}
 @end example
 
 The value of @var{what} specifies the kind of information returned:
 @table @code
 @item version
 Return the version of the program.
 @item pid
 Return the process id of the process.
 @item agent-check
 Return OK if the agent is running.
 @item cmd_has_option @var{cmd} @var{opt}
 Return OK if the command @var{cmd} implements the option @var{opt}.
 The leading two dashes usually used with @var{opt} shall not be given.
 @item offline
 Return OK if the connection is in offline mode.  This may be either
 due to a @code{OPTION offline=1} or due to @command{gpgsm} being
 started with option @option{--disable-dirmngr}.
 @end table
 
 @node GPGSM OPTION
 @subsection  Session options
 
 The standard Assuan option handler supports these options.
 
 @example
 OPTION @var{name}[=@var{value}]
 @end example
 
 These @var{name}s are recognized:
 
 @table @code
 
 @item putenv
 Change the session's environment to be passed via gpg-agent to
 Pinentry.  @var{value} is a string of the form
 @code{<KEY>[=[<STRING>]]}.  If only @code{<KEY>} is given the
 environment variable @code{<KEY>} is removed from the session
 environment, if @code{<KEY>=} is given that environment variable is
 set to the empty string, and if @code{<STRING>} is given it is set to
 that string.
 
 @item display
 @efindex DISPLAY
 Set the session environment variable @code{DISPLAY} is set to @var{value}.
 @item ttyname
 @efindex GPG_TTY
 Set the session environment variable @code{GPG_TTY} is set to @var{value}.
 @item ttytype
 @efindex TERM
 Set the session environment variable @code{TERM} is set to @var{value}.
 @item lc-ctype
 @efindex LC_CTYPE
 Set the session environment variable @code{LC_CTYPE} is set to @var{value}.
 @item lc-messages
 @efindex LC_MESSAGES
 Set the session environment variable @code{LC_MESSAGES} is set to @var{value}.
 @item xauthority
 @efindex XAUTHORITY
 Set the session environment variable @code{XAUTHORITY} is set to @var{value}.
 @item pinentry-user-data
 @efindex PINENTRY_USER_DATA
 Set the session environment variable @code{PINENTRY_USER_DATA} is set
 to @var{value}.
 
 @item include-certs
 This option overrides the command line option
 @option{--include-certs}.  A @var{value} of -2 includes all
 certificates except for the root certificate, -1 includes all
 certificates, 0 does not include any certificates, 1 includes only the
 signers certificate and all other positive values include up to
 @var{value} certificates starting with the signer cert.
 
 @item list-mode
 @xref{gpgsm-cmd listkeys}.
 
 @item list-to-output
 If @var{value} is true the output of the list commands
 (@pxref{gpgsm-cmd listkeys}) is written to the file descriptor set
 with the last @code{OUTPUT} command.  If @var{value} is false the output is
 written via data lines; this is the default.
 
 @item with-validation
 If @var{value} is true for each listed certificate the validation
 status is printed.  This may result in the download of a CRL or the
 user being asked about the trustworthiness of a root certificate.  The
 default is given by a command line option (@pxref{gpgsm-option
 --with-validation}).
 
 
 @item with-secret
 If @var{value} is true certificates with a corresponding private key
 are marked by the list commands.
 
 @item validation-model
 This option overrides the command line option
 @option{validation-model} for the session.
 (@xref{gpgsm-option --validation-model}.)
 
 @item with-key-data
 This option globally enables the command line option
 @option{--with-key-data}.  (@xref{gpgsm-option --with-key-data}.)
 
 @item enable-audit-log
 If @var{value} is true data to write an audit log is gathered.
 (@xref{gpgsm-cmd getauditlog}.)
 
 @item allow-pinentry-notify
 If this option is used notifications about the launch of a Pinentry
 are passed back to the client.
 
 @item with-ephemeral-keys
 If @var{value} is true ephemeral certificates are included in the
 output of the list commands.
 
 @item no-encrypt-to
 If this option is used all keys set by the command line option
 @option{--encrypt-to} are ignored.
 
 @item offline
 If @var{value} is true or @var{value} is not given all network access
 is disabled for this session.  This is the same as the command line
 option @option{--disable-dirmngr}.
 
+@item input-size-hint
+This is the same as the @option{--input-size-hint} command line option.
+
 @end table
 
 @mansect see also
 @ifset isman
 @command{gpg2}(1),
 @command{gpg-agent}(1)
 @end ifset
 @include see-also-note.texi
diff --git a/sm/decrypt.c b/sm/decrypt.c
index 9f8175c75..99422425c 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -1,1530 +1,1532 @@
 /* decrypt.c - Decrypt a message
  * Copyright (C) 2001, 2003, 2010 Free Software Foundation, Inc.
  * Copyright (C) 2001-2019 Werner Koch
  * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
 #include "../common/i18n.h"
 #include "../common/compliance.h"
 #include "../common/tlv.h"
 
 /* We can provide an enum value which is only availabale with KSBA
  * 1.6.0 so that we can compile even against older versions.  Some
  * calls will of course return an error in this case.  This value is
  * currently not used because the cipher mode is sufficient here.  */
 /* #if KSBA_VERSION_NUMBER < 0x010600  /\* 1.6.0 *\/ */
 /* # define KSBA_CT_AUTHENVELOPED_DATA 10 */
 /* #endif */
 
 
 struct decrypt_filter_parm_s
 {
   int algo;
   int mode;
   int blklen;
   gcry_cipher_hd_t hd;
   char iv[16];
   size_t ivlen;
   int any_data;  /* did we push anything through the filter at all? */
   unsigned char lastblock[16];  /* to strip the padding we have to
                                    keep this one */
   char helpblock[16];  /* needed because there is no block buffering in
                           libgcrypt (yet) */
   int  helpblocklen;
   int is_de_vs;        /* Helper to track CO_DE_VS state.  */
 };
 
 
 /* Return the hash algorithm's algo id from its name given in the
  * non-null termnated string in (buffer,buflen).  Returns 0 on failure
  * or if the algo is not known.  */
 static char *
 string_from_gcry_buffer (gcry_buffer_t *buffer)
 {
   char *string;
 
   string = xtrymalloc (buffer->len + 1);
   if (!string)
     return NULL;
   memcpy (string, buffer->data, buffer->len);
   string[buffer->len] = 0;
   return string;
 }
 
 
 /* Helper to construct and hash the
  *  ECC-CMS-SharedInfo ::= SEQUENCE {
  *      keyInfo         AlgorithmIdentifier,
  *      entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL,
  *      suppPubInfo [2] EXPLICIT OCTET STRING  }
  * as described in RFC-5753, 7.2.  */
 gpg_error_t
 hash_ecc_cms_shared_info (gcry_md_hd_t hash_hd, const char *wrap_algo_str,
                           unsigned int keylen,
                           const void *ukm, unsigned int ukmlen)
 {
   gpg_error_t err;
   void *p;
   unsigned char *oid;
   size_t n, oidlen, toidlen, tkeyinfo, tukmlen, tsupppubinfo;
   unsigned char keylenbuf[6];
   membuf_t mb = MEMBUF_ZERO;
 
   err = ksba_oid_from_str (wrap_algo_str, &oid, &oidlen);
   if (err)
     return err;
   toidlen = get_tlv_length (CLASS_UNIVERSAL, TAG_OBJECT_ID, 0, oidlen);
   tkeyinfo = get_tlv_length (CLASS_UNIVERSAL, TAG_SEQUENCE, 1, toidlen);
 
   tukmlen = ukm? get_tlv_length (CLASS_CONTEXT, 0, 1, ukmlen) : 0;
 
   keylen *= 8;
   keylenbuf[0] = TAG_OCTET_STRING;
   keylenbuf[1] = 4;
   keylenbuf[2] = (keylen >> 24);
   keylenbuf[3] = (keylen >> 16);
   keylenbuf[4] = (keylen >> 8);
   keylenbuf[5] = keylen;
 
   tsupppubinfo = get_tlv_length (CLASS_CONTEXT, 2, 1, sizeof keylenbuf);
 
   put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_SEQUENCE, 1,
                      tkeyinfo + tukmlen + tsupppubinfo);
   put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_SEQUENCE, 1,
                      toidlen);
   put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_OBJECT_ID, 0, oidlen);
   put_membuf (&mb, oid, oidlen);
   ksba_free (oid);
 
   if (ukm)
     {
       put_tlv_to_membuf (&mb, CLASS_CONTEXT, 0, 1, ukmlen);
       put_membuf (&mb, ukm, ukmlen);
     }
 
   put_tlv_to_membuf (&mb, CLASS_CONTEXT, 2, 1, sizeof keylenbuf);
   put_membuf (&mb, keylenbuf, sizeof keylenbuf);
 
   p = get_membuf (&mb, &n);
   if (!p)
     return gpg_error_from_syserror ();
 
   gcry_md_write (hash_hd, p, n);
   xfree (p);
   return 0;
 }
 
 
 
 /* Derive a KEK (key wrapping key) using (SECRET,SECRETLEN), an
  * optional (UKM,ULMLEN), the wrap algorithm WRAP_ALGO_STR in decimal
  * dotted form, and the hash algorithm HASH_ALGO.  On success a key of
  * length KEYLEN is stored at KEY.  */
 gpg_error_t
 ecdh_derive_kek (unsigned char *key, unsigned int keylen,
                  int hash_algo, const char *wrap_algo_str,
                  const void *secret, unsigned int secretlen,
                  const void *ukm, unsigned int ukmlen)
 {
   gpg_error_t err = 0;
   unsigned int hashlen;
   gcry_md_hd_t hash_hd;
   unsigned char counter;
   unsigned int n, ncopy;
 
   hashlen = gcry_md_get_algo_dlen (hash_algo);
   if (!hashlen)
     return gpg_error (GPG_ERR_INV_ARG);
 
   err = gcry_md_open (&hash_hd, hash_algo, 0);
   if (err)
     return err;
 
   /* According to SEC1 3.6.1 we should check that
    *   SECRETLEN + UKMLEN + 4 < maxhashlen
    * However, we have no practical limit on the hash length and thus
    * there is no point in checking this.  The second check that
    *   KEYLEN < hashlen*(2^32-1)
    * is obviously also not needed.
    */
   for (n=0, counter=1; n < keylen; counter++)
     {
       if (counter > 1)
         gcry_md_reset (hash_hd);
       gcry_md_write (hash_hd, secret, secretlen);
       gcry_md_write (hash_hd, "\x00\x00\x00", 3);  /* MSBs of counter */
       gcry_md_write (hash_hd, &counter, 1);
       err = hash_ecc_cms_shared_info (hash_hd, wrap_algo_str, keylen,
                                       ukm, ukmlen);
       if (err)
         break;
       gcry_md_final (hash_hd);
       if (n + hashlen > keylen)
         ncopy = keylen - n;
       else
         ncopy = hashlen;
       memcpy (key+n, gcry_md_read (hash_hd, 0), ncopy);
       n += ncopy;
     }
 
   gcry_md_close (hash_hd);
   return err;
 }
 
 
 /* This function will modify SECRET.  NBITS is the size of the curve
  * which which we took from the certificate.  */
 static gpg_error_t
 ecdh_decrypt (unsigned char *secret, size_t secretlen,
               unsigned int nbits, gcry_sexp_t enc_val,
               unsigned char **r_result, unsigned int *r_resultlen)
 {
   gpg_error_t err;
   gcry_buffer_t ioarray[4] = { {0}, {0}, {0}, {0} };
   char *encr_algo_str = NULL;
   char *wrap_algo_str = NULL;
   int hash_algo, cipher_algo;
   const unsigned char *ukm;  /* Alias for ioarray[2].  */
   unsigned int ukmlen;
   const unsigned char *data;  /* Alias for ioarray[3].  */
   unsigned int datalen;
   unsigned int keylen;
   unsigned char key[32];
   gcry_cipher_hd_t cipher_hd = NULL;
   unsigned char *result = NULL;
   unsigned int resultlen;
 
   *r_resultlen = 0;
   *r_result = NULL;
 
   /* Extract X from SECRET; this is the actual secret.  Unless a
    * smartcard diretcly returns X, it must be in the format of:
    *
    *   04 || X || Y
    *   40 || X
    *   41 || X
    */
   if (secretlen < 2)
     return gpg_error (GPG_ERR_BAD_DATA);
   if (secretlen == (nbits+7)/8)
     ; /* Matches curve length - this is already the X coordinate.  */
   else if (*secret == 0x04)
     {
       secretlen--;
       memmove (secret, secret+1, secretlen);
       if ((secretlen & 1))
         return gpg_error (GPG_ERR_BAD_DATA);
       secretlen /= 2;
     }
   else if (*secret == 0x40 || *secret == 0x41)
     {
       secretlen--;
       memmove (secret, secret+1, secretlen);
     }
   else
     return gpg_error (GPG_ERR_BAD_DATA);
   if (!secretlen)
     return gpg_error (GPG_ERR_BAD_DATA);
 
   if (DBG_CRYPTO)
     log_printhex (secret, secretlen, "ECDH X ..:");
 
   /* We have now the shared secret bytes in (SECRET,SECRETLEN).  Now
    * we will compute the KEK using a value dervied from the secret
    * bytes. */
   err = gcry_sexp_extract_param (enc_val, "enc-val",
                                  "&'encr-algo''wrap-algo''ukm'?s",
                                  ioarray+0, ioarray+1,
                                  ioarray+2, ioarray+3, NULL);
   if (err)
     {
       log_error ("extracting ECDH parameter failed: %s\n", gpg_strerror (err));
       goto leave;
     }
   encr_algo_str = string_from_gcry_buffer (ioarray);
   if (!encr_algo_str)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   wrap_algo_str = string_from_gcry_buffer (ioarray+1);
   if (!wrap_algo_str)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   ukm = ioarray[2].data;
   ukmlen = ioarray[2].len;
   data = ioarray[3].data;
   datalen = ioarray[3].len;
 
   /* Check parameters.  */
   if (DBG_CRYPTO)
     {
       log_debug ("encr_algo: %s\n", encr_algo_str);
       log_debug ("wrap_algo: %s\n", wrap_algo_str);
       log_printhex (ukm, ukmlen, "ukm .....:");
       log_printhex (data, datalen, "data ....:");
     }
 
   if (!strcmp (encr_algo_str, "1.3.132.1.11.1"))
     {
       /* dhSinglePass-stdDH-sha256kdf-scheme */
       hash_algo = GCRY_MD_SHA256;
     }
   else if (!strcmp (encr_algo_str, "1.3.132.1.11.2"))
     {
       /* dhSinglePass-stdDH-sha384kdf-scheme */
       hash_algo = GCRY_MD_SHA384;
     }
   else if (!strcmp (encr_algo_str, "1.3.132.1.11.3"))
     {
       /* dhSinglePass-stdDH-sha512kdf-scheme */
       hash_algo = GCRY_MD_SHA512;
     }
   else if (!strcmp (encr_algo_str, "1.3.133.16.840.63.0.2"))
     {
       /* dhSinglePass-stdDH-sha1kdf-scheme */
       hash_algo = GCRY_MD_SHA1;
     }
   else
     {
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
       goto leave;
     }
 
   if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.5"))
     {
       cipher_algo = GCRY_CIPHER_AES128;
       keylen = 16;
     }
   else if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.25"))
     {
       cipher_algo = GCRY_CIPHER_AES192;
       keylen = 24;
     }
   else if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.45"))
     {
       cipher_algo = GCRY_CIPHER_AES256;
       keylen = 32;
     }
   else
     {
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
       goto leave;
     }
 
   err = ecdh_derive_kek (key, keylen, hash_algo, wrap_algo_str,
                          secret, secretlen, ukm, ukmlen);
   if (err)
     goto leave;
 
   if (DBG_CRYPTO)
     log_printhex (key, keylen, "KEK .....:");
 
   /* Unwrap the key.  */
   if ((datalen % 8) || datalen < 16)
     {
       log_error ("can't use a shared secret of %u bytes for ecdh\n", datalen);
       err = gpg_error (GPG_ERR_BAD_DATA);
       goto leave;
     }
 
   resultlen = datalen - 8;
   result = xtrymalloc_secure (resultlen);
   if (!result)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
 
   err = gcry_cipher_open (&cipher_hd, cipher_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
   if (err)
     {
       log_error ("ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_cipher_setkey (cipher_hd, key, keylen);
   wipememory (key, sizeof key);
   if (err)
     {
       log_error ("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_cipher_decrypt (cipher_hd, result, resultlen, data, datalen);
   if (err)
     {
       log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",gpg_strerror (err));
       goto leave;
     }
 
   *r_resultlen = resultlen;
   *r_result = result;
   result = NULL;
 
  leave:
   if (result)
     {
       wipememory (result, resultlen);
       xfree (result);
     }
   gcry_cipher_close (cipher_hd);
   xfree (encr_algo_str);
   xfree (wrap_algo_str);
   xfree (ioarray[0].data);
   xfree (ioarray[1].data);
   xfree (ioarray[2].data);
   xfree (ioarray[3].data);
   return err;
 }
 
 
 /* Helper for pwri_decrypt to parse the derive info.
  * Example data for (DER,DERLEN):
  * SEQUENCE {
  *   OCTET STRING
  *     60 76 4B E9 5E DF 3C F8 B2 F9 B6 C2 7D 5A FB 90
  *     23 B6 47 DF
  *   INTEGER 10000
  *   SEQUENCE {
  *     OBJECT IDENTIFIER
  *       hmacWithSHA512 (1 2 840 113549 2 11)
  *     NULL
  *     }
  *   }
  */
 static gpg_error_t
 pwri_parse_pbkdf2 (const unsigned char *der, size_t derlen,
                    unsigned char const **r_salt, unsigned int *r_saltlen,
                    unsigned long *r_iterations,
                    enum gcry_md_algos *r_digest)
 {
   gpg_error_t err;
   size_t objlen, hdrlen;
   int class, tag, constructed, ndef;
   char *oidstr;
 
   err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
   if (!err && (objlen > derlen || tag != TAG_SEQUENCE
                || !constructed || ndef))
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     return err;
   derlen = objlen;
 
   err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
   if (!err && (objlen > derlen || tag != TAG_OCTET_STRING
                || constructed || ndef))
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     return err;
   *r_salt = der;
   *r_saltlen = objlen;
   der += objlen;
   derlen -= objlen;
 
   err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
   if (!err && (objlen > derlen || tag != TAG_INTEGER
                || constructed || ndef))
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     return err;
   *r_iterations = 0;
   for (; objlen; objlen--)
     {
       *r_iterations <<= 8;
       *r_iterations |= (*der++) & 0xff;
       derlen--;
     }
 
   err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
   if (!err && (objlen > derlen || tag != TAG_SEQUENCE
                || !constructed || ndef))
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     return err;
   derlen = objlen;
 
   err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
                           &ndef, &objlen, &hdrlen);
   if (!err && (objlen > derlen || tag != TAG_OBJECT_ID
                || constructed || ndef))
     err = gpg_error (GPG_ERR_INV_OBJ);
   if (err)
     return err;
 
   oidstr = ksba_oid_to_str (der, objlen);
   if (!oidstr)
     return gpg_error_from_syserror ();
   *r_digest = gcry_md_map_name (oidstr);
   if (*r_digest)
     ;
   else if (!strcmp (oidstr, "1.2.840.113549.2.7"))
     *r_digest = GCRY_MD_SHA1;
   else if (!strcmp (oidstr, "1.2.840.113549.2.8"))
     *r_digest = GCRY_MD_SHA224;
   else if (!strcmp (oidstr, "1.2.840.113549.2.9"))
     *r_digest = GCRY_MD_SHA256;
   else if (!strcmp (oidstr, "1.2.840.113549.2.10"))
     *r_digest = GCRY_MD_SHA384;
   else if (!strcmp (oidstr, "1.2.840.113549.2.11"))
     *r_digest = GCRY_MD_SHA512;
   else
     err = gpg_error (GPG_ERR_DIGEST_ALGO);
   ksba_free (oidstr);
 
   return err;
 }
 
 
 /* Password based decryption.
  * ENC_VAL has the form:
  *  (enc-val
  *    (pwri
  *      (derive-algo <oid>) --| both are optional
  *      (derive-parm <der>) --|
  *      (encr-algo <oid>)
  *      (encr-parm <iv>)
  *      (encr-key <key>)))  -- this is the encrypted session key
  *
  */
 static gpg_error_t
 pwri_decrypt (ctrl_t ctrl, gcry_sexp_t enc_val,
               unsigned char **r_result, unsigned int *r_resultlen,
               struct decrypt_filter_parm_s *parm)
 {
   gpg_error_t err;
   gcry_buffer_t ioarray[5] = { {0} };
   char *derive_algo_str = NULL;
   char *encr_algo_str = NULL;
   const unsigned char *dparm;  /* Alias for ioarray[1].  */
   unsigned int dparmlen;
   const unsigned char *eparm;  /* Alias for ioarray[3].  */
   unsigned int eparmlen;
   const unsigned char *ekey;   /* Alias for ioarray[4].  */
   unsigned int ekeylen;
   unsigned char kek[32];
   unsigned int keklen;
   enum gcry_cipher_algos encr_algo;
   enum gcry_cipher_modes encr_mode;
   gcry_cipher_hd_t encr_hd = NULL;
   unsigned char *result = NULL;
   unsigned int resultlen;
   unsigned int blklen;
   const unsigned char *salt;   /* Points int dparm. */
   unsigned int saltlen;
   unsigned long iterations;
   enum gcry_md_algos digest_algo;
   char *passphrase = NULL;
 
 
   *r_resultlen = 0;
   *r_result = NULL;
 
   err = gcry_sexp_extract_param (enc_val, "enc-val!pwri",
                                  "&'derive-algo'?'derive-parm'?"
                                  "'encr-algo''encr-parm''encr-key'",
                                  ioarray+0, ioarray+1,
                                  ioarray+2, ioarray+3, ioarray+4, NULL);
   if (err)
     {
       /* If this is not pwri element, it is likly a kekri element
        * which we do not yet support.  Change the error back to the
        * original as returned by ksba_cms_get_issuer.  */
       if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
         err = gpg_error (GPG_ERR_UNSUPPORTED_CMS_OBJ);
       else
         log_error ("extracting PWRI parameter failed: %s\n",
                    gpg_strerror (err));
       goto leave;
     }
 
   if (ioarray[0].data)
     {
       derive_algo_str = string_from_gcry_buffer (ioarray+0);
       if (!derive_algo_str)
         {
           err = gpg_error_from_syserror ();
           goto leave;
         }
     }
   dparm    = ioarray[1].data;
   dparmlen = ioarray[1].len;
   encr_algo_str = string_from_gcry_buffer (ioarray+2);
   if (!encr_algo_str)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   eparm    = ioarray[3].data;
   eparmlen = ioarray[3].len;
   ekey     = ioarray[4].data;
   ekeylen  = ioarray[4].len;
 
   /* Check parameters.  */
   if (DBG_CRYPTO)
     {
       if (derive_algo_str)
         {
           log_debug ("derive algo: %s\n", derive_algo_str);
           log_printhex (dparm, dparmlen, "derive parm:");
         }
       log_debug ("encr algo .: %s\n", encr_algo_str);
       log_printhex (eparm, eparmlen, "encr parm .:");
       log_printhex (ekey, ekeylen,   "encr key  .:");
     }
 
   if (!derive_algo_str)
     {
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       log_info ("PWRI with no key derivation detected\n");
       goto leave;
     }
   if (strcmp (derive_algo_str, "1.2.840.113549.1.5.12"))
     {
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       log_info ("PWRI does not use PBKDF2 (but %s)\n", derive_algo_str);
       goto leave;
     }
 
   digest_algo = 0;  /*(silence cc warning)*/
   err = pwri_parse_pbkdf2 (dparm, dparmlen,
                            &salt, &saltlen, &iterations, &digest_algo);
   if (err)
     {
       log_error ("parsing PWRI parameter failed: %s\n", gpg_strerror (err));
       goto leave;
     }
 
   parm->is_de_vs = (parm->is_de_vs
                     && gnupg_digest_is_compliant (CO_DE_VS, digest_algo));
 
 
   encr_algo = gcry_cipher_map_name (encr_algo_str);
   encr_mode = gcry_cipher_mode_from_oid (encr_algo_str);
   if (!encr_algo || !encr_mode)
     {
       log_error ("PWRI uses unknown algorithm %s\n", encr_algo_str);
       err = gpg_error (GPG_ERR_CIPHER_ALGO);
       goto leave;
     }
 
   parm->is_de_vs =
     (parm->is_de_vs
      && gnupg_cipher_is_compliant (CO_DE_VS, encr_algo, encr_mode));
 
   keklen = gcry_cipher_get_algo_keylen (encr_algo);
   blklen = gcry_cipher_get_algo_blklen (encr_algo);
   if (!keklen || keklen > sizeof kek || blklen != 16 )
     {
       log_error ("PWRI algorithm %s cannot be used\n", encr_algo_str);
       err = gpg_error (GPG_ERR_INV_KEYLEN);
       goto leave;
     }
   if ((ekeylen % blklen) || (ekeylen / blklen < 2))
     {
       /* Note that we need at least two full blocks.  */
       log_error ("PWRI uses a wrong length of encrypted key\n");
       err = gpg_error (GPG_ERR_INV_KEYLEN);
       goto leave;
     }
 
   err = gpgsm_agent_ask_passphrase
     (ctrl,
      i18n_utf8 (N_("Please enter the passphrase for decryption.")),
      0, &passphrase);
   if (err)
     goto leave;
 
   err = gcry_kdf_derive (passphrase, strlen (passphrase),
                          GCRY_KDF_PBKDF2, digest_algo,
                          salt, saltlen, iterations,
                          keklen, kek);
   if (passphrase)
     {
       wipememory (passphrase, strlen (passphrase));
       xfree (passphrase);
       passphrase = NULL;
     }
   if (err)
     {
       log_error ("deriving key from passphrase failed: %s\n",
                  gpg_strerror (err));
       goto leave;
     }
 
   if (DBG_CRYPTO)
     log_printhex (kek, keklen, "KEK .......:");
 
   /* Unwrap the key.  */
   resultlen = ekeylen;
   result = xtrymalloc_secure (resultlen);
   if (!result)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
 
   err = gcry_cipher_open (&encr_hd, encr_algo, encr_mode, 0);
   if (err)
     {
       log_error ("PWRI failed to open cipher: %s\n", gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_cipher_setkey (encr_hd, kek, keklen);
   wipememory (kek, sizeof kek);
   if (!err)
     err = gcry_cipher_setiv (encr_hd, ekey + ekeylen - 2 * blklen, blklen);
   if (!err)
     err = gcry_cipher_decrypt (encr_hd, result + ekeylen - blklen, blklen,
                                ekey + ekeylen - blklen, blklen);
   if (!err)
     err = gcry_cipher_setiv (encr_hd, result + ekeylen - blklen, blklen);
   if (!err)
     err = gcry_cipher_decrypt (encr_hd, result, ekeylen - blklen,
                                ekey, ekeylen - blklen);
   /* (We assume that that eparm is the octet string with the IV)  */
   if (!err)
     err = gcry_cipher_setiv (encr_hd, eparm, eparmlen);
   if (!err)
     err = gcry_cipher_decrypt (encr_hd, result, resultlen, NULL, 0);
 
   if (err)
     {
       log_error ("KEK decryption failed for PWRI: %s\n", gpg_strerror (err));
       goto leave;
     }
 
   if (DBG_CRYPTO)
     log_printhex (result, resultlen, "Frame .....:");
 
   if (result[0] < 8                /* At least 64 bits */
       || (result[0] % 8)           /* Multiple of 64 bits */
       || result[0] > resultlen - 4 /* Not more than the size of the input */
       || ( (result[1] ^ result[4]) /* Matching check bytes.  */
            & (result[2] ^ result[5])
            & (result[3] ^ result[6]) ) != 0xff)
     {
       err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
       goto leave;
     }
 
   *r_resultlen = result[0];
   *r_result = memmove (result, result + 4, result[0]);
   result = NULL;
 
  leave:
   if (result)
     {
       wipememory (result, resultlen);
       xfree (result);
     }
   if (passphrase)
     {
       wipememory (passphrase, strlen (passphrase));
       xfree (passphrase);
     }
   gcry_cipher_close (encr_hd);
   xfree (derive_algo_str);
   xfree (encr_algo_str);
   xfree (ioarray[0].data);
   xfree (ioarray[1].data);
   xfree (ioarray[2].data);
   xfree (ioarray[3].data);
   xfree (ioarray[4].data);
   return err;
 }
 
 
 /* Decrypt the session key and fill in the parm structure.  The
    algo and the IV is expected to be already in PARM. */
 static int
 prepare_decryption (ctrl_t ctrl, const char *hexkeygrip,
                     int pk_algo, unsigned int nbits, const char *desc,
                     ksba_const_sexp_t enc_val,
                     struct decrypt_filter_parm_s *parm)
 {
   char *seskey = NULL;
   size_t n, seskeylen;
   int pwri = !hexkeygrip && !pk_algo;
   int rc;
 
   if (DBG_CRYPTO)
     log_printcanon ("decrypting:", enc_val, 0);
 
   if (!pwri)
     {
       rc = gpgsm_agent_pkdecrypt (ctrl, hexkeygrip, desc, enc_val,
                                   &seskey, &seskeylen);
       if (rc)
         {
           log_error ("error decrypting session key: %s\n", gpg_strerror (rc));
           goto leave;
         }
 
       if (DBG_CRYPTO)
         log_printhex (seskey, seskeylen, "DEK frame:");
     }
 
   n=0;
   if (pwri) /* Password based encryption.  */
     {
       gcry_sexp_t s_enc_val;
       unsigned char *decrypted;
       unsigned int decryptedlen;
 
       rc = gcry_sexp_sscan (&s_enc_val, NULL, enc_val,
                             gcry_sexp_canon_len (enc_val, 0, NULL, NULL));
       if (rc)
         goto leave;
 
       rc = pwri_decrypt (ctrl, s_enc_val, &decrypted, &decryptedlen, parm);
       gcry_sexp_release (s_enc_val);
       if (rc)
         goto leave;
       xfree (seskey);
       seskey = decrypted;
       seskeylen = decryptedlen;
     }
   else if (pk_algo == GCRY_PK_ECC)
     {
       gcry_sexp_t s_enc_val;
       unsigned char *decrypted;
       unsigned int decryptedlen;
 
       rc = gcry_sexp_sscan (&s_enc_val, NULL, enc_val,
                             gcry_sexp_canon_len (enc_val, 0, NULL, NULL));
       if (rc)
         goto leave;
 
       rc = ecdh_decrypt (seskey, seskeylen, nbits, s_enc_val,
                          &decrypted, &decryptedlen);
       gcry_sexp_release (s_enc_val);
       if (rc)
         goto leave;
       xfree (seskey);
       seskey = decrypted;
       seskeylen = decryptedlen;
 
     }
   else if (seskeylen == 32 || seskeylen == 24 || seskeylen == 16)
     {
       /* Smells like an AES-128, 3-DES, or AES-256 key.  This might
        * happen because a SC has already done the unpacking.  A better
        * solution would be to test for this only after we triggered
        * the GPG_ERR_INV_SESSION_KEY. */
     }
   else
     {
       if (n + 7 > seskeylen )
         {
           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
           goto leave;
         }
 
       /* FIXME: Actually the leading zero is required but due to the way
          we encode the output in libgcrypt as an MPI we are not able to
          encode that leading zero.  However, when using a Smartcard we are
          doing it the right way and therefore we have to skip the zero.  This
          should be fixed in gpg-agent of course. */
       if (!seskey[n])
         n++;
 
       if (seskey[n] != 2 )  /* Wrong block type version. */
         {
           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
           goto leave;
         }
 
       for (n++; n < seskeylen && seskey[n]; n++) /* Skip the random bytes. */
         ;
       n++; /* and the zero byte */
       if (n >= seskeylen )
         {
           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
           goto leave;
         }
     }
 
   if (DBG_CRYPTO)
     {
       log_printhex (seskey+n, seskeylen-n, "CEK .......:");
       log_printhex (parm->iv, parm->ivlen, "IV ........:");
     }
 
   if (opt.verbose)
     log_info (_("%s.%s encrypted data\n"),
               gcry_cipher_algo_name (parm->algo),
               cipher_mode_to_string (parm->mode));
 
   rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0);
   if (rc)
     {
       log_error ("error creating decryptor: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
   if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
     {
       log_info (_("WARNING: message was encrypted with "
                   "a weak key in the symmetric cipher.\n"));
       rc = 0;
     }
   if (rc)
     {
       log_error("key setup failed: %s\n", gpg_strerror(rc) );
       goto leave;
     }
 
   rc = gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
   if (rc)
     {
       log_error("IV setup failed: %s\n", gpg_strerror(rc) );
       goto leave;
     }
 
   if (parm->mode == GCRY_CIPHER_MODE_GCM)
     {
       /* GCM mode really sucks in CMS.  We need to know the AAD before
        * we start decrypting but CMS puts the AAD after the content.
        * Thus temporary files are required.  Let's hope that no real
        * messages with actual AAD are ever used.  OCB Rules! */
     }
 
  leave:
   xfree (seskey);
   return rc;
 }
 
 
 /* This function is called by the KSBA writer just before the actual
    write is done.  The function must take INLEN bytes from INBUF,
    decrypt it and store it inoutbuf which has a maximum size of
    maxoutlen.  The valid bytes in outbuf should be return in outlen.
    Due to different buffer sizes or different length of input and
    output, it may happen that fewer bytes are processed or fewer bytes
    are written. */
 static gpg_error_t
 decrypt_filter (void *arg,
                 const void *inbuf, size_t inlen, size_t *inused,
                 void *outbuf, size_t maxoutlen, size_t *outlen)
 {
   struct decrypt_filter_parm_s *parm = arg;
   int blklen = parm->blklen;
   size_t orig_inlen = inlen;
 
   /* fixme: Should we issue an error when we have not seen one full block? */
   if (!inlen)
     return gpg_error (GPG_ERR_BUG);
 
   if (maxoutlen < 2*parm->blklen)
     return gpg_error (GPG_ERR_BUG);
   /* Make some space because we will later need an extra block at the end.  */
   maxoutlen -= blklen;
 
   if (parm->helpblocklen)
     {
       int i, j;
 
       for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
         parm->helpblock[i] = ((const char*)inbuf)[j];
       inlen -= j;
       if (blklen > maxoutlen)
         return gpg_error (GPG_ERR_BUG);
       if (i < blklen)
         {
           parm->helpblocklen = i;
           *outlen = 0;
         }
       else
         {
           parm->helpblocklen = 0;
           if (parm->any_data)
             {
               memcpy (outbuf, parm->lastblock, blklen);
               *outlen =blklen;
             }
           else
             *outlen = 0;
           gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
                                parm->helpblock, blklen);
           parm->any_data = 1;
         }
       *inused = orig_inlen - inlen;
       return 0;
     }
 
 
   if (inlen > maxoutlen)
     inlen = maxoutlen;
   if (inlen % blklen)
     { /* store the remainder away */
       parm->helpblocklen = inlen%blklen;
       inlen = inlen/blklen*blklen;
       memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
     }
 
   *inused = inlen + parm->helpblocklen;
   if (inlen)
     {
       assert (inlen >= blklen);
       if (parm->any_data)
         {
           gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
                                inbuf, inlen);
           memcpy (outbuf, parm->lastblock, blklen);
           memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
           *outlen = inlen;
         }
       else
         {
           gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
           memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
           *outlen = inlen - blklen;
           parm->any_data = 1;
         }
     }
   else
     *outlen = 0;
   return 0;
 }
 
 
 /* This is the GCM version of decrypt_filter.  */
 static gpg_error_t
 decrypt_gcm_filter (void *arg,
                     const void *inbuf, size_t inlen, size_t *inused,
                     void *outbuf, size_t maxoutlen, size_t *outlen)
 {
   struct decrypt_filter_parm_s *parm = arg;
 
   if (!inlen)
     return gpg_error (GPG_ERR_BUG);
 
   if (maxoutlen < parm->blklen)
     return gpg_error (GPG_ERR_BUG);
 
   if (inlen > maxoutlen)
     inlen = maxoutlen;
 
   *inused = inlen;
   if (inlen)
     {
       gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
       *outlen = inlen;
       parm->any_data = 1;
     }
   else
     *outlen = 0;
   return 0;
 }
 
 
 
 /* Perform a decrypt operation.  */
 int
 gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
 {
   int rc;
   gnupg_ksba_io_t b64reader = NULL;
   gnupg_ksba_io_t b64writer = NULL;
   ksba_reader_t reader;
   ksba_writer_t writer;
   ksba_cms_t cms = NULL;
   ksba_stop_reason_t stopreason;
   KEYDB_HANDLE kh;
   int recp;
   estream_t in_fp = NULL;
   struct decrypt_filter_parm_s dfparm;
 
   memset (&dfparm, 0, sizeof dfparm);
 
   audit_set_type (ctrl->audit, AUDIT_TYPE_DECRYPT);
 
   kh = keydb_new ();
   if (!kh)
     {
       log_error (_("failed to allocate keyDB handle\n"));
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
   in_fp = es_fdopen_nc (in_fd, "rb");
   if (!in_fp)
     {
       rc = gpg_error_from_syserror ();
       log_error ("fdopen() failed: %s\n", strerror (errno));
       goto leave;
     }
 
   rc = gnupg_ksba_create_reader
     (&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
                   | (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
                   | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)),
      in_fp, &reader);
   if (rc)
     {
       log_error ("can't create reader: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   rc = gnupg_ksba_create_writer
     (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
                   | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
      ctrl->pem_name, out_fp, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
+  if (ctrl->input_size_hint)
+    gnupg_ksba_set_total (b64writer, ctrl->input_size_hint);
 
   rc = ksba_cms_new (&cms);
   if (rc)
     goto leave;
 
   rc = ksba_cms_set_reader_writer (cms, reader, writer);
   if (rc)
     {
       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
                  gpg_strerror (rc));
       goto leave;
     }
 
   audit_log (ctrl->audit, AUDIT_SETUP_READY);
 
   /* Parser loop. */
   do
     {
       rc = ksba_cms_parse (cms, &stopreason);
       if (rc)
         {
           log_debug ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
 
       if (stopreason == KSBA_SR_BEGIN_DATA
           || stopreason == KSBA_SR_DETACHED_DATA)
         {
           int algo, mode;
           const char *algoid;
           int any_key = 0;
 
           audit_log (ctrl->audit, AUDIT_GOT_DATA);
 
           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
           algo = gcry_cipher_map_name (algoid);
           mode = gcry_cipher_mode_from_oid (algoid);
           if (!algo || !mode)
             {
               rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
               log_error ("unsupported algorithm '%s'\n", algoid? algoid:"?");
               if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
                 log_info (_("(this is the RC2 algorithm)\n"));
               else if (!algoid)
                 log_info (_("(this does not seem to be an encrypted"
                             " message)\n"));
               {
                 char numbuf[50];
                 sprintf (numbuf, "%d", rc);
                 gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
                                numbuf, algoid?algoid:"?", NULL);
                 audit_log_s (ctrl->audit, AUDIT_BAD_DATA_CIPHER_ALGO, algoid);
               }
 
               /* If it seems that this is not an encrypted message we
                  return a more sensible error code. */
               if (!algoid)
                 rc = gpg_error (GPG_ERR_NO_DATA);
 
               goto leave;
             }
 
           /* Check compliance.  */
           if (! gnupg_cipher_is_allowed (opt.compliance, 0, algo, mode))
             {
               log_error (_("cipher algorithm '%s'"
                            " may not be used in %s mode\n"),
                          gcry_cipher_algo_name (algo),
                          gnupg_compliance_option_string (opt.compliance));
               rc = gpg_error (GPG_ERR_CIPHER_ALGO);
               goto leave;
             }
 
           /* For CMS, CO_DE_VS demands CBC mode.  */
           dfparm.is_de_vs = gnupg_cipher_is_compliant (CO_DE_VS, algo, mode);
 
           audit_log_i (ctrl->audit, AUDIT_DATA_CIPHER_ALGO, algo);
           dfparm.algo = algo;
           dfparm.mode = mode;
           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
           if (dfparm.blklen > sizeof (dfparm.helpblock))
             {
               rc = gpg_error (GPG_ERR_BUG);
               goto leave;
             }
 
           rc = ksba_cms_get_content_enc_iv (cms,
                                             dfparm.iv,
                                             sizeof (dfparm.iv),
                                             &dfparm.ivlen);
           if (rc)
             {
               log_error ("error getting IV: %s\n", gpg_strerror (rc));
               goto leave;
             }
 
           for (recp=0; !any_key; recp++)
             {
               char *issuer;
               ksba_sexp_t serial;
               ksba_sexp_t enc_val;
               char *hexkeygrip = NULL;
               char *pkalgostr = NULL;
               char *pkfpr = NULL;
               char *desc = NULL;
               char kidbuf[16+1];
               int tmp_rc;
               ksba_cert_t cert = NULL;
               unsigned int nbits;
               int pk_algo = 0;
               int maybe_pwri = 0;
 
               *kidbuf = 0;
 
               tmp_rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
               if (tmp_rc == -1 && recp)
                 break; /* no more recipients */
               audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp);
               if (gpg_err_code (tmp_rc) == GPG_ERR_UNSUPPORTED_CMS_OBJ)
                 {
                   maybe_pwri = 1;
                 }
               else if (tmp_rc)
                 {
                   log_error ("recp %d - error getting info: %s\n",
                              recp, gpg_strerror (tmp_rc));
                 }
               else
                 {
                   if (opt.verbose)
                     {
                       log_debug ("recp %d - issuer: '%s'\n",
                                  recp, issuer? issuer:"[NONE]");
                       log_debug ("recp %d - serial: ", recp);
                       gpgsm_dump_serial (serial);
                       log_printf ("\n");
                     }
 
                   if (ctrl->audit)
                     {
                       char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
                       audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr);
                       xfree (tmpstr);
                     }
 
                   keydb_search_reset (kh);
                   rc = keydb_search_issuer_sn (ctrl, kh, issuer, serial);
                   if (rc)
                     {
                       log_error ("failed to find the certificate: %s\n",
                                  gpg_strerror(rc));
                       goto oops;
                     }
 
                   rc = keydb_get_cert (kh, &cert);
                   if (rc)
                     {
                       log_error ("failed to get cert: %s\n", gpg_strerror (rc));
                       goto oops;
                     }
 
                   /* Print the ENC_TO status line.  Note that we can
                      do so only if we have the certificate.  This is
                      in contrast to gpg where the keyID is commonly
                      included in the encrypted messages. It is too
                      cumbersome to retrieve the used algorithm, thus
                      we don't print it for now.  We also record the
                      keyid for later use.  */
                   {
                     unsigned long kid[2];
 
                     kid[0] = gpgsm_get_short_fingerprint (cert, kid+1);
                     snprintf (kidbuf, sizeof kidbuf, "%08lX%08lX",
                               kid[1], kid[0]);
                     gpgsm_status2 (ctrl, STATUS_ENC_TO,
                                    kidbuf, "0", "0", NULL);
                   }
 
                   /* Put the certificate into the audit log.  */
                   audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert, 0);
 
                   /* Just in case there is a problem with the own
                      certificate we print this message - should never
                      happen of course */
                   rc = gpgsm_cert_use_decrypt_p (cert);
                   if (rc)
                     {
                       char numbuf[50];
                       sprintf (numbuf, "%d", rc);
                       gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
                                      numbuf, NULL);
                       rc = 0;
                     }
 
                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
                   desc = gpgsm_format_keydesc (cert);
 
                   pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
                   pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
                   pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
                   if (!opt.quiet)
                     log_info (_("encrypted to %s key %s\n"), pkalgostr, pkfpr);
 
                   /* Check compliance.  */
                   if (!gnupg_pk_is_allowed (opt.compliance,
                                             PK_USE_DECRYPTION,
                                             pk_algo, 0, NULL, nbits, NULL))
                     {
                       char  kidstr[10+1];
 
                       snprintf (kidstr, sizeof kidstr, "0x%08lX",
                                 gpgsm_get_short_fingerprint (cert, NULL));
                       log_info (_("key %s is not suitable for decryption"
                                   " in %s mode\n"),
                                 kidstr,
                                 gnupg_compliance_option_string(opt.compliance));
                       rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
                       goto oops;
                     }
 
                   /* Check that all certs are compliant with CO_DE_VS.  */
                   dfparm.is_de_vs =
                     (dfparm.is_de_vs
                      && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0,
                                                NULL, nbits, NULL));
 
                 oops:
                   if (rc)
                     {
                       /* We cannot check compliance of certs that we
                        * don't have.  */
                       dfparm.is_de_vs = 0;
                     }
                   xfree (issuer);
                   xfree (serial);
                   ksba_cert_release (cert);
                 }
 
               if ((!hexkeygrip || !pk_algo) && !maybe_pwri)
                 ;
               else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
                 {
                   log_error ("recp %d - error getting encrypted session key\n",
                              recp);
                   if (maybe_pwri)
                     log_info ("(possibly unsupported KEK info)\n");
                 }
               else
                 {
                   if (maybe_pwri && opt.verbose)
                     log_info ("recp %d - KEKRI or PWRI\n", recp);
 
                   rc = prepare_decryption (ctrl, hexkeygrip, pk_algo, nbits,
                                            desc, enc_val, &dfparm);
                   xfree (enc_val);
                   if (rc)
                     {
                       log_info ("decrypting session key failed: %s\n",
                                 gpg_strerror (rc));
                       if (gpg_err_code (rc) == GPG_ERR_NO_SECKEY && *kidbuf)
                         gpgsm_status2 (ctrl, STATUS_NO_SECKEY, kidbuf, NULL);
                     }
                   else
                     { /* setup the bulk decrypter */
                       any_key = 1;
                       ksba_writer_set_filter
                         (writer,
                          dfparm.mode == GCRY_CIPHER_MODE_GCM?
                          decrypt_gcm_filter : decrypt_filter,
                          &dfparm);
 
                       if (dfparm.is_de_vs
                           && gnupg_gcrypt_is_compliant (CO_DE_VS))
                         gpgsm_status (ctrl, STATUS_DECRYPTION_COMPLIANCE_MODE,
                                       gnupg_status_compliance_flag (CO_DE_VS));
                       else if (opt.require_compliance
                                && opt.compliance == CO_DE_VS)
                         {
                           log_error (_("operation forced to fail due to"
                                        " unfulfilled compliance rules\n"));
                           gpgsm_errors_seen = 1;
                         }
                     }
                   audit_log_ok (ctrl->audit, AUDIT_RECP_RESULT, rc);
                 }
               xfree (pkalgostr);
               xfree (pkfpr);
               xfree (hexkeygrip);
               xfree (desc);
             }
 
           /* If we write an audit log add the unused recipients to the
              log as well.  */
           if (ctrl->audit && any_key)
             {
               for (;; recp++)
                 {
                   char *issuer;
                   ksba_sexp_t serial;
                   int tmp_rc;
 
                   tmp_rc = ksba_cms_get_issuer_serial (cms, recp,
                                                        &issuer, &serial);
                   if (tmp_rc == -1)
                     break; /* no more recipients */
                   audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp);
                   if (tmp_rc)
                     log_error ("recp %d - error getting info: %s\n",
                                recp, gpg_strerror (rc));
                   else
                     {
                       char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
                       audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr);
                       xfree (tmpstr);
                       xfree (issuer);
                       xfree (serial);
                     }
                 }
             }
 
           if (!any_key)
             {
               if (!rc)
                 rc = gpg_error (GPG_ERR_NO_SECKEY);
               goto leave;
             }
         }
       else if (stopreason == KSBA_SR_END_DATA)
         {
           ksba_writer_set_filter (writer, NULL, NULL);
           if (dfparm.mode == GCRY_CIPHER_MODE_GCM)
             {
               /* Nothing yet to do.  We wait for the ready event.  */
             }
           else if (dfparm.any_data )
             { /* write the last block with padding removed */
               int i, npadding = dfparm.lastblock[dfparm.blklen-1];
               if (!npadding || npadding > dfparm.blklen)
                 {
                   log_error ("invalid padding with value %d\n", npadding);
                   rc = gpg_error (GPG_ERR_INV_DATA);
                   goto leave;
                 }
               rc = ksba_writer_write (writer,
                                       dfparm.lastblock,
                                       dfparm.blklen - npadding);
               if (rc)
                 goto leave;
 
               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
                 {
                   if (dfparm.lastblock[i] != npadding)
                     {
                       log_error ("inconsistent padding\n");
                       rc = gpg_error (GPG_ERR_INV_DATA);
                       goto leave;
                     }
                 }
             }
         }
       else if (stopreason == KSBA_SR_READY)
         {
           if (dfparm.mode == GCRY_CIPHER_MODE_GCM)
             {
               char *authtag;
               size_t authtaglen;
 
               rc = ksba_cms_get_message_digest (cms, 0, &authtag, &authtaglen);
               if (rc)
                 {
                   log_error ("error getting authtag: %s\n", gpg_strerror (rc));
                   goto leave;
                 }
               if (DBG_CRYPTO)
                 log_printhex (authtag, authtaglen, "Authtag ...:");
               rc = gcry_cipher_checktag (dfparm.hd, authtag, authtaglen);
               xfree (authtag);
               if (rc)
                 log_error ("data is not authentic: %s\n", gpg_strerror (rc));
               goto leave;
             }
         }
     }
   while (stopreason != KSBA_SR_READY);
 
   rc = gnupg_ksba_finish_writer (b64writer);
   if (rc)
     {
       log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
 
 
  leave:
   audit_log_ok (ctrl->audit, AUDIT_DECRYPTION_RESULT, rc);
   if (rc)
     {
       gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
       log_error ("message decryption failed: %s <%s>\n",
                  gpg_strerror (rc), gpg_strsource (rc));
     }
   ksba_cms_release (cms);
   gnupg_ksba_destroy_reader (b64reader);
   gnupg_ksba_destroy_writer (b64writer);
   keydb_release (kh);
   es_fclose (in_fp);
   if (dfparm.hd)
     gcry_cipher_close (dfparm.hd);
   return rc;
 }
diff --git a/sm/encrypt.c b/sm/encrypt.c
index ed5cd2f90..fc104db1d 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -1,886 +1,888 @@
 /* encrypt.c - Encrypt a message
  * Copyright (C) 2001, 2003, 2004, 2007, 2008,
  *               2010 Free Software Foundation, Inc.
  * Copyright (C) 2001-2019 Werner Koch
  * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
 #include "../common/i18n.h"
 #include "../common/compliance.h"
 
 
 struct dek_s {
   const char *algoid;
   int algo;
   gcry_cipher_hd_t chd;
   char key[32];
   int keylen;
   char iv[32];
   int ivlen;
 };
 typedef struct dek_s *DEK;
 
 
 /* Callback parameters for the encryption.  */
 struct encrypt_cb_parm_s
 {
   estream_t fp;
   DEK dek;
   int eof_seen;
   int ready;
   int readerror;
   int bufsize;
   unsigned char *buffer;
   int buflen;
 };
 
 
 
 
 
 /* Initialize the data encryption key (session key). */
 static int
 init_dek (DEK dek)
 {
   int rc=0, mode, i;
 
   dek->algo = gcry_cipher_map_name (dek->algoid);
   mode = gcry_cipher_mode_from_oid (dek->algoid);
   if (!dek->algo || !mode)
     {
       log_error ("unsupported algorithm '%s'\n", dek->algoid);
       return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     }
 
   /* Extra check for algorithms we consider to be too weak for
      encryption, although we support them for decryption.  Note that
      there is another check below discriminating on the key length. */
   switch (dek->algo)
     {
     case GCRY_CIPHER_DES:
     case GCRY_CIPHER_RFC2268_40:
       log_error ("cipher algorithm '%s' not allowed: too weak\n",
                  gnupg_cipher_algo_name (dek->algo));
       return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     default:
       break;
     }
 
   dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
   if (!dek->keylen || dek->keylen > sizeof (dek->key))
     return gpg_error (GPG_ERR_BUG);
 
   dek->ivlen = gcry_cipher_get_algo_blklen (dek->algo);
   if (!dek->ivlen || dek->ivlen > sizeof (dek->iv))
     return gpg_error (GPG_ERR_BUG);
 
   /* Make sure we don't use weak keys. */
   if (dek->keylen < 100/8)
     {
       log_error ("key length of '%s' too small\n", dek->algoid);
       return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     }
 
   rc = gcry_cipher_open (&dek->chd, dek->algo, mode, GCRY_CIPHER_SECURE);
   if (rc)
     {
       log_error ("failed to create cipher context: %s\n", gpg_strerror (rc));
       return rc;
     }
 
   for (i=0; i < 8; i++)
     {
       gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM );
       rc = gcry_cipher_setkey (dek->chd, dek->key, dek->keylen);
       if (gpg_err_code (rc) != GPG_ERR_WEAK_KEY)
         break;
       log_info(_("weak key created - retrying\n") );
     }
   if (rc)
     {
       log_error ("failed to set the key: %s\n", gpg_strerror (rc));
       gcry_cipher_close (dek->chd);
       dek->chd = NULL;
       return rc;
     }
 
   gcry_create_nonce (dek->iv, dek->ivlen);
   rc = gcry_cipher_setiv (dek->chd, dek->iv, dek->ivlen);
   if (rc)
     {
       log_error ("failed to set the IV: %s\n", gpg_strerror (rc));
       gcry_cipher_close (dek->chd);
       dek->chd = NULL;
       return rc;
     }
 
   return 0;
 }
 
 /* Encrypt an RSA session key.  */
 static int
 encode_session_key (DEK dek, gcry_sexp_t * r_data)
 {
   gcry_sexp_t data;
   char *p;
   int rc;
 
   p = xtrymalloc (64 + 2 * dek->keylen);
   if (!p)
     return gpg_error_from_syserror ();
   strcpy (p, "(data\n (flags pkcs1)\n (value #");
   bin2hex (dek->key, dek->keylen, p + strlen (p));
   strcat (p, "#))\n");
   rc = gcry_sexp_sscan (&data, NULL, p, strlen (p));
   xfree (p);
   *r_data = data;
   return rc;
 }
 
 
 /* Encrypt DEK using ECDH.  S_PKEY is the public key.  On success the
  * result is stored at R_ENCVAL.  Example of a public key:
  *
  *   (public-key (ecc (curve "1.3.132.0.34") (q #04B0[...]B8#)))
  *
  */
 static gpg_error_t
 ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
 {
   gpg_error_t err;
   gcry_sexp_t l1;
   char *curvebuf = NULL;
   const char *curve;
   unsigned int curvebits;
   const char *encr_algo_str;
   const char *wrap_algo_str;
   int hash_algo, cipher_algo;
   unsigned int keylen, hashlen;
   unsigned char key[32];
   gcry_sexp_t s_data = NULL;
   gcry_sexp_t s_encr = NULL;
   gcry_buffer_t ioarray[2] = { {0}, {0} };
   unsigned char *secret;  /* Alias for ioarray[0].  */
   unsigned int secretlen;
   unsigned char *pubkey;  /* Alias for ioarray[1].  */
   unsigned int pubkeylen;
   gcry_cipher_hd_t cipher_hd = NULL;
   unsigned char *result = NULL;
   unsigned int resultlen;
 
   *r_encval = NULL;
 
   /* Figure out the encryption and wrap algo OIDs.  */
   /* Get the curve name if any,  */
   l1 = gcry_sexp_find_token (s_pkey, "curve", 0);
   if (l1)
     {
       curvebuf = gcry_sexp_nth_string (l1, 1);
       gcry_sexp_release (l1);
     }
   if (!curvebuf)
     {
       err = gpg_error (GPG_ERR_INV_CURVE);
       log_error ("%s: invalid public key: no curve\n", __func__);
       goto leave;
     }
 
   /* We need to use our OpenPGP mapping to turn a curve name into its
    * canonical numerical OID.  We also use this to get the size of the
    * curve which we need to figure out a suitable hash algo.  We
    * should have a Libgcrypt function to do this; see bug report #4926.  */
   curve = openpgp_curve_to_oid (curvebuf, &curvebits, NULL);
   if (!curve)
     {
       err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
       log_error ("%s: invalid public key: %s\n", __func__, gpg_strerror (err));
       goto leave;
     }
   xfree (curvebuf);
   curvebuf = NULL;
 
   /* Our mapping matches the recommended algorithms from RFC-5753 but
    * not supporing the short curves which would require 3DES.  */
   if (curvebits < 255)
     {
       err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
       log_error ("%s: curve '%s' is not supported\n", __func__, curve);
       goto leave;
     }
   else if (curvebits <= 256)
     {
       /* dhSinglePass-stdDH-sha256kdf-scheme */
       encr_algo_str = "1.3.132.1.11.1";
       wrap_algo_str = "2.16.840.1.101.3.4.1.5";
       hash_algo     = GCRY_MD_SHA256;
       hashlen       = 32;
       cipher_algo   = GCRY_CIPHER_AES128;
       keylen        = 16;
     }
   else if (curvebits <= 384)
     {
       /* dhSinglePass-stdDH-sha384kdf-scheme */
       encr_algo_str = "1.3.132.1.11.2";
       wrap_algo_str = "2.16.840.1.101.3.4.1.25";
       hash_algo     = GCRY_MD_SHA384;
       hashlen       = 48;
       cipher_algo   = GCRY_CIPHER_AES256;
       keylen        = 24;
     }
   else
     {
       /* dhSinglePass-stdDH-sha512kdf-scheme*/
       encr_algo_str = "1.3.132.1.11.3";
       wrap_algo_str = "2.16.840.1.101.3.4.1.45";
       hash_algo     = GCRY_MD_SHA512;
       hashlen       = 64;
       cipher_algo   = GCRY_CIPHER_AES256;
       keylen        = 32;
     }
 
 
   /* Create a secret and an ephemeral key.  */
   {
     char *k;
     k = gcry_random_bytes_secure ((curvebits+7)/8, GCRY_STRONG_RANDOM);
     if (DBG_CRYPTO)
       log_printhex (k, (curvebits+7)/8, "ephm. k .:");
     err = gcry_sexp_build (&s_data, NULL, "%b", (int)(curvebits+7)/8, k);
     xfree (k);
   }
   if (err)
     {
       log_error ("%s: error building ephemeral secret: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_pk_encrypt (&s_encr, s_data, s_pkey);
   if (err)
     {
       log_error ("%s: error encrypting ephemeral secret: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
   err = gcry_sexp_extract_param (s_encr, NULL, "&se",
                                  &ioarray+0, ioarray+1, NULL);
   if (err)
     {
       log_error ("%s: error extracting ephemeral key and secret: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
   secret    = ioarray[0].data;
   secretlen = ioarray[0].len;
   pubkey    = ioarray[1].data;
   pubkeylen = ioarray[1].len;
 
   if (DBG_CRYPTO)
     {
       log_printhex (pubkey, pubkeylen, "pubkey ..:");
       log_printhex (secret, secretlen, "secret ..:");
     }
 
   /* Extract X coordinate from SECRET.  */
   if (secretlen < 5)  /* 5 because N could be reduced to (n-1)/2.  */
     err = gpg_error (GPG_ERR_BAD_DATA);
   else if (*secret == 0x04)
     {
       secretlen--;
       memmove (secret, secret+1, secretlen);
       if ((secretlen & 1))
         {
           err = gpg_error (GPG_ERR_BAD_DATA);
           goto leave;
         }
       secretlen /= 2;
     }
   else if (*secret == 0x40 || *secret == 0x41)
     {
       secretlen--;
       memmove (secret, secret+1, secretlen);
     }
   else
     err = gpg_error (GPG_ERR_BAD_DATA);
   if (err)
     goto leave;
 
   if (DBG_CRYPTO)
     log_printhex (secret, secretlen, "ECDH X ..:");
 
   /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X.
    * According to SEC1 3.6.1 we should check that
    *   SECRETLEN + UKMLEN + 4 < maxhashlen
    * However, we have no practical limit on the hash length and thus
    * there is no point in checking this.  The second check that
    *   KEYLEN < hashlen*(2^32-1)
    * is obviously also not needed.  Because with our allowed
    * parameters KEYLEN is always less or equal to HASHLEN so that we
    * do not need to iterate at all.
    */
   log_assert (gcry_md_get_algo_dlen (hash_algo) == hashlen);
   {
     gcry_md_hd_t hash_hd;
     err = gcry_md_open (&hash_hd, hash_algo, 0);
     if (err)
       goto leave;
     gcry_md_write(hash_hd, secret, secretlen);
     gcry_md_write(hash_hd, "\x00\x00\x00\x01", 4);  /* counter */
     err = hash_ecc_cms_shared_info (hash_hd, wrap_algo_str, keylen, NULL, 0);
     gcry_md_final (hash_hd);
     log_assert (keylen <= sizeof key && keylen <= hashlen);
     memcpy (key, gcry_md_read (hash_hd, 0), keylen);
     gcry_md_close (hash_hd);
     if (err)
       goto leave;
   }
 
   if (DBG_CRYPTO)
     log_printhex (key, keylen, "KEK .....:");
 
   /* Wrap the key.  */
   if ((dek->keylen % 8) || dek->keylen < 16)
     {
       log_error ("%s: can't use a session key of %u bytes\n",
                  __func__, dek->keylen);
       err = gpg_error (GPG_ERR_BAD_DATA);
       goto leave;
     }
 
   resultlen = dek->keylen + 8;
   result = xtrymalloc_secure (resultlen);
   if (!result)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
 
   err = gcry_cipher_open (&cipher_hd, cipher_algo, GCRY_CIPHER_MODE_AESWRAP, 0);
   if (err)
     {
       log_error ("%s: failed to initialize AESWRAP: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_cipher_setkey (cipher_hd, key, keylen);
   wipememory (key, sizeof key);
   if (err)
     {
       log_error ("%s: failed in gcry_cipher_setkey: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
 
   err = gcry_cipher_encrypt (cipher_hd, result, resultlen,
                              dek->key, dek->keylen);
   if (err)
     {
       log_error ("%s: failed in gcry_cipher_encrypt: %s\n",
                  __func__, gpg_strerror (err));
       goto leave;
     }
 
   if (DBG_CRYPTO)
     log_printhex (result, resultlen, "w(CEK) ..:");
 
   err = gcry_sexp_build (r_encval, NULL,
                          "(enc-val(ecdh(e%b)(s%b)(encr-algo%s)(wrap-algo%s)))",
                          (int)pubkeylen, pubkey,
                          (int)resultlen, result,
                          encr_algo_str,
                          wrap_algo_str,
                          NULL);
   if (err)
     log_error ("%s: failed building final S-exp: %s\n",
                __func__, gpg_strerror (err));
 
  leave:
   gcry_cipher_close (cipher_hd);
   wipememory (key, sizeof key);
   xfree (result);
   xfree (ioarray[0].data);
   xfree (ioarray[1].data);
   gcry_sexp_release (s_data);
   gcry_sexp_release (s_encr);
   xfree (curvebuf);
   return err;
 }
 
 
 /* Encrypt the DEK under the key contained in CERT and return it as a
  * canonical S-expressions at ENCVAL. PK_ALGO is the public key
  * algorithm which the caller has already retrieved from CERT.  */
 static int
 encrypt_dek (const DEK dek, ksba_cert_t cert, int pk_algo,
              unsigned char **encval)
 {
   gcry_sexp_t s_ciph, s_data, s_pkey;
   int rc;
   ksba_sexp_t buf;
   size_t len;
 
   *encval = NULL;
 
   /* get the key from the cert */
   buf = ksba_cert_get_public_key (cert);
   if (!buf)
     {
       log_error ("no public key for recipient\n");
       return gpg_error (GPG_ERR_NO_PUBKEY);
     }
   len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
   if (!len)
     {
       log_error ("libksba did not return a proper S-Exp\n");
       return gpg_error (GPG_ERR_BUG);
     }
   rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)buf, len);
   xfree (buf); buf = NULL;
   if (rc)
     {
       log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
       return rc;
     }
 
   if (DBG_CRYPTO)
     {
       log_printsexp (" pubkey:", s_pkey);
       log_printhex (dek->key, dek->keylen, "CEK .....:");
     }
 
   /* Put the encoded cleartext into a simple list. */
   s_data = NULL; /* (avoid compiler warning) */
   if (pk_algo == GCRY_PK_ECC)
     {
       if (!(opt.compat_flags & COMPAT_ALLOW_ECC_ENCR))
         rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
       else
         rc = ecdh_encrypt (dek, s_pkey, &s_ciph);
     }
   else
     {
       rc = encode_session_key (dek, &s_data);
       if (rc)
         {
           log_error ("encode_session_key failed: %s\n", gpg_strerror (rc));
           return rc;
         }
       if (DBG_CRYPTO)
         log_printsexp ("   data:", s_data);
 
       /* pass it to libgcrypt */
       rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
     }
   gcry_sexp_release (s_data);
   gcry_sexp_release (s_pkey);
 
   if (DBG_CRYPTO)
     log_printsexp ("enc-val:", s_ciph);
 
   /* Reformat it. */
   if (!rc)
     {
       rc = make_canon_sexp (s_ciph, encval, NULL);
       gcry_sexp_release (s_ciph);
     }
   return rc;
 }
 
 
 
 /* do the actual encryption */
 static int
 encrypt_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
 {
   struct encrypt_cb_parm_s *parm = cb_value;
   int blklen = parm->dek->ivlen;
   unsigned char *p;
   size_t n;
 
   *nread = 0;
   if (!buffer)
     return -1; /* not supported */
 
   if (parm->ready)
     return -1;
 
   if (count < blklen)
     BUG ();
 
   if (!parm->eof_seen)
     { /* fillup the buffer */
       p = parm->buffer;
       for (n=parm->buflen; n < parm->bufsize; n++)
         {
           int c = es_getc (parm->fp);
           if (c == EOF)
             {
               if (es_ferror (parm->fp))
                 {
                   parm->readerror = errno;
                   return -1;
                 }
               parm->eof_seen = 1;
               break;
             }
           p[n] = c;
         }
       parm->buflen = n;
     }
 
   n = parm->buflen < count? parm->buflen : count;
   n = n/blklen * blklen;
   if (n)
     { /* encrypt the stuff */
       gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
       *nread = n;
       /* Who cares about cycles, take the easy way and shift the buffer */
       parm->buflen -= n;
       memmove (parm->buffer, parm->buffer+n, parm->buflen);
     }
   else if (parm->eof_seen)
     { /* no complete block but eof: add padding */
       /* fixme: we should try to do this also in the above code path */
       int i, npad = blklen - (parm->buflen % blklen);
       p = parm->buffer;
       for (n=parm->buflen, i=0; n < parm->bufsize && i < npad; n++, i++)
         p[n] = npad;
       gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
       *nread = n;
       parm->ready = 1;
     }
 
   return 0;
 }
 
 
 
 
 /* Perform an encrypt operation.
 
    Encrypt the data received on DATA-FD and write it to OUT_FP.  The
    recipients are take from the certificate given in recplist; if this
    is NULL it will be encrypted for a default recipient */
 int
 gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
 {
   int rc = 0;
   gnupg_ksba_io_t b64writer = NULL;
   gpg_error_t err;
   ksba_writer_t writer;
   ksba_reader_t reader = NULL;
   ksba_cms_t cms = NULL;
   ksba_stop_reason_t stopreason;
   KEYDB_HANDLE kh = NULL;
   struct encrypt_cb_parm_s encparm;
   DEK dek = NULL;
   int recpno;
   estream_t data_fp = NULL;
   certlist_t cl;
   int count;
   int compliant;
 
   memset (&encparm, 0, sizeof encparm);
 
   audit_set_type (ctrl->audit, AUDIT_TYPE_ENCRYPT);
 
   /* Check that the certificate list is not empty and that at least
      one certificate is not flagged as encrypt_to; i.e. is a real
      recipient. */
   for (cl = recplist; cl; cl = cl->next)
     if (!cl->is_encrypt_to)
       break;
   if (!cl)
     {
       log_error(_("no valid recipients given\n"));
       gpgsm_status (ctrl, STATUS_NO_RECP, "0");
       audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 0);
       rc = gpg_error (GPG_ERR_NO_PUBKEY);
       goto leave;
     }
 
   for (count = 0, cl = recplist; cl; cl = cl->next)
     count++;
   audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, count);
 
   kh = keydb_new ();
   if (!kh)
     {
       log_error (_("failed to allocate keyDB handle\n"));
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
   /* Fixme:  We should use the unlocked version of the es functions.  */
   data_fp = es_fdopen_nc (data_fd, "rb");
   if (!data_fp)
     {
       rc = gpg_error_from_syserror ();
       log_error ("fdopen() failed: %s\n", strerror (errno));
       goto leave;
     }
 
   err = ksba_reader_new (&reader);
   if (err)
       rc = err;
   if (!rc)
     rc = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
   if (rc)
       goto leave;
 
   encparm.fp = data_fp;
 
   ctrl->pem_name = "ENCRYPTED MESSAGE";
   rc = gnupg_ksba_create_writer
     (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
                   | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
      ctrl->pem_name, out_fp, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
+  if (ctrl->input_size_hint)
+    gnupg_ksba_set_total (b64writer, ctrl->input_size_hint);
 
   err = ksba_cms_new (&cms);
   if (err)
     {
       rc = err;
       goto leave;
     }
 
   err = ksba_cms_set_reader_writer (cms, reader, writer);
   if (err)
     {
       log_error ("ksba_cms_set_reader_writer failed: %s\n",
                  gpg_strerror (err));
       rc = err;
       goto leave;
     }
 
   audit_log (ctrl->audit, AUDIT_GOT_DATA);
 
   /* We are going to create enveloped data with uninterpreted data as
      inner content */
   err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
   if (!err)
     err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
   if (err)
     {
       log_error ("ksba_cms_set_content_type failed: %s\n",
                  gpg_strerror (err));
       rc = err;
       goto leave;
     }
 
   /* Check compliance.  */
   if (!gnupg_cipher_is_allowed
       (opt.compliance, 1, gcry_cipher_map_name (opt.def_cipher_algoid),
        gcry_cipher_mode_from_oid (opt.def_cipher_algoid)))
     {
       log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
 		 opt.def_cipher_algoid,
 		 gnupg_compliance_option_string (opt.compliance));
       rc = gpg_error (GPG_ERR_CIPHER_ALGO);
       goto leave;
     }
 
   if (!gnupg_rng_is_compliant (opt.compliance))
     {
       rc = gpg_error (GPG_ERR_FORBIDDEN);
       log_error (_("%s is not compliant with %s mode\n"),
                  "RNG",
                  gnupg_compliance_option_string (opt.compliance));
       gpgsm_status_with_error (ctrl, STATUS_ERROR,
                                "random-compliance", rc);
       goto leave;
     }
 
   /* Create a session key */
   dek = xtrycalloc_secure (1, sizeof *dek);
   if (!dek)
     rc = out_of_core ();
   else
   {
     dek->algoid = opt.def_cipher_algoid;
     rc = init_dek (dek);
   }
   if (rc)
     {
       log_error ("failed to create the session key: %s\n",
                  gpg_strerror (rc));
       goto leave;
     }
 
   err = ksba_cms_set_content_enc_algo (cms, dek->algoid, dek->iv, dek->ivlen);
   if (err)
     {
       log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
                  gpg_strerror (err));
       rc = err;
       goto leave;
     }
 
   encparm.dek = dek;
   /* Use a ~8k (AES) or ~4k (3DES) buffer */
   encparm.bufsize = 500 * dek->ivlen;
   encparm.buffer = xtrymalloc (encparm.bufsize);
   if (!encparm.buffer)
     {
       rc = out_of_core ();
       goto leave;
     }
 
   audit_log_s (ctrl->audit, AUDIT_SESSION_KEY, dek->algoid);
 
   compliant = gnupg_cipher_is_compliant (CO_DE_VS, dek->algo,
                                          GCRY_CIPHER_MODE_CBC);
 
   /* Gather certificates of recipients, encrypt the session key for
      each and store them in the CMS object */
   for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next)
     {
       unsigned char *encval;
       unsigned int nbits;
       int pk_algo;
 
       /* Check compliance.  */
       pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
       if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
                                   NULL, nbits, NULL))
         {
           char  kidstr[10+1];
 
           snprintf (kidstr, sizeof kidstr, "0x%08lX",
                     gpgsm_get_short_fingerprint (cl->cert, NULL));
           log_info (_("WARNING: key %s is not suitable for encryption"
                       " in %s mode\n"),
                     kidstr,
                     gnupg_compliance_option_string (opt.compliance));
         }
 
       /* Fixme: When adding ECC we need to provide the curvename and
        * the key to gnupg_pk_is_compliant.  */
       if (compliant
           && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL))
         compliant = 0;
 
       rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
       if (rc)
         {
           audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc);
           log_error ("encryption failed for recipient no. %d: %s\n",
                      recpno, gpg_strerror (rc));
           goto leave;
         }
 
       err = ksba_cms_add_recipient (cms, cl->cert);
       if (err)
         {
           audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
           log_error ("ksba_cms_add_recipient failed: %s\n",
                      gpg_strerror (err));
           rc = err;
           xfree (encval);
           goto leave;
         }
 
       err = ksba_cms_set_enc_val (cms, recpno, encval);
       xfree (encval);
       audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
       if (err)
         {
           log_error ("ksba_cms_set_enc_val failed: %s\n",
                      gpg_strerror (err));
           rc = err;
           goto leave;
         }
     }
 
   if (compliant && gnupg_gcrypt_is_compliant (CO_DE_VS))
     gpgsm_status (ctrl, STATUS_ENCRYPTION_COMPLIANCE_MODE,
                   gnupg_status_compliance_flag (CO_DE_VS));
   else if (opt.require_compliance
            && opt.compliance == CO_DE_VS)
     {
       log_error (_("operation forced to fail due to"
                    " unfulfilled compliance rules\n"));
       gpgsm_errors_seen = 1;
       rc = gpg_error (GPG_ERR_FORBIDDEN);
       goto leave;
     }
 
   /* Main control loop for encryption. */
   recpno = 0;
   do
     {
       err = ksba_cms_build (cms, &stopreason);
       if (err)
         {
           log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
           rc = err;
           goto leave;
         }
     }
   while (stopreason != KSBA_SR_READY);
 
   if (encparm.readerror)
     {
       log_error ("error reading input: %s\n", strerror (encparm.readerror));
       rc = gpg_error (gpg_err_code_from_errno (encparm.readerror));
       goto leave;
     }
 
 
   rc = gnupg_ksba_finish_writer (b64writer);
   if (rc)
     {
       log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE);
   if (!opt.quiet)
     log_info ("encrypted data created\n");
 
  leave:
   ksba_cms_release (cms);
   gnupg_ksba_destroy_writer (b64writer);
   ksba_reader_release (reader);
   keydb_release (kh);
   xfree (dek);
   es_fclose (data_fp);
   xfree (encparm.buffer);
   return rc;
 }
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index ffa5a55a7..4606c5aa9 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -1,2278 +1,2284 @@
 /* gpgsm.c - GnuPG for S/MIME
  * Copyright (C) 2001-2020 Free Software Foundation, Inc.
  * Copyright (C) 2001-2019 Werner Koch
  * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
 #include <fcntl.h>
 
 #define INCLUDED_BY_MAIN_MODULE 1
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <assuan.h> /* malloc hooks */
 
 #include "passphrase.h"
 #include "../common/shareddefs.h"
 #include "../kbx/keybox.h" /* malloc hooks */
 #include "../common/i18n.h"
 #include "keydb.h"
 #include "../common/sysutils.h"
 #include "../common/gc-opt-flags.h"
 #include "../common/asshelp.h"
 #include "../common/init.h"
 #include "../common/compliance.h"
 #include "minip12.h"
 
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
 enum cmd_and_opt_values {
   aNull = 0,
   oArmor        = 'a',
   aDetachedSign = 'b',
   aSym	        = 'c',
   aDecrypt	= 'd',
   aEncr	        = 'e',
   aListKeys	= 'k',
   aListSecretKeys = 'K',
   oDryRun	= 'n',
   oOutput	= 'o',
   oQuiet	= 'q',
   oRecipient	= 'r',
   aSign	        = 's',
   oUser	        = 'u',
   oVerbose	= 'v',
   oBatch	= 500,
   aClearsign,
   aKeygen,
   aSignEncr,
   aDeleteKey,
   aImport,
   aVerify,
   aListExternalKeys,
   aListChain,
   aSendKeys,
   aRecvKeys,
   aExport,
   aExportSecretKeyP12,
   aExportSecretKeyP8,
   aExportSecretKeyRaw,
   aServer,
   aLearnCard,
   aCallDirmngr,
   aCallProtectTool,
   aPasswd,
   aGPGConfList,
   aGPGConfTest,
   aDumpKeys,
   aDumpChain,
   aDumpSecretKeys,
   aDumpExternalKeys,
   aKeydbClearSomeCertFlags,
   aFingerprint,
 
   oOptions,
   oDebug,
   oDebugLevel,
   oDebugAll,
   oDebugNone,
   oDebugWait,
   oDebugAllowCoreDump,
   oDebugNoChainValidation,
   oDebugIgnoreExpiration,
   oLogFile,
   oNoLogFile,
   oAuditLog,
   oHtmlAuditLog,
 
   oEnableSpecialFilenames,
 
   oAgentProgram,
   oDisplay,
   oTTYname,
   oTTYtype,
   oLCctype,
   oLCmessages,
   oXauthority,
 
   oPreferSystemDirmngr,
   oDirmngrProgram,
   oDisableDirmngr,
   oProtectToolProgram,
   oFakedSystemTime,
 
   oPassphraseFD,
   oPinentryMode,
   oRequestOrigin,
 
   oAssumeArmor,
   oAssumeBase64,
   oAssumeBinary,
+  oInputSizeHint,
 
   oBase64,
   oNoArmor,
   oP12Charset,
 
   oCompliance,
 
   oDisableCRLChecks,
   oEnableCRLChecks,
   oDisableTrustedCertCRLCheck,
   oEnableTrustedCertCRLCheck,
   oForceCRLRefresh,
   oEnableIssuerBasedCRLCheck,
 
   oDisableOCSP,
   oEnableOCSP,
 
   oIncludeCerts,
   oPolicyFile,
   oDisablePolicyChecks,
   oEnablePolicyChecks,
   oAutoIssuerKeyRetrieve,
   oMinRSALength,
 
   oWithFingerprint,
   oWithMD5Fingerprint,
   oWithKeygrip,
   oWithSecret,
   oAnswerYes,
   oAnswerNo,
   oKeyring,
   oDefaultKey,
   oDefRecipient,
   oDefRecipientSelf,
   oNoDefRecipient,
   oStatusFD,
   oCipherAlgo,
   oDigestAlgo,
   oExtraDigestAlgo,
   oNoVerbose,
   oNoSecmemWarn,
   oNoDefKeyring,
   oNoGreeting,
   oNoTTY,
   oNoOptions,
   oNoBatch,
   oHomedir,
   oWithColons,
   oWithKeyData,
   oWithValidation,
   oWithEphemeralKeys,
   oSkipVerify,
   oValidationModel,
   oKeyServer,
   oKeyServer_deprecated,
   oEncryptTo,
   oNoEncryptTo,
   oLoggerFD,
   oDisableCipherAlgo,
   oDisablePubkeyAlgo,
   oIgnoreTimeConflict,
   oNoRandomSeedFile,
   oNoCommonCertsImport,
   oIgnoreCertExtension,
   oIgnoreCertWithOID,
   oRequireCompliance,
   oCompatibilityFlags,
   oKbxBufferSize,
   oNoAutostart
  };
 
 
 static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_group (300, N_("@Commands:\n ")),
 
   ARGPARSE_c (aSign, "sign", N_("make a signature")),
 /*ARGPARSE_c (aClearsign, "clearsign", N_("make a clear text signature") ),*/
   ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")),
   ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")),
 /*ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")),*/
   ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")),
   ARGPARSE_c (aVerify, "verify",  N_("verify a signature")),
   ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
   ARGPARSE_c (aListExternalKeys, "list-external-keys",
               N_("list external keys")),
   ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
   ARGPARSE_c (aListChain,   "list-chain",  N_("list certificate chain")),
   ARGPARSE_c (aFingerprint, "fingerprint", N_("list keys and fingerprints")),
   ARGPARSE_c (aKeygen, "generate-key", N_("generate a new key pair")),
   ARGPARSE_c (aKeygen, "gen-key", "@"),
   ARGPARSE_c (aDeleteKey, "delete-keys",
               N_("remove keys from the public keyring")),
 /*ARGPARSE_c (aSendKeys, "send-keys", N_("export keys to a keyserver")),*/
 /*ARGPARSE_c (aRecvKeys, "recv-keys", N_("import keys from a keyserver")),*/
   ARGPARSE_c (aImport, "import", N_("import certificates")),
   ARGPARSE_c (aExport, "export", N_("export certificates")),
 
   /* We use -raw and not -p1 for pkcs#1 secret key export so that it
      won't accidentally be used in case -p12 was intended.  */
   ARGPARSE_c (aExportSecretKeyP12, "export-secret-key-p12", "@"),
   ARGPARSE_c (aExportSecretKeyP8,  "export-secret-key-p8", "@"),
   ARGPARSE_c (aExportSecretKeyRaw, "export-secret-key-raw", "@"),
 
   ARGPARSE_c (aLearnCard, "learn-card", N_("register a smartcard")),
   ARGPARSE_c (aServer, "server", N_("run in server mode")),
   ARGPARSE_c (aCallDirmngr, "call-dirmngr",
               N_("pass a command to the dirmngr")),
   ARGPARSE_c (aCallProtectTool, "call-protect-tool",
               N_("invoke gpg-protect-tool")),
   ARGPARSE_c (aPasswd, "change-passphrase", N_("change a passphrase")),
   ARGPARSE_c (aPasswd, "passwd", "@"),
   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
   ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
 
   ARGPARSE_c (aDumpKeys, "dump-cert", "@"),
   ARGPARSE_c (aDumpKeys, "dump-keys", "@"),
   ARGPARSE_c (aDumpChain, "dump-chain", "@"),
   ARGPARSE_c (aDumpExternalKeys, "dump-external-keys", "@"),
   ARGPARSE_c (aDumpSecretKeys, "dump-secret-keys", "@"),
   ARGPARSE_c (aKeydbClearSomeCertFlags, "keydb-clear-some-cert-flags", "@"),
 
 
   ARGPARSE_header ("Monitor", N_("Options controlling the diagnostic output")),
 
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
   ARGPARSE_s_n (oQuiet,	"quiet",  N_("be somewhat more quiet")),
   ARGPARSE_s_n (oNoTTY, "no-tty", N_("don't use the terminal at all")),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
   ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level",
                 N_("|LEVEL|set the debugging level to LEVEL")),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
   ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
   ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
   ARGPARSE_s_n (oDebugNoChainValidation, "debug-no-chain-validation", "@"),
   ARGPARSE_s_n (oDebugIgnoreExpiration,  "debug-ignore-expiration", "@"),
   ARGPARSE_s_s (oLogFile, "log-file",
                 N_("|FILE|write server mode logs to FILE")),
   ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
   ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
   ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
 
 
   ARGPARSE_header ("Configuration",
                    N_("Options controlling the configuration")),
 
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
   ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
   ARGPARSE_s_n (oPreferSystemDirmngr,"prefer-system-dirmngr", "@"),
   ARGPARSE_s_s (oValidationModel, "validation-model", "@"),
   ARGPARSE_s_i (oIncludeCerts, "include-certs",
                 N_("|N|number of certificates to include") ),
   ARGPARSE_s_s (oPolicyFile, "policy-file",
                 N_("|FILE|take policy information from FILE")),
   ARGPARSE_s_s (oCompliance, "compliance",   "@"),
   ARGPARSE_p_u (oMinRSALength, "min-rsa-length", "@"),
   ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
   ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
   ARGPARSE_s_s (oIgnoreCertWithOID, "ignore-cert-with-oid", "@"),
   ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
   ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
   ARGPARSE_s_s (oProtectToolProgram, "protect-tool-program", "@"),
 
 
   ARGPARSE_header ("Input", N_("Options controlling the input")),
 
   ARGPARSE_s_n (oAssumeArmor, "assume-armor",
                 N_("assume input is in PEM format")),
   ARGPARSE_s_n (oAssumeBase64, "assume-base64",
                 N_("assume input is in base-64 format")),
   ARGPARSE_s_n (oAssumeBinary, "assume-binary",
                 N_("assume input is in binary format")),
+  ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"),
 
 
   ARGPARSE_header ("Output", N_("Options controlling the output")),
 
   ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")),
   ARGPARSE_s_n (oArmor, "armour", "@"),
   ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
   ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
   ARGPARSE_s_n (oBase64, "base64", N_("create base-64 encoded output")),
   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
 
 
   ARGPARSE_header (NULL, N_("Options to specify keys")),
 
   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
   ARGPARSE_s_s (oUser, "local-user",
                 N_("|USER-ID|use USER-ID to sign or decrypt")),
   ARGPARSE_s_s (oDefaultKey, "default-key",
                 N_("|USER-ID|use USER-ID as default secret key")),
   ARGPARSE_s_s (oEncryptTo, "encrypt-to",
                 N_("|NAME|encrypt to user ID NAME as well")),
   ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"),
   /* Not yet used: */
   /*   ARGPARSE_s_s (oDefRecipient, "default-recipient", */
   /*                  N_("|NAME|use NAME as default recipient")), */
   /*   ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", */
   /*                  N_("use the default key as default recipient")), */
   /*   ARGPARSE_s_n (oNoDefRecipient, "no-default-recipient", "@"), */
   ARGPARSE_s_s (oKeyring, "keyring",
                 N_("|FILE|add keyring to the list of keyrings")),
   ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
   ARGPARSE_s_s (oKeyServer_deprecated, "ldapserver", "@"),
   ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
 
   ARGPARSE_header ("ImportExport",
                    N_("Options controlling key import and export")),
 
   ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr",
                 N_("disable all access to the dirmngr")),
   ARGPARSE_s_n (oAutoIssuerKeyRetrieve, "auto-issuer-key-retrieve",
                 N_("fetch missing issuer certificates")),
   ARGPARSE_s_s (oP12Charset, "p12-charset",
                 N_("|NAME|use encoding NAME for PKCS#12 passphrases")),
 
 
   ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
 
   ARGPARSE_s_n (oWithColons, "with-colons", "@"),
   ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"),
   ARGPARSE_s_n (oWithValidation, "with-validation", "@"),
   ARGPARSE_s_n (oWithMD5Fingerprint, "with-md5-fingerprint", "@"),
   ARGPARSE_s_n (oWithEphemeralKeys,  "with-ephemeral-keys", "@"),
   ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
   ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
 
   ARGPARSE_header ("Security", N_("Options controlling the security")),
 
   ARGPARSE_s_n (oDisableCRLChecks, "disable-crl-checks",
                 N_("never consult a CRL")),
   ARGPARSE_s_n (oEnableCRLChecks, "enable-crl-checks", "@"),
   ARGPARSE_s_n (oDisableTrustedCertCRLCheck,
                 "disable-trusted-cert-crl-check",
                 N_("do not check CRLs for root certificates")),
   ARGPARSE_s_n (oEnableTrustedCertCRLCheck,
                 "enable-trusted-cert-crl-check", "@"),
   ARGPARSE_s_n (oDisableOCSP, "disable-ocsp", "@"),
   ARGPARSE_s_n (oEnableOCSP,  "enable-ocsp", N_("check validity using OCSP")),
   ARGPARSE_s_n (oDisablePolicyChecks, "disable-policy-checks",
                 N_("do not check certificate policies")),
   ARGPARSE_s_n (oEnablePolicyChecks, "enable-policy-checks", "@"),
   ARGPARSE_s_s (oCipherAlgo, "cipher-algo",
                 N_("|NAME|use cipher algorithm NAME")),
   ARGPARSE_s_s (oDigestAlgo, "digest-algo",
                 N_("|NAME|use message digest algorithm NAME")),
   ARGPARSE_s_s (oExtraDigestAlgo, "extra-digest-algo", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
   ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
   ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
   ARGPARSE_s_n (oNoRandomSeedFile,  "no-random-seed-file", "@"),
   ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"),
 
 
   ARGPARSE_header (NULL, N_("Options for unattended use")),
 
   ARGPARSE_s_n (oBatch, "batch", N_("batch mode: never ask")),
   ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
   ARGPARSE_s_n (oAnswerYes, "yes", N_("assume yes on most questions")),
   ARGPARSE_s_n (oAnswerNo,  "no",  N_("assume no on most questions")),
   ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
   ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
   ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
   ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
 
 
   ARGPARSE_header (NULL, N_("Other options")),
 
   ARGPARSE_conffile (oOptions, "options", N_("|FILE|read options from FILE")),
   ARGPARSE_noconffile (oNoOptions, "no-options", "@"),
   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
   ARGPARSE_s_s (oRequestOrigin,   "request-origin", "@"),
   ARGPARSE_s_n (oForceCRLRefresh, "force-crl-refresh", "@"),
   ARGPARSE_s_n (oEnableIssuerBasedCRLCheck, "enable-issuer-based-crl-check",
                 "@"),
   ARGPARSE_s_s (oAuditLog, "audit-log",
                 N_("|FILE|write an audit log to FILE")),
   ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", "@"),
   ARGPARSE_s_s (oDisplay,    "display", "@"),
   ARGPARSE_s_s (oTTYname,    "ttyname", "@"),
   ARGPARSE_s_s (oTTYtype,    "ttytype", "@"),
   ARGPARSE_s_s (oLCctype,    "lc-ctype", "@"),
   ARGPARSE_s_s (oLCmessages, "lc-messages", "@"),
   ARGPARSE_s_s (oXauthority, "xauthority", "@"),
   ARGPARSE_s_s (oCompatibilityFlags, "compatibility-flags", "@"),
   ARGPARSE_p_u (oKbxBufferSize,  "kbx-buffer-size", "@"),
 
   ARGPARSE_header (NULL, ""),  /* Stop the header group.  */
 
 
   /* Command aliases.  */
   ARGPARSE_c (aListKeys, "list-key", "@"),
   ARGPARSE_c (aListChain, "list-signatures", "@"),
   ARGPARSE_c (aListChain, "list-sigs", "@"),
   ARGPARSE_c (aListChain, "check-signatures", "@"),
   ARGPARSE_c (aListChain, "check-sigs", "@"),
   ARGPARSE_c (aDeleteKey, "delete-key", "@"),
 
   ARGPARSE_group (302, N_(
   "@\n(See the man page for a complete listing of all commands and options)\n"
   )),
 
   ARGPARSE_end ()
 };
 
 
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
     { DBG_X509_VALUE   , "x509"    },
     { DBG_MPI_VALUE    , "mpi"     },
     { DBG_CRYPTO_VALUE , "crypto"  },
     { DBG_MEMORY_VALUE , "memory"  },
     { DBG_CACHE_VALUE  , "cache"   },
     { DBG_MEMSTAT_VALUE, "memstat" },
     { DBG_HASHING_VALUE, "hashing" },
     { DBG_IPC_VALUE    , "ipc"     },
     { 0, NULL }
   };
 
 
 /* The list of compatibility flags.  */
 static struct compatibility_flags_s compatibility_flags [] =
   {
     { COMPAT_ALLOW_KA_TO_ENCR, "allow-ka-to-encr" },
     { COMPAT_ALLOW_ECC_ENCR,   "allow-ecc-encr" },
     { 0, NULL }
   };
 
 
 /* Global variable to keep an error count. */
 int gpgsm_errors_seen = 0;
 
 /* It is possible that we are currentlu running under setuid permissions */
 static int maybe_setuid = 1;
 
 /* Helper to implement --debug-level and --debug*/
 static const char *debug_level;
 static unsigned int debug_value;
 
 /* Default value for include-certs.  We need an extra macro for
    gpgconf-list because the variable will be changed by the command
    line option.
 
    It is often cumbersome to locate intermediate certificates, thus by
    default we include all certificates in the chain.  However we leave
    out the root certificate because that would make it too easy for
    the recipient to import that root certificate.  A root certificate
    should be installed only after due checks and thus it won't help to
    send it along with each message.  */
 #define DEFAULT_INCLUDE_CERTS -2 /* Include all certs but root. */
 static int default_include_certs = DEFAULT_INCLUDE_CERTS;
 
 /* Whether the chain mode shall be used for validation.  */
 static int default_validation_model;
 
 /* The default cipher algo.  */
 #define DEFAULT_CIPHER_ALGO "AES256"
 
 
 static char *build_list (const char *text,
 			 const char *(*mapf)(int), int (*chkf)(int));
 static void set_cmd (enum cmd_and_opt_values *ret_cmd,
                      enum cmd_and_opt_values new_cmd );
 
 static void emergency_cleanup (void);
 static int open_read (const char *filename);
 static estream_t open_es_fread (const char *filename, const char *mode);
 static estream_t open_es_fwrite (const char *filename);
 static void run_protect_tool (int argc, char **argv);
 
 static int
 our_pk_test_algo (int algo)
 {
   switch (algo)
     {
     case GCRY_PK_RSA:
     case GCRY_PK_ECDSA:
     case GCRY_PK_EDDSA:
       return gcry_pk_test_algo (algo);
     default:
       return 1;
     }
 }
 
 static int
 our_cipher_test_algo (int algo)
 {
   switch (algo)
     {
     case GCRY_CIPHER_3DES:
     case GCRY_CIPHER_AES128:
     case GCRY_CIPHER_AES192:
     case GCRY_CIPHER_AES256:
     case GCRY_CIPHER_SERPENT128:
     case GCRY_CIPHER_SERPENT192:
     case GCRY_CIPHER_SERPENT256:
     case GCRY_CIPHER_SEED:
     case GCRY_CIPHER_CAMELLIA128:
     case GCRY_CIPHER_CAMELLIA192:
     case GCRY_CIPHER_CAMELLIA256:
       return gcry_cipher_test_algo (algo);
     default:
       return 1;
     }
 }
 
 
 static int
 our_md_test_algo (int algo)
 {
   switch (algo)
     {
     case GCRY_MD_MD5:
     case GCRY_MD_SHA1:
     case GCRY_MD_RMD160:
     case GCRY_MD_SHA224:
     case GCRY_MD_SHA256:
     case GCRY_MD_SHA384:
     case GCRY_MD_SHA512:
     case GCRY_MD_WHIRLPOOL:
       return gcry_md_test_algo (algo);
     default:
       return 1;
     }
 }
 
 
 static char *
 make_libversion (const char *libname, const char *(*getfnc)(const char*))
 {
   const char *s;
   char *result;
 
   if (maybe_setuid)
     {
       gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
       maybe_setuid = 0;
     }
   s = getfnc (NULL);
   result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
   strcpy (stpcpy (stpcpy (result, libname), " "), s);
   return result;
 }
 
 
 static const char *
 my_strusage( int level )
 {
   static char *digests, *pubkeys, *ciphers;
   static char *ver_gcry, *ver_ksba;
   const char *p;
 
   switch (level)
     {
     case  9: p = "GPL-3.0-or-later"; break;
     case 11: p = "@GPGSM@ (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
     case 17: p = PRINTABLE_OS_NAME; break;
     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
 
     case 1:
     case 40: p = _("Usage: @GPGSM@ [options] [files] (-h for help)");
       break;
     case 41:
       p = _("Syntax: @GPGSM@ [options] [files]\n"
             "Sign, check, encrypt or decrypt using the S/MIME protocol\n"
             "Default operation depends on the input data\n");
       break;
 
     case 20:
       if (!ver_gcry)
         ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
       p = ver_gcry;
       break;
     case 21:
       if (!ver_ksba)
         ver_ksba = make_libversion ("libksba", ksba_check_version);
       p = ver_ksba;
       break;
 
     case 31: p = "\nHome: "; break;
     case 32: p = gnupg_homedir (); break;
     case 33: p = _("\nSupported algorithms:\n"); break;
     case 34:
       if (!ciphers)
         ciphers = build_list ("Cipher: ", gnupg_cipher_algo_name,
                               our_cipher_test_algo );
       p = ciphers;
       break;
     case 35:
       if (!pubkeys)
         pubkeys = build_list ("Pubkey: ", gcry_pk_algo_name,
                               our_pk_test_algo );
       p = pubkeys;
       break;
     case 36:
       if (!digests)
         digests = build_list("Hash: ", gcry_md_algo_name, our_md_test_algo );
       p = digests;
       break;
 
     default: p = NULL; break;
     }
   return p;
 }
 
 
 static char *
 build_list (const char *text, const char * (*mapf)(int), int (*chkf)(int))
 {
   int i;
   size_t n=strlen(text)+2;
   char *list, *p;
 
   if (maybe_setuid) {
     gcry_control (GCRYCTL_DROP_PRIVS); /* drop setuid */
   }
 
   for (i=1; i < 400; i++ )
     if (!chkf(i))
       n += strlen(mapf(i)) + 2;
   list = xmalloc (21 + n);
   *list = 0;
   for (p=NULL, i=1; i < 400; i++)
     {
       if (!chkf(i))
         {
           if( !p )
             p = stpcpy (list, text );
           else
             p = stpcpy (p, ", ");
           p = stpcpy (p, mapf(i) );
 	}
     }
   if (p)
     strcpy (p, "\n" );
   return list;
 }
 
 
 /* Set the file pointer into binary mode if required.  */
 static void
 set_binary (FILE *fp)
 {
 #ifdef HAVE_DOSISH_SYSTEM
   setmode (fileno (fp), O_BINARY);
 #else
   (void)fp;
 #endif
 }
 
 
 
 static void
 wrong_args (const char *text)
 {
   fprintf (stderr, _("usage: %s [options] %s\n"), GPGSM_NAME, text);
   gpgsm_exit (2);
 }
 
 
 static void
 set_opt_session_env (const char *name, const char *value)
 {
   gpg_error_t err;
 
   err = session_env_setenv (opt.session_env, name, value);
   if (err)
     log_fatal ("error setting session environment: %s\n",
                gpg_strerror (err));
 }
 
 
 /* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
    debug flags are propagated to the subsystems.  With DEBUG_LEVEL
    set, a specific set of debug flags is set; and individual debugging
    flags will be added on top.  */
 static void
 set_debug (void)
 {
   int numok = (debug_level && digitp (debug_level));
   int numlvl = numok? atoi (debug_level) : 0;
 
   if (!debug_level)
     ;
   else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
     opt.debug = DBG_IPC_VALUE|DBG_X509_VALUE;
   else if (!strcmp (debug_level, "expert")  || (numok && numlvl <= 8))
     opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
       opt.debug = ~0;
       /* Unless the "guru" string has been used we don't want to allow
          hashing debugging.  The rationale is that people tend to
          select the highest debug value and would then clutter their
          disk with debug files which may reveal confidential data.  */
       if (numok)
         opt.debug &= ~(DBG_HASHING_VALUE);
     }
   else
     {
       log_error (_("invalid debug-level '%s' given\n"), debug_level);
       gpgsm_exit (2);
     }
 
   opt.debug |= debug_value;
 
   if (opt.debug && !opt.verbose)
     opt.verbose = 1;
   if (opt.debug)
     opt.quiet = 0;
 
   if (opt.debug & DBG_MPI_VALUE)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
     parse_debug_flag (NULL, &opt.debug, debug_flags);
 
   /* minip12.c may be used outside of GnuPG, thus we don't have the
    * opt structure over there.  */
   p12_set_verbosity (opt.verbose);
 }
 
 
 
 static void
 set_cmd (enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd)
 {
   enum cmd_and_opt_values cmd = *ret_cmd;
 
   if (!cmd || cmd == new_cmd)
     cmd = new_cmd;
   else if ( cmd == aSign && new_cmd == aEncr )
     cmd = aSignEncr;
   else if ( cmd == aEncr && new_cmd == aSign )
     cmd = aSignEncr;
   else if ( (cmd == aSign && new_cmd == aClearsign)
             || (cmd == aClearsign && new_cmd == aSign) )
     cmd = aClearsign;
   else
     {
       log_error(_("conflicting commands\n"));
       gpgsm_exit(2);
     }
 
   *ret_cmd = cmd;
 }
 
 
 /* Helper to add recipients to a list. */
 static void
 do_add_recipient (ctrl_t ctrl, const char *name,
                   certlist_t *recplist, int is_encrypt_to, int recp_required)
 {
   int rc = gpgsm_add_to_certlist (ctrl, name, 0, recplist, is_encrypt_to);
   if (rc)
     {
       if (recp_required)
         {
           log_error ("can't encrypt to '%s': %s\n", name, gpg_strerror (rc));
           gpgsm_status2 (ctrl, STATUS_INV_RECP,
                          get_inv_recpsgnr_code (rc), name, NULL);
         }
       else
         log_info (_("Note: won't be able to encrypt to '%s': %s\n"),
                   name, gpg_strerror (rc));
     }
 }
 
 
 static void
 parse_validation_model (const char *model)
 {
   int i = gpgsm_parse_validation_model (model);
   if (i == -1)
     log_error (_("unknown validation model '%s'\n"), model);
   else
     default_validation_model = i;
 }
 
 
 
 int
 main ( int argc, char **argv)
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
   char **orig_argv;
   /*  char *username;*/
   int may_coredump;
   strlist_t sl, remusr= NULL, locusr=NULL;
   strlist_t nrings=NULL;
   int detached_sig = 0;
   char *last_configname = NULL;
   const char *configname = NULL; /* NULL or points to last_configname.
                                   * NULL also indicates that we are
                                   * processing options from the cmdline.  */
   int debug_argparser = 0;
   int no_more_options = 0;
   int default_keyring = 1;
   char *logfile = NULL;
   char *auditlog = NULL;
   char *htmlauditlog = NULL;
   int greeting = 0;
   int nogreeting = 0;
   int debug_wait = 0;
   int use_random_seed = 1;
   int no_common_certs_import = 0;
   int with_fpr = 0;
   const char *forced_digest_algo = NULL;
   const char *extra_digest_algo = NULL;
   enum cmd_and_opt_values cmd = 0;
   struct server_control_s ctrl;
   certlist_t recplist = NULL;
   certlist_t signerlist = NULL;
   int do_not_setup_keys = 0;
   int recp_required = 0;
   estream_t auditfp = NULL;
   estream_t htmlauditfp = NULL;
   struct assuan_malloc_hooks malloc_hooks;
   int pwfd = -1;
 
   static const char *homedirvalue;
 
   early_system_init ();
   gnupg_reopen_std (GPGSM_NAME);
   /* trap_unaligned ();*/
   gnupg_rl_initialize ();
   set_strusage (my_strusage);
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
 
   /* Please note that we may running SUID(ROOT), so be very CAREFUL
      when adding any stuff between here and the call to secmem_init()
      somewhere after the option parsing */
   log_set_prefix (GPGSM_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY);
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
   /* Check that the libraries are suitable.  Do it here because the
      option parse may need services of the library */
   if (!ksba_check_version (NEED_KSBA_VERSION) )
     log_fatal (_("%s is too old (need %s, have %s)\n"), "libksba",
                NEED_KSBA_VERSION, ksba_check_version (NULL) );
 
 
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
   may_coredump = disable_core_dumps ();
 
   gnupg_init_signals (0, emergency_cleanup);
 
   dotlock_create (NULL, 0); /* Register lockfile cleanup.  */
 
   /* Tell the compliance module who we are.  */
   gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPGSM);
 
   opt.autostart = 1;
   opt.session_env = session_env_new ();
   if (!opt.session_env)
     log_fatal ("error allocating session environment block: %s\n",
                strerror (errno));
 
   /* Note: If you change this default cipher algorithm , please
      remember to update the Gpgconflist entry as well.  */
   opt.def_cipher_algoid = DEFAULT_CIPHER_ALGO;
 
 
   /* First check whether we have a config file on the commandline */
   orig_argc = argc;
   orig_argv = argv;
   pargs.argc = &argc;
   pargs.argv = &argv;
   pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
   while (gnupg_argparse (NULL, &pargs, opts))
     {
       switch (pargs.r_opt)
         {
         case oDebug:
         case oDebugAll:
           debug_argparser++;
           break;
 
         case oNoOptions:
           /* Set here here because the homedir would otherwise be
            * created before main option parsing starts.  */
           opt.no_homedir_creation = 1;
           break;
 
         case oHomedir:
           homedirvalue = pargs.r.ret_str;
           break;
 
         case aCallProtectTool:
           /* Make sure that --version and --help are passed to the
            * protect-tool. */
           goto leave_cmdline_parser;
         }
     }
  leave_cmdline_parser:
   /* Reset the flags.  */
   pargs.flags &= ~(ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
 
 
   /* Initialize the secure memory. */
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
   maybe_setuid = 0;
 
   /*
    * Now we are now working under our real uid
    */
 
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
 
   malloc_hooks.malloc = gcry_malloc;
   malloc_hooks.realloc = gcry_realloc;
   malloc_hooks.free = gcry_free;
   assuan_set_malloc_hooks (&malloc_hooks);
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
   setup_libassuan_logging (&opt.debug, NULL);
 
   /* Set homedir.  */
   gnupg_set_homedir (homedirvalue);
 
   /* Setup a default control structure for command line mode */
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
   ctrl.no_server = 1;
   ctrl.status_fd = -1; /* No status output. */
   ctrl.autodetect_encoding = 1;
 
   /* Set the default policy file */
   opt.policy_file = make_filename (gnupg_homedir (), "policies.txt", NULL);
 
   /* The configuraton directories for use by gpgrt_argparser.  */
   gnupg_set_confdir (GNUPG_CONFDIR_SYS, gnupg_sysconfdir ());
   gnupg_set_confdir (GNUPG_CONFDIR_USER, gnupg_homedir ());
 
   /* We are re-using the struct, thus the reset flag.  We OR the
    * flags so that the internal intialized flag won't be cleared. */
   argc        = orig_argc;
   argv        = orig_argv;
   pargs.argc  = &argc;
   pargs.argv  = &argv;
   pargs.flags |=  (ARGPARSE_FLAG_RESET
                    | ARGPARSE_FLAG_KEEP
                    | ARGPARSE_FLAG_SYS
                    | ARGPARSE_FLAG_USER);
 
   while (!no_more_options
          && gnupg_argparser (&pargs, opts, GPGSM_NAME EXTSEP_S "conf"))
     {
       switch (pargs.r_opt)
         {
         case ARGPARSE_CONFFILE:
           if (debug_argparser)
             log_info (_("reading options from '%s'\n"),
                       pargs.r_type? pargs.r.ret_str: "[cmdline]");
           if (pargs.r_type)
             {
               xfree (last_configname);
               last_configname = xstrdup (pargs.r.ret_str);
               configname = last_configname;
             }
           else
             configname = NULL;
           break;
 
 	case aGPGConfList:
 	case aGPGConfTest:
           set_cmd (&cmd, pargs.r_opt);
           do_not_setup_keys = 1;
           default_keyring = 0;
           nogreeting = 1;
           break;
 
         case aServer:
           opt.batch = 1;
           set_cmd (&cmd, aServer);
           break;
 
         case aCallDirmngr:
           opt.batch = 1;
           set_cmd (&cmd, aCallDirmngr);
           do_not_setup_keys = 1;
           break;
 
         case aCallProtectTool:
           opt.batch = 1;
           set_cmd (&cmd, aCallProtectTool);
           no_more_options = 1; /* Stop parsing. */
           do_not_setup_keys = 1;
           break;
 
         case aDeleteKey:
           set_cmd (&cmd, aDeleteKey);
           /*greeting=1;*/
           do_not_setup_keys = 1;
           break;
 
         case aDetachedSign:
           detached_sig = 1;
           set_cmd (&cmd, aSign );
           break;
 
         case aKeygen:
           set_cmd (&cmd, aKeygen);
           greeting=1;
           do_not_setup_keys = 1;
           break;
 
         case aImport:
         case aSendKeys:
         case aRecvKeys:
         case aExport:
         case aExportSecretKeyP12:
         case aExportSecretKeyP8:
         case aExportSecretKeyRaw:
         case aDumpKeys:
         case aDumpChain:
         case aDumpExternalKeys:
         case aDumpSecretKeys:
         case aListKeys:
         case aListExternalKeys:
         case aListSecretKeys:
         case aListChain:
         case aLearnCard:
         case aPasswd:
         case aKeydbClearSomeCertFlags:
           do_not_setup_keys = 1;
           set_cmd (&cmd, pargs.r_opt);
           break;
 
         case aEncr:
           recp_required = 1;
           set_cmd (&cmd, pargs.r_opt);
           break;
 
         case aSym:
         case aDecrypt:
         case aSign:
         case aClearsign:
         case aVerify:
           set_cmd (&cmd, pargs.r_opt);
           break;
 
           /* Output encoding selection.  */
         case oArmor:
           ctrl.create_pem = 1;
           break;
         case oBase64:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 1;
           break;
         case oNoArmor:
           ctrl.create_pem = 0;
           ctrl.create_base64 = 0;
           break;
 
         case oP12Charset:
           opt.p12_charset = pargs.r.ret_str;
           break;
 
         case oPassphraseFD:
 	  pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
 	  break;
 
         case oPinentryMode:
 	  opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
 	  if (opt.pinentry_mode == -1)
             log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
 	  break;
 
         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;
           ctrl.is_pem = 1;
           ctrl.is_base64 = 0;
           break;
         case oAssumeBase64:
           ctrl.autodetect_encoding = 0;
           ctrl.is_pem = 0;
           ctrl.is_base64 = 1;
           break;
         case oAssumeBinary:
           ctrl.autodetect_encoding = 0;
           ctrl.is_pem = 0;
           ctrl.is_base64 = 0;
           break;
 
+        case oInputSizeHint:
+          ctrl.input_size_hint = string_to_u64 (pargs.r.ret_str);
+          break;
+
         case oDisableCRLChecks:
           opt.no_crl_check = 1;
           break;
         case oEnableCRLChecks:
           opt.no_crl_check = 0;
           break;
         case oDisableTrustedCertCRLCheck:
           opt.no_trusted_cert_crl_check = 1;
           break;
         case oEnableTrustedCertCRLCheck:
           opt.no_trusted_cert_crl_check = 0;
           break;
         case oForceCRLRefresh:
           opt.force_crl_refresh = 1;
           break;
         case oEnableIssuerBasedCRLCheck:
           opt.enable_issuer_based_crl_check = 1;
           break;
 
         case oDisableOCSP:
           ctrl.use_ocsp = opt.enable_ocsp = 0;
           break;
         case oEnableOCSP:
           ctrl.use_ocsp = opt.enable_ocsp = 1;
           break;
 
         case oIncludeCerts:
           ctrl.include_certs = default_include_certs = pargs.r.ret_int;
           break;
 
         case oPolicyFile:
           xfree (opt.policy_file);
           if (*pargs.r.ret_str)
             opt.policy_file = xstrdup (pargs.r.ret_str);
           else
             opt.policy_file = NULL;
           break;
 
         case oDisablePolicyChecks:
           opt.no_policy_check = 1;
           break;
         case oEnablePolicyChecks:
           opt.no_policy_check = 0;
           break;
 
         case oAutoIssuerKeyRetrieve:
           opt.auto_issuer_key_retrieve = 1;
           break;
 
         case oOutput: opt.outfile = pargs.r.ret_str; break;
 
 
         case oQuiet: opt.quiet = 1; break;
         case oNoTTY: /* fixme:tty_no_terminal(1);*/ break;
         case oDryRun: opt.dry_run = 1; break;
 
         case oVerbose:
           opt.verbose++;
           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
           break;
         case oNoVerbose:
           opt.verbose = 0;
           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
           break;
 
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oNoLogFile: logfile = NULL; break;
 
         case oAuditLog: auditlog = pargs.r.ret_str; break;
         case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
 
         case oBatch:
           opt.batch = 1;
           greeting = 0;
           break;
         case oNoBatch: opt.batch = 0; break;
 
         case oAnswerYes: opt.answer_yes = 1; break;
         case oAnswerNo: opt.answer_no = 1; break;
 
         case oKeyring: append_to_strlist (&nrings, pargs.r.ret_str); break;
 
         case oDebug:
           if (parse_debug_flag (pargs.r.ret_str, &debug_value, debug_flags))
             {
               pargs.r_opt = ARGPARSE_INVALID_ARG;
               pargs.err = ARGPARSE_PRINT_ERROR;
             }
           break;
         case oDebugAll: debug_value = ~0; break;
         case oDebugNone: debug_value = 0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
         case oDebugAllowCoreDump:
           may_coredump = enable_core_dumps ();
           break;
         case oDebugNoChainValidation: opt.no_chain_validation = 1; break;
         case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break;
 
         case oCompatibilityFlags:
           if (parse_compatibility_flags (pargs.r.ret_str, &opt.compat_flags,
                                          compatibility_flags))
             {
               pargs.r_opt = ARGPARSE_INVALID_ARG;
               pargs.err = ARGPARSE_PRINT_ERROR;
             }
           break;
 
         case oStatusFD:
             ctrl.status_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 1);
             break;
         case oLoggerFD:
             log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
             break;
         case oWithMD5Fingerprint:
           opt.with_md5_fingerprint=1; /*fall through*/
         case oWithFingerprint:
           with_fpr=1; /*fall through*/
         case aFingerprint:
           opt.fingerprint++;
           break;
 
         case oWithKeygrip:
           opt.with_keygrip = 1;
           break;
 
         case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
 
         case oDisplay:
           set_opt_session_env ("DISPLAY", pargs.r.ret_str);
           break;
         case oTTYname:
           set_opt_session_env ("GPG_TTY", pargs.r.ret_str);
           break;
         case oTTYtype:
           set_opt_session_env ("TERM", pargs.r.ret_str);
           break;
         case oXauthority:
           set_opt_session_env ("XAUTHORITY", pargs.r.ret_str);
           break;
 
         case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
         case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
 
         case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
         case oDisableDirmngr: opt.disable_dirmngr = 1;  break;
         case oPreferSystemDirmngr: /* Obsolete */; break;
         case oProtectToolProgram:
           opt.protect_tool_program = pargs.r.ret_str;
           break;
 
         case oFakedSystemTime:
           {
             time_t faked_time = isotime2epoch (pargs.r.ret_str);
             if (faked_time == (time_t)(-1))
               faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
             gnupg_set_time (faked_time, 0);
           }
           break;
 
         case oNoDefKeyring: default_keyring = 0; break;
         case oNoGreeting: nogreeting = 1; break;
 
         case oDefaultKey:
           if (*pargs.r.ret_str)
             {
               xfree (opt.local_user);
               opt.local_user = xstrdup (pargs.r.ret_str);
             }
           break;
         case oDefRecipient:
           if (*pargs.r.ret_str)
             opt.def_recipient = xstrdup (pargs.r.ret_str);
           break;
         case oDefRecipientSelf:
           xfree (opt.def_recipient);
           opt.def_recipient = NULL;
           opt.def_recipient_self = 1;
           break;
         case oNoDefRecipient:
           xfree (opt.def_recipient);
           opt.def_recipient = NULL;
           opt.def_recipient_self = 0;
           break;
 
         case oWithKeyData: opt.with_key_data=1; /* fall through */
         case oWithColons: ctrl.with_colons = 1; break;
         case oWithSecret: ctrl.with_secret = 1; break;
         case oWithValidation: ctrl.with_validation=1; break;
         case oWithEphemeralKeys: ctrl.with_ephemeral_keys=1; break;
 
         case oSkipVerify: opt.skip_verify=1; break;
 
         case oNoEncryptTo: opt.no_encrypt_to = 1; break;
         case oEncryptTo: /* Store the recipient in the second list */
           sl = add_to_strlist (&remusr, pargs.r.ret_str);
           sl->flags = 1;
           break;
 
         case oRecipient: /* store the recipient */
           add_to_strlist ( &remusr, pargs.r.ret_str);
           break;
 
         case oUser: /* Store the local users, the first one is the default */
           if (!opt.local_user)
             opt.local_user = xstrdup (pargs.r.ret_str);
           add_to_strlist (&locusr, pargs.r.ret_str);
           break;
 
         case oNoSecmemWarn:
           gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
           break;
 
         case oCipherAlgo:
           opt.def_cipher_algoid = pargs.r.ret_str;
           break;
 
         case oDisableCipherAlgo:
           {
             int algo = gcry_cipher_map_name (pargs.r.ret_str);
             gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo);
           }
           break;
         case oDisablePubkeyAlgo:
           {
             int algo = gcry_pk_map_name (pargs.r.ret_str);
             gcry_pk_ctl (GCRYCTL_DISABLE_ALGO,&algo, sizeof algo );
           }
           break;
 
         case oDigestAlgo:
           forced_digest_algo = pargs.r.ret_str;
           break;
 
         case oExtraDigestAlgo:
           extra_digest_algo = pargs.r.ret_str;
           break;
 
         case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
         case oNoRandomSeedFile: use_random_seed = 0; break;
         case oNoCommonCertsImport: no_common_certs_import = 1; break;
 
         case oEnableSpecialFilenames:
           enable_special_filenames ();
           break;
 
         case oValidationModel: parse_validation_model (pargs.r.ret_str); break;
 
 	case oKeyServer:
           append_to_strlist (&opt.keyserver, pargs.r.ret_str);
 	  break;
 
         case oKeyServer_deprecated:
           obsolete_option (configname, pargs.lineno, "ldapserver");
           break;
 
         case oIgnoreCertExtension:
           add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str);
           break;
 
         case oIgnoreCertWithOID:
           add_to_strlist (&opt.ignore_cert_with_oid, pargs.r.ret_str);
           break;
 
         case oNoAutostart: opt.autostart = 0; break;
 
         case oCompliance:
           {
             struct gnupg_compliance_option compliance_options[] =
               {
                 { "gnupg", CO_GNUPG },
                 { "de-vs", CO_DE_VS }
               };
             int compliance = gnupg_parse_compliance_option (pargs.r.ret_str,
                                                             compliance_options,
                                                             DIM (compliance_options),
                                                             opt.quiet);
             if (compliance < 0)
               log_inc_errorcount (); /* Force later termination.  */
             opt.compliance = compliance;
           }
           break;
 
         case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
 
         case oRequireCompliance: opt.require_compliance = 1;  break;
 
         case oKbxBufferSize:
           keybox_set_buffersize (pargs.r.ret_ulong, 0);
           break;
 
         default:
           if (configname)
             pargs.err = ARGPARSE_PRINT_WARNING;
           else
             {
               pargs.err = ARGPARSE_PRINT_ERROR;
               /* The argparse function calls a plain exit and thus we
                * need to print a status here.  */
               gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser",
                                        gpg_error (GPG_ERR_GENERAL));
             }
           break;
 	}
     }
 
   gnupg_argparse (NULL, &pargs, NULL);  /* Release internal state.  */
 
   if (!last_configname)
     opt.config_filename = make_filename (gnupg_homedir (),
                                          GPGSM_NAME EXTSEP_S "conf",
                                          NULL);
   else
     opt.config_filename = last_configname;
 
   if (log_get_errorcount(0))
     {
       gpgsm_status_with_error (&ctrl, STATUS_FAILURE,
                                "option-parser", gpg_error (GPG_ERR_GENERAL));
       gpgsm_exit(2);
     }
 
   if (pwfd != -1)	/* Read the passphrase now.  */
     read_passphrase_from_fd (pwfd);
 
   /* Now that we have the options parsed we need to update the default
      control structure.  */
   gpgsm_init_default_ctrl (&ctrl);
 
   if (nogreeting)
     greeting = 0;
 
   if (greeting)
     {
       es_fprintf (es_stderr, "%s %s; %s\n",
                   strusage(11), strusage(13), strusage(14) );
       es_fprintf (es_stderr, "%s\n", strusage(15) );
     }
 #  ifdef IS_DEVELOPMENT_VERSION
   if (!opt.batch)
     {
       log_info ("NOTE: THIS IS A DEVELOPMENT VERSION!\n");
       log_info ("It is only intended for test purposes and should NOT be\n");
       log_info ("used in a production environment or with production keys!\n");
     }
 #  endif
 
   if (may_coredump && !opt.quiet)
     log_info (_("WARNING: program may create a core file!\n"));
 
 /*   if (opt.qualsig_approval && !opt.quiet) */
 /*     log_info (_("This software has officially been approved to " */
 /*                 "create and verify\n" */
 /*                 "qualified signatures according to German law.\n")); */
 
   if (logfile && cmd == aServer)
     {
       log_set_file (logfile);
       log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
     }
 
   if (gnupg_faked_time_p ())
     {
       gnupg_isotime_t tbuf;
 
       log_info (_("WARNING: running with faked system time: "));
       gnupg_get_isotime (tbuf);
       dump_isotime (tbuf);
       log_printf ("\n");
     }
 
   /* Print a warning if an argument looks like an option.  */
   if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
     {
       int i;
 
       for (i=0; i < argc; i++)
         if (argv[i][0] == '-' && argv[i][1] == '-')
           log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
     }
 
 /*FIXME    if (opt.batch) */
 /*      tty_batchmode (1); */
 
   gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
 
   set_debug ();
   if (opt.verbose) /* Print the compatibility flags.  */
     parse_compatibility_flags (NULL, &opt.compat_flags, compatibility_flags);
   gnupg_set_compliance_extra_info (CO_EXTRA_INFO_MIN_RSA, opt.min_rsa_length);
 
   /* Although we always use gpgsm_exit, we better install a regualr
      exit handler so that at least the secure memory gets wiped
      out. */
   if (atexit (emergency_cleanup))
     {
       log_error ("atexit failed\n");
       gpgsm_exit (2);
     }
 
   /* Must do this after dropping setuid, because the mapping functions
      may try to load an module and we may have disabled an algorithm.
      We remap the commonly used algorithms to the OIDs for
      convenience.  We need to work with the OIDs because they are used
      to check whether the encryption mode is actually available. */
   if (!strcmp (opt.def_cipher_algoid, "3DES") )
     opt.def_cipher_algoid = "1.2.840.113549.3.7";
   else if (!strcmp (opt.def_cipher_algoid, "AES")
            || !strcmp (opt.def_cipher_algoid, "AES128"))
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.2";
   else if (!strcmp (opt.def_cipher_algoid, "AES192") )
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.22";
   else if (!strcmp (opt.def_cipher_algoid, "AES256") )
     opt.def_cipher_algoid = "2.16.840.1.101.3.4.1.42";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT")
            || !strcmp (opt.def_cipher_algoid, "SERPENT128") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.2";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT192") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.22";
   else if (!strcmp (opt.def_cipher_algoid, "SERPENT256") )
     opt.def_cipher_algoid = "1.3.6.1.4.1.11591.13.2.42";
   else if (!strcmp (opt.def_cipher_algoid, "SEED") )
     opt.def_cipher_algoid = "1.2.410.200004.1.4";
   else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA")
            || !strcmp (opt.def_cipher_algoid, "CAMELLIA128") )
     opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.2";
   else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA192") )
     opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.3";
   else if (!strcmp (opt.def_cipher_algoid, "CAMELLIA256") )
     opt.def_cipher_algoid = "1.2.392.200011.61.1.1.1.4";
 
   if (cmd != aGPGConfList)
     {
       if ( !gcry_cipher_map_name (opt.def_cipher_algoid)
            || !gcry_cipher_mode_from_oid (opt.def_cipher_algoid))
         log_error (_("selected cipher algorithm is invalid\n"));
 
       if (forced_digest_algo)
         {
           opt.forced_digest_algo = gcry_md_map_name (forced_digest_algo);
           if (our_md_test_algo(opt.forced_digest_algo) )
             log_error (_("selected digest algorithm is invalid\n"));
         }
       if (extra_digest_algo)
         {
           opt.extra_digest_algo = gcry_md_map_name (extra_digest_algo);
           if (our_md_test_algo (opt.extra_digest_algo) )
             log_error (_("selected digest algorithm is invalid\n"));
         }
     }
 
   /* Check our chosen algorithms against the list of allowed
    * algorithms in the current compliance mode, and fail hard if it 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.  */
   if (! gnupg_cipher_is_allowed (opt.compliance,
                                  cmd == aEncr || cmd == aSignEncr,
                                  gcry_cipher_map_name (opt.def_cipher_algoid),
                                  GCRY_CIPHER_MODE_NONE)
       && ! gnupg_cipher_is_allowed (opt.compliance,
                                     cmd == aEncr || cmd == aSignEncr,
                                     gcry_cipher_mode_from_oid
                                     (opt.def_cipher_algoid),
                                     GCRY_CIPHER_MODE_NONE))
     log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
                opt.def_cipher_algoid,
                gnupg_compliance_option_string (opt.compliance));
 
   if (forced_digest_algo
       && ! gnupg_digest_is_allowed (opt.compliance,
                                      cmd == aSign
                                      || cmd == aSignEncr
                                      || cmd == aClearsign,
                                      opt.forced_digest_algo))
     log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
                forced_digest_algo,
                gnupg_compliance_option_string (opt.compliance));
 
   if (extra_digest_algo
       && ! gnupg_digest_is_allowed (opt.compliance,
                                      cmd == aSign
                                      || cmd == aSignEncr
                                      || cmd == aClearsign,
                                      opt.extra_digest_algo))
     log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
                extra_digest_algo,
                gnupg_compliance_option_string (opt.compliance));
 
   if (log_get_errorcount(0))
     {
       gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-postprocessing",
                                gpg_error (GPG_ERR_GENERAL));
       gpgsm_exit (2);
     }
 
   /* Set the random seed file. */
   if (use_random_seed)
     {
       char *p = make_filename (gnupg_homedir (), "random_seed", NULL);
       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
       xfree(p);
     }
 
   if (!cmd && opt.fingerprint && !with_fpr)
     set_cmd (&cmd, aListKeys);
 
   /* Add default keybox. */
   if (!nrings && default_keyring)
     {
       int created;
 
       keydb_add_resource (&ctrl, "pubring.kbx", 0, &created);
       if (created && !no_common_certs_import)
         {
           /* Import the standard certificates for a new default keybox. */
           char *filelist[2];
 
           filelist[0] = make_filename (gnupg_datadir (),"com-certs.pem", NULL);
           filelist[1] = NULL;
           if (!gnupg_access (filelist[0], F_OK))
             {
               log_info (_("importing common certificates '%s'\n"),
                         filelist[0]);
               gpgsm_import_files (&ctrl, 1, filelist, open_read);
             }
           xfree (filelist[0]);
         }
     }
   for (sl = nrings; sl; sl = sl->next)
     keydb_add_resource (&ctrl, sl->d, 0, NULL);
   FREE_STRLIST(nrings);
 
 
   /* Prepare the audit log feature for certain commands.  */
   if (auditlog || htmlauditlog)
     {
       switch (cmd)
         {
         case aEncr:
         case aSign:
         case aDecrypt:
         case aVerify:
           audit_release (ctrl.audit);
           ctrl.audit = audit_new ();
           if (auditlog)
             auditfp = open_es_fwrite (auditlog);
           if (htmlauditlog)
             htmlauditfp = open_es_fwrite (htmlauditlog);
           break;
         default:
           break;
         }
     }
 
 
   if (!do_not_setup_keys)
     {
       int errcount = log_get_errorcount (0);
 
       for (sl = locusr; sl ; sl = sl->next)
         {
           int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0);
           if (rc)
             {
               log_error (_("can't sign using '%s': %s\n"),
                          sl->d, gpg_strerror (rc));
               gpgsm_status2 (&ctrl, STATUS_INV_SGNR,
                              get_inv_recpsgnr_code (rc), sl->d, NULL);
               gpgsm_status2 (&ctrl, STATUS_INV_RECP,
                              get_inv_recpsgnr_code (rc), sl->d, NULL);
             }
         }
 
       /* Build the recipient list.  We first add the regular ones and then
          the encrypt-to ones because the underlying function will silently
          ignore duplicates and we can't allow keeping a duplicate which is
          flagged as encrypt-to as the actually encrypt function would then
          complain about no (regular) recipients. */
       for (sl = remusr; sl; sl = sl->next)
         if (!(sl->flags & 1))
           do_add_recipient (&ctrl, sl->d, &recplist, 0, recp_required);
       if (!opt.no_encrypt_to)
         {
           for (sl = remusr; sl; sl = sl->next)
             if ((sl->flags & 1))
               do_add_recipient (&ctrl, sl->d, &recplist, 1, recp_required);
         }
 
       /* We do not require a recipient for decryption but because
        * recipients and signers are always checked and log_error is
        * sometimes used (for failed signing keys or due to a failed
        * CRL checking) that would have bumbed up the error counter.
        * We clear the counter in the decryption case because there is
        * no reason to force decryption to fail. */
       if (cmd == aDecrypt && !errcount)
         log_get_errorcount (1); /* clear counter */
     }
 
   if (log_get_errorcount(0))
     gpgsm_exit(1); /* Must stop for invalid recipients. */
 
   /* Dispatch command.  */
   switch (cmd)
     {
     case aGPGConfList:
       { /* List options and default values in the GPG Conf format.  */
 
 	es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
         es_printf ("include-certs:%lu:%d:\n", GC_OPT_FLAG_DEFAULT,
                    DEFAULT_INCLUDE_CERTS);
         es_printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
                    DEFAULT_CIPHER_ALGO);
         es_printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT);
         es_printf ("default-key:%lu:\n", GC_OPT_FLAG_DEFAULT);
         es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT);
 
         /* 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-3072");
       }
       break;
     case aGPGConfTest:
       /* This is merely a dummy command to test whether the
          configuration file is valid.  */
       break;
 
     case aServer:
       if (debug_wait)
         {
           log_debug ("waiting for debugger - my pid is %u .....\n",
                      (unsigned int)getpid());
           gnupg_sleep (debug_wait);
           log_debug ("... okay\n");
          }
       gpgsm_server (recplist);
       break;
 
     case aCallDirmngr:
       if (!argc)
         wrong_args ("--call-dirmngr <command> {args}");
       else
         if (gpgsm_dirmngr_run_command (&ctrl, *argv, argc-1, argv+1))
           gpgsm_exit (1);
       break;
 
     case aCallProtectTool:
       run_protect_tool (argc, argv);
       break;
 
     case aEncr: /* Encrypt the given file. */
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         set_binary (stdin);
 
         if (!argc) /* Source is stdin. */
           gpgsm_encrypt (&ctrl, recplist, 0, fp);
         else if (argc == 1)  /* Source is the given file. */
           gpgsm_encrypt (&ctrl, recplist, open_read (*argv), fp);
         else
           wrong_args ("--encrypt [datafile]");
 
         es_fclose (fp);
       }
       break;
 
     case aSign: /* Sign the given file. */
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         /* Fixme: We should also allow concatenation of multiple files for
            signing because that is what gpg does.*/
         set_binary (stdin);
         if (!argc) /* Create from stdin. */
           gpgsm_sign (&ctrl, signerlist, 0, detached_sig, fp);
         else if (argc == 1) /* From file. */
           gpgsm_sign (&ctrl, signerlist,
                       open_read (*argv), detached_sig, fp);
         else
           wrong_args ("--sign [datafile]");
 
         es_fclose (fp);
       }
       break;
 
     case aSignEncr: /* sign and encrypt the given file */
       log_error ("the command '%s' has not yet been implemented\n",
                  "--sign --encrypt");
       gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser",
                                gpg_error (GPG_ERR_NOT_IMPLEMENTED));
       break;
 
     case aClearsign: /* make a clearsig */
       log_error ("the command '%s' has not yet been implemented\n",
                  "--clearsign");
       gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser",
                                gpg_error (GPG_ERR_NOT_IMPLEMENTED));
       break;
 
     case aVerify:
       {
         estream_t fp = NULL;
 
         set_binary (stdin);
         if (argc == 2 && opt.outfile)
           log_info ("option --output ignored for a detached signature\n");
         else if (opt.outfile)
           fp = open_es_fwrite (opt.outfile);
 
         if (!argc)
           gpgsm_verify (&ctrl, 0, -1, fp); /* normal signature from stdin */
         else if (argc == 1)
           gpgsm_verify (&ctrl, open_read (*argv), -1, fp); /* std signature */
         else if (argc == 2) /* detached signature (sig, detached) */
           gpgsm_verify (&ctrl, open_read (*argv), open_read (argv[1]), NULL);
         else
           wrong_args ("--verify [signature [detached_data]]");
 
         es_fclose (fp);
       }
       break;
 
     case aDecrypt:
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
         gpg_error_t err;
 
         set_binary (stdin);
         if (!argc)
           err = gpgsm_decrypt (&ctrl, 0, fp); /* from stdin */
         else if (argc == 1)
           err = gpgsm_decrypt (&ctrl, open_read (*argv), fp); /* from file */
         else
           wrong_args ("--decrypt [filename]");
 
 #if GPGRT_VERSION_NUMBER >= 0x012700  /* 1.39 */
         if (err)
           gpgrt_fcancel (fp);
         else
 #endif
           es_fclose (fp);
       }
       break;
 
     case aDeleteKey:
       for (sl=NULL; argc; argc--, argv++)
         add_to_strlist (&sl, *argv);
       gpgsm_delete (&ctrl, sl);
       free_strlist(sl);
       break;
 
     case aListChain:
     case aDumpChain:
        ctrl.with_chain = 1; /* fall through */
     case aListKeys:
     case aDumpKeys:
     case aListExternalKeys:
     case aDumpExternalKeys:
     case aListSecretKeys:
     case aDumpSecretKeys:
       {
         unsigned int mode;
         estream_t fp;
 
         switch (cmd)
           {
           case aListChain:
           case aListKeys:         mode = (0   | 0 | (1<<6)); break;
           case aDumpChain:
           case aDumpKeys:         mode = (256 | 0 | (1<<6)); break;
           case aListExternalKeys: mode = (0   | 0 | (1<<7)); break;
           case aDumpExternalKeys: mode = (256 | 0 | (1<<7)); break;
           case aListSecretKeys:   mode = (0   | 2 | (1<<6)); break;
           case aDumpSecretKeys:   mode = (256 | 2 | (1<<6)); break;
           default: BUG();
           }
 
         fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
         for (sl=NULL; argc; argc--, argv++)
           add_to_strlist (&sl, *argv);
         gpgsm_list_keys (&ctrl, sl, fp, mode);
         free_strlist(sl);
         es_fclose (fp);
       }
       break;
 
 
     case aKeygen: /* Generate a key; well kind of. */
       {
         estream_t fpin = NULL;
         estream_t fpout;
 
         if (opt.batch)
           {
             if (!argc) /* Create from stdin. */
               fpin = open_es_fread ("-", "r");
             else if (argc == 1) /* From file. */
               fpin = open_es_fread (*argv, "r");
             else
               wrong_args ("--generate-key --batch [parmfile]");
           }
 
         fpout = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (fpin)
           gpgsm_genkey (&ctrl, fpin, fpout);
         else
           gpgsm_gencertreq_tty (&ctrl, fpout);
 
         es_fclose (fpout);
       }
       break;
 
 
     case aImport:
       gpgsm_import_files (&ctrl, argc, argv, open_read);
       break;
 
     case aExport:
       {
         estream_t fp;
 
         fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
         for (sl=NULL; argc; argc--, argv++)
           add_to_strlist (&sl, *argv);
         gpgsm_export (&ctrl, sl, fp);
         free_strlist(sl);
         es_fclose (fp);
       }
       break;
 
     case aExportSecretKeyP12:
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
           gpgsm_p12_export (&ctrl, *argv, fp, 0);
         else
           wrong_args ("--export-secret-key-p12 KEY-ID");
         if (fp != es_stdout)
           es_fclose (fp);
       }
       break;
 
     case aExportSecretKeyP8:
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
           gpgsm_p12_export (&ctrl, *argv, fp, 1);
         else
           wrong_args ("--export-secret-key-p8 KEY-ID");
         if (fp != es_stdout)
           es_fclose (fp);
       }
       break;
 
     case aExportSecretKeyRaw:
       {
         estream_t fp = open_es_fwrite (opt.outfile?opt.outfile:"-");
 
         if (argc == 1)
           gpgsm_p12_export (&ctrl, *argv, fp, 2);
         else
           wrong_args ("--export-secret-key-raw KEY-ID");
         if (fp != es_stdout)
           es_fclose (fp);
       }
       break;
 
     case aSendKeys:
     case aRecvKeys:
       log_error ("this command has not yet been implemented\n");
       break;
 
 
     case aLearnCard:
       if (argc)
         wrong_args ("--learn-card");
       else
         {
           int rc = gpgsm_agent_learn (&ctrl);
           if (rc)
             log_error ("error learning card: %s\n", gpg_strerror (rc));
         }
       break;
 
     case aPasswd:
       if (argc != 1)
         wrong_args ("--change-passphrase <key-Id>");
       else
         {
           int rc;
           ksba_cert_t cert = NULL;
           char *grip = NULL;
 
           rc = gpgsm_find_cert (&ctrl, *argv, NULL, &cert, 0);
           if (rc)
             ;
           else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
             rc = gpg_error (GPG_ERR_BUG);
           else
             {
               char *desc = gpgsm_format_keydesc (cert);
               rc = gpgsm_agent_passwd (&ctrl, grip, desc);
               xfree (desc);
             }
           if (rc)
             log_error ("error changing passphrase: %s\n", gpg_strerror (rc));
           xfree (grip);
           ksba_cert_release (cert);
         }
       break;
 
     case aKeydbClearSomeCertFlags:
       for (sl=NULL; argc; argc--, argv++)
         add_to_strlist (&sl, *argv);
       keydb_clear_some_cert_flags (&ctrl, sl);
       free_strlist(sl);
       break;
 
 
     default:
       log_error (_("invalid command (there is no implicit command)\n"));
       gpgsm_status_with_error (&ctrl, STATUS_FAILURE, "option-parser",
                                gpg_error (GPG_ERR_MISSING_ACTION));
       break;
     }
 
   /* Print the audit result if needed.  */
   if ((auditlog && auditfp) || (htmlauditlog && htmlauditfp))
     {
       if (auditlog && auditfp)
         audit_print_result (ctrl.audit, auditfp, 0);
       if (htmlauditlog && htmlauditfp)
         audit_print_result (ctrl.audit, htmlauditfp, 1);
       audit_release (ctrl.audit);
       ctrl.audit = NULL;
       es_fclose (auditfp);
       es_fclose (htmlauditfp);
     }
 
   /* cleanup */
   free_strlist (opt.keyserver);
   opt.keyserver = NULL;
   gpgsm_release_certlist (recplist);
   gpgsm_release_certlist (signerlist);
   FREE_STRLIST (remusr);
   FREE_STRLIST (locusr);
   gpgsm_exit(0);
   return 8; /*NOTREACHED*/
 }
 
 /* Note: This function is used by signal handlers!. */
 static void
 emergency_cleanup (void)
 {
   gcry_control (GCRYCTL_TERM_SECMEM );
 }
 
 
 void
 gpgsm_exit (int rc)
 {
   gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
   if (opt.debug & DBG_MEMSTAT_VALUE)
     {
       gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
       gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
     }
   if (opt.debug)
     gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
   emergency_cleanup ();
   rc = rc? rc : log_get_errorcount(0)? 2 : gpgsm_errors_seen? 1 : 0;
   exit (rc);
 }
 
 
 void
 gpgsm_init_default_ctrl (struct server_control_s *ctrl)
 {
   ctrl->include_certs = default_include_certs;
   ctrl->use_ocsp = opt.enable_ocsp;
   ctrl->validation_model = default_validation_model;
   ctrl->offline = opt.disable_dirmngr;
 }
 
 
 int
 gpgsm_parse_validation_model (const char *model)
 {
   if (!ascii_strcasecmp (model, "shell") )
     return 0;
   else if ( !ascii_strcasecmp (model, "chain") )
     return 1;
   else if ( !ascii_strcasecmp (model, "steed") )
     return 2;
   else
     return -1;
 }
 
 
 
 /* Open the FILENAME for read and return the file descriptor.  Stop
    with an error message in case of problems.  "-" denotes stdin and
    if special filenames are allowed the given fd is opened instead.  */
 static int
 open_read (const char *filename)
 {
   int fd;
 
   if (filename[0] == '-' && !filename[1])
     {
       set_binary (stdin);
       return 0; /* stdin */
     }
   fd = check_special_filename (filename, 0, 0);
   if (fd != -1)
     return fd;
   fd = gnupg_open (filename, O_RDONLY | O_BINARY, 0);
   if (fd == -1)
     {
       log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fd;
 }
 
 /* Same as open_read but return an estream_t.  */
 static estream_t
 open_es_fread (const char *filename, const char *mode)
 {
   int fd;
   estream_t fp;
 
   if (filename[0] == '-' && !filename[1])
     fd = fileno (stdin);
   else
     fd = check_special_filename (filename, 0, 0);
   if (fd != -1)
     {
       fp = es_fdopen_nc (fd, mode);
       if (!fp)
         {
           log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));
           gpgsm_exit (2);
         }
       return fp;
     }
   fp = es_fopen (filename, mode);
   if (!fp)
     {
       log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
 }
 
 
 /* Open FILENAME for fwrite and return an extended stream.  Stop with
    an error message in case of problems.  "-" denotes stdout and if
    special filenames are allowed the given fd is opened instead.
    Caller must close the returned stream. */
 static estream_t
 open_es_fwrite (const char *filename)
 {
   int fd;
   estream_t fp;
 
   if (filename[0] == '-' && !filename[1])
     {
       fflush (stdout);
       fp = es_fdopen_nc (fileno(stdout), "wb");
       return fp;
     }
 
   fd = check_special_filename (filename, 1, 0);
   if (fd != -1)
     {
       fp = es_fdopen_nc (fd, "wb");
       if (!fp)
         {
           log_error ("es_fdopen(%d) failed: %s\n", fd, strerror (errno));
           gpgsm_exit (2);
         }
       return fp;
     }
   fp = es_fopen (filename, "wb");
   if (!fp)
     {
       log_error (_("can't open '%s': %s\n"), filename, strerror (errno));
       gpgsm_exit (2);
     }
   return fp;
 }
 
 
 static void
 run_protect_tool (int argc, char **argv)
 {
 #ifdef HAVE_W32_SYSTEM
   (void)argc;
   (void)argv;
 #else
   const char *pgm;
   char **av;
   int i;
 
   if (!opt.protect_tool_program || !*opt.protect_tool_program)
     pgm = gnupg_module_name (GNUPG_MODULE_NAME_PROTECT_TOOL);
   else
     pgm = opt.protect_tool_program;
 
   av = xcalloc (argc+2, sizeof *av);
   av[0] = strrchr (pgm, '/');
   if (!av[0])
     av[0] = xstrdup (pgm);
   for (i=1; argc; i++, argc--, argv++)
     av[i] = *argv;
   av[i] = NULL;
   execv (pgm, av);
   log_error ("error executing '%s': %s\n", pgm, strerror (errno));
 #endif /*!HAVE_W32_SYSTEM*/
   gpgsm_exit (2);
 }
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 5790a64f4..a7cbb2381 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -1,480 +1,485 @@
 /* gpgsm.h - Global definitions for GpgSM
  * Copyright (C) 2001, 2003, 2004, 2007, 2009,
  *               2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #ifndef GPGSM_H
 #define GPGSM_H
 
 #ifdef GPG_ERR_SOURCE_DEFAULT
 #error GPG_ERR_SOURCE_DEFAULT already defined
 #endif
 #define GPG_ERR_SOURCE_DEFAULT  GPG_ERR_SOURCE_GPGSM
 #include <gpg-error.h>
 
 
 #include <ksba.h>
 #include "../common/util.h"
 #include "../common/status.h"
 #include "../common/audit.h"
 #include "../common/session-env.h"
 #include "../common/ksba-io-support.h"
 #include "../common/compliance.h"
 
 
 #define MAX_DIGEST_LEN 64
 
 
 /* A large struct named "opt" to keep global flags. */
 EXTERN_UNLESS_MAIN_MODULE
 struct
 {
   unsigned int debug; /* debug flags (DBG_foo_VALUE) */
   int verbose;      /* verbosity level */
   int quiet;        /* be as quiet as possible */
   int batch;        /* run in batch mode, i.e w/o any user interaction */
   int answer_yes;   /* assume yes on most questions */
   int answer_no;    /* assume no on most questions */
   int dry_run;      /* don't change any persistent data */
   int no_homedir_creation;
 
   const char *config_filename; /* Name of the used config file. */
   const char *agent_program;
 
   session_env_t session_env;
   char *lc_ctype;
   char *lc_messages;
 
   int autostart;
   const char *dirmngr_program;
   int disable_dirmngr;        /* Do not do any dirmngr calls.  */
   const char *protect_tool_program;
   char *outfile;    /* name of output file */
 
   int with_key_data;/* include raw key in the column delimted output */
 
   int fingerprint;  /* list fingerprints in all key listings */
 
   int with_md5_fingerprint; /* Also print an MD5 fingerprint for
                                standard key listings. */
 
   int with_keygrip; /* Option --with-keygrip 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*/
 
   const char *p12_charset; /* Use this charset for encoding the
                               pkcs#12 passphrase.  */
 
 
   const char *def_cipher_algoid;  /* cipher algorithm to use if
                                      nothing else is specified */
 
   int def_compress_algo;  /* Ditto for compress algorithm */
 
   int forced_digest_algo; /* User forced hash algorithm. */
 
   char *def_recipient;    /* userID of the default recipient */
   int def_recipient_self; /* The default recipient is the default key */
 
   int no_encrypt_to;      /* Ignore all as encrypt to marked recipients. */
 
   char *local_user;       /* NULL or argument to -u */
 
   int extra_digest_algo;  /* A digest algorithm also used for
                              verification of signatures.  */
 
   int always_trust;       /* Trust the given keys even if there is no
                              valid certification chain */
   int skip_verify;        /* do not check signatures on data */
 
   int lock_once;          /* Keep lock once they are set */
 
   int ignore_time_conflict; /* Ignore certain time conflicts */
 
   int no_crl_check;         /* Don't do a CRL check */
   int no_trusted_cert_crl_check; /* Don't run a CRL check for trusted certs. */
   int force_crl_refresh;    /* Force refreshing the CRL. */
   int enable_issuer_based_crl_check; /* Backward compatibility hack.  */
   int enable_ocsp;          /* Default to use OCSP checks. */
 
   char *policy_file;        /* full pathname of policy file */
   int no_policy_check;      /* ignore certificate policies */
   int no_chain_validation;  /* Bypass all cert chain validity tests */
   int ignore_expiration;    /* Ignore the notAfter validity checks. */
 
   int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */
 
   int qualsig_approval;     /* Set to true if this software has
                                officially been approved to create an
                                verify qualified signatures.  This is a
                                runtime option in case we want to check
                                the integrity of the software at
                                runtime. */
 
   unsigned int min_rsa_length;   /* Used for compliance checks.  */
 
   strlist_t keyserver;
 
   /* A list of certificate extension OIDs which are ignored so that
      one can claim that a critical extension has been handled.  One
      OID per string.  */
   strlist_t ignored_cert_extensions;
 
   /* A list of OIDs which will be used to ignore certificates with
    * sunch an OID during --learn-card.  */
   strlist_t ignore_cert_with_oid;
 
   /* The current compliance mode.  */
   enum gnupg_compliance_mode compliance;
 
   /* Fail if an operation can't be done in the requested compliance
    * mode.  */
   int require_compliance;
 
   /* Compatibility flags (COMPAT_FLAG_xxxx).  */
   unsigned int compat_flags;
 } opt;
 
 /* Debug values and macros.  */
 #define DBG_X509_VALUE    1	/* debug x.509 data reading/writing */
 #define DBG_MPI_VALUE	  2	/* debug mpi details */
 #define DBG_CRYPTO_VALUE  4	/* debug low level crypto */
 #define DBG_MEMORY_VALUE  32	/* debug memory allocation stuff */
 #define DBG_CACHE_VALUE   64	/* debug the caching */
 #define DBG_MEMSTAT_VALUE 128	/* show memory statistics */
 #define DBG_HASHING_VALUE 512	/* debug hashing operations */
 #define DBG_IPC_VALUE     1024  /* debug assuan communication */
 
 #define DBG_X509    (opt.debug & DBG_X509_VALUE)
 #define DBG_CRYPTO  (opt.debug & DBG_CRYPTO_VALUE)
 #define DBG_MEMORY  (opt.debug & DBG_MEMORY_VALUE)
 #define DBG_CACHE   (opt.debug & DBG_CACHE_VALUE)
 #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
 #define DBG_IPC     (opt.debug & DBG_IPC_VALUE)
 
 
 /* Compatibility flags */
 /* Telesec RSA cards produced for NRW in 2022 came with only the
  * keyAgreement bit set.  This flag allows there use for encryption
  * anyway.  Example cert:
  *    Issuer: /CN=DOI CA 10a/OU=DOI/O=PKI-1-Verwaltung/C=DE
  * key usage: digitalSignature nonRepudiation keyAgreement
  *  policies: 1.3.6.1.4.1.7924.1.1:N:
  */
 #define COMPAT_ALLOW_KA_TO_ENCR   1
 #define COMPAT_ALLOW_ECC_ENCR     2
 
 
 /* Forward declaration for an object defined in server.c */
 struct server_local_s;
 
 /* Session control object.  This object is passed down to most
    functions.  Note that the default values for it are set by
    gpgsm_init_default_ctrl(). */
 struct server_control_s
 {
   int no_server;      /* We are not running under server control */
   int  status_fd;     /* Only for non-server mode */
   struct server_local_s *server_local;
 
   audit_ctx_t audit;  /* NULL or a context for the audit subsystem.  */
   int agent_seen;     /* Flag indicating that the gpg-agent has been
                          accessed.  */
 
   int with_colons;    /* Use column delimited output format */
   int with_secret;    /* Mark secret keys in a public key listing.  */
   int with_chain;     /* Include the certifying certs in a listing */
   int with_validation;/* Validate each key while listing. */
   int with_ephemeral_keys;  /* Include ephemeral flagged keys in the
                                keylisting. */
 
   int autodetect_encoding; /* Try to detect the input encoding */
   int is_pem;         /* Is in PEM format */
   int is_base64;      /* is in plain base-64 format */
 
+  /* If > 0 a hint with the expected number of input data bytes.  This
+   * is not necessary an exact number but intended to be used for
+   * progress info and to decide on how to allocate buffers.  */
+  uint64_t input_size_hint;
+
   int create_base64;  /* Create base64 encoded output */
   int create_pem;     /* create PEM output */
   const char *pem_name; /* PEM name to use */
 
   int include_certs;  /* -1 to send all certificates in the chain
                          along with a signature or the number of
                          certificates up the chain (0 = none, 1 = only
                          signer) */
   int use_ocsp;       /* Set to true if OCSP should be used. */
   int validation_model; /* 0 := standard model (shell),
                            1 := chain model,
                            2 := STEED model. */
   int offline;        /* If true gpgsm won't do any network access.  */
 
   /* The current time.  Used as a helper in certchain.c.  */
   ksba_isotime_t current_time;
 };
 
 
 /* An object to keep a list of certificates. */
 struct certlist_s
 {
   struct certlist_s *next;
   ksba_cert_t cert;
   int is_encrypt_to; /* True if the certificate has been set through
                         the --encrypto-to option. */
   int pk_algo;       /* The PK_ALGO from CERT or 0 if not yet known.  */
   int hash_algo;     /* Used to track the hash algorithm to use.  */
   const char *hash_algo_oid;  /* And the corresponding OID.  */
 };
 typedef struct certlist_s *certlist_t;
 
 
 /* A structure carrying information about trusted root certificates. */
 struct rootca_flags_s
 {
   unsigned int valid:1;  /* The rest of the structure has valid
                             information.  */
   unsigned int relax:1;  /* Relax checking of root certificates.  */
   unsigned int chain_model:1; /* Root requires the use of the chain model.  */
 };
 
 
 
 /*-- gpgsm.c --*/
 extern int gpgsm_errors_seen;
 
 void gpgsm_exit (int rc);
 void gpgsm_init_default_ctrl (struct server_control_s *ctrl);
 int  gpgsm_parse_validation_model (const char *model);
 
 /*-- server.c --*/
 void gpgsm_server (certlist_t default_recplist);
 gpg_error_t gpgsm_status (ctrl_t ctrl, int no, const char *text);
 gpg_error_t gpgsm_status2 (ctrl_t ctrl, int no, ...) GPGRT_ATTR_SENTINEL(0);
 gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
                                         gpg_err_code_t ec);
 gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
                                      gpg_error_t err);
 gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total);
 gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl,
                                          const unsigned char *line);
 
 /*-- fingerprint --*/
 unsigned char *gpgsm_get_fingerprint (ksba_cert_t cert, int algo,
                                       unsigned char *array, int *r_len);
 char *gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo);
 char *gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo);
 unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
                                            unsigned long *r_high);
 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);
 int  gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits,
                                char **r_curve);
 int   gpgsm_is_ecc_key (ksba_cert_t cert);
 char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
 char *gpgsm_get_certid (ksba_cert_t cert);
 
 
 /*-- certdump.c --*/
 void gpgsm_print_serial (estream_t fp, ksba_const_sexp_t p);
 void gpgsm_print_serial_decimal (estream_t fp, ksba_const_sexp_t sn);
 void gpgsm_print_time (estream_t fp, ksba_isotime_t t);
 void gpgsm_print_name2 (FILE *fp, const char *string, int translate);
 void gpgsm_print_name (FILE *fp, const char *string);
 void gpgsm_es_print_name (estream_t fp, const char *string);
 void gpgsm_es_print_name2 (estream_t fp, const char *string, int translate);
 
 void gpgsm_cert_log_name (const char *text, ksba_cert_t cert);
 
 void gpgsm_dump_cert (const char *text, ksba_cert_t cert);
 void gpgsm_dump_serial (ksba_const_sexp_t p);
 void gpgsm_dump_time (ksba_isotime_t t);
 void gpgsm_dump_string (const char *string);
 
 char *gpgsm_format_serial (ksba_const_sexp_t p);
 char *gpgsm_format_name2 (const char *name, int translate);
 char *gpgsm_format_name (const char *name);
 char *gpgsm_format_sn_issuer (ksba_sexp_t sn, const char *issuer);
 
 char *gpgsm_fpr_and_name_for_status (ksba_cert_t cert);
 
 char *gpgsm_format_keydesc (ksba_cert_t cert);
 
 
 /*-- certcheck.c --*/
 int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert);
 int gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t sigval,
                                gcry_md_hd_t md,
                                int hash_algo, unsigned int pkalgoflags,
                                int *r_pkalgo);
 /* fixme: move create functions to another file */
 int gpgsm_create_cms_signature (ctrl_t ctrl,
                                 ksba_cert_t cert, gcry_md_hd_t md, int mdalgo,
                                 unsigned char **r_sigval);
 
 
 /*-- certchain.c --*/
 
 /* Flags used with  gpgsm_validate_chain.  */
 #define VALIDATE_FLAG_NO_DIRMNGR  1
 #define VALIDATE_FLAG_CHAIN_MODEL 2
 #define VALIDATE_FLAG_STEED       4
 
 int gpgsm_walk_cert_chain (ctrl_t ctrl,
                            ksba_cert_t start, ksba_cert_t *r_next);
 int gpgsm_is_root_cert (ksba_cert_t cert);
 int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert,
                           ksba_isotime_t checktime,
                           ksba_isotime_t r_exptime,
                           int listmode, estream_t listfp,
                           unsigned int flags, unsigned int *retflags);
 int gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert);
 
 /*-- certlist.c --*/
 int gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent);
 int gpgsm_cert_use_encrypt_p (ksba_cert_t cert);
 int gpgsm_cert_use_verify_p (ksba_cert_t cert);
 int gpgsm_cert_use_decrypt_p (ksba_cert_t cert);
 int gpgsm_cert_use_cert_p (ksba_cert_t cert);
 int gpgsm_cert_use_ocsp_p (ksba_cert_t cert);
 int gpgsm_cert_has_well_known_private_key (ksba_cert_t cert);
 int gpgsm_certs_identical_p (ksba_cert_t cert_a, ksba_cert_t cert_b);
 int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
                                 certlist_t *listaddr, int is_encrypt_to);
 int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
                            certlist_t *listaddr, int is_encrypt_to);
 void gpgsm_release_certlist (certlist_t list);
 
 #define FIND_CERT_ALLOW_AMBIG 1
 #define FIND_CERT_WITH_EPHEM  2
 int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid,
                      ksba_cert_t *r_cert, unsigned int flags);
 
 /*-- keylist.c --*/
 gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names,
                              estream_t fp, unsigned int mode);
 
 /*-- import.c --*/
 int gpgsm_import (ctrl_t ctrl, int in_fd, int reimport_mode);
 int gpgsm_import_files (ctrl_t ctrl, int nfiles, char **files,
                         int (*of)(const char *fname));
 
 /*-- export.c --*/
 void gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream);
 void gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream,
                        int rawmode);
 
 /*-- delete.c --*/
 int gpgsm_delete (ctrl_t ctrl, strlist_t names);
 
 /*-- verify.c --*/
 int gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp);
 
 /*-- sign.c --*/
 int gpgsm_get_default_cert (ctrl_t ctrl, ksba_cert_t *r_cert);
 int gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
                 int data_fd, int detached, estream_t out_fp);
 
 /*-- encrypt.c --*/
 int gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist,
                    int in_fd, estream_t out_fp);
 
 /*-- decrypt.c --*/
 gpg_error_t hash_ecc_cms_shared_info (gcry_md_hd_t hash_hd,
                                       const char *wrap_algo_str,
                                       unsigned int keylen,
                                       const void *ukm, unsigned int ukmlen);
 int gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp);
 
 /*-- certreqgen.c --*/
 int gpgsm_genkey (ctrl_t ctrl, estream_t in_stream, estream_t out_stream);
 
 /*-- certreqgen-ui.c --*/
 void gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t out_stream);
 
 
 /*-- qualified.c --*/
 gpg_error_t gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert,
                                         char *country);
 gpg_error_t gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert);
 gpg_error_t gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert);
 
 /*-- call-agent.c --*/
 int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
                         unsigned char *digest,
                         size_t digestlen,
                         int digestalgo,
                         unsigned char **r_buf, size_t *r_buflen);
 int gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
                       unsigned char *digest, size_t digestlen, int digestalgo,
                       unsigned char **r_buf, size_t *r_buflen);
 int gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
                            ksba_const_sexp_t ciphertext,
                            char **r_buf, size_t *r_buflen);
 int gpgsm_agent_genkey (ctrl_t ctrl,
                         ksba_const_sexp_t keyparms, ksba_sexp_t *r_pubkey);
 int gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
                          ksba_sexp_t *r_pubkey);
 int gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno);
 int gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list);
 int gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
                            struct rootca_flags_s *rootca_flags);
 int gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip);
 int gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert);
 int gpgsm_agent_learn (ctrl_t ctrl);
 int gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc);
 gpg_error_t gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc);
 gpg_error_t gpgsm_agent_send_nop (ctrl_t ctrl);
 gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
                                  char **r_serialno);
 gpg_error_t gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg,
                                         int repeat, char **r_passphrase);
 gpg_error_t gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
                                      void **r_kek, size_t *r_keklen);
 gpg_error_t gpgsm_agent_import_key (ctrl_t ctrl,
                                     const void *key, size_t keylen);
 gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip,
                                     const char *desc,
                                     unsigned char **r_result,
                                     size_t *r_resultlen);
 
 /*-- call-dirmngr.c --*/
 int gpgsm_dirmngr_isvalid (ctrl_t ctrl,
                            ksba_cert_t cert, ksba_cert_t issuer_cert,
                            int use_ocsp);
 int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri,
                           int cache_only,
                           void (*cb)(void*, ksba_cert_t), void *cb_value);
 int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
                                int argc, char **argv);
 
 
 /*-- misc.c --*/
 void setup_pinentry_env (void);
 gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen,
                               int mdalgo,
                               unsigned char **r_newsigval,
                               size_t *r_newsigvallen);
 gcry_sexp_t gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx);
 int gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval,
                                      unsigned int *r_pkalgo_flags);
 
 
 
 #endif /*GPGSM_H*/
diff --git a/sm/server.c b/sm/server.c
index dc1bce246..6503217bc 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -1,1554 +1,1558 @@
 /* server.c - Server mode and main entry point
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
  *               2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <unistd.h>
 
 #include "gpgsm.h"
 #include <assuan.h>
 #include "../common/sysutils.h"
 #include "../common/server-help.h"
 #include "../common/asshelp.h"
 #include "../common/shareddefs.h"
 
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
 
 /* The filepointer for status message used in non-server mode */
 static FILE *statusfp;
 
 /* Data used to assuciate an Assuan context with local server data */
 struct server_local_s {
   assuan_context_t assuan_ctx;
   int message_fd;
   int list_internal;
   int list_external;
   int list_to_output;           /* Write keylistings to the output fd. */
   int enable_audit_log;         /* Use an audit log.  */
   certlist_t recplist;
   certlist_t signerlist;
   certlist_t default_recplist; /* As set by main() - don't release. */
   int allow_pinentry_notify;   /* Set if pinentry notifications should
                                   be passed back to the client. */
   int no_encrypt_to;           /* Local version of option.  */
 };
 
 
 /* Cookie definition for assuan data line output.  */
 static gpgrt_ssize_t data_line_cookie_write (void *cookie,
                                              const void *buffer, size_t size);
 static int data_line_cookie_close (void *cookie);
 static es_cookie_io_functions_t data_line_cookie_functions =
   {
     NULL,
     data_line_cookie_write,
     NULL,
     data_line_cookie_close
   };
 
 
 
 static int command_has_option (const char *cmd, const char *cmdopt);
 
 
 
 
 /* Note that it is sufficient to allocate the target string D as
    long as the source string S, i.e.: strlen(s)+1; */
 static void
 strcpy_escaped_plus (char *d, const char *s)
 {
   while (*s)
     {
       if (*s == '%' && s[1] && s[2])
         {
           s++;
           *d++ = xtoi_2 (s);
           s += 2;
         }
       else if (*s == '+')
         *d++ = ' ', s++;
       else
         *d++ = *s++;
     }
   *d = 0;
 }
 
 
 /* A write handler used by es_fopencookie to write assuan data
    lines.  */
 static gpgrt_ssize_t
 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
 {
   assuan_context_t ctx = cookie;
 
   if (assuan_send_data (ctx, buffer, size))
     {
       gpg_err_set_errno (EIO);
       return -1;
     }
 
   return (gpgrt_ssize_t)size;
 }
 
 static int
 data_line_cookie_close (void *cookie)
 {
   assuan_context_t ctx = cookie;
 
   if (assuan_send_data (ctx, NULL, 0))
     {
       gpg_err_set_errno (EIO);
       return -1;
     }
 
   return 0;
 }
 
 
 static void
 close_message_fd (ctrl_t ctrl)
 {
   if (ctrl->server_local->message_fd != -1)
     {
 #ifdef HAVE_W32CE_SYSTEM
 #warning Is this correct for W32/W32CE?
 #endif
       close (ctrl->server_local->message_fd);
       ctrl->server_local->message_fd = -1;
     }
 }
 
 
 /* Start a new audit session if this has been enabled.  */
 static gpg_error_t
 start_audit_session (ctrl_t ctrl)
 {
   audit_release (ctrl->audit);
   ctrl->audit = NULL;
   if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
     return gpg_error_from_syserror ();
 
   return 0;
 }
 
 
 static gpg_error_t
 option_handler (assuan_context_t ctx, const char *key, const char *value)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
 
   if (!strcmp (key, "putenv"))
     {
       /* Change the session's environment to be used for the
          Pinentry.  Valid values are:
           <NAME>            Delete envvar NAME
           <KEY>=            Set envvar NAME to the empty string
           <KEY>=<VALUE>     Set envvar NAME to VALUE
       */
       err = session_env_putenv (opt.session_env, value);
     }
   else if (!strcmp (key, "display"))
     {
       err = session_env_setenv (opt.session_env, "DISPLAY", value);
     }
   else if (!strcmp (key, "ttyname"))
     {
       err = session_env_setenv (opt.session_env, "GPG_TTY", value);
     }
   else if (!strcmp (key, "ttytype"))
     {
       err = session_env_setenv (opt.session_env, "TERM", value);
     }
   else if (!strcmp (key, "lc-ctype"))
     {
       xfree (opt.lc_ctype);
       opt.lc_ctype = xtrystrdup (value);
       if (!opt.lc_ctype)
         err = gpg_error_from_syserror ();
     }
   else if (!strcmp (key, "lc-messages"))
     {
       xfree (opt.lc_messages);
       opt.lc_messages = xtrystrdup (value);
       if (!opt.lc_messages)
         err = gpg_error_from_syserror ();
     }
   else if (!strcmp (key, "xauthority"))
     {
       err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
     }
   else if (!strcmp (key, "pinentry-user-data"))
     {
       err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
     }
   else if (!strcmp (key, "include-certs"))
     {
       int i = *value? atoi (value) : -1;
       if (ctrl->include_certs < -2)
         err = gpg_error (GPG_ERR_ASS_PARAMETER);
       else
         ctrl->include_certs = i;
     }
   else if (!strcmp (key, "list-mode"))
     {
       int i = *value? atoi (value) : 0;
       if (!i || i == 1) /* default and mode 1 */
         {
           ctrl->server_local->list_internal = 1;
           ctrl->server_local->list_external = 0;
         }
       else if (i == 2)
         {
           ctrl->server_local->list_internal = 0;
           ctrl->server_local->list_external = 1;
         }
       else if (i == 3)
         {
           ctrl->server_local->list_internal = 1;
           ctrl->server_local->list_external = 1;
         }
       else
         err = gpg_error (GPG_ERR_ASS_PARAMETER);
     }
   else if (!strcmp (key, "list-to-output"))
     {
       int i = *value? atoi (value) : 0;
       ctrl->server_local->list_to_output = i;
     }
   else if (!strcmp (key, "with-validation"))
     {
       int i = *value? atoi (value) : 0;
       ctrl->with_validation = i;
     }
   else if (!strcmp (key, "with-secret"))
     {
       int i = *value? atoi (value) : 0;
       ctrl->with_secret = i;
     }
   else if (!strcmp (key, "validation-model"))
     {
       int i = gpgsm_parse_validation_model (value);
       if ( i >= 0 && i <= 2 )
         ctrl->validation_model = i;
       else
         err = gpg_error (GPG_ERR_ASS_PARAMETER);
     }
   else if (!strcmp (key, "with-key-data"))
     {
       opt.with_key_data = 1;
     }
   else if (!strcmp (key, "enable-audit-log"))
     {
       int i = *value? atoi (value) : 0;
       ctrl->server_local->enable_audit_log = i;
     }
   else if (!strcmp (key, "allow-pinentry-notify"))
     {
       ctrl->server_local->allow_pinentry_notify = 1;
     }
   else if (!strcmp (key, "with-ephemeral-keys"))
     {
       int i = *value? atoi (value) : 0;
       ctrl->with_ephemeral_keys = i;
     }
   else if (!strcmp (key, "no-encrypt-to"))
     {
       ctrl->server_local->no_encrypt_to = 1;
     }
   else if (!strcmp (key, "offline"))
     {
       /* We ignore this option if gpgsm has been started with
          --disable-dirmngr (which also sets offline).  */
       if (!opt.disable_dirmngr)
         {
           int i = *value? !!atoi (value) : 1;
           ctrl->offline = i;
         }
     }
   else if (!strcmp (key, "request-origin"))
     {
       if (!opt.request_origin)
         {
           int i = parse_request_origin (value);
           if (i == -1)
             err = gpg_error (GPG_ERR_INV_VALUE);
           else
             opt.request_origin = i;
         }
     }
+  else if (!strcmp (key, "input-size-hint"))
+    {
+      ctrl->input_size_hint = string_to_u64 (value);
+    }
   else
     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
   return err;
 }
 
 
 static gpg_error_t
 reset_notify (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
   (void) line;
 
   gpgsm_release_certlist (ctrl->server_local->recplist);
   gpgsm_release_certlist (ctrl->server_local->signerlist);
   ctrl->server_local->recplist = NULL;
   ctrl->server_local->signerlist = NULL;
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
   return 0;
 }
 
 
 static gpg_error_t
 input_notify (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
   ctrl->autodetect_encoding = 0;
   ctrl->is_pem = 0;
   ctrl->is_base64 = 0;
   if (strstr (line, "--armor"))
     ctrl->is_pem = 1;
   else if (strstr (line, "--base64"))
     ctrl->is_base64 = 1;
   else if (strstr (line, "--binary"))
     ;
   else
     ctrl->autodetect_encoding = 1;
   return 0;
 }
 
 static gpg_error_t
 output_notify (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
   ctrl->create_pem = 0;
   ctrl->create_base64 = 0;
   if (strstr (line, "--armor"))
     ctrl->create_pem = 1;
   else if (strstr (line, "--base64"))
     ctrl->create_base64 = 1; /* just the raw output */
   return 0;
 }
 
 
 static const char hlp_recipient[] =
   "RECIPIENT <userID>\n"
   "\n"
   "Set the recipient for the encryption.  USERID shall be the\n"
   "internal representation of the key; the server may accept any other\n"
   "way of specification [we will support this].  If this is a valid and\n"
   "trusted recipient the server does respond with OK, otherwise the\n"
   "return is an ERR with the reason why the recipient can't be used,\n"
   "the encryption will then not be done for this recipient.  If the\n"
   "policy is not to encrypt at all if not all recipients are valid, the\n"
   "client has to take care of this.  All RECIPIENT commands are\n"
   "cumulative until a RESET or an successful ENCRYPT command.";
 static gpg_error_t
 cmd_recipient (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc;
 
   if (!ctrl->audit)
     rc = start_audit_session (ctrl);
   else
     rc = 0;
 
   if (!rc)
     rc = gpgsm_add_to_certlist (ctrl, line, 0,
                                 &ctrl->server_local->recplist, 0);
   if (rc)
     {
       gpgsm_status2 (ctrl, STATUS_INV_RECP,
                      get_inv_recpsgnr_code (rc), line, NULL);
     }
 
   return rc;
 }
 
 
 static const char hlp_signer[] =
   "SIGNER <userID>\n"
   "\n"
   "Set the signer's keys for the signature creation.  USERID should\n"
   "be the internal representation of the key; the server may accept any\n"
   "other way of specification [we will support this].  If this is a\n"
   "valid and usable signing key the server does respond with OK,\n"
   "otherwise it returns an ERR with the reason why the key can't be\n"
   "used, the signing will then not be done for this key.  If the policy\n"
   "is not to sign at all if not all signer keys are valid, the client\n"
   "has to take care of this.  All SIGNER commands are cumulative until\n"
   "a RESET but they are *not* reset by an SIGN command because it can\n"
   "be expected that set of signers are used for more than one sign\n"
   "operation.";
 static gpg_error_t
 cmd_signer (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc;
 
   rc = gpgsm_add_to_certlist (ctrl, line, 1,
                               &ctrl->server_local->signerlist, 0);
   if (rc)
     {
       gpgsm_status2 (ctrl, STATUS_INV_SGNR,
                      get_inv_recpsgnr_code (rc), line, NULL);
       /* For compatibility reasons we also issue the old code after the
          new one.  */
       gpgsm_status2 (ctrl, STATUS_INV_RECP,
                      get_inv_recpsgnr_code (rc), line, NULL);
     }
   return rc;
 }
 
 
 static const char hlp_encrypt[] =
   "ENCRYPT \n"
   "\n"
   "Do the actual encryption process. Takes the plaintext from the INPUT\n"
   "command, writes to the ciphertext to the file descriptor set with\n"
   "the OUTPUT command, take the recipients form all the recipients set\n"
   "so far.  If this command fails the clients should try to delete all\n"
   "output currently done or otherwise mark it as invalid.  GPGSM does\n"
   "ensure that there won't be any security problem with leftover data\n"
   "on the output in this case.\n"
   "\n"
   "This command should in general not fail, as all necessary checks\n"
   "have been done while setting the recipients.  The input and output\n"
   "pipes are closed.";
 static gpg_error_t
 cmd_encrypt (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   certlist_t cl;
   int inp_fd, out_fd;
   estream_t out_fp;
   int rc;
 
   (void)line;
 
   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   if (inp_fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   if (out_fd == -1)
     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
 
   out_fp = es_fdopen_nc (out_fd, "w");
   if (!out_fp)
     return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
 
   /* Now add all encrypt-to marked recipients from the default
      list. */
   rc = 0;
   if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
     {
       for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
         if (cl->is_encrypt_to)
           rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
                                            &ctrl->server_local->recplist, 1);
     }
   if (!rc)
     rc = ctrl->audit? 0 : start_audit_session (ctrl);
   if (!rc)
     rc = gpgsm_encrypt (assuan_get_pointer (ctx),
                         ctrl->server_local->recplist,
                         inp_fd, out_fp);
   es_fclose (out_fp);
 
   gpgsm_release_certlist (ctrl->server_local->recplist);
   ctrl->server_local->recplist = NULL;
   /* Close and reset the fd */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
   return rc;
 }
 
 
 static const char hlp_decrypt[] =
   "DECRYPT\n"
   "\n"
   "This performs the decrypt operation after doing some check on the\n"
   "internal state. (e.g. that only needed data has been set).  Because\n"
   "it utilizes the GPG-Agent for the session key decryption, there is\n"
   "no need to ask the client for a protecting passphrase - GPG-Agent\n"
   "does take care of this by requesting this from the user.";
 static gpg_error_t
 cmd_decrypt (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int inp_fd, out_fd;
   estream_t out_fp;
   int rc;
 
   (void)line;
 
   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   if (inp_fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   if (out_fd == -1)
     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
 
   out_fp = es_fdopen_nc (out_fd, "w");
   if (!out_fp)
     return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
 
   rc = start_audit_session (ctrl);
   if (!rc)
     rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
   es_fclose (out_fp);
 
   /* Close and reset the fds. */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 static const char hlp_verify[] =
   "VERIFY\n"
   "\n"
   "This does a verify operation on the message send to the input FD.\n"
   "The result is written out using status lines.  If an output FD was\n"
   "given, the signed text will be written to that.\n"
   "\n"
   "If the signature is a detached one, the server will inquire about\n"
   "the signed material and the client must provide it.";
 static gpg_error_t
 cmd_verify (assuan_context_t ctx, char *line)
 {
   int rc;
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   estream_t out_fp = NULL;
 
   (void)line;
 
   if (fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
 
   if (out_fd != -1)
     {
       out_fp = es_fdopen_nc (out_fd, "w");
       if (!out_fp)
         return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     }
 
   rc = start_audit_session (ctrl);
   if (!rc)
     rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
                        ctrl->server_local->message_fd, out_fp);
   es_fclose (out_fp);
 
   /* Close and reset the fd.  */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 static const char hlp_sign[] =
   "SIGN [--detached]\n"
   "\n"
   "Sign the data set with the INPUT command and write it to the sink\n"
   "set by OUTPUT.  With \"--detached\", a detached signature is\n"
   "created (surprise).";
 static gpg_error_t
 cmd_sign (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int inp_fd, out_fd;
   estream_t out_fp;
   int detached;
   int rc;
 
   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   if (inp_fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   if (out_fd == -1)
     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
 
   detached = has_option (line, "--detached");
 
   out_fp = es_fdopen_nc (out_fd, "w");
   if (!out_fp)
     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
 
   rc = start_audit_session (ctrl);
   if (!rc)
     rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
                      inp_fd, detached, out_fp);
   es_fclose (out_fp);
 
   /* close and reset the fd */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 static const char hlp_import[] =
   "IMPORT [--re-import]\n"
   "\n"
   "Import the certificates read form the input-fd, return status\n"
   "message for each imported one.  The import checks the validity of\n"
   "the certificate but not of the entire chain.  It is possible to\n"
   "import expired certificates.\n"
   "\n"
   "With the option --re-import the input data is expected to a be a LF\n"
   "separated list of fingerprints.  The command will re-import these\n"
   "certificates, meaning that they are made permanent by removing\n"
   "their ephemeral flag.";
 static gpg_error_t
 cmd_import (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc;
   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   int reimport = has_option (line, "--re-import");
 
   (void)line;
 
   if (fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
 
   rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
 
   /* close and reset the fd */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 static const char hlp_export[] =
   "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
   "\n"
   "Export the certificates selected by PATTERN.  With --data the output\n"
   "is returned using Assuan D lines; the default is to use the sink given\n"
   "by the last \"OUTPUT\" command.  The options --armor or --base64 encode \n"
   "the output using the PEM respective a plain base-64 format; the default\n"
   "is a binary format which is only suitable for a single certificate.\n"
   "With --secret the secret key is exported using the PKCS#8 format,\n"
   "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
 static gpg_error_t
 cmd_export (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   char *p;
   strlist_t list, sl;
   int use_data;
   int opt_secret;
   int opt_raw = 0;
   int opt_pkcs12 = 0;
 
   use_data = has_option (line, "--data");
   if (use_data)
     {
       /* We need to override any possible setting done by an OUTPUT command. */
       ctrl->create_pem = has_option (line, "--armor");
       ctrl->create_base64 = has_option (line, "--base64");
     }
   opt_secret = has_option (line, "--secret");
   if (opt_secret)
     {
       opt_raw = has_option (line, "--raw");
       opt_pkcs12 = has_option (line, "--pkcs12");
     }
 
   line = skip_options (line);
 
   /* Break the line down into an strlist_t. */
   list = NULL;
   for (p=line; *p; line = p)
     {
       while (*p && *p != ' ')
         p++;
       if (*p)
         *p++ = 0;
       if (*line)
         {
           sl = xtrymalloc (sizeof *sl + strlen (line));
           if (!sl)
             {
               free_strlist (list);
               return out_of_core ();
             }
           sl->flags = 0;
           strcpy_escaped_plus (sl->d, line);
           sl->next = list;
           list = sl;
         }
     }
 
   if (opt_secret)
     {
       if (!list)
         return set_error (GPG_ERR_NO_DATA, "No key given");
       if (!*list->d)
         {
           free_strlist (list);
           return set_error (GPG_ERR_NO_DATA, "No key given");
         }
       if (list->next)
         return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
   }
 
   if (use_data)
     {
       estream_t stream;
 
       stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
       if (!stream)
         {
           free_strlist (list);
           return set_error (GPG_ERR_ASS_GENERAL,
                             "error setting up a data stream");
         }
       if (opt_secret)
         gpgsm_p12_export (ctrl, list->d, stream,
                           opt_raw? 2 : opt_pkcs12 ? 0 : 1);
       else
         gpgsm_export (ctrl, list, stream);
       es_fclose (stream);
     }
   else
     {
       int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
       estream_t out_fp;
 
       if (fd == -1)
         {
           free_strlist (list);
           return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
         }
       out_fp = es_fdopen_nc (fd, "w");
       if (!out_fp)
         {
           free_strlist (list);
           return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
         }
 
       if (opt_secret)
         gpgsm_p12_export (ctrl, list->d, out_fp,
                           opt_raw? 2 : opt_pkcs12 ? 0 : 1);
       else
         gpgsm_export (ctrl, list, out_fp);
       es_fclose (out_fp);
     }
 
   free_strlist (list);
   /* Close and reset the fds. */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
   return 0;
 }
 
 
 
 static const char hlp_delkeys[] =
   "DELKEYS <patterns>\n"
   "\n"
   "Delete the certificates specified by PATTERNS.  Each pattern shall be\n"
   "a percent-plus escaped certificate specification.  Usually a\n"
   "fingerprint will be used for this.";
 static gpg_error_t
 cmd_delkeys (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   char *p;
   strlist_t list, sl;
   int rc;
 
   /* break the line down into an strlist_t */
   list = NULL;
   for (p=line; *p; line = p)
     {
       while (*p && *p != ' ')
         p++;
       if (*p)
         *p++ = 0;
       if (*line)
         {
           sl = xtrymalloc (sizeof *sl + strlen (line));
           if (!sl)
             {
               free_strlist (list);
               return out_of_core ();
             }
           sl->flags = 0;
           strcpy_escaped_plus (sl->d, line);
           sl->next = list;
           list = sl;
         }
     }
 
   rc = gpgsm_delete (ctrl, list);
   free_strlist (list);
 
   /* close and reset the fd */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 
 static const char hlp_output[] =
   "OUTPUT FD[=<n>]\n"
   "\n"
   "Set the file descriptor to write the output data to N.  If N is not\n"
   "given and the operating system supports file descriptor passing, the\n"
   "file descriptor currently in flight will be used.  See also the\n"
   "\"INPUT\" and \"MESSAGE\" commands.";
 static const char hlp_input[] =
   "INPUT FD[=<n>]\n"
   "\n"
   "Set the file descriptor to read the input data to N.  If N is not\n"
   "given and the operating system supports file descriptor passing, the\n"
   "file descriptor currently in flight will be used.  See also the\n"
   "\"MESSAGE\" and \"OUTPUT\" commands.";
 static const char hlp_message[] =
   "MESSAGE FD[=<n>]\n"
   "\n"
   "Set the file descriptor to read the message for a detached\n"
   "signatures to N.  If N is not given and the operating system\n"
   "supports file descriptor passing, the file descriptor currently in\n"
   "flight will be used.  See also the \"INPUT\" and \"OUTPUT\" commands.";
 static gpg_error_t
 cmd_message (assuan_context_t ctx, char *line)
 {
   int rc;
   gnupg_fd_t sysfd;
   int fd;
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
   rc = assuan_command_parse_fd (ctx, line, &sysfd);
   if (rc)
     return rc;
 
 #ifdef HAVE_W32CE_SYSTEM
   sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0);
   if (sysfd == INVALID_HANDLE_VALUE)
     return set_error (gpg_err_code_from_syserror (),
 		      "rvid conversion failed");
 #endif
 
   fd = translate_sys2libc_fd (sysfd, 0);
   if (fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
   ctrl->server_local->message_fd = fd;
   return 0;
 }
 
 
 
 static const char hlp_listkeys[] =
   "LISTKEYS [<patterns>]\n"
   "LISTSECRETKEYS [<patterns>]\n"
   "DUMPKEYS [<patterns>]\n"
   "DUMPSECRETKEYS [<patterns>]\n"
   "\n"
   "List all certificates or only those specified by PATTERNS.  Each\n"
   "pattern shall be a percent-plus escaped certificate specification.\n"
   "The \"SECRET\" versions of the command filter the output to include\n"
   "only certificates where the secret key is available or a corresponding\n"
   "smartcard has been registered.  The \"DUMP\" versions of the command\n"
   "are only useful for debugging.  The output format is a percent escaped\n"
   "colon delimited listing as described in the manual.\n"
   "\n"
   "These \"OPTION\" command keys effect the output::\n"
   "\n"
   "  \"list-mode\" set to 0: List only local certificates (default).\n"
   "                     1: Ditto.\n"
   "                     2: List only external certificates.\n"
   "                     3: List local and external certificates.\n"
   "\n"
   "  \"with-validation\" set to true: Validate each certificate.\n"
   "\n"
   "  \"with-ephemeral-key\" set to true: Always include ephemeral\n"
   "                                    certificates.\n"
   "\n"
   "  \"list-to-output\" set to true: Write output to the file descriptor\n"
   "                                given by the last \"OUTPUT\" command.";
 static int
 do_listkeys (assuan_context_t ctx, char *line, int mode)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   estream_t fp;
   char *p;
   strlist_t list, sl;
   unsigned int listmode;
   gpg_error_t err;
 
   /* Break the line down into an strlist. */
   list = NULL;
   for (p=line; *p; line = p)
     {
       while (*p && *p != ' ')
         p++;
       if (*p)
         *p++ = 0;
       if (*line)
         {
           sl = xtrymalloc (sizeof *sl + strlen (line));
           if (!sl)
             {
               free_strlist (list);
               return out_of_core ();
             }
           sl->flags = 0;
           strcpy_escaped_plus (sl->d, line);
           sl->next = list;
           list = sl;
         }
     }
 
   if (ctrl->server_local->list_to_output)
     {
       int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
 
       if ( outfd == -1 )
         {
           free_strlist (list);
           return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
         }
       fp = es_fdopen_nc (outfd, "w");
       if (!fp)
         {
           free_strlist (list);
           return set_error (gpg_err_code_from_syserror (),
                             "es_fdopen() failed");
         }
     }
   else
     {
       fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
       if (!fp)
         {
           free_strlist (list);
           return set_error (GPG_ERR_ASS_GENERAL,
                             "error setting up a data stream");
         }
     }
 
   ctrl->with_colons = 1;
   listmode = mode;
   if (ctrl->server_local->list_internal)
     listmode |= (1<<6);
   if (ctrl->server_local->list_external)
     listmode |= (1<<7);
   err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
   free_strlist (list);
   es_fclose (fp);
   if (ctrl->server_local->list_to_output)
     assuan_close_output_fd (ctx);
   return err;
 }
 
 static gpg_error_t
 cmd_listkeys (assuan_context_t ctx, char *line)
 {
   return do_listkeys (ctx, line, 3);
 }
 
 static gpg_error_t
 cmd_dumpkeys (assuan_context_t ctx, char *line)
 {
   return do_listkeys (ctx, line, 259);
 }
 
 static gpg_error_t
 cmd_listsecretkeys (assuan_context_t ctx, char *line)
 {
   return do_listkeys (ctx, line, 2);
 }
 
 static gpg_error_t
 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
 {
   return do_listkeys (ctx, line, 258);
 }
 
 
 
 static const char hlp_genkey[] =
   "GENKEY\n"
   "\n"
   "Read the parameters in native format from the input fd and write a\n"
   "certificate request to the output.";
 static gpg_error_t
 cmd_genkey (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int inp_fd, out_fd;
   estream_t in_stream, out_stream;
   int rc;
 
   (void)line;
 
   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
   if (inp_fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
   if (out_fd == -1)
     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
 
   in_stream = es_fdopen_nc (inp_fd, "r");
   if (!in_stream)
     return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
 
   out_stream = es_fdopen_nc (out_fd, "w");
   if (!out_stream)
     {
       es_fclose (in_stream);
       return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     }
   rc = gpgsm_genkey (ctrl, in_stream, out_stream);
   es_fclose (out_stream);
   es_fclose (in_stream);
 
   /* close and reset the fds */
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   return rc;
 }
 
 
 
 static const char hlp_getauditlog[] =
   "GETAUDITLOG [--data] [--html]\n"
   "\n"
   "If --data is used, the output is send using D-lines and not to the\n"
   "file descriptor given by an OUTPUT command.\n"
   "\n"
   "If --html is used the output is formatted as an XHTML block. This is\n"
   "designed to be incorporated into a HTML document.";
 static gpg_error_t
 cmd_getauditlog (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int  out_fd;
   estream_t out_stream;
   int opt_data, opt_html;
   int rc;
 
   opt_data = has_option (line, "--data");
   opt_html = has_option (line, "--html");
   /* Not needed: line = skip_options (line); */
 
   if (!ctrl->audit)
     return gpg_error (GPG_ERR_NO_DATA);
 
   if (opt_data)
     {
       out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
       if (!out_stream)
         return set_error (GPG_ERR_ASS_GENERAL,
                           "error setting up a data stream");
     }
   else
     {
       out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
       if (out_fd == -1)
         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
 
       out_stream = es_fdopen_nc (out_fd, "w");
       if (!out_stream)
         {
           return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
         }
     }
 
   audit_print_result (ctrl->audit, out_stream, opt_html);
   rc = 0;
 
   es_fclose (out_stream);
 
   /* Close and reset the fd. */
   if (!opt_data)
     assuan_close_output_fd (ctx);
   return rc;
 }
 
 static const char hlp_getinfo[] =
   "GETINFO <what>\n"
   "\n"
   "Multipurpose function to return a variety of information.\n"
   "Supported values for WHAT are:\n"
   "\n"
   "  version     - Return the version of the program.\n"
   "  pid         - Return the process id of the server.\n"
   "  agent-check - Return success if the agent is running.\n"
   "  cmd_has_option CMD OPT\n"
   "              - Returns OK if the command CMD implements the option OPT.\n"
   "  offline     - Returns OK if the connection is in offline mode.";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc = 0;
 
   if (!strcmp (line, "version"))
     {
       const char *s = VERSION;
       rc = assuan_send_data (ctx, s, strlen (s));
     }
   else if (!strcmp (line, "pid"))
     {
       char numbuf[50];
 
       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
     }
   else if (!strcmp (line, "agent-check"))
     {
       rc = gpgsm_agent_send_nop (ctrl);
     }
   else if (!strncmp (line, "cmd_has_option", 14)
            && (line[14] == ' ' || line[14] == '\t' || !line[14]))
     {
       char *cmd, *cmdopt;
       line += 14;
       while (*line == ' ' || *line == '\t')
         line++;
       if (!*line)
         rc = gpg_error (GPG_ERR_MISSING_VALUE);
       else
         {
           cmd = line;
           while (*line && (*line != ' ' && *line != '\t'))
             line++;
           if (!*line)
             rc = gpg_error (GPG_ERR_MISSING_VALUE);
           else
             {
               *line++ = 0;
               while (*line == ' ' || *line == '\t')
                 line++;
               if (!*line)
                 rc = gpg_error (GPG_ERR_MISSING_VALUE);
               else
                 {
                   cmdopt = line;
                   if (!command_has_option (cmd, cmdopt))
                     rc = gpg_error (GPG_ERR_FALSE);
                 }
             }
         }
     }
   else if (!strcmp (line, "offline"))
     {
       rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE);
     }
   else
     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
 
   return rc;
 }
 
 
 static const char hlp_passwd[] =
   "PASSWD <userID>\n"
   "\n"
   "Change the passphrase of the secret key for USERID.";
 static gpg_error_t
 cmd_passwd (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
   ksba_cert_t cert = NULL;
   char *grip = NULL;
 
   line = skip_options (line);
 
   err = gpgsm_find_cert (ctrl, line, NULL, &cert, 0);
   if (err)
     ;
   else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
     err = gpg_error (GPG_ERR_INTERNAL);
   else
     {
       char *desc = gpgsm_format_keydesc (cert);
       err = gpgsm_agent_passwd (ctrl, grip, desc);
       xfree (desc);
     }
 
   xfree (grip);
   ksba_cert_release (cert);
 
   return err;
 }
 
 
 
 /* Return true if the command CMD implements the option OPT.  */
 static int
 command_has_option (const char *cmd, const char *cmdopt)
 {
   if (!strcmp (cmd, "IMPORT"))
     {
       if (!strcmp (cmdopt, "re-import"))
         return 1;
     }
 
   return 0;
 }
 
 
 /* Tell the assuan library about our commands */
 static int
 register_commands (assuan_context_t ctx)
 {
   static struct {
     const char *name;
     assuan_handler_t handler;
     const char * const help;
   } table[] = {
     { "RECIPIENT",     cmd_recipient, hlp_recipient },
     { "SIGNER",        cmd_signer,    hlp_signer },
     { "ENCRYPT",       cmd_encrypt,   hlp_encrypt },
     { "DECRYPT",       cmd_decrypt,   hlp_decrypt },
     { "VERIFY",        cmd_verify,    hlp_verify },
     { "SIGN",          cmd_sign,      hlp_sign },
     { "IMPORT",        cmd_import,    hlp_import },
     { "EXPORT",        cmd_export,    hlp_export },
     { "INPUT",         NULL,          hlp_input },
     { "OUTPUT",        NULL,          hlp_output },
     { "MESSAGE",       cmd_message,   hlp_message },
     { "LISTKEYS",      cmd_listkeys,  hlp_listkeys },
     { "DUMPKEYS",      cmd_dumpkeys,  hlp_listkeys },
     { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
     { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
     { "GENKEY",        cmd_genkey,    hlp_genkey },
     { "DELKEYS",       cmd_delkeys,   hlp_delkeys },
     { "GETAUDITLOG",   cmd_getauditlog,    hlp_getauditlog },
     { "GETINFO",       cmd_getinfo,   hlp_getinfo },
     { "PASSWD",        cmd_passwd,    hlp_passwd },
     { NULL }
   };
   int i, rc;
 
   for (i=0; table[i].name; i++)
     {
       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
                                     table[i].help);
       if (rc)
         return rc;
     }
   return 0;
 }
 
 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
    set from the command line or config file.  We only require those
    marked as encrypt-to. */
 void
 gpgsm_server (certlist_t default_recplist)
 {
   int rc;
   assuan_fd_t filedes[2];
   assuan_context_t ctx;
   struct server_control_s ctrl;
   static const char hello[] = ("GNU Privacy Guard's S/M server "
                                VERSION " ready");
 
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
 
   /* We use a pipe based server so that we can work from scripts.
      assuan_init_pipe_server will automagically detect when we are
      called with a socketpair and ignore FILEDES in this case. */
 #ifdef HAVE_W32CE_SYSTEM
   #define SERVER_STDIN es_fileno(es_stdin)
   #define SERVER_STDOUT es_fileno(es_stdout)
 #else
 #define SERVER_STDIN 0
 #define SERVER_STDOUT 1
 #endif
   filedes[0] = assuan_fdopen (SERVER_STDIN);
   filedes[1] = assuan_fdopen (SERVER_STDOUT);
   rc = assuan_new (&ctx);
   if (rc)
     {
       log_error ("failed to allocate assuan context: %s\n",
                  gpg_strerror (rc));
       gpgsm_exit (2);
     }
 
   rc = assuan_init_pipe_server (ctx, filedes);
   if (rc)
     {
       log_error ("failed to initialize the server: %s\n",
                  gpg_strerror (rc));
       gpgsm_exit (2);
     }
   rc = register_commands (ctx);
   if (rc)
     {
       log_error ("failed to the register commands with Assuan: %s\n",
                  gpg_strerror(rc));
       gpgsm_exit (2);
     }
   if (opt.verbose || opt.debug)
     {
       char *tmp;
 
       /* Fixme: Use the really used socket name.  */
       if (asprintf (&tmp,
                     "Home: %s\n"
                     "Config: %s\n"
                     "DirmngrInfo: %s\n"
                     "%s",
                     gnupg_homedir (),
                     opt.config_filename,
                     dirmngr_socket_name (),
                     hello) > 0)
         {
           assuan_set_hello_line (ctx, tmp);
           free (tmp);
         }
     }
   else
     assuan_set_hello_line (ctx, hello);
 
   assuan_register_reset_notify (ctx, reset_notify);
   assuan_register_input_notify (ctx, input_notify);
   assuan_register_output_notify (ctx, output_notify);
   assuan_register_option_handler (ctx, option_handler);
 
   assuan_set_pointer (ctx, &ctrl);
   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
   ctrl.server_local->assuan_ctx = ctx;
   ctrl.server_local->message_fd = -1;
   ctrl.server_local->list_internal = 1;
   ctrl.server_local->list_external = 0;
   ctrl.server_local->default_recplist = default_recplist;
 
   for (;;)
     {
       rc = assuan_accept (ctx);
       if (rc == -1)
         {
           break;
         }
       else if (rc)
         {
           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
           break;
         }
 
       rc = assuan_process (ctx);
       if (rc)
         {
           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
           continue;
         }
     }
 
   gpgsm_release_certlist (ctrl.server_local->recplist);
   ctrl.server_local->recplist = NULL;
   gpgsm_release_certlist (ctrl.server_local->signerlist);
   ctrl.server_local->signerlist = NULL;
   xfree (ctrl.server_local);
 
   audit_release (ctrl.audit);
   ctrl.audit = NULL;
 
   assuan_release (ctx);
 }
 
 
 
 gpg_error_t
 gpgsm_status2 (ctrl_t ctrl, int no, ...)
 {
   gpg_error_t err = 0;
   va_list arg_ptr;
   const char *text;
 
   va_start (arg_ptr, no);
 
   if (ctrl->no_server && ctrl->status_fd == -1)
     ; /* No status wanted. */
   else if (ctrl->no_server)
     {
       if (!statusfp)
         {
           if (ctrl->status_fd == 1)
             statusfp = stdout;
           else if (ctrl->status_fd == 2)
             statusfp = stderr;
           else
             statusfp = fdopen (ctrl->status_fd, "w");
 
           if (!statusfp)
             {
               log_fatal ("can't open fd %d for status output: %s\n",
                          ctrl->status_fd, strerror(errno));
             }
         }
 
       fputs ("[GNUPG:] ", statusfp);
       fputs (get_status_string (no), statusfp);
 
       while ( (text = va_arg (arg_ptr, const char*) ))
         {
           putc ( ' ', statusfp );
           for (; *text; text++)
             {
               if (*text == '\n')
                 fputs ( "\\n", statusfp );
               else if (*text == '\r')
                 fputs ( "\\r", statusfp );
               else
                 putc ( *(const byte *)text,  statusfp );
             }
         }
       putc ('\n', statusfp);
       if (ferror (statusfp))
         err = gpg_error_from_syserror ();
       else
         {
           fflush (statusfp);
           if (ferror (statusfp))
             err = gpg_error_from_syserror ();
         }
     }
   else
     {
       err = vprint_assuan_status_strings (ctrl->server_local->assuan_ctx,
                                           get_status_string (no), arg_ptr);
     }
 
   va_end (arg_ptr);
   return err;
 }
 
 gpg_error_t
 gpgsm_status (ctrl_t ctrl, int no, const char *text)
 {
   return gpgsm_status2 (ctrl, no, text, NULL);
 }
 
 gpg_error_t
 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
                             gpg_err_code_t ec)
 {
   char buf[30];
 
   snprintf (buf, sizeof buf, "%u", (unsigned int)ec);
   if (text)
     return gpgsm_status2 (ctrl, no, text, buf, NULL);
   else
     return gpgsm_status2 (ctrl, no, buf, NULL);
 }
 
 gpg_error_t
 gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
                          gpg_error_t err)
 {
   char buf[30];
 
   snprintf (buf, sizeof buf, "%u", err);
   if (text)
     return gpgsm_status2 (ctrl, no, text, buf, NULL);
   else
     return gpgsm_status2 (ctrl, no, buf, NULL);
 }
 
 
 /* This callback is used to emit progress status lines.  */
 gpg_error_t
 gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total)
 {
   char buffer[60];
   char units[] = "BKMGTPEZY?";
   int unitidx = 0;
 
   if (total)
     {
       if (current > total)
         current = total;
 
       while (total > 1024*1024)
         {
           total /= 1024;
           current /= 1024;
           unitidx++;
         }
     }
   else
     {
       while (current > 1024*1024)
         {
           current /= 1024;
           unitidx++;
         }
     }
 
   if (unitidx > 9)
     unitidx = 9;
 
   snprintf (buffer, sizeof buffer, "? %lu %lu %c%s",
             (unsigned long)current, (unsigned long)total,
             units[unitidx], unitidx? "iB" : "");
   return gpgsm_status2 (ctrl, STATUS_PROGRESS, "?", buffer, NULL);
 }
 
 
 /* Helper to notify the client about Pinentry events.  Because that
    might disturb some older clients, this is only done when enabled
    via an option.  Returns an gpg error code. */
 gpg_error_t
 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
 {
   if (!ctrl || !ctrl->server_local
       || !ctrl->server_local->allow_pinentry_notify)
     return 0;
   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
 }
diff --git a/sm/sign.c b/sm/sign.c
index 5b442b9a7..0dfd15864 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -1,852 +1,854 @@
 /* sign.c - Sign a message
  * Copyright (C) 2001, 2002, 2003, 2008,
  *               2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
 #include "../common/i18n.h"
 
 
 /* Hash the data and return if something was hashed.  Return -1 on error.  */
 static int
 hash_data (int fd, gcry_md_hd_t md)
 {
   estream_t fp;
   char buffer[4096];
   int nread;
   int rc = 0;
 
   fp = es_fdopen_nc (fd, "rb");
   if (!fp)
     {
       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
       return -1;
     }
 
   do
     {
       nread = es_fread (buffer, 1, DIM(buffer), fp);
       gcry_md_write (md, buffer, nread);
     }
   while (nread);
   if (es_ferror (fp))
     {
       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
       rc = -1;
     }
   es_fclose (fp);
   return rc;
 }
 
 
 static int
 hash_and_copy_data (int fd, gcry_md_hd_t md, ksba_writer_t writer)
 {
   gpg_error_t err;
   estream_t fp;
   char buffer[4096];
   int nread;
   int rc = 0;
   int any = 0;
 
   fp = es_fdopen_nc (fd, "rb");
   if (!fp)
     {
       gpg_error_t tmperr = gpg_error_from_syserror ();
       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
       return tmperr;
     }
 
   do
     {
       nread = es_fread (buffer, 1, DIM(buffer), fp);
       if (nread)
         {
           any = 1;
           gcry_md_write (md, buffer, nread);
           err = ksba_writer_write_octet_string (writer, buffer, nread, 0);
           if (err)
             {
               log_error ("write failed: %s\n", gpg_strerror (err));
               rc = err;
             }
         }
     }
   while (nread && !rc);
   if (es_ferror (fp))
     {
       rc = gpg_error_from_syserror ();
       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
     }
   es_fclose (fp);
   if (!any)
     {
       /* We can't allow signing an empty message because it does not
          make much sense and more seriously, ksba_cms_build has
          already written the tag for data and now expects an octet
          string and an octet string of size 0 is illegal.  */
       log_error ("cannot sign an empty message\n");
       rc = gpg_error (GPG_ERR_NO_DATA);
     }
   if (!rc)
     {
       err = ksba_writer_write_octet_string (writer, NULL, 0, 1);
       if (err)
         {
           log_error ("write failed: %s\n", gpg_strerror (err));
           rc = err;
         }
     }
 
   return rc;
 }
 
 
 /* Get the default certificate which is defined as the first
    certificate capable of signing returned by the keyDB and has a
    secret key available. */
 int
 gpgsm_get_default_cert (ctrl_t ctrl, ksba_cert_t *r_cert)
 {
   KEYDB_HANDLE hd;
   ksba_cert_t cert = NULL;
   int rc;
   char *p;
 
   hd = keydb_new ();
   if (!hd)
     return gpg_error (GPG_ERR_GENERAL);
   rc = keydb_search_first (ctrl, hd);
   if (rc)
     {
       keydb_release (hd);
       return rc;
     }
 
   do
     {
       rc = keydb_get_cert (hd, &cert);
       if (rc)
         {
           log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
           keydb_release (hd);
           return rc;
         }
 
       if (!gpgsm_cert_use_sign_p (cert, 1))
         {
           p = gpgsm_get_keygrip_hexstring (cert);
           if (p)
             {
               if (!gpgsm_agent_havekey (ctrl, p))
                 {
                   xfree (p);
                   keydb_release (hd);
                   *r_cert = cert;
                   return 0; /* got it */
                 }
               xfree (p);
             }
         }
 
       ksba_cert_release (cert);
       cert = NULL;
     }
   while (!(rc = keydb_search_next (ctrl, hd)));
   if (rc && rc != -1)
     log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc));
 
   ksba_cert_release (cert);
   keydb_release (hd);
   return rc;
 }
 
 
 static ksba_cert_t
 get_default_signer (ctrl_t ctrl)
 {
   KEYDB_SEARCH_DESC desc;
   ksba_cert_t cert = NULL;
   KEYDB_HANDLE kh = NULL;
   int rc;
 
   if (!opt.local_user)
     {
       rc = gpgsm_get_default_cert (ctrl, &cert);
       if (rc)
         {
           if (rc != -1)
             log_debug ("failed to find default certificate: %s\n",
                        gpg_strerror (rc));
           return NULL;
         }
       return cert;
     }
 
   rc = classify_user_id (opt.local_user, &desc, 0);
   if (rc)
     {
       log_error ("failed to find default signer: %s\n", gpg_strerror (rc));
       return NULL;
     }
 
   kh = keydb_new ();
   if (!kh)
     return NULL;
 
   rc = keydb_search (ctrl, kh, &desc, 1);
   if (rc)
     {
       log_debug ("failed to find default certificate: rc=%d\n", rc);
     }
   else
     {
       rc = keydb_get_cert (kh, &cert);
       if (rc)
         {
           log_debug ("failed to get cert: rc=%d\n", rc);
         }
     }
 
   keydb_release (kh);
   return cert;
 }
 
 /* Depending on the options in CTRL add the certificate CERT as well as
    other certificate up in the chain to the Root-CA to the CMS
    object. */
 static int
 add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert)
 {
   gpg_error_t err;
   int rc = 0;
   ksba_cert_t next = NULL;
   int n;
   int not_root = 0;
 
   ksba_cert_ref (cert);
 
   n = ctrl->include_certs;
   log_debug ("adding certificates at level %d\n", n);
   if (n == -2)
     {
       not_root = 1;
       n = -1;
     }
   if (n < 0 || n > 50)
     n = 50; /* We better apply an upper bound */
 
   /* First add my own certificate unless we don't want any certificate
      included at all. */
   if (n)
     {
       if (not_root && gpgsm_is_root_cert (cert))
         err = 0;
       else
         err = ksba_cms_add_cert (cms, cert);
       if (err)
         goto ksba_failure;
       if (n>0)
         n--;
     }
   /* Walk the chain to include all other certificates.  Note that a -1
      used for N makes sure that there is no limit and all certs get
      included. */
   while ( n-- && !(rc = gpgsm_walk_cert_chain (ctrl, cert, &next)) )
     {
       if (not_root && gpgsm_is_root_cert (next))
         err = 0;
       else
         err = ksba_cms_add_cert (cms, next);
       ksba_cert_release (cert);
       cert = next; next = NULL;
       if (err)
         goto ksba_failure;
     }
   ksba_cert_release (cert);
 
   return gpg_err_code (rc) == GPG_ERR_NOT_FOUND? 0 : rc;
 
  ksba_failure:
   ksba_cert_release (cert);
   log_error ("ksba_cms_add_cert failed: %s\n", gpg_strerror (err));
   return err;
 }
 
 
 
 
 /* Perform a sign operation.
 
    Sign the data received on DATA-FD in embedded mode or in detached
    mode when DETACHED is true.  Write the signature to OUT_FP.  The
    keys used to sign are taken from SIGNERLIST or the default one will
    be used if the value of this argument is NULL. */
 int
 gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
             int data_fd, int detached, estream_t out_fp)
 {
   int i, rc;
   gpg_error_t err;
   gnupg_ksba_io_t b64writer = NULL;
   ksba_writer_t writer;
   ksba_cms_t cms = NULL;
   ksba_stop_reason_t stopreason;
   KEYDB_HANDLE kh = NULL;
   gcry_md_hd_t data_md = NULL;
   int signer;
   const char *algoid;
   int algo;
   ksba_isotime_t signed_at;
   certlist_t cl;
   int release_signerlist = 0;
 
   audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN);
 
   kh = keydb_new ();
   if (!kh)
     {
       log_error (_("failed to allocate keyDB handle\n"));
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
   if (!gnupg_rng_is_compliant (opt.compliance))
     {
       rc = gpg_error (GPG_ERR_FORBIDDEN);
       log_error (_("%s is not compliant with %s mode\n"),
                  "RNG",
                  gnupg_compliance_option_string (opt.compliance));
       gpgsm_status_with_error (ctrl, STATUS_ERROR,
                                "random-compliance", rc);
       goto leave;
     }
 
   ctrl->pem_name = "SIGNED MESSAGE";
   rc = gnupg_ksba_create_writer
     (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
                   | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
      ctrl->pem_name, out_fp, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
+  if (ctrl->input_size_hint)
+    gnupg_ksba_set_total (b64writer, ctrl->input_size_hint);
 
   err = ksba_cms_new (&cms);
   if (err)
     {
       rc = err;
       goto leave;
     }
 
   err = ksba_cms_set_reader_writer (cms, NULL, writer);
   if (err)
     {
       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
                  gpg_strerror (err));
       rc = err;
       goto leave;
     }
 
   /* We are going to create signed data with data as encap. content */
   err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA);
   if (!err)
     err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
   if (err)
     {
       log_debug ("ksba_cms_set_content_type failed: %s\n",
                  gpg_strerror (err));
       rc = err;
       goto leave;
     }
 
   /* If no list of signers is given, use the default certificate. */
   if (!signerlist)
     {
       ksba_cert_t cert = get_default_signer (ctrl);
       if (!cert)
         {
           log_error ("no default signer found\n");
           gpgsm_status2 (ctrl, STATUS_INV_SGNR,
                          get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
           rc = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
 
       /* Although we don't check for ambiguous specification we will
          check that the signer's certificate is usable and valid.  */
       rc = gpgsm_cert_use_sign_p (cert, 0);
       if (!rc)
         rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
       if (rc)
         {
           char *tmpfpr;
 
           tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
           gpgsm_status2 (ctrl, STATUS_INV_SGNR,
                          get_inv_recpsgnr_code (rc), tmpfpr, NULL);
           xfree (tmpfpr);
           goto leave;
         }
 
       /* That one is fine - create signerlist. */
       signerlist = xtrycalloc (1, sizeof *signerlist);
       if (!signerlist)
         {
           rc = out_of_core ();
           ksba_cert_release (cert);
           goto leave;
         }
       signerlist->cert = cert;
       release_signerlist = 1;
     }
 
 
   /* Figure out the hash algorithm to use. We do not want to use the
      one for the certificate but if possible an OID for the plain
      algorithm.  */
   if (opt.forced_digest_algo && opt.verbose)
     log_info ("user requested hash algorithm %d\n", opt.forced_digest_algo);
   for (i=0, cl=signerlist; cl; cl = cl->next, i++)
     {
       const char *oid;
       unsigned int nbits;
       int pk_algo;
 
       pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
       cl->pk_algo = pk_algo;
 
       if (opt.forced_digest_algo)
         {
           oid = NULL;
           cl->hash_algo = opt.forced_digest_algo;
         }
       else
         {
           if (pk_algo == GCRY_PK_ECC)
             {
               /* Map the Curve to a corresponding hash algo.  */
               if (nbits <= 256)
                 oid = "2.16.840.1.101.3.4.2.1"; /* sha256 */
               else if (nbits <= 384)
                 oid = "2.16.840.1.101.3.4.2.2"; /* sha384 */
               else
                 oid = "2.16.840.1.101.3.4.2.3"; /* sha512 */
             }
           else
             {
               /* For RSA we reuse the hash algo used by the certificate.  */
               oid = ksba_cert_get_digest_algo (cl->cert);
             }
           cl->hash_algo = oid ? gcry_md_map_name (oid) : 0;
         }
       switch (cl->hash_algo)
         {
         case GCRY_MD_SHA1:   oid = "1.3.14.3.2.26"; break;
         case GCRY_MD_RMD160: oid = "1.3.36.3.2.1"; break;
         case GCRY_MD_SHA224: oid = "2.16.840.1.101.3.4.2.4"; break;
         case GCRY_MD_SHA256: oid = "2.16.840.1.101.3.4.2.1"; break;
         case GCRY_MD_SHA384: oid = "2.16.840.1.101.3.4.2.2"; break;
         case GCRY_MD_SHA512: oid = "2.16.840.1.101.3.4.2.3"; break;
 
         case GCRY_MD_MD5:  /* We don't want to use MD5.  */
         case 0:            /* No algorithm found in cert.  */
         default:           /* Other algorithms.  */
           log_info (_("hash algorithm %d (%s) for signer %d not supported;"
                       " using %s\n"),
                     cl->hash_algo, oid? oid: "?", i,
                     gcry_md_algo_name (GCRY_MD_SHA1));
           cl->hash_algo = GCRY_MD_SHA1;
           oid = "1.3.14.3.2.26";
           break;
         }
       cl->hash_algo_oid = oid;
 
       /* Check compliance.  */
       if (! gnupg_digest_is_allowed (opt.compliance, 1, cl->hash_algo))
         {
           log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
                      gcry_md_algo_name (cl->hash_algo),
                      gnupg_compliance_option_string (opt.compliance));
           err = gpg_error (GPG_ERR_DIGEST_ALGO);
           goto leave;
         }
 
       if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
                                 NULL, nbits, NULL))
         {
           char  kidstr[10+1];
 
           snprintf (kidstr, sizeof kidstr, "0x%08lX",
                     gpgsm_get_short_fingerprint (cl->cert, NULL));
           log_error (_("key %s may not be used for signing in %s mode\n"),
                      kidstr,
                      gnupg_compliance_option_string (opt.compliance));
           err = gpg_error (GPG_ERR_PUBKEY_ALGO);
           goto leave;
         }
     }
 
   if (opt.verbose > 1 || opt.debug)
     {
       for (i=0, cl=signerlist; cl; cl = cl->next, i++)
         log_info (_("hash algorithm used for signer %d: %s (%s)\n"),
                   i, gcry_md_algo_name (cl->hash_algo), cl->hash_algo_oid);
     }
 
 
   /* Gather certificates of signers and store them in the CMS object. */
   for (cl=signerlist; cl; cl = cl->next)
     {
       rc = gpgsm_cert_use_sign_p (cl->cert, 0);
       if (rc)
         goto leave;
 
       err = ksba_cms_add_signer (cms, cl->cert);
       if (err)
         {
           log_error ("ksba_cms_add_signer failed: %s\n", gpg_strerror (err));
           rc = err;
           goto leave;
         }
       rc = add_certificate_list (ctrl, cms, cl->cert);
       if (rc)
         {
           log_error ("failed to store list of certificates: %s\n",
                      gpg_strerror(rc));
           goto leave;
         }
       /* Set the hash algorithm we are going to use */
       err = ksba_cms_add_digest_algo (cms, cl->hash_algo_oid);
       if (err)
         {
           log_debug ("ksba_cms_add_digest_algo failed: %s\n",
                      gpg_strerror (err));
           rc = err;
           goto leave;
         }
     }
 
 
   /* Check whether one of the certificates is qualified.  Note that we
      already validated the certificate and thus the user data stored
      flag must be available. */
   if (!opt.no_chain_validation)
     {
       for (cl=signerlist; cl; cl = cl->next)
         {
           size_t buflen;
           char buffer[1];
 
           err = ksba_cert_get_user_data (cl->cert, "is_qualified",
                                          &buffer, sizeof (buffer), &buflen);
           if (err || !buflen)
             {
               log_error (_("checking for qualified certificate failed: %s\n"),
                          gpg_strerror (err));
               rc = err;
               goto leave;
             }
           if (*buffer)
             err = gpgsm_qualified_consent (ctrl, cl->cert);
           else
             err = gpgsm_not_qualified_warning (ctrl, cl->cert);
           if (err)
             {
               rc = err;
               goto leave;
             }
         }
     }
 
   /* Prepare hashing (actually we are figuring out what we have set
      above). */
   rc = gcry_md_open (&data_md, 0, 0);
   if (rc)
     {
       log_error ("md_open failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   if (DBG_HASHING)
     gcry_md_debug (data_md, "sign.data");
 
   for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
     {
       algo = gcry_md_map_name (algoid);
       if (!algo)
         {
           log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?");
           rc = gpg_error (GPG_ERR_BUG);
           goto leave;
         }
       gcry_md_enable (data_md, algo);
       audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
     }
 
   audit_log (ctrl->audit, AUDIT_SETUP_READY);
 
   if (detached)
     { /* We hash the data right now so that we can store the message
          digest.  ksba_cms_build() takes this as an flag that detached
          data is expected. */
       unsigned char *digest;
       size_t digest_len;
 
       if (!hash_data (data_fd, data_md))
         audit_log (ctrl->audit, AUDIT_GOT_DATA);
       for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
         {
           digest = gcry_md_read (data_md, cl->hash_algo);
           digest_len = gcry_md_get_algo_dlen (cl->hash_algo);
           if ( !digest || !digest_len )
             {
               log_error ("problem getting the hash of the data\n");
               rc = gpg_error (GPG_ERR_BUG);
               goto leave;
             }
           err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
           if (err)
             {
               log_error ("ksba_cms_set_message_digest failed: %s\n",
                          gpg_strerror (err));
               rc = err;
               goto leave;
             }
         }
     }
 
   gnupg_get_isotime (signed_at);
   for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
     {
       err = ksba_cms_set_signing_time (cms, signer, signed_at);
       if (err)
         {
           log_error ("ksba_cms_set_signing_time failed: %s\n",
                      gpg_strerror (err));
           rc = err;
           goto leave;
         }
     }
 
   /* We need to write at least a minimal list of our capabilities to
    * try to convince some MUAs to use 3DES and not the crippled
    * RC2. Our list is:
    *
    *   aes256-CBC
    *   aes128-CBC
    *   des-EDE3-CBC
    */
   err = ksba_cms_add_smime_capability (cms, "2.16.840.1.101.3.4.1.42", NULL,0);
   if (!err)
     err = ksba_cms_add_smime_capability (cms, "2.16.840.1.101.3.4.1.2", NULL,0);
   if (!err)
     err = ksba_cms_add_smime_capability (cms, "1.2.840.113549.3.7", NULL, 0);
   if (err)
     {
       log_error ("ksba_cms_add_smime_capability failed: %s\n",
                  gpg_strerror (err));
       goto leave;
     }
 
 
   /* Main building loop. */
   do
     {
       err = ksba_cms_build (cms, &stopreason);
       if (err)
         {
           log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
           rc = err;
           goto leave;
         }
 
       if (stopreason == KSBA_SR_BEGIN_DATA)
         {
           /* Hash the data and store the message digest. */
           unsigned char *digest;
           size_t digest_len;
 
           assert (!detached);
 
           rc = hash_and_copy_data (data_fd, data_md, writer);
           if (rc)
             goto leave;
           audit_log (ctrl->audit, AUDIT_GOT_DATA);
           for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
             {
               digest = gcry_md_read (data_md, cl->hash_algo);
               digest_len = gcry_md_get_algo_dlen (cl->hash_algo);
               if ( !digest || !digest_len )
                 {
                   log_error ("problem getting the hash of the data\n");
                   rc = gpg_error (GPG_ERR_BUG);
                   goto leave;
                 }
               err = ksba_cms_set_message_digest (cms, signer,
                                                  digest, digest_len);
               if (err)
                 {
                   log_error ("ksba_cms_set_message_digest failed: %s\n",
                              gpg_strerror (err));
                   rc = err;
                   goto leave;
                 }
             }
         }
       else if (stopreason == KSBA_SR_NEED_SIG)
         {
           /* Compute the signature for all signers.  */
           gcry_md_hd_t md;
 
           rc = gcry_md_open (&md, 0, 0);
           if (rc)
             {
               log_error ("md_open failed: %s\n", gpg_strerror (rc));
               goto leave;
             }
           if (DBG_HASHING)
             gcry_md_debug (md, "sign.attr");
           ksba_cms_set_hash_function (cms, HASH_FNC, md);
           for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
             {
               unsigned char *sigval = NULL;
               char *buf, *fpr;
 
               audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);
               if (signer)
                 gcry_md_reset (md);
               {
                 certlist_t cl_tmp;
 
                 for (cl_tmp=signerlist; cl_tmp; cl_tmp = cl_tmp->next)
                   {
                     gcry_md_enable (md, cl_tmp->hash_algo);
                     audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO,
                                  cl_tmp->hash_algo);
                   }
               }
 
               rc = ksba_cms_hash_signed_attrs (cms, signer);
               if (rc)
                 {
                   log_debug ("hashing signed attrs failed: %s\n",
                              gpg_strerror (rc));
                   gcry_md_close (md);
                   goto leave;
                 }
 
               rc = gpgsm_create_cms_signature (ctrl, cl->cert,
                                                md, cl->hash_algo, &sigval);
               if (rc)
                 {
                   audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, rc);
                   gcry_md_close (md);
                   goto leave;
                 }
 
               err = ksba_cms_set_sig_val (cms, signer, sigval);
               xfree (sigval);
               if (err)
                 {
                   audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err);
                   log_error ("failed to store the signature: %s\n",
                              gpg_strerror (err));
                   rc = err;
                   gcry_md_close (md);
                   goto leave;
                 }
 
               /* write a status message */
               fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1);
               if (!fpr)
                 {
                   rc = gpg_error (GPG_ERR_ENOMEM);
                   gcry_md_close (md);
                   goto leave;
                 }
               rc = 0;
               if (opt.verbose)
                 {
                   char *pkalgostr = gpgsm_pubkey_algo_string (cl->cert, NULL);
                   log_info (_("%s/%s signature using %s key %s\n"),
                             pubkey_algo_to_string (cl->pk_algo),
                             gcry_md_algo_name (cl->hash_algo),
                             pkalgostr, fpr);
                   xfree (pkalgostr);
                 }
               buf = xtryasprintf ("%c %d %d 00 %s %s",
                                   detached? 'D':'S',
                                   cl->pk_algo,
                                   cl->hash_algo,
                                   signed_at,
                                   fpr);
               if (!buf)
                 rc = gpg_error_from_syserror ();
               xfree (fpr);
               if (rc)
                 {
                   gcry_md_close (md);
                   goto leave;
                 }
               gpgsm_status (ctrl, STATUS_SIG_CREATED, buf);
               xfree (buf);
               audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, 0);
             }
           gcry_md_close (md);
         }
     }
   while (stopreason != KSBA_SR_READY);
 
   rc = gnupg_ksba_finish_writer (b64writer);
   if (rc)
     {
       log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   audit_log (ctrl->audit, AUDIT_SIGNING_DONE);
   log_info ("signature created\n");
 
  leave:
   if (rc)
     log_error ("error creating signature: %s <%s>\n",
                gpg_strerror (rc), gpg_strsource (rc) );
   if (release_signerlist)
     gpgsm_release_certlist (signerlist);
   ksba_cms_release (cms);
   gnupg_ksba_destroy_writer (b64writer);
   keydb_release (kh);
   gcry_md_close (data_md);
   return rc;
 }
diff --git a/sm/verify.c b/sm/verify.c
index 8fc073c2f..6840ed16b 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -1,748 +1,750 @@
 /* verify.c - Verify a messages signature
  * Copyright (C) 2001, 2002, 2003, 2007,
  *               2010 Free Software Foundation, Inc.
  * Copyright (C) 2001-2019 Werner Koch
  * Copyright (C) 2015-2020 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
 #include "../common/i18n.h"
 #include "../common/compliance.h"
 
 static char *
 strtimestamp_r (ksba_isotime_t atime)
 {
   char *buffer = xmalloc (15);
 
   if (!atime || !*atime)
     strcpy (buffer, "none");
   else
     sprintf (buffer, "%.4s-%.2s-%.2s", atime, atime+4, atime+6);
   return buffer;
 }
 
 
 
 /* Hash the data for a detached signature.  Returns 0 on success.  */
 static gpg_error_t
 hash_data (int fd, gcry_md_hd_t md)
 {
   gpg_error_t err = 0;
   estream_t fp;
   char buffer[4096];
   int nread;
 
   fp = es_fdopen_nc (fd, "rb");
   if (!fp)
     {
       err = gpg_error_from_syserror ();
       log_error ("fdopen(%d) failed: %s\n", fd, gpg_strerror (err));
       return err;
     }
 
   do
     {
       nread = es_fread (buffer, 1, DIM(buffer), fp);
       gcry_md_write (md, buffer, nread);
     }
   while (nread);
   if (es_ferror (fp))
     {
       err = gpg_error_from_syserror ();
       log_error ("read error on fd %d: %s\n", fd, gpg_strerror (err));
     }
   es_fclose (fp);
   return err;
 }
 
 
 
 
 /* Perform a verify operation.  To verify detached signatures, DATA_FD
    must be different than -1.  With OUT_FP given and a non-detached
    signature, the signed material is written to that stream.  */
 int
 gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
 {
   int i, rc;
   gnupg_ksba_io_t b64reader = NULL;
   gnupg_ksba_io_t b64writer = NULL;
   ksba_reader_t reader;
   ksba_writer_t writer = NULL;
   ksba_cms_t cms = NULL;
   ksba_stop_reason_t stopreason;
   ksba_cert_t cert;
   KEYDB_HANDLE kh;
   gcry_md_hd_t data_md = NULL;
   int signer;
   const char *algoid;
   int algo;
   int is_detached;
   estream_t in_fp = NULL;
   char *p;
 
   audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);
 
   kh = keydb_new ();
   if (!kh)
     {
       log_error (_("failed to allocate keyDB handle\n"));
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
 
   in_fp = es_fdopen_nc (in_fd, "rb");
   if (!in_fp)
     {
       rc = gpg_error_from_syserror ();
       log_error ("fdopen() failed: %s\n", strerror (errno));
       goto leave;
     }
 
   rc = gnupg_ksba_create_reader
     (&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
                   | (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
                   | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)),
      in_fp, &reader);
   if (rc)
     {
       log_error ("can't create reader: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   if (out_fp)
     {
       rc = gnupg_ksba_create_writer
         (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)
                       | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)),
          ctrl->pem_name, out_fp, &writer);
       if (rc)
         {
           log_error ("can't create writer: %s\n", gpg_strerror (rc));
           goto leave;
         }
     }
 
   gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
+  if (ctrl->input_size_hint)
+    gnupg_ksba_set_total (b64writer, ctrl->input_size_hint);
 
   rc = ksba_cms_new (&cms);
   if (rc)
     goto leave;
 
   rc = ksba_cms_set_reader_writer (cms, reader, writer);
   if (rc)
     {
       log_error ("ksba_cms_set_reader_writer failed: %s\n",
                  gpg_strerror (rc));
       goto leave;
     }
 
   rc = gcry_md_open (&data_md, 0, 0);
   if (rc)
     {
       log_error ("md_open failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   if (DBG_HASHING)
     gcry_md_debug (data_md, "vrfy.data");
 
   audit_log (ctrl->audit, AUDIT_SETUP_READY);
 
   is_detached = 0;
   do
     {
       rc = ksba_cms_parse (cms, &stopreason);
       if (rc)
         {
           log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
 
       if (stopreason == KSBA_SR_NEED_HASH)
         {
           is_detached = 1;
           audit_log (ctrl->audit, AUDIT_DETACHED_SIGNATURE);
           if (opt.verbose)
             log_info ("detached signature\n");
         }
 
       if (stopreason == KSBA_SR_NEED_HASH
           || stopreason == KSBA_SR_BEGIN_DATA)
         {
           audit_log (ctrl->audit, AUDIT_GOT_DATA);
 
           /* We are now able to enable the hash algorithms */
           for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
             {
               algo = gcry_md_map_name (algoid);
               if (!algo)
                 {
                   log_error ("unknown hash algorithm '%s'\n",
                              algoid? algoid:"?");
                   if (algoid
                       && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
                           ||!strcmp (algoid, "1.2.840.113549.2.2")))
                     log_info (_("(this is the MD2 algorithm)\n"));
                   audit_log_s (ctrl->audit, AUDIT_BAD_DATA_HASH_ALGO, algoid);
                 }
               else
                 {
                   if (DBG_X509)
                     log_debug ("enabling hash algorithm %d (%s)\n",
                                algo, algoid? algoid:"");
                   gcry_md_enable (data_md, algo);
                   audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
                 }
             }
           if (opt.extra_digest_algo)
             {
               if (DBG_X509)
                 log_debug ("enabling extra hash algorithm %d\n",
                            opt.extra_digest_algo);
               gcry_md_enable (data_md, opt.extra_digest_algo);
               audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO,
                            opt.extra_digest_algo);
             }
           if (is_detached)
             {
               if (data_fd == -1)
                 {
                   log_info ("detached signature w/o data "
                             "- assuming certs-only\n");
                   audit_log (ctrl->audit, AUDIT_CERT_ONLY_SIG);
                 }
               else
                 audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING,
                               hash_data (data_fd, data_md));
             }
           else
             {
               ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
             }
         }
       else if (stopreason == KSBA_SR_END_DATA)
         { /* The data bas been hashed */
           audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING, 0);
         }
     }
   while (stopreason != KSBA_SR_READY);
 
   if (b64writer)
     {
       rc = gnupg_ksba_finish_writer (b64writer);
       if (rc)
         {
           log_error ("write failed: %s\n", gpg_strerror (rc));
           audit_log_ok (ctrl->audit, AUDIT_WRITE_ERROR, rc);
           goto leave;
         }
     }
 
   if (data_fd != -1 && !is_detached)
     {
       log_error ("data given for a non-detached signature\n");
       rc = gpg_error (GPG_ERR_CONFLICT);
       audit_log (ctrl->audit, AUDIT_USAGE_ERROR);
       goto leave;
     }
 
   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
     {
       /* Fixme: it might be better to check the validity of the
          certificate first before entering it into the DB.  This way
          we would avoid cluttering the DB with invalid
          certificates. */
       audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert,
                       keydb_store_cert (ctrl, cert, 0, NULL));
       ksba_cert_release (cert);
     }
 
   cert = NULL;
   for (signer=0; ; signer++)
     {
       char *issuer = NULL;
       gcry_sexp_t sigval = NULL;
       ksba_isotime_t sigtime, keyexptime;
       ksba_sexp_t serial;
       char *msgdigest = NULL;
       size_t msgdigestlen;
       char *ctattr;
       int sigval_hash_algo;
       int info_pkalgo;
       unsigned int nbits;
       int pkalgo;
       char *pkalgostr = NULL;
       char *pkcurve = NULL;
       char *pkfpr = NULL;
       unsigned int pkalgoflags, verifyflags;
 
       rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
       if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
           && data_fd == -1 && is_detached)
         {
           log_info ("certs-only message accepted\n");
           rc = 0;
           break;
         }
       if (rc)
         {
           if (signer && rc == -1)
             rc = 0;
           break;
         }
 
       gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
       audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);
 
       if (DBG_X509)
         {
           log_debug ("signer %d - issuer: '%s'\n",
                      signer, issuer? issuer:"[NONE]");
           log_debug ("signer %d - serial: ", signer);
           gpgsm_dump_serial (serial);
           log_printf ("\n");
         }
       if (ctrl->audit)
         {
           char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
           audit_log_s (ctrl->audit, AUDIT_SIG_NAME, tmpstr);
           xfree (tmpstr);
         }
 
       rc = ksba_cms_get_signing_time (cms, signer, sigtime);
       if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
         *sigtime = 0;
       else if (rc)
         {
           log_error ("error getting signing time: %s\n", gpg_strerror (rc));
           *sigtime = 0; /* (we can't encode an error in the time string.) */
         }
 
       rc = ksba_cms_get_message_digest (cms, signer,
                                         &msgdigest, &msgdigestlen);
       if (!rc)
         {
           algoid = ksba_cms_get_digest_algo (cms, signer);
           algo = gcry_md_map_name (algoid);
           if (DBG_X509)
             log_debug ("signer %d - digest algo: %d\n", signer, algo);
           if (! gcry_md_is_enabled (data_md, algo))
             {
               log_error ("digest algo %d (%s) has not been enabled\n",
                          algo, algoid?algoid:"");
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "unsupported");
               goto next_signer;
             }
         }
       else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
         {
           assert (!msgdigest);
           rc = 0;
           algoid = NULL;
           algo = 0;
         }
       else /* real error */
         {
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
           break;
         }
 
       rc = ksba_cms_get_sigattr_oids (cms, signer,
                                       "1.2.840.113549.1.9.3", &ctattr);
       if (!rc)
         {
           const char *s;
 
           if (DBG_X509)
             log_debug ("signer %d - content-type attribute: %s",
                        signer, ctattr);
 
           s = ksba_cms_get_content_oid (cms, 1);
           if (!s || strcmp (ctattr, s))
             {
               log_error ("content-type attribute does not match "
                          "actual content-type\n");
               ksba_free (ctattr);
               ctattr = NULL;
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
               goto next_signer;
             }
           ksba_free (ctattr);
           ctattr = NULL;
         }
       else if (rc != -1)
         {
           log_error ("error getting content-type attribute: %s\n",
                      gpg_strerror (rc));
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
           goto next_signer;
         }
       rc = 0;
 
 
       sigval = gpgsm_ksba_cms_get_sig_val (cms, signer);
       if (!sigval)
         {
           log_error ("no signature value available\n");
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
           goto next_signer;
         }
 
       sigval_hash_algo = gpgsm_get_hash_algo_from_sigval (sigval, &pkalgoflags);
       if (DBG_X509)
         {
           log_debug ("signer %d - signature available (sigval hash=%d pkaf=%u)",
                      signer, sigval_hash_algo, pkalgoflags);
         }
       if (!sigval_hash_algo)
         sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */
 
       /* Find the certificate of the signer */
       keydb_search_reset (kh);
       rc = keydb_search_issuer_sn (ctrl, kh, issuer, serial);
       if (rc)
         {
           if (rc == -1)
             {
               log_error ("certificate not found\n");
               rc = gpg_error (GPG_ERR_NO_PUBKEY);
             }
           else
             log_error ("failed to find the certificate: %s\n",
                        gpg_strerror(rc));
           {
             char numbuf[50];
             sprintf (numbuf, "%d", rc);
 
             gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
                            numbuf, NULL);
           }
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "no-cert");
           goto next_signer;
         }
 
       rc = keydb_get_cert (kh, &cert);
       if (rc)
         {
           log_error ("failed to get cert: %s\n", gpg_strerror (rc));
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
           goto next_signer;
         }
 
       pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
       pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
       pkalgo = gpgsm_get_key_algo_info2 (cert, &nbits, &pkcurve);
       /* Remap the ECC algo to the algo we use.  Note that EdDSA has
        * already been mapped.  */
       if (pkalgo == GCRY_PK_ECC)
         pkalgo = GCRY_PK_ECDSA;
 
       log_info (_("Signature made "));
       if (*sigtime)
         {
           /* We take the freedom as noted in RFC3339 to use a space
            * instead of the "T" delimiter between date and time.  We
            * also append a separate UTC instead of a "Z" or "+00:00"
            * suffix because that makes it clear to everyone what kind
            * of time this is.  */
           dump_isotime (sigtime);
           log_printf (" UTC");
         }
       else
         log_printf (_("[date not given]"));
       log_info (_("               using %s key %s\n"), pkalgostr, pkfpr);
       if (opt.verbose)
         {
           log_info (_("algorithm:"));
           log_printf (" %s + %s",
                       pubkey_algo_to_string (pkalgo),
                       gcry_md_algo_name (sigval_hash_algo));
           if (algo != sigval_hash_algo)
             log_printf (" (%s)", gcry_md_algo_name (algo));
           log_printf ("\n");
         }
 
       audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
 
       /* Check compliance.  */
       if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
                                  pkalgo, pkalgoflags, NULL, nbits, NULL))
         {
           char  kidstr[10+1];
 
           snprintf (kidstr, sizeof kidstr, "0x%08lX",
                     gpgsm_get_short_fingerprint (cert, NULL));
           log_error (_("key %s may not be used for signing in %s mode\n"),
                      kidstr,
                      gnupg_compliance_option_string (opt.compliance));
           goto next_signer;
         }
 
       if (!gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
         {
           log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
                      gcry_md_algo_name (sigval_hash_algo),
                      gnupg_compliance_option_string (opt.compliance));
           goto next_signer;
         }
 
       /* Print compliance warning for the key.  */
       if (!opt.quiet
           && !gnupg_pk_is_compliant (opt.compliance, pkalgo, pkalgoflags,
                                      NULL, nbits, pkcurve))
           {
             log_info (_("WARNING: This key is not suitable for signing"
                         " in %s mode\n"),
                       gnupg_compliance_option_string (opt.compliance));
           }
 
       /* Check compliance with CO_DE_VS.  */
       if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags,
                                  NULL, nbits, pkcurve)
           && gnupg_gcrypt_is_compliant (CO_DE_VS)
           && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
         gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
                       gnupg_status_compliance_flag (CO_DE_VS));
       else if (opt.require_compliance
                && opt.compliance == CO_DE_VS)
         {
           log_error (_("operation forced to fail due to"
                        " unfulfilled compliance rules\n"));
           gpgsm_errors_seen = 1;
         }
 
       /* Now we can check the signature.  */
       if (msgdigest)
         { /* Signed attributes are available. */
           gcry_md_hd_t md;
           unsigned char *s;
 
           /* Check that the message digest in the signed attributes
              matches the one we calculated on the data.  */
           s = gcry_md_read (data_md, algo);
           if ( !s || !msgdigestlen
                || gcry_md_get_algo_dlen (algo) != msgdigestlen
                || memcmp (s, msgdigest, msgdigestlen) )
             {
               char *fpr;
 
               log_error (_("invalid signature: message digest attribute "
                            "does not match computed one\n"));
               if (DBG_X509)
                 {
                   if (msgdigest)
                     log_printhex (msgdigest, msgdigestlen, "message:  ");
                   if (s)
                     log_printhex (s, gcry_md_get_algo_dlen (algo),
                                   "computed: ");
                 }
               fpr = gpgsm_fpr_and_name_for_status (cert);
               gpgsm_status (ctrl, STATUS_BADSIG, fpr);
               xfree (fpr);
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
               goto next_signer;
             }
 
           audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, sigval_hash_algo);
           rc = gcry_md_open (&md, sigval_hash_algo, 0);
           if (rc)
             {
               log_error ("md_open failed: %s\n", gpg_strerror (rc));
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
               goto next_signer;
             }
           if (DBG_HASHING)
             gcry_md_debug (md, "vrfy.attr");
 
           ksba_cms_set_hash_function (cms, HASH_FNC, md);
           rc = ksba_cms_hash_signed_attrs (cms, signer);
           if (rc)
             {
               log_error ("hashing signed attrs failed: %s\n",
                          gpg_strerror (rc));
               gcry_md_close (md);
               audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
               goto next_signer;
             }
           rc = gpgsm_check_cms_signature (cert, sigval, md, sigval_hash_algo,
                                           pkalgoflags, &info_pkalgo);
           gcry_md_close (md);
         }
       else
         {
           rc = gpgsm_check_cms_signature (cert, sigval, data_md,
                                           algo, pkalgoflags, &info_pkalgo);
         }
 
       if (rc)
         {
           char *fpr;
 
           log_error ("invalid signature: %s\n", gpg_strerror (rc));
           fpr = gpgsm_fpr_and_name_for_status (cert);
           gpgsm_status (ctrl, STATUS_BADSIG, fpr);
           xfree (fpr);
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
           goto next_signer;
         }
       rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
       if (rc)
         {
           gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
                                       gpg_err_code (rc));
           rc = 0;
         }
 
       if (DBG_X509)
         log_debug ("signature okay - checking certs\n");
       audit_log (ctrl->audit, AUDIT_VALIDATE_CHAIN);
       rc = gpgsm_validate_chain (ctrl, cert,
                                  *sigtime? sigtime : "19700101T000000",
                                  keyexptime, 0,
                                  NULL, 0, &verifyflags);
       {
         char *fpr, *buf, *tstr;
 
         fpr = gpgsm_fpr_and_name_for_status (cert);
         if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
           {
             gpgsm_status (ctrl, STATUS_EXPKEYSIG, fpr);
             rc = 0;
           }
         else
           gpgsm_status (ctrl, STATUS_GOODSIG, fpr);
 
         xfree (fpr);
 
         fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
         tstr = strtimestamp_r (sigtime);
         buf = xasprintf ("%s %s %s %s 0 0 %d %d 00", fpr, tstr,
                          *sigtime? sigtime : "0",
                          *keyexptime? keyexptime : "0",
                          info_pkalgo, algo);
         xfree (tstr);
         xfree (fpr);
         gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
         xfree (buf);
       }
 
       audit_log_ok (ctrl->audit, AUDIT_CHAIN_STATUS, rc);
       if (rc) /* of validate_chain */
         {
           log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
           if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
               || gpg_err_code (rc) == GPG_ERR_BAD_CERT
               || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
               || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
                                         gpg_err_code (rc));
           else
             gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL,
                                         gpg_err_code (rc));
           audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
           goto next_signer;
         }
 
       audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "good");
 
       for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
         {
           log_info (!i? _("Good signature from")
                       : _("                aka"));
           log_printf (" \"");
           gpgsm_es_print_name (log_get_stream (), p);
           log_printf ("\"\n");
           ksba_free (p);
         }
 
       /* Print a note if this is a qualified signature.  */
       {
         size_t qualbuflen;
         char qualbuffer[1];
 
         rc = ksba_cert_get_user_data (cert, "is_qualified", &qualbuffer,
                                       sizeof (qualbuffer), &qualbuflen);
         if (!rc && qualbuflen)
           {
             if (*qualbuffer)
               {
                 log_info (_("This is a qualified signature\n"));
                 if (!opt.qualsig_approval)
                   log_info
                     (_("Note, that this software is not officially approved "
                        "to create or verify such signatures.\n"));
               }
           }
         else if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
           log_error ("get_user_data(is_qualified) failed: %s\n",
                      gpg_strerror (rc));
       }
 
       gpgsm_status (ctrl, STATUS_TRUST_FULLY,
                     (verifyflags & VALIDATE_FLAG_STEED)?
                     "0 steed":
                     (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
                     "0 chain": "0 shell");
 
     next_signer:
       rc = 0;
       xfree (issuer);
       xfree (serial);
       gcry_sexp_release (sigval);
       xfree (msgdigest);
       xfree (pkalgostr);
       xfree (pkcurve);
       xfree (pkfpr);
       ksba_cert_release (cert);
       cert = NULL;
     }
   rc = 0;
 
  leave:
   ksba_cms_release (cms);
   gnupg_ksba_destroy_reader (b64reader);
   gnupg_ksba_destroy_writer (b64writer);
   keydb_release (kh);
   gcry_md_close (data_md);
   es_fclose (in_fp);
 
   if (rc)
     {
       char numbuf[50];
       sprintf (numbuf, "%d", rc );
       gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
                      numbuf, NULL);
     }
 
   return rc;
 }