diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi
index 81af28105..1271994c4 100644
--- a/doc/scdaemon.texi
+++ b/doc/scdaemon.texi
@@ -1,770 +1,776 @@
 @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 SCDAEMON
 @chapter Invoking the SCDAEMON
 @cindex SCDAEMON command options
 @cindex command options
 @cindex options, SCDAEMON command
 
 @manpage scdaemon.1
 @ifset manverb
 .B scdaemon
 \- Smartcard daemon for the GnuPG system
 @end ifset
 
 @mansect synopsis
 @ifset manverb
 .B  scdaemon
 .RB [ \-\-homedir
 .IR dir ]
 .RB [ \-\-options
 .IR file ]
 .RI [ options ]
 .B  \-\-server
 .br
 .B  scdaemon
 .RB [ \-\-homedir
 .IR dir ]
 .RB [ \-\-options
 .IR file ]
 .RI [ options ]
 .B  \-\-daemon
 .RI [ command_line ]
 @end ifset
 
 
 @mansect description
 The @command{scdaemon} is a daemon to manage smartcards.  It is usually
 invoked by @command{gpg-agent} and in general not used directly.
 
 @manpause
 @xref{Option Index}, for an index to @command{scdaemon}'s commands and
 options.
 @mancont
 
 @menu
 * Scdaemon Commands::      List of all commands.
 * Scdaemon Options::       List of all options.
 * Card applications::      Description of card applications.
 * Scdaemon Configuration:: Configuration files.
 * Scdaemon Examples::      Some usage examples.
 * Scdaemon Protocol::      The protocol the daemon uses.
 @end menu
 
 @mansect commands
 
 @node Scdaemon Commands
 @section Commands
 
 Commands are not distinguished from options except for the fact that
 only one command is allowed.
 
 @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 --dump-options
 @opindex dump-options
 Print a list of all available options and commands.  Note that you cannot
 abbreviate this command.
 
 @item --server
 @opindex server
 Run in server mode and wait for commands on the @code{stdin}.  The
 default mode is to create a socket and listen for commands there.
 
 @item --multi-server
 @opindex multi-server
 Run in server mode and wait for commands on the @code{stdin} as well as
 on an additional Unix Domain socket.  The server command @code{GETINFO}
 may be used to get the name of that extra socket.
 
 @item --daemon
 @opindex daemon
 Run the program in the background.  This option is required to prevent
 it from being accidentally running in the background.
 
 @end table
 
 
 @mansect options
 
 @node Scdaemon Options
 @section Option Summary
 
 @table @gnupgtabopt
 
 @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{scdaemon.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 --debug-level @var{level}
 @opindex debug-level
 Select the debug level for investigating problems.  @var{level} may be
 a numeric value or 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.
 
 @quotation Note
 All debugging options are subject to change and thus should not be used
 by any application program.  As the name says, they are only used as
 helpers to debug problems.
 @end quotation
 
 
 @item --debug @var{flags}
 @opindex debug
 This option is only useful for debugging and the behavior may change at
 any time without notice.  FLAGS are bit encoded and may be given in
 usual C-Syntax. The currently defined bits are:
 
 @table @code
 @item 0  (1)
 command I/O
 @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.
 See also option @option{--debug-assuan-log-cats}.
 @item 11 (2048)
 trace APDU I/O to the card.  This may reveal sensitive data.
 @item 12 (4096)
 trace some card reader related function calls.
 @end table
 
 @item --debug-all
 @opindex debug-all
 Same as @code{--debug=0xffffffff}
 
 @item --debug-wait @var{n}
 @opindex debug-wait
 When running in server mode, wait @var{n} seconds before entering the
 actual processing loop and print the pid.  This gives time to attach a
 debugger.
 
 @item --debug-ccid-driver
 @opindex debug-wait
 Enable debug output from the included CCID driver for smartcards.
 Using this option twice will also enable some tracing of the T=1
 protocol.  Note that this option may reveal sensitive data.
 
 @item --debug-disable-ticker
 @opindex debug-disable-ticker
 This option disables all ticker functions like checking for card
 insertions.
 
 @item --debug-allow-core-dump
 @opindex debug-allow-core-dump
 For security reasons we won't create a core dump when the process
 aborts.  For debugging purposes it is sometimes better to allow core
 dump.  This option enables it and also changes the working directory to
 @file{/tmp} when running in @option{--server} mode.
 
 @item --debug-log-tid
 @opindex debug-log-tid
 This option appends a thread ID to the PID in the log output.
 
 @item --debug-assuan-log-cats @var{cats}
 @opindex debug-assuan-log-cats
 @efindex ASSUAN_DEBUG
 Changes the active Libassuan logging categories to @var{cats}.  The
 value for @var{cats} is an unsigned integer given in usual C-Syntax.
 A value of 0 switches to a default category.  If this option is not
 used the categories are taken from the environment variable
 @code{ASSUAN_DEBUG}.  Note that this option has only an effect if the
 Assuan debug flag has also been with the option @option{--debug}.  For
 a list of categories see the Libassuan manual.
 
 @item --no-detach
 @opindex no-detach
 Don't detach the process from the console.  This is mainly useful for
 debugging.
 
 @item --listen-backlog @var{n}
 @opindex listen-backlog
 Set the size of the queue for pending connections.  The default is 64.
 This option has an effect only if @option{--multi-server} is also
 used.
 
 @item --log-file @var{file}
 @opindex log-file
 Append all logging output to @var{file}.  This is very helpful in
 seeing what the agent actually does.  Use @file{socket://} to log to
 socket.
 
+@item --pcsc-shared
+@opindex pcsc-shared
+Use shared mode to access the card via PC/SC.  This is a somewhat
+dangerous option because Scdaemon assumes exclusivbe access to teh
+card and for example caches certain information from the card.  Use
+this option only if you know what you are doing.
 
 @item --pcsc-driver @var{library}
 @opindex pcsc-driver
 Use @var{library} to access the smartcard reader.  The current default
 is @file{libpcsclite.so}.  Instead of using this option you might also
 want to install a symbolic link to the default file name
 (e.g. from @file{libpcsclite.so.1}).
 
 @item --ctapi-driver @var{library}
 @opindex ctapi-driver
 Use @var{library} to access the smartcard reader.  The current default
 is @file{libtowitoko.so}.  Note that the use of this interface is
 deprecated; it may be removed in future releases.
 
 @item --disable-ccid
 @opindex disable-ccid
 Disable the integrated support for CCID compliant readers.  This
 allows falling back to one of the other drivers even if the internal
 CCID driver can handle the reader.  Note, that CCID support is only
 available if libusb was available at build time.
 
 @item --reader-port @var{number_or_string}
 @opindex reader-port
 This option may be used to specify the port of the card terminal.  A
 value of 0 refers to the first serial device; add 32768 to access USB
 devices.  The default is 32768 (first USB device).  PC/SC or CCID
 readers might need a string here; run the program in verbose mode to get
 a list of available readers.  The default is then the first reader
 found.
 
 To get a list of available CCID readers you may use this command:
 @cartouche
 @smallexample
   echo scd getinfo reader_list \
     | gpg-connect-agent --decode | awk '/^D/ @{print $2@}'
 @end smallexample
 @end cartouche
 
 @item --card-timeout @var{n}
 @opindex card-timeout
 If @var{n} is not 0 and no client is actively using the card, the card
 will be powered down after @var{n} seconds.  Powering down the card
 avoids a potential risk of damaging a card when used with certain
 cheap readers.  This also allows applications that are not aware of
 Scdaemon to access the card.  The disadvantage of using a card timeout
 is that accessing the card takes longer and that the user needs to
 enter the PIN again after the next power up.
 
 Note that with the current version of Scdaemon the card is powered
 down immediately at the next timer tick for any value of @var{n} other
 than 0.
 
 @item --enable-pinpad-varlen
 @opindex enable-pinpad-varlen
 Please specify this option when the card reader supports variable
 length input for pinpad (default is no).  For known readers (listed in
 ccid-driver.c and apdu.c), this option is not needed.  Note that if
 your card reader doesn't supports variable length input but you want
 to use it, you need to specify your pinpad request on your card.
 
 
 @item --disable-pinpad
 @opindex disable-pinpad
 Even if a card reader features a pinpad, do not try to use it.
 
 
 @item --deny-admin
 @opindex deny-admin
 @opindex allow-admin
 This option disables the use of admin class commands for card
 applications where this is supported.  Currently we support it for the
 OpenPGP card. This option is useful to inhibit accidental access to
 admin class command which could ultimately lock the card through wrong
 PIN numbers.  Note that GnuPG versions older than 2.0.11 featured an
 @option{--allow-admin} option which was required to use such admin
 commands.  This option has no more effect today because the default is
 now to allow admin commands.
 
 @item --disable-application @var{name}
 @opindex disable-application
 This option disables the use of the card application named
 @var{name}.  This is mainly useful for debugging or if a application
 with lower priority should be used by default.
 
 @end table
 
 All the long options may also be given in the configuration file after
 stripping off the two leading dashes.
 
 
 @mansect card applications
 @node Card applications
 @section Description of card applications
 
 @command{scdaemon} supports the card applications as described below.
 
 @menu
 * OpenPGP Card::          The OpenPGP card application
 * NKS Card::              The Telesec NetKey card application
 * DINSIG Card::           The DINSIG card application
 * PKCS#15 Card::          The PKCS#15 card application
 * Geldkarte Card::        The Geldkarte application
 * SmartCard-HSM::         The SmartCard-HSM application
 * Undefined Card::        The Undefined stub application
 @end menu
 
 @node OpenPGP Card
 @subsection The OpenPGP card application ``openpgp''
 
 This application is currently only used by @command{gpg} but may in
 future also be useful with @command{gpgsm}.  Version 1 and version 2 of
 the card is supported.
 
 @noindent
 The specifications for these cards are available at@*
 @uref{http://g10code.com/docs/openpgp-card-1.0.pdf} and@*
 @uref{http://g10code.com/docs/openpgp-card-2.0.pdf}.
 
 @node NKS Card
 @subsection The Telesec NetKey card ``nks''
 
 This is the main application of the Telesec cards as available in
 Germany.  It is a superset of the German DINSIG card.  The card is
 used by @command{gpgsm}.
 
 @node DINSIG Card
 @subsection The DINSIG card application ``dinsig''
 
 This is an application as described in the German draft standard
 @emph{DIN V 66291-1}.  It is intended to be used by cards supporting
 the German signature law and its bylaws (SigG and SigV).
 
 @node PKCS#15 Card
 @subsection The PKCS#15 card application ``p15''
 
 This is common framework for smart card applications.  It is used by
 @command{gpgsm}.
 
 @node Geldkarte Card
 @subsection The Geldkarte card application ``geldkarte''
 
 This is a simple application to display information of a German
 Geldkarte.  The Geldkarte is a small amount debit card application which
 comes with almost all German banking cards.
 
 @node SmartCard-HSM
 @subsection The SmartCard-HSM card application ``sc-hsm''
 
 This application adds read-only support for keys and certificates
 stored on a @uref{http://www.smartcard-hsm.com, SmartCard-HSM}.
 
 To generate keys and store certificates you may use
 @uref{https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM, OpenSC} or
 the tools from @uref{http://www.openscdp.org, OpenSCDP}.
 
 The SmartCard-HSM cards requires a card reader that supports Extended
 Length APDUs.
 
 @node Undefined Card
 @subsection The Undefined card application ``undefined''
 
 This is a stub application to allow the use of the APDU command even
 if no supported application is found on the card.  This application is
 not used automatically but must be explicitly requested using the
 SERIALNO command.
 
 
 @c *******************************************
 @c ***************            ****************
 @c ***************   FILES    ****************
 @c ***************            ****************
 @c *******************************************
 @mansect files
 @node Scdaemon Configuration
 @section Configuration files
 
 There are a few configuration files to control certain aspects of
 @command{scdaemons}'s operation. Unless noted, they are expected in the
 current home directory (@pxref{option --homedir}).
 
 @table @file
 
 @item scdaemon.conf
 @cindex scdaemon.conf
 This is the standard configuration file read by @command{scdaemon} 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{option --options}).
 
 @item scd-event
 @cindex scd-event
 If this file is present and executable, it will be called on every card
 reader's status change.  An example of this script is provided with the
 distribution
 
 @item reader_@var{n}.status
 This file is created by @command{scdaemon} to let other applications now
 about reader status changes.  Its use is now deprecated in favor of
 @file{scd-event}.
 
 @end table
 
 
 @c
 @c  Examples
 @c
 @mansect examples
 @node Scdaemon Examples
 @section Examples
 
 @c man begin EXAMPLES
 
 @example
 $ scdaemon --server -v
 @end example
 
 @c man end
 
 @c
 @c  Assuan Protocol
 @c
 @manpause
 @node Scdaemon Protocol
 @section Scdaemon's Assuan Protocol
 
 The SC-Daemon should be started by the system to provide access to
 external tokens.  Using Smartcards on a multi-user system does not
 make much sense except for system services, but in this case no
 regular user accounts are hosted on the machine.
 
 A client connects to the SC-Daemon by connecting to the socket named
 @file{@value{LOCALRUNDIR}/scdaemon/socket}, configuration information
 is read from @var{@value{SYSCONFDIR}/scdaemon.conf}
 
 Each connection acts as one session, SC-Daemon takes care of
 synchronizing access to a token between sessions.
 
 @menu
 * Scdaemon SERIALNO::     Return the serial number.
 * Scdaemon LEARN::        Read all useful information from the card.
 * Scdaemon READCERT::     Return a certificate.
 * Scdaemon READKEY::      Return a public key.
 * Scdaemon PKSIGN::       Signing data with a Smartcard.
 * Scdaemon PKDECRYPT::    Decrypting data with a Smartcard.
 * Scdaemon GETATTR::      Read an attribute's value.
 * Scdaemon SETATTR::      Update an attribute's value.
 * Scdaemon WRITEKEY::     Write a key to a card.
 * Scdaemon GENKEY::       Generate a new key on-card.
 * Scdaemon RANDOM::       Return random bytes generated on-card.
 * Scdaemon PASSWD::       Change PINs.
 * Scdaemon CHECKPIN::     Perform a VERIFY operation.
 * Scdaemon RESTART::      Restart connection
 * Scdaemon APDU::         Send a verbatim APDU to the card
 @end menu
 
 @node Scdaemon SERIALNO
 @subsection Return the serial number
 
 This command should be used to check for the presence of a card.  It is
 special in that it can be used to reset the card.  Most other commands
 will return an error when a card change has been detected and the use of
 this function is therefore required.
 
 Background: We want to keep the client clear of handling card changes
 between operations; i.e. the client can assume that all operations are
 done on the same card unless he call this function.
 
 @example
   SERIALNO
 @end example
 
 Return the serial number of the card using a status response like:
 
 @example
   S SERIALNO D27600000000000000000000
 @end example
 
 The serial number is the hex encoded value identified by
 the @code{0x5A} tag in the GDO file (FIX=0x2F02).
 
 
 
 @node Scdaemon LEARN
 @subsection Read all useful information from the card
 
 @example
   LEARN [--force]
 @end example
 
 Learn all useful information of the currently inserted card.  When
 used without the @option{--force} option, the command might do an INQUIRE
 like this:
 
 @example
       INQUIRE KNOWNCARDP <hexstring_with_serialNumber>
 @end example
 
 The client should just send an @code{END} if the processing should go on
 or a @code{CANCEL} to force the function to terminate with a cancel
 error message.  The response of this command is a list of status lines
 formatted as this:
 
 @example
      S KEYPAIRINFO @var{hexstring_with_keygrip} @var{hexstring_with_id}
 @end example
 
 If there is no certificate yet stored on the card a single "X" is
 returned in @var{hexstring_with_keygrip}.
 
 @node Scdaemon READCERT
 @subsection Return a certificate
 
 @example
  READCERT @var{hexified_certid}|@var{keyid}
 @end example
 
 This function is used to read a certificate identified by
 @var{hexified_certid} from the card.  With OpenPGP cards the keyid
 @code{OpenPGP.3} may be used to read the certificate of version 2 cards.
 
 
 @node Scdaemon READKEY
 @subsection Return a public key
 
 @example
 READKEY @var{hexified_certid}
 @end example
 
 Return the public key for the given cert or key ID as an standard
 S-Expression.
 
 
 
 @node Scdaemon PKSIGN
 @subsection Signing data with a Smartcard
 
 To sign some data the caller should use the command
 
 @example
  SETDATA @var{hexstring}
 @end example
 
 to tell @command{scdaemon} about the data to be signed.  The data must be given in
 hex notation.  The actual signing is done using the command
 
 @example
   PKSIGN @var{keyid}
 @end example
 
 where @var{keyid} is the hexified ID of the key to be used.  The key id
 may have been retrieved using the command @code{LEARN}.  If another
 hash algorithm than SHA-1 is used, that algorithm may be given like:
 
 @example
   PKSIGN --hash=@var{algoname} @var{keyid}
 @end example
 
 With @var{algoname} are one of @code{sha1}, @code{rmd160} or @code{md5}.
 
 
 @node Scdaemon PKDECRYPT
 @subsection Decrypting data with a Smartcard
 
 To decrypt some data the caller should use the command
 
 @example
  SETDATA @var{hexstring}
 @end example
 
 to tell @command{scdaemon} about the data to be decrypted.  The data
 must be given in hex notation.  The actual decryption is then done
 using the command
 
 @example
   PKDECRYPT @var{keyid}
 @end example
 
 where @var{keyid} is the hexified ID of the key to be used.
 
 If the card is aware of the apdding format a status line with padding
 information is send before the plaintext data.  The key for this
 status line is @code{PADDING} with the only defined value being 0 and
 meaning padding has been removed.
 
 @node Scdaemon GETATTR
 @subsection Read an attribute's value
 
 TO BE WRITTEN.
 
 @node Scdaemon SETATTR
 @subsection Update an attribute's value
 
 TO BE WRITTEN.
 
 @node Scdaemon WRITEKEY
 @subsection Write a key to a card
 
 @example
   WRITEKEY [--force] @var{keyid}
 @end example
 
 This command is used to store a secret key on a smartcard.  The
 allowed keyids depend on the currently selected smartcard
 application. The actual keydata is requested using the inquiry
 @code{KEYDATA} and need to be provided without any protection.  With
 @option{--force} set an existing key under this @var{keyid} will get
 overwritten.  The key data is expected to be the usual canonical encoded
 S-expression.
 
 A PIN will be requested in most cases.  This however depends on the
 actual card application.
 
 
 @node Scdaemon GENKEY
 @subsection Generate a new key on-card
 
 TO BE WRITTEN.
 
 @node Scdaemon RANDOM
 @subsection Return random bytes generated on-card
 
 TO BE WRITTEN.
 
 
 @node Scdaemon PASSWD
 @subsection Change PINs
 
 @example
    PASSWD [--reset] [--nullpin] @var{chvno}
 @end example
 
 Change the PIN or reset the retry counter of the card holder
 verification vector number @var{chvno}.  The option @option{--nullpin}
 is used to initialize the PIN of TCOS cards (6 byte NullPIN only).
 
 
 @node Scdaemon CHECKPIN
 @subsection Perform a VERIFY operation
 
 @example
   CHECKPIN @var{idstr}
 @end example
 
 Perform a VERIFY operation without doing anything else.  This may be
 used to initialize a the PIN cache earlier to long lasting
 operations.  Its use is highly application dependent:
 
 @table @strong
 @item OpenPGP
 
 Perform a simple verify operation for CHV1 and CHV2, so that further
 operations won't ask for CHV2 and it is possible to do a cheap check on
 the PIN: If there is something wrong with the PIN entry system, only the
 regular CHV will get blocked and not the dangerous CHV3.  @var{idstr} is
 the usual card's serial number in hex notation; an optional fingerprint
 part will get ignored.
 
 There is however a special mode if @var{idstr} is suffixed with the
 literal string @code{[CHV3]}: In this case the Admin PIN is checked if
 and only if the retry counter is still at 3.
 
 @end table
 
 
 
 @node Scdaemon RESTART
 @subsection Perform a RESTART operation
 
 @example
   RESTART
 @end example
 
 Restart the current connection; this is a kind of warm reset.  It
 deletes the context used by this connection but does not actually
 reset the card.
 
 This is used by gpg-agent to reuse a primary pipe connection and
 may be used by clients to backup from a conflict in the serial
 command; i.e. to select another application.
 
 
 
 
 @node Scdaemon APDU
 @subsection Send a verbatim APDU to the card
 
 @example
   APDU [--atr] [--more] [--exlen[=@var{n}]] [@var{hexstring}]
 @end example
 
 
 Send an APDU to the current reader.  This command bypasses the high
 level functions and sends the data directly to the card.
 @var{hexstring} is expected to be a proper APDU.  If @var{hexstring} is
 not given no commands are send to the card; However the command will
 implicitly check whether the card is ready for use.
 
 Using the option @code{--atr} returns the ATR of the card as a status
 message before any data like this:
 @example
      S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1
 @end example
 
 Using the option @code{--more} handles the card status word MORE_DATA
 (61xx) and concatenate all responses to one block.
 
 Using the option @code{--exlen} the returned APDU may use extended
 length up to N bytes.  If N is not given a default value is used
 (currently 4096).
 
 
 
 @mansect see also
 @ifset isman
 @command{gpg-agent}(1),
 @command{gpgsm}(1),
 @command{gpg2}(1)
 @end ifset
 @include see-also-note.texi
 
diff --git a/scd/apdu.c b/scd/apdu.c
index 3bdb509b3..6850aae49 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -1,3342 +1,3343 @@
 /* apdu.c - ISO 7816 APDU functions and low level I/O
  * Copyright (C) 2003, 2004, 2008, 2009, 2010,
  *               2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 /* NOTE: This module is also used by other software, thus the use of
    the macro USE_NPTH is mandatory.  For GnuPG this macro is
    guaranteed to be defined true. */
 
 #include <config.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <signal.h>
 #ifdef USE_NPTH
 # include <unistd.h>
 # include <fcntl.h>
 # include <npth.h>
 #endif
 
 
 /* If requested include the definitions for the remote APDU protocol
    code. */
 #ifdef USE_G10CODE_RAPDU
 #include "rapdu.h"
 #endif /*USE_G10CODE_RAPDU*/
 
 #if defined(GNUPG_SCD_MAIN_HEADER)
 #include GNUPG_SCD_MAIN_HEADER
 #elif GNUPG_MAJOR_VERSION == 1
 /* This is used with GnuPG version < 1.9.  The code has been source
    copied from the current GnuPG >= 1.9  and is maintained over
    there. */
 #include "../common/options.h"
 #include "errors.h"
 #include "memory.h"
 #include "../common/util.h"
 #include "../common/i18n.h"
 #include "dynload.h"
 #include "cardglue.h"
 #else /* GNUPG_MAJOR_VERSION != 1 */
 #include "scdaemon.h"
 #include "../common/exechelp.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
 #include "../common/host2net.h"
 
 #include "iso7816.h"
 #include "apdu.h"
 #define CCID_DRIVER_INCLUDE_USB_IDS 1
 #include "ccid-driver.h"
 
 struct dev_list {
   void *table;
   const char *portstr;
   int idx;
   int idx_max;
 };
 
 #define MAX_READER 4 /* Number of readers we support concurrently. */
 
 
 #if defined(_WIN32) || defined(__CYGWIN__)
 #define DLSTDCALL __stdcall
 #else
 #define DLSTDCALL
 #endif
 
 #if defined(__APPLE__) || defined(_WIN32) || defined(__CYGWIN__)
 typedef unsigned int pcsc_dword_t;
 #else
 typedef unsigned long pcsc_dword_t;
 #endif
 
 /* A structure to collect information pertaining to one reader
    slot. */
 struct reader_table_s {
   int used;            /* True if slot is used. */
   unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
 
   /* Function pointers initialized to the various backends.  */
   int (*connect_card)(int);
   int (*disconnect_card)(int);
   int (*close_reader)(int);
   int (*reset_reader)(int);
   int (*get_status_reader)(int, unsigned int *, int);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
                           unsigned char *, size_t *, pininfo_t *);
   int (*check_pinpad)(int, int, pininfo_t *);
   void (*dump_status_reader)(int);
   int (*set_progress_cb)(int, gcry_handler_progress_t, void*);
   int (*set_prompt_cb)(int, void (*) (void *, int), void*);
   int (*pinpad_verify)(int, int, int, int, int, pininfo_t *);
   int (*pinpad_modify)(int, int, int, int, int, pininfo_t *);
 
   struct {
     ccid_driver_t handle;
   } ccid;
   struct {
     long context;
     long card;
     pcsc_dword_t protocol;
     pcsc_dword_t verify_ioctl;
     pcsc_dword_t modify_ioctl;
     int pinmin;
     int pinmax;
     pcsc_dword_t current_state;
   } pcsc;
 #ifdef USE_G10CODE_RAPDU
   struct {
     rapdu_t handle;
   } rapdu;
 #endif /*USE_G10CODE_RAPDU*/
   char *rdrname;     /* Name of the connected reader or NULL if unknown. */
   unsigned int is_t0:1;     /* True if we know that we are running T=0. */
   unsigned int is_spr532:1; /* True if we know that the reader is a SPR532.  */
   unsigned int pinpad_varlen_supported:1;  /* True if we know that the reader
                                               supports variable length pinpad
                                               input.  */
   unsigned int require_get_status:1;
   unsigned char atr[33];
   size_t atrlen;           /* A zero length indicates that the ATR has
                               not yet been read; i.e. the card is not
                               ready for use. */
 #ifdef USE_NPTH
   npth_mutex_t lock;
 #endif
 };
 typedef struct reader_table_s *reader_table_t;
 
 /* A global table to keep track of active readers. */
 static struct reader_table_s reader_table[MAX_READER];
 
 #ifdef USE_NPTH
 static npth_mutex_t reader_table_lock;
 #endif
 
 
 /* PC/SC constants and function pointer. */
 #define PCSC_SCOPE_USER      0
 #define PCSC_SCOPE_TERMINAL  1
 #define PCSC_SCOPE_SYSTEM    2
 #define PCSC_SCOPE_GLOBAL    3
 
 #define PCSC_PROTOCOL_T0     1
 #define PCSC_PROTOCOL_T1     2
 #ifdef HAVE_W32_SYSTEM
 # define PCSC_PROTOCOL_RAW   0x00010000  /* The active protocol.  */
 #else
 # define PCSC_PROTOCOL_RAW   4
 #endif
 
 #define PCSC_SHARE_EXCLUSIVE 1
 #define PCSC_SHARE_SHARED    2
 #define PCSC_SHARE_DIRECT    3
 
 #define PCSC_LEAVE_CARD      0
 #define PCSC_RESET_CARD      1
 #define PCSC_UNPOWER_CARD    2
 #define PCSC_EJECT_CARD      3
 
 #ifdef HAVE_W32_SYSTEM
 # define PCSC_UNKNOWN    0x0000  /* The driver is not aware of the status.  */
 # define PCSC_ABSENT     0x0001  /* Card is absent.  */
 # define PCSC_PRESENT    0x0002  /* Card is present.  */
 # define PCSC_SWALLOWED  0x0003  /* Card is present and electrical connected. */
 # define PCSC_POWERED    0x0004  /* Card is powered.  */
 # define PCSC_NEGOTIABLE 0x0005  /* Card is awaiting PTS.  */
 # define PCSC_SPECIFIC   0x0006  /* Card is ready for use.  */
 #else
 # define PCSC_UNKNOWN    0x0001
 # define PCSC_ABSENT     0x0002  /* Card is absent.  */
 # define PCSC_PRESENT    0x0004  /* Card is present.  */
 # define PCSC_SWALLOWED  0x0008  /* Card is present and electrical connected. */
 # define PCSC_POWERED    0x0010  /* Card is powered.  */
 # define PCSC_NEGOTIABLE 0x0020  /* Card is awaiting PTS.  */
 # define PCSC_SPECIFIC   0x0040  /* Card is ready for use.  */
 #endif
 
 #define PCSC_STATE_UNAWARE     0x0000  /* Want status.  */
 #define PCSC_STATE_IGNORE      0x0001  /* Ignore this reader.  */
 #define PCSC_STATE_CHANGED     0x0002  /* State has changed.  */
 #define PCSC_STATE_UNKNOWN     0x0004  /* Reader unknown.  */
 #define PCSC_STATE_UNAVAILABLE 0x0008  /* Status unavailable.  */
 #define PCSC_STATE_EMPTY       0x0010  /* Card removed.  */
 #define PCSC_STATE_PRESENT     0x0020  /* Card inserted.  */
 #define PCSC_STATE_ATRMATCH    0x0040  /* ATR matches card. */
 #define PCSC_STATE_EXCLUSIVE   0x0080  /* Exclusive Mode.  */
 #define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
 #define PCSC_STATE_MUTE        0x0200  /* Unresponsive card.  */
 #ifdef HAVE_W32_SYSTEM
 # define PCSC_STATE_UNPOWERED  0x0400  /* Card not powerred up.  */
 #endif
 
 /* Some PC/SC error codes.  */
 #define PCSC_E_CANCELLED               0x80100002
 #define PCSC_E_CANT_DISPOSE            0x8010000E
 #define PCSC_E_INSUFFICIENT_BUFFER     0x80100008
 #define PCSC_E_INVALID_ATR             0x80100015
 #define PCSC_E_INVALID_HANDLE          0x80100003
 #define PCSC_E_INVALID_PARAMETER       0x80100004
 #define PCSC_E_INVALID_TARGET          0x80100005
 #define PCSC_E_INVALID_VALUE           0x80100011
 #define PCSC_E_NO_MEMORY               0x80100006
 #define PCSC_E_UNKNOWN_READER          0x80100009
 #define PCSC_E_TIMEOUT                 0x8010000A
 #define PCSC_E_SHARING_VIOLATION       0x8010000B
 #define PCSC_E_NO_SMARTCARD            0x8010000C
 #define PCSC_E_UNKNOWN_CARD            0x8010000D
 #define PCSC_E_PROTO_MISMATCH          0x8010000F
 #define PCSC_E_NOT_READY               0x80100010
 #define PCSC_E_SYSTEM_CANCELLED        0x80100012
 #define PCSC_E_NOT_TRANSACTED          0x80100016
 #define PCSC_E_READER_UNAVAILABLE      0x80100017
 #define PCSC_E_NO_SERVICE              0x8010001D
 #define PCSC_E_SERVICE_STOPPED         0x8010001E
 #define PCSC_W_RESET_CARD              0x80100068
 #define PCSC_W_REMOVED_CARD            0x80100069
 
 /* Fix pcsc-lite ABI incompatibility.  */
 #ifndef SCARD_CTL_CODE
 #ifdef _WIN32
 #include <winioctl.h>
 #define SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_SMARTCARD, (code), \
                                       METHOD_BUFFERED, FILE_ANY_ACCESS)
 #else
 #define SCARD_CTL_CODE(code) (0x42000000 + (code))
 #endif
 #endif
 
 #define CM_IOCTL_GET_FEATURE_REQUEST     SCARD_CTL_CODE(3400)
 #define CM_IOCTL_VENDOR_IFD_EXCHANGE     SCARD_CTL_CODE(1)
 #define FEATURE_VERIFY_PIN_DIRECT        0x06
 #define FEATURE_MODIFY_PIN_DIRECT        0x07
 #define FEATURE_GET_TLV_PROPERTIES       0x12
 
 #define PCSCv2_PART10_PROPERTY_bEntryValidationCondition 2
 #define PCSCv2_PART10_PROPERTY_bTimeOut2                 3
 #define PCSCv2_PART10_PROPERTY_bMinPINSize               6
 #define PCSCv2_PART10_PROPERTY_bMaxPINSize               7
 #define PCSCv2_PART10_PROPERTY_wIdVendor                11
 #define PCSCv2_PART10_PROPERTY_wIdProduct               12
 
 
 /* The PC/SC error is defined as a long as per specs.  Due to left
    shifts bit 31 will get sign extended.  We use this mask to fix
    it. */
 #define PCSC_ERR_MASK(a)  ((a) & 0xffffffff)
 
 
 struct pcsc_io_request_s
 {
   unsigned long protocol;
   unsigned long pci_len;
 };
 
 typedef struct pcsc_io_request_s *pcsc_io_request_t;
 
 #ifdef __APPLE__
 #pragma pack(1)
 #endif
 
 struct pcsc_readerstate_s
 {
   const char *reader;
   void *user_data;
   pcsc_dword_t current_state;
   pcsc_dword_t event_state;
   pcsc_dword_t atrlen;
   unsigned char atr[33];
 };
 
 #ifdef __APPLE__
 #pragma pack()
 #endif
 
 typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
 
 long (* DLSTDCALL pcsc_establish_context) (pcsc_dword_t scope,
                                            const void *reserved1,
                                            const void *reserved2,
                                            long *r_context);
 long (* DLSTDCALL pcsc_release_context) (long context);
 long (* DLSTDCALL pcsc_list_readers) (long context,
                                       const char *groups,
                                       char *readers, pcsc_dword_t*readerslen);
 long (* DLSTDCALL pcsc_get_status_change) (long context,
                                            pcsc_dword_t timeout,
                                            pcsc_readerstate_t readerstates,
                                            pcsc_dword_t nreaderstates);
 long (* DLSTDCALL pcsc_connect) (long context,
                                  const char *reader,
                                  pcsc_dword_t share_mode,
                                  pcsc_dword_t preferred_protocols,
                                  long *r_card,
                                  pcsc_dword_t *r_active_protocol);
 long (* DLSTDCALL pcsc_reconnect) (long card,
                                    pcsc_dword_t share_mode,
                                    pcsc_dword_t preferred_protocols,
                                    pcsc_dword_t initialization,
                                    pcsc_dword_t *r_active_protocol);
 long (* DLSTDCALL pcsc_disconnect) (long card,
                                     pcsc_dword_t disposition);
 long (* DLSTDCALL pcsc_status) (long card,
                                 char *reader, pcsc_dword_t *readerlen,
                                 pcsc_dword_t *r_state,
                                 pcsc_dword_t *r_protocol,
                                 unsigned char *atr, pcsc_dword_t *atrlen);
 long (* DLSTDCALL pcsc_begin_transaction) (long card);
 long (* DLSTDCALL pcsc_end_transaction) (long card,
                                          pcsc_dword_t disposition);
 long (* DLSTDCALL pcsc_transmit) (long card,
                                   const pcsc_io_request_t send_pci,
                                   const unsigned char *send_buffer,
                                   pcsc_dword_t send_len,
                                   pcsc_io_request_t recv_pci,
                                   unsigned char *recv_buffer,
                                   pcsc_dword_t *recv_len);
 long (* DLSTDCALL pcsc_set_timeout) (long context,
                                      pcsc_dword_t timeout);
 long (* DLSTDCALL pcsc_control) (long card,
                                  pcsc_dword_t control_code,
                                  const void *send_buffer,
                                  pcsc_dword_t send_len,
                                  void *recv_buffer,
                                  pcsc_dword_t recv_len,
                                  pcsc_dword_t *bytes_returned);
 
 
 /*  Prototypes.  */
 static int pcsc_vendor_specific_init (int slot);
 static int pcsc_get_status (int slot, unsigned int *status, int on_wire);
 static int reset_pcsc_reader (int slot);
 static int apdu_get_status_internal (int slot, int hang, unsigned int *status,
                                      int on_wire);
 static int check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo);
 static int pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
                                pininfo_t *pininfo);
 static int pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
                                pininfo_t *pininfo);
 
 
 
 /*
       Helper
  */
 
 static int
 lock_slot (int slot)
 {
 #ifdef USE_NPTH
   int err;
 
   err = npth_mutex_lock (&reader_table[slot].lock);
   if (err)
     {
       log_error ("failed to acquire apdu lock: %s\n", strerror (err));
       return SW_HOST_LOCKING_FAILED;
     }
 #endif /*USE_NPTH*/
   return 0;
 }
 
 static int
 trylock_slot (int slot)
 {
 #ifdef USE_NPTH
   int err;
 
   err = npth_mutex_trylock (&reader_table[slot].lock);
   if (err == EBUSY)
     return SW_HOST_BUSY;
   else if (err)
     {
       log_error ("failed to acquire apdu lock: %s\n", strerror (err));
       return SW_HOST_LOCKING_FAILED;
     }
 #endif /*USE_NPTH*/
   return 0;
 }
 
 static void
 unlock_slot (int slot)
 {
 #ifdef USE_NPTH
   int err;
 
   err = npth_mutex_unlock (&reader_table[slot].lock);
   if (err)
     log_error ("failed to release apdu lock: %s\n", strerror (errno));
 #endif /*USE_NPTH*/
 }
 
 
 /* Find an unused reader slot for PORTSTR and put it into the reader
    table.  Return -1 on error or the index into the reader table.
    Acquire slot's lock on successful return.  Caller needs to unlock it.  */
 static int
 new_reader_slot (void)
 {
   int i, reader = -1;
 
   for (i=0; i < MAX_READER; i++)
     if (!reader_table[i].used)
       {
         reader = i;
         reader_table[reader].used = 1;
         break;
       }
 
   if (reader == -1)
     {
       log_error ("new_reader_slot: out of slots\n");
       return -1;
     }
 
   if (lock_slot (reader))
     {
       reader_table[reader].used = 0;
       return -1;
     }
 
   reader_table[reader].connect_card = NULL;
   reader_table[reader].disconnect_card = NULL;
   reader_table[reader].close_reader = NULL;
   reader_table[reader].reset_reader = NULL;
   reader_table[reader].get_status_reader = NULL;
   reader_table[reader].send_apdu_reader = NULL;
   reader_table[reader].check_pinpad = check_pcsc_pinpad;
   reader_table[reader].dump_status_reader = NULL;
   reader_table[reader].set_progress_cb = NULL;
   reader_table[reader].set_prompt_cb = NULL;
   reader_table[reader].pinpad_verify = pcsc_pinpad_verify;
   reader_table[reader].pinpad_modify = pcsc_pinpad_modify;
 
   reader_table[reader].is_t0 = 1;
   reader_table[reader].is_spr532 = 0;
   reader_table[reader].pinpad_varlen_supported = 0;
   reader_table[reader].require_get_status = 1;
   reader_table[reader].pcsc.verify_ioctl = 0;
   reader_table[reader].pcsc.modify_ioctl = 0;
   reader_table[reader].pcsc.pinmin = -1;
   reader_table[reader].pcsc.pinmax = -1;
   reader_table[reader].pcsc.current_state = PCSC_STATE_UNAWARE;
 
   return reader;
 }
 
 
 static void
 dump_reader_status (int slot)
 {
   if (!opt.verbose)
     return;
 
   if (reader_table[slot].dump_status_reader)
     reader_table[slot].dump_status_reader (slot);
 
   if (reader_table[slot].atrlen)
     {
       log_info ("slot %d: ATR=", slot);
       log_printhex (reader_table[slot].atr, reader_table[slot].atrlen, "");
     }
 }
 
 
 
 static const char *
 host_sw_string (long err)
 {
   switch (err)
     {
     case 0: return "okay";
     case SW_HOST_OUT_OF_CORE: return "out of core";
     case SW_HOST_INV_VALUE: return "invalid value";
     case SW_HOST_NO_DRIVER: return "no driver";
     case SW_HOST_NOT_SUPPORTED: return "not supported";
     case SW_HOST_LOCKING_FAILED: return "locking failed";
     case SW_HOST_BUSY: return "busy";
     case SW_HOST_NO_CARD: return "no card";
     case SW_HOST_CARD_INACTIVE: return "card inactive";
     case SW_HOST_CARD_IO_ERROR: return "card I/O error";
     case SW_HOST_GENERAL_ERROR: return "general error";
     case SW_HOST_NO_READER: return "no reader";
     case SW_HOST_ABORTED: return "aborted";
     case SW_HOST_NO_PINPAD: return "no pinpad";
     case SW_HOST_ALREADY_CONNECTED: return "already connected";
     case SW_HOST_CANCELLED: return "cancelled";
     case SW_HOST_USB_OTHER:    return "USB general error";
     case SW_HOST_USB_IO:       return "USB I/O error";
     case SW_HOST_USB_ACCESS:   return "USB permission denied";
     case SW_HOST_USB_NO_DEVICE:return "USB no device";
     case SW_HOST_USB_BUSY:     return "USB busy";
     case SW_HOST_USB_TIMEOUT:  return "USB timeout";
     case SW_HOST_USB_OVERFLOW: return "USB overflow";
     default: return "unknown host status error";
     }
 }
 
 
 const char *
 apdu_strerror (int rc)
 {
   switch (rc)
     {
     case SW_EOF_REACHED    : return "eof reached";
     case SW_EEPROM_FAILURE : return "eeprom failure";
     case SW_WRONG_LENGTH   : return "wrong length";
     case SW_SM_NOT_SUP     : return "secure messaging not supported";
     case SW_CC_NOT_SUP     : return "command chaining not supported";
     case SW_FILE_STRUCT    : return "command can't be used for file structure.";
     case SW_CHV_WRONG      : return "CHV wrong";
     case SW_CHV_BLOCKED    : return "CHV blocked";
     case SW_REF_DATA_INV   : return "referenced data invalidated";
     case SW_USE_CONDITIONS : return "use conditions not satisfied";
     case SW_NO_CURRENT_EF  : return "no current EF selected";
     case SW_BAD_PARAMETER  : return "bad parameter";
     case SW_NOT_SUPPORTED  : return "not supported";
     case SW_FILE_NOT_FOUND : return "file not found";
     case SW_RECORD_NOT_FOUND:return "record not found";
     case SW_REF_NOT_FOUND  : return "reference not found";
     case SW_NOT_ENOUGH_MEMORY: return "not enough memory space in the file";
     case SW_INCONSISTENT_LC: return "Lc inconsistent with TLV structure.";
     case SW_INCORRECT_P0_P1: return "incorrect parameters P0,P1";
     case SW_BAD_LC         : return "Lc inconsistent with P0,P1";
     case SW_BAD_P0_P1      : return "bad P0,P1";
     case SW_INS_NOT_SUP    : return "instruction not supported";
     case SW_CLA_NOT_SUP    : return "class not supported";
     case SW_SUCCESS        : return "success";
     default:
       if ((rc & ~0x00ff) == SW_MORE_DATA)
         return "more data available";
       if ( (rc & 0x10000) )
         return host_sw_string (rc);
       return "unknown status error";
     }
 }
 
 /*
        PC/SC Interface
  */
 
 static const char *
 pcsc_error_string (long err)
 {
   const char *s;
 
   if (!err)
     return "okay";
   if ((err & 0x80100000) != 0x80100000)
     return "invalid PC/SC error code";
   err &= 0xffff;
   switch (err)
     {
     case 0x0002: s = "cancelled"; break;
     case 0x000e: s = "can't dispose"; break;
     case 0x0008: s = "insufficient buffer"; break;
     case 0x0015: s = "invalid ATR"; break;
     case 0x0003: s = "invalid handle"; break;
     case 0x0004: s = "invalid parameter"; break;
     case 0x0005: s = "invalid target"; break;
     case 0x0011: s = "invalid value"; break;
     case 0x0006: s = "no memory"; break;
     case 0x0013: s = "comm error"; break;
     case 0x0001: s = "internal error"; break;
     case 0x0014: s = "unknown error"; break;
     case 0x0007: s = "waited too long"; break;
     case 0x0009: s = "unknown reader"; break;
     case 0x000a: s = "timeout"; break;
     case 0x000b: s = "sharing violation"; break;
     case 0x000c: s = "no smartcard"; break;
     case 0x000d: s = "unknown card"; break;
     case 0x000f: s = "proto mismatch"; break;
     case 0x0010: s = "not ready"; break;
     case 0x0012: s = "system cancelled"; break;
     case 0x0016: s = "not transacted"; break;
     case 0x0017: s = "reader unavailable"; break;
     case 0x0065: s = "unsupported card"; break;
     case 0x0066: s = "unresponsive card"; break;
     case 0x0067: s = "unpowered card"; break;
     case 0x0068: s = "reset card"; break;
     case 0x0069: s = "removed card"; break;
     case 0x006a: s = "inserted card"; break;
     case 0x001f: s = "unsupported feature"; break;
     case 0x0019: s = "PCI too small"; break;
     case 0x001a: s = "reader unsupported"; break;
     case 0x001b: s = "duplicate reader"; break;
     case 0x001c: s = "card unsupported"; break;
     case 0x001d: s = "no service"; break;
     case 0x001e: s = "service stopped"; break;
     default:     s = "unknown PC/SC error code"; break;
     }
   return s;
 }
 
 /* Map PC/SC error codes to our special host status words.  */
 static int
 pcsc_error_to_sw (long ec)
 {
   int rc;
 
   switch ( PCSC_ERR_MASK (ec) )
     {
     case 0:  rc = 0; break;
 
     case PCSC_E_CANCELLED:           rc = SW_HOST_CANCELLED; break;
     case PCSC_E_NO_MEMORY:           rc = SW_HOST_OUT_OF_CORE; break;
     case PCSC_E_TIMEOUT:             rc = SW_HOST_CARD_IO_ERROR; break;
     case PCSC_E_NO_SERVICE:
     case PCSC_E_SERVICE_STOPPED:
     case PCSC_E_UNKNOWN_READER:      rc = SW_HOST_NO_READER; break;
     case PCSC_E_SHARING_VIOLATION:   rc = SW_HOST_LOCKING_FAILED; break;
     case PCSC_E_NO_SMARTCARD:        rc = SW_HOST_NO_CARD; break;
     case PCSC_W_REMOVED_CARD:        rc = SW_HOST_NO_CARD; break;
 
     case PCSC_E_INVALID_TARGET:
     case PCSC_E_INVALID_VALUE:
     case PCSC_E_INVALID_HANDLE:
     case PCSC_E_INVALID_PARAMETER:
     case PCSC_E_INSUFFICIENT_BUFFER: rc = SW_HOST_INV_VALUE; break;
 
     default:  rc = SW_HOST_GENERAL_ERROR; break;
     }
 
   return rc;
 }
 
 static void
 dump_pcsc_reader_status (int slot)
 {
   if (reader_table[slot].pcsc.card)
     {
       log_info ("reader slot %d: active protocol:", slot);
       if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T0))
         log_printf (" T0");
       else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
         log_printf (" T1");
       else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_RAW))
         log_printf (" raw");
       log_printf ("\n");
     }
   else
     log_info ("reader slot %d: not connected\n", slot);
 }
 
 
 static int
 pcsc_get_status (int slot, unsigned int *status, int on_wire)
 {
   long err;
   struct pcsc_readerstate_s rdrstates[1];
 
   (void)on_wire;
   memset (rdrstates, 0, sizeof *rdrstates);
   rdrstates[0].reader = reader_table[slot].rdrname;
   rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
   err = pcsc_get_status_change (reader_table[slot].pcsc.context,
                                 0,
                                 rdrstates, 1);
   if (err == PCSC_E_TIMEOUT)
     err = 0; /* Timeout is no error here.  */
   if (err)
     {
       log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       return pcsc_error_to_sw (err);
     }
 
   if ((rdrstates[0].event_state & PCSC_STATE_CHANGED))
     reader_table[slot].pcsc.current_state =
       (rdrstates[0].event_state & ~PCSC_STATE_CHANGED);
 
   if (DBG_READER)
     log_debug
       ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n",
        (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"",
        (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"",
        (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"",
        (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"",
        (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"",
        (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"",
        (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"",
        (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"",
        (rdrstates[0].event_state & PCSC_STATE_INUSE)? " inuse":"",
        (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" );
 
   *status = 0;
   if ( (reader_table[slot].pcsc.current_state & PCSC_STATE_PRESENT) )
     {
       *status |= APDU_CARD_PRESENT;
       if ( !(reader_table[slot].pcsc.current_state & PCSC_STATE_MUTE) )
         *status |= APDU_CARD_ACTIVE;
     }
 #ifndef HAVE_W32_SYSTEM
   /* We indicate a useful card if it is not in use by another
      application.  This is because we only use exclusive access
      mode.  */
   if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
        == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
-       && !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE) )
+       && (opt.pcsc_shared
+           || !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE)))
     *status |= APDU_CARD_USABLE;
 #else
   /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
      time when we are the only user (SCM SCR335) under Windows.  */
   if ((*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
       == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
     *status |= APDU_CARD_USABLE;
 #endif
 
   if (!on_wire && (rdrstates[0].event_state & PCSC_STATE_CHANGED))
     /* Event like sleep/resume occurs, which requires RESET.  */
     return SW_HOST_NO_READER;
   else
     return 0;
 }
 
 
 /* Send the APDU of length APDULEN to SLOT and return a maximum of
    *BUFLEN data in BUFFER, the actual returned size will be stored at
    BUFLEN.  Returns: A status word. */
 static int
 pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                 unsigned char *buffer, size_t *buflen,
                 pininfo_t *pininfo)
 {
   long err;
   struct pcsc_io_request_s send_pci;
   pcsc_dword_t recv_len;
 
   (void)pininfo;
 
   if (!reader_table[slot].atrlen
       && (err = reset_pcsc_reader (slot)))
     return err;
 
   if (DBG_CARD_IO)
     log_printhex (apdu, apdulen, "  PCSC_data:");
 
   if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
       send_pci.protocol = PCSC_PROTOCOL_T1;
   else
       send_pci.protocol = PCSC_PROTOCOL_T0;
   send_pci.pci_len = sizeof send_pci;
   recv_len = *buflen;
   err = pcsc_transmit (reader_table[slot].pcsc.card,
                        &send_pci, apdu, apdulen,
                        NULL, buffer, &recv_len);
   *buflen = recv_len;
   if (err)
     log_error ("pcsc_transmit failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
 
   /* Handle fatal errors which require shutdown of reader.  */
   if (err == PCSC_E_NOT_TRANSACTED || err == PCSC_W_RESET_CARD
       || err == PCSC_W_REMOVED_CARD)
     {
       reader_table[slot].pcsc.current_state = PCSC_STATE_UNAWARE;
       scd_kick_the_loop ();
     }
 
   return pcsc_error_to_sw (err);
 }
 
 
 /* Do some control with the value of IOCTL_CODE to the card inserted
    to SLOT.  Input buffer is specified by CNTLBUF of length LEN.
    Output buffer is specified by BUFFER of length *BUFLEN, and the
    actual output size will be stored at BUFLEN.  Returns: A status word.
    This routine is used for PIN pad input support.  */
 static int
 control_pcsc (int slot, pcsc_dword_t ioctl_code,
               const unsigned char *cntlbuf, size_t len,
               unsigned char *buffer, pcsc_dword_t *buflen)
 {
   long err;
 
   err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
                       cntlbuf, len, buffer, buflen? *buflen:0, buflen);
   if (err)
     {
       log_error ("pcsc_control failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       return pcsc_error_to_sw (err);
     }
 
   return 0;
 }
 
 
 static int
 close_pcsc_reader (int slot)
 {
   pcsc_release_context (reader_table[slot].pcsc.context);
   return 0;
 }
 
 
 /* Connect a PC/SC card.  */
 static int
 connect_pcsc_card (int slot)
 {
   long err;
 
   assert (slot >= 0 && slot < MAX_READER);
 
   if (reader_table[slot].pcsc.card)
     return SW_HOST_ALREADY_CONNECTED;
 
   reader_table[slot].atrlen = 0;
   reader_table[slot].is_t0 = 0;
 
   err = pcsc_connect (reader_table[slot].pcsc.context,
                       reader_table[slot].rdrname,
-                      PCSC_SHARE_EXCLUSIVE,
+                      opt.pcsc_shared? PCSC_SHARE_SHARED:PCSC_SHARE_EXCLUSIVE,
                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
                       &reader_table[slot].pcsc.card,
                       &reader_table[slot].pcsc.protocol);
   if (err)
     {
       reader_table[slot].pcsc.card = 0;
       if (err != PCSC_E_NO_SMARTCARD)
         log_error ("pcsc_connect failed: %s (0x%lx)\n",
                    pcsc_error_string (err), err);
     }
   else
     {
       char reader[250];
       pcsc_dword_t readerlen, atrlen;
       pcsc_dword_t card_state, card_protocol;
 
       pcsc_vendor_specific_init (slot);
 
       atrlen = DIM (reader_table[0].atr);
       readerlen = sizeof reader -1 ;
       err = pcsc_status (reader_table[slot].pcsc.card,
                          reader, &readerlen,
                          &card_state, &card_protocol,
                          reader_table[slot].atr, &atrlen);
       if (err)
         log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
                    pcsc_error_string (err), err, (long unsigned int)readerlen);
       else
         {
           if (atrlen > DIM (reader_table[0].atr))
             log_bug ("ATR returned by pcsc_status is too large\n");
           reader_table[slot].atrlen = atrlen;
           reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
         }
     }
 
   dump_reader_status (slot);
   return pcsc_error_to_sw (err);
 }
 
 
 static int
 disconnect_pcsc_card (int slot)
 {
   long err;
 
   assert (slot >= 0 && slot < MAX_READER);
 
   if (!reader_table[slot].pcsc.card)
     return 0;
 
   err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
   if (err)
     {
       log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       return SW_HOST_CARD_IO_ERROR;
     }
   reader_table[slot].pcsc.card = 0;
   return 0;
 }
 
 
 /* Send an PC/SC reset command and return a status word on error or 0
    on success. */
 static int
 reset_pcsc_reader (int slot)
 {
   int sw;
 
   sw = disconnect_pcsc_card (slot);
   if (!sw)
     sw = connect_pcsc_card (slot);
 
   return sw;
 }
 
 
 /* Examine reader specific parameters and initialize.  This is mostly
    for pinpad input.  Called at opening the connection to the reader.  */
 static int
 pcsc_vendor_specific_init (int slot)
 {
   unsigned char buf[256];
   pcsc_dword_t len;
   int sw;
   int vendor = 0;
   int product = 0;
   pcsc_dword_t get_tlv_ioctl = (pcsc_dword_t)-1;
   unsigned char *p;
 
   len = sizeof (buf);
   sw = control_pcsc (slot, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, buf, &len);
   if (sw)
     {
       log_error ("pcsc_vendor_specific_init: GET_FEATURE_REQUEST failed: %d\n",
                  sw);
       return SW_NOT_SUPPORTED;
     }
   else
     {
       p = buf;
       while (p < buf + len)
         {
           unsigned char code = *p++;
           int l = *p++;
           unsigned int v = 0;
 
           if (l == 1)
             v = p[0];
           else if (l == 2)
             v = buf16_to_uint (p);
           else if (l == 4)
             v = buf32_to_uint (p);
 
           if (code == FEATURE_VERIFY_PIN_DIRECT)
             reader_table[slot].pcsc.verify_ioctl = v;
           else if (code == FEATURE_MODIFY_PIN_DIRECT)
             reader_table[slot].pcsc.modify_ioctl = v;
           else if (code == FEATURE_GET_TLV_PROPERTIES)
             get_tlv_ioctl = v;
 
           if (DBG_CARD_IO)
             log_debug ("feature: code=%02X, len=%d, v=%02X\n", code, l, v);
 
           p += l;
         }
     }
 
   if (get_tlv_ioctl == (pcsc_dword_t)-1)
     {
       /*
        * For system which doesn't support GET_TLV_PROPERTIES,
        * we put some heuristics here.
        */
       if (reader_table[slot].rdrname)
         {
           if (strstr (reader_table[slot].rdrname, "SPRx32"))
             {
               reader_table[slot].is_spr532 = 1;
               reader_table[slot].pinpad_varlen_supported = 1;
             }
           else if (strstr (reader_table[slot].rdrname, "ST-2xxx"))
             {
               reader_table[slot].pcsc.pinmax = 15;
               reader_table[slot].pinpad_varlen_supported = 1;
             }
           else if (strstr (reader_table[slot].rdrname, "cyberJack")
                    || strstr (reader_table[slot].rdrname, "DIGIPASS")
                    || strstr (reader_table[slot].rdrname, "Gnuk")
                    || strstr (reader_table[slot].rdrname, "KAAN")
                    || strstr (reader_table[slot].rdrname, "Trustica"))
             reader_table[slot].pinpad_varlen_supported = 1;
         }
 
       return 0;
     }
 
   len = sizeof (buf);
   sw = control_pcsc (slot, get_tlv_ioctl, NULL, 0, buf, &len);
   if (sw)
     {
       log_error ("pcsc_vendor_specific_init: GET_TLV_IOCTL failed: %d\n", sw);
       return SW_NOT_SUPPORTED;
     }
 
   p = buf;
   while (p < buf + len)
     {
       unsigned char tag = *p++;
       int l = *p++;
       unsigned int v = 0;
 
       /* Umm... here is little endian, while the encoding above is big.  */
       if (l == 1)
         v = p[0];
       else if (l == 2)
         v = (((unsigned int)p[1] << 8) | p[0]);
       else if (l == 4)
         v = (((unsigned int)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
 
       if (tag == PCSCv2_PART10_PROPERTY_bMinPINSize)
         reader_table[slot].pcsc.pinmin = v;
       else if (tag == PCSCv2_PART10_PROPERTY_bMaxPINSize)
         reader_table[slot].pcsc.pinmax = v;
       else if (tag == PCSCv2_PART10_PROPERTY_wIdVendor)
         vendor = v;
       else if (tag == PCSCv2_PART10_PROPERTY_wIdProduct)
         product = v;
 
       if (DBG_CARD_IO)
         log_debug ("TLV properties: tag=%02X, len=%d, v=%08X\n", tag, l, v);
 
       p += l;
     }
 
   if (vendor == VENDOR_VEGA && product == VEGA_ALPHA)
     {
       /*
        * Please read the comment of ccid_vendor_specific_init in
        * ccid-driver.c.
        */
       const unsigned char cmd[] = { '\xb5', '\x01', '\x00', '\x03', '\x00' };
       sw = control_pcsc (slot, CM_IOCTL_VENDOR_IFD_EXCHANGE,
                          cmd, sizeof (cmd), NULL, 0);
       if (sw)
         return SW_NOT_SUPPORTED;
     }
   else if (vendor == VENDOR_SCM && product == SCM_SPR532) /* SCM SPR532 */
     {
       reader_table[slot].is_spr532 = 1;
       reader_table[slot].pinpad_varlen_supported = 1;
     }
   else if (vendor == 0x046a)
     {
       /* Cherry ST-2xxx (product == 0x003e) supports TPDU level
        * exchange.  Other products which only support short APDU level
        * exchange only work with shorter keys like RSA 1024.
        */
       reader_table[slot].pcsc.pinmax = 15;
       reader_table[slot].pinpad_varlen_supported = 1;
     }
   else if (vendor == 0x0c4b /* Tested with Reiner cyberJack GO */
            || vendor == 0x1a44 /* Tested with Vasco DIGIPASS 920 */
            || vendor == 0x234b /* Tested with FSIJ Gnuk Token */
            || vendor == 0x0d46 /* Tested with KAAN Advanced??? */
            || (vendor == 0x1fc9 && product == 0x81e6) /* Tested with Trustica Cryptoucan */)
     reader_table[slot].pinpad_varlen_supported = 1;
 
   return 0;
 }
 
 
 /* Open the PC/SC reader without using the wrapper.  Returns -1 on
    error or a slot number for the reader.  */
 static int
 open_pcsc_reader (const char *portstr)
 {
   long err;
   int slot;
   char *list = NULL;
   char *rdrname = NULL;
   pcsc_dword_t nreader;
   char *p;
 
   slot = new_reader_slot ();
   if (slot == -1)
     return -1;
 
   /* Fixme: Allocating a context for each slot is not required.  One
      global context should be sufficient.  */
   err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
                                 &reader_table[slot].pcsc.context);
   if (err)
     {
       log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       reader_table[slot].used = 0;
       unlock_slot (slot);
       return -1;
     }
 
   err = pcsc_list_readers (reader_table[slot].pcsc.context,
                            NULL, NULL, &nreader);
   if (!err)
     {
       list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
       if (!list)
         {
           log_error ("error allocating memory for reader list\n");
           pcsc_release_context (reader_table[slot].pcsc.context);
           reader_table[slot].used = 0;
           unlock_slot (slot);
           return -1 /*SW_HOST_OUT_OF_CORE*/;
         }
       err = pcsc_list_readers (reader_table[slot].pcsc.context,
                                NULL, list, &nreader);
     }
   if (err)
     {
       log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       pcsc_release_context (reader_table[slot].pcsc.context);
       reader_table[slot].used = 0;
       xfree (list);
       unlock_slot (slot);
       return -1;
     }
 
   p = list;
   while (nreader)
     {
       if (!*p && !p[1])
         break;
       log_info ("detected reader '%s'\n", p);
       if (nreader < (strlen (p)+1))
         {
           log_error ("invalid response from pcsc_list_readers\n");
           break;
         }
       if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
         rdrname = p;
       nreader -= strlen (p)+1;
       p += strlen (p) + 1;
     }
 
   if (!rdrname)
     rdrname = list;
 
   reader_table[slot].rdrname = xtrystrdup (rdrname);
   if (!reader_table[slot].rdrname)
     {
       log_error ("error allocating memory for reader name\n");
       pcsc_release_context (reader_table[slot].pcsc.context);
       reader_table[slot].used = 0;
       unlock_slot (slot);
       return -1;
     }
   xfree (list);
   list = NULL;
 
   reader_table[slot].pcsc.card = 0;
   reader_table[slot].atrlen = 0;
 
   reader_table[slot].connect_card = connect_pcsc_card;
   reader_table[slot].disconnect_card = disconnect_pcsc_card;
   reader_table[slot].close_reader = close_pcsc_reader;
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
   dump_reader_status (slot);
   unlock_slot (slot);
   return slot;
 }
 
 
 /* Check whether the reader supports the ISO command code COMMAND
    on the pinpad.  Return 0 on success.  */
 static int
 check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo)
 {
   int r;
 
   if (reader_table[slot].pcsc.pinmin >= 0)
     pininfo->minlen = reader_table[slot].pcsc.pinmin;
 
   if (reader_table[slot].pcsc.pinmax >= 0)
     pininfo->maxlen = reader_table[slot].pcsc.pinmax;
 
   if (!pininfo->minlen)
     pininfo->minlen = 1;
   if (!pininfo->maxlen)
     pininfo->maxlen = 15;
 
   if ((command == ISO7816_VERIFY && reader_table[slot].pcsc.verify_ioctl != 0)
       || (command == ISO7816_CHANGE_REFERENCE_DATA
           && reader_table[slot].pcsc.modify_ioctl != 0))
     r = 0;                       /* Success */
   else
     r = SW_NOT_SUPPORTED;
 
   if (DBG_CARD_IO)
     log_debug ("check_pcsc_pinpad: command=%02X, r=%d\n",
                (unsigned int)command, r);
 
   if (reader_table[slot].pinpad_varlen_supported)
     pininfo->fixedlen = 0;
 
   return r;
 }
 
 #define PIN_VERIFY_STRUCTURE_SIZE 24
 static int
 pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
                     pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_verify;
   int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen;
   /*
    * The result buffer is only expected to have two-byte result on
    * return.  However, some implementation uses this buffer for lower
    * layer too and it assumes that there is enough space for lower
    * layer communication.  Such an implementation fails for TPDU
    * readers with "insufficient buffer", as it needs header and
    * trailer.  Six is the number for header + result + trailer (TPDU).
    */
   unsigned char result[6];
   pcsc_dword_t resultlen = 6;
   int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
   if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
   pin_verify = xtrymalloc (len);
   if (!pin_verify)
     return SW_HOST_OUT_OF_CORE;
 
   no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
 
   pin_verify[0] = 0x00; /* bTimeOut */
   pin_verify[1] = 0x00; /* bTimeOut2 */
   pin_verify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
   pin_verify[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_verify[4] = 0x00; /* bmPINLengthFormat */
   pin_verify[5] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_verify[6] = pininfo->minlen; /* wPINMaxExtraDigit */
   pin_verify[7] = 0x02; /* bEntryValidationCondition: Validation key pressed */
   if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
     pin_verify[7] |= 0x01; /* Max size reached.  */
   pin_verify[8] = 0x01; /* bNumberMessage: One message */
   pin_verify[9] =  0x09; /* wLangId: 0x0409: US English */
   pin_verify[10] = 0x04; /* wLangId: 0x0409: US English */
   pin_verify[11] = 0x00; /* bMsgIndex */
   pin_verify[12] = 0x00; /* bTeoPrologue[0] */
   pin_verify[13] = 0x00; /* bTeoPrologue[1] */
   pin_verify[14] = pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
   pin_verify[15] = pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_verify[16] = 0x00; /* ulDataLength */
   pin_verify[17] = 0x00; /* ulDataLength */
   pin_verify[18] = 0x00; /* ulDataLength */
   pin_verify[19] = class; /* abData[0] */
   pin_verify[20] = ins; /* abData[1] */
   pin_verify[21] = p0; /* abData[2] */
   pin_verify[22] = p1; /* abData[3] */
   pin_verify[23] = pininfo->fixedlen; /* abData[4] */
   if (pininfo->fixedlen)
     memset (&pin_verify[24], 0xff, pininfo->fixedlen);
   else if (no_lc)
     len--;
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
                class, ins, p0, p1, len, pininfo->maxlen);
 
   sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
                      pin_verify, len, result, &resultlen);
   xfree (pin_verify);
   if (sw || resultlen < 2)
     {
       log_error ("control_pcsc failed: %d\n", sw);
       return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
     }
   sw = (result[resultlen-2] << 8) | result[resultlen-1];
   if (DBG_CARD_IO)
     log_debug (" response: sw=%04X  datalen=%d\n", sw, (unsigned int)resultlen);
   return sw;
 }
 
 
 #define PIN_MODIFY_STRUCTURE_SIZE 29
 static int
 pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
                     pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_modify;
   int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
   unsigned char result[6];      /* See the comment at pinpad_verify.  */
   pcsc_dword_t resultlen = 6;
   int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
   if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
   pin_modify = xtrymalloc (len);
   if (!pin_modify)
     return SW_HOST_OUT_OF_CORE;
 
   no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
 
   pin_modify[0] = 0x00; /* bTimeOut */
   pin_modify[1] = 0x00; /* bTimeOut2 */
   pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
   pin_modify[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_modify[4] = 0x00; /* bmPINLengthFormat */
   pin_modify[5] = 0x00; /* bInsertionOffsetOld */
   pin_modify[6] = pininfo->fixedlen; /* bInsertionOffsetNew */
   pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
   pin_modify[9] = (p0 == 0 ? 0x03 : 0x01);
                   /* bConfirmPIN
                    *    0x00: new PIN once
                    *    0x01: new PIN twice (confirmation)
                    *    0x02: old PIN and new PIN once
                    *    0x03: old PIN and new PIN twice (confirmation)
                    */
   pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */
   if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
     pin_modify[10] |= 0x01; /* Max size reached.  */
   pin_modify[11] = 0x03; /* bNumberMessage: Three messages */
   pin_modify[12] = 0x09; /* wLangId: 0x0409: US English */
   pin_modify[13] = 0x04; /* wLangId: 0x0409: US English */
   pin_modify[14] = 0x00; /* bMsgIndex1 */
   pin_modify[15] = 0x01; /* bMsgIndex2 */
   pin_modify[16] = 0x02; /* bMsgIndex3 */
   pin_modify[17] = 0x00; /* bTeoPrologue[0] */
   pin_modify[18] = 0x00; /* bTeoPrologue[1] */
   pin_modify[19] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
   pin_modify[20] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_modify[21] = 0x00; /* ulDataLength */
   pin_modify[22] = 0x00; /* ulDataLength */
   pin_modify[23] = 0x00; /* ulDataLength */
   pin_modify[24] = class; /* abData[0] */
   pin_modify[25] = ins; /* abData[1] */
   pin_modify[26] = p0; /* abData[2] */
   pin_modify[27] = p1; /* abData[3] */
   pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */
   if (pininfo->fixedlen)
     memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen);
   else if (no_lc)
     len--;
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
                class, ins, p0, p1, len, (int)pininfo->maxlen);
 
   sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
                      pin_modify, len, result, &resultlen);
   xfree (pin_modify);
   if (sw || resultlen < 2)
     {
       log_error ("control_pcsc failed: %d\n", sw);
       return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
     }
   sw = (result[resultlen-2] << 8) | result[resultlen-1];
   if (DBG_CARD_IO)
     log_debug (" response: sw=%04X  datalen=%d\n", sw, (unsigned int)resultlen);
   return sw;
 }
 
 #ifdef HAVE_LIBUSB
 /*
      Internal CCID driver interface.
  */
 
 
 static void
 dump_ccid_reader_status (int slot)
 {
   log_info ("reader slot %d: using ccid driver\n", slot);
 }
 
 static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
   return 0;
 }
 
 
 static int
 reset_ccid_reader (int slot)
 {
   int err;
   reader_table_t slotp = reader_table + slot;
   unsigned char atr[33];
   size_t atrlen;
 
   err = ccid_get_atr (slotp->ccid.handle, atr, sizeof atr, &atrlen);
   if (err)
     return err;
   /* If the reset was successful, update the ATR. */
   assert (sizeof slotp->atr >= sizeof atr);
   slotp->atrlen = atrlen;
   memcpy (slotp->atr, atr, atrlen);
   dump_reader_status (slot);
   return 0;
 }
 
 
 static int
 set_progress_cb_ccid_reader (int slot, gcry_handler_progress_t cb, void *cb_arg)
 {
   reader_table_t slotp = reader_table + slot;
 
   return ccid_set_progress_cb (slotp->ccid.handle, cb, cb_arg);
 }
 
 static int
 set_prompt_cb_ccid_reader (int slot, void (*cb) (void *, int ), void *cb_arg)
 {
   reader_table_t slotp = reader_table + slot;
 
   return ccid_set_prompt_cb (slotp->ccid.handle, cb, cb_arg);
 }
 
 
 static int
 get_status_ccid (int slot, unsigned int *status, int on_wire)
 {
   int rc;
   int bits;
 
   rc = ccid_slot_status (reader_table[slot].ccid.handle, &bits, on_wire);
   if (rc)
     return rc;
 
   if (bits == 0)
     *status = (APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE);
   else if (bits == 1)
     *status = APDU_CARD_PRESENT;
   else
     *status = 0;
 
   return 0;
 }
 
 
 /* Actually send the APDU of length APDULEN to SLOT and return a
    maximum of *BUFLEN data in BUFFER, the actual returned size will be
    set to BUFLEN.  Returns: Internal CCID driver error code. */
 static int
 send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
                 unsigned char *buffer, size_t *buflen,
                 pininfo_t *pininfo)
 {
   long err;
   size_t maxbuflen;
 
   /* If we don't have an ATR, we need to reset the reader first. */
   if (!reader_table[slot].atrlen
       && (err = reset_ccid_reader (slot)))
     return err;
 
   if (DBG_CARD_IO)
     log_printhex (apdu, apdulen, " raw apdu:");
 
   maxbuflen = *buflen;
   if (pininfo)
     err = ccid_transceive_secure (reader_table[slot].ccid.handle,
                                   apdu, apdulen, pininfo,
                                   buffer, maxbuflen, buflen);
   else
     err = ccid_transceive (reader_table[slot].ccid.handle,
                            apdu, apdulen,
                            buffer, maxbuflen, buflen);
   if (err)
     log_error ("ccid_transceive failed: (0x%lx)\n",
                err);
 
   return err;
 }
 
 
 /* Check whether the CCID reader supports the ISO command code COMMAND
    on the pinpad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 static int
 check_ccid_pinpad (int slot, int command, pininfo_t *pininfo)
 {
   unsigned char apdu[] = { 0, 0, 0, 0x81 };
 
   apdu[1] = command;
   return ccid_transceive_secure (reader_table[slot].ccid.handle, apdu,
                                  sizeof apdu, pininfo, NULL, 0, NULL);
 }
 
 
 static int
 ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1,
                        pininfo_t *pininfo)
 {
   unsigned char apdu[4];
   int err, sw;
   unsigned char result[2];
   size_t resultlen = 2;
 
   apdu[0] = class;
   apdu[1] = ins;
   apdu[2] = p0;
   apdu[3] = p1;
   err = ccid_transceive_secure (reader_table[slot].ccid.handle,
                                 apdu, sizeof apdu, pininfo,
                                 result, 2, &resultlen);
   if (err)
     return err;
 
   if (resultlen < 2)
     return SW_HOST_INCOMPLETE_CARD_RESPONSE;
 
   sw = (result[resultlen-2] << 8) | result[resultlen-1];
   return sw;
 }
 
 
 /* Open the reader and try to read an ATR.  */
 static int
 open_ccid_reader (struct dev_list *dl)
 {
   int err;
   int slot;
   int require_get_status;
   reader_table_t slotp;
 
   slot = new_reader_slot ();
   if (slot == -1)
     return -1;
   slotp = reader_table + slot;
 
   err = ccid_open_reader (dl->portstr, dl->idx, dl->table,
                           &slotp->ccid.handle, &slotp->rdrname);
   if (!err)
     {
       err = ccid_get_atr (slotp->ccid.handle,
                           slotp->atr, sizeof slotp->atr, &slotp->atrlen);
       if (err)
         ccid_close_reader (slotp->ccid.handle);
     }
 
   if (err)
     {
       slotp->used = 0;
       unlock_slot (slot);
       return -1;
     }
 
   require_get_status = ccid_require_get_status (slotp->ccid.handle);
 
   reader_table[slot].close_reader = close_ccid_reader;
   reader_table[slot].reset_reader = reset_ccid_reader;
   reader_table[slot].get_status_reader = get_status_ccid;
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
   reader_table[slot].check_pinpad = check_ccid_pinpad;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
   reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader;
   reader_table[slot].set_prompt_cb = set_prompt_cb_ccid_reader;
   reader_table[slot].pinpad_verify = ccid_pinpad_operation;
   reader_table[slot].pinpad_modify = ccid_pinpad_operation;
   /* Our CCID reader code does not support T=0 at all, thus reset the
      flag.  */
   reader_table[slot].is_t0 = 0;
   reader_table[slot].require_get_status = require_get_status;
 
   dump_reader_status (slot);
   unlock_slot (slot);
   return slot;
 }
 #endif /* HAVE_LIBUSB */
 
 #ifdef USE_G10CODE_RAPDU
 /*
      The Remote APDU Interface.
 
      This uses the Remote APDU protocol to contact a reader.
 
      The port number is actually an index into the list of ports as
      returned via the protocol.
  */
 
 
 static int
 rapdu_status_to_sw (int status)
 {
   int rc;
 
   switch (status)
     {
     case RAPDU_STATUS_SUCCESS:  rc = 0; break;
 
     case RAPDU_STATUS_INVCMD:
     case RAPDU_STATUS_INVPROT:
     case RAPDU_STATUS_INVSEQ:
     case RAPDU_STATUS_INVCOOKIE:
     case RAPDU_STATUS_INVREADER:  rc = SW_HOST_INV_VALUE;  break;
 
     case RAPDU_STATUS_TIMEOUT:  rc = SW_HOST_CARD_IO_ERROR; break;
     case RAPDU_STATUS_CARDIO:   rc = SW_HOST_CARD_IO_ERROR; break;
     case RAPDU_STATUS_NOCARD:   rc = SW_HOST_NO_CARD; break;
     case RAPDU_STATUS_CARDCHG:  rc = SW_HOST_NO_CARD; break;
     case RAPDU_STATUS_BUSY:     rc = SW_HOST_BUSY; break;
     case RAPDU_STATUS_NEEDRESET: rc = SW_HOST_CARD_INACTIVE; break;
 
     default: rc = SW_HOST_GENERAL_ERROR; break;
     }
 
   return rc;
 }
 
 
 
 static int
 close_rapdu_reader (int slot)
 {
   rapdu_release (reader_table[slot].rapdu.handle);
   return 0;
 }
 
 
 static int
 reset_rapdu_reader (int slot)
 {
   int err;
   reader_table_t slotp;
   rapdu_msg_t msg = NULL;
 
   slotp = reader_table + slot;
 
   err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_RESET);
   if (err)
     {
       log_error ("sending rapdu command RESET failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       rapdu_msg_release (msg);
       return rapdu_status_to_sw (err);
     }
   err = rapdu_read_msg (slotp->rapdu.handle, &msg);
   if (err)
     {
       log_error ("receiving rapdu message failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       rapdu_msg_release (msg);
       return rapdu_status_to_sw (err);
     }
   if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
     {
       int sw = rapdu_status_to_sw (msg->cmd);
       log_error ("rapdu command RESET failed: %s\n",
                  rapdu_strerror (msg->cmd));
       rapdu_msg_release (msg);
       return sw;
     }
   if (msg->datalen > DIM (slotp->atr))
     {
       log_error ("ATR returned by the RAPDU layer is too large\n");
       rapdu_msg_release (msg);
       return SW_HOST_INV_VALUE;
     }
   slotp->atrlen = msg->datalen;
   memcpy (slotp->atr, msg->data, msg->datalen);
 
   rapdu_msg_release (msg);
   return 0;
 }
 
 
 static int
 my_rapdu_get_status (int slot, unsigned int *status, int on_wire)
 {
   int err;
   reader_table_t slotp;
   rapdu_msg_t msg = NULL;
   int oldslot;
 
   (void)on_wire;
   slotp = reader_table + slot;
 
   oldslot = rapdu_set_reader (slotp->rapdu.handle, slot);
   err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_GET_STATUS);
   rapdu_set_reader (slotp->rapdu.handle, oldslot);
   if (err)
     {
       log_error ("sending rapdu command GET_STATUS failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       return rapdu_status_to_sw (err);
     }
   err = rapdu_read_msg (slotp->rapdu.handle, &msg);
   if (err)
     {
       log_error ("receiving rapdu message failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       rapdu_msg_release (msg);
       return rapdu_status_to_sw (err);
     }
   if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
     {
       int sw = rapdu_status_to_sw (msg->cmd);
       log_error ("rapdu command GET_STATUS failed: %s\n",
                  rapdu_strerror (msg->cmd));
       rapdu_msg_release (msg);
       return sw;
     }
   *status = msg->data[0];
 
   rapdu_msg_release (msg);
   return 0;
 }
 
 
 /* Actually send the APDU of length APDULEN to SLOT and return a
    maximum of *BUFLEN data in BUFFER, the actual returned size will be
    set to BUFLEN.  Returns: APDU error code. */
 static int
 my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                     unsigned char *buffer, size_t *buflen,
                     pininfo_t *pininfo)
 {
   int err;
   reader_table_t slotp;
   rapdu_msg_t msg = NULL;
   size_t maxlen = *buflen;
 
   slotp = reader_table + slot;
 
   *buflen = 0;
   if (DBG_CARD_IO)
     log_printhex (apdu, apdulen, "  APDU_data:");
 
   if (apdulen < 4)
     {
       log_error ("rapdu_send_apdu: APDU is too short\n");
       return SW_HOST_INV_VALUE;
     }
 
   err = rapdu_send_apdu (slotp->rapdu.handle, apdu, apdulen);
   if (err)
     {
       log_error ("sending rapdu command APDU failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       rapdu_msg_release (msg);
       return rapdu_status_to_sw (err);
     }
   err = rapdu_read_msg (slotp->rapdu.handle, &msg);
   if (err)
     {
       log_error ("receiving rapdu message failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       rapdu_msg_release (msg);
       return rapdu_status_to_sw (err);
     }
   if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
     {
       int sw = rapdu_status_to_sw (msg->cmd);
       log_error ("rapdu command APDU failed: %s\n",
                  rapdu_strerror (msg->cmd));
       rapdu_msg_release (msg);
       return sw;
     }
 
   if (msg->datalen > maxlen)
     {
       log_error ("rapdu response apdu too large\n");
       rapdu_msg_release (msg);
       return SW_HOST_INV_VALUE;
     }
 
   *buflen = msg->datalen;
   memcpy (buffer, msg->data, msg->datalen);
 
   rapdu_msg_release (msg);
   return 0;
 }
 
 static int
 open_rapdu_reader (int portno,
                    const unsigned char *cookie, size_t length,
                    int (*readfnc) (void *opaque,
                                    void *buffer, size_t size),
                    void *readfnc_value,
                    int (*writefnc) (void *opaque,
                                     const void *buffer, size_t size),
                    void *writefnc_value,
                    void (*closefnc) (void *opaque),
                    void *closefnc_value)
 {
   int err;
   int slot;
   reader_table_t slotp;
   rapdu_msg_t msg = NULL;
 
   slot = new_reader_slot ();
   if (slot == -1)
     return -1;
   slotp = reader_table + slot;
 
   slotp->rapdu.handle = rapdu_new ();
   if (!slotp->rapdu.handle)
     {
       slotp->used = 0;
       unlock_slot (slot);
       return -1;
     }
 
   rapdu_set_reader (slotp->rapdu.handle, portno);
 
   rapdu_set_iofunc (slotp->rapdu.handle,
                     readfnc, readfnc_value,
                     writefnc, writefnc_value,
                     closefnc, closefnc_value);
   rapdu_set_cookie (slotp->rapdu.handle, cookie, length);
 
   /* First try to get the current ATR, but if the card is inactive
      issue a reset instead.  */
   err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_GET_ATR);
   if (err == RAPDU_STATUS_NEEDRESET)
     err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_RESET);
   if (err)
     {
       log_info ("sending rapdu command GET_ATR/RESET failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       goto failure;
     }
   err = rapdu_read_msg (slotp->rapdu.handle, &msg);
   if (err)
     {
       log_info ("receiving rapdu message failed: %s\n",
                 err < 0 ? strerror (errno): rapdu_strerror (err));
       goto failure;
     }
   if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
     {
       log_info ("rapdu command GET ATR failed: %s\n",
                  rapdu_strerror (msg->cmd));
       goto failure;
     }
   if (msg->datalen > DIM (slotp->atr))
     {
       log_error ("ATR returned by the RAPDU layer is too large\n");
       goto failure;
     }
   slotp->atrlen = msg->datalen;
   memcpy (slotp->atr, msg->data, msg->datalen);
 
   reader_table[slot].close_reader = close_rapdu_reader;
   reader_table[slot].reset_reader = reset_rapdu_reader;
   reader_table[slot].get_status_reader = my_rapdu_get_status;
   reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
   reader_table[slot].check_pinpad = NULL;
   reader_table[slot].dump_status_reader = NULL;
   reader_table[slot].pinpad_verify = NULL;
   reader_table[slot].pinpad_modify = NULL;
 
   dump_reader_status (slot);
   rapdu_msg_release (msg);
   unlock_slot (slot);
   return slot;
 
  failure:
   rapdu_msg_release (msg);
   rapdu_release (slotp->rapdu.handle);
   slotp->used = 0;
   unlock_slot (slot);
   return -1;
 }
 
 #endif /*USE_G10CODE_RAPDU*/
 
 
 
 /*
        Driver Access
  */
 gpg_error_t
 apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
 {
   struct dev_list *dl = xtrymalloc (sizeof (struct dev_list));
 
   *l_p = NULL;
   if (!dl)
     return gpg_error_from_syserror ();
 
   dl->portstr = portstr;
   dl->idx = 0;
 
   npth_mutex_lock (&reader_table_lock);
 
 #ifdef HAVE_LIBUSB
   if (opt.disable_ccid)
     {
       dl->table = NULL;
       dl->idx_max = 1;
     }
   else
     {
       gpg_error_t err;
 
       err = ccid_dev_scan (&dl->idx_max, &dl->table);
       if (err)
         return err;
 
       if (dl->idx_max == 0)
         {
           /* If a CCID reader specification has been given, the user does
              not want a fallback to other drivers. */
           if (portstr && strlen (portstr) > 5 && portstr[4] == ':')
             {
               if (DBG_READER)
                 log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
 
               xfree (dl);
               npth_mutex_unlock (&reader_table_lock);
               return gpg_error (GPG_ERR_ENODEV);
             }
           else
             dl->idx_max = 1;
         }
     }
 #else
   dl->table = NULL;
   dl->idx_max = 1;
 #endif /* HAVE_LIBUSB */
 
   *l_p = dl;
   return 0;
 }
 
 void
 apdu_dev_list_finish (struct dev_list *dl)
 {
 #ifdef HAVE_LIBUSB
   if (dl->table)
     ccid_dev_scan_finish (dl->table, dl->idx_max);
 #endif
   xfree (dl);
   npth_mutex_unlock (&reader_table_lock);
 }
 
 
 /* Open the reader and return an internal slot number or -1 on
    error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
    the first USB reader.  For PC/SC the first listed reader). */
 static int
 apdu_open_one_reader (const char *portstr)
 {
   static int pcsc_api_loaded;
   int slot;
 
   if (DBG_READER)
     log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
 
   /* Lets try the PC/SC API */
   if (!pcsc_api_loaded)
     {
       void *handle;
 
       handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
       if (!handle)
         {
           log_error ("apdu_open_reader: failed to open driver '%s': %s\n",
                      opt.pcsc_driver, dlerror ());
           return -1;
         }
 
       pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
       pcsc_release_context   = dlsym (handle, "SCardReleaseContext");
       pcsc_list_readers      = dlsym (handle, "SCardListReaders");
 #if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_list_readers)
         pcsc_list_readers    = dlsym (handle, "SCardListReadersA");
 #endif
       pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
 #if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_get_status_change)
         pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
 #endif
       pcsc_connect           = dlsym (handle, "SCardConnect");
 #if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_connect)
         pcsc_connect         = dlsym (handle, "SCardConnectA");
 #endif
       pcsc_reconnect         = dlsym (handle, "SCardReconnect");
 #if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_reconnect)
         pcsc_reconnect       = dlsym (handle, "SCardReconnectA");
 #endif
       pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
       pcsc_status            = dlsym (handle, "SCardStatus");
 #if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_status)
         pcsc_status          = dlsym (handle, "SCardStatusA");
 #endif
       pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
       pcsc_end_transaction   = dlsym (handle, "SCardEndTransaction");
       pcsc_transmit          = dlsym (handle, "SCardTransmit");
       pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
       pcsc_control           = dlsym (handle, "SCardControl");
 
       if (!pcsc_establish_context
           || !pcsc_release_context
           || !pcsc_list_readers
           || !pcsc_get_status_change
           || !pcsc_connect
           || !pcsc_reconnect
           || !pcsc_disconnect
           || !pcsc_status
           || !pcsc_begin_transaction
           || !pcsc_end_transaction
           || !pcsc_transmit
           || !pcsc_control
           /* || !pcsc_set_timeout */)
         {
           /* Note that set_timeout is currently not used and also not
              available under Windows. */
           log_error ("apdu_open_reader: invalid PC/SC driver "
                      "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
                      !!pcsc_establish_context,
                      !!pcsc_release_context,
                      !!pcsc_list_readers,
                      !!pcsc_get_status_change,
                      !!pcsc_connect,
                      !!pcsc_reconnect,
                      !!pcsc_disconnect,
                      !!pcsc_status,
                      !!pcsc_begin_transaction,
                      !!pcsc_end_transaction,
                      !!pcsc_transmit,
                      !!pcsc_set_timeout,
                      !!pcsc_control );
           dlclose (handle);
           return -1;
         }
       pcsc_api_loaded = 1;
     }
 
   slot = open_pcsc_reader (portstr);
 
   if (DBG_READER)
     log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
   return slot;
 }
 
 int
 apdu_open_reader (struct dev_list *dl, int app_empty)
 {
   int slot;
 
 #ifdef HAVE_LIBUSB
   if (dl->table)
     { /* CCID readers.  */
       int readerno;
 
       /* See whether we want to use the reader ID string or a reader
          number. A readerno of -1 indicates that the reader ID string is
          to be used. */
       if (dl->portstr && strchr (dl->portstr, ':'))
         readerno = -1; /* We want to use the readerid.  */
       else if (dl->portstr)
         {
           readerno = atoi (dl->portstr);
           if (readerno < 0)
             {
               return -1;
             }
         }
       else
         readerno = 0;  /* Default. */
 
       if (readerno > 0)
         { /* Use single, the specific reader.  */
           if (readerno >= dl->idx_max)
             return -1;
 
           dl->idx = readerno;
           dl->portstr = NULL;
           slot = open_ccid_reader (dl);
           dl->idx = dl->idx_max;
           if (slot >= 0)
             return slot;
           else
             return -1;
         }
 
       while (dl->idx < dl->idx_max)
         {
           unsigned int bai = ccid_get_BAI (dl->idx, dl->table);
 
           if (DBG_READER)
             log_debug ("apdu_open_reader: BAI=%x\n", bai);
 
           /* Check identity by BAI against already opened HANDLEs.  */
           for (slot = 0; slot < MAX_READER; slot++)
             if (reader_table[slot].used
                 && reader_table[slot].ccid.handle
                 && ccid_compare_BAI (reader_table[slot].ccid.handle, bai))
               break;
 
           if (slot == MAX_READER)
             { /* Found a new device.  */
               if (DBG_READER)
                 log_debug ("apdu_open_reader: new device=%x\n", bai);
 
               slot = open_ccid_reader (dl);
 
               dl->idx++;
               if (slot >= 0)
                 return slot;
               else
                 {
                   /* Skip this reader.  */
                   log_error ("ccid open error: skip\n");
                   continue;
                 }
             }
           else
             dl->idx++;
         }
 
       /* Not found.  Try one for PC/SC, only when it's the initial scan.  */
       if (app_empty && dl->idx == dl->idx_max)
         {
           dl->idx++;
           slot = apdu_open_one_reader (dl->portstr);
         }
       else
         slot = -1;
     }
   else
 #endif
     { /* PC/SC readers.  */
       if (app_empty && dl->idx == 0)
         {
           dl->idx++;
           slot = apdu_open_one_reader (dl->portstr);
         }
       else
         slot = -1;
     }
 
   return slot;
 }
 
 
 /* Open an remote reader and return an internal slot number or -1 on
    error. This function is an alternative to apdu_open_reader and used
    with remote readers only.  Note that the supplied CLOSEFNC will
    only be called once and the slot will not be valid afther this.
 
    If PORTSTR is NULL we default to the first available port.
 */
 int
 apdu_open_remote_reader (const char *portstr,
                          const unsigned char *cookie, size_t length,
                          int (*readfnc) (void *opaque,
                                          void *buffer, size_t size),
                          void *readfnc_value,
                          int (*writefnc) (void *opaque,
                                           const void *buffer, size_t size),
                          void *writefnc_value,
                          void (*closefnc) (void *opaque),
                          void *closefnc_value)
 {
 #ifdef USE_G10CODE_RAPDU
   return open_rapdu_reader (portstr? atoi (portstr) : 0,
                             cookie, length,
                             readfnc, readfnc_value,
                             writefnc, writefnc_value,
                             closefnc, closefnc_value);
 #else
   (void)portstr;
   (void)cookie;
   (void)length;
   (void)readfnc;
   (void)readfnc_value;
   (void)writefnc;
   (void)writefnc_value;
   (void)closefnc;
   (void)closefnc_value;
 #ifdef _WIN32
   errno = ENOENT;
 #else
   errno = ENOSYS;
 #endif
   return -1;
 #endif
 }
 
 
 int
 apdu_close_reader (int slot)
 {
   int sw;
 
   if (DBG_READER)
     log_debug ("enter: apdu_close_reader: slot=%d\n", slot);
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     {
       if (DBG_READER)
         log_debug ("leave: apdu_close_reader => SW_HOST_NO_DRIVER\n");
       return SW_HOST_NO_DRIVER;
     }
   sw = apdu_disconnect (slot);
   if (sw)
     {
       /*
        * When the reader/token was removed it might come here.
        * It should go through to call CLOSE_READER even if we got an error.
        */
       if (DBG_READER)
         log_debug ("apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
     }
   if (reader_table[slot].close_reader)
     {
       sw = reader_table[slot].close_reader (slot);
       reader_table[slot].used = 0;
       if (DBG_READER)
         log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
       return sw;
     }
   xfree (reader_table[slot].rdrname);
   reader_table[slot].rdrname = NULL;
   reader_table[slot].used = 0;
   if (DBG_READER)
     log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
   return SW_HOST_NOT_SUPPORTED;
 }
 
 
 /* Function suitable for a cleanup function to close all reader.  It
    should not be used if the reader will be opened again.  The reason
    for implementing this to properly close USB devices so that they
    will startup the next time without error. */
 void
 apdu_prepare_exit (void)
 {
   static int sentinel;
   int slot;
 
   if (!sentinel)
     {
       sentinel = 1;
       npth_mutex_lock (&reader_table_lock);
       for (slot = 0; slot < MAX_READER; slot++)
         if (reader_table[slot].used)
           {
             apdu_disconnect (slot);
             if (reader_table[slot].close_reader)
               reader_table[slot].close_reader (slot);
             xfree (reader_table[slot].rdrname);
             reader_table[slot].rdrname = NULL;
             reader_table[slot].used = 0;
           }
       npth_mutex_unlock (&reader_table_lock);
       sentinel = 0;
     }
 }
 
 
 /* Enumerate all readers and return information on whether this reader
    is in use.  The caller should start with SLOT set to 0 and
    increment it with each call until an error is returned. */
 int
 apdu_enum_reader (int slot, int *used)
 {
   if (slot < 0 || slot >= MAX_READER)
     return SW_HOST_NO_DRIVER;
   *used = reader_table[slot].used;
   return 0;
 }
 
 
 /* Connect a card.  This is used to power up the card and make sure
    that an ATR is available.  Depending on the reader backend it may
    return an error for an inactive card or if no card is available.
    Return -1 on error.  Return 1 if reader requires get_status to
    watch card removal.  Return 0 if it's a token (always with a card),
    or it supports INTERRUPT endpoint to watch card removal.
   */
 int
 apdu_connect (int slot)
 {
   int sw = 0;
   unsigned int status = 0;
 
   if (DBG_READER)
     log_debug ("enter: apdu_connect: slot=%d\n", slot);
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     {
       if (DBG_READER)
         log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
       return -1;
     }
 
   /* Only if the access method provides a connect function we use it.
      If not, we expect that the card has been implicitly connected by
      apdu_open_reader.  */
   if (reader_table[slot].connect_card)
     {
       sw = lock_slot (slot);
       if (!sw)
         {
           sw = reader_table[slot].connect_card (slot);
           unlock_slot (slot);
         }
     }
 
   /* We need to call apdu_get_status_internal, so that the last-status
      machinery gets setup properly even if a card is inserted while
      scdaemon is fired up and apdu_get_status has not yet been called.
      Without that we would force a reset of the card with the next
      call to apdu_get_status.  */
   if (!sw)
     sw = apdu_get_status_internal (slot, 1, &status, 1);
 
   if (sw)
     ;
   else if (!(status & APDU_CARD_PRESENT))
     sw = SW_HOST_NO_CARD;
   else if ((status & APDU_CARD_PRESENT) && !(status & APDU_CARD_ACTIVE))
     sw = SW_HOST_CARD_INACTIVE;
 
   if (sw == SW_HOST_CARD_INACTIVE)
     {
       /* Try power it up again.  */
       sw = apdu_reset (slot);
     }
 
   if (DBG_READER)
     log_debug ("leave: apdu_connect => sw=0x%x\n", sw);
 
   if (sw)
     return -1;
 
   return reader_table[slot].require_get_status;
 }
 
 
 int
 apdu_disconnect (int slot)
 {
   int sw;
 
   if (DBG_READER)
     log_debug ("enter: apdu_disconnect: slot=%d\n", slot);
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     {
       if (DBG_READER)
         log_debug ("leave: apdu_disconnect => SW_HOST_NO_DRIVER\n");
       return SW_HOST_NO_DRIVER;
     }
 
   if (reader_table[slot].disconnect_card)
     {
       sw = lock_slot (slot);
       if (!sw)
         {
           sw = reader_table[slot].disconnect_card (slot);
           unlock_slot (slot);
         }
     }
   else
     sw = 0;
 
   if (DBG_READER)
     log_debug ("leave: apdu_disconnect => sw=0x%x\n", sw);
   return sw;
 }
 
 
 /* Set the progress callback of SLOT to CB and its args to CB_ARG.  If
    CB is NULL the progress callback is removed.  */
 int
 apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg)
 {
   int sw;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (reader_table[slot].set_progress_cb)
     {
       sw = lock_slot (slot);
       if (!sw)
         {
           sw = reader_table[slot].set_progress_cb (slot, cb, cb_arg);
           unlock_slot (slot);
         }
     }
   else
     sw = 0;
   return sw;
 }
 
 
 int
 apdu_set_prompt_cb (int slot, void (*cb) (void *, int), void *cb_arg)
 {
   int sw;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (reader_table[slot].set_prompt_cb)
     {
       sw = lock_slot (slot);
       if (!sw)
         {
           sw = reader_table[slot].set_prompt_cb (slot, cb, cb_arg);
           unlock_slot (slot);
         }
     }
   else
     sw = 0;
   return sw;
 }
 
 
 /* Do a reset for the card in reader at SLOT. */
 int
 apdu_reset (int slot)
 {
   int sw;
 
   if (DBG_READER)
     log_debug ("enter: apdu_reset: slot=%d\n", slot);
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     {
       if (DBG_READER)
         log_debug ("leave: apdu_reset => SW_HOST_NO_DRIVER\n");
       return SW_HOST_NO_DRIVER;
     }
 
   if ((sw = lock_slot (slot)))
     {
       if (DBG_READER)
         log_debug ("leave: apdu_reset => sw=0x%x (lock_slot)\n", sw);
       return sw;
     }
 
   if (reader_table[slot].reset_reader)
     sw = reader_table[slot].reset_reader (slot);
 
   unlock_slot (slot);
   if (DBG_READER)
     log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
   return sw;
 }
 
 
 /* Return the ATR or NULL if none is available.  On success the length
    of the ATR is stored at ATRLEN.  The caller must free the returned
    value.  */
 unsigned char *
 apdu_get_atr (int slot, size_t *atrlen)
 {
   unsigned char *buf;
 
   if (DBG_READER)
     log_debug ("enter: apdu_get_atr: slot=%d\n", slot);
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     {
       if (DBG_READER)
         log_debug ("leave: apdu_get_atr => NULL (bad slot)\n");
       return NULL;
     }
   if (!reader_table[slot].atrlen)
     {
       if (DBG_READER)
         log_debug ("leave: apdu_get_atr => NULL (no ATR)\n");
       return NULL;
     }
 
   buf = xtrymalloc (reader_table[slot].atrlen);
   if (!buf)
     {
       if (DBG_READER)
         log_debug ("leave: apdu_get_atr => NULL (out of core)\n");
       return NULL;
     }
   memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
   *atrlen = reader_table[slot].atrlen;
   if (DBG_READER)
     log_debug ("leave: apdu_get_atr => atrlen=%zu\n", *atrlen);
   return buf;
 }
 
 
 
 /* Retrieve the status for SLOT. The function does only wait for the
    card to become available if HANG is set to true. On success the
    bits in STATUS will be set to
 
      APDU_CARD_USABLE  (bit 0) = card present and usable
      APDU_CARD_PRESENT (bit 1) = card present
      APDU_CARD_ACTIVE  (bit 2) = card active
                        (bit 3) = card access locked [not yet implemented]
 
    For most applications, testing bit 0 is sufficient.
 */
 static int
 apdu_get_status_internal (int slot, int hang, unsigned int *status, int on_wire)
 {
   int sw;
   unsigned int s = 0;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if ((sw = hang? lock_slot (slot) : trylock_slot (slot)))
     return sw;
 
   if (reader_table[slot].get_status_reader)
     sw = reader_table[slot].get_status_reader (slot, &s, on_wire);
 
   unlock_slot (slot);
 
   if (sw)
     {
       if (on_wire)
         reader_table[slot].atrlen = 0;
       s = 0;
     }
 
   if (status)
     *status = s;
   return sw;
 }
 
 
 /* See above for a description.  */
 int
 apdu_get_status (int slot, int hang, unsigned int *status)
 {
   int sw;
 
   if (DBG_READER)
     log_debug ("enter: apdu_get_status: slot=%d hang=%d\n", slot, hang);
   sw = apdu_get_status_internal (slot, hang, status, 0);
   if (DBG_READER)
     {
       if (status)
         log_debug ("leave: apdu_get_status => sw=0x%x status=%u\n",
                    sw, *status);
       else
         log_debug ("leave: apdu_get_status => sw=0x%x\n", sw);
     }
   return sw;
 }
 
 
 /* Check whether the reader supports the ISO command code COMMAND on
    the pinpad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 int
 apdu_check_pinpad (int slot, int command, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (opt.enable_pinpad_varlen)
     pininfo->fixedlen = 0;
 
   if (reader_table[slot].check_pinpad)
     {
       int sw;
 
       if ((sw = lock_slot (slot)))
         return sw;
 
       sw = reader_table[slot].check_pinpad (slot, command, pininfo);
       unlock_slot (slot);
       return sw;
     }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 int
 apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
                     pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (reader_table[slot].pinpad_verify)
     {
       int sw;
 
       if ((sw = lock_slot (slot)))
         return sw;
 
       sw = reader_table[slot].pinpad_verify (slot, class, ins, p0, p1,
                                              pininfo);
       unlock_slot (slot);
       return sw;
     }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 int
 apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1,
                     pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (reader_table[slot].pinpad_modify)
     {
       int sw;
 
       if ((sw = lock_slot (slot)))
         return sw;
 
       sw = reader_table[slot].pinpad_modify (slot, class, ins, p0, p1,
                                              pininfo);
       unlock_slot (slot);
       return sw;
     }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 /* Dispatcher for the actual send_apdu function. Note, that this
    function should be called in locked state. */
 static int
 send_apdu (int slot, unsigned char *apdu, size_t apdulen,
            unsigned char *buffer, size_t *buflen, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (reader_table[slot].send_apdu_reader)
     return reader_table[slot].send_apdu_reader (slot,
                                                 apdu, apdulen,
                                                 buffer, buflen,
                                                 pininfo);
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 /* Core APDU tranceiver function. Parameters are described at
    apdu_send_le with the exception of PININFO which indicates pinpad
    related operations if not NULL.  If EXTENDED_MODE is not 0
    command chaining or extended length will be used according to these
    values:
        n < 0 := Use command chaining with the data part limited to -n
                 in each chunk.  If -1 is used a default value is used.
       n == 0 := No extended mode or command chaining.
       n == 1 := Use extended length for input and output without a
                 length limit.
        n > 1 := Use extended length with up to N bytes.
 
 */
 static int
 send_le (int slot, int class, int ins, int p0, int p1,
          int lc, const char *data, int le,
          unsigned char **retbuf, size_t *retbuflen,
          pininfo_t *pininfo, int extended_mode)
 {
 #define SHORT_RESULT_BUFFER_SIZE 258
   /* We allocate 8 extra bytes as a safety margin towards a driver bug.  */
   unsigned char short_result_buffer[SHORT_RESULT_BUFFER_SIZE+10];
   unsigned char *result_buffer = NULL;
   size_t result_buffer_size;
   unsigned char *result;
   size_t resultlen;
   unsigned char short_apdu_buffer[5+256+1];
   unsigned char *apdu_buffer = NULL;
   size_t apdu_buffer_size;
   unsigned char *apdu;
   size_t apdulen;
   int sw;
   long rc; /* We need a long here due to PC/SC. */
   int did_exact_length_hack = 0;
   int use_chaining = 0;
   int use_extended_length = 0;
   int lc_chunk;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (DBG_CARD_IO)
     log_debug ("send apdu: c=%02X i=%02X p1=%02X p2=%02X lc=%d le=%d em=%d\n",
                class, ins, p0, p1, lc, le, extended_mode);
 
   if (lc != -1 && (lc > 255 || lc < 0))
     {
       /* Data does not fit into an APDU.  What we do now depends on
          the EXTENDED_MODE parameter.  */
       if (!extended_mode)
         return SW_WRONG_LENGTH; /* No way to send such an APDU.  */
       else if (extended_mode > 0)
         use_extended_length = 1;
       else if (extended_mode < 0)
         {
           /* Send APDU using chaining mode.  */
           if (lc > 16384)
             return SW_WRONG_LENGTH;   /* Sanity check.  */
           if ((class&0xf0) != 0)
             return SW_HOST_INV_VALUE; /* Upper 4 bits need to be 0.  */
           use_chaining = extended_mode == -1? 255 : -extended_mode;
           use_chaining &= 0xff;
         }
       else
         return SW_HOST_INV_VALUE;
     }
   else if (lc == -1 && extended_mode > 0)
     use_extended_length = 1;
 
   if (le != -1 && (le > (extended_mode > 0? 255:256) || le < 0))
     {
       /* Expected Data does not fit into an APDU.  What we do now
          depends on the EXTENDED_MODE parameter.  Note that a check
          for command chaining does not make sense because we are
          looking at Le.  */
       if (!extended_mode)
         return SW_WRONG_LENGTH; /* No way to send such an APDU.  */
       else if (use_extended_length)
         ; /* We are already using extended length.  */
       else if (extended_mode > 0)
         use_extended_length = 1;
       else
         return SW_HOST_INV_VALUE;
     }
 
   if ((!data && lc != -1) || (data && lc == -1))
     return SW_HOST_INV_VALUE;
 
   if (use_extended_length)
     {
       if (reader_table[slot].is_t0)
         return SW_HOST_NOT_SUPPORTED;
 
       /* Space for: cls/ins/p1/p2+Z+2_byte_Lc+Lc+2_byte_Le.  */
       apdu_buffer_size = 4 + 1 + (lc >= 0? (2+lc):0) + 2;
       apdu_buffer = xtrymalloc (apdu_buffer_size + 10);
       if (!apdu_buffer)
         return SW_HOST_OUT_OF_CORE;
       apdu = apdu_buffer;
     }
   else
     {
       apdu_buffer_size = sizeof short_apdu_buffer;
       apdu = short_apdu_buffer;
     }
 
   if (use_extended_length && (le > 256 || le < 0))
     {
       /* Two more bytes are needed for status bytes.  */
       result_buffer_size = le < 0? 4096 : (le + 2);
       result_buffer = xtrymalloc (result_buffer_size);
       if (!result_buffer)
         {
           xfree (apdu_buffer);
           return SW_HOST_OUT_OF_CORE;
         }
       result = result_buffer;
     }
   else
     {
       result_buffer_size = SHORT_RESULT_BUFFER_SIZE;
       result = short_result_buffer;
     }
 #undef SHORT_RESULT_BUFFER_SIZE
 
   if ((sw = lock_slot (slot)))
     {
       xfree (apdu_buffer);
       xfree (result_buffer);
       return sw;
     }
 
   do
     {
       if (use_extended_length)
         {
           use_chaining = 0;
           apdulen = 0;
           apdu[apdulen++] = class;
           apdu[apdulen++] = ins;
           apdu[apdulen++] = p0;
           apdu[apdulen++] = p1;
           if (lc > 0)
             {
               apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((lc >> 8) & 0xff);
               apdu[apdulen++] = (lc & 0xff);
               memcpy (apdu+apdulen, data, lc);
               data += lc;
               apdulen += lc;
             }
           if (le != -1)
             {
               if (lc <= 0)
                 apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((le >> 8) & 0xff);
               apdu[apdulen++] = (le & 0xff);
             }
         }
       else
         {
           apdulen = 0;
           apdu[apdulen] = class;
           if (use_chaining && lc > 255)
             {
               apdu[apdulen] |= 0x10;
               assert (use_chaining < 256);
               lc_chunk = use_chaining;
               lc -= use_chaining;
             }
           else
             {
               use_chaining = 0;
               lc_chunk = lc;
             }
           apdulen++;
           apdu[apdulen++] = ins;
           apdu[apdulen++] = p0;
           apdu[apdulen++] = p1;
           if (lc_chunk != -1)
             {
               apdu[apdulen++] = lc_chunk;
               memcpy (apdu+apdulen, data, lc_chunk);
               data += lc_chunk;
               apdulen += lc_chunk;
               /* T=0 does not allow the use of Lc together with Le;
                  thus disable Le in this case.  */
               if (reader_table[slot].is_t0)
                 le = -1;
             }
           if (le != -1 && !use_chaining)
             apdu[apdulen++] = le; /* Truncation is okay (0 means 256). */
         }
 
     exact_length_hack:
       /* As a safeguard don't pass any garbage to the driver.  */
       assert (apdulen <= apdu_buffer_size);
       memset (apdu+apdulen, 0, apdu_buffer_size - apdulen);
       resultlen = result_buffer_size;
       rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
       if (rc || resultlen < 2)
         {
           log_info ("apdu_send_simple(%d) failed: %s\n",
                     slot, apdu_strerror (rc));
           unlock_slot (slot);
           xfree (apdu_buffer);
           xfree (result_buffer);
           return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
         }
       sw = (result[resultlen-2] << 8) | result[resultlen-1];
       if (!use_extended_length
           && !did_exact_length_hack && SW_EXACT_LENGTH_P (sw))
         {
           apdu[apdulen-1] = (sw & 0x00ff);
           did_exact_length_hack = 1;
           goto exact_length_hack;
         }
     }
   while (use_chaining && sw == SW_SUCCESS);
 
   if (apdu_buffer)
     {
       xfree (apdu_buffer);
       apdu_buffer = NULL;
     }
 
   /* Store away the returned data but strip the statusword. */
   resultlen -= 2;
   if (DBG_CARD_IO)
     {
       log_debug (" response: sw=%04X  datalen=%d\n",
                  sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
         log_printhex (result, resultlen, "    dump: ");
     }
 
   if (sw == SW_SUCCESS || sw == SW_EOF_REACHED)
     {
       if (retbuf)
         {
           *retbuf = xtrymalloc (resultlen? resultlen : 1);
           if (!*retbuf)
             {
               unlock_slot (slot);
               xfree (result_buffer);
               return SW_HOST_OUT_OF_CORE;
             }
           *retbuflen = resultlen;
           memcpy (*retbuf, result, resultlen);
         }
     }
   else if ((sw & 0xff00) == SW_MORE_DATA)
     {
       unsigned char *p = NULL, *tmp;
       size_t bufsize = 4096;
 
       /* It is likely that we need to return much more data, so we
          start off with a large buffer. */
       if (retbuf)
         {
           *retbuf = p = xtrymalloc (bufsize);
           if (!*retbuf)
             {
               unlock_slot (slot);
               xfree (result_buffer);
               return SW_HOST_OUT_OF_CORE;
             }
           assert (resultlen < bufsize);
           memcpy (p, result, resultlen);
           p += resultlen;
         }
 
       do
         {
           int len = (sw & 0x00ff);
 
           if (DBG_CARD_IO)
             log_debug ("apdu_send_simple(%d): %d more bytes available\n",
                        slot, len);
           apdu_buffer_size = sizeof short_apdu_buffer;
           apdu = short_apdu_buffer;
           apdulen = 0;
           apdu[apdulen++] = class;
           apdu[apdulen++] = 0xC0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = len;
           assert (apdulen <= apdu_buffer_size);
           memset (apdu+apdulen, 0, apdu_buffer_size - apdulen);
           resultlen = result_buffer_size;
           rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
           if (rc || resultlen < 2)
             {
               log_error ("apdu_send_simple(%d) for get response failed: %s\n",
                          slot, apdu_strerror (rc));
               unlock_slot (slot);
               xfree (result_buffer);
               return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
             }
           sw = (result[resultlen-2] << 8) | result[resultlen-1];
           resultlen -= 2;
           if (DBG_CARD_IO)
             {
               log_debug ("     more: sw=%04X  datalen=%d\n",
                          sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
                 log_printhex (result, resultlen, "     dump: ");
             }
 
           if ((sw & 0xff00) == SW_MORE_DATA
               || sw == SW_SUCCESS
               || sw == SW_EOF_REACHED )
             {
               if (retbuf && resultlen)
                 {
                   if (p - *retbuf + resultlen > bufsize)
                     {
                       bufsize += resultlen > 4096? resultlen: 4096;
                       tmp = xtryrealloc (*retbuf, bufsize);
                       if (!tmp)
                         {
                           unlock_slot (slot);
                           xfree (result_buffer);
                           return SW_HOST_OUT_OF_CORE;
                         }
                       p = tmp + (p - *retbuf);
                       *retbuf = tmp;
                     }
                   memcpy (p, result, resultlen);
                   p += resultlen;
                 }
             }
           else
             log_info ("apdu_send_simple(%d) "
                       "got unexpected status %04X from get response\n",
                       slot, sw);
         }
       while ((sw & 0xff00) == SW_MORE_DATA);
 
       if (retbuf)
         {
           *retbuflen = p - *retbuf;
           tmp = xtryrealloc (*retbuf, *retbuflen);
           if (tmp)
             *retbuf = tmp;
         }
     }
 
   unlock_slot (slot);
   xfree (result_buffer);
 
   if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
     log_printhex (*retbuf, *retbuflen, "      dump: ");
 
   return sw;
 }
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
    given parameters: CLASS, INS, P0, P1, LC, DATA, LE.  A value of -1
    for LC won't sent this field and the data field; in this case DATA
    must also be passed as NULL.  If EXTENDED_MODE is not 0 command
    chaining or extended length will be used; see send_le for details.
    The return value is the status word or -1 for an invalid SLOT or
    other non card related error.  If RETBUF is not NULL, it will
    receive an allocated buffer with the returned data.  The length of
    that data will be put into *RETBUFLEN.  The caller is responsible
    for releasing the buffer even in case of errors.  */
 int
 apdu_send_le(int slot, int extended_mode,
              int class, int ins, int p0, int p1,
              int lc, const char *data, int le,
              unsigned char **retbuf, size_t *retbuflen)
 {
   return send_le (slot, class, ins, p0, p1,
                   lc, data, le,
                   retbuf, retbuflen,
                   NULL, extended_mode);
 }
 
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
    given parameters: CLASS, INS, P0, P1, LC, DATA.  A value of -1 for
    LC won't sent this field and the data field; in this case DATA must
    also be passed as NULL.  If EXTENDED_MODE is not 0 command chaining
    or extended length will be used; see send_le for details.  The
    return value is the status word or -1 for an invalid SLOT or other
    non card related error.  If RETBUF is not NULL, it will receive an
    allocated buffer with the returned data.  The length of that data
    will be put into *RETBUFLEN.  The caller is responsible for
    releasing the buffer even in case of errors.  */
 int
 apdu_send (int slot, int extended_mode,
            int class, int ins, int p0, int p1,
            int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
 {
   return send_le (slot, class, ins, p0, p1, lc, data, 256,
                   retbuf, retbuflen, NULL, extended_mode);
 }
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
    given parameters: CLASS, INS, P0, P1, LC, DATA.  A value of -1 for
    LC won't sent this field and the data field; in this case DATA must
    also be passed as NULL.  If EXTENDED_MODE is not 0 command chaining
    or extended length will be used; see send_le for details.  The
    return value is the status word or -1 for an invalid SLOT or other
    non card related error.  No data will be returned.  */
 int
 apdu_send_simple (int slot, int extended_mode,
                   int class, int ins, int p0, int p1,
                   int lc, const char *data)
 {
   return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL,
                   extended_mode);
 }
 
 
 /* This is a more generic version of the apdu sending routine.  It
  * takes an already formatted APDU in APDUDATA or length APDUDATALEN
  * and returns with an APDU including the status word.  With
  * HANDLE_MORE set to true this function will handle the MORE DATA
  * status and return all APDUs concatenated with one status word at
  * the end.  If EXTENDED_LENGTH is != 0 extended lengths are allowed
  * with a max. result data length of EXTENDED_LENGTH bytes.  The
  * function does not return a regular status word but 0 on success.
  * If the slot is locked, the function returns immediately with an
  * error.
  *
  * Out of historical reasons the function returns 0 on success and
  * outs the status word at the end of the result to be able to get the
  * status word in the case of a not provided RETBUF, R_SW can be used
  * to store the SW.  But note that R_SW qill only be set if the
  * function returns 0. */
 int
 apdu_send_direct (int slot, size_t extended_length,
                   const unsigned char *apdudata, size_t apdudatalen,
                   int handle_more, unsigned int *r_sw,
                   unsigned char **retbuf, size_t *retbuflen)
 {
 #define SHORT_RESULT_BUFFER_SIZE 258
   unsigned char short_result_buffer[SHORT_RESULT_BUFFER_SIZE+10];
   unsigned char *result_buffer = NULL;
   size_t result_buffer_size;
   unsigned char *result;
   size_t resultlen;
   unsigned char short_apdu_buffer[5+256+10];
   unsigned char *apdu_buffer = NULL;
   unsigned char *apdu;
   size_t apdulen;
   int sw;
   long rc; /* we need a long here due to PC/SC. */
   int class;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
   if (apdudatalen > 65535)
     return SW_HOST_INV_VALUE;
 
   if (apdudatalen > sizeof short_apdu_buffer - 5)
     {
       apdu_buffer = xtrymalloc (apdudatalen + 5);
       if (!apdu_buffer)
         return SW_HOST_OUT_OF_CORE;
       apdu = apdu_buffer;
     }
   else
     {
       apdu = short_apdu_buffer;
     }
   apdulen = apdudatalen;
   memcpy (apdu, apdudata, apdudatalen);
   class = apdulen? *apdu : 0;
 
   if (extended_length >= 256 && extended_length <= 65536)
     {
       result_buffer_size = extended_length;
       result_buffer = xtrymalloc (result_buffer_size + 10);
       if (!result_buffer)
         {
           xfree (apdu_buffer);
           return SW_HOST_OUT_OF_CORE;
         }
       result = result_buffer;
     }
   else
     {
       result_buffer_size = SHORT_RESULT_BUFFER_SIZE;
       result = short_result_buffer;
     }
 #undef SHORT_RESULT_BUFFER_SIZE
 
   if ((sw = trylock_slot (slot)))
     {
       xfree (apdu_buffer);
       xfree (result_buffer);
       return sw;
     }
 
   resultlen = result_buffer_size;
   rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
   xfree (apdu_buffer);
   apdu_buffer = NULL;
   if (rc || resultlen < 2)
     {
       log_error ("apdu_send_direct(%d) failed: %s\n",
                  slot, apdu_strerror (rc));
       unlock_slot (slot);
       xfree (result_buffer);
       return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
     }
   sw = (result[resultlen-2] << 8) | result[resultlen-1];
   /* Store away the returned data but strip the statusword. */
   resultlen -= 2;
   if (DBG_CARD_IO)
     {
       log_debug (" response: sw=%04X  datalen=%d\n",
                  sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
         log_printhex (result, resultlen, "     dump: ");
     }
 
   if (handle_more && (sw & 0xff00) == SW_MORE_DATA)
     {
       unsigned char *p = NULL, *tmp;
       size_t bufsize = 4096;
 
       /* It is likely that we need to return much more data, so we
          start off with a large buffer. */
       if (retbuf)
         {
           *retbuf = p = xtrymalloc (bufsize + 2);
           if (!*retbuf)
             {
               unlock_slot (slot);
               xfree (result_buffer);
               return SW_HOST_OUT_OF_CORE;
             }
           assert (resultlen < bufsize);
           memcpy (p, result, resultlen);
           p += resultlen;
         }
 
       do
         {
           int len = (sw & 0x00ff);
 
           if (DBG_CARD_IO)
             log_debug ("apdu_send_direct(%d): %d more bytes available\n",
                        slot, len);
           apdu = short_apdu_buffer;
           apdulen = 0;
           apdu[apdulen++] = class;
           apdu[apdulen++] = 0xC0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = len;
           memset (apdu+apdulen, 0, sizeof (short_apdu_buffer) - apdulen);
           resultlen = result_buffer_size;
           rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
           if (rc || resultlen < 2)
             {
               log_error ("apdu_send_direct(%d) for get response failed: %s\n",
                          slot, apdu_strerror (rc));
               unlock_slot (slot);
               xfree (result_buffer);
               return rc ? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
             }
           sw = (result[resultlen-2] << 8) | result[resultlen-1];
           resultlen -= 2;
           if (DBG_CARD_IO)
             {
               log_debug ("     more: sw=%04X  datalen=%d\n",
                          sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
                 log_printhex (result, resultlen, "     dump: ");
             }
 
           if ((sw & 0xff00) == SW_MORE_DATA
               || sw == SW_SUCCESS
               || sw == SW_EOF_REACHED )
             {
               if (retbuf && resultlen)
                 {
                   if (p - *retbuf + resultlen > bufsize)
                     {
                       bufsize += resultlen > 4096? resultlen: 4096;
                       tmp = xtryrealloc (*retbuf, bufsize + 2);
                       if (!tmp)
                         {
                           unlock_slot (slot);
                           xfree (result_buffer);
                           return SW_HOST_OUT_OF_CORE;
                         }
                       p = tmp + (p - *retbuf);
                       *retbuf = tmp;
                     }
                   memcpy (p, result, resultlen);
                   p += resultlen;
                 }
             }
           else
             log_info ("apdu_send_direct(%d) "
                       "got unexpected status %04X from get response\n",
                       slot, sw);
         }
       while ((sw & 0xff00) == SW_MORE_DATA);
 
       if (retbuf)
         {
           *retbuflen = p - *retbuf;
           tmp = xtryrealloc (*retbuf, *retbuflen + 2);
           if (tmp)
             *retbuf = tmp;
         }
     }
   else
     {
       if (retbuf)
         {
           *retbuf = xtrymalloc ((resultlen? resultlen : 1)+2);
           if (!*retbuf)
             {
               unlock_slot (slot);
               xfree (result_buffer);
               return SW_HOST_OUT_OF_CORE;
             }
           *retbuflen = resultlen;
           memcpy (*retbuf, result, resultlen);
         }
     }
 
   unlock_slot (slot);
   xfree (result_buffer);
 
   /* Append the status word.  Note that we reserved the two extra
      bytes while allocating the buffer.  */
   if (retbuf)
     {
       (*retbuf)[(*retbuflen)++] = (sw >> 8);
       (*retbuf)[(*retbuflen)++] = sw;
     }
 
   if (r_sw)
     *r_sw = sw;
 
   if (DBG_CARD_IO && retbuf)
     log_printhex (*retbuf, *retbuflen, "      dump: ");
 
 
   return 0;
 }
 
 
 const char *
 apdu_get_reader_name (int slot)
 {
   return reader_table[slot].rdrname;
 }
 
 gpg_error_t
 apdu_init (void)
 {
 #ifdef USE_NPTH
   gpg_error_t err;
   int i;
 
   if (npth_mutex_init (&reader_table_lock, NULL))
     goto leave;
 
   for (i = 0; i < MAX_READER; i++)
     if (npth_mutex_init (&reader_table[i].lock, NULL))
       goto leave;
 
   /* All done well.  */
   return 0;
 
  leave:
   err = gpg_error_from_syserror ();
   log_error ("apdu: error initializing mutex: %s\n", gpg_strerror (err));
   return err;
 #endif /*USE_NPTH*/
   return 0;
 }
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index efd8d79bb..4ac7f5d72 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1,5439 +1,5439 @@
 /* app-openpgp.c - The OpenPGP card application.
  * Copyright (C) 2003-2005, 2007-2009,
  *               2013-2015 Free Software Foundation, Inc.
  * Copyright (C) 2003-2005, 2007-2009, 2013-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/>.
  */
 
 /* Some notes:
 
    CHV means Card Holder Verification and is nothing else than a PIN
    or password.  That term seems to have been used originally with GSM
    cards.  Version v2 of the specs changes the term to the clearer
    term PW for password.  We use the terms here interchangeable
    because we do not want to change existing strings i18n wise.
 
    Version 2 of the specs also drops the separate PW2 which was
    required in v1 due to ISO requirements.  It is now possible to have
    one physical PW but two reference to it so that they can be
    individually be verified (e.g. to implement a forced verification
    for one key).  Thus you will noticed the use of PW2 with the verify
    command but not with change_reference_data because the latter
    operates directly on the physical PW.
 
    The Reset Code (RC) as implemented by v2 cards uses the same error
    counter as the PW2 of v1 cards.  By default no RC is set and thus
    that error counter is set to 0.  After setting the RC the error
    counter will be initialized to 3.
 
  */
 
 #include <config.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
 #include <assert.h>
 #include <time.h>
 
 #include "scdaemon.h"
 
 #include "../common/util.h"
 #include "../common/i18n.h"
 #include "iso7816.h"
 #include "../common/tlv.h"
 #include "../common/host2net.h"
 #include "../common/openpgpdefs.h"
 
 
 #define KDF_DATA_LENGTH_MIN  90
 #define KDF_DATA_LENGTH_MAX 110
 
 /* A table describing the DOs of the card.  */
 static struct {
   int tag;
   int constructed;
   int get_from;  /* Constructed DO with this DO or 0 for direct access. */
   unsigned int binary:1;
   unsigned int dont_cache:1;
   unsigned int flush_on_error:1;
   unsigned int get_immediate_in_v11:1; /* Enable a hack to bypass the cache of
                                  this data object if it is used in 1.1
                                  and later versions of the card.  This
                                  does not work with composite DO and
                                  is currently only useful for the CHV
                                  status bytes. */
   unsigned int try_extlen:2;           /* Large object; try to use an extended
                                  length APDU when !=0.  The size is
                                  determined by extcap.max_certlen_3
                                  when == 1, and by extcap.max_special_do
                                  when == 2.  */
   char *desc;
 } data_objects[] = {
   { 0x005E, 0,    0, 1, 0, 0, 0, 2, "Login Data" },
   { 0x5F50, 0,    0, 0, 0, 0, 0, 2, "URL" },
   { 0x5F52, 0,    0, 1, 0, 0, 0, 0, "Historical Bytes" },
   { 0x0065, 1,    0, 1, 0, 0, 0, 0, "Cardholder Related Data"},
   { 0x005B, 0, 0x65, 0, 0, 0, 0, 0, "Name" },
   { 0x5F2D, 0, 0x65, 0, 0, 0, 0, 0, "Language preferences" },
   { 0x5F35, 0, 0x65, 0, 0, 0, 0, 0, "Salutation" },
   { 0x006E, 1,    0, 1, 0, 0, 0, 0, "Application Related Data" },
   { 0x004F, 0, 0x6E, 1, 0, 0, 0, 0, "AID" },
   { 0x0073, 1,    0, 1, 0, 0, 0, 0, "Discretionary Data Objects" },
   { 0x0047, 0, 0x6E, 1, 1, 0, 0, 0, "Card Capabilities" },
   { 0x00C0, 0, 0x6E, 1, 1, 0, 0, 0, "Extended Card Capabilities" },
   { 0x00C1, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Signature" },
   { 0x00C2, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Decryption" },
   { 0x00C3, 0, 0x6E, 1, 1, 0, 0, 0, "Algorithm Attributes Authentication" },
   { 0x00C4, 0, 0x6E, 1, 0, 1, 1, 0, "CHV Status Bytes" },
   { 0x00C5, 0, 0x6E, 1, 0, 0, 0, 0, "Fingerprints" },
   { 0x00C6, 0, 0x6E, 1, 0, 0, 0, 0, "CA Fingerprints" },
   { 0x00CD, 0, 0x6E, 1, 0, 0, 0, 0, "Generation time" },
   { 0x007A, 1,    0, 1, 0, 0, 0, 0, "Security Support Template" },
   { 0x0093, 0, 0x7A, 1, 1, 0, 0, 0, "Digital Signature Counter" },
   { 0x0101, 0,    0, 0, 0, 0, 0, 2, "Private DO 1"},
   { 0x0102, 0,    0, 0, 0, 0, 0, 2, "Private DO 2"},
   { 0x0103, 0,    0, 0, 0, 0, 0, 2, "Private DO 3"},
   { 0x0104, 0,    0, 0, 0, 0, 0, 2, "Private DO 4"},
   { 0x7F21, 1,    0, 1, 0, 0, 0, 1, "Cardholder certificate"},
   /* V3.0 */
   { 0x7F74, 0,    0, 1, 0, 0, 0, 0, "General Feature Management"},
   { 0x00D5, 0,    0, 1, 0, 0, 0, 0, "AES key data"},
   { 0x00F9, 0,    0, 1, 0, 0, 0, 0, "KDF data object"},
   { 0 }
 };
 
 
 /* Type of keys.  */
 typedef enum
   {
     KEY_TYPE_ECC,
     KEY_TYPE_RSA,
   }
 key_type_t;
 
 
 /* The format of RSA private keys.  */
 typedef enum
   {
     RSA_UNKNOWN_FMT,
     RSA_STD,
     RSA_STD_N,
     RSA_CRT,
     RSA_CRT_N
   }
 rsa_key_format_t;
 
 
 /* One cache item for DOs.  */
 struct cache_s {
   struct cache_s *next;
   int tag;
   size_t length;
   unsigned char data[1];
 };
 
 
 /* Object with application (i.e. OpenPGP card) specific data.  */
 struct app_local_s {
   /* A linked list with cached DOs.  */
   struct cache_s *cache;
 
   /* Keep track of the public keys.  */
   struct
   {
     int read_done;   /* True if we have at least tried to read them.  */
     unsigned char *key; /* This is a malloced buffer with a canonical
                            encoded S-expression encoding a public
                            key. Might be NULL if key is not
                            available.  */
     size_t keylen;      /* The length of the above S-expression.  This
                            is usually only required for cross checks
                            because the length of an S-expression is
                            implicitly available.  */
     unsigned char keygrip_str[41]; /* The keygrip, null terminated */
   } pk[3];
 
   unsigned char status_indicator; /* The card status indicator.  */
 
   unsigned int manufacturer:16;   /* Manufacturer ID from the s/n.  */
 
   /* Keep track of the ISO card capabilities.  */
   struct
   {
     unsigned int cmd_chaining:1;  /* Command chaining is supported.  */
     unsigned int ext_lc_le:1;     /* Extended Lc and Le are supported.  */
   } cardcap;
 
   /* Keep track of extended card capabilities.  */
   struct
   {
     unsigned int is_v2:1;              /* Compatible to v2 or later.        */
     unsigned int extcap_v3:1;          /* Extcap is in v3 format.           */
     unsigned int has_button:1;         /* Has confirmation button or not.   */
 
     unsigned int sm_supported:1;       /* Secure Messaging is supported.    */
     unsigned int get_challenge:1;
     unsigned int key_import:1;
     unsigned int change_force_chv:1;
     unsigned int private_dos:1;
     unsigned int algo_attr_change:1;   /* Algorithm attributes changeable.  */
     unsigned int has_decrypt:1;        /* Support symmetric decryption.     */
     unsigned int kdf_do:1;             /* Support KDF DO.                   */
 
     unsigned int sm_algo:2;            /* Symmetric crypto algo for SM.     */
     unsigned int pin_blk2:1;           /* PIN block 2 format supported.     */
     unsigned int mse:1;                /* MSE command supported.            */
     unsigned int max_certlen_3:16;
     unsigned int max_get_challenge:16; /* Maximum size for get_challenge.   */
     unsigned int max_special_do:16;    /* Maximum size for special DOs.     */
   } extcap;
 
   /* Flags used to control the application.  */
   struct
   {
     unsigned int no_sync:1;   /* Do not sync CHV1 and CHV2 */
     unsigned int def_chv2:1;  /* Use 123456 for CHV2.  */
   } flags;
 
   /* Pinpad request specified on card.  */
   struct
   {
     unsigned int disabled:1;    /* No pinpad use because of KDF DO.  */
     unsigned int specified:1;
     int fixedlen_user;
     int fixedlen_admin;
   } pinpad;
 
    struct
    {
     key_type_t key_type;
     union {
       struct {
         unsigned int n_bits;     /* Size of the modulus in bits.  The rest
                                     of this strucuire is only valid if
                                     this is not 0.  */
         unsigned int e_bits;     /* Size of the public exponent in bits.  */
         rsa_key_format_t format;
       } rsa;
       struct {
         const char *curve;
         int flags;
       } ecc;
     };
    } keyattr[3];
 };
 
 #define ECC_FLAG_DJB_TWEAK (1 << 0)
 #define ECC_FLAG_PUBKEY    (1 << 1)
 
 
 /***** Local prototypes  *****/
 static unsigned long convert_sig_counter_value (const unsigned char *value,
                                                 size_t valuelen);
 static unsigned long get_sig_counter (app_t app);
 static gpg_error_t do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
                             gpg_error_t (*pincb)(void*, const char *, char **),
                             void *pincb_arg,
                             const void *indata, size_t indatalen,
                             unsigned char **outdata, size_t *outdatalen);
 static void parse_algorithm_attribute (app_t app, int keyno);
 static gpg_error_t change_keyattr_from_string
                            (app_t app,
                             gpg_error_t (*pincb)(void*, const char *, char **),
                             void *pincb_arg,
                             const void *value, size_t valuelen);
 
 
 /* Return the OpenPGP card manufacturer name. */
 static const char *
 get_manufacturer (unsigned int no)
 {
   /* Note:  Make sure that there is no colon or linefeed in the string. */
   switch (no)
     {
     case 0x0001: return "PPC Card Systems";
     case 0x0002: return "Prism";
     case 0x0003: return "OpenFortress";
     case 0x0004: return "Wewid";
     case 0x0005: return "ZeitControl";
     case 0x0006: return "Yubico";
     case 0x0007: return "OpenKMS";
     case 0x0008: return "LogoEmail";
     case 0x0009: return "Fidesmo";
     case 0x000A: return "Dangerous Things";
     case 0x000B: return "Feitian Technologies";
 
     case 0x002A: return "Magrathea";
     case 0x0042: return "GnuPG e.V.";
 
     case 0x1337: return "Warsaw Hackerspace";
     case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
     case 0x4354: return "Confidential Technologies";   /* cotech.de */
     case 0x5443: return "TIF-IT e.V.";
     case 0x63AF: return "Trustica";
     case 0xBA53: return "c-base e.V.";
     case 0xBD0E: return "Paranoidlabs";
     case 0xF517: return "FSIJ";
     case 0xF5EC: return "F-Secure";
 
       /* 0x0000 and 0xFFFF are defined as test cards per spec,
        * 0xFF00 to 0xFFFE are assigned for use with randomly created
        * serial numbers.  */
     case 0x0000:
     case 0xffff: return "test card";
     default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown";
     }
 }
 
 
 
 
 /* Deconstructor. */
 static void
 do_deinit (app_t app)
 {
   if (app && app->app_local)
     {
       struct cache_s *c, *c2;
       int i;
 
       for (c = app->app_local->cache; c; c = c2)
         {
           c2 = c->next;
           xfree (c);
         }
 
       for (i=0; i < DIM (app->app_local->pk); i++)
         {
           xfree (app->app_local->pk[i].key);
           app->app_local->pk[i].read_done = 0;
         }
       xfree (app->app_local);
       app->app_local = NULL;
     }
 }
 
 
 /* Wrapper around iso7816_get_data which first tries to get the data
    from the cache.  With GET_IMMEDIATE passed as true, the cache is
    bypassed.  With TRY_EXTLEN extended lengths APDUs are use if
    supported by the card.  */
 static gpg_error_t
 get_cached_data (app_t app, int tag,
                  unsigned char **result, size_t *resultlen,
                  int get_immediate, int try_extlen)
 {
   gpg_error_t err;
   int i;
   unsigned char *p;
   size_t len;
   struct cache_s *c;
   int exmode;
 
   *result = NULL;
   *resultlen = 0;
 
   if (!get_immediate)
     {
       for (c=app->app_local->cache; c; c = c->next)
         if (c->tag == tag)
           {
             if(c->length)
               {
                 p = xtrymalloc (c->length);
                 if (!p)
                   return gpg_error (gpg_err_code_from_errno (errno));
                 memcpy (p, c->data, c->length);
                 *result = p;
               }
 
             *resultlen = c->length;
 
             return 0;
           }
     }
 
   if (try_extlen && app->app_local->cardcap.ext_lc_le)
     {
       if (try_extlen == 1)
         exmode = app->app_local->extcap.max_certlen_3;
       else if (try_extlen == 2 && app->app_local->extcap.extcap_v3)
         exmode = app->app_local->extcap.max_special_do;
       else
         exmode = 0;
     }
   else
     exmode = 0;
 
   err = iso7816_get_data (app->slot, exmode, tag, &p, &len);
   if (err)
     return err;
   if (len)
     *result = p;
   *resultlen = len;
 
   /* Check whether we should cache this object. */
   if (get_immediate)
     return 0;
 
   for (i=0; data_objects[i].tag; i++)
     if (data_objects[i].tag == tag)
       {
         if (data_objects[i].dont_cache)
           return 0;
         break;
       }
 
   /* Okay, cache it. */
   for (c=app->app_local->cache; c; c = c->next)
     assert (c->tag != tag);
 
   c = xtrymalloc (sizeof *c + len);
   if (c)
     {
       if (len)
         memcpy (c->data, p, len);
       else
         xfree (p);
       c->length = len;
       c->tag = tag;
       c->next = app->app_local->cache;
       app->app_local->cache = c;
     }
 
   return 0;
 }
 
 /* Remove DO at TAG from the cache. */
 static void
 flush_cache_item (app_t app, int tag)
 {
   struct cache_s *c, *cprev;
   int i;
 
   if (!app->app_local)
     return;
 
   for (c=app->app_local->cache, cprev=NULL; c ; cprev=c, c = c->next)
     if (c->tag == tag)
       {
         if (cprev)
           cprev->next = c->next;
         else
           app->app_local->cache = c->next;
         xfree (c);
 
         for (c=app->app_local->cache; c ; c = c->next)
           {
             assert (c->tag != tag); /* Oops: duplicated entry. */
           }
         return;
       }
 
   /* Try again if we have an outer tag. */
   for (i=0; data_objects[i].tag; i++)
     if (data_objects[i].tag == tag && data_objects[i].get_from
         && data_objects[i].get_from != tag)
       flush_cache_item (app, data_objects[i].get_from);
 }
 
 /* Flush all entries from the cache which might be out of sync after
    an error. */
 static void
 flush_cache_after_error (app_t app)
 {
   int i;
 
   for (i=0; data_objects[i].tag; i++)
     if (data_objects[i].flush_on_error)
       flush_cache_item (app, data_objects[i].tag);
 }
 
 
 /* Flush the entire cache. */
 static void
 flush_cache (app_t app)
 {
   if (app && app->app_local)
     {
       struct cache_s *c, *c2;
 
       for (c = app->app_local->cache; c; c = c2)
         {
           c2 = c->next;
           xfree (c);
         }
       app->app_local->cache = NULL;
     }
 }
 
 
 /* Get the DO identified by TAG from the card in SLOT and return a
    buffer with its content in RESULT and NBYTES.  The return value is
    NULL if not found or a pointer which must be used to release the
    buffer holding value. */
 static void *
 get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
             int *r_rc)
 {
   int rc, i;
   unsigned char *buffer;
   size_t buflen;
   unsigned char *value;
   size_t valuelen;
   int dummyrc;
   int exmode;
 
   if (!r_rc)
     r_rc = &dummyrc;
 
   *result = NULL;
   *nbytes = 0;
   *r_rc = 0;
   for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
     ;
 
   if (app->appversion > 0x0100 && data_objects[i].get_immediate_in_v11)
     {
       exmode = 0;
       rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
       if (rc)
         {
           *r_rc = rc;
           return NULL;
         }
       *result = buffer;
       *nbytes = buflen;
       return buffer;
     }
 
   value = NULL;
   rc = -1;
   if (data_objects[i].tag && data_objects[i].get_from)
     {
       rc = get_cached_data (app, data_objects[i].get_from,
                             &buffer, &buflen,
                             (data_objects[i].dont_cache
                              || data_objects[i].get_immediate_in_v11),
                             data_objects[i].try_extlen);
       if (!rc)
         {
           const unsigned char *s;
 
           s = find_tlv_unchecked (buffer, buflen, tag, &valuelen);
           if (!s)
             value = NULL; /* not found */
           else if (valuelen > buflen - (s - buffer))
             {
               log_error ("warning: constructed DO too short\n");
               value = NULL;
               xfree (buffer); buffer = NULL;
             }
           else
             value = buffer + (s - buffer);
         }
     }
 
   if (!value) /* Not in a constructed DO, try simple. */
     {
       rc = get_cached_data (app, tag, &buffer, &buflen,
                             (data_objects[i].dont_cache
                              || data_objects[i].get_immediate_in_v11),
                             data_objects[i].try_extlen);
       if (!rc)
         {
           value = buffer;
           valuelen = buflen;
         }
     }
 
   if (!rc)
     {
       *nbytes = valuelen;
       *result = value;
       return buffer;
     }
   *r_rc = rc;
   return NULL;
 }
 
 
 static void
 dump_all_do (int slot)
 {
   int rc, i, j;
   unsigned char *buffer;
   size_t buflen;
 
   for (i=0; data_objects[i].tag; i++)
     {
       if (data_objects[i].get_from)
         continue;
 
       /* We don't try extended length APDU because such large DO would
          be pretty useless in a log file.  */
       rc = iso7816_get_data (slot, 0, data_objects[i].tag, &buffer, &buflen);
       if (gpg_err_code (rc) == GPG_ERR_NO_OBJ)
         ;
       else if (rc)
         log_info ("DO '%s' not available: %s\n",
                   data_objects[i].desc, gpg_strerror (rc));
       else
         {
           if (data_objects[i].binary)
             {
               log_info ("DO '%s': ", data_objects[i].desc);
               log_printhex (buffer, buflen, "");
             }
           else
             log_info ("DO '%s': '%.*s'\n",
                       data_objects[i].desc,
                       (int)buflen, buffer); /* FIXME: sanitize */
 
           if (data_objects[i].constructed)
             {
               for (j=0; data_objects[j].tag; j++)
                 {
                   const unsigned char *value;
                   size_t valuelen;
 
                   if (j==i || data_objects[i].tag != data_objects[j].get_from)
                     continue;
                   value = find_tlv_unchecked (buffer, buflen,
                                               data_objects[j].tag, &valuelen);
                   if (!value)
                     ; /* not found */
                   else if (valuelen > buflen - (value - buffer))
                     log_error ("warning: constructed DO too short\n");
                   else
                     {
                       if (data_objects[j].binary)
                         {
                           log_info ("DO '%s': ", data_objects[j].desc);
                           if (valuelen > 200)
                             log_info ("[%u]\n", (unsigned int)valuelen);
                           else
                             log_printhex (value, valuelen, "");
                         }
                       else
                         log_info ("DO '%s': '%.*s'\n",
                                   data_objects[j].desc,
                                   (int)valuelen, value); /* FIXME: sanitize */
                     }
                 }
             }
         }
       xfree (buffer); buffer = NULL;
     }
 }
 
 
 /* Count the number of bits, assuming the A represents an unsigned big
    integer of length LEN bytes. */
 static unsigned int
 count_bits (const unsigned char *a, size_t len)
 {
   unsigned int n = len * 8;
   int i;
 
   for (; len && !*a; len--, a++, n -=8)
     ;
   if (len)
     {
       for (i=7; i && !(*a & (1<<i)); i--)
         n--;
     }
   return n;
 }
 
 /* GnuPG makes special use of the login-data DO, this function parses
    the login data to store the flags for later use.  It may be called
    at any time and should be called after changing the login-data DO.
 
    Everything up to a LF is considered a mailbox or account name.  If
    the first LF is followed by DC4 (0x14) control sequence are
    expected up to the next LF.  Control sequences are separated by FS
    (0x18) and consist of key=value pairs.  There are two keys defined:
 
     F=<flags>
 
     Where FLAGS is a plain hexadecimal number representing flag values.
     The lsb is here the rightmost bit.  Defined flags bits are:
 
       Bit 0 = CHV1 and CHV2 are not synchronized
       Bit 1 = CHV2 has been set to the default PIN of "123456"
               (this implies that bit 0 is also set).
 
     P=<pinpad-request>
 
     Where PINPAD_REQUEST is in the format of: <n> or <n>,<m>.
     N for user PIN, M for admin PIN.  If M is missing it means M=N.
     0 means to force not to use pinpad.
 
 */
 static void
 parse_login_data (app_t app)
 {
   unsigned char *buffer, *p;
   size_t buflen, len;
   void *relptr;
 
   /* Set defaults.  */
   app->app_local->flags.no_sync = 0;
   app->app_local->flags.def_chv2 = 0;
   app->app_local->pinpad.specified = 0;
   app->app_local->pinpad.fixedlen_user = -1;
   app->app_local->pinpad.fixedlen_admin = -1;
 
   /* Read the DO.  */
   relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
   if (!relptr)
     return; /* Ooops. */
   for (; buflen; buflen--, buffer++)
     if (*buffer == '\n')
       break;
   if (buflen < 2 || buffer[1] != '\x14')
     {
       xfree (relptr);
       return; /* No control sequences.  */
     }
 
   buflen--;
   buffer++;
   do
     {
       buflen--;
       buffer++;
       if (buflen > 1 && *buffer == 'F' && buffer[1] == '=')
         {
           /* Flags control sequence found.  */
           int lastdig = 0;
 
           /* For now we are only interested in the last digit, so skip
              any leading digits but bail out on invalid characters. */
           for (p=buffer+2, len = buflen-2; len && hexdigitp (p); p++, len--)
             lastdig = xtoi_1 (p);
           buffer = p;
           buflen = len;
           if (len && !(*p == '\n' || *p == '\x18'))
             goto next;  /* Invalid characters in field.  */
           app->app_local->flags.no_sync = !!(lastdig & 1);
           app->app_local->flags.def_chv2 = (lastdig & 3) == 3;
         }
       else if (buflen > 1 && *buffer == 'P' && buffer[1] == '=')
         {
           /* Pinpad request control sequence found.  */
           buffer += 2;
           buflen -= 2;
 
           if (buflen)
             {
               if (digitp (buffer))
                 {
                   char *q;
                   int n, m;
 
                   n = strtol (buffer, &q, 10);
                   if (q >= (char *)buffer + buflen
                       || *q == '\x18' || *q == '\n')
                     m = n;
                   else
                     {
                       if (*q++ != ',' || !digitp (q))
                         goto next;
                       m = strtol (q, &q, 10);
                     }
 
                   if (buflen < ((unsigned char *)q - buffer))
                     break;
 
                   buflen -= ((unsigned char *)q - buffer);
                   buffer = q;
 
                   if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
                     goto next;
                   app->app_local->pinpad.specified = 1;
                   app->app_local->pinpad.fixedlen_user = n;
                   app->app_local->pinpad.fixedlen_admin = m;
                 }
             }
         }
     next:
       /* Skip to FS (0x18) or LF (\n).  */
       for (; buflen && *buffer != '\x18' && *buffer != '\n'; buflen--)
         buffer++;
     }
   while (buflen && *buffer != '\n');
 
   xfree (relptr);
 }
 
 
 #define MAX_ARGS_STORE_FPR 3
 
 /* Note, that FPR must be at least 20 bytes. */
 static gpg_error_t
 store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr,
            int algo, ...)
 {
   unsigned int n, nbits;
   unsigned char *buffer, *p;
   int tag, tag2;
   int rc;
   const unsigned char *m[MAX_ARGS_STORE_FPR];
   size_t mlen[MAX_ARGS_STORE_FPR];
   va_list ap;
   int argc;
   int i;
 
   n = 6;    /* key packet version, 4-byte timestamps, and algorithm */
   if (algo == PUBKEY_ALGO_ECDH)
     argc = 3;
   else
     argc = 2;
 
   va_start (ap, algo);
   for (i = 0; i < argc; i++)
     {
       m[i] = va_arg (ap, const unsigned char *);
       mlen[i] = va_arg (ap, size_t);
       if (algo == PUBKEY_ALGO_RSA || i == 1)
         n += 2;
       n += mlen[i];
     }
   va_end (ap);
 
   p = buffer = xtrymalloc (3 + n);
   if (!buffer)
     return gpg_error_from_syserror ();
 
   *p++ = 0x99;     /* ctb */
   *p++ = n >> 8;   /* 2 byte length header */
   *p++ = n;
   *p++ = 4;        /* key packet version */
   *p++ = timestamp >> 24;
   *p++ = timestamp >> 16;
   *p++ = timestamp >>  8;
   *p++ = timestamp;
   *p++ = algo;
 
   for (i = 0; i < argc; i++)
     {
       if (algo == PUBKEY_ALGO_RSA || i == 1)
         {
           nbits = count_bits (m[i], mlen[i]);
           *p++ = nbits >> 8;
           *p++ = nbits;
         }
       memcpy (p, m[i], mlen[i]);
       p += mlen[i];
     }
 
   gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3);
 
   xfree (buffer);
 
   tag = (app->appversion > 0x0007? 0xC7 : 0xC6) + keynumber;
   flush_cache_item (app, 0xC5);
   tag2 = 0xCE + keynumber;
   flush_cache_item (app, 0xCD);
 
   rc = iso7816_put_data (app->slot, 0, tag, fpr, 20);
   if (rc)
     log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc));
 
   if (!rc && app->appversion > 0x0100)
     {
       unsigned char buf[4];
 
       buf[0] = timestamp >> 24;
       buf[1] = timestamp >> 16;
       buf[2] = timestamp >>  8;
       buf[3] = timestamp;
 
       rc = iso7816_put_data (app->slot, 0, tag2, buf, 4);
       if (rc)
         log_error (_("failed to store the creation date: %s\n"),
                    gpg_strerror (rc));
     }
 
   return rc;
 }
 
 
 static void
 send_fpr_if_not_null (ctrl_t ctrl, const char *keyword,
                       int number, const unsigned char *fpr)
 {
   int i;
   char buf[41];
   char numbuf[25];
 
   for (i=0; i < 20 && !fpr[i]; i++)
     ;
   if (i==20)
     return; /* All zero. */
   bin2hex (fpr, 20, buf);
   if (number == -1)
     *numbuf = 0; /* Don't print the key number */
   else
     sprintf (numbuf, "%d", number);
   send_status_info (ctrl, keyword,
                     numbuf, (size_t)strlen(numbuf),
                     buf, (size_t)strlen (buf), NULL, 0);
 }
 
 static void
 send_fprtime_if_not_null (ctrl_t ctrl, const char *keyword,
                           int number, const unsigned char *stamp)
 {
   char numbuf1[50], numbuf2[50];
   unsigned long value;
 
   value = buf32_to_ulong (stamp);
   if (!value)
     return;
   sprintf (numbuf1, "%d", number);
   sprintf (numbuf2, "%lu", value);
   send_status_info (ctrl, keyword,
                     numbuf1, (size_t)strlen(numbuf1),
                     numbuf2, (size_t)strlen(numbuf2), NULL, 0);
 }
 
 static void
 send_key_data (ctrl_t ctrl, const char *name,
                const unsigned char *a, size_t alen)
 {
   char *buffer, *buf;
   size_t buflen;
 
   buffer = buf = bin2hex (a, alen, NULL);
   if (!buffer)
     {
       log_error ("memory allocation error in send_key_data\n");
       return;
     }
   buflen = strlen (buffer);
 
   /* 768 is the hexified size for the modulus of an 3072 bit key.  We
      use extra chunks to transmit larger data (i.e for 4096 bit).  */
   for ( ;buflen > 768; buflen -= 768, buf += 768)
     send_status_info (ctrl, "KEY-DATA",
                       "-", 1,
                       buf, 768,
                       NULL, 0);
   send_status_info (ctrl, "KEY-DATA",
                     name, (size_t)strlen(name),
                     buf, buflen,
                     NULL, 0);
   xfree (buffer);
 }
 
 
 static void
 send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno)
 {
   char buffer[200];
 
   assert (keyno >=0 && keyno < DIM(app->app_local->keyattr));
 
   if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
     snprintf (buffer, sizeof buffer, "%d 1 rsa%u %u %d",
               keyno+1,
               app->app_local->keyattr[keyno].rsa.n_bits,
               app->app_local->keyattr[keyno].rsa.e_bits,
               app->app_local->keyattr[keyno].rsa.format);
   else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
     {
       snprintf (buffer, sizeof buffer, "%d %d %s",
                 keyno+1,
                 keyno==1? PUBKEY_ALGO_ECDH :
                 (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
                 PUBKEY_ALGO_EDDSA : PUBKEY_ALGO_ECDSA,
                 app->app_local->keyattr[keyno].ecc.curve);
     }
   else
     snprintf (buffer, sizeof buffer, "%d 0 0 UNKNOWN", keyno+1);
 
   send_status_direct (ctrl, keyword, buffer);
 }
 
 
 #define RSA_SMALL_SIZE_KEY 1952
 #define RSA_SMALL_SIZE_OP  2048
 
 static int
 determine_rsa_response (app_t app, int keyno)
 {
   int size;
 
   size = 2 + 3 /* header */
     + 4 /* tag+len */ + (app->app_local->keyattr[keyno].rsa.n_bits+7)/8
     + 2 /* tag+len */ + (app->app_local->keyattr[keyno].rsa.e_bits+7)/8;
 
   return size;
 }
 
 
 /* Implement the GETATTR command.  This is similar to the LEARN
    command but returns just one value via the status interface. */
 static gpg_error_t
 do_getattr (app_t app, ctrl_t ctrl, const char *name)
 {
   static struct {
     const char *name;
     int tag;
     int special;
   } table[] = {
     { "DISP-NAME",    0x005B },
     { "LOGIN-DATA",   0x005E },
     { "DISP-LANG",    0x5F2D },
     { "DISP-SEX",     0x5F35 },
     { "PUBKEY-URL",   0x5F50 },
     { "KEY-FPR",      0x00C5, 3 },
     { "KEY-TIME",     0x00CD, 4 },
     { "KEY-ATTR",     0x0000, -5 },
     { "CA-FPR",       0x00C6, 3 },
     { "CHV-STATUS",   0x00C4, 1 },
     { "SIG-COUNTER",  0x0093, 2 },
     { "SERIALNO",     0x004F, -1 },
     { "AID",          0x004F },
     { "EXTCAP",       0x0000, -2 },
     { "PRIVATE-DO-1", 0x0101 },
     { "PRIVATE-DO-2", 0x0102 },
     { "PRIVATE-DO-3", 0x0103 },
     { "PRIVATE-DO-4", 0x0104 },
     { "$AUTHKEYID",   0x0000, -3 },
     { "$ENCRKEYID",   0x0000, -6 },
     { "$SIGNKEYID",   0x0000, -7 },
     { "$DISPSERIALNO",0x0000, -4 },
     { "KDF",          0x00F9, 5 },
     { "MANUFACTURER", 0x0000, -8 },
     { NULL, 0 }
   };
   int idx, i, rc;
   void *relptr;
   unsigned char *value;
   size_t valuelen;
 
   for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
     ;
   if (!table[idx].name)
     return gpg_error (GPG_ERR_INV_NAME);
 
   if (table[idx].special == -1)
     {
       /* The serial number is very special.  We could have used the
          AID DO to retrieve it.  The AID DO is available anyway but
          not hex formatted. */
       char *serial = app_get_serialno (app);
 
       if (serial)
         {
           send_status_direct (ctrl, "SERIALNO", serial);
           xfree (serial);
         }
       return 0;
     }
   if (table[idx].special == -2)
     {
       char tmp[110];
 
       snprintf (tmp, sizeof tmp,
                 "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d "
                 "sm=%d si=%u dec=%d bt=%d kdf=%d",
                 app->app_local->extcap.get_challenge,
                 app->app_local->extcap.key_import,
                 app->app_local->extcap.change_force_chv,
                 app->app_local->extcap.private_dos,
                 app->app_local->extcap.max_certlen_3,
                 app->app_local->extcap.algo_attr_change,
                 (app->app_local->extcap.sm_supported
                  ? (app->app_local->extcap.sm_algo == 0? CIPHER_ALGO_3DES :
                     (app->app_local->extcap.sm_algo == 1?
                      CIPHER_ALGO_AES : CIPHER_ALGO_AES256))
                  : 0),
                 app->app_local->status_indicator,
                 app->app_local->extcap.has_decrypt,
                 app->app_local->extcap.has_button,
                 app->app_local->extcap.kdf_do);
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
   if (table[idx].special == -3)
     {
       char const tmp[] = "OPENPGP.3";
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
   if (table[idx].special == -4)
     {
       char *serial = app_get_dispserialno (app, 0);
 
       if (serial)
         {
           send_status_info (ctrl, table[idx].name,
                             serial, strlen (serial), NULL, 0);
           xfree (serial);
           return 0;
         }
       return gpg_error (GPG_ERR_INV_NAME);
     }
   if (table[idx].special == -5)
     {
       for (i=0; i < 3; i++)
         send_key_attr (ctrl, app, table[idx].name, i);
       return 0;
     }
   if (table[idx].special == -6)
     {
       char const tmp[] = "OPENPGP.2";
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
   if (table[idx].special == -7)
     {
       char const tmp[] = "OPENPGP.1";
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
   if (table[idx].special == -8)
     {
       return send_status_printf
         (ctrl, table[idx].name, "%u %s",
          app->app_local->manufacturer,
          get_manufacturer (app->app_local->manufacturer));
     }
 
   relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
   if (relptr)
     {
       if (table[idx].special == 1)
         {
           char numbuf[7*23];
 
           for (i=0,*numbuf=0; i < valuelen && i < 7; i++)
             sprintf (numbuf+strlen (numbuf), " %d", value[i]);
           send_status_info (ctrl, table[idx].name,
                             numbuf, strlen (numbuf), NULL, 0);
         }
       else if (table[idx].special == 2)
         {
           char numbuf[50];
 
           sprintf (numbuf, "%lu", convert_sig_counter_value (value, valuelen));
           send_status_info (ctrl, table[idx].name,
                             numbuf, strlen (numbuf), NULL, 0);
         }
       else if (table[idx].special == 3)
         {
           if (valuelen >= 60)
             for (i=0; i < 3; i++)
               send_fpr_if_not_null (ctrl, table[idx].name, i+1, value+i*20);
         }
       else if (table[idx].special == 4)
         {
           if (valuelen >= 12)
             for (i=0; i < 3; i++)
               send_fprtime_if_not_null (ctrl, table[idx].name, i+1, value+i*4);
         }
       else if (table[idx].special == 5)
         {
           if ((valuelen == KDF_DATA_LENGTH_MIN
                || valuelen == KDF_DATA_LENGTH_MAX)
               && (value[2] == 0x03))
             app->app_local->pinpad.disabled = 1;
           else
             app->app_local->pinpad.disabled = 0;
 
           send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0);
         }
       else
         send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0);
 
       xfree (relptr);
     }
   else
     {
       if (table[idx].special == 5)
         app->app_local->pinpad.disabled = 0;
     }
   return rc;
 }
 
 
 /* Return the DISP-NAME without any padding characters.  Caller must
  * free the result.  If not found or empty NULL is returned.  */
 static char *
 get_disp_name (app_t app)
 {
   int rc;
   void *relptr;
   unsigned char *value;
   size_t valuelen;
   char *string;
   char *p, *given;
   char *result;
 
   relptr = get_one_do (app, 0x005B, &value, &valuelen, &rc);
   if (!relptr)
     return NULL;
 
   string = xtrymalloc (valuelen + 1);
   if (!string)
     {
       xfree (relptr);
       return NULL;
     }
   memcpy (string, value, valuelen);
   string[valuelen] = 0;
   xfree (relptr);
 
   /* Swap surname and given name.  */
   given = strstr (string, "<<");
   for (p = string; *p; p++)
     if (*p == '<')
       *p = ' ';
 
   if (given && given[2])
     {
       *given = 0;
       given += 2;
       result = strconcat (given, " ", string, NULL);
     }
   else
     {
       result = string;
       string = NULL;
     }
 
   xfree (string);
   return result;
 }
 
 
 /* Return the pretty formatted serialnumber.  On error NULL is
  * returned.  */
 static char *
 get_disp_serialno (app_t app)
 {
   char *serial = app_get_serialno (app);
 
   /* For our OpenPGP cards we do not want to show the entire serial
    * number but a nicely reformatted actual serial number.  */
   if (serial && strlen (serial) > 16+12)
     {
       memmove (serial, serial+16, 4);
       serial[4] = ' ';
       /* memmove (serial+5, serial+20, 4); */
       /* serial[9] = ' '; */
       /* memmove (serial+10, serial+24, 4); */
       /* serial[14] = 0; */
       memmove (serial+5, serial+20, 8);
       serial[13] = 0;
     }
   return serial;
 }
 
 
 /* Return the number of remaining tries for the standard or the admin
  * pw.  Returns -1 on card error.  */
 static int
 get_remaining_tries (app_t app, int adminpw)
 {
   void *relptr;
   unsigned char *value;
   size_t valuelen;
   int remaining;
 
   relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
   if (!relptr || valuelen < 7)
     {
       log_error (_("error retrieving CHV status from card\n"));
       xfree (relptr);
       return -1;
     }
   remaining = value[adminpw? 6 : 4];
   xfree (relptr);
   return remaining;
 }
 
 
 /* Retrieve the fingerprint from the card inserted in SLOT and write
    the according hex representation to FPR.  Caller must have provide
    a buffer at FPR of least 41 bytes.  Returns 0 on success or an
    error code. */
 static gpg_error_t
 retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
 {
   gpg_error_t err = 0;
   void *relptr;
   unsigned char *value;
   size_t valuelen;
 
   assert (keyno >=0 && keyno <= 2);
 
   relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL);
   if (relptr && valuelen >= 60)
     bin2hex (value+keyno*20, 20, fpr);
   else
     err = gpg_error (GPG_ERR_NOT_FOUND);
   xfree (relptr);
   return err;
 }
 
 
 /* Retrieve the public key material for the RSA key, whose fingerprint
    is FPR, from gpg output, which can be read through the stream FP.
    The RSA modulus will be stored at the address of M and MLEN, the
    public exponent at E and ELEN.  Returns zero on success, an error
    code on failure.  Caller must release the allocated buffers at M
    and E if the function returns success.  */
 static gpg_error_t
 retrieve_key_material (FILE *fp, const char *hexkeyid,
                        const unsigned char **m, size_t *mlen,
                        const unsigned char **e, size_t *elen)
 {
   gcry_error_t err = 0;
   char *line = NULL;    /* read_line() buffer. */
   size_t line_size = 0; /* Helper for for read_line. */
   int found_key = 0;    /* Helper to find a matching key. */
   unsigned char *m_new = NULL;
   unsigned char *e_new = NULL;
   size_t m_new_n = 0;
   size_t e_new_n = 0;
 
   /* Loop over all records until we have found the subkey
      corresponding to the fingerprint. Inm general the first record
      should be the pub record, but we don't rely on that.  Given that
      we only need to look at one key, it is sufficient to compare the
      keyid so that we don't need to look at "fpr" records. */
   for (;;)
     {
       char *p;
       char *fields[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
       int nfields;
       size_t max_length;
       gcry_mpi_t mpi;
       int i;
 
       max_length = 4096;
       i = read_line (fp, &line, &line_size, &max_length);
       if (!i)
         break; /* EOF. */
       if (i < 0)
         {
           err = gpg_error_from_syserror ();
           goto leave; /* Error. */
         }
       if (!max_length)
         {
           err = gpg_error (GPG_ERR_TRUNCATED);
           goto leave;  /* Line truncated - we better stop processing.  */
         }
 
       /* Parse the line into fields. */
       for (nfields=0, p=line; p && nfields < DIM (fields); nfields++)
         {
           fields[nfields] = p;
           p = strchr (p, ':');
           if (p)
             *(p++) = 0;
         }
       if (!nfields)
         continue; /* No fields at all - skip line.  */
 
       if (!found_key)
         {
           if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
                && nfields > 4 && !strcmp (fields[4], hexkeyid))
             found_key = 1;
           continue;
         }
 
       if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") )
         break; /* Next key - stop.  */
 
       if ( strcmp (fields[0], "pkd") )
         continue; /* Not a key data record.  */
       if ( nfields < 4 || (i = atoi (fields[1])) < 0 || i > 1
            || (!i && m_new) || (i && e_new))
         {
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave; /* Error: Invalid key data record or not an RSA key.  */
         }
 
       err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL);
       if (err)
         mpi = NULL;
       else if (!i)
         err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &m_new, &m_new_n, mpi);
       else
         err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &e_new, &e_new_n, mpi);
       gcry_mpi_release (mpi);
       if (err)
         goto leave;
     }
 
   if (m_new && e_new)
     {
       *m = m_new;
       *mlen = m_new_n;
       m_new = NULL;
       *e = e_new;
       *elen = e_new_n;
       e_new = NULL;
     }
   else
     err = gpg_error (GPG_ERR_GENERAL);
 
  leave:
   xfree (m_new);
   xfree (e_new);
   xfree (line);
   return err;
 }
 
 
 static gpg_error_t
 rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at,  int keyno,
                  const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
 {
   gpg_error_t err;
   const unsigned char *m, *e;
   size_t mlen, elen;
   unsigned char *mbuf = NULL, *ebuf = NULL;
 
   m = find_tlv (data, datalen, 0x0081, &mlen);
   if (!m)
     {
       log_error (_("response does not contain the RSA modulus\n"));
       return gpg_error (GPG_ERR_CARD);
     }
 
   e = find_tlv (data, datalen, 0x0082, &elen);
   if (!e)
     {
       log_error (_("response does not contain the RSA public exponent\n"));
       return gpg_error (GPG_ERR_CARD);
     }
 
   if (ctrl)
     {
       send_key_data (ctrl, "n", m, mlen);
       send_key_data (ctrl, "e", e, elen);
     }
 
   for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
     ;
   for (; elen && !*e; elen--, e++) /* strip leading zeroes */
     ;
 
   if (ctrl)
     {
       unsigned char fprbuf[20];
 
       err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
                        m, mlen, e, elen);
       if (err)
         return err;
 
       send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
     }
 
   mbuf = xtrymalloc (mlen + 1);
   if (!mbuf)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   /* Prepend numbers with a 0 if needed.  */
   if (mlen && (*m & 0x80))
     {
       *mbuf = 0;
       memcpy (mbuf+1, m, mlen);
       mlen++;
     }
   else
     memcpy (mbuf, m, mlen);
 
   ebuf = xtrymalloc (elen + 1);
   if (!ebuf)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   /* Prepend numbers with a 0 if needed.  */
   if (elen && (*e & 0x80))
     {
       *ebuf = 0;
       memcpy (ebuf+1, e, elen);
       elen++;
     }
   else
     memcpy (ebuf, e, elen);
 
   err = gcry_sexp_build (r_sexp, NULL, "(public-key(rsa(n%b)(e%b)))",
                          (int)mlen, mbuf, (int)elen, ebuf);
  leave:
   xfree (mbuf);
   xfree (ebuf);
   return err;
 }
 
 
 /* Determine KDF hash algorithm and KEK encryption algorithm by CURVE.  */
 static const unsigned char*
 ecdh_params (const char *curve)
 {
   unsigned int nbits;
 
   openpgp_curve_to_oid (curve, &nbits, NULL);
 
   /* See RFC-6637 for those constants.
          0x03: Number of bytes
          0x01: Version for this parameter format
          KDF hash algo
          KEK symmetric cipher algo
   */
   if (nbits <= 256)
     return (const unsigned char*)"\x03\x01\x08\x07";
   else if (nbits <= 384)
     return (const unsigned char*)"\x03\x01\x09\x08";
   else
     return (const unsigned char*)"\x03\x01\x0a\x09";
 }
 
 static gpg_error_t
 ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
                  const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp)
 {
   gpg_error_t err;
   unsigned char *qbuf = NULL;
   const unsigned char *ecc_q;
   size_t ecc_q_len;
   gcry_mpi_t oid = NULL;
   int n;
   const char *curve;
   const char *oidstr;
   const unsigned char *oidbuf;
   size_t oid_len;
   int algo;
   const char *format;
 
   ecc_q = find_tlv (data, datalen, 0x0086, &ecc_q_len);
   if (!ecc_q)
     {
       log_error (_("response does not contain the EC public key\n"));
       return gpg_error (GPG_ERR_CARD);
     }
 
   curve = app->app_local->keyattr[keyno].ecc.curve;
   oidstr = openpgp_curve_to_oid (curve, NULL, NULL);
   err = openpgp_oid_from_str (oidstr, &oid);
   if (err)
     return err;
   oidbuf = gcry_mpi_get_opaque (oid, &n);
   if (!oidbuf)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   oid_len = (n+7)/8;
 
   qbuf = xtrymalloc (ecc_q_len + 1);
   if (!qbuf)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
 
   if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
     {               /* Prepend 0x40 prefix.  */
       *qbuf = 0x40;
       memcpy (qbuf+1, ecc_q, ecc_q_len);
       ecc_q_len++;
     }
   else
     memcpy (qbuf, ecc_q, ecc_q_len);
 
   if (ctrl)
     {
       send_key_data (ctrl, "q", qbuf, ecc_q_len);
       send_key_data (ctrl, "curve", oidbuf, oid_len);
     }
 
   if (keyno == 1)
     {
       if (ctrl)
         send_key_data (ctrl, "kdf/kek", ecdh_params (curve), (size_t)4);
       algo = PUBKEY_ALGO_ECDH;
     }
   else
     {
       if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
         algo = PUBKEY_ALGO_EDDSA;
       else
         algo = PUBKEY_ALGO_ECDSA;
     }
 
   if (ctrl)
     {
       unsigned char fprbuf[20];
 
       err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
                        qbuf, ecc_q_len, ecdh_params (curve), (size_t)4);
       if (err)
         goto leave;
 
       send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
     }
 
   if (!(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
     format = "(public-key(ecc(curve%s)(q%b)))";
   else if (keyno == 1)
     format = "(public-key(ecc(curve%s)(flags djb-tweak)(q%b)))";
   else
     format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))";
 
   err = gcry_sexp_build (r_sexp, NULL, format,
                          app->app_local->keyattr[keyno].ecc.curve,
                          (int)ecc_q_len, qbuf);
  leave:
   gcry_mpi_release (oid);
   xfree (qbuf);
   return err;
 }
 
 
 /* Compute the keygrip form the local info and store it there.  */
 static gpg_error_t
 store_keygrip (app_t app, int keyno)
 {
   gpg_error_t err;
   unsigned char grip[20];
 
   err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key,
                                  app->app_local->pk[keyno].keylen,
                                  grip);
   if (err)
     return err;
 
   bin2hex (grip, 20, app->app_local->pk[keyno].keygrip_str);
   return 0;
 }
 
 
 /* Parse tag-length-value data for public key in BUFFER of BUFLEN
    length.  Key of KEYNO in APP is updated with an S-expression of
    public key.  When CTRL is not NULL, fingerprint is computed with
    CREATED_AT, and fingerprint is written to the card, and key data
    and fingerprint are send back to the client side.
  */
 static gpg_error_t
 read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
                  const unsigned char *buffer, size_t buflen)
 {
   gpg_error_t err;
   const unsigned char *data;
   size_t datalen;
   gcry_sexp_t s_pkey = NULL;
 
   data = find_tlv (buffer, buflen, 0x7F49, &datalen);
   if (!data)
     {
       log_error (_("response does not contain the public key data\n"));
       return gpg_error (GPG_ERR_CARD);
     }
 
   if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
     err = rsa_read_pubkey (app, ctrl, created_at, keyno,
                            data, datalen, &s_pkey);
   else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
     err = ecc_read_pubkey (app, ctrl, created_at, keyno,
                            data, datalen, &s_pkey);
   else
     err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
   if (!err)
     {
       unsigned char *keybuf;
       size_t len;
 
       len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
       keybuf = xtrymalloc (len);
       if (!data)
         {
           err = gpg_error_from_syserror ();
           gcry_sexp_release (s_pkey);
           return err;
         }
 
       gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
       gcry_sexp_release (s_pkey);
 
       app->app_local->pk[keyno].key = keybuf;
       /* Decrement for trailing '\0' */
       app->app_local->pk[keyno].keylen = len - 1;
 
       err = store_keygrip (app, keyno);
     }
 
   return err;
 }
 
 
 /* Get the public key for KEYNO and store it as an S-expression with
    the APP handle.  On error that field gets cleared.  If we already
    know about the public key we will just return.  Note that this does
    not mean a key is available; this is solely indicated by the
    presence of the app->app_local->pk[KEYNO].key field.
 
    Note that GnuPG 1.x does not need this and it would be too time
    consuming to send it just for the fun of it. However, given that we
    use the same code in gpg 1.4, we can't use the gcry S-expression
    here but need to open encode it. */
 static gpg_error_t
 get_public_key (app_t app, int keyno)
 {
   gpg_error_t err = 0;
   unsigned char *buffer;
   const unsigned char *m, *e;
   size_t buflen;
   size_t mlen = 0;
   size_t elen = 0;
   char *keybuf = NULL;
   gcry_sexp_t s_pkey;
   size_t len;
 
   if (keyno < 0 || keyno > 2)
     return gpg_error (GPG_ERR_INV_ID);
 
   /* Already cached? */
   if (app->app_local->pk[keyno].read_done)
     return 0;
 
   xfree (app->app_local->pk[keyno].key);
   app->app_local->pk[keyno].key = NULL;
   app->app_local->pk[keyno].keylen = 0;
 
   m = e = NULL; /* (avoid cc warning) */
 
   if (app->appversion > 0x0100)
     {
       int exmode, le_value;
 
       /* We may simply read the public key out of these cards.  */
       if (app->app_local->cardcap.ext_lc_le
           && app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA
           && app->app_local->keyattr[keyno].rsa.n_bits > RSA_SMALL_SIZE_KEY)
         {
           exmode = 1;    /* Use extended length.  */
           le_value = determine_rsa_response (app, keyno);
         }
       else
         {
           exmode = 0;
           le_value = 256; /* Use legacy value. */
         }
 
       err = iso7816_read_public_key (app->slot, exmode,
                                      (keyno == 0? "\xB6" :
                                       keyno == 1? "\xB8" : "\xA4"),
                                      2, le_value, &buffer, &buflen);
       if (err)
         {
           /* Yubikey returns wrong code.  Fix it up.  */
           /*
            * NOTE: It's not correct to blindly change the error code,
            * however, for our experiences, it is only Yubikey...
            */
           err = gpg_error (GPG_ERR_NO_OBJ);
           log_error (_("reading public key failed: %s\n"), gpg_strerror (err));
           goto leave;
         }
 
       err = read_public_key (app, NULL, 0U, keyno, buffer, buflen);
     }
   else
     {
       /* Due to a design problem in v1.0 cards we can't get the public
          key out of these cards without doing a verify on CHV3.
          Clearly that is not an option and thus we try to locate the
          key using an external helper.
 
          The helper we use here is gpg itself, which should know about
          the key in any case.  */
 
       char fpr[41];
       char *hexkeyid;
       char *command = NULL;
       FILE *fp;
       int ret;
 
       buffer = NULL; /* We don't need buffer.  */
 
       err = retrieve_fpr_from_card (app, keyno, fpr);
       if (err)
         {
           log_error ("error while retrieving fpr from card: %s\n",
                      gpg_strerror (err));
           goto leave;
         }
       hexkeyid = fpr + 24;
 
       ret = gpgrt_asprintf
         (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr);
       if (ret < 0)
         {
           err = gpg_error_from_syserror ();
           goto leave;
         }
 
       fp = popen (command, "r");
       xfree (command);
       if (!fp)
         {
           err = gpg_error_from_syserror ();
           log_error ("running gpg failed: %s\n", gpg_strerror (err));
           goto leave;
         }
 
       err = retrieve_key_material (fp, hexkeyid, &m, &mlen, &e, &elen);
       pclose (fp);
       if (err)
         {
           log_error ("error while retrieving key material through pipe: %s\n",
                      gpg_strerror (err));
           goto leave;
         }
 
       err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))",
                              (int)mlen, m, (int)elen, e);
       if (err)
         goto leave;
 
       len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
 
       keybuf = xtrymalloc (len);
       if (!keybuf)
         {
           err = gpg_error_from_syserror ();
           gcry_sexp_release (s_pkey);
           goto leave;
         }
 
       gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
       gcry_sexp_release (s_pkey);
 
       app->app_local->pk[keyno].key = (unsigned char*)keybuf;
       /* Decrement for trailing '\0' */
       app->app_local->pk[keyno].keylen = len - 1;
 
       err = store_keygrip (app, keyno);
     }
 
  leave:
   /* Set a flag to indicate that we tried to read the key.  */
   if (!err)
     app->app_local->pk[keyno].read_done = 1;
 
   xfree (buffer);
   return err;
 }
 
 
 /* Send the KEYPAIRINFO back. KEY needs to be in the range [1,3].
    This is used by the LEARN command. */
 static gpg_error_t
 send_keypair_info (app_t app, ctrl_t ctrl, int key)
 {
   int keyno = key - 1;
   gpg_error_t err = 0;
   char idbuf[50];
   const char *usage;
 
   err = get_public_key (app, keyno);
   if (err)
     goto leave;
 
   assert (keyno >= 0 && keyno <= 2);
   if (!app->app_local->pk[keyno].key)
     goto leave; /* No such key - ignore. */
 
   switch (keyno)
     {
     case 0: usage = "sc"; break;
     case 1: usage = "e";  break;
     case 2: usage = "sa"; break;
     default: usage = "";  break;
     }
 
   sprintf (idbuf, "OPENPGP.%d", keyno+1);
   send_status_info (ctrl, "KEYPAIRINFO",
                     app->app_local->pk[keyno].keygrip_str, 40,
                     idbuf, strlen (idbuf),
                     usage, strlen (usage),
                     NULL, (size_t)0);
 
  leave:
   return err;
 }
 
 
 /* Handle the LEARN command for OpenPGP.  */
 static gpg_error_t
 do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
 {
   gpg_error_t err = 0;
 
   (void)flags;
 
   err = do_getattr (app, ctrl, "EXTCAP");
   if (!err)
     err = do_getattr (app, ctrl, "MANUFACTURER");
   if (!err)
     err = do_getattr (app, ctrl, "DISP-NAME");
   if (!err)
     err = do_getattr (app, ctrl, "DISP-LANG");
   if (!err)
     err = do_getattr (app, ctrl, "DISP-SEX");
   if (!err)
     err = do_getattr (app, ctrl, "PUBKEY-URL");
   if (!err)
     err = do_getattr (app, ctrl, "LOGIN-DATA");
   if (!err)
     err = do_getattr (app, ctrl, "KEY-FPR");
   if (!err && app->appversion > 0x0100)
     err = do_getattr (app, ctrl, "KEY-TIME");
   if (!err)
     err = do_getattr (app, ctrl, "CA-FPR");
   if (!err)
     err = do_getattr (app, ctrl, "CHV-STATUS");
   if (!err)
     err = do_getattr (app, ctrl, "SIG-COUNTER");
   if (!err && app->app_local->extcap.kdf_do)
     {
       err = do_getattr (app, ctrl, "KDF");
       if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
         err = 0;
     }
   if (!err && app->app_local->extcap.private_dos)
     {
       if (!err)
         err = do_getattr (app, ctrl, "PRIVATE-DO-1");
       if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
         err = 0;
       if (!err)
         err = do_getattr (app, ctrl, "PRIVATE-DO-2");
       if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
         err = 0;
       if (!err && app->did_chv2)
         err = do_getattr (app, ctrl, "PRIVATE-DO-3");
       if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
         err = 0;
       if (!err && app->did_chv3)
         err = do_getattr (app, ctrl, "PRIVATE-DO-4");
       if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
         err = 0;
     }
   if (!err)
     err = send_keypair_info (app, ctrl, 1);
   if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
     err = 0;
   if (!err)
     err = send_keypair_info (app, ctrl, 2);
   if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
     err = 0;
   if (!err)
     err = send_keypair_info (app, ctrl, 3);
   if (gpg_err_code (err) == GPG_ERR_NO_OBJ)
     err = 0;
   /* Note: We do not send the Cardholder Certificate, because that is
      relatively long and for OpenPGP applications not really needed.  */
   return err;
 }
 
 
 /* Handle the READKEY command for OpenPGP.  On success a canonical
    encoded S-expression with the public key will get stored at PK and
    its length (for assertions) at PKLEN; the caller must release that
    buffer. On error PK and PKLEN are not changed and an error code is
    returned.  */
 static gpg_error_t
 do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags,
             unsigned char **pk, size_t *pklen)
 {
   gpg_error_t err;
   int keyno;
   unsigned char *buf;
 
   (void)ctrl;
 
   if (!strcmp (keyid, "OPENPGP.1"))
     keyno = 0;
   else if (!strcmp (keyid, "OPENPGP.2"))
     keyno = 1;
   else if (!strcmp (keyid, "OPENPGP.3"))
     keyno = 2;
   else
     return gpg_error (GPG_ERR_INV_ID);
 
   err = get_public_key (app, keyno);
   if (err)
     return err;
 
   buf = app->app_local->pk[keyno].key;
   if (!buf)
     return gpg_error (GPG_ERR_NO_PUBKEY);
 
   if ((flags & APP_READKEY_FLAG_ADVANCED))
     {
       gcry_sexp_t s_key;
 
       err = gcry_sexp_new (&s_key, buf, app->app_local->pk[keyno].keylen, 0);
       if (err)
         return err;
 
       *pklen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, NULL, 0);
       *pk = xtrymalloc (*pklen);
       if (!*pk)
         {
           err = gpg_error_from_syserror ();
           *pklen = 0;
           return err;
         }
 
       gcry_sexp_sprint (s_key, GCRYSEXP_FMT_ADVANCED, *pk, *pklen);
       gcry_sexp_release (s_key);
       /* Decrement for trailing '\0' */
       *pklen = *pklen - 1;
     }
   else
     {
       *pklen = app->app_local->pk[keyno].keylen;
       *pk = xtrymalloc (*pklen);
       if (!*pk)
         {
           err = gpg_error_from_syserror ();
           *pklen = 0;
           return err;
         }
       memcpy (*pk, buf, *pklen);
     }
 
   return 0;
 }
 
 /* Read the standard certificate of an OpenPGP v2 card.  It is
    returned in a freshly allocated buffer with that address stored at
    CERT and the length of the certificate stored at CERTLEN.  CERTID
    needs to be set to "OPENPGP.3".  */
 static gpg_error_t
 do_readcert (app_t app, const char *certid,
              unsigned char **cert, size_t *certlen)
 {
   gpg_error_t err;
   unsigned char *buffer;
   size_t buflen;
   void *relptr;
 
   *cert = NULL;
   *certlen = 0;
   if (strcmp (certid, "OPENPGP.3"))
     return gpg_error (GPG_ERR_INV_ID);
   if (!app->app_local->extcap.is_v2)
     return gpg_error (GPG_ERR_NOT_FOUND);
 
   relptr = get_one_do (app, 0x7F21, &buffer, &buflen, NULL);
   if (!relptr)
     return gpg_error (GPG_ERR_NOT_FOUND);
 
   if (!buflen)
     err = gpg_error (GPG_ERR_NOT_FOUND);
   else if (!(*cert = xtrymalloc (buflen)))
     err = gpg_error_from_syserror ();
   else
     {
       memcpy (*cert, buffer, buflen);
       *certlen = buflen;
       err  = 0;
     }
   xfree (relptr);
   return err;
 }
 
 
 /* Decide if we use the pinpad of the reader for PIN input according
    to the user preference on the card, and the capability of the
    reader.  This routine is only called when the reader has pinpad.
    Returns 0 if we use pinpad, 1 otherwise.  */
 static int
 check_pinpad_request (app_t app, pininfo_t *pininfo, int admin_pin)
 {
   if (app->app_local->pinpad.disabled)
     return 1;
 
   if (app->app_local->pinpad.specified == 0) /* No preference on card.  */
     {
       if (pininfo->fixedlen == 0) /* Reader has varlen capability.  */
         return 0;                 /* Then, use pinpad.  */
       else
         /*
          * Reader has limited capability, and it may not match PIN of
          * the card.
          */
         return 1;
     }
 
   if (admin_pin)
     pininfo->fixedlen = app->app_local->pinpad.fixedlen_admin;
   else
     pininfo->fixedlen = app->app_local->pinpad.fixedlen_user;
 
   if (pininfo->fixedlen == 0    /* User requests disable pinpad.  */
       || pininfo->fixedlen < pininfo->minlen
       || pininfo->fixedlen > pininfo->maxlen
       /* Reader doesn't have the capability to input a PIN which
        * length is FIXEDLEN.  */)
     return 1;
 
   return 0;
 }
 
 
 /* Return a string with information about the card for use in a
  * prompt.  Returns NULL on memory failure.  */
 static char *
 get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining)
 {
   char *serial, *disp_name, *rembuf, *tmpbuf, *result;
 
   serial = get_disp_serialno (app);
   if (!serial)
     return NULL;
 
   disp_name = get_disp_name (app);
   if (chvno == 1)
     {
       /* TRANSLATORS: Put a \x1f right before a colon.  This can be
        * used by pinentry to nicely align the names and values.  Keep
        * the %s at the start and end of the string.  */
       result = xtryasprintf (_("%s"
                                "Number\x1f: %s%%0A"
                                "Holder\x1f: %s%%0A"
                                "Counter\x1f: %lu"
                                "%s"),
                              "\x1e",
                              serial,
                              disp_name? disp_name:"",
                              sigcount,
                              "");
     }
   else
     {
       result = xtryasprintf (_("%s"
                                "Number\x1f: %s%%0A"
                                "Holder\x1f: %s"
                                "%s"),
                              "\x1e",
                              serial,
                              disp_name? disp_name:"",
                              "");
     }
   xfree (disp_name);
   xfree (serial);
 
   if (remaining != -1)
     {
       /* TRANSLATORS: This is the number of remaining attempts to
        * enter a PIN.  Use %%0A (double-percent,0A) for a linefeed. */
       rembuf = xtryasprintf (_("Remaining attempts: %d"), remaining);
       if (!rembuf)
         {
           xfree (result);
           return NULL;
         }
       tmpbuf = strconcat (result, "%0A%0A", rembuf, NULL);
       xfree (rembuf);
       if (!tmpbuf)
         {
           xfree (result);
           return NULL;
         }
       xfree (result);
       result = tmpbuf;
     }
 
   return result;
 }
 
 /* Compute hash if KDF-DO is available.  CHVNO must be 0 for reset
    code, 1 or 2 for user pin and 3 for admin pin.
  */
 static gpg_error_t
 pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
 {
   gpg_error_t err = 0;
   void *relptr = NULL;
   unsigned char *buffer;
   size_t buflen;
 
   if (app->app_local->extcap.kdf_do
       && (relptr = get_one_do (app, 0x00F9, &buffer, &buflen, NULL))
       && buflen >= KDF_DATA_LENGTH_MIN && (buffer[2] == 0x03))
     {
       const char *salt;
       unsigned long s2k_count;
       char dek[32];
       int salt_index;
 
       s2k_count = (((unsigned int)buffer[8] << 24)
                    | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]);
 
       if (buflen == KDF_DATA_LENGTH_MIN)
         salt_index =14;
       else if (buflen == KDF_DATA_LENGTH_MAX)
         salt_index = (chvno==3 ? 34 : (chvno==0 ? 24 : 14));
       else
         {
           err = gpg_error (GPG_ERR_INV_DATA);
           goto leave;
         }
 
       salt = &buffer[salt_index];
       err = gcry_kdf_derive (pinvalue, strlen (pinvalue),
                              GCRY_KDF_ITERSALTED_S2K,
                              DIGEST_ALGO_SHA256, salt, 8,
                              s2k_count, sizeof (dek), dek);
       if (!err)
         {
           /* pinvalue has a buffer of MAXLEN_PIN+1, 32 is OK.  */
           *r_pinlen = 32;
           memcpy (pinvalue, dek, *r_pinlen);
           wipememory (dek, *r_pinlen);
         }
    }
   else
     *r_pinlen = strlen (pinvalue);
 
  leave:
   xfree (relptr);
   return err;
 }
 
 
 /* Verify a CHV either using the pinentry or if possible by
    using a pinpad.  PINCB and PINCB_ARG describe the usual callback
    for the pinentry.  CHVNO must be either 1 or 2. SIGCOUNT is only
    used with CHV1.  PINVALUE is the address of a pointer which will
    receive a newly allocated block with the actual PIN (this is useful
    in case that PIN shall be used for another verify operation).  The
    caller needs to free this value.  If the function returns with
    success and NULL is stored at PINVALUE, the caller should take this
    as an indication that the pinpad has been used.
    */
 static gpg_error_t
 verify_a_chv (app_t app,
               gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg, int chvno, unsigned long sigcount,
               char **pinvalue, int *pinlen)
 {
   int rc = 0;
   char *prompt_buffer = NULL;
   const char *prompt;
   pininfo_t pininfo;
   int minlen = 6;
   int remaining;
 
   log_assert (chvno == 1 || chvno == 2);
 
   *pinvalue = NULL;
   *pinlen = 0;
 
   remaining = get_remaining_tries (app, 0);
   if (remaining == -1)
     return gpg_error (GPG_ERR_CARD);
 
   if (chvno == 2 && app->app_local->flags.def_chv2)
     {
       /* Special case for def_chv2 mechanism. */
       if (opt.verbose)
         log_info (_("using default PIN as %s\n"), "CHV2");
       rc = iso7816_verify (app->slot, 0x82, "123456", 6);
       if (rc)
         {
           /* Verification of CHV2 with the default PIN failed,
              although the card pretends to have the default PIN set as
              CHV2.  We better disable the def_chv2 flag now. */
           log_info (_("failed to use default PIN as %s: %s"
                       " - disabling further default use\n"),
                     "CHV2", gpg_strerror (rc));
           app->app_local->flags.def_chv2 = 0;
         }
       return rc;
     }
 
   memset (&pininfo, 0, sizeof pininfo);
   pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
 
   {
     const char *firstline = _("||Please unlock the card");
     char *infoblock = get_prompt_info (app, chvno, sigcount,
                                        remaining < 3? remaining : -1);
 
     prompt_buffer = strconcat (firstline, "%0A%0A", infoblock, NULL);
     if (prompt_buffer)
       prompt = prompt_buffer;
     else
       prompt = firstline;  /* ENOMEM fallback.  */
 
     xfree (infoblock);
   }
 
   if (!opt.disable_pinpad
       && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
       && !check_pinpad_request (app, &pininfo, 0))
     {
       /* The reader supports the verify command through the pinpad.
          Note that the pincb appends a text to the prompt telling the
          user to use the pinpad. */
       rc = pincb (pincb_arg, prompt, NULL);
       prompt = NULL;
       xfree (prompt_buffer);
       prompt_buffer = NULL;
       if (rc)
         {
           log_info (_("PIN callback returned error: %s\n"),
                     gpg_strerror (rc));
           return rc;
         }
       rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo);
       /* Dismiss the prompt. */
       pincb (pincb_arg, NULL, NULL);
 
       log_assert (!*pinvalue);
     }
   else
     {
       /* The reader has no pinpad or we don't want to use it. */
       rc = pincb (pincb_arg, prompt, pinvalue);
       prompt = NULL;
       xfree (prompt_buffer);
       prompt_buffer = NULL;
       if (rc)
         {
           log_info (_("PIN callback returned error: %s\n"),
                     gpg_strerror (rc));
           return rc;
         }
 
       if (strlen (*pinvalue) < minlen)
         {
           log_error (_("PIN for CHV%d is too short;"
                        " minimum length is %d\n"), chvno, minlen);
           xfree (*pinvalue);
           *pinvalue = NULL;
           return gpg_error (GPG_ERR_BAD_PIN);
         }
 
       rc = pin2hash_if_kdf (app, chvno, *pinvalue, pinlen);
       if (!rc)
         rc = iso7816_verify (app->slot, 0x80+chvno, *pinvalue, *pinlen);
     }
 
   if (rc)
     {
       log_error (_("verify CHV%d failed: %s\n"), chvno, gpg_strerror (rc));
       xfree (*pinvalue);
       *pinvalue = NULL;
       flush_cache_after_error (app);
     }
 
   return rc;
 }
 
 
 /* Verify CHV2 if required.  Depending on the configuration of the
    card CHV1 will also be verified. */
 static gpg_error_t
 verify_chv2 (app_t app,
              gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg)
 {
   int rc;
   char *pinvalue;
   int pinlen;
   int i;
 
   if (app->did_chv2)
     return 0;  /* We already verified CHV2.  */
 
   /* Make sure we have load the public keys.  */
   for (i = 0; i < 3; i++)
     get_public_key (app, i);
 
   if (app->app_local->pk[1].key || app->app_local->pk[2].key)
     {
       rc = verify_a_chv (app, pincb, pincb_arg, 2, 0, &pinvalue, &pinlen);
       if (rc)
         return rc;
       app->did_chv2 = 1;
 
-      if (!app->did_chv1 && !app->force_chv1 && pinvalue)
+      if (!app->did_chv1 && !app->force_chv1 && pinvalue && !opt.pcsc_shared)
         {
           /* For convenience we verify CHV1 here too.  We do this only if
              the card is not configured to require a verification before
              each CHV1 controlled operation (force_chv1) and if we are not
              using the pinpad (PINVALUE == NULL). */
           rc = iso7816_verify (app->slot, 0x81, pinvalue, pinlen);
           if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
             rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
           if (rc)
             {
               log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
               flush_cache_after_error (app);
             }
           else
             app->did_chv1 = 1;
         }
     }
   else
     {
       rc = verify_a_chv (app, pincb, pincb_arg, 1, 0, &pinvalue, &pinlen);
       if (rc)
         return rc;
     }
 
   xfree (pinvalue);
 
   return rc;
 }
 
 
 /* Build the prompt to enter the Admin PIN.  The prompt depends on the
    current sdtate of the card.  */
 static gpg_error_t
 build_enter_admin_pin_prompt (app_t app, char **r_prompt)
 {
   int remaining;
   char *prompt;
   char *infoblock;
 
   *r_prompt = NULL;
 
   remaining = get_remaining_tries (app, 1);
   if (remaining == -1)
     return gpg_error (GPG_ERR_CARD);
   if (!remaining)
     {
       log_info (_("card is permanently locked!\n"));
       return gpg_error (GPG_ERR_BAD_PIN);
     }
 
   log_info (ngettext("%d Admin PIN attempt remaining before card"
                      " is permanently locked\n",
                      "%d Admin PIN attempts remaining before card"
                      " is permanently locked\n",
                      remaining), remaining);
 
   infoblock = get_prompt_info (app, 3, 0, remaining < 3? remaining : -1);
 
   /* TRANSLATORS: Do not translate the "|A|" prefix but keep it at
      the start of the string.  Use %0A (single percent) for a linefeed.  */
   prompt = strconcat (_("|A|Please enter the Admin PIN"),
                       "%0A%0A", infoblock, NULL);
   xfree (infoblock);
   if (!prompt)
     return gpg_error_from_syserror ();
 
   *r_prompt = prompt;
   return 0;
 }
 
 
 /* Verify CHV3 if required. */
 static gpg_error_t
 verify_chv3 (app_t app,
              gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg)
 {
   int rc = 0;
 
   if (!opt.allow_admin)
     {
       log_info (_("access to admin commands is not configured\n"));
       return gpg_error (GPG_ERR_EACCES);
     }
 
   if (!app->did_chv3)
     {
       pininfo_t pininfo;
       int minlen = 8;
       char *prompt;
 
       memset (&pininfo, 0, sizeof pininfo);
       pininfo.fixedlen = -1;
       pininfo.minlen = minlen;
 
       rc = build_enter_admin_pin_prompt (app, &prompt);
       if (rc)
         return rc;
 
       if (!opt.disable_pinpad
           && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
           && !check_pinpad_request (app, &pininfo, 1))
         {
           /* The reader supports the verify command through the pinpad. */
           rc = pincb (pincb_arg, prompt, NULL);
           xfree (prompt);
           prompt = NULL;
           if (rc)
             {
               log_info (_("PIN callback returned error: %s\n"),
                         gpg_strerror (rc));
               return rc;
             }
           rc = iso7816_verify_kp (app->slot, 0x83, &pininfo);
           /* Dismiss the prompt. */
           pincb (pincb_arg, NULL, NULL);
         }
       else
         {
           char *pinvalue;
           int pinlen;
 
           rc = pincb (pincb_arg, prompt, &pinvalue);
           xfree (prompt);
           prompt = NULL;
           if (rc)
             {
               log_info (_("PIN callback returned error: %s\n"),
                         gpg_strerror (rc));
               return rc;
             }
 
           if (strlen (pinvalue) < minlen)
             {
               log_error (_("PIN for CHV%d is too short;"
                            " minimum length is %d\n"), 3, minlen);
               xfree (pinvalue);
               return gpg_error (GPG_ERR_BAD_PIN);
             }
 
           rc = pin2hash_if_kdf (app, 3, pinvalue, &pinlen);
           if (!rc)
             rc = iso7816_verify (app->slot, 0x83, pinvalue, pinlen);
           xfree (pinvalue);
         }
 
       if (rc)
         {
           log_error (_("verify CHV%d failed: %s\n"), 3, gpg_strerror (rc));
           flush_cache_after_error (app);
           return rc;
         }
       app->did_chv3 = 1;
     }
   return rc;
 }
 
 
 /* Handle the SETATTR operation. All arguments are already basically
    checked. */
 static gpg_error_t
 do_setattr (app_t app, ctrl_t ctrl, const char *name,
             gpg_error_t (*pincb)(void*, const char *, char **),
             void *pincb_arg,
             const unsigned char *value, size_t valuelen)
 {
   gpg_error_t rc;
   int idx;
   static struct {
     const char *name;
     int tag;
     int flush_tag;  /* The tag which needs to be flushed or 0. */
     int need_chv;
     int special;
     unsigned int need_v2:1;
   } table[] = {
     { "DISP-NAME",    0x005B, 0,      3 },
     { "LOGIN-DATA",   0x005E, 0,      3, 2 },
     { "DISP-LANG",    0x5F2D, 0,      3 },
     { "DISP-SEX",     0x5F35, 0,      3 },
     { "PUBKEY-URL",   0x5F50, 0,      3 },
     { "CHV-STATUS-1", 0x00C4, 0,      3, 1 },
     { "CA-FPR-1",     0x00CA, 0x00C6, 3 },
     { "CA-FPR-2",     0x00CB, 0x00C6, 3 },
     { "CA-FPR-3",     0x00CC, 0x00C6, 3 },
     { "PRIVATE-DO-1", 0x0101, 0,      2 },
     { "PRIVATE-DO-2", 0x0102, 0,      3 },
     { "PRIVATE-DO-3", 0x0103, 0,      2 },
     { "PRIVATE-DO-4", 0x0104, 0,      3 },
     { "CERT-3",       0x7F21, 0,      3, 0, 1 },
     { "SM-KEY-ENC",   0x00D1, 0,      3, 0, 1 },
     { "SM-KEY-MAC",   0x00D2, 0,      3, 0, 1 },
     { "KEY-ATTR",     0,      0,      0, 3, 1 },
     { "AESKEY",       0x00D5, 0,      3, 0, 1 },
     { "KDF",          0x00F9, 0,      3, 4, 1 },
     { NULL, 0 }
   };
   int exmode;
 
   (void)ctrl;
 
   for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
     ;
   if (!table[idx].name)
     return gpg_error (GPG_ERR_INV_NAME);
   if (table[idx].need_v2 && !app->app_local->extcap.is_v2)
     return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Not yet supported.  */
 
   if (table[idx].special == 3)
     return change_keyattr_from_string (app, pincb, pincb_arg, value, valuelen);
 
   switch (table[idx].need_chv)
     {
     case 2:
       rc = verify_chv2 (app, pincb, pincb_arg);
       break;
     case 3:
       rc = verify_chv3 (app, pincb, pincb_arg);
       break;
     default:
       rc = 0;
     }
   if (rc)
     return rc;
 
   /* Flush the cache before writing it, so that the next get operation
      will reread the data from the card and thus get synced in case of
      errors (e.g. data truncated by the card). */
   flush_cache_item (app, table[idx].flush_tag? table[idx].flush_tag
                     /* */                    : table[idx].tag);
 
   if (app->app_local->cardcap.ext_lc_le && valuelen > 254)
     exmode = 1;    /* Use extended length w/o a limit.  */
   else if (app->app_local->cardcap.cmd_chaining && valuelen > 254)
     exmode = -254; /* Command chaining with max. 254 bytes.  */
   else
     exmode = 0;
   rc = iso7816_put_data (app->slot, exmode, table[idx].tag, value, valuelen);
   if (rc)
     log_error ("failed to set '%s': %s\n", table[idx].name, gpg_strerror (rc));
 
   if (table[idx].special == 1)
     app->force_chv1 = (valuelen && *value == 0);
   else if (table[idx].special == 2)
     parse_login_data (app);
   else if (table[idx].special == 4)
     {
       app->did_chv1 = 0;
       app->did_chv2 = 0;
       app->did_chv3 = 0;
 
       if ((valuelen == KDF_DATA_LENGTH_MIN || valuelen == KDF_DATA_LENGTH_MAX)
           && (value[2] == 0x03))
         app->app_local->pinpad.disabled = 1;
       else
         app->app_local->pinpad.disabled = 0;
     }
 
   return rc;
 }
 
 
 /* Handle the WRITECERT command for OpenPGP.  This rites the standard
    certifciate to the card; CERTID needs to be set to "OPENPGP.3".
    PINCB and PINCB_ARG are the usual arguments for the pinentry
    callback.  */
 static gpg_error_t
 do_writecert (app_t app, ctrl_t ctrl,
               const char *certidstr,
               gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg,
               const unsigned char *certdata, size_t certdatalen)
 {
   if (strcmp (certidstr, "OPENPGP.3"))
     return gpg_error (GPG_ERR_INV_ID);
   if (!certdata || !certdatalen)
     return gpg_error (GPG_ERR_INV_ARG);
   if (!app->app_local->extcap.is_v2)
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
   if (certdatalen > app->app_local->extcap.max_certlen_3)
     return gpg_error (GPG_ERR_TOO_LARGE);
   return do_setattr (app, ctrl, "CERT-3", pincb, pincb_arg,
                      certdata, certdatalen);
 }
 
 
 
 /* Handle the PASSWD command.  The following combinations are
    possible:
 
     Flags  CHVNO Vers.  Description
     RESET    1   1      Verify CHV3 and set a new CHV1 and CHV2
     RESET    1   2      Verify PW3 and set a new PW1.
     RESET    2   1      Verify CHV3 and set a new CHV1 and CHV2.
     RESET    2   2      Verify PW3 and set a new Reset Code.
     RESET    3   any    Returns GPG_ERR_INV_ID.
      -       1   1      Verify CHV2 and set a new CHV1 and CHV2.
      -       1   2      Verify PW1 and set a new PW1.
      -       2   1      Verify CHV2 and set a new CHV1 and CHV2.
      -       2   2      Verify Reset Code and set a new PW1.
      -       3   any    Verify CHV3/PW3 and set a new CHV3/PW3.
 
    The CHVNO can be prefixed with "OPENPGP.".
  */
 static gpg_error_t
 do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
                unsigned int flags,
                gpg_error_t (*pincb)(void*, const char *, char **),
                void *pincb_arg)
 {
   int rc = 0;
   int chvno;
   char *resetcode = NULL;
   char *oldpinvalue = NULL;
   char *pinvalue = NULL;
   int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
   int set_resetcode = 0;
   pininfo_t pininfo;
   int use_pinpad = 0;
   int minlen = 6;
   int pinlen0 = 0;
   int pinlen = 0;
 
   (void)ctrl;
 
   if (digitp (chvnostr))
     chvno = atoi (chvnostr);
   else if (!ascii_strcasecmp (chvnostr, "OPENPGP.1"))
     chvno = 1;
   else if (!ascii_strcasecmp (chvnostr, "OPENPGP.2"))
     chvno = 2;
   else if (!ascii_strcasecmp (chvnostr, "OPENPGP.3"))
     chvno = 3;
   else
     return gpg_error (GPG_ERR_INV_ID);
 
   memset (&pininfo, 0, sizeof pininfo);
   pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
 
   if ((flags & APP_CHANGE_FLAG_CLEAR))
     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
 
   if (reset_mode && chvno == 3)
     {
       rc = gpg_error (GPG_ERR_INV_ID);
       goto leave;
     }
 
   if (!app->app_local->extcap.is_v2)
     {
       /* Version 1 cards.  */
 
       if (reset_mode || chvno == 3)
         {
           /* We always require that the PIN is entered. */
           app->did_chv3 = 0;
           rc = verify_chv3 (app, pincb, pincb_arg);
           if (rc)
             goto leave;
         }
       else if (chvno == 1 || chvno == 2)
         {
           /* On a v1.x card CHV1 and CVH2 should always have the same
              value, thus we enforce it here.  */
           int save_force = app->force_chv1;
 
           app->force_chv1 = 0;
           app->did_chv1 = 0;
           app->did_chv2 = 0;
           rc = verify_chv2 (app, pincb, pincb_arg);
           app->force_chv1 = save_force;
           if (rc)
             goto leave;
         }
       else
         {
           rc = gpg_error (GPG_ERR_INV_ID);
           goto leave;
         }
     }
   else
     {
       /* Version 2 cards.  */
 
       if (!opt.disable_pinpad
           && !iso7816_check_pinpad (app->slot,
                                     ISO7816_CHANGE_REFERENCE_DATA, &pininfo)
           && !check_pinpad_request (app, &pininfo, chvno == 3))
         use_pinpad = 1;
 
       if (reset_mode)
         {
           /* To reset a PIN the Admin PIN is required. */
           use_pinpad = 0;
           app->did_chv3 = 0;
           rc = verify_chv3 (app, pincb, pincb_arg);
           if (rc)
             goto leave;
 
           if (chvno == 2)
             set_resetcode = 1;
         }
       else if (chvno == 1 || chvno == 3)
         {
           if (!use_pinpad)
             {
               char *promptbuf = NULL;
               const char *prompt;
 
               if (chvno == 3)
                 {
                   minlen = 8;
                   rc = build_enter_admin_pin_prompt (app, &promptbuf);
                   if (rc)
                     goto leave;
                   prompt = promptbuf;
                 }
               else
                 prompt = _("||Please enter the PIN");
               rc = pincb (pincb_arg, prompt, &oldpinvalue);
               xfree (promptbuf);
               promptbuf = NULL;
               if (rc)
                 {
                   log_info (_("PIN callback returned error: %s\n"),
                             gpg_strerror (rc));
                   goto leave;
                 }
 
               if (strlen (oldpinvalue) < minlen)
                 {
                   log_info (_("PIN for CHV%d is too short;"
                               " minimum length is %d\n"), chvno, minlen);
                   rc = gpg_error (GPG_ERR_BAD_PIN);
                   goto leave;
                 }
             }
         }
       else if (chvno == 2)
         {
           /* There is no PW2 for v2 cards.  We use this condition to
              allow a PW reset using the Reset Code.  */
           void *relptr;
           unsigned char *value;
           size_t valuelen;
           int remaining;
 
           use_pinpad = 0;
           minlen = 8;
           relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
           if (!relptr || valuelen < 7)
             {
               log_error (_("error retrieving CHV status from card\n"));
               xfree (relptr);
               rc = gpg_error (GPG_ERR_CARD);
               goto leave;
             }
           remaining = value[5];
           xfree (relptr);
           if (!remaining)
             {
               log_error (_("Reset Code not or not anymore available\n"));
               rc = gpg_error (GPG_ERR_BAD_PIN);
               goto leave;
             }
 
           rc = pincb (pincb_arg,
                       _("||Please enter the Reset Code for the card"),
                       &resetcode);
           if (rc)
             {
               log_info (_("PIN callback returned error: %s\n"),
                         gpg_strerror (rc));
               goto leave;
             }
           if (strlen (resetcode) < minlen)
             {
               log_info (_("Reset Code is too short; minimum length is %d\n"),
                         minlen);
               rc = gpg_error (GPG_ERR_BAD_PIN);
               goto leave;
             }
         }
       else
         {
           rc = gpg_error (GPG_ERR_INV_ID);
           goto leave;
         }
     }
 
   if (chvno == 3)
     app->did_chv3 = 0;
   else
     app->did_chv1 = app->did_chv2 = 0;
 
   if (!use_pinpad)
     {
       /* TRANSLATORS: Do not translate the "|*|" prefixes but
          keep it at the start of the string.  We need this elsewhere
          to get some infos on the string. */
       rc = pincb (pincb_arg, set_resetcode? _("|RN|New Reset Code") :
                   chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
                   &pinvalue);
       if (rc || pinvalue == NULL)
         {
           log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
           goto leave;
         }
     }
 
 
   if (resetcode)
     {
       char *buffer;
 
       buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1);
       if (!buffer)
         rc = gpg_error_from_syserror ();
       else
         {
           strcpy (buffer, resetcode);
           rc = pin2hash_if_kdf (app, 0, buffer, &pinlen0);
           if (!rc)
             {
               strcpy (buffer+pinlen0, pinvalue);
               rc = pin2hash_if_kdf (app, 0, buffer+pinlen0, &pinlen);
             }
           if (!rc)
             rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
                                                       buffer, pinlen0+pinlen);
           wipememory (buffer, pinlen0 + pinlen);
           xfree (buffer);
         }
     }
   else if (set_resetcode)
     {
       if (strlen (pinvalue) < 8)
         {
           log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
           rc = gpg_error (GPG_ERR_BAD_PIN);
         }
       else
         {
           rc = pin2hash_if_kdf (app, 0, pinvalue, &pinlen);
           if (!rc)
             rc = iso7816_put_data (app->slot, 0, 0xD3, pinvalue, pinlen);
         }
     }
   else if (reset_mode)
     {
       rc = pin2hash_if_kdf (app, 1, pinvalue, &pinlen);
       if (!rc)
         rc = iso7816_reset_retry_counter (app->slot, 0x81, pinvalue, pinlen);
       if (!rc && !app->app_local->extcap.is_v2)
         rc = iso7816_reset_retry_counter (app->slot, 0x82, pinvalue, pinlen);
     }
   else if (!app->app_local->extcap.is_v2)
     {
       /* Version 1 cards.  */
       if (chvno == 1 || chvno == 2)
         {
           rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
                                               pinvalue, strlen (pinvalue));
           if (!rc)
             rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
                                                 pinvalue, strlen (pinvalue));
         }
       else /* CHVNO == 3 */
         {
           rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
                                               pinvalue, strlen (pinvalue));
         }
     }
   else
     {
       /* Version 2 cards.  */
       assert (chvno == 1 || chvno == 3);
 
       if (use_pinpad)
         {
           rc = pincb (pincb_arg,
                       chvno == 3 ?
                       _("||Please enter the Admin PIN and New Admin PIN") :
                       _("||Please enter the PIN and New PIN"), NULL);
           if (rc)
             {
               log_info (_("PIN callback returned error: %s\n"),
                         gpg_strerror (rc));
               goto leave;
             }
           rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno, 0,
                                                  &pininfo);
           pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
         }
       else
 	{
           rc = pin2hash_if_kdf (app, chvno, oldpinvalue, &pinlen0);
           if (!rc)
 	    rc = pin2hash_if_kdf (app, chvno, pinvalue, &pinlen);
           if (!rc)
             rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
                                                 oldpinvalue, pinlen0,
                                                 pinvalue, pinlen);
         }
     }
 
   if (pinvalue)
     {
       wipememory (pinvalue, pinlen);
       xfree (pinvalue);
     }
   if (rc)
     flush_cache_after_error (app);
 
  leave:
   if (resetcode)
     {
       wipememory (resetcode, strlen (resetcode));
       xfree (resetcode);
     }
   if (oldpinvalue)
     {
       wipememory (oldpinvalue, pinlen0);
       xfree (oldpinvalue);
     }
   return rc;
 }
 
 
 /* Check whether a key already exists.  KEYIDX is the index of the key
    (0..2).  If FORCE is TRUE a diagnositic will be printed but no
    error returned if the key already exists.  The flag GENERATING is
    only used to print correct messages. */
 static gpg_error_t
 does_key_exist (app_t app, int keyidx, int generating, int force)
 {
   const unsigned char *fpr;
   unsigned char *buffer;
   size_t buflen, n;
   int i;
 
   assert (keyidx >=0 && keyidx <= 2);
 
   if (iso7816_get_data (app->slot, 0, 0x006E, &buffer, &buflen))
     {
       log_error (_("error reading application data\n"));
       return gpg_error (GPG_ERR_GENERAL);
     }
   fpr = find_tlv (buffer, buflen, 0x00C5, &n);
   if (!fpr || n < 60)
     {
       log_error (_("error reading fingerprint DO\n"));
       xfree (buffer);
       return gpg_error (GPG_ERR_GENERAL);
     }
   fpr += 20*keyidx;
   for (i=0; i < 20 && !fpr[i]; i++)
     ;
   xfree (buffer);
   if (i!=20 && !force)
     {
       log_error (_("key already exists\n"));
       return gpg_error (GPG_ERR_EEXIST);
     }
   else if (i!=20)
     log_info (_("existing key will be replaced\n"));
   else if (generating)
     log_info (_("generating new key\n"));
   else
     log_info (_("writing new key\n"));
   return 0;
 }
 
 
 /* Create a TLV tag and value and store it at BUFFER.  Return the length
    of tag and length.  A LENGTH greater than 65535 is truncated. */
 static size_t
 add_tlv (unsigned char *buffer, unsigned int tag, size_t length)
 {
   unsigned char *p = buffer;
 
   assert (tag <= 0xffff);
   if ( tag > 0xff )
     *p++ = tag >> 8;
   *p++ = tag;
   if (length < 128)
     *p++ = length;
   else if (length < 256)
     {
       *p++ = 0x81;
       *p++ = length;
     }
   else
     {
       if (length > 0xffff)
         length = 0xffff;
       *p++ = 0x82;
       *p++ = length >> 8;
       *p++ = length;
     }
 
   return p - buffer;
 }
 
 
 static gpg_error_t
 build_privkey_template (app_t app, int keyno,
                         const unsigned char *rsa_n, size_t rsa_n_len,
                         const unsigned char *rsa_e, size_t rsa_e_len,
                         const unsigned char *rsa_p, size_t rsa_p_len,
                         const unsigned char *rsa_q, size_t rsa_q_len,
                         const unsigned char *rsa_u, size_t rsa_u_len,
                         const unsigned char *rsa_dp, size_t rsa_dp_len,
                         const unsigned char *rsa_dq, size_t rsa_dq_len,
                         unsigned char **result, size_t *resultlen)
 {
   size_t rsa_e_reqlen;
   unsigned char privkey[7*(1+3+3)];
   size_t privkey_len;
   unsigned char exthdr[2+2+3];
   size_t exthdr_len;
   unsigned char suffix[2+3];
   size_t suffix_len;
   unsigned char *tp;
   size_t datalen;
   unsigned char *template;
   size_t template_size;
 
   *result = NULL;
   *resultlen = 0;
 
   switch (app->app_local->keyattr[keyno].rsa.format)
     {
     case RSA_STD:
     case RSA_STD_N:
     case RSA_CRT:
     case RSA_CRT_N:
       break;
 
     default:
       return gpg_error (GPG_ERR_INV_VALUE);
     }
 
   /* Get the required length for E. Rounded up to the nearest byte  */
   rsa_e_reqlen = (app->app_local->keyattr[keyno].rsa.e_bits + 7) / 8;
   assert (rsa_e_len <= rsa_e_reqlen);
 
   /* Build the 7f48 cardholder private key template.  */
   datalen = 0;
   tp = privkey;
 
   tp += add_tlv (tp, 0x91, rsa_e_reqlen);
   datalen += rsa_e_reqlen;
 
   tp += add_tlv (tp, 0x92, rsa_p_len);
   datalen += rsa_p_len;
 
   tp += add_tlv (tp, 0x93, rsa_q_len);
   datalen += rsa_q_len;
 
   if (app->app_local->keyattr[keyno].rsa.format == RSA_CRT
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
       tp += add_tlv (tp, 0x94, rsa_u_len);
       datalen += rsa_u_len;
       tp += add_tlv (tp, 0x95, rsa_dp_len);
       datalen += rsa_dp_len;
       tp += add_tlv (tp, 0x96, rsa_dq_len);
       datalen += rsa_dq_len;
     }
 
   if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
       tp += add_tlv (tp, 0x97, rsa_n_len);
       datalen += rsa_n_len;
     }
   privkey_len = tp - privkey;
 
   /* Build the extended header list without the private key template.  */
   tp = exthdr;
   *tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4;
   *tp++ = 0;
   tp += add_tlv (tp, 0x7f48, privkey_len);
   exthdr_len = tp - exthdr;
 
   /* Build the 5f48 suffix of the data.  */
   tp = suffix;
   tp += add_tlv (tp, 0x5f48, datalen);
   suffix_len = tp - suffix;
 
   /* Now concatenate everything.  */
   template_size = (1 + 3   /* 0x4d and len. */
                    + exthdr_len
                    + privkey_len
                    + suffix_len
                    + datalen);
   tp = template = xtrymalloc_secure (template_size);
   if (!template)
     return gpg_error_from_syserror ();
 
   tp += add_tlv (tp, 0x4d, exthdr_len + privkey_len + suffix_len + datalen);
   memcpy (tp, exthdr, exthdr_len);
   tp += exthdr_len;
   memcpy (tp, privkey, privkey_len);
   tp += privkey_len;
   memcpy (tp, suffix, suffix_len);
   tp += suffix_len;
 
   memcpy (tp, rsa_e, rsa_e_len);
   if (rsa_e_len < rsa_e_reqlen)
     {
       /* Right justify E. */
       memmove (tp + rsa_e_reqlen - rsa_e_len, tp, rsa_e_len);
       memset (tp, 0, rsa_e_reqlen - rsa_e_len);
     }
   tp += rsa_e_reqlen;
 
   memcpy (tp, rsa_p, rsa_p_len);
   tp += rsa_p_len;
 
   memcpy (tp, rsa_q, rsa_q_len);
   tp += rsa_q_len;
 
   if (app->app_local->keyattr[keyno].rsa.format == RSA_CRT
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
       memcpy (tp, rsa_u, rsa_u_len);
       tp += rsa_u_len;
       memcpy (tp, rsa_dp, rsa_dp_len);
       tp += rsa_dp_len;
       memcpy (tp, rsa_dq, rsa_dq_len);
       tp += rsa_dq_len;
     }
 
   if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
       memcpy (tp, rsa_n, rsa_n_len);
       tp += rsa_n_len;
     }
 
   /* Sanity check.  We don't know the exact length because we
      allocated 3 bytes for the first length header.  */
   assert (tp - template <= template_size);
 
   *result = template;
   *resultlen = tp - template;
   return 0;
 }
 
 static gpg_error_t
 build_ecc_privkey_template (app_t app, int keyno,
                             const unsigned char *ecc_d, size_t ecc_d_len,
                             size_t ecc_d_fixed_len,
                             const unsigned char *ecc_q, size_t ecc_q_len,
                             unsigned char **result, size_t *resultlen)
 {
   unsigned char privkey[2*(1+3)];
   size_t privkey_len;
   unsigned char exthdr[2+2+3];
   size_t exthdr_len;
   unsigned char suffix[2+3];
   size_t suffix_len;
   unsigned char *tp;
   size_t datalen;
   unsigned char *template;
   size_t template_size;
   int pubkey_required;
 
   /* This case doesn't occur in GnuPG 2.3 or later, because
      agent/sexp-secret.c does the fixup.  */
   if (ecc_d_fixed_len < ecc_d_len)
     {
       if (ecc_d_fixed_len != ecc_d_len - 1 || *ecc_d)
         return gpg_error (GPG_ERR_INV_OBJ);
 
       /* Remove the additional zero.  */
       ecc_d_len--;
       ecc_d++;
     }
 
   pubkey_required = !!(app->app_local->keyattr[keyno].ecc.flags
                        & ECC_FLAG_PUBKEY);
 
   *result = NULL;
   *resultlen = 0;
 
   /* Build the 7f48 cardholder private key template.  */
   datalen = 0;
   tp = privkey;
 
   tp += add_tlv (tp, 0x92, ecc_d_fixed_len);
   datalen += ecc_d_fixed_len;
 
   if (pubkey_required)
     {
       tp += add_tlv (tp, 0x99, ecc_q_len);
       datalen += ecc_q_len;
     }
 
   privkey_len = tp - privkey;
 
 
   /* Build the extended header list without the private key template.  */
   tp = exthdr;
   *tp++ = keyno ==0 ? 0xb6 : keyno == 1? 0xb8 : 0xa4;
   *tp++ = 0;
   tp += add_tlv (tp, 0x7f48, privkey_len);
   exthdr_len = tp - exthdr;
 
   /* Build the 5f48 suffix of the data.  */
   tp = suffix;
   tp += add_tlv (tp, 0x5f48, datalen);
   suffix_len = tp - suffix;
 
   /* Now concatenate everything.  */
   template_size = (1 + 1   /* 0x4d and len. */
                    + exthdr_len
                    + privkey_len
                    + suffix_len
                    + datalen);
   if (exthdr_len + privkey_len + suffix_len + datalen >= 128)
     template_size++;
   tp = template = xtrymalloc_secure (template_size);
   if (!template)
     return gpg_error_from_syserror ();
 
   tp += add_tlv (tp, 0x4d, exthdr_len + privkey_len + suffix_len + datalen);
   memcpy (tp, exthdr, exthdr_len);
   tp += exthdr_len;
   memcpy (tp, privkey, privkey_len);
   tp += privkey_len;
   memcpy (tp, suffix, suffix_len);
   tp += suffix_len;
 
   if (ecc_d_fixed_len > ecc_d_len)
     {
       memset (tp, 0, ecc_d_fixed_len - ecc_d_len);
       memcpy (tp + ecc_d_fixed_len - ecc_d_len, ecc_d, ecc_d_len);
     }
   else
     memcpy (tp, ecc_d, ecc_d_len);
   tp += ecc_d_fixed_len;
 
   if (pubkey_required)
     {
       memcpy (tp, ecc_q, ecc_q_len);
       tp += ecc_q_len;
     }
 
   assert (tp - template == template_size);
 
   *result = template;
   *resultlen = tp - template;
   return 0;
 }
 
 
 /* Helper for do_writekey to change the size of a key.  Note that
    this deletes the entire key without asking.  */
 static gpg_error_t
 change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
                 gpg_error_t (*pincb)(void*, const char *, char **),
                 void *pincb_arg)
 {
   gpg_error_t err;
 
   assert (keyno >=0 && keyno <= 2);
 
   /* Prepare for storing the key.  */
   err = verify_chv3 (app, pincb, pincb_arg);
   if (err)
     return err;
 
   /* Change the attribute.  */
   err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buf, buflen);
   if (err)
     log_error ("error changing key attribute (key=%d)\n", keyno+1);
   else
     log_info ("key attribute changed (key=%d)\n", keyno+1);
   flush_cache (app);
   parse_algorithm_attribute (app, keyno);
   app->did_chv1 = 0;
   app->did_chv2 = 0;
   app->did_chv3 = 0;
   return err;
 }
 
 
 static gpg_error_t
 change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
                     gpg_error_t (*pincb)(void*, const char *, char **),
                     void *pincb_arg)
 {
   gpg_error_t err = 0;
   unsigned char *buf;
   size_t buflen;
   void *relptr;
 
   /* Read the current attributes into a buffer.  */
   relptr = get_one_do (app, 0xC1+keyno, &buf, &buflen, NULL);
   if (!relptr)
     err = gpg_error (GPG_ERR_CARD);
   else if (buflen < 6)
     {
       /* Attributes too short.  */
       xfree (relptr);
       err = gpg_error (GPG_ERR_CARD);
     }
   else
     {
       /* If key attribute was RSA, we only change n_bits and don't
          touch anything else.  Before we do so, we round up NBITS to a
          sensible way in the same way as gpg's key generation does it.
          This may help to sort out problems with a few bits too short
          keys.  */
       nbits = ((nbits + 31) / 32) * 32;
       buf[1] = (nbits >> 8);
       buf[2] = nbits;
 
       /* If it was not RSA, we need to fill other parts.  */
       if (buf[0] != PUBKEY_ALGO_RSA)
         {
           buf[0] = PUBKEY_ALGO_RSA;
           buf[3] = 0;
           buf[4] = 32;
           buf[5] = 0;
           buflen = 6;
         }
 
       err = change_keyattr (app, keyno, buf, buflen, pincb, pincb_arg);
       xfree (relptr);
     }
 
   return err;
 }
 
 
 /* Helper to process an setattr command for name KEY-ATTR.
    In (VALUE,VALUELEN), it expects following string:
         RSA: "--force <key> <algo> rsa<nbits>"
         ECC: "--force <key> <algo> <curvename>"
   */
 static gpg_error_t
 change_keyattr_from_string (app_t app,
                             gpg_error_t (*pincb)(void*, const char *, char **),
                             void *pincb_arg,
                             const void *value, size_t valuelen)
 {
   gpg_error_t err = 0;
   char *string;
   int key, keyno, algo;
   int n = 0;
 
   /* VALUE is expected to be a string but not guaranteed to be
      terminated.  Thus copy it to an allocated buffer first. */
   string = xtrymalloc (valuelen+1);
   if (!string)
     return gpg_error_from_syserror ();
   memcpy (string, value, valuelen);
   string[valuelen] = 0;
 
   /* Because this function deletes the key we require the string
      "--force" in the data to make clear that something serious might
      happen.  */
   sscanf (string, "--force %d %d %n", &key, &algo, &n);
   if (n < 12)
     {
       err = gpg_error (GPG_ERR_INV_DATA);
       goto leave;
     }
 
   keyno = key - 1;
   if (keyno < 0 || keyno > 2)
     err = gpg_error (GPG_ERR_INV_ID);
   else if (algo == PUBKEY_ALGO_RSA)
     {
       unsigned int nbits;
 
       errno = 0;
       nbits = strtoul (string+n+3, NULL, 10);
       if (errno)
         err = gpg_error (GPG_ERR_INV_DATA);
       else if (nbits < 1024)
         err = gpg_error (GPG_ERR_TOO_SHORT);
       else if (nbits > 4096)
         err = gpg_error (GPG_ERR_TOO_LARGE);
       else
         err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
     }
   else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA)
     {
       const char *oidstr;
       gcry_mpi_t oid;
       const unsigned char *oidbuf;
       size_t oid_len;
 
       oidstr = openpgp_curve_to_oid (string+n, NULL, NULL);
       if (!oidstr)
         {
           err = gpg_error (GPG_ERR_INV_DATA);
           goto leave;
         }
 
       err = openpgp_oid_from_str (oidstr, &oid);
       if (err)
         goto leave;
 
       oidbuf = gcry_mpi_get_opaque (oid, &n);
       oid_len = (n+7)/8;
 
       /* We have enough room at STRING.  */
       string[0] = algo;
       memcpy (string+1, oidbuf+1, oid_len-1);
       err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
       gcry_mpi_release (oid);
     }
   else
     err = gpg_error (GPG_ERR_PUBKEY_ALGO);
 
  leave:
   xfree (string);
   return err;
 }
 
 
 static gpg_error_t
 rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg, int keyno,
               const unsigned char *buf, size_t buflen, int depth)
 {
   gpg_error_t err;
   const unsigned char *tok;
   size_t toklen;
   int last_depth1, last_depth2;
   const unsigned char *rsa_n = NULL;
   const unsigned char *rsa_e = NULL;
   const unsigned char *rsa_p = NULL;
   const unsigned char *rsa_q = NULL;
   size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
   unsigned int nbits;
   unsigned int maxbits;
   unsigned char *template = NULL;
   unsigned char *tp;
   size_t template_len;
   unsigned char fprbuf[20];
   u32 created_at = 0;
 
   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_RSA)
     {
       log_error (_("unsupported algorithm: %s"), "RSA");
       err = gpg_error (GPG_ERR_INV_VALUE);
       goto leave;
     }
 
   last_depth1 = depth;
   while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
          && depth && depth >= last_depth1)
     {
       if (tok)
         {
           err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
           goto leave;
         }
       if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
         goto leave;
       if (tok && toklen == 1)
         {
           const unsigned char **mpi;
           size_t *mpi_len;
 
           switch (*tok)
             {
             case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break;
             case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break;
             case 'p': mpi = &rsa_p; mpi_len = &rsa_p_len; break;
             case 'q': mpi = &rsa_q; mpi_len = &rsa_q_len;break;
             default: mpi = NULL;  mpi_len = NULL; break;
             }
           if (mpi && *mpi)
             {
               err = gpg_error (GPG_ERR_DUP_VALUE);
               goto leave;
             }
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
           if (tok && mpi)
             {
               /* Strip off leading zero bytes and save. */
               for (;toklen && !*tok; toklen--, tok++)
                 ;
               *mpi = tok;
               *mpi_len = toklen;
             }
         }
       /* Skip until end of list. */
       last_depth2 = depth;
       while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
              && depth && depth >= last_depth2)
         ;
       if (err)
         goto leave;
     }
   /* Parse other attributes. */
   last_depth1 = depth;
   while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
          && depth && depth >= last_depth1)
     {
       if (tok)
         {
           err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
           goto leave;
         }
       if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
         goto leave;
       if (tok && toklen == 10 && !memcmp ("created-at", tok, toklen))
         {
           if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen)))
             goto leave;
           if (tok)
             {
               for (created_at=0; toklen && *tok && *tok >= '0' && *tok <= '9';
                    tok++, toklen--)
                 created_at = created_at*10 + (*tok - '0');
             }
         }
       /* Skip until end of list. */
       last_depth2 = depth;
       while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
              && depth && depth >= last_depth2)
         ;
       if (err)
         goto leave;
     }
 
 
   /* Check that we have all parameters and that they match the card
      description. */
   if (!created_at)
     {
       log_error (_("creation timestamp missing\n"));
       err = gpg_error (GPG_ERR_INV_VALUE);
       goto leave;
     }
 
   maxbits = app->app_local->keyattr[keyno].rsa.n_bits;
   nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
   if (opt.verbose)
     log_info ("RSA modulus size is %u bits\n", nbits);
   if (nbits && nbits != maxbits
       && app->app_local->extcap.algo_attr_change)
     {
       /* Try to switch the key to a new length.  */
       err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
       if (!err)
         maxbits = app->app_local->keyattr[keyno].rsa.n_bits;
     }
   if (nbits != maxbits)
     {
       log_error (_("RSA modulus missing or not of size %d bits\n"),
                  (int)maxbits);
       err = gpg_error (GPG_ERR_BAD_SECKEY);
       goto leave;
     }
 
   maxbits = app->app_local->keyattr[keyno].rsa.e_bits;
   if (maxbits > 32 && !app->app_local->extcap.is_v2)
     maxbits = 32; /* Our code for v1 does only support 32 bits.  */
   nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0;
   if (nbits < 2 || nbits > maxbits)
     {
       log_error (_("RSA public exponent missing or larger than %d bits\n"),
                  (int)maxbits);
       err = gpg_error (GPG_ERR_BAD_SECKEY);
       goto leave;
     }
 
   maxbits = app->app_local->keyattr[keyno].rsa.n_bits/2;
   nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0;
   if (nbits != maxbits)
     {
       log_error (_("RSA prime %s missing or not of size %d bits\n"),
                  "P", (int)maxbits);
       err = gpg_error (GPG_ERR_BAD_SECKEY);
       goto leave;
     }
   nbits = rsa_q? count_bits (rsa_q, rsa_q_len) : 0;
   if (nbits != maxbits)
     {
       log_error (_("RSA prime %s missing or not of size %d bits\n"),
                  "Q", (int)maxbits);
       err = gpg_error (GPG_ERR_BAD_SECKEY);
       goto leave;
     }
 
   /* We need to remove the cached public key.  */
   xfree (app->app_local->pk[keyno].key);
   app->app_local->pk[keyno].key = NULL;
   app->app_local->pk[keyno].keylen = 0;
   app->app_local->pk[keyno].read_done = 0;
 
 
   if (app->app_local->extcap.is_v2)
     {
       unsigned char *rsa_u, *rsa_dp, *rsa_dq;
       size_t rsa_u_len, rsa_dp_len, rsa_dq_len;
       gcry_mpi_t mpi_e, mpi_p, mpi_q;
       gcry_mpi_t mpi_u = gcry_mpi_snew (0);
       gcry_mpi_t mpi_dp = gcry_mpi_snew (0);
       gcry_mpi_t mpi_dq = gcry_mpi_snew (0);
       gcry_mpi_t mpi_tmp = gcry_mpi_snew (0);
       int exmode;
 
       /* Calculate the u, dp and dq components needed by RSA_CRT cards */
       gcry_mpi_scan (&mpi_e, GCRYMPI_FMT_USG, rsa_e, rsa_e_len, NULL);
       gcry_mpi_scan (&mpi_p, GCRYMPI_FMT_USG, rsa_p, rsa_p_len, NULL);
       gcry_mpi_scan (&mpi_q, GCRYMPI_FMT_USG, rsa_q, rsa_q_len, NULL);
 
       gcry_mpi_invm (mpi_u, mpi_q, mpi_p);
       gcry_mpi_sub_ui (mpi_tmp, mpi_p, 1);
       gcry_mpi_invm (mpi_dp, mpi_e, mpi_tmp);
       gcry_mpi_sub_ui (mpi_tmp, mpi_q, 1);
       gcry_mpi_invm (mpi_dq, mpi_e, mpi_tmp);
 
       gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_u, &rsa_u_len, mpi_u);
       gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dp, &rsa_dp_len, mpi_dp);
       gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dq, &rsa_dq_len, mpi_dq);
 
       gcry_mpi_release (mpi_e);
       gcry_mpi_release (mpi_p);
       gcry_mpi_release (mpi_q);
       gcry_mpi_release (mpi_u);
       gcry_mpi_release (mpi_dp);
       gcry_mpi_release (mpi_dq);
       gcry_mpi_release (mpi_tmp);
 
       /* Build the private key template as described in section 4.3.3.7 of
          the OpenPGP card specs version 2.0.  */
       err = build_privkey_template (app, keyno,
                                     rsa_n, rsa_n_len,
                                     rsa_e, rsa_e_len,
                                     rsa_p, rsa_p_len,
                                     rsa_q, rsa_q_len,
                                     rsa_u, rsa_u_len,
                                     rsa_dp, rsa_dp_len,
                                     rsa_dq, rsa_dq_len,
                                     &template, &template_len);
       xfree(rsa_u);
       xfree(rsa_dp);
       xfree(rsa_dq);
 
       if (err)
         goto leave;
 
       /* Prepare for storing the key.  */
       err = verify_chv3 (app, pincb, pincb_arg);
       if (err)
         goto leave;
 
       /* Store the key. */
       if (app->app_local->cardcap.ext_lc_le && template_len > 254)
         exmode = 1;    /* Use extended length w/o a limit.  */
       else if (app->app_local->cardcap.cmd_chaining && template_len > 254)
         exmode = -254;
       else
         exmode = 0;
       err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
                                   template, template_len);
     }
   else
     {
       /* Build the private key template as described in section 4.3.3.6 of
          the OpenPGP card specs version 1.1:
          0xC0   <length> public exponent
          0xC1   <length> prime p
          0xC2   <length> prime q
       */
       assert (rsa_e_len <= 4);
       template_len = (1 + 1 + 4
                       + 1 + 1 + rsa_p_len
                       + 1 + 1 + rsa_q_len);
       template = tp = xtrymalloc_secure (template_len);
       if (!template)
         {
           err = gpg_error_from_syserror ();
           goto leave;
         }
       *tp++ = 0xC0;
       *tp++ = 4;
       memcpy (tp, rsa_e, rsa_e_len);
       if (rsa_e_len < 4)
         {
           /* Right justify E. */
           memmove (tp+4-rsa_e_len, tp, rsa_e_len);
           memset (tp, 0, 4-rsa_e_len);
         }
       tp += 4;
 
       *tp++ = 0xC1;
       *tp++ = rsa_p_len;
       memcpy (tp, rsa_p, rsa_p_len);
       tp += rsa_p_len;
 
       *tp++ = 0xC2;
       *tp++ = rsa_q_len;
       memcpy (tp, rsa_q, rsa_q_len);
       tp += rsa_q_len;
 
       assert (tp - template == template_len);
 
       /* Prepare for storing the key.  */
       err = verify_chv3 (app, pincb, pincb_arg);
       if (err)
         goto leave;
 
       /* Store the key. */
       err = iso7816_put_data (app->slot, 0,
                               (app->appversion > 0x0007? 0xE0:0xE9)+keyno,
                               template, template_len);
     }
   if (err)
     {
       log_error (_("failed to store the key: %s\n"), gpg_strerror (err));
       goto leave;
     }
 
   err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
                    rsa_n, rsa_n_len, rsa_e, rsa_e_len);
   if (err)
     goto leave;
 
 
  leave:
   xfree (template);
   return err;
 }
 
 
 static gpg_error_t
 ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg, int keyno,
               const unsigned char *buf, size_t buflen, int depth)
 {
   gpg_error_t err;
   const unsigned char *tok;
   size_t toklen;
   int last_depth1, last_depth2;
   const unsigned char *ecc_q = NULL;
   const unsigned char *ecc_d = NULL;
   size_t ecc_q_len, ecc_d_len;
   const char *curve = NULL;
   u32 created_at = 0;
   const char *oidstr;
   int flag_djb_tweak = 0;
   int algo;
   gcry_mpi_t oid = NULL;
   const unsigned char *oidbuf;
   unsigned int n;
   size_t oid_len;
   unsigned char fprbuf[20];
   size_t ecc_d_fixed_len;
 
   /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)):
      curve = "NIST P-256" */
   /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)):
      curve = "secp256k1" */
   /* (private-key(ecc(curve%s)(flags eddsa)(q%m)(d%m))(created-at%d)):
       curve = "Ed25519" */
   last_depth1 = depth;
   while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
          && depth && depth >= last_depth1)
     {
       if (tok)
         {
           err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
           goto leave;
         }
       if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
         goto leave;
 
       if (tok && toklen == 5 && !memcmp (tok, "curve", 5))
         {
           char *curve_name;
 
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
 
           curve_name = xtrymalloc (toklen+1);
           if (!curve_name)
             {
               err = gpg_error_from_syserror ();
               goto leave;
             }
 
           memcpy (curve_name, tok, toklen);
           curve_name[toklen] = 0;
           curve = openpgp_is_curve_supported (curve_name, NULL, NULL);
           xfree (curve_name);
         }
       else if (tok && toklen == 5 && !memcmp (tok, "flags", 5))
         {
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
 
           if (tok)
             {
               if ((toklen == 5 && !memcmp (tok, "eddsa", 5))
                   || (toklen == 9 && !memcmp (tok, "djb-tweak", 9)))
                 flag_djb_tweak = 1;
             }
         }
       else if (tok && toklen == 1)
         {
           const unsigned char **buf2;
           size_t *buf2len;
           int native = flag_djb_tweak;
 
           switch (*tok)
             {
             case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break;
             case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; native = 0; break;
             default: buf2 = NULL;  buf2len = NULL; break;
             }
           if (buf2 && *buf2)
             {
               err = gpg_error (GPG_ERR_DUP_VALUE);
               goto leave;
             }
           if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
             goto leave;
           if (tok && buf2)
             {
               if (!native)
                 /* Strip off leading zero bytes and save. */
                 for (;toklen && !*tok; toklen--, tok++)
                   ;
 
               *buf2 = tok;
               *buf2len = toklen;
             }
         }
       /* Skip until end of list. */
       last_depth2 = depth;
       while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
              && depth && depth >= last_depth2)
         ;
       if (err)
         goto leave;
     }
   /* Parse other attributes. */
   last_depth1 = depth;
   while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
          && depth && depth >= last_depth1)
     {
       if (tok)
         {
           err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
           goto leave;
         }
       if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
         goto leave;
       if (tok && toklen == 10 && !memcmp ("created-at", tok, toklen))
         {
           if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen)))
             goto leave;
           if (tok)
             {
               for (created_at=0; toklen && *tok && *tok >= '0' && *tok <= '9';
                    tok++, toklen--)
                 created_at = created_at*10 + (*tok - '0');
             }
         }
       /* Skip until end of list. */
       last_depth2 = depth;
       while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
              && depth && depth >= last_depth2)
         ;
       if (err)
         goto leave;
     }
 
 
   /* Check that we have all parameters and that they match the card
      description. */
   if (!curve)
     {
       log_error (_("unsupported curve\n"));
       err = gpg_error (GPG_ERR_INV_VALUE);
       goto leave;
     }
   if (!created_at)
     {
       log_error (_("creation timestamp missing\n"));
       err = gpg_error (GPG_ERR_INV_VALUE);
       goto leave;
     }
   if (flag_djb_tweak && keyno != 1)
     algo = PUBKEY_ALGO_EDDSA;
   else if (keyno == 1)
     algo = PUBKEY_ALGO_ECDH;
   else
     algo = PUBKEY_ALGO_ECDSA;
 
   oidstr = openpgp_curve_to_oid (curve, &n, NULL);
   ecc_d_fixed_len = (n+7)/8;
   err = openpgp_oid_from_str (oidstr, &oid);
   if (err)
     goto leave;
   oidbuf = gcry_mpi_get_opaque (oid, &n);
   if (!oidbuf)
     {
       err = gpg_error_from_syserror ();
       goto leave;
     }
   oid_len = (n+7)/8;
 
   if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
       || app->app_local->keyattr[keyno].ecc.curve != curve
       || (flag_djb_tweak !=
           (app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)))
     {
       if (app->app_local->extcap.algo_attr_change)
         {
           unsigned char *keyattr;
 
           if (!oid_len)
             {
               err = gpg_error (GPG_ERR_INTERNAL);
               goto leave;
             }
           keyattr = xtrymalloc (oid_len);
           if (!keyattr)
             {
               err = gpg_error_from_syserror ();
               goto leave;
             }
           keyattr[0] = algo;
           memcpy (keyattr+1, oidbuf+1, oid_len-1);
           err = change_keyattr (app, keyno, keyattr, oid_len, pincb, pincb_arg);
           xfree (keyattr);
           if (err)
             goto leave;
         }
       else
         {
           log_error ("key attribute on card doesn't match\n");
           err = gpg_error (GPG_ERR_INV_VALUE);
           goto leave;
         }
     }
 
   if (opt.verbose)
     log_info ("ECC private key size is %u bytes\n", (unsigned int)ecc_d_len);
 
   /* We need to remove the cached public key.  */
   xfree (app->app_local->pk[keyno].key);
   app->app_local->pk[keyno].key = NULL;
   app->app_local->pk[keyno].keylen = 0;
   app->app_local->pk[keyno].read_done = 0;
 
   if (app->app_local->extcap.is_v2)
     {
       /* Build the private key template as described in section 4.3.3.7 of
          the OpenPGP card specs version 2.0.  */
       unsigned char *template;
       size_t template_len;
       int exmode;
 
       err = build_ecc_privkey_template (app, keyno,
                                         ecc_d, ecc_d_len, ecc_d_fixed_len,
                                         ecc_q, ecc_q_len,
                                         &template, &template_len);
       if (err)
         goto leave;
 
       /* Prepare for storing the key.  */
       err = verify_chv3 (app, pincb, pincb_arg);
       if (err)
         {
           xfree (template);
           goto leave;
         }
 
       /* Store the key. */
       if (app->app_local->cardcap.ext_lc_le && template_len > 254)
         exmode = 1;    /* Use extended length w/o a limit.  */
       else if (app->app_local->cardcap.cmd_chaining && template_len > 254)
         exmode = -254;
       else
         exmode = 0;
       err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
                                   template, template_len);
       xfree (template);
     }
   else
     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
 
   if (err)
     {
       log_error (_("failed to store the key: %s\n"), gpg_strerror (err));
       goto leave;
     }
 
   err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
                    ecc_q, ecc_q_len, ecdh_params (curve), (size_t)4);
 
  leave:
   gcry_mpi_release (oid);
   return err;
 }
 
 /* Handle the WRITEKEY command for OpenPGP.  This function expects a
    canonical encoded S-expression with the secret key in KEYDATA and
    its length (for assertions) in KEYDATALEN.  KEYID needs to be the
    usual keyid which for OpenPGP is the string "OPENPGP.n" with
    n=1,2,3.  Bit 0 of FLAGS indicates whether an existing key shall
    get overwritten.  PINCB and PINCB_ARG are the usual arguments for
    the pinentry callback.  */
 static gpg_error_t
 do_writekey (app_t app, ctrl_t ctrl,
              const char *keyid, unsigned int flags,
              gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg,
              const unsigned char *keydata, size_t keydatalen)
 {
   gpg_error_t err;
   int force = (flags & 1);
   int keyno;
   const unsigned char *buf, *tok;
   size_t buflen, toklen;
   int depth;
 
   (void)ctrl;
 
   if (!strcmp (keyid, "OPENPGP.1"))
     keyno = 0;
   else if (!strcmp (keyid, "OPENPGP.2"))
     keyno = 1;
   else if (!strcmp (keyid, "OPENPGP.3"))
     keyno = 2;
   else
     return gpg_error (GPG_ERR_INV_ID);
 
   err = does_key_exist (app, keyno, 0, force);
   if (err)
     return err;
 
 
   /*
      Parse the S-expression
    */
   buf = keydata;
   buflen = keydatalen;
   depth = 0;
   if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
     goto leave;
   if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
     goto leave;
   if (!tok || toklen != 11 || memcmp ("private-key", tok, toklen))
     {
       if (!tok)
         ;
       else if (toklen == 21 && !memcmp ("protected-private-key", tok, toklen))
         log_info ("protected-private-key passed to writekey\n");
       else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen))
         log_info ("shadowed-private-key passed to writekey\n");
       err = gpg_error (GPG_ERR_BAD_SECKEY);
       goto leave;
     }
   if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
     goto leave;
   if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
     goto leave;
   if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
     err = rsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
   else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0)
     err = ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
   else
     {
       err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
       goto leave;
     }
 
  leave:
   return err;
 }
 
 
 
 /* Handle the GENKEY command. */
 static gpg_error_t
 do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, const char *keytype,
            unsigned int flags, time_t createtime,
            gpg_error_t (*pincb)(void*, const char *, char **),
            void *pincb_arg)
 {
   gpg_error_t err;
   char numbuf[30];
   unsigned char *buffer = NULL;
   const unsigned char *keydata;
   size_t buflen, keydatalen;
   u32 created_at;
   int keyno = atoi (keynostr) - 1;
   int force = (flags & 1);
   time_t start_at;
   int exmode = 0;
   int le_value = 256; /* Use legacy value. */
 
   (void)keytype;  /* Ignored for OpenPGP cards.  */
 
   if (keyno < 0 || keyno > 2)
     return gpg_error (GPG_ERR_INV_ID);
 
   /* We flush the cache to increase the traffic before a key
      generation.  This _might_ help a card to gather more entropy. */
   flush_cache (app);
 
   /* Obviously we need to remove the cached public key.  */
   xfree (app->app_local->pk[keyno].key);
   app->app_local->pk[keyno].key = NULL;
   app->app_local->pk[keyno].keylen = 0;
   app->app_local->pk[keyno].read_done = 0;
 
   /* Check whether a key already exists.  */
   err = does_key_exist (app, keyno, 1, force);
   if (err)
     return err;
 
   if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
     {
       unsigned int keybits = app->app_local->keyattr[keyno].rsa.n_bits;
 
       /* Because we send the key parameter back via status lines we need
          to put a limit on the max. allowed keysize.  2048 bit will
          already lead to a 527 byte long status line and thus a 4096 bit
          key would exceed the Assuan line length limit.  */
       if (keybits > 4096)
         return gpg_error (GPG_ERR_TOO_LARGE);
 
       if (app->app_local->cardcap.ext_lc_le && keybits > RSA_SMALL_SIZE_KEY
           && app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
         {
           exmode = 1;    /* Use extended length w/o a limit.  */
           le_value = determine_rsa_response (app, keyno);
           /* No need to check le_value because it comes from a 16 bit
              value and thus can't create an overflow on a 32 bit
              system.  */
         }
     }
 
   /* Prepare for key generation by verifying the Admin PIN.  */
   err = verify_chv3 (app, pincb, pincb_arg);
   if (err)
     return err;
 
 
   log_info (_("please wait while key is being generated ...\n"));
   start_at = time (NULL);
   err = iso7816_generate_keypair (app->slot, exmode, 0x80, 0,
                                   (keyno == 0? "\xB6" :
                                    keyno == 1? "\xB8" : "\xA4"),
                                   2, le_value, &buffer, &buflen);
   if (err)
     {
       log_error (_("generating key failed\n"));
       return gpg_error (GPG_ERR_CARD);
     }
 
   {
     int nsecs = (int)(time (NULL) - start_at);
     log_info (ngettext("key generation completed (%d second)\n",
                        "key generation completed (%d seconds)\n",
                        nsecs), nsecs);
   }
 
   keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
   if (!keydata)
     {
       err = gpg_error (GPG_ERR_CARD);
       log_error (_("response does not contain the public key data\n"));
       goto leave;
     }
 
   created_at = (u32)(createtime? createtime : gnupg_get_time ());
   sprintf (numbuf, "%u", created_at);
   send_status_info (ctrl, "KEY-CREATED-AT",
                     numbuf, (size_t)strlen(numbuf), NULL, 0);
 
   err = read_public_key (app, ctrl, created_at, keyno, buffer, buflen);
  leave:
   xfree (buffer);
   return err;
 }
 
 
 static unsigned long
 convert_sig_counter_value (const unsigned char *value, size_t valuelen)
 {
   unsigned long ul;
 
   if (valuelen == 3 )
     ul = (value[0] << 16) | (value[1] << 8) | value[2];
   else
     {
       log_error (_("invalid structure of OpenPGP card (DO 0x93)\n"));
       ul = 0;
     }
   return ul;
 }
 
 static unsigned long
 get_sig_counter (app_t app)
 {
   void *relptr;
   unsigned char *value;
   size_t valuelen;
   unsigned long ul;
 
   relptr = get_one_do (app, 0x0093, &value, &valuelen, NULL);
   if (!relptr)
     return 0;
   ul = convert_sig_counter_value (value, valuelen);
   xfree (relptr);
   return ul;
 }
 
 static gpg_error_t
 compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
 {
   const unsigned char *fpr;
   unsigned char *buffer;
   size_t buflen, n;
   int rc, i;
 
   assert (keyno >= 0 && keyno <= 2);
 
   rc = get_cached_data (app, 0x006E, &buffer, &buflen, 0, 0);
   if (rc)
     {
       log_error (_("error reading application data\n"));
       return gpg_error (GPG_ERR_GENERAL);
     }
   fpr = find_tlv (buffer, buflen, 0x00C5, &n);
   if (!fpr || n < 60)
     {
       xfree (buffer);
       log_error (_("error reading fingerprint DO\n"));
       return gpg_error (GPG_ERR_GENERAL);
     }
   fpr += keyno*20;
   for (i=0; i < 20; i++)
     if (sha1fpr[i] != fpr[i])
       {
         xfree (buffer);
         log_info (_("fingerprint on card does not match requested one\n"));
         return gpg_error (GPG_ERR_WRONG_SECKEY);
       }
   xfree (buffer);
   return 0;
 }
 
 
 /* If a fingerprint has been specified check it against the one on the
    card.  This allows for a meaningful error message in case the key
    on the card has been replaced but the shadow information known to
    gpg has not been updated.  If there is no fingerprint we assume
    that this is okay. */
 static gpg_error_t
 check_against_given_fingerprint (app_t app, const char *fpr, int key)
 {
   unsigned char tmp[20];
   const char *s;
   int n;
 
   for (s=fpr, n=0; hexdigitp (s); s++, n++)
     ;
   if (n != 40)
     return gpg_error (GPG_ERR_INV_ID);
   else if (!*s)
     ; /* okay */
   else
     return gpg_error (GPG_ERR_INV_ID);
 
   for (s=fpr, n=0; n < 20; s += 2, n++)
         tmp[n] = xtoi_2 (s);
   return compare_fingerprint (app, key-1, tmp);
 }
 
 
 /* Check KEYIDSTR, if it's valid.
    When KEYNO is 0, it means it's for PIN check.
    Otherwise, KEYNO corresponds to the slot (signing, decipher and auth).
    KEYIDSTR is either:
     (1) Serial number
     (2) Serial number "/" fingerprint
     (3) Serial number "[CHV3]"
     (4) keygrip
 
    When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should
    be to be compared is the first one (keygrip for signing).
    When KEYNO is 1, KEYIDSTR is for a keygrip, and R_USE_AUTH is not
    NULL, OpenPGP.1 is first tested and then OpenPGP.3.  In the latter
    case 1 is stored at R_USE_AUTH
  */
 static int
 check_keyidstr (app_t app, const char *keyidstr, int keyno, int *r_use_auth)
 {
   int rc;
   const char *s;
   int n;
   const char *fpr = NULL;
   int i;
 
   if (r_use_auth)
     *r_use_auth = 0;
 
   /* Make sure we have load the public keys.  */
   for (i = 0; i < 3; i++)
     get_public_key (app, i);
 
   if (strlen (keyidstr) < 32)
     return gpg_error (GPG_ERR_INV_ID);
   else
     {
       char *serial;
 
       for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
         ;
 
       /* Check if it's a keygrip */
       if (n == 40)
         {
           const unsigned char *keygrip_str;
 
           keygrip_str = app->app_local->pk[keyno?keyno-1:0].keygrip_str;
           if (!strncmp (keygrip_str, keyidstr, 40))
             return 0;
           else if (keyno == 1 && r_use_auth
                    && !strncmp (app->app_local->pk[2].keygrip_str,
                                 keyidstr, 40))
             {
               *r_use_auth = 1;
               return 0;
             }
           else
             return gpg_error (GPG_ERR_INV_ID);
         }
 
       if (n != 32 || strncmp (keyidstr, "D27600012401", 12))
         return gpg_error (GPG_ERR_INV_ID);
       else if (!*s)
         ; /* no fingerprint given: we allow this for now. */
       else if (*s == '/')
         fpr = s + 1;
 
       serial = app_get_serialno (app);
       if (strncmp (serial, keyidstr, 32))
         {
           xfree (serial);
           return gpg_error (GPG_ERR_WRONG_CARD);
         }
 
       xfree (serial);
     }
 
   /* If a fingerprint has been specified check it against the one on
      the card.  This is allows for a meaningful error message in case
      the key on the card has been replaced but the shadow information
      known to gpg was not updated.  If there is no fingerprint, gpg
      will detect a bogus signature anyway due to the
      verify-after-signing feature. */
   rc = (fpr&&keyno)? check_against_given_fingerprint (app, fpr, keyno) : 0;
 
   return rc;
 }
 
 
 /* Compute a digital signature on INDATA which is expected to be the
    raw message digest. For this application the KEYIDSTR consists of
    the serialnumber and the fingerprint delimited by a slash.
 
    Note that this function may return the error code
    GPG_ERR_WRONG_CARD to indicate that the card currently present does
    not match the one required for the requested action (e.g. the
    serial number does not match).
 
    As a special feature a KEYIDSTR of "OPENPGP.3" redirects the
    operation to the auth command.
 */
 static gpg_error_t
 do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
          gpg_error_t (*pincb)(void*, const char *, char **),
          void *pincb_arg,
          const void *indata, size_t indatalen,
          unsigned char **outdata, size_t *outdatalen )
 {
   static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
     { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
       0x02, 0x01, 0x05, 0x00, 0x04, 0x14  };
   static unsigned char sha1_prefix[15] =   /* (1.3.14.3.2.26) */
     { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
       0x02, 0x1a, 0x05, 0x00, 0x04, 0x14  };
   static unsigned char sha224_prefix[19] = /* (2.16.840.1.101.3.4.2.4) */
     { 0x30, 0x2D, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
       0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
       0x1C  };
   static unsigned char sha256_prefix[19] = /* (2.16.840.1.101.3.4.2.1) */
     { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
       0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
       0x00, 0x04, 0x20  };
   static unsigned char sha384_prefix[19] = /* (2.16.840.1.101.3.4.2.2) */
     { 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
       0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
       0x00, 0x04, 0x30  };
   static unsigned char sha512_prefix[19] = /* (2.16.840.1.101.3.4.2.3) */
     { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
       0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
       0x00, 0x04, 0x40  };
   int rc;
   unsigned char data[19+64];
   size_t datalen;
   unsigned long sigcount;
   int use_auth = 0;
   int exmode, le_value;
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Strip off known prefixes.  */
 #define X(a,b,c,d) \
   if (hashalgo == GCRY_MD_ ## a                               \
       && (d)                                                  \
       && indatalen == sizeof b ## _prefix + (c)               \
       && !memcmp (indata, b ## _prefix, sizeof b ## _prefix)) \
     {                                                         \
       indata = (const char*)indata + sizeof b ## _prefix;     \
       indatalen -= sizeof b ## _prefix;                       \
     }
 
   if (indatalen == 20)
     ;  /* Assume a plain SHA-1 or RMD160 digest has been given.  */
   else X(SHA1,   sha1,   20, 1)
   else X(RMD160, rmd160, 20, 1)
   else X(SHA224, sha224, 28, app->app_local->extcap.is_v2)
   else X(SHA256, sha256, 32, app->app_local->extcap.is_v2)
   else X(SHA384, sha384, 48, app->app_local->extcap.is_v2)
   else X(SHA512, sha512, 64, app->app_local->extcap.is_v2)
   else if ((indatalen == 28 || indatalen == 32
             || indatalen == 48 || indatalen ==64)
            && app->app_local->extcap.is_v2)
     ;  /* Assume a plain SHA-3 digest has been given.  */
   else
     {
       log_error (_("card does not support digest algorithm %s\n"),
                  gcry_md_algo_name (hashalgo));
       /* Or the supplied digest length does not match an algorithm.  */
       return gpg_error (GPG_ERR_INV_VALUE);
     }
 #undef X
 
   /* Check whether an OpenPGP card of any version has been requested. */
   if (!strcmp (keyidstr, "OPENPGP.1"))
     ;
   else if (!strcmp (keyidstr, "OPENPGP.3"))
     use_auth = 1;
   else
     {
       rc = check_keyidstr (app, keyidstr, 1, &use_auth);
       if (rc)
         return rc;
     }
 
   /* Concatenate prefix and digest.  */
 #define X(a,b,d) \
   if (hashalgo == GCRY_MD_ ## a && (d) )                      \
     {                                                         \
       datalen = sizeof b ## _prefix + indatalen;              \
       assert (datalen <= sizeof data);                        \
       memcpy (data, b ## _prefix, sizeof b ## _prefix);       \
       memcpy (data + sizeof b ## _prefix, indata, indatalen); \
     }
 
   if (use_auth
       || app->app_local->keyattr[use_auth? 2: 0].key_type == KEY_TYPE_RSA)
     {
       X(SHA1,   sha1,   1)
       else X(RMD160, rmd160, 1)
       else X(SHA224, sha224, app->app_local->extcap.is_v2)
       else X(SHA256, sha256, app->app_local->extcap.is_v2)
       else X(SHA384, sha384, app->app_local->extcap.is_v2)
       else X(SHA512, sha512, app->app_local->extcap.is_v2)
       else
         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     }
   else
     {
       datalen = indatalen;
       memcpy (data, indata, indatalen);
     }
 #undef X
 
   /* Redirect to the AUTH command if asked to. */
   if (use_auth)
     {
       return do_auth (app, ctrl, "OPENPGP.3", pincb, pincb_arg,
                       data, datalen,
                       outdata, outdatalen);
     }
 
   /* Show the number of signature done using this key.  */
   sigcount = get_sig_counter (app);
   log_info (_("signatures created so far: %lu\n"), sigcount);
 
   /* Check CHV if needed.  */
   if (!app->did_chv1 || app->force_chv1)
     {
       char *pinvalue;
       int pinlen;
 
       rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, &pinvalue, &pinlen);
       if (rc)
         return rc;
 
       app->did_chv1 = 1;
 
       /* For cards with versions < 2 we want to keep CHV1 and CHV2 in
          sync, thus we verify CHV2 here using the given PIN.  Cards
          with version2 to not have the need for a separate CHV2 and
          internally use just one.  Obviously we can't do that if the
          pinpad has been used. */
       if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2)
         {
           rc = iso7816_verify (app->slot, 0x82, pinvalue, pinlen);
           if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
             rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
           if (rc)
             {
               log_error (_("verify CHV%d failed: %s\n"), 2, gpg_strerror (rc));
               xfree (pinvalue);
               flush_cache_after_error (app);
               return rc;
             }
           app->did_chv2 = 1;
         }
       xfree (pinvalue);
     }
 
 
   if (app->app_local->cardcap.ext_lc_le
       && app->app_local->keyattr[0].key_type == KEY_TYPE_RSA
       && app->app_local->keyattr[0].rsa.n_bits > RSA_SMALL_SIZE_OP)
     {
       exmode = 1;    /* Use extended length.  */
       le_value = app->app_local->keyattr[0].rsa.n_bits / 8;
     }
   else
     {
       exmode = 0;
       le_value = 0;
     }
   rc = iso7816_compute_ds (app->slot, exmode, data, datalen, le_value,
                            outdata, outdatalen);
   if (!rc && app->force_chv1)
     app->did_chv1 = 0;
 
   return rc;
 }
 
 /* Compute a digital signature using the INTERNAL AUTHENTICATE command
    on INDATA which is expected to be the raw message digest. For this
    application the KEYIDSTR consists of the serialnumber and the
    fingerprint delimited by a slash.  Optionally the id OPENPGP.3 may
    be given.
 
    Note that this function may return the error code
    GPG_ERR_WRONG_CARD to indicate that the card currently present does
    not match the one required for the requested action (e.g. the
    serial number does not match). */
 static gpg_error_t
 do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
          gpg_error_t (*pincb)(void*, const char *, char **),
          void *pincb_arg,
          const void *indata, size_t indatalen,
          unsigned char **outdata, size_t *outdatalen )
 {
   int rc;
 
   (void)ctrl;
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
   if (app->app_local->keyattr[2].key_type == KEY_TYPE_RSA
       && indatalen > 101) /* For a 2048 bit key. */
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECC)
     {
       if (!(app->app_local->keyattr[2].ecc.flags & ECC_FLAG_DJB_TWEAK)
           && (indatalen == 51 || indatalen == 67 || indatalen == 83))
         {
           const char *p = (const char *)indata + 19;
           indata = p;
           indatalen -= 19;
         }
       else
         {
           const char *p = (const char *)indata + 15;
           indata = p;
           indatalen -= 15;
         }
     }
 
   /* Check whether an OpenPGP card of any version has been requested. */
   if (!ascii_strcasecmp (keyidstr, "OPENPGP.3"))
     ;
   else
     {
       rc = check_keyidstr (app, keyidstr, 3, NULL);
       if (rc)
         return rc;
     }
 
   rc = verify_chv2 (app, pincb, pincb_arg);
   if (!rc)
     {
       int exmode, le_value;
 
       if (app->app_local->cardcap.ext_lc_le
           && app->app_local->keyattr[2].key_type == KEY_TYPE_RSA
           && app->app_local->keyattr[2].rsa.n_bits > RSA_SMALL_SIZE_OP)
         {
           exmode = 1;    /* Use extended length.  */
           le_value = app->app_local->keyattr[2].rsa.n_bits / 8;
         }
       else
         {
           exmode = 0;
           le_value = 0;
         }
       rc = iso7816_internal_authenticate (app->slot, exmode,
                                           indata, indatalen, le_value,
                                           outdata, outdatalen);
     }
   return rc;
 }
 
 
 static gpg_error_t
 do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
              gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg,
              const void *indata, size_t indatalen,
              unsigned char **outdata, size_t *outdatalen,
              unsigned int *r_info)
 {
   int rc;
   int n;
   int exmode, le_value;
   unsigned char *fixbuf = NULL;
   int padind = 0;
   int fixuplen = 0;
 
   (void)ctrl;
 
   if (!keyidstr || !*keyidstr || !indatalen)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Check whether an OpenPGP card of any version has been requested. */
   if (!ascii_strcasecmp (keyidstr, "OPENPGP.2"))
     ;
   else
     {
       rc = check_keyidstr (app, keyidstr, 2, NULL);
       if (rc)
         return rc;
     }
 
   rc = verify_chv2 (app, pincb, pincb_arg);
   if (rc)
     return rc;
 
   if ((indatalen == 16 + 1 || indatalen == 32 + 1)
       && ((char *)indata)[0] == 0x02)
     {
       /* PSO:DECIPHER with symmetric key.  */
       padind = -1;
     }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_RSA)
     {
       /* We might encounter a couple of leading zeroes in the
          cryptogram.  Due to internal use of MPIs these leading zeroes
          are stripped.  However the OpenPGP card expects exactly 128
          bytes for the cryptogram (for a 1k key).  Thus we need to fix
          it up.  We do this for up to 16 leading zero bytes; a
          cryptogram with more than this is with a very high
          probability anyway broken.  If a signed conversion was used
          we may also encounter one leading zero followed by the correct
          length.  We fix that as well.  */
       if (indatalen >= (128-16) && indatalen < 128)      /* 1024 bit key.  */
         fixuplen = 128 - indatalen;
       else if (indatalen >= (192-16) && indatalen < 192) /* 1536 bit key.  */
         fixuplen = 192 - indatalen;
       else if (indatalen >= (256-16) && indatalen < 256) /* 2048 bit key.  */
         fixuplen = 256 - indatalen;
       else if (indatalen >= (384-16) && indatalen < 384) /* 3072 bit key.  */
         fixuplen = 384 - indatalen;
       else if (indatalen >= (512-16) && indatalen < 512) /* 4096 bit key.  */
         fixuplen = 512 - indatalen;
       else if (!*(const char *)indata && (indatalen == 129
                                           || indatalen == 193
                                           || indatalen == 257
                                           || indatalen == 385
                                           || indatalen == 513))
         fixuplen = -1;
       else
         fixuplen = 0;
 
       if (fixuplen > 0)
         {
           /* While we have to prepend stuff anyway, we can also
              include the padding byte here so that iso1816_decipher
              does not need to do another data mangling.  */
           fixuplen++;
 
           fixbuf = xtrymalloc (fixuplen + indatalen);
           if (!fixbuf)
             return gpg_error_from_syserror ();
 
           memset (fixbuf, 0, fixuplen);
           memcpy (fixbuf+fixuplen, indata, indatalen);
           indata = fixbuf;
           indatalen = fixuplen + indatalen;
           padind = -1; /* Already padded.  */
         }
       else if (fixuplen < 0)
         {
           /* We use the extra leading zero as the padding byte.  */
           padind = -1;
         }
     }
   else if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC)
     {
       int old_format_len = 0;
 
       if ((app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK))
         {
           if (indatalen > 32 && (indatalen % 2))
             { /*
                * Skip the prefix.  It may be 0x40 (in new format), or MPI
                * head of 0x00 (in old format).
                */
               indata = (const char *)indata + 1;
               indatalen--;
             }
           else if (indatalen < 32)
             { /*
                * Old format trancated by MPI handling.
                */
               old_format_len = indatalen;
               indatalen = 32;
             }
         }
 
       n = 0;
       if (indatalen < 128)
         fixuplen = 7;
       else
         fixuplen = 10;
 
       fixbuf = xtrymalloc (fixuplen + indatalen);
       if (!fixbuf)
         return gpg_error_from_syserror ();
 
       /* Build 'Cipher DO' */
       fixbuf[n++] = '\xa6';
       if (indatalen < 128)
         fixbuf[n++] = (char)(indatalen+5);
       else
         {
           fixbuf[n++] = 0x81;
           fixbuf[n++] = (char)(indatalen+7);
         }
       fixbuf[n++] = '\x7f';
       fixbuf[n++] = '\x49';
       if (indatalen < 128)
         fixbuf[n++] = (char)(indatalen+2);
       else
         {
           fixbuf[n++] = 0x81;
           fixbuf[n++] = (char)(indatalen+3);
         }
       fixbuf[n++] = '\x86';
       if (indatalen < 128)
         fixbuf[n++] = (char)indatalen;
       else
         {
           fixbuf[n++] = 0x81;
           fixbuf[n++] = (char)indatalen;
         }
 
       if (old_format_len)
         {
           memset (fixbuf+fixuplen, 0, 32 - old_format_len);
           memcpy (fixbuf+fixuplen + 32 - old_format_len,
                   indata, old_format_len);
         }
       else
         {
           memcpy (fixbuf+fixuplen, indata, indatalen);
         }
       indata = fixbuf;
       indatalen = fixuplen + indatalen;
 
       padind = -1;
     }
   else
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (app->app_local->cardcap.ext_lc_le
       && (indatalen > 254
           || (app->app_local->keyattr[1].key_type == KEY_TYPE_RSA
               && app->app_local->keyattr[1].rsa.n_bits > RSA_SMALL_SIZE_OP)))
     {
       exmode = 1;    /* Extended length w/o a limit.  */
       le_value = app->app_local->keyattr[1].rsa.n_bits / 8;
     }
   else if (app->app_local->cardcap.cmd_chaining && indatalen > 254)
     {
       exmode = -254; /* Command chaining with max. 254 bytes.  */
       le_value = 0;
     }
   else
     exmode = le_value = 0;
 
   rc = iso7816_decipher (app->slot, exmode,
                          indata, indatalen, le_value, padind,
                          outdata, outdatalen);
   xfree (fixbuf);
   if (app->app_local->keyattr[1].key_type == KEY_TYPE_ECC)
     {
       unsigned char prefix = 0;
 
       if (app->app_local->keyattr[1].ecc.flags & ECC_FLAG_DJB_TWEAK)
         prefix = 0x40;
       else if ((*outdatalen % 2) == 0) /* No 0x04 -> x-coordinate only */
         prefix = 0x41;
 
       if (prefix)
         { /* Add the prefix */
           fixbuf = xtrymalloc (*outdatalen + 1);
           if (!fixbuf)
             {
               xfree (*outdata);
               return gpg_error_from_syserror ();
             }
           fixbuf[0] = prefix;
           memcpy (fixbuf+1, *outdata, *outdatalen);
           xfree (*outdata);
           *outdata = fixbuf;
           *outdatalen = *outdatalen + 1;
         }
     }
 
   if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
       && app->app_local->manufacturer == 5
       && app->appversion == 0x0200)
     log_info ("NOTE: Cards with manufacturer id 5 and s/n <= 346 (0x15a)"
               " do not work with encryption keys > 2048 bits\n");
 
   *r_info |= APP_DECIPHER_INFO_NOPAD;
 
   return rc;
 }
 
 
 /* Perform a simple verify operation for CHV1 and CHV2, so that
    further operations won't ask for CHV2 and it is possible to do a
    cheap check on the PIN: If there is something wrong with the PIN
    entry system, only the regular CHV will get blocked and not the
    dangerous CHV3.  KEYIDSTR is the usual card's serial number; an
    optional fingerprint part will be ignored.
 
    There is a special mode if the keyidstr is "<serialno>[CHV3]" with
    the "[CHV3]" being a literal string:  The Admin Pin is checked if
    and only if the retry counter is still at 3. */
 static gpg_error_t
 do_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
               gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg)
 {
   int rc;
   int admin_pin = 0;
 
   (void)ctrl;
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   rc = check_keyidstr (app, keyidstr, 0, NULL);
   if (rc)
     return rc;
 
   if ((strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]"))
       || (strlen (keyidstr) >= 40+6 && !strcmp (keyidstr+40, "[CHV3]")))
     admin_pin = 1;
 
   /* Yes, there is a race conditions: The user might pull the card
      right here and we won't notice that.  However this is not a
      problem and the check above is merely for a graceful failure
      between operations. */
 
   if (admin_pin)
     {
       void *relptr;
       unsigned char *value;
       size_t valuelen;
       int count;
 
       relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
       if (!relptr || valuelen < 7)
         {
           log_error (_("error retrieving CHV status from card\n"));
           xfree (relptr);
           return gpg_error (GPG_ERR_CARD);
         }
       count = value[6];
       xfree (relptr);
 
       if (!count)
         {
           log_info (_("card is permanently locked!\n"));
           return gpg_error (GPG_ERR_BAD_PIN);
         }
       else if (count < 3)
         {
           log_info (_("verification of Admin PIN is currently prohibited "
                       "through this command\n"));
           return gpg_error (GPG_ERR_GENERAL);
         }
 
       app->did_chv3 = 0; /* Force verification.  */
       return verify_chv3 (app, pincb, pincb_arg);
     }
   else
     return verify_chv2 (app, pincb, pincb_arg);
 }
 
 
 /* Show information about card capabilities.  */
 static void
 show_caps (struct app_local_s *s)
 {
   log_info ("Version-2+ .....: %s\n", s->extcap.is_v2? "yes":"no");
   log_info ("Extcap-v3 ......: %s\n", s->extcap.extcap_v3? "yes":"no");
   log_info ("Button .........: %s\n", s->extcap.has_button? "yes":"no");
 
   log_info ("SM-Support .....: %s", s->extcap.sm_supported? "yes":"no");
   if (s->extcap.sm_supported)
     log_printf (" (%s)", s->extcap.sm_algo==2? "3DES":
                 (s->extcap.sm_algo==2? "AES-128" : "AES-256"));
   log_info ("Get-Challenge ..: %s", s->extcap.get_challenge? "yes":"no");
   if (s->extcap.get_challenge)
     log_printf (" (%u bytes max)", s->extcap.max_get_challenge);
   log_info ("Key-Import .....: %s\n", s->extcap.key_import? "yes":"no");
   log_info ("Change-Force-PW1: %s\n", s->extcap.change_force_chv? "yes":"no");
   log_info ("Private-DOs ....: %s\n", s->extcap.private_dos? "yes":"no");
   log_info ("Algo-Attr-Change: %s\n", s->extcap.algo_attr_change? "yes":"no");
   log_info ("Symmetric Crypto: %s\n", s->extcap.has_decrypt? "yes":"no");
   log_info ("KDF-Support ....: %s\n", s->extcap.kdf_do? "yes":"no");
   log_info ("Max-Cert3-Len ..: %u\n", s->extcap.max_certlen_3);
   if (s->extcap.extcap_v3)
     {
       log_info ("PIN-Block-2 ....: %s\n", s->extcap.pin_blk2? "yes":"no");
       log_info ("MSE-Support ....: %s\n", s->extcap.mse? "yes":"no");
       log_info ("Max-Special-DOs : %u\n", s->extcap.max_special_do);
     }
   log_info ("Cmd-Chaining ...: %s\n", s->cardcap.cmd_chaining?"yes":"no");
   log_info ("Ext-Lc-Le ......: %s\n", s->cardcap.ext_lc_le?"yes":"no");
   log_info ("Status-Indicator: %02X\n", s->status_indicator);
 
   log_info ("GnuPG-No-Sync ..: %s\n",  s->flags.no_sync? "yes":"no");
   log_info ("GnuPG-Def-PW2 ..: %s\n",  s->flags.def_chv2? "yes":"no");
 }
 
 
 /* Parse the historical bytes in BUFFER of BUFLEN and store them in
    APPLOC.  */
 static void
 parse_historical (struct app_local_s *apploc,
                   const unsigned char * buffer, size_t buflen)
 {
   /* Example buffer: 00 31 C5 73 C0 01 80 00 90 00  */
   if (buflen < 4)
     {
       log_error ("warning: historical bytes are too short\n");
       return; /* Too short.  */
     }
   if (*buffer)
     {
       log_error ("warning: bad category indicator in historical bytes\n");
       return;
     }
 
   /* Skip category indicator.  */
   buffer++;
   buflen--;
 
   /* Get the status indicator.  */
   apploc->status_indicator = buffer[buflen-3];
   buflen -= 3;
 
   /* Parse the compact TLV.  */
   while (buflen)
     {
       unsigned int tag = (*buffer & 0xf0) >> 4;
       unsigned int len = (*buffer & 0x0f);
       if (len+1 > buflen)
         {
           log_error ("warning: bad Compact-TLV in historical bytes\n");
           return; /* Error.  */
         }
       buffer++;
       buflen--;
       if (tag == 7 && len == 3)
         {
           /* Card capabilities.  */
           apploc->cardcap.cmd_chaining = !!(buffer[2] & 0x80);
           apploc->cardcap.ext_lc_le    = !!(buffer[2] & 0x40);
         }
       buffer += len;
       buflen -= len;
     }
 }
 
 
 /*
  * Check if the OID in an DER encoding is available by GnuPG/libgcrypt,
  * and return the curve name.  Return NULL if not available.
  * The constant string is not allocated dynamically, never free it.
  */
 static const char *
 ecc_curve (unsigned char *buf, size_t buflen)
 {
   gcry_mpi_t oid;
   char *oidstr;
   const char *result;
   unsigned char *oidbuf;
 
   oidbuf = xtrymalloc (buflen + 1);
   if (!oidbuf)
     return NULL;
 
   memcpy (oidbuf+1, buf, buflen);
   oidbuf[0] = buflen;
   oid = gcry_mpi_set_opaque (NULL, oidbuf, (buflen+1) * 8);
   if (!oid)
     {
       xfree (oidbuf);
       return NULL;
     }
 
   oidstr = openpgp_oid_to_str (oid);
   gcry_mpi_release (oid);
   if (!oidstr)
     return NULL;
 
   result = openpgp_oid_to_curve (oidstr, 1);
   xfree (oidstr);
   return result;
 }
 
 
 /* Parse and optionally show the algorithm attributes for KEYNO.
    KEYNO must be in the range 0..2.  */
 static void
 parse_algorithm_attribute (app_t app, int keyno)
 {
   unsigned char *buffer;
   size_t buflen;
   void *relptr;
   const char desc[3][5] = {"sign", "encr", "auth"};
 
   assert (keyno >=0 && keyno <= 2);
 
   app->app_local->keyattr[keyno].key_type = KEY_TYPE_RSA;
   app->app_local->keyattr[keyno].rsa.n_bits = 0;
 
   relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL);
   if (!relptr)
     {
       log_error ("error reading DO 0x%02X\n", 0xc1+keyno);
       return;
     }
   if (buflen < 1)
     {
       log_error ("error reading DO 0x%02X\n", 0xc1+keyno);
       xfree (relptr);
       return;
     }
 
   if (opt.verbose)
     log_info ("Key-Attr-%s ..: ", desc[keyno]);
   if (*buffer == PUBKEY_ALGO_RSA && (buflen == 5 || buflen == 6))
     {
       app->app_local->keyattr[keyno].rsa.n_bits = (buffer[1]<<8 | buffer[2]);
       app->app_local->keyattr[keyno].rsa.e_bits = (buffer[3]<<8 | buffer[4]);
       app->app_local->keyattr[keyno].rsa.format = 0;
       if (buflen < 6)
         app->app_local->keyattr[keyno].rsa.format = RSA_STD;
       else
         app->app_local->keyattr[keyno].rsa.format = (buffer[5] == 0? RSA_STD   :
                                                      buffer[5] == 1? RSA_STD_N :
                                                      buffer[5] == 2? RSA_CRT   :
                                                      buffer[5] == 3? RSA_CRT_N :
                                                      RSA_UNKNOWN_FMT);
 
       if (opt.verbose)
         log_printf
           ("RSA, n=%u, e=%u, fmt=%s\n",
            app->app_local->keyattr[keyno].rsa.n_bits,
            app->app_local->keyattr[keyno].rsa.e_bits,
            app->app_local->keyattr[keyno].rsa.format == RSA_STD?  "std"  :
            app->app_local->keyattr[keyno].rsa.format == RSA_STD_N?"std+n":
            app->app_local->keyattr[keyno].rsa.format == RSA_CRT?  "crt"  :
            app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N?"crt+n":"?");
     }
   else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA
            || *buffer == PUBKEY_ALGO_EDDSA)
     {
       const char *curve;
       int oidlen = buflen - 1;
 
       app->app_local->keyattr[keyno].ecc.flags = 0;
 
       if (buffer[buflen-1] == 0x00 || buffer[buflen-1] == 0xff)
         { /* Found "pubkey required"-byte for private key template.  */
           oidlen--;
           if (buffer[buflen-1] == 0xff)
             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_PUBKEY;
         }
 
       curve = ecc_curve (buffer + 1, oidlen);
 
       if (!curve)
         log_printhex (buffer+1, buflen-1, "Curve with OID not supported: ");
       else
         {
           app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC;
           app->app_local->keyattr[keyno].ecc.curve = curve;
           if (*buffer == PUBKEY_ALGO_EDDSA
               || (*buffer == PUBKEY_ALGO_ECDH
                   && !strcmp (app->app_local->keyattr[keyno].ecc.curve,
                               "Curve25519")))
             app->app_local->keyattr[keyno].ecc.flags |= ECC_FLAG_DJB_TWEAK;
           if (opt.verbose)
             log_printf
               ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.curve,
                !(app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK)?
                "": keyno==1? " (djb-tweak)": " (eddsa)");
         }
     }
   else if (opt.verbose)
     log_printhex (buffer, buflen, "");
 
   xfree (relptr);
 }
 
 /* Select the OpenPGP application on the card in SLOT.  This function
    must be used before any other OpenPGP application functions. */
 gpg_error_t
 app_select_openpgp (app_t app)
 {
   static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
   int slot = app->slot;
   int rc;
   unsigned char *buffer;
   size_t buflen;
   void *relptr;
 
   /* Note that the card can't cope with P2=0xCO, thus we need to pass a
      special flag value. */
   rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
   if (!rc)
     {
       unsigned int manufacturer;
 
       app->apptype = APPTYPE_OPENPGP;
 
       app->did_chv1 = 0;
       app->did_chv2 = 0;
       app->did_chv3 = 0;
       app->app_local = NULL;
 
       /* The OpenPGP card returns the serial number as part of the
          AID; because we prefer to use OpenPGP serial numbers, we
          replace a possibly already set one from a EF.GDO with this
          one.  Note, that for current OpenPGP cards, no EF.GDO exists
          and thus it won't matter at all. */
       rc = iso7816_get_data (slot, 0, 0x004F, &buffer, &buflen);
       if (rc)
         goto leave;
       if (opt.verbose)
         {
           log_info ("AID: ");
           log_printhex (buffer, buflen, "");
         }
 
       app->appversion = buffer[6] << 8;
       app->appversion |= buffer[7];
       manufacturer = (buffer[8]<<8 | buffer[9]);
 
       xfree (app->serialno);
       app->serialno = buffer;
       app->serialnolen = buflen;
       buffer = NULL;
       app->app_local = xtrycalloc (1, sizeof *app->app_local);
       if (!app->app_local)
         {
           rc = gpg_error (gpg_err_code_from_errno (errno));
           goto leave;
         }
 
       app->app_local->manufacturer = manufacturer;
 
       if (app->appversion >= 0x0200)
         app->app_local->extcap.is_v2 = 1;
 
       if (app->appversion >= 0x0300)
         app->app_local->extcap.extcap_v3 = 1;
 
       /* Read the historical bytes.  */
       relptr = get_one_do (app, 0x5f52, &buffer, &buflen, NULL);
       if (relptr)
         {
           if (opt.verbose)
             {
               log_info ("Historical Bytes: ");
               log_printhex (buffer, buflen, "");
             }
           parse_historical (app->app_local, buffer, buflen);
           xfree (relptr);
         }
 
       /* Read the force-chv1 flag.  */
       relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
       if (!relptr)
         {
           log_error (_("can't access %s - invalid OpenPGP card?\n"),
                      "CHV Status Bytes");
           goto leave;
         }
       app->force_chv1 = (buflen && *buffer == 0);
       xfree (relptr);
 
       /* Read the extended capabilities.  */
       relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
       if (!relptr)
         {
           log_error (_("can't access %s - invalid OpenPGP card?\n"),
                      "Extended Capability Flags" );
           goto leave;
         }
       if (buflen)
         {
           app->app_local->extcap.sm_supported     = !!(*buffer & 0x80);
           app->app_local->extcap.get_challenge    = !!(*buffer & 0x40);
           app->app_local->extcap.key_import       = !!(*buffer & 0x20);
           app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
           app->app_local->extcap.private_dos      = !!(*buffer & 0x08);
           app->app_local->extcap.algo_attr_change = !!(*buffer & 0x04);
           app->app_local->extcap.has_decrypt      = !!(*buffer & 0x02);
           app->app_local->extcap.kdf_do           = !!(*buffer & 0x01);
         }
       if (buflen >= 10)
         {
           /* Available with cards of v2 or later.  */
           app->app_local->extcap.sm_algo = buffer[1];
           app->app_local->extcap.max_get_challenge
                                                = (buffer[2] << 8 | buffer[3]);
           app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
 
           /* Interpretation is different between v2 and v3, unfortunately.  */
           if (app->app_local->extcap.extcap_v3)
             {
               app->app_local->extcap.max_special_do
                 = (buffer[6] << 8 | buffer[7]);
               app->app_local->extcap.pin_blk2 = !!(buffer[8] & 0x01);
               app->app_local->extcap.mse= !!(buffer[9] & 0x01);
             }
         }
       xfree (relptr);
 
       /* Some of the first cards accidentally don't set the
          CHANGE_FORCE_CHV bit but allow it anyway. */
       if (app->appversion <= 0x0100 && manufacturer == 1)
         app->app_local->extcap.change_force_chv = 1;
 
       /* Check optional DO of "General Feature Management" for button.  */
       relptr = get_one_do (app, 0x7f74, &buffer, &buflen, NULL);
       if (relptr)
         /* It must be: 03 81 01 20 */
         app->app_local->extcap.has_button = 1;
 
       parse_login_data (app);
 
       if (opt.verbose)
         show_caps (app->app_local);
 
       parse_algorithm_attribute (app, 0);
       parse_algorithm_attribute (app, 1);
       parse_algorithm_attribute (app, 2);
 
       if (opt.verbose > 1)
         dump_all_do (slot);
 
       app->fnc.deinit = do_deinit;
       app->fnc.learn_status = do_learn_status;
       app->fnc.readcert = do_readcert;
       app->fnc.readkey = do_readkey;
       app->fnc.getattr = do_getattr;
       app->fnc.setattr = do_setattr;
       app->fnc.writecert = do_writecert;
       app->fnc.writekey = do_writekey;
       app->fnc.genkey = do_genkey;
       app->fnc.sign = do_sign;
       app->fnc.auth = do_auth;
       app->fnc.decipher = do_decipher;
       app->fnc.change_pin = do_change_pin;
       app->fnc.check_pin = do_check_pin;
    }
 
 leave:
   if (rc)
     do_deinit (app);
   return rc;
 }
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 6db9c1b7d..862278b5c 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -1,1435 +1,1438 @@
 /* scdaemon.c  -  The GnuPG Smartcard Daemon
  * Copyright (C) 2001-2002, 2004-2005, 2007-2009 Free Software Foundation, Inc.
  * Copyright (C) 2001-2002, 2004-2005, 2007-2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <https://www.gnu.org/licenses/>.
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 #include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <time.h>
 #include <fcntl.h>
 #ifndef HAVE_W32_SYSTEM
 #include <sys/socket.h>
 #include <sys/un.h>
 #endif /*HAVE_W32_SYSTEM*/
 #include <unistd.h>
 #include <signal.h>
 #include <npth.h>
 
 #define INCLUDED_BY_MAIN_MODULE 1
 #define GNUPG_COMMON_NEED_AFLOCAL
 #include "scdaemon.h"
 #include <ksba.h>
 #include <gcrypt.h>
 
 #include <assuan.h> /* malloc hooks */
 
 #include "../common/i18n.h"
 #include "../common/sysutils.h"
 #include "iso7816.h"
 #include "apdu.h"
 #include "ccid-driver.h"
 #include "../common/gc-opt-flags.h"
 #include "../common/asshelp.h"
 #include "../common/exechelp.h"
 #include "../common/init.h"
 
 #ifndef ENAMETOOLONG
 # define ENAMETOOLONG EINVAL
 #endif
 
 enum cmd_and_opt_values
 { aNull = 0,
   oCsh            = 'c',
   oQuiet          = 'q',
   oSh             = 's',
   oVerbose        = 'v',
 
   oNoVerbose = 500,
   aGPGConfList,
   aGPGConfTest,
   oOptions,
   oDebug,
   oDebugAll,
   oDebugLevel,
   oDebugWait,
   oDebugAllowCoreDump,
   oDebugCCIDDriver,
   oDebugLogTid,
   oDebugAssuanLogCats,
   oNoGreeting,
   oNoOptions,
   oHomedir,
   oNoDetach,
   oNoGrab,
   oLogFile,
   oServer,
   oMultiServer,
   oDaemon,
   oBatch,
   oReaderPort,
   oCardTimeout,
   octapiDriver,
   opcscDriver,
+  opcscShared,
   oDisableCCID,
   oDisableOpenSC,
   oDisablePinpad,
   oAllowAdmin,
   oDenyAdmin,
   oDisableApplication,
   oEnablePinpadVarlen,
   oListenBacklog,
 
   oNoop
 };
 
 
 
 static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
   ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
 
   ARGPARSE_group (301, N_("@Options:\n ")),
 
   ARGPARSE_s_n (oServer,"server", N_("run in server mode (foreground)")),
   ARGPARSE_s_n (oMultiServer, "multi-server",
                 N_("run in multi server mode (foreground)")),
   ARGPARSE_s_n (oDaemon, "daemon", N_("run in daemon mode (background)")),
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
   ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
   ARGPARSE_s_n (oSh,    "sh", N_("sh-style command output")),
   ARGPARSE_s_n (oCsh,   "csh", N_("csh-style command output")),
   ARGPARSE_conffile (oOptions, "options", N_("|FILE|read options from FILE")),
   ARGPARSE_s_s (oDebug, "debug", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
   ARGPARSE_s_s (oDebugLevel, "debug-level" ,
                 N_("|LEVEL|set the debugging level to LEVEL")),
   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
   ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
   ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
   ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
   ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
   ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
   ARGPARSE_s_s (oLogFile,  "log-file", N_("|FILE|write a log to FILE")),
   ARGPARSE_s_s (oReaderPort, "reader-port",
                 N_("|N|connect to reader at port N")),
   ARGPARSE_s_s (octapiDriver, "ctapi-driver",
                 N_("|NAME|use NAME as ct-API driver")),
   ARGPARSE_s_s (opcscDriver, "pcsc-driver",
                 N_("|NAME|use NAME as PC/SC driver")),
+  ARGPARSE_s_n (opcscShared, "pcsc-shared", "@"),
   ARGPARSE_s_n (oDisableCCID, "disable-ccid",
 #ifdef HAVE_LIBUSB
                                     N_("do not use the internal CCID driver")
 #else
                                     "@"
 #endif
                 /* end --disable-ccid */),
   ARGPARSE_s_u (oCardTimeout, "card-timeout",
                 N_("|N|disconnect the card after N seconds of inactivity")),
 
   ARGPARSE_s_n (oDisablePinpad, "disable-pinpad",
                 N_("do not use a reader's pinpad")),
   ARGPARSE_ignore (300, "disable-keypad"),
 
   ARGPARSE_s_n (oAllowAdmin, "allow-admin", "@"),
   ARGPARSE_s_n (oDenyAdmin, "deny-admin",
                 N_("deny the use of admin card commands")),
   ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
   ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
                 N_("use variable length input for pinpad")),
   ARGPARSE_s_s (oHomedir,    "homedir",      "@"),
   ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
   ARGPARSE_noconffile (oNoOptions, "no-options", "@"),
 
   /* Stubs for options which are implemented by 2.3 or later.  */
   ARGPARSE_s_s (oNoop, "application-priority", "@"),
 
   ARGPARSE_end ()
 };
 
 
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
     { 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"     },
     { DBG_CARD_IO_VALUE, "cardio"  },
     { DBG_READER_VALUE , "reader"  },
     { 0, NULL }
   };
 
 
 /* The card driver we use by default for PC/SC.  */
 #if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__)
 #define DEFAULT_PCSC_DRIVER "winscard.dll"
 #elif defined(__APPLE__)
 #define DEFAULT_PCSC_DRIVER "/System/Library/Frameworks/PCSC.framework/PCSC"
 #elif defined(__GLIBC__)
 #define DEFAULT_PCSC_DRIVER "libpcsclite.so.1"
 #else
 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
 #endif
 
 /* The timer tick used to check card removal.
 
    We poll every 500ms to let the user immediately know a status
    change.
 
    For a card reader with an interrupt endpoint, this timer is not
    used with the internal CCID driver.
 
    This is not too good for power saving but given that there is no
    easy way to block on card status changes it is the best we can do.
    For PC/SC we could in theory use an extra thread to wait for status
    changes but that requires a native thread because there is no way
    to make the underlying PC/SC card change function block using a Npth
    mechanism.  Given that a native thread could only be used under W32
    we don't do that at all.  */
 #define TIMERTICK_INTERVAL_SEC     (0)
 #define TIMERTICK_INTERVAL_USEC    (500000)
 
 /* Flag to indicate that a shutdown was requested. */
 static int shutdown_pending;
 
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
 
 /* Flag telling whether we are running as a pipe server.  */
 static int pipe_server;
 
 /* Name of the communication socket */
 static char *socket_name;
 /* Name of the redirected socket or NULL.  */
 static char *redir_socket_name;
 
 /* We need to keep track of the server's nonces (these are dummies for
    POSIX systems). */
 static assuan_sock_nonce_t socket_nonce;
 
 /* Value for the listen() backlog argument.  Change at runtime with
  * --listen-backlog.  */
 static int listen_backlog = 64;
 
 #ifdef HAVE_W32_SYSTEM
 static HANDLE the_event;
 #else
 /* PID to notify update of usb devices.  */
 static pid_t main_thread_pid;
 #endif
 #ifdef HAVE_PSELECT_NO_EINTR
 /* FD to notify changes.  */
 static int notify_fd;
 #endif
 
 static char *create_socket_name (char *standard_name);
 static gnupg_fd_t create_server_socket (const char *name,
                                         char **r_redir_name,
                                         assuan_sock_nonce_t *nonce);
 
 static void *start_connection_thread (void *arg);
 static void handle_connections (int listen_fd);
 
 /* Pth wrapper function definitions. */
 ASSUAN_SYSTEM_NPTH_IMPL;
 
 static int active_connections;
 
 
 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 *ver_gcry, *ver_ksba;
   const char *p;
 
   switch (level)
     {
     case  9: p = "GPL-3.0-or-later"; break;
     case 11: p = "@SCDAEMON@ (@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 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 1:
     case 40: p =  _("Usage: @SCDAEMON@ [options] (-h for help)");
       break;
     case 41: p =  _("Syntax: scdaemon [options] [command [args]]\n"
                     "Smartcard daemon for @GNUPG@\n");
     break;
 
     default: p = NULL;
     }
   return p;
 }
 
 
 static int
 tid_log_callback (unsigned long *rvalue)
 {
   int len = sizeof (*rvalue);
   npth_t thread;
 
   thread = npth_self ();
   if (sizeof (thread) < len)
     len = sizeof (thread);
   memcpy (rvalue, &thread, len);
 
   return 2; /* Use use hex representation.  */
 }
 
 
 /* Setup the debugging.  With a LEVEL of NULL only the active debug
    flags are propagated to the subsystems.  With LEVEL set, a specific
    set of debug flags is set; thus overriding all flags already
    set. */
 static void
 set_debug (const char *level)
 {
   int numok = (level && digitp (level));
   int numlvl = numok? atoi (level) : 0;
 
   if (!level)
     ;
   else if (!strcmp (level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
   else if (!strcmp (level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (level, "advanced") || (numok && numlvl <= 5))
     opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (level, "expert") || (numok && numlvl <= 8))
     opt.debug = (DBG_IPC_VALUE|DBG_CACHE_VALUE|DBG_CARD_IO_VALUE);
   else if (!strcmp (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"), level);
       scd_exit(2);
     }
 
 
   if (opt.debug && !opt.verbose)
     opt.verbose = 1;
   if (opt.debug && opt.quiet)
     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);
 }
 
 
 
 static void
 cleanup (void)
 {
   if (socket_name && *socket_name)
     {
       char *name;
 
       name = redir_socket_name? redir_socket_name : socket_name;
 
       gnupg_remove (name);
       *socket_name = 0;
     }
 }
 
 static void
 setup_signal_mask (void)
 {
 #ifndef HAVE_W32_SYSTEM
   npth_sigev_init ();
   npth_sigev_add (SIGHUP);
   npth_sigev_add (SIGUSR1);
   npth_sigev_add (SIGUSR2);
   npth_sigev_add (SIGINT);
   npth_sigev_add (SIGCONT);
   npth_sigev_add (SIGTERM);
   npth_sigev_fini ();
   main_thread_pid = getpid ();
 #endif
 }
 
 int
 main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
   char **orig_argv;
   char *last_configname = NULL;
   const char *configname = NULL;
   const char *shell;
   int debug_argparser = 0;
   const char *debug_level = NULL;
   int greeting = 0;
   int nogreeting = 0;
   int multi_server = 0;
   int is_daemon = 0;
   int nodetach = 0;
   int csh_style = 0;
   char *logfile = NULL;
   int debug_wait = 0;
   int gpgconf_list = 0;
   char *config_filename = NULL;
   int allow_coredump = 0;
   struct assuan_malloc_hooks malloc_hooks;
   int res;
   npth_t pipecon_handler;
 
   early_system_init ();
   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 INIT_SECMEM()
      somewhere after the option parsing */
   log_set_prefix ("scdaemon", GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID);
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
   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);
   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   assuan_sock_init ();
   setup_libassuan_logging (&opt.debug, NULL);
 
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
 
   disable_core_dumps ();
 
   /* Set default options. */
   opt.allow_admin = 1;
   opt.pcsc_driver = DEFAULT_PCSC_DRIVER;
 
   shell = getenv ("SHELL");
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
   /* 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 oHomedir:
           gnupg_set_homedir (pargs.r.ret_str);
           break;
         }
     }
   /* 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 working under our real uid
    */
 
   /* The configuraton directories for use by gpgrt_argparser.  */
   gnupg_set_confdir (GNUPG_CONFDIR_SYS, gnupg_sysconfdir ());
   gnupg_set_confdir (GNUPG_CONFDIR_USER, gnupg_homedir ());
 
   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 (gnupg_argparser (&pargs, opts, SCDAEMON_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: gpgconf_list = 1; break;
         case aGPGConfTest: gpgconf_list = 2; break;
         case oQuiet: opt.quiet = 1; break;
         case oVerbose: opt.verbose++; break;
         case oBatch: opt.batch=1; break;
 
         case oDebug:
           if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
             {
               pargs.r_opt = ARGPARSE_INVALID_ARG;
               pargs.err = ARGPARSE_PRINT_ERROR;
             }
           break;
         case oDebugAll: opt.debug = ~0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
         case oDebugAllowCoreDump:
           enable_core_dumps ();
           allow_coredump = 1;
           break;
         case oDebugCCIDDriver:
 #ifdef HAVE_LIBUSB
           ccid_set_debug_level (ccid_set_debug_level (-1)+1);
 #endif /*HAVE_LIBUSB*/
           break;
         case oDebugLogTid:
           log_set_pid_suffix_cb (tid_log_callback);
           break;
         case oDebugAssuanLogCats:
           set_libassuan_log_cats (pargs.r.ret_ulong);
           break;
 
         case oNoGreeting: nogreeting = 1; break;
         case oNoVerbose: opt.verbose = 0; break;
         case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
         case oNoDetach: nodetach = 1; break;
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oCsh: csh_style = 1; break;
         case oSh: csh_style = 0; break;
         case oServer: pipe_server = 1; break;
         case oMultiServer: pipe_server = 1; multi_server = 1; break;
         case oDaemon: is_daemon = 1; break;
 
         case oReaderPort: opt.reader_port = pargs.r.ret_str; break;
         case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
         case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
+        case opcscShared: opt.pcsc_shared = 1; break;
         case oDisableCCID: opt.disable_ccid = 1; break;
         case oDisableOpenSC: break;
 
         case oDisablePinpad: opt.disable_pinpad = 1; break;
 
         case oAllowAdmin: /* Dummy because allow is now the default.  */
           break;
         case oDenyAdmin: opt.allow_admin = 0; break;
 
         case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break;
 
         case oDisableApplication:
           add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
           break;
 
         case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break;
 
         case oListenBacklog:
           listen_backlog = pargs.r.ret_int;
           break;
 
         case oNoop: break;
 
         default:
           if (configname)
             pargs.err = ARGPARSE_PRINT_WARNING;
           else
             pargs.err = ARGPARSE_PRINT_ERROR;
           break;
         }
     }
   gnupg_argparse (NULL, &pargs, NULL);  /* Release internal state.  */
 
   if (!last_configname)
     config_filename = make_filename (gnupg_homedir (),
                                      SCDAEMON_NAME EXTSEP_S "conf",
                                      NULL);
   else
     {
       config_filename = last_configname;
       last_configname = NULL;
     }
 
   if (log_get_errorcount(0))
     exit(2);
   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
   log_info ("NOTE: this is a development version!\n");
 #endif
 
   /* 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]);
     }
 
   if (atexit (cleanup))
     {
       log_error ("atexit failed\n");
       cleanup ();
       exit (1);
     }
 
   set_debug (debug_level);
 
   if (initialize_module_command ())
     {
       log_error ("initialization failed\n");
       cleanup ();
       exit (1);
     }
 
   if (gpgconf_list == 2)
     scd_exit (0);
   if (gpgconf_list)
     {
       /* List options and default values in the GPG Conf format.  */
       char *filename_esc;
 
       filename_esc = percent_escape (config_filename, NULL);
       es_printf ("%s-%s.conf:%lu:\"%s\n",
                  GPGCONF_NAME, SCDAEMON_NAME,
                  GC_OPT_FLAG_DEFAULT, filename_esc);
       xfree (filename_esc);
 
       es_printf ("verbose:%lu:\n"
                  "quiet:%lu:\n"
                  "debug-level:%lu:\"none:\n"
                  "log-file:%lu:\n",
                  GC_OPT_FLAG_NONE,
                  GC_OPT_FLAG_NONE,
                  GC_OPT_FLAG_DEFAULT,
                  GC_OPT_FLAG_NONE );
 
       es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
       es_printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
       es_printf ("pcsc-driver:%lu:\"%s:\n",
               GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
 #ifdef HAVE_LIBUSB
       es_printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
 #endif
       es_printf ("deny-admin:%lu:\n", GC_OPT_FLAG_NONE );
       es_printf ("disable-pinpad:%lu:\n", GC_OPT_FLAG_NONE );
       es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0);
       es_printf ("enable-pinpad-varlen:%lu:\n", GC_OPT_FLAG_NONE );
 
       scd_exit (0);
     }
 
   /* Now start with logging to a file if this is desired.  */
   if (logfile)
     {
       log_set_file (logfile);
       log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
     }
 
   if (debug_wait && pipe_server)
     {
       log_debug ("waiting for debugger - my pid is %u .....\n",
                  (unsigned int)getpid());
       gnupg_sleep (debug_wait);
       log_debug ("... okay\n");
     }
 
   if (pipe_server)
     {
       /* This is the simple pipe based server */
       ctrl_t ctrl;
       npth_attr_t tattr;
       int fd = -1;
 
 #ifndef HAVE_W32_SYSTEM
       {
         struct sigaction sa;
 
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
         sigaction (SIGPIPE, &sa, NULL);
       }
 #endif
 
       npth_init ();
       setup_signal_mask ();
       gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
 
       /* If --debug-allow-core-dump has been given we also need to
          switch the working directory to a place where we can actually
          write. */
       if (allow_coredump)
         {
           if (chdir("/tmp"))
             log_debug ("chdir to '/tmp' failed: %s\n", strerror (errno));
           else
             log_debug ("changed working directory to '/tmp'\n");
         }
 
       /* In multi server mode we need to listen on an additional
          socket.  Create that socket now before starting the handler
          for the pipe connection.  This allows that handler to send
          back the name of that socket. */
       if (multi_server)
         {
           socket_name = create_socket_name (SCDAEMON_SOCK_NAME);
           fd = FD2INT(create_server_socket (socket_name,
                                             &redir_socket_name, &socket_nonce));
         }
 
       res = npth_attr_init (&tattr);
       if (res)
         {
           log_error ("error allocating thread attributes: %s\n",
                      strerror (res));
           scd_exit (2);
         }
       npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
 
       ctrl = xtrycalloc (1, sizeof *ctrl);
       if ( !ctrl )
         {
           log_error ("error allocating connection control data: %s\n",
                      strerror (errno) );
           scd_exit (2);
         }
       ctrl->thread_startup.fd = GNUPG_INVALID_FD;
       res = npth_create (&pipecon_handler, &tattr, start_connection_thread, ctrl);
       if (res)
         {
           log_error ("error spawning pipe connection handler: %s\n",
                      strerror (res) );
           xfree (ctrl);
           scd_exit (2);
         }
       npth_setname_np (pipecon_handler, "pipe-connection");
       npth_attr_destroy (&tattr);
 
       /* We run handle_connection to wait for the shutdown signal and
          to run the ticker stuff.  */
       handle_connections (fd);
       if (fd != -1)
         close (fd);
     }
   else if (!is_daemon)
     {
       log_info (_("please use the option '--daemon'"
                   " to run the program in the background\n"));
     }
   else
     { /* Regular server mode */
       int fd;
 #ifndef HAVE_W32_SYSTEM
       pid_t pid;
       int i;
 #endif
 
       /* Create the socket.  */
       socket_name = create_socket_name (SCDAEMON_SOCK_NAME);
       fd = FD2INT (create_server_socket (socket_name,
                                          &redir_socket_name, &socket_nonce));
 
 
       fflush (NULL);
 #ifdef HAVE_W32_SYSTEM
       (void)csh_style;
       (void)nodetach;
 #else
       pid = fork ();
       if (pid == (pid_t)-1)
         {
           log_fatal ("fork failed: %s\n", strerror (errno) );
           exit (1);
         }
       else if (pid)
         { /* we are the parent */
           char *infostr;
 
           close (fd);
 
           /* create the info string: <name>:<pid>:<protocol_version> */
           if (gpgrt_asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1",
                               socket_name, (ulong) pid) < 0)
             {
               log_error ("out of core\n");
               kill (pid, SIGTERM);
               exit (1);
             }
           *socket_name = 0; /* don't let cleanup() remove the socket -
                                the child should do this from now on */
           if (argc)
             { /* run the program given on the commandline */
               if (putenv (infostr))
                 {
                   log_error ("failed to set environment: %s\n",
                              strerror (errno) );
                   kill (pid, SIGTERM );
                   exit (1);
                 }
               execvp (argv[0], argv);
               log_error ("failed to run the command: %s\n", strerror (errno));
               kill (pid, SIGTERM);
               exit (1);
             }
           else
             {
               /* Print the environment string, so that the caller can use
                  shell's eval to set it */
               if (csh_style)
                 {
                   *strchr (infostr, '=') = ' ';
                   es_printf ( "setenv %s;\n", infostr);
                 }
               else
                 {
                   es_printf ( "%s; export SCDAEMON_INFO;\n", infostr);
                 }
               xfree (infostr);
               exit (0);
             }
           /* NOTREACHED */
         } /* end parent */
 
       /* This is the child. */
 
       npth_init ();
       setup_signal_mask ();
       gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
 
       /* Detach from tty and put process into a new session. */
       if (!nodetach )
         {
           /* Close stdin, stdout and stderr unless it is the log stream. */
           for (i=0; i <= 2; i++)
             {
               if (!log_test_fd (i) && i != fd )
                 {
                   if ( !close (i)
                        && open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
                     {
                       log_error ("failed to open '%s': %s\n",
                                  "/dev/null", strerror (errno));
                       cleanup ();
                       exit (1);
                     }
                 }
             }
 
           if (setsid() == -1)
             {
               log_error ("setsid() failed: %s\n", strerror(errno) );
               cleanup ();
               exit (1);
             }
         }
 
       {
         struct sigaction sa;
 
         sa.sa_handler = SIG_IGN;
         sigemptyset (&sa.sa_mask);
         sa.sa_flags = 0;
         sigaction (SIGPIPE, &sa, NULL);
       }
 
 #endif /*!HAVE_W32_SYSTEM*/
 
       if (gnupg_chdir (gnupg_daemon_rootdir ()))
         {
           log_error ("chdir to '%s' failed: %s\n",
                      gnupg_daemon_rootdir (), strerror (errno));
           exit (1);
         }
 
       handle_connections (fd);
 
       close (fd);
     }
 
   xfree (config_filename);
   return 0;
 }
 
 
 void
 scd_exit (int rc)
 {
   apdu_prepare_exit ();
 #if 0
 #warning no update_random_seed_file
   update_random_seed_file();
 #endif
 #if 0
   /* at this time a bit annoying */
   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 );
 #endif
   gcry_control (GCRYCTL_TERM_SECMEM );
   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
   exit (rc);
 }
 
 
 static void
 scd_init_default_ctrl (ctrl_t ctrl)
 {
   (void)ctrl;
 }
 
 static void
 scd_deinit_default_ctrl (ctrl_t ctrl)
 {
   if (!ctrl)
     return;
   xfree (ctrl->in_data.value);
   ctrl->in_data.value = NULL;
   ctrl->in_data.valuelen = 0;
 }
 
 
 /* Return the name of the socket to be used to connect to this
    process.  If no socket is available, return NULL. */
 const char *
 scd_get_socket_name ()
 {
   if (socket_name && *socket_name)
     return socket_name;
   return NULL;
 }
 
 
 #ifndef HAVE_W32_SYSTEM
 static void
 handle_signal (int signo)
 {
   switch (signo)
     {
     case SIGHUP:
       log_info ("SIGHUP received - "
                 "re-reading configuration and resetting cards\n");
 /*       reread_configuration (); */
       break;
 
     case SIGUSR1:
       log_info ("SIGUSR1 received - printing internal information:\n");
       /* Fixme: We need to see how to integrate pth dumping into our
          logging system.  */
       /* pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); */
       app_dump_state ();
       break;
 
     case SIGUSR2:
       log_info ("SIGUSR2 received - no action defined\n");
       break;
 
     case SIGCONT:
       /* Nothing.  */
       log_debug ("SIGCONT received - breaking select\n");
       break;
 
     case SIGTERM:
       if (!shutdown_pending)
         log_info ("SIGTERM received - shutting down ...\n");
       else
         log_info ("SIGTERM received - still %i running threads\n",
                   active_connections);
       shutdown_pending++;
       if (shutdown_pending > 2)
         {
           log_info ("shutdown forced\n");
           log_info ("%s %s stopped\n", strusage(11), strusage(13) );
           cleanup ();
           scd_exit (0);
         }
       break;
 
     case SIGINT:
       log_info ("SIGINT received - immediate shutdown\n");
       log_info( "%s %s stopped\n", strusage(11), strusage(13));
       cleanup ();
       scd_exit (0);
       break;
 
     default:
       log_info ("signal %d received - no action defined\n", signo);
     }
 }
 #endif /*!HAVE_W32_SYSTEM*/
 
 
 /* Create a name for the socket.  We check for valid characters as
    well as against a maximum allowed length for a unix domain socket
    is done.  The function terminates the process in case of an error.
    Retunrs: Pointer to an allcoated string with the absolute name of
    the socket used.  */
 static char *
 create_socket_name (char *standard_name)
 {
   char *name;
 
   name = make_filename (gnupg_socketdir (), standard_name, NULL);
   if (strchr (name, PATHSEP_C))
     {
       log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
       scd_exit (2);
     }
   return name;
 }
 
 
 
 /* Create a Unix domain socket with NAME.  Returns the file descriptor
    or terminates the process in case of an error.  If the socket has
    been redirected the name of the real socket is stored as a malloced
    string at R_REDIR_NAME. */
 static gnupg_fd_t
 create_server_socket (const char *name, char **r_redir_name,
                       assuan_sock_nonce_t *nonce)
 {
   struct sockaddr *addr;
   struct sockaddr_un *unaddr;
   socklen_t len;
   gnupg_fd_t fd;
   int rc;
 
   xfree (*r_redir_name);
   *r_redir_name = NULL;
 
   fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
   if (fd == GNUPG_INVALID_FD)
     {
       log_error (_("can't create socket: %s\n"), strerror (errno));
       scd_exit (2);
     }
 
   unaddr = xmalloc (sizeof (*unaddr));
   addr = (struct sockaddr*)unaddr;
 
   {
     int redirected;
 
     if (assuan_sock_set_sockaddr_un (name, addr, &redirected))
       {
         if (errno == ENAMETOOLONG)
           log_error (_("socket name '%s' is too long\n"), name);
         else
           log_error ("error preparing socket '%s': %s\n",
                      name, gpg_strerror (gpg_error_from_syserror ()));
         scd_exit (2);
       }
     if (redirected)
       {
         *r_redir_name = xstrdup (unaddr->sun_path);
         if (opt.verbose)
           log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name);
       }
   }
 
   len = SUN_LEN (unaddr);
 
   rc = assuan_sock_bind (fd, addr, len);
   if (rc == -1 && errno == EADDRINUSE)
     {
       gnupg_remove (unaddr->sun_path);
       rc = assuan_sock_bind (fd, addr, len);
     }
   if (rc != -1
       && (rc=assuan_sock_get_nonce (addr, len, nonce)))
     log_error (_("error getting nonce for the socket\n"));
  if (rc == -1)
     {
       log_error (_("error binding socket to '%s': %s\n"),
                  unaddr->sun_path,
                  gpg_strerror (gpg_error_from_syserror ()));
       assuan_sock_close (fd);
       scd_exit (2);
     }
 
   if (gnupg_chmod (unaddr->sun_path, "-rwx"))
     log_error (_("can't set permissions of '%s': %s\n"),
                unaddr->sun_path, strerror (errno));
 
   if (listen (FD2INT(fd), listen_backlog) == -1)
     {
       log_error ("listen(fd, %d) failed: %s\n",
                  listen_backlog, gpg_strerror (gpg_error_from_syserror ()));
       assuan_sock_close (fd);
       scd_exit (2);
     }
 
   if (opt.verbose)
     log_info (_("listening on socket '%s'\n"), unaddr->sun_path);
 
   return fd;
 }
 
 
 
 /* This is the standard connection thread's main function.  */
 static void *
 start_connection_thread (void *arg)
 {
   ctrl_t ctrl = arg;
 
   if (ctrl->thread_startup.fd != GNUPG_INVALID_FD
       && assuan_sock_check_nonce (ctrl->thread_startup.fd, &socket_nonce))
     {
       log_info (_("error reading nonce on fd %d: %s\n"),
                 FD2INT(ctrl->thread_startup.fd), strerror (errno));
       assuan_sock_close (ctrl->thread_startup.fd);
       xfree (ctrl);
       return NULL;
     }
 
   active_connections++;
 
   scd_init_default_ctrl (ctrl);
   if (opt.verbose)
     log_info (_("handler for fd %d started\n"),
               FD2INT(ctrl->thread_startup.fd));
 
   /* If this is a pipe server, we request a shutdown if the command
      handler asked for it.  With the next ticker event and given that
      no other connections are running the shutdown will then
      happen.  */
   if (scd_command_handler (ctrl, FD2INT(ctrl->thread_startup.fd))
       && pipe_server)
     shutdown_pending = 1;
 
   if (opt.verbose)
     log_info (_("handler for fd %d terminated\n"),
               FD2INT (ctrl->thread_startup.fd));
 
   scd_deinit_default_ctrl (ctrl);
   xfree (ctrl);
 
   if (--active_connections == 0)
     scd_kick_the_loop ();
 
   return NULL;
 }
 
 
 void
 scd_kick_the_loop (void)
 {
   /* Kick the select loop.  */
 #ifdef HAVE_W32_SYSTEM
   int ret = SetEvent (the_event);
   if (ret == 0)
     log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
                w32_strerror (-1));
 #elif defined(HAVE_PSELECT_NO_EINTR)
   write (notify_fd, "", 1);
 #else
   int ret = kill (main_thread_pid, SIGCONT);
   if (ret < 0)
     log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
                gpg_strerror (gpg_error_from_syserror ()));
 #endif
 }
 
 /* Connection handler loop.  Wait for connection requests and spawn a
    thread after accepting a connection.  LISTEN_FD is allowed to be -1
    in which case this code will only do regular timeouts and handle
    signals. */
 static void
 handle_connections (int listen_fd)
 {
   npth_attr_t tattr;
   struct sockaddr_un paddr;
   socklen_t plen;
   fd_set fdset, read_fdset;
   int nfd;
   int ret;
   int fd;
   struct timespec timeout;
   struct timespec *t;
   int saved_errno;
 #ifdef HAVE_W32_SYSTEM
   HANDLE events[2];
   unsigned int events_set;
 #else
   int signo;
 #endif
 #ifdef HAVE_PSELECT_NO_EINTR
   int pipe_fd[2];
 
   ret = gnupg_create_pipe (pipe_fd);
   if (ret)
     {
       log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
       return;
     }
   notify_fd = pipe_fd[1];
 #endif
 
   ret = npth_attr_init(&tattr);
   if (ret)
     {
       log_error ("npth_attr_init failed: %s\n", strerror (ret));
       return;
     }
 
   npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
 
 #ifdef HAVE_W32_SYSTEM
   {
     HANDLE h, h2;
     SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
 
     events[0] = the_event = INVALID_HANDLE_VALUE;
     events[1] = INVALID_HANDLE_VALUE;
     h = CreateEvent (&sa, TRUE, FALSE, NULL);
     if (!h)
       log_error ("can't create scd event: %s\n", w32_strerror (-1) );
     else if (!DuplicateHandle (GetCurrentProcess(), h,
                                GetCurrentProcess(), &h2,
                                EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
       {
         log_error ("setting synchronize for scd_kick_the_loop failed: %s\n",
                    w32_strerror (-1) );
         CloseHandle (h);
       }
     else
       {
         CloseHandle (h);
         events[0] = the_event = h2;
       }
   }
 #endif
 
   FD_ZERO (&fdset);
   nfd = 0;
   if (listen_fd != -1)
     {
       FD_SET (listen_fd, &fdset);
       nfd = listen_fd;
     }
 
   for (;;)
     {
       int periodical_check;
       int max_fd = nfd;
 
       if (shutdown_pending)
         {
           if (active_connections == 0)
             break; /* ready */
 
           /* Do not accept anymore connections but wait for existing
              connections to terminate. We do this by clearing out all
              file descriptors to wait for, so that the select will be
              used to just wait on a signal or timeout event. */
           FD_ZERO (&fdset);
           listen_fd = -1;
         }
 
       periodical_check = scd_update_reader_status_file ();
 
       timeout.tv_sec = TIMERTICK_INTERVAL_SEC;
       timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000;
 
       if (shutdown_pending || periodical_check)
         t = &timeout;
       else
         t = NULL;
 
       /* POSIX says that fd_set should be implemented as a structure,
          thus a simple assignment is fine to copy the entire set.  */
       read_fdset = fdset;
 
 #ifdef HAVE_PSELECT_NO_EINTR
       FD_SET (pipe_fd[0], &read_fdset);
       if (max_fd < pipe_fd[0])
         max_fd = pipe_fd[0];
 #else
       (void)max_fd;
 #endif
 
 #ifndef HAVE_W32_SYSTEM
       ret = npth_pselect (max_fd+1, &read_fdset, NULL, NULL, t,
                           npth_sigev_sigmask ());
       saved_errno = errno;
 
       while (npth_sigev_get_pending(&signo))
         handle_signal (signo);
 #else
       ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, t,
                           events, &events_set);
       saved_errno = errno;
       if (events_set & 1)
         continue;
 #endif
 
       if (ret == -1 && saved_errno != EINTR)
         {
           log_error (_("npth_pselect failed: %s - waiting 1s\n"),
                      strerror (saved_errno));
           npth_sleep (1);
           continue;
         }
 
       if (ret <= 0)
         /* Timeout.  Will be handled when calculating the next timeout.  */
         continue;
 
 #ifdef HAVE_PSELECT_NO_EINTR
       if (FD_ISSET (pipe_fd[0], &read_fdset))
         {
           char buf[256];
 
           read (pipe_fd[0], buf, sizeof buf);
         }
 #endif
 
       if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset))
         {
           ctrl_t ctrl;
 
           plen = sizeof paddr;
           fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
           if (fd == -1)
             {
               log_error ("accept failed: %s\n", strerror (errno));
             }
           else if ( !(ctrl = xtrycalloc (1, sizeof *ctrl)) )
             {
               log_error ("error allocating connection control data: %s\n",
                          strerror (errno) );
               close (fd);
             }
           else
             {
               char threadname[50];
               npth_t thread;
 
               snprintf (threadname, sizeof threadname, "conn fd=%d", fd);
               ctrl->thread_startup.fd = INT2FD (fd);
               ret = npth_create (&thread, &tattr, start_connection_thread, ctrl);
               if (ret)
                 {
                   log_error ("error spawning connection handler: %s\n",
                              strerror (ret));
                   xfree (ctrl);
                   close (fd);
                 }
               else
                 npth_setname_np (thread, threadname);
             }
         }
     }
 
 #ifdef HAVE_W32_SYSTEM
   if (the_event != INVALID_HANDLE_VALUE)
     CloseHandle (the_event);
 #endif
 #ifdef HAVE_PSELECT_NO_EINTR
   close (pipe_fd[0]);
   close (pipe_fd[1]);
 #endif
   cleanup ();
   log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
   npth_attr_destroy (&tattr);
 }
 
 /* Return the number of active connections. */
 int
 get_active_connection_count (void)
 {
   return active_connections;
 }
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 336013805..3ba1b9ad0 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -1,142 +1,143 @@
 /* scdaemon.h - Global definitions for the SCdaemon
  *	Copyright (C) 2001, 2002, 2003 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 SCDAEMON_H
 #define SCDAEMON_H
 
 #ifdef GPG_ERR_SOURCE_DEFAULT
 #error GPG_ERR_SOURCE_DEFAULT already defined
 #endif
 #define GPG_ERR_SOURCE_DEFAULT  GPG_ERR_SOURCE_SCD
 #include <gpg-error.h>
 
 #include <time.h>
 #include <gcrypt.h>
 #include "../common/util.h"
 #include "../common/sysutils.h"
 #include "app-common.h"
 
 
 /* To convey some special hash algorithms we use algorithm numbers
    reserved for application use. */
 #ifndef GCRY_MODULE_ID_USER
 #define GCRY_MODULE_ID_USER 1024
 #endif
 #define MD_USER_TLS_MD5SHA1 (GCRY_MODULE_ID_USER+1)
 
 /* Maximum length of a digest.  */
 #define MAX_DIGEST_LEN 64
 
 
 
 /* A large struct name "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 dry_run;        /* Don't change any persistent data. */
   int batch;          /* Batch mode. */
   const char *ctapi_driver; /* Library to access the ctAPI. */
   const char *pcsc_driver;  /* Library to access the PC/SC system. */
   const char *reader_port;  /* NULL or reder port to use. */
   int disable_ccid;    /* Disable the use of the internal CCID driver. */
   int disable_pinpad;  /* Do not use a pinpad. */
   int enable_pinpad_varlen;  /* Use variable length input for pinpad. */
   int allow_admin;     /* Allow the use of admin commands for certain
                           cards. */
+  int pcsc_shared;     /* Use shared PC/SC access.  */
   strlist_t disabled_applications;  /* Card applications we do not
                                        want to use. */
   unsigned long card_timeout; /* Disconnect after N seconds of inactivity.  */
 } opt;
 
 
 #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
 #define DBG_CARD_IO_VALUE 2048
 #define DBG_READER_VALUE  4096  /* Trace reader related functions.  */
 
 #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)
 #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
 #define DBG_READER  (opt.debug & DBG_READER_VALUE)
 
 struct server_local_s;
 struct app_ctx_s;
 
 struct server_control_s
 {
   /* Private data used to fire up the connection thread.  We use this
      structure do avoid an extra allocation for just a few bytes. */
   struct {
     gnupg_fd_t fd;
   } thread_startup;
 
   /* Local data of the server; used only in command.c. */
   struct server_local_s *server_local;
 
   /* The application context used with this connection or NULL if none
      associated.  Note that this is shared with the other connections:
      All connections accessing the same reader are using the same
      application context. */
   struct app_ctx_s *app_ctx;
 
   /* Helper to store the value we are going to sign */
   struct
   {
     unsigned char *value;
     int valuelen;
   } in_data;
 };
 
 
 /*-- scdaemon.c --*/
 void scd_exit (int rc);
 const char *scd_get_socket_name (void);
 
 /*-- command.c --*/
 gpg_error_t initialize_module_command (void);
 int  scd_command_handler (ctrl_t, int);
 void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
                    const char *serialno, const char *idstr);
 void send_status_info (ctrl_t ctrl, const char *keyword, ...)
      GPGRT_ATTR_SENTINEL(1);
 gpg_error_t send_status_direct (ctrl_t ctrl, const char *keyword,
                                 const char *args);
 gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword,
                                 const char *format, ...) GPGRT_ATTR_PRINTF(3,4);
 
 void popup_prompt (void *opaque, int on);
 void send_client_notifications (app_t app, int removal);
 void scd_kick_the_loop (void);
 int get_active_connection_count (void);
 
 /*-- app.c --*/
 int scd_update_reader_status_file (void);
 
 #endif /*SCDAEMON_H*/