Cleanups, fixes and PC/SC support

This commit is contained in:
Werner Koch 2003-08-05 17:11:04 +00:00
parent 9ca4830a5b
commit 1bcf8ef9de
24 changed files with 601 additions and 520 deletions

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.

View 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
View File

@ -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 )

View File

@ -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;
}

View File

@ -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*/

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 );

View File

@ -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.

View File

@ -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",

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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");

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;