mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Cleanups, fixes and PC/SC support
This commit is contained in:
parent
9ca4830a5b
commit
1bcf8ef9de
@ -1,3 +1,7 @@
|
||||
2003-08-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* configure.ac (GNUPG_DEFAULT_HONMEDIR): Changed back to ~/.gnupg.
|
||||
|
||||
2003-07-31 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (DISTCLEANFILES): Add g10defs.h
|
||||
|
10
NEWS
10
NEWS
@ -1,6 +1,16 @@
|
||||
Noteworthy changes in version 1.9.0 (unreleased)
|
||||
------------------------------------------------
|
||||
|
||||
* gpg has been renamed to gpg2 and gpgv to gpgv2. This is a
|
||||
temporary solution to allow co-existing with stable gpg versions.
|
||||
|
||||
* The default config file is ~/.gnupg/gpg.conf-1.9.0 if it exists.
|
||||
|
||||
* Removed the -k, -kv and -kvv commands. -k is now an alias to
|
||||
--list-keys. New command -K as alias for --list-secret-keys.
|
||||
|
||||
* Removed --run-as-shm-coprocess feature.
|
||||
|
||||
* gpg does now also use libgcrypt, libgpg-error is required.
|
||||
|
||||
* New gpgsm commands --call-dirmngr and --call-protect-tool.
|
||||
|
38
README
38
README
@ -34,6 +34,21 @@ gpgsm:
|
||||
prepended before each block.
|
||||
|
||||
|
||||
gpg2:
|
||||
-----
|
||||
|
||||
--card-status
|
||||
|
||||
Show information pertaining smartcards implementing the OpenPGP
|
||||
application.
|
||||
|
||||
--change-pin
|
||||
|
||||
Offers a menu to change the PIN of OpenPGP smartcards and to reset
|
||||
the retry counters.
|
||||
|
||||
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
|
||||
@ -139,6 +154,22 @@ gpg-agent:
|
||||
lockups in case of bugs.
|
||||
|
||||
|
||||
scdaemon:
|
||||
--------
|
||||
|
||||
--ctapi-driver <libraryname>
|
||||
|
||||
The default for Scdaemon is to use the PC/SC API currently provided
|
||||
by libpcsclite.so. As an alternative the ctAPI can be used by
|
||||
specify this option with the appropriate driver name
|
||||
(e.g. libtowitoko.so).
|
||||
|
||||
--reader-port <portname>
|
||||
|
||||
This specifies the port of the chipcard reader. For PC/SC this is
|
||||
currently ignored and the first PC/SC reader is used. For the
|
||||
ctAPI, a number must be specified (the default is 32768 for the
|
||||
first USB port).
|
||||
|
||||
|
||||
|
||||
@ -174,10 +205,15 @@ gpg.conf
|
||||
Options for gpg. Note that old versions of gpg use the
|
||||
filename `options' instead of `gpg.conf'.
|
||||
|
||||
gpg.conf-1.9.x
|
||||
|
||||
Options for gpg; tried before gpg.conf
|
||||
|
||||
|
||||
policies.txt
|
||||
|
||||
A list of allowed CA policies. This file should give the
|
||||
object identifiers of the policies line by line. emptry lines
|
||||
object identifiers of the policies line by line. Empty lines
|
||||
and lines startung with a hash mark are ignored.
|
||||
|
||||
++++++++++
|
||||
|
3
TODO
3
TODO
@ -55,5 +55,8 @@ might want to have an agent context for each service request
|
||||
* sm/export.c
|
||||
** Return an error code or a status info per user ID.
|
||||
|
||||
* scd/apdu.c
|
||||
** We need close_reader functionality
|
||||
|
||||
* ALL
|
||||
** Return IMPORT_OK status.
|
||||
|
@ -224,7 +224,7 @@ AH_BOTTOM([
|
||||
#ifdef HAVE_DRIVE_LETTERS
|
||||
#define GNUPG_DEFAULT_HOMEDIR "c:/gnupg"
|
||||
#else
|
||||
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg2"
|
||||
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
|
||||
#endif
|
||||
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
|
||||
|
||||
@ -966,7 +966,7 @@ cat >g10defs.tmp <<G10EOF
|
||||
#ifdef __VMS
|
||||
#define GNUPG_HOMEDIR "/SYS\$LOGIN/gnupg"
|
||||
#else
|
||||
#define GNUPG_HOMEDIR "~/.gnupg2"
|
||||
#define GNUPG_HOMEDIR "~/.gnupg"
|
||||
#endif
|
||||
#endif
|
||||
/* those are here to be redefined by handcrafted g10defs.h.
|
||||
|
@ -142,6 +142,10 @@ 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).
|
||||
|
||||
@item --ctapi-driver @var{library}
|
||||
Use @var{library} to access the smartcard reader. The current default
|
||||
is @code{libtowitoko.so}.
|
||||
|
||||
@end table
|
||||
|
||||
All the long options may also be given in the configuration file after
|
||||
|
@ -1,3 +1,23 @@
|
||||
2003-08-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (install-data-local): Dropped check for the ancient
|
||||
gpgm tool.
|
||||
(bin_PROGRAMS): Renamed gpg to gpg2 and gpgv to gpgv2. This is so
|
||||
that it won't conflict with the current stable version of gpg.
|
||||
|
||||
* pkglue.c (pk_check_secret_key): New.
|
||||
* seckey-cert.c (do_check): Reenable this test here again.
|
||||
|
||||
* g10.c (main): Add command -K as an alias for
|
||||
--list-secret-keys. Command "-k" is now an alias to --list-keys.
|
||||
Remove special treatment of -kv and -kvv.
|
||||
(set_cmd): Ditto.
|
||||
(main): Strip a "-cvs" suffix when testing for a version specific
|
||||
config file.
|
||||
|
||||
* status.h, status.c, g10.c [USE_SHM_COPROCESSING]: Removed. This
|
||||
is not any longer available.
|
||||
|
||||
2003-07-29 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* g10.c (main): Add secmem features and set the random seed file.
|
||||
|
@ -31,8 +31,7 @@ AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
|
||||
endif
|
||||
needed_libs = ../common/libcommon.a ../jnlib/libjnlib.a
|
||||
|
||||
#noinst_PROGRAMS = gpgd
|
||||
bin_PROGRAMS = gpg gpgv
|
||||
bin_PROGRAMS = gpg2 gpgv2
|
||||
|
||||
common_source = \
|
||||
global.h gpg.h \
|
||||
@ -65,7 +64,7 @@ common_source = \
|
||||
keylist.c \
|
||||
pkglue.c pkglue.h
|
||||
|
||||
gpg_SOURCES = g10.c \
|
||||
gpg2_SOURCES = g10.c \
|
||||
$(common_source) \
|
||||
pkclist.c \
|
||||
skclist.c \
|
||||
@ -99,7 +98,7 @@ gpg_SOURCES = g10.c \
|
||||
card-util.c \
|
||||
exec.c exec.h
|
||||
|
||||
gpgv_SOURCES = gpgv.c \
|
||||
gpgv2_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
verify.c
|
||||
|
||||
@ -111,8 +110,8 @@ gpgv_SOURCES = gpgv.c \
|
||||
# $(common_source)
|
||||
|
||||
LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
|
||||
gpg_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
|
||||
gpgv_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
|
||||
gpg2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
|
||||
gpgv2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error
|
||||
|
||||
$(PROGRAMS): $(needed_libs)
|
||||
|
||||
@ -120,8 +119,4 @@ install-data-local:
|
||||
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
|
||||
$(INSTALL_DATA) $(srcdir)/options.skel \
|
||||
$(DESTDIR)$(pkgdatadir)/options.skel
|
||||
@set -e;\
|
||||
if test -f $(DESTDIR)$(bindir)/gpgm ; then \
|
||||
echo "removing obsolete gpgm binary" ; \
|
||||
rm $(DESTDIR)$(bindir)/gpgm ; \
|
||||
fi
|
||||
|
||||
|
107
g10/g10.c
107
g10/g10.c
@ -61,7 +61,8 @@ enum cmd_and_opt_values { aNull = 0,
|
||||
aEncr = 'e',
|
||||
aEncrFiles,
|
||||
oInteractive = 'i',
|
||||
oKOption = 'k',
|
||||
aListKeys = 'k',
|
||||
aListSecretKeys = 'K',
|
||||
oDryRun = 'n',
|
||||
oOutput = 'o',
|
||||
oQuiet = 'q',
|
||||
@ -93,15 +94,11 @@ enum cmd_and_opt_values { aNull = 0,
|
||||
aDeleteKeys,
|
||||
aDeleteSecretKeys,
|
||||
aDeleteSecretAndPublicKeys,
|
||||
aKMode,
|
||||
aKModeC,
|
||||
aImport,
|
||||
aFastImport,
|
||||
aVerify,
|
||||
aVerifyFiles,
|
||||
aListKeys,
|
||||
aListSigs,
|
||||
aListSecretKeys,
|
||||
aSendKeys,
|
||||
aRecvKeys,
|
||||
aSearchKeys,
|
||||
@ -213,7 +210,6 @@ enum cmd_and_opt_values { aNull = 0,
|
||||
oTrustModel,
|
||||
oForceOwnertrust,
|
||||
oEmuChecksumBug,
|
||||
oRunAsShmCP,
|
||||
oSetFilename,
|
||||
oForYourEyesOnly,
|
||||
oNoForYourEyesOnly,
|
||||
@ -514,7 +510,6 @@ static ARGPARSE_OPTS opts[] = {
|
||||
/* Not yet used */
|
||||
/* { aListTrustPath, "list-trust-path",0, "@"}, */
|
||||
{ aPipeMode, "pipemode", 0, "@" },
|
||||
{ oKOption, NULL, 0, "@"},
|
||||
{ oPasswdFD, "passphrase-fd",1, "@" },
|
||||
#ifdef __riscos__
|
||||
{ oPasswdFile, "passphrase-file",2, "@" },
|
||||
@ -549,7 +544,6 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oTrustModel, "trust-model", 2, "@"},
|
||||
{ oForceOwnertrust, "force-ownertrust", 2, "@"},
|
||||
{ oEmuChecksumBug, "emulate-checksum-bug", 0, "@"},
|
||||
{ oRunAsShmCP, "run-as-shm-coprocess", 4, "@" },
|
||||
{ oSetFilename, "set-filename", 2, "@" },
|
||||
{ oForYourEyesOnly, "for-your-eyes-only", 0, "@" },
|
||||
{ oNoForYourEyesOnly, "no-for-your-eyes-only", 0, "@" },
|
||||
@ -879,8 +873,6 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
|
||||
cmd = aSignSym;
|
||||
else if( cmd == aSym && new_cmd == aSign )
|
||||
cmd = aSignSym;
|
||||
else if( cmd == aKMode && new_cmd == aSym )
|
||||
cmd = aKModeC;
|
||||
else if( ( cmd == aSign && new_cmd == aClearsign )
|
||||
|| ( cmd == aClearsign && new_cmd == aSign ) )
|
||||
cmd = aClearsign;
|
||||
@ -1167,9 +1159,6 @@ main( int argc, char **argv )
|
||||
int pwfd = -1;
|
||||
int with_fpr = 0; /* make an option out of --fingerprint */
|
||||
int any_explicit_recipient = 0;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
ulong requested_shm_size=0;
|
||||
#endif
|
||||
|
||||
#ifdef __riscos__
|
||||
riscos_global_defaults();
|
||||
@ -1276,19 +1265,6 @@ main( int argc, char **argv )
|
||||
opt.strict=0;
|
||||
log_set_strict(0);
|
||||
}
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
else if( pargs.r_opt == oRunAsShmCP ) {
|
||||
/* does not make sense in a options file, we do it here,
|
||||
* so that we are the able to drop setuid as soon as possible */
|
||||
opt.shm_coprocess = 1;
|
||||
requested_shm_size = pargs.r.ret_ulong;
|
||||
}
|
||||
else if ( pargs.r_opt == oStatusFD ) {
|
||||
/* this is needed to ensure that the status-fd filedescriptor is
|
||||
* initialized when init_shm_coprocessing() is called */
|
||||
set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
@ -1301,11 +1277,7 @@ main( int argc, char **argv )
|
||||
set_homedir (buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess ) {
|
||||
init_shm_coprocessing(requested_shm_size, 1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the secure memory. */
|
||||
gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
|
||||
maybe_setuid = 0;
|
||||
@ -1318,9 +1290,14 @@ main( int argc, char **argv )
|
||||
|
||||
if( default_config )
|
||||
{
|
||||
/* Try for a version specific config file first */
|
||||
/* Try for a version specific config file first but strip our
|
||||
usual cvs suffix. That suffix indicates that it is not yet
|
||||
the given version but we already want this config file. */
|
||||
configname = make_filename(opt.homedir,
|
||||
"gpg" EXTSEP_S "conf-" SAFE_VERSION, NULL );
|
||||
if (!strcmp (configname + strlen (configname) - 4, "-cvs"))
|
||||
configname[strlen (configname)-4] = 0;
|
||||
|
||||
if(access(configname,R_OK))
|
||||
{
|
||||
xfree (configname);
|
||||
@ -1458,7 +1435,6 @@ main( int argc, char **argv )
|
||||
case oInteractive: opt.interactive = 1; break;
|
||||
case oVerbose: g10_opt_verbose++;
|
||||
opt.verbose++; opt.list_sigs=1; break;
|
||||
case oKOption: set_cmd( &cmd, aKMode ); break;
|
||||
|
||||
case oBatch: opt.batch = 1; nogreeting = 1; break;
|
||||
case oUseAgent:
|
||||
@ -1631,17 +1607,6 @@ main( int argc, char **argv )
|
||||
case oGnuPG: opt.compliance = CO_GNUPG; break;
|
||||
case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
|
||||
case oCompressSigs: opt.compress_sigs = 1; break;
|
||||
case oRunAsShmCP:
|
||||
#ifndef __riscos__
|
||||
# ifndef USE_SHM_COPROCESSING
|
||||
/* not possible in the option file,
|
||||
* but we print the warning here anyway */
|
||||
log_error("shared memory coprocessing is not available\n");
|
||||
# endif
|
||||
#else /* __riscos__ */
|
||||
riscos_not_implemented("run-as-shm-coprocess");
|
||||
#endif /* __riscos__ */
|
||||
break;
|
||||
case oSetFilename: opt.set_filename = pargs.r.ret_str; break;
|
||||
case oForYourEyesOnly: eyes_only = 1; break;
|
||||
case oNoForYourEyesOnly: eyes_only = 0; break;
|
||||
@ -2276,21 +2241,6 @@ main( int argc, char **argv )
|
||||
set_cmd( &cmd, aListKeys);
|
||||
}
|
||||
|
||||
if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */
|
||||
if( cmd == aKModeC ) {
|
||||
opt.fingerprint = 1;
|
||||
cmd = aKMode;
|
||||
}
|
||||
opt.list_sigs = 0;
|
||||
if( opt.verbose > 2 )
|
||||
opt.check_sigs++;
|
||||
if( opt.verbose > 1 )
|
||||
opt.list_sigs++;
|
||||
|
||||
opt.verbose = opt.verbose > 1;
|
||||
g10_opt_verbose = opt.verbose;
|
||||
}
|
||||
|
||||
/* Compression algorithm 0 means no compression at all */
|
||||
if( opt.def_compress_algo == 0)
|
||||
opt.compress = 0;
|
||||
@ -2302,12 +2252,11 @@ main( int argc, char **argv )
|
||||
if( opt.verbose > 1 )
|
||||
set_packet_list_mode(1);
|
||||
|
||||
/* Add the keyrings, but not for some special commands and not in
|
||||
case of "-kvv userid keyring". Also avoid adding the secret
|
||||
keyring for a couple of commands to avoid unneeded access in
|
||||
case the secrings are stored on a floppy */
|
||||
if( cmd != aDeArmor && cmd != aEnArmor
|
||||
&& !(cmd == aKMode && argc == 2 ) )
|
||||
/* Add the keyrings, but not for some special commands. Also
|
||||
avoid adding the secret keyring for a couple of commands to
|
||||
avoid unneeded access in case the secrings are stored on a
|
||||
floppy */
|
||||
if( cmd != aDeArmor && cmd != aEnArmor )
|
||||
{
|
||||
if (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys
|
||||
&& cmd != aVerify && cmd != aVerifyFiles
|
||||
@ -2544,34 +2493,6 @@ main( int argc, char **argv )
|
||||
free_strlist(sl);
|
||||
break;
|
||||
|
||||
case aKMode: /* list keyring -- NOTE: This will be removed soon */
|
||||
if( argc < 2 ) { /* -kv [userid] */
|
||||
sl = NULL;
|
||||
if (argc && **argv)
|
||||
add_to_strlist2( &sl, *argv, utf8_strings );
|
||||
public_key_list( sl );
|
||||
free_strlist(sl);
|
||||
}
|
||||
else if( argc == 2 ) { /* -kv userid keyring */
|
||||
if( access( argv[1], R_OK ) ) {
|
||||
log_error(_("can't open %s: %s\n"),
|
||||
print_fname_stdin(argv[1]), strerror(errno));
|
||||
}
|
||||
else {
|
||||
/* add keyring (default keyrings are not registered in this
|
||||
* special case */
|
||||
keydb_add_resource( argv[1], 0, 0 );
|
||||
sl = NULL;
|
||||
if (**argv)
|
||||
add_to_strlist2( &sl, *argv, utf8_strings );
|
||||
public_key_list( sl );
|
||||
free_strlist(sl);
|
||||
}
|
||||
}
|
||||
else
|
||||
wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") );
|
||||
break;
|
||||
|
||||
case aKeygen: /* generate a key */
|
||||
if( opt.batch ) {
|
||||
if( argc > 1 )
|
||||
|
37
g10/pkglue.c
37
g10/pkglue.c
@ -287,8 +287,39 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
|
||||
}
|
||||
|
||||
|
||||
/* Check whether SKEY is a suitable secret key. */
|
||||
int
|
||||
pk_check_secret_key (int algo, gcry_mpi_t *skey)
|
||||
{
|
||||
gcry_sexp_t s_skey;
|
||||
int rc;
|
||||
|
||||
if (algo == GCRY_PK_DSA)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4]);
|
||||
}
|
||||
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3]);
|
||||
}
|
||||
else if (algo == GCRY_PK_RSA)
|
||||
{
|
||||
rc = gcry_sexp_build (&s_skey, NULL,
|
||||
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
|
||||
skey[0], skey[1], skey[2], skey[3], skey[4],
|
||||
skey[5]);
|
||||
}
|
||||
else
|
||||
return GPG_ERR_PUBKEY_ALGO;
|
||||
|
||||
|
||||
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
rc = gcry_pk_testkey (s_skey);
|
||||
gcry_sexp_release (s_skey);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
|
||||
gcry_mpi_t *pkey);
|
||||
int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
|
||||
gcry_mpi_t *skey);
|
||||
int pk_check_secret_key (int algo, gcry_mpi_t *skey);
|
||||
|
||||
|
||||
#endif /*GNUPG_G10_PKGLUE_H*/
|
||||
|
@ -215,14 +215,13 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
|
||||
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
|
||||
}
|
||||
/* the checksum may fail, so we also check the key itself */
|
||||
#warning fixme - we need to reenable this
|
||||
/* res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey ); */
|
||||
/* if( res ) { */
|
||||
/* copy_secret_key( sk, save_sk ); */
|
||||
/* passphrase_clear_cache ( keyid, sk->pubkey_algo ); */
|
||||
/* free_secret_key( save_sk ); */
|
||||
/* return gpg_error (GPG_ERR_BAD_PASSPHRASE); */
|
||||
/* } */
|
||||
res = pk_check_secret_key (sk->pubkey_algo, sk->skey);
|
||||
if (res) {
|
||||
copy_secret_key( sk, save_sk );
|
||||
passphrase_clear_cache ( keyid, sk->pubkey_algo );
|
||||
free_secret_key( save_sk );
|
||||
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
|
||||
}
|
||||
free_secret_key( save_sk );
|
||||
sk->is_protected = 0;
|
||||
}
|
||||
|
226
g10/status.c
226
g10/status.c
@ -1,5 +1,6 @@
|
||||
/* status.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -25,21 +26,6 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
#ifdef USE_CAPABILITIES
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#if defined(HAVE_MLOCK)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "gpg.h"
|
||||
#include "util.h"
|
||||
@ -56,13 +42,6 @@
|
||||
|
||||
static FILE *statusfp;
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
static int shm_id = -1;
|
||||
static volatile char *shm_area;
|
||||
static size_t shm_size;
|
||||
static int shm_is_locked;
|
||||
#endif /*USE_SHM_COPROCESSING*/
|
||||
|
||||
|
||||
static void
|
||||
progress_cb (void *ctx, const char *what, int printchar, int current, int total)
|
||||
@ -291,179 +270,6 @@ write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
|
||||
|
||||
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
static void
|
||||
remove_shmid( void )
|
||||
{
|
||||
if( shm_id != -1 ) {
|
||||
shmctl ( shm_id, IPC_RMID, 0);
|
||||
shm_id = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
init_shm_coprocessing ( ulong requested_shm_size, int lock_mem )
|
||||
{
|
||||
char buf[100];
|
||||
struct shmid_ds shmds;
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
atexit( remove_shmid );
|
||||
#endif
|
||||
requested_shm_size = (requested_shm_size + 4095) & ~4095;
|
||||
if ( requested_shm_size > 2 * 4096 )
|
||||
log_fatal("too much shared memory requested; only 8k are allowed\n");
|
||||
shm_size = 4096 /* one page for us */ + requested_shm_size;
|
||||
|
||||
shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 );
|
||||
if ( shm_id == -1 )
|
||||
log_fatal("can't get %uk of shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
|
||||
#if !defined(IPC_HAVE_SHM_LOCK) \
|
||||
&& defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
|
||||
/* part of the old code which uses mlock */
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
/* (need the cast for Solaris with Sun's workshop compilers) */
|
||||
if ( mlock ( (char*)shm_area, shm_size) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
#else /* this is the new code which handles the changes in the SHM
|
||||
* semantics introduced with Linux 2.4. The changes is that we
|
||||
* now change the permissions and then attach to the memory.
|
||||
*/
|
||||
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
#ifdef IPC_HAVE_SHM_LOCK
|
||||
if ( shmctl (shm_id, SHM_LOCK, 0) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#else
|
||||
log_info("Locking shared memory %d failed: No way to do it\n", shm_id );
|
||||
#endif
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* write info; Protocol version, id, size, locked size */
|
||||
sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(),
|
||||
shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 );
|
||||
write_status_text( STATUS_SHM_INFO, buf );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Request a string from client
|
||||
* If bool, returns static string on true (do not free) or NULL for false
|
||||
*/
|
||||
static char *
|
||||
do_shm_get( const char *keyword, int hidden, int bool )
|
||||
{
|
||||
size_t n;
|
||||
byte *p;
|
||||
char *string;
|
||||
|
||||
if( !shm_area )
|
||||
BUG();
|
||||
|
||||
shm_area[0] = 0; /* msb of length of control block */
|
||||
shm_area[1] = 32; /* and lsb */
|
||||
shm_area[2] = 1; /* indicate that we are waiting on a reply */
|
||||
shm_area[3] = 0; /* clear data available flag */
|
||||
|
||||
write_status_text( bool? STATUS_SHM_GET_BOOL :
|
||||
hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword );
|
||||
|
||||
do {
|
||||
pause_on_sigusr(1);
|
||||
if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 )
|
||||
log_fatal("client modified shm control block - abort\n");
|
||||
} while( !shm_area[3] );
|
||||
shm_area[2] = 0; /* reset request flag */
|
||||
p = (byte*)shm_area+32;
|
||||
n = p[0] << 8 | p[1];
|
||||
p += 2;
|
||||
if( n+32+2+1 > 4095 )
|
||||
log_fatal("client returns too large data (%u bytes)\n", (unsigned)n );
|
||||
|
||||
if( bool )
|
||||
return p[0]? "" : NULL;
|
||||
|
||||
string = hidden? xmalloc_secure ( n+1 ) : xmalloc ( n+1 );
|
||||
memcpy(string, p, n );
|
||||
string[n] = 0; /* make sure it is a string */
|
||||
if( hidden ) /* invalidate the memory */
|
||||
memset( p, 0, n );
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#endif /* USE_SHM_COPROCESSING */
|
||||
|
||||
static int
|
||||
myread(int fd, void *buf, size_t count)
|
||||
{
|
||||
@ -541,10 +347,6 @@ cpr_enabled()
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return 1;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -555,10 +357,6 @@ cpr_get_no_help( const char *keyword, const char *prompt )
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
return p;
|
||||
@ -572,10 +370,6 @@ cpr_get( const char *keyword, const char *prompt )
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
|
||||
@ -608,10 +402,6 @@ cpr_get_hidden( const char *keyword, const char *prompt )
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 1, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 1, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get_hidden( prompt );
|
||||
if( *p == '?' && !p[1] ) {
|
||||
@ -628,10 +418,6 @@ cpr_kill_prompt(void)
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return;
|
||||
#endif
|
||||
tty_kill_prompt();
|
||||
return;
|
||||
}
|
||||
@ -644,10 +430,6 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt )
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
@ -672,10 +454,6 @@ cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
|
@ -110,10 +110,6 @@ void write_status_buffer ( int no,
|
||||
void write_status_text_and_buffer ( int no, const char *text,
|
||||
const char *buffer, size_t len, int wrap );
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
void init_shm_coprocessing ( ulong requested_shm_size, int lock_mem );
|
||||
#endif /*USE_SHM_COPROCESSING*/
|
||||
|
||||
int cpr_enabled(void);
|
||||
char *cpr_get( const char *keyword, const char *prompt );
|
||||
char *cpr_get_no_help( const char *keyword, const char *prompt );
|
||||
|
@ -1,3 +1,25 @@
|
||||
2003-08-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
|
||||
an error.
|
||||
|
||||
2003-08-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* app.c (app_set_default_reader_port): New.
|
||||
(select_application): Use it here.
|
||||
* scdaemon.c (main): and here.
|
||||
* sc-copykeys.c: --reader-port does now take a string.
|
||||
* sc-investigate.c, scdaemon.c: Ditto.
|
||||
* apdu.c (apdu_open_reader): Ditto. Load pcsclite if no ctapi
|
||||
driver is configured. Always include code for ctapi.
|
||||
(new_reader_slot): Don't test for already used ports and remove
|
||||
port arg.
|
||||
(open_pcsc_reader, pcsc_send_apdu, pcsc_error_string): New.
|
||||
(apdu_send_le): Changed RC to long to cope with PC/SC.
|
||||
|
||||
* scdaemon.c, scdaemon.h: New option --ctapi-driver.
|
||||
* sc-investigate.c, sc-copykeys.c: Ditto.
|
||||
|
||||
2003-07-31 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (scdaemon_LDADD): Added INTLLIBS.
|
||||
|
426
scd/apdu.c
426
scd/apdu.c
@ -29,8 +29,6 @@
|
||||
#include "scdaemon.h"
|
||||
#include "apdu.h"
|
||||
|
||||
#define HAVE_CTAPI 1
|
||||
|
||||
#define MAX_READER 4 /* Number of readers we support concurrently. */
|
||||
#define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for
|
||||
insertion of the card (1 = don't wait). */
|
||||
@ -40,7 +38,13 @@
|
||||
/* A global table to keep track of active readers. */
|
||||
static struct {
|
||||
int used; /* True if slot is used. */
|
||||
unsigned short port; /* port number0 = unused, 1 - dev/tty */
|
||||
unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */
|
||||
int is_ctapi; /* This is a ctAPI driver. */
|
||||
struct {
|
||||
unsigned long context;
|
||||
unsigned long card;
|
||||
unsigned long protocol;
|
||||
} pcsc;
|
||||
int status;
|
||||
unsigned char atr[33];
|
||||
size_t atrlen;
|
||||
@ -55,6 +59,61 @@ static char (*CT_data) (unsigned short ctn, unsigned char *dad,
|
||||
unsigned char *rsp);
|
||||
static char (*CT_close) (unsigned short ctn);
|
||||
|
||||
/* 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
|
||||
#define PCSC_PROTOCOL_RAW 4
|
||||
|
||||
#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
|
||||
|
||||
struct pcsc_io_request_s {
|
||||
unsigned long protocol;
|
||||
unsigned long pci_len;
|
||||
};
|
||||
|
||||
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
||||
|
||||
long (*pcsc_establish_context) (unsigned long scope,
|
||||
const void *reserved1,
|
||||
const void *reserved2,
|
||||
unsigned long *r_context);
|
||||
long (*pcsc_release_context) (unsigned long context);
|
||||
long (*pcsc_list_readers) (unsigned long context, const char *groups,
|
||||
char *readers, unsigned long *readerslen);
|
||||
long (*pcsc_connect) (unsigned long context,
|
||||
const char *reader,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long *r_card,
|
||||
unsigned long *r_active_protocol);
|
||||
long (*pcsc_disconnect) (unsigned long card, unsigned long disposition);
|
||||
long (*pcsc_status) (unsigned long card,
|
||||
char *reader, unsigned long *readerlen,
|
||||
unsigned long *r_state, unsigned long *r_protocol,
|
||||
unsigned char *atr, unsigned long *atrlen);
|
||||
long (*pcsc_begin_transaction) (unsigned long card);
|
||||
long (*pcsc_end_transaction) (unsigned long card);
|
||||
long (*pcsc_transmit) (unsigned long card,
|
||||
const pcsc_io_request_t send_pci,
|
||||
const unsigned char *send_buffer,
|
||||
unsigned long send_len,
|
||||
pcsc_io_request_t recv_pci,
|
||||
unsigned char *recv_buffer,
|
||||
unsigned long *recv_len);
|
||||
long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -64,28 +123,16 @@ static char (*CT_close) (unsigned short ctn);
|
||||
*/
|
||||
|
||||
|
||||
/* Find an unused reader slot for PORT and put it into the reader
|
||||
/* 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. */
|
||||
static int
|
||||
new_reader_slot (int port)
|
||||
new_reader_slot (void)
|
||||
{
|
||||
int i, reader = -1;
|
||||
|
||||
if (port < 0 || port > 0xffff)
|
||||
{
|
||||
log_error ("new_reader_slot: invalid port %d requested\n", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i < MAX_READER; i++)
|
||||
{
|
||||
if (reader_table[i].used && reader_table[i].port == port)
|
||||
{
|
||||
log_error ("new_reader_slot: requested port %d already in use\n",
|
||||
reader);
|
||||
return -1;
|
||||
}
|
||||
else if (!reader_table[i].used && reader == -1)
|
||||
if (!reader_table[i].used && reader == -1)
|
||||
reader = i;
|
||||
}
|
||||
if (reader == -1)
|
||||
@ -94,7 +141,7 @@ new_reader_slot (int port)
|
||||
return -1;
|
||||
}
|
||||
reader_table[reader].used = 1;
|
||||
reader_table[reader].port = port;
|
||||
reader_table[reader].is_ctapi = 0;
|
||||
return reader;
|
||||
}
|
||||
|
||||
@ -102,11 +149,25 @@ new_reader_slot (int port)
|
||||
static void
|
||||
dump_reader_status (int reader)
|
||||
{
|
||||
log_info ("reader %d: %s\n", reader,
|
||||
reader_table[reader].status == 1? "Processor ICC present" :
|
||||
reader_table[reader].status == 0? "Memory ICC present" :
|
||||
"ICC not present" );
|
||||
|
||||
if (reader_table[reader].is_ctapi)
|
||||
{
|
||||
log_info ("reader slot %d: %s\n", reader,
|
||||
reader_table[reader].status == 1? "Processor ICC present" :
|
||||
reader_table[reader].status == 0? "Memory ICC present" :
|
||||
"ICC not present" );
|
||||
}
|
||||
else
|
||||
{
|
||||
log_info ("reader slot %d: active protocol:", reader);
|
||||
if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T0))
|
||||
log_printf (" T0");
|
||||
else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T1))
|
||||
log_printf (" T1");
|
||||
else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_RAW))
|
||||
log_printf (" raw");
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
if (reader_table[reader].status != -1)
|
||||
{
|
||||
log_info ("reader %d: ATR=", reader);
|
||||
@ -117,13 +178,12 @@ dump_reader_status (int reader)
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_CTAPI
|
||||
/*
|
||||
ct API Interface
|
||||
*/
|
||||
|
||||
static const char *
|
||||
ct_error_string (int err)
|
||||
ct_error_string (long err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
@ -150,7 +210,7 @@ ct_activate_card (int reader)
|
||||
unsigned short buflen;
|
||||
|
||||
if (count)
|
||||
sleep (1); /* FIXME: we should use a more reliable timer. */
|
||||
; /* FIXME: we should use a more reliable timer than sleep. */
|
||||
|
||||
/* Check whether card has been inserted. */
|
||||
dad[0] = 1; /* Destination address: CT. */
|
||||
@ -221,9 +281,15 @@ open_ct_reader (int port)
|
||||
{
|
||||
int rc, reader;
|
||||
|
||||
reader = new_reader_slot (port);
|
||||
if (port < 0 || port > 0xffff)
|
||||
{
|
||||
log_error ("open_ct_reader: invalid port %d requested\n", port);
|
||||
return -1;
|
||||
}
|
||||
reader = new_reader_slot ();
|
||||
if (reader == -1)
|
||||
return reader;
|
||||
reader_table[reader].port = port;
|
||||
|
||||
rc = CT_init (reader, (unsigned short)port);
|
||||
if (rc)
|
||||
@ -241,6 +307,7 @@ open_ct_reader (int port)
|
||||
return -1;
|
||||
}
|
||||
|
||||
reader_table[reader].is_ctapi = 1;
|
||||
dump_reader_status (reader);
|
||||
return reader;
|
||||
}
|
||||
@ -271,16 +338,205 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
}
|
||||
|
||||
|
||||
#endif /*HAVE_CTAPI*/
|
||||
|
||||
|
||||
#ifdef HAVE_PCSC
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
PC/SC Interface
|
||||
*/
|
||||
|
||||
static int
|
||||
open_pcsc_reader (const char *portstr)
|
||||
{
|
||||
long err;
|
||||
int slot;
|
||||
char *list = NULL;
|
||||
unsigned long nreader, listlen, atrlen;
|
||||
char *p;
|
||||
unsigned long card_state, card_protocol;
|
||||
|
||||
slot = new_reader_slot ();
|
||||
if (slot == -1)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listlen = nreader;
|
||||
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;
|
||||
}
|
||||
nreader -= strlen (p)+1;
|
||||
p += strlen (p) + 1;
|
||||
}
|
||||
|
||||
err = pcsc_connect (reader_table[slot].pcsc.context,
|
||||
portstr? portstr : list,
|
||||
PCSC_SHARE_EXCLUSIVE,
|
||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||
&reader_table[slot].pcsc.card,
|
||||
&reader_table[slot].pcsc.protocol);
|
||||
if (err)
|
||||
{
|
||||
log_error ("pcsc_connect 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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
atrlen = 32;
|
||||
/* (We need to pass a dummy buffer. We use LIST because it ought to
|
||||
be large enough.) */
|
||||
err = pcsc_status (reader_table[slot].pcsc.card,
|
||||
list, &listlen,
|
||||
&card_state, &card_protocol,
|
||||
reader_table[slot].atr, &atrlen);
|
||||
xfree (list);
|
||||
if (err)
|
||||
{
|
||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
return -1;
|
||||
}
|
||||
if (atrlen >= DIM (reader_table[0].atr))
|
||||
log_bug ("ATR returned by pcsc_status is too large\n");
|
||||
reader_table[slot].atrlen = atrlen;
|
||||
/* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */
|
||||
/* log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
|
||||
|
||||
dump_reader_status (slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
/* 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: CT API error code. */
|
||||
static int
|
||||
pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
unsigned char *buffer, size_t *buflen)
|
||||
{
|
||||
long err;
|
||||
struct pcsc_io_request_s send_pci;
|
||||
unsigned long recv_len;
|
||||
|
||||
if (DBG_CARD_IO)
|
||||
log_printhex (" CT_data:", apdu, apdulen);
|
||||
|
||||
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);
|
||||
|
||||
return err? -1:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /*HAVE_PCSC*/
|
||||
|
||||
|
||||
/*
|
||||
@ -288,35 +544,86 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
*/
|
||||
|
||||
/* Open the reader and return an internal slot number or -1 on
|
||||
error. */
|
||||
error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
|
||||
the first USB reader. For PCSC/ the first listed reader. */
|
||||
int
|
||||
apdu_open_reader (int port)
|
||||
apdu_open_reader (const char *portstr)
|
||||
{
|
||||
static int ct_api_loaded;
|
||||
static int pcsc_api_loaded, ct_api_loaded;
|
||||
|
||||
if (!ct_api_loaded)
|
||||
if (opt.ctapi_driver && *opt.ctapi_driver)
|
||||
{
|
||||
int port = portstr? atoi (portstr) : 32768;
|
||||
|
||||
if (!ct_api_loaded)
|
||||
{
|
||||
void *handle;
|
||||
|
||||
handle = dlopen (opt.ctapi_driver, RTLD_LAZY);
|
||||
if (!handle)
|
||||
{
|
||||
log_error ("apdu_open_reader: failed to open driver: %s",
|
||||
dlerror ());
|
||||
return -1;
|
||||
}
|
||||
CT_init = dlsym (handle, "CT_init");
|
||||
CT_data = dlsym (handle, "CT_data");
|
||||
CT_close = dlsym (handle, "CT_close");
|
||||
if (!CT_init || !CT_data || !CT_close)
|
||||
{
|
||||
log_error ("apdu_open_reader: invalid ctAPI driver\n");
|
||||
dlclose (handle);
|
||||
return -1;
|
||||
}
|
||||
ct_api_loaded = 1;
|
||||
}
|
||||
return open_ct_reader (port);
|
||||
}
|
||||
|
||||
|
||||
/* No ctAPI configured, so lets try the PC/SC API */
|
||||
if (!pcsc_api_loaded)
|
||||
{
|
||||
void *handle;
|
||||
|
||||
handle = dlopen ("libtowitoko.so", RTLD_LAZY);
|
||||
handle = dlopen ("libpcsclite.so", RTLD_LAZY);
|
||||
if (!handle)
|
||||
{
|
||||
log_error ("apdu_open_reader: failed to open driver: %s",
|
||||
dlerror ());
|
||||
return -1;
|
||||
}
|
||||
CT_init = dlsym (handle, "CT_init");
|
||||
CT_data = dlsym (handle, "CT_data");
|
||||
CT_close = dlsym (handle, "CT_close");
|
||||
if (!CT_init || !CT_data || !CT_close)
|
||||
|
||||
pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
|
||||
pcsc_release_context = dlsym (handle, "SCardReleaseContext");
|
||||
pcsc_list_readers = dlsym (handle, "SCardListReaders");
|
||||
pcsc_connect = dlsym (handle, "SCardConnect");
|
||||
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
|
||||
pcsc_status = dlsym (handle, "SCardStatus");
|
||||
pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
|
||||
pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
|
||||
pcsc_transmit = dlsym (handle, "SCardTransmit");
|
||||
pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
|
||||
|
||||
if (!pcsc_establish_context
|
||||
|| !pcsc_release_context
|
||||
|| !pcsc_list_readers
|
||||
|| !pcsc_connect
|
||||
|| !pcsc_disconnect
|
||||
|| !pcsc_status
|
||||
|| !pcsc_begin_transaction
|
||||
|| !pcsc_end_transaction
|
||||
|| !pcsc_transmit
|
||||
|| !pcsc_set_timeout)
|
||||
{
|
||||
log_error ("apdu_open_reader: invalid driver\n");
|
||||
log_error ("apdu_open_reader: invalid PC/SC driver\n");
|
||||
dlclose (handle);
|
||||
return -1;
|
||||
}
|
||||
ct_api_loaded = 1;
|
||||
pcsc_api_loaded = 1;
|
||||
}
|
||||
return open_ct_reader (port);
|
||||
|
||||
return open_pcsc_reader (portstr);
|
||||
}
|
||||
|
||||
|
||||
@ -338,15 +645,14 @@ apdu_get_atr (int slot, size_t *atrlen)
|
||||
|
||||
|
||||
static const char *
|
||||
error_string (int slot, int rc)
|
||||
error_string (int slot, long rc)
|
||||
{
|
||||
#ifdef HAVE_CTAPI
|
||||
return ct_error_string (rc);
|
||||
#elif defined(HAVE_PCSC)
|
||||
return "?";
|
||||
#else
|
||||
return "?";
|
||||
#endif
|
||||
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
||||
return "[invalid slot]";
|
||||
if (reader_table[slot].is_ctapi)
|
||||
return ct_error_string (rc);
|
||||
else
|
||||
return pcsc_error_string (rc);
|
||||
}
|
||||
|
||||
|
||||
@ -355,13 +661,12 @@ static int
|
||||
send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
unsigned char *buffer, size_t *buflen)
|
||||
{
|
||||
#ifdef HAVE_CTAPI
|
||||
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||
#elif defined(HAVE_PCSC)
|
||||
return SW_HOST_NO_DRIVER;
|
||||
#else
|
||||
return SW_HOST_NO_DRIVER;
|
||||
#endif
|
||||
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
||||
return SW_HOST_NO_DRIVER;
|
||||
if (reader_table[slot].is_ctapi)
|
||||
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||
else
|
||||
return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||
}
|
||||
|
||||
/* Send an APDU to the card in SLOT. The APDU is created from all
|
||||
@ -382,7 +687,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
size_t resultlen = 256;
|
||||
unsigned char apdu[5+256+1];
|
||||
size_t apdulen;
|
||||
int rc, sw;
|
||||
int sw;
|
||||
long rc; /* we need a long here due to PC/SC. */
|
||||
|
||||
if (DBG_CARD_IO)
|
||||
log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n",
|
||||
|
@ -47,12 +47,13 @@ enum {
|
||||
between errnos on a failed malloc. */
|
||||
SW_HOST_INV_VALUE = 0x10002,
|
||||
SW_HOST_INCOMPLETE_CARD_RESPONSE = 0x10003,
|
||||
SW_HOST_NO_DRIVER = 0x10004
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Note , that apdu_open_reader returns no status word but -1 on error. */
|
||||
int apdu_open_reader (int port);
|
||||
int apdu_open_reader (const char *portstr);
|
||||
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
|
||||
|
||||
|
||||
|
@ -69,6 +69,7 @@ struct app_ctx_s {
|
||||
};
|
||||
|
||||
/*-- app.c --*/
|
||||
void app_set_default_reader_port (const char *portstr);
|
||||
APP select_application (void);
|
||||
int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp);
|
||||
int app_write_learn_status (APP app, CTRL ctrl);
|
||||
|
@ -214,71 +214,6 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
static void
|
||||
dump_one_do (int slot, int tag)
|
||||
{
|
||||
int rc, i;
|
||||
unsigned char *buffer;
|
||||
size_t buflen;
|
||||
const char *desc;
|
||||
int binary;
|
||||
const unsigned char *value;
|
||||
size_t valuelen;
|
||||
|
||||
for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
|
||||
;
|
||||
desc = data_objects[i].tag? data_objects[i].desc : "?";
|
||||
binary = data_objects[i].tag? data_objects[i].binary : 1;
|
||||
|
||||
value = NULL;
|
||||
rc = -1;
|
||||
if (data_objects[i].tag && data_objects[i].get_from)
|
||||
{
|
||||
rc = iso7816_get_data (slot, data_objects[i].get_from,
|
||||
&buffer, &buflen);
|
||||
if (!rc)
|
||||
{
|
||||
value = find_tlv (buffer, buflen, tag, &valuelen, 0);
|
||||
if (!value)
|
||||
; /* not found */
|
||||
else if (valuelen > buflen - (value - buffer))
|
||||
{
|
||||
log_error ("warning: constructed DO too short\n");
|
||||
value = NULL;
|
||||
xfree (buffer); buffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!value) /* Not in a constructed DO, try simple. */
|
||||
{
|
||||
rc = iso7816_get_data (slot, tag, &buffer, &buflen);
|
||||
if (!rc)
|
||||
{
|
||||
value = buffer;
|
||||
valuelen = buflen;
|
||||
}
|
||||
}
|
||||
if (rc == 0x6a88)
|
||||
log_info ("DO `%s' not available\n", desc);
|
||||
else if (rc)
|
||||
log_info ("DO `%s' not available (rc=%04X)\n", desc, rc);
|
||||
else
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
log_info ("DO `%s': ", desc);
|
||||
log_printhex ("", value, valuelen);
|
||||
}
|
||||
else
|
||||
log_info ("DO `%s': `%.*s'\n",
|
||||
desc, (int)valuelen, value); /* FIXME: sanitize */
|
||||
xfree (buffer);
|
||||
}
|
||||
}
|
||||
#endif /*not used*/
|
||||
|
||||
|
||||
static void
|
||||
dump_all_do (int slot)
|
||||
@ -293,11 +228,11 @@ dump_all_do (int slot)
|
||||
continue;
|
||||
|
||||
rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen);
|
||||
if (rc == 0x6a88)
|
||||
if (gpg_error (rc) == GPG_ERR_NO_OBJ)
|
||||
;
|
||||
else if (rc)
|
||||
log_info ("DO `%s' not available (rc=%04X)\n",
|
||||
data_objects[i].desc, rc);
|
||||
log_info ("DO `%s' not available: %s\n",
|
||||
data_objects[i].desc, gpg_strerror (rc));
|
||||
else
|
||||
{
|
||||
if (data_objects[i].binary)
|
||||
@ -309,34 +244,34 @@ dump_all_do (int slot)
|
||||
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++)
|
||||
if (data_objects[i].constructed)
|
||||
{
|
||||
const unsigned char *value;
|
||||
size_t valuelen;
|
||||
|
||||
if (j==i || data_objects[i].tag != data_objects[j].get_from)
|
||||
continue;
|
||||
value = find_tlv (buffer, buflen,
|
||||
data_objects[j].tag, &valuelen, 0);
|
||||
if (!value)
|
||||
; /* not found */
|
||||
else if (valuelen > buflen - (value - buffer))
|
||||
log_error ("warning: constructed DO too short\n");
|
||||
else
|
||||
for (j=0; data_objects[j].tag; j++)
|
||||
{
|
||||
if (data_objects[j].binary)
|
||||
{
|
||||
log_info ("DO `%s': ", data_objects[j].desc);
|
||||
log_printhex ("", value, valuelen);
|
||||
}
|
||||
const unsigned char *value;
|
||||
size_t valuelen;
|
||||
|
||||
if (j==i || data_objects[i].tag != data_objects[j].get_from)
|
||||
continue;
|
||||
value = find_tlv (buffer, buflen,
|
||||
data_objects[j].tag, &valuelen, 0);
|
||||
if (!value)
|
||||
; /* not found */
|
||||
else if (valuelen > buflen - (value - buffer))
|
||||
log_error ("warning: constructed DO too short\n");
|
||||
else
|
||||
log_info ("DO `%s': `%.*s'\n",
|
||||
data_objects[j].desc,
|
||||
(int)valuelen, value); /* FIXME: sanitize */
|
||||
{
|
||||
if (data_objects[j].binary)
|
||||
{
|
||||
log_info ("DO `%s': ", data_objects[j].desc);
|
||||
log_printhex ("", value, valuelen);
|
||||
}
|
||||
else
|
||||
log_info ("DO `%s': `%.*s'\n",
|
||||
data_objects[j].desc,
|
||||
(int)valuelen, value); /* FIXME: sanitize */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,7 +345,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
|
||||
rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6)
|
||||
+ keynumber, fpr, 20);
|
||||
if (rc)
|
||||
log_error ("failed to store the fingerprint: rc=%04X\n", rc);
|
||||
log_error ("failed to store the fingerprint: %s\n",gpg_strerror (rc));
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -582,7 +517,7 @@ do_setattr (APP app, const char *name,
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV3 failed\n");
|
||||
log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc));
|
||||
rc = gpg_error (GPG_ERR_GENERAL);
|
||||
return rc;
|
||||
}
|
||||
@ -626,7 +561,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV3 failed: rc=%04X\n", rc);
|
||||
log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
@ -642,7 +577,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV1 failed: rc=%04X\n", rc);
|
||||
log_error ("verify CHV1 failed: rc=%s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
@ -658,7 +593,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV2 failed: rc=%04X\n", rc);
|
||||
log_error ("verify CHV2 failed: rc=%s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
@ -757,7 +692,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV3 failed: rc=%04X\n", rc);
|
||||
log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -1224,8 +1159,6 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
|
||||
rc = iso7816_select_application (slot, aid, sizeof aid);
|
||||
if (!rc)
|
||||
{
|
||||
/* fixme: get the full AID and check that the version is okay
|
||||
with us. */
|
||||
rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
|
||||
if (rc)
|
||||
goto leave;
|
||||
@ -1386,7 +1319,7 @@ app_openpgp_storekey (APP app, int keyno,
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("verify CHV3 failed: rc=%04X\n", rc);
|
||||
log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -1395,7 +1328,7 @@ app_openpgp_storekey (APP app, int keyno,
|
||||
template, template_len);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to store the key: rc=%04X\n", rc);
|
||||
log_error ("failed to store the key: rc=%s\n", gpg_strerror (rc));
|
||||
rc = gpg_error (GPG_ERR_CARD);
|
||||
goto leave;
|
||||
}
|
||||
|
13
scd/app.c
13
scd/app.c
@ -30,17 +30,26 @@
|
||||
#include "apdu.h"
|
||||
#include "iso7816.h"
|
||||
|
||||
static char *default_reader_port;
|
||||
|
||||
void
|
||||
app_set_default_reader_port (const char *portstr)
|
||||
{
|
||||
xfree (default_reader_port);
|
||||
default_reader_port = portstr? xstrdup (portstr): NULL;
|
||||
}
|
||||
|
||||
|
||||
/* The select the best fitting application and return a context.
|
||||
Returns NULL if no application was found or no card is present. */
|
||||
APP
|
||||
select_application (void)
|
||||
{
|
||||
int reader_port = 32768; /* First USB reader. */
|
||||
int slot;
|
||||
int rc;
|
||||
APP app;
|
||||
|
||||
slot = apdu_open_reader (reader_port);
|
||||
slot = apdu_open_reader (default_reader_port);
|
||||
if (slot == -1)
|
||||
{
|
||||
log_error ("card reader not available\n");
|
||||
|
@ -44,6 +44,7 @@
|
||||
enum cmd_and_opt_values
|
||||
{ oVerbose = 'v',
|
||||
oReaderPort = 500,
|
||||
octapiDriver,
|
||||
oDebug,
|
||||
oDebugAll,
|
||||
|
||||
@ -55,7 +56,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ 301, NULL, 0, "@Options:\n " },
|
||||
|
||||
{ oVerbose, "verbose", 0, "verbose" },
|
||||
{ oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
|
||||
{ oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
|
||||
{ octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
|
||||
{ oDebug, "debug" ,4|16, "set debugging flags"},
|
||||
{ oDebugAll, "debug-all" ,0, "enable full debugging"},
|
||||
{0}
|
||||
@ -115,7 +117,7 @@ main (int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
int slot, rc;
|
||||
int reader_port = 32768; /* First USB reader. */
|
||||
const char *reader_port = NULL;
|
||||
struct app_ctx_s appbuf;
|
||||
|
||||
memset (&appbuf, 0, sizeof appbuf);
|
||||
@ -146,6 +148,8 @@ main (int argc, char **argv )
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: opt.debug = ~0; break;
|
||||
case oReaderPort: reader_port = pargs.r.ret_str; break;
|
||||
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
enum cmd_and_opt_values
|
||||
{ oVerbose = 'v',
|
||||
oReaderPort = 500,
|
||||
octapiDriver,
|
||||
oDebug,
|
||||
oDebugAll,
|
||||
|
||||
@ -52,7 +53,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ 301, NULL, 0, "@Options:\n " },
|
||||
|
||||
{ oVerbose, "verbose", 0, "verbose" },
|
||||
{ oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
|
||||
{ oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
|
||||
{ octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
|
||||
{ oDebug, "debug" ,4|16, "set debugging flags"},
|
||||
{ oDebugAll, "debug-all" ,0, "enable full debugging"},
|
||||
{ oGenRandom, "gen-random", 4, "|N|generate N bytes of random"},
|
||||
@ -108,7 +110,7 @@ main (int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
int slot, rc;
|
||||
int reader_port = 32768; /* First USB reader. */
|
||||
const char *reader_port = NULL;
|
||||
struct app_ctx_s appbuf;
|
||||
unsigned long gen_random = 0;
|
||||
|
||||
@ -139,6 +141,8 @@ main (int argc, char **argv )
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: opt.debug = ~0; break;
|
||||
case oReaderPort: reader_port = pargs.r.ret_str; break;
|
||||
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
|
||||
case oGenRandom: gen_random = pargs.r.ret_ulong; break;
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
#include "i18n.h"
|
||||
#include "sysutils.h"
|
||||
|
||||
#include "app-common.h"
|
||||
|
||||
|
||||
enum cmd_and_opt_values
|
||||
@ -69,6 +69,7 @@ enum cmd_and_opt_values
|
||||
oDaemon,
|
||||
oBatch,
|
||||
oReaderPort,
|
||||
octapiDriver,
|
||||
|
||||
aTest };
|
||||
|
||||
@ -91,8 +92,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
{ oDebugSC, "debug-sc", 1, N_("|N|set OpenSC debug level to N")},
|
||||
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
|
||||
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
|
||||
{ oReaderPort, "reader-port", 1, N_("|N|connect to reader at port N")},
|
||||
|
||||
{ oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
|
||||
{ octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")},
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -230,7 +231,6 @@ main (int argc, char **argv )
|
||||
int csh_style = 0;
|
||||
char *logfile = NULL;
|
||||
int debug_wait = 0;
|
||||
int reader_port = 32768; /* First USB reader. */
|
||||
|
||||
set_strusage (my_strusage);
|
||||
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
|
||||
@ -299,6 +299,7 @@ main (int argc, char **argv )
|
||||
|
||||
if (default_config)
|
||||
configname = make_filename (opt.homedir, "scdaemon.conf", NULL );
|
||||
|
||||
|
||||
argc = orig_argc;
|
||||
argv = orig_argv;
|
||||
@ -365,7 +366,8 @@ main (int argc, char **argv )
|
||||
case oServer: pipe_server = 1; break;
|
||||
case oDaemon: is_daemon = 1; break;
|
||||
|
||||
case oReaderPort: reader_port = pargs.r.ret_int; break;
|
||||
case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
|
||||
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
|
||||
|
||||
default : pargs.err = configfp? 1:2; break;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ struct {
|
||||
int dry_run; /* don't change any persistent data */
|
||||
int batch; /* batch mode */
|
||||
const char *homedir; /* configuration directory name */
|
||||
const char *ctapi_driver; /* Library to access the ctAPI. */
|
||||
} opt;
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user