diff --git a/ChangeLog b/ChangeLog index b846f27a7..83e9cba0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-08-05 Werner Koch + + * configure.ac (GNUPG_DEFAULT_HONMEDIR): Changed back to ~/.gnupg. + 2003-07-31 Werner Koch * Makefile.am (DISTCLEANFILES): Add g10defs.h diff --git a/NEWS b/NEWS index 794ad11f1..9e6b9f1af 100644 --- a/NEWS +++ b/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. diff --git a/README b/README index 7aea069b3..8dea9dbb9 100644 --- a/README +++ b/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 + + 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 + + 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. ++++++++++ diff --git a/TODO b/TODO index 431f2a2ea..c9b2d18ff 100644 --- a/TODO +++ b/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. diff --git a/configure.ac b/configure.ac index 9d8aef9ee..060f31d97 100644 --- a/configure.ac +++ b/configure.ac @@ -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 < + + * 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 * g10.c (main): Add secmem features and set the random seed file. diff --git a/g10/Makefile.am b/g10/Makefile.am index d6984941e..59213d04b 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -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 + diff --git a/g10/g10.c b/g10/g10.c index f89556184..aef76992b 100644 --- a/g10/g10.c +++ b/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 ) diff --git a/g10/pkglue.c b/g10/pkglue.c index 7920a5223..015aaf9ff 100644 --- a/g10/pkglue.c +++ b/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; +} diff --git a/g10/pkglue.h b/g10/pkglue.h index 3065d66aa..43b82785b 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -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*/ diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 5a7db4c97..5b0238240 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -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; } diff --git a/g10/status.c b/g10/status.c index 432ec575c..4414b33e9 100644 --- a/g10/status.c +++ b/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 #include #include -#ifdef USE_SHM_COPROCESSING -#ifdef USE_CAPABILITIES -#include -#endif -#ifdef HAVE_SYS_IPC_H -#include -#include -#endif -#ifdef HAVE_SYS_SHM_H -#include -#endif -#if defined(HAVE_MLOCK) -#include -#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 */ diff --git a/g10/status.h b/g10/status.h index 44a7d6d32..4a0bcd45b 100644 --- a/g10/status.h +++ b/g10/status.h @@ -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 ); diff --git a/scd/ChangeLog b/scd/ChangeLog index ad4b0518c..ae2e6ce6e 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,25 @@ +2003-08-05 Werner Koch + + * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after + an error. + +2003-08-04 Werner Koch + + * 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 * Makefile.am (scdaemon_LDADD): Added INTLLIBS. diff --git a/scd/apdu.c b/scd/apdu.c index 6fec584b9..60de5b953 100644 --- a/scd/apdu.c +++ b/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", diff --git a/scd/apdu.h b/scd/apdu.h index 44166a3fe..6e4244ba0 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -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); diff --git a/scd/app-common.h b/scd/app-common.h index 282f82715..1243ca3ec 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -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); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 09a19699d..7f6114292 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -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; } diff --git a/scd/app.c b/scd/app.c index 7a85df336..04b421b55 100644 --- a/scd/app.c +++ b/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"); diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 9caf39a8a..b56b88590 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -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; } } diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index e8f0eb83c..ecd385690 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -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; } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 8e0ef37c9..11952615d 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -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; } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index b21e19f8c..bdc4c21b3 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -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;