mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
* Makefile.am: Add OPENSC_LIBS to all programs.
* scdaemon.c, scdaemon.h: New option --disable-opensc. * card.c (card_open): Implement it. * apdu.c (open_osc_reader, osc_send_apdu): New. (apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not disabled. (error_string) [HAVE_OPENSC]: Use sc_strerror. (send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.
This commit is contained in:
parent
6bdd855d11
commit
0506e4ebec
@ -1,3 +1,9 @@
|
|||||||
|
2003-08-06 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* configure.ac: Check for libgpg-error. Print infos about missing
|
||||||
|
libraries more nicely.
|
||||||
|
* acinclude.m4 (AM_PATH_GPG_ERROR): Added.
|
||||||
|
|
||||||
2003-08-05 Werner Koch <wk@gnupg.org>
|
2003-08-05 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
Released 1.9.0.
|
Released 1.9.0.
|
||||||
|
4
NEWS
4
NEWS
@ -1,6 +1,10 @@
|
|||||||
Noteworthy changes in version 1.9.1 (unreleased)
|
Noteworthy changes in version 1.9.1 (unreleased)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
* Support for OpenSC is back. scdaemon support a --disable-opensc to
|
||||||
|
disable OpenSC use at runtime, so that PC/SC or ct-API can still be
|
||||||
|
used directly.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 1.9.0 (2003-08-05)
|
Noteworthy changes in version 1.9.0 (2003-08-05)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
56
acinclude.m4
56
acinclude.m4
@ -636,3 +636,59 @@ AC_DEFUN(AM_PATH_OPENSC,
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl AM_PATH_GPG_ERROR([MINIMUM-VERSION,
|
||||||
|
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
|
||||||
|
dnl Test for libgpg-error and define GPG_ERROR_CFLAGS and GPG_ERROR_LIBS
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(AM_PATH_GPG_ERROR,
|
||||||
|
[ AC_ARG_WITH(gpg-error-prefix,
|
||||||
|
AC_HELP_STRING([--with-gpg-error-prefix=PFX],
|
||||||
|
[prefix where GPG Error is installed (optional)]),
|
||||||
|
gpg_error_config_prefix="$withval", gpg_error_config_prefix="")
|
||||||
|
if test x$gpg_error_config_prefix != x ; then
|
||||||
|
gpg_error_config_args="$gpg_error_config_args --prefix=$gpg_error_config_prefix"
|
||||||
|
if test x${GPG_ERROR_CONFIG+set} != xset ; then
|
||||||
|
GPG_ERROR_CONFIG=$gpg_error_config_prefix/bin/gpg-error-config
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_PATH_PROG(GPG_ERROR_CONFIG, gpg-error-config, no)
|
||||||
|
min_gpg_error_version=ifelse([$1], ,0.0,$1)
|
||||||
|
AC_MSG_CHECKING(for GPG Error - version >= $min_gpg_error_version)
|
||||||
|
ok=no
|
||||||
|
if test "$GPG_ERROR_CONFIG" != "no" ; then
|
||||||
|
req_major=`echo $min_gpg_error_version | \
|
||||||
|
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
|
||||||
|
req_minor=`echo $min_gpg_error_version | \
|
||||||
|
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
|
||||||
|
gpg_error_config_version=`$GPG_ERROR_CONFIG $gpg_error_config_args --version`
|
||||||
|
major=`echo $gpg_error_config_version | \
|
||||||
|
sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
|
||||||
|
minor=`echo $gpg_error_config_version | \
|
||||||
|
sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
|
||||||
|
if test "$major" -gt "$req_major"; then
|
||||||
|
ok=yes
|
||||||
|
else
|
||||||
|
if test "$major" -eq "$req_major"; then
|
||||||
|
if test "$minor" -ge "$req_minor"; then
|
||||||
|
ok=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test $ok = yes; then
|
||||||
|
GPG_ERROR_CFLAGS=`$GPG_ERROR_CONFIG $gpg_error_config_args --cflags`
|
||||||
|
GPG_ERROR_LIBS=`$GPG_ERROR_CONFIG $gpg_error_config_args --libs`
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
ifelse([$2], , :, [$2])
|
||||||
|
else
|
||||||
|
GPG_ERROR_CFLAGS=""
|
||||||
|
GPG_ERROR_LIBS=""
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
ifelse([$3], , :, [$3])
|
||||||
|
fi
|
||||||
|
AC_SUBST(GPG_ERROR_CFLAGS)
|
||||||
|
AC_SUBST(GPG_ERROR_LIBS)
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
114
configure.ac
114
configure.ac
@ -27,8 +27,9 @@ AC_INIT(gnupg, 1.9.1-cvs, gnupg-devel@gnupg.org)
|
|||||||
# feel that the default check for a development version is not
|
# feel that the default check for a development version is not
|
||||||
# sufficient.
|
# sufficient.
|
||||||
development_version=yes
|
development_version=yes
|
||||||
|
NEED_GPG_ERROR_VERSION=0.2
|
||||||
NEED_LIBGCRYPT_VERSION=1.1.42
|
NEED_LIBGCRYPT_VERSION=1.1.42
|
||||||
NEED_LIBASSUAN_VERSION=0.0.1
|
NEED_LIBASSUAN_VERSION=0.6.0
|
||||||
NEED_KSBA_VERSION=0.4.6
|
NEED_KSBA_VERSION=0.4.6
|
||||||
NEED_OPENSC_VERSION=0.7.0
|
NEED_OPENSC_VERSION=0.7.0
|
||||||
|
|
||||||
@ -47,7 +48,9 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
|
|||||||
AC_GNU_SOURCE
|
AC_GNU_SOURCE
|
||||||
|
|
||||||
# Some status variables to give feedback at the end of a configure run
|
# Some status variables to give feedback at the end of a configure run
|
||||||
habe_libassuan=no
|
have_gpg_error=no
|
||||||
|
have_libgcrypt=no
|
||||||
|
have_libassuan=no
|
||||||
have_ksba=no
|
have_ksba=no
|
||||||
have_opensc=no
|
have_opensc=no
|
||||||
have_pth=no
|
have_pth=no
|
||||||
@ -346,59 +349,32 @@ AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes)
|
|||||||
# Checks for libraries.
|
# Checks for libraries.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# libgpg-error is a library with error codes shared between GnuPG
|
||||||
|
# related projects.
|
||||||
|
#
|
||||||
|
AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION"
|
||||||
|
have_gpg_error=yes,have_gpg_error=no)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Libgcrypt is our generic crypto library
|
# Libgcrypt is our generic crypto library
|
||||||
#
|
#
|
||||||
#AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config)
|
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_VERSION",
|
||||||
#if test -n "$LIBGCRYPT_CONFIG"; then
|
have_libgcrypt=yes,have_libgcrypt=no)
|
||||||
# LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags`
|
|
||||||
# LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs`
|
|
||||||
#else
|
|
||||||
# AC_MSG_ERROR([[
|
|
||||||
#***
|
|
||||||
#*** You need libgcrypt to build this program.
|
|
||||||
#*** It should be available at the same place you
|
|
||||||
#*** got this software.
|
|
||||||
#***]])
|
|
||||||
#fi
|
|
||||||
#AC_SUBST(LIBGCRYPT_CFLAGS)
|
|
||||||
#AC_SUBST(LIBGCRYPT_LIBS)
|
|
||||||
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_VERSION",,
|
|
||||||
AC_MSG_ERROR([[
|
|
||||||
***
|
|
||||||
*** libgcrypt was not found. You may want to get it from
|
|
||||||
*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgcrypt/
|
|
||||||
***
|
|
||||||
]]))
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# libassuan is used for IPC
|
# libassuan is used for IPC
|
||||||
#
|
#
|
||||||
AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_VERSION",
|
AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_VERSION",
|
||||||
have_libasssuan=yes,have_libasssun=no)
|
have_libassuan=yes,have_libassuan=no)
|
||||||
if test "$have_libassuan" = "no"; then
|
|
||||||
AC_MSG_ERROR([[
|
|
||||||
***
|
|
||||||
*** You need libassuan to build this program..
|
|
||||||
*** It should be available at the same place you
|
|
||||||
*** got this software.
|
|
||||||
***]])
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# libksba is our X.509 support library
|
# libksba is our X.509 support library
|
||||||
#
|
#
|
||||||
AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
|
AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
|
||||||
if test "$have_ksba" = "no"; then
|
|
||||||
AC_MSG_ERROR([[
|
|
||||||
***
|
|
||||||
*** You need libksba to build this program..
|
|
||||||
*** It should be available at the same place you
|
|
||||||
*** got this software.
|
|
||||||
***]])
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -910,6 +886,64 @@ AC_SUBST(NETLIBS)
|
|||||||
AC_DEFINE(HAVE_JNLIB_LOGGING, 1,
|
AC_DEFINE(HAVE_JNLIB_LOGGING, 1,
|
||||||
[Defined if jnlib style logging fucntions are available])
|
[Defined if jnlib style logging fucntions are available])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Print errors here so that they are visible all
|
||||||
|
# together and the user can acquire them all together.
|
||||||
|
#
|
||||||
|
die=no
|
||||||
|
if test "$have_gpg_error" = "no"; then
|
||||||
|
die=yes
|
||||||
|
AC_MSG_NOTICE([[
|
||||||
|
***
|
||||||
|
*** You need libgpg-error to build this program.
|
||||||
|
** This library is for example available at
|
||||||
|
*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgpg-error
|
||||||
|
*** (at least version $NEED_GPG_ERROR_VERSION is required.)
|
||||||
|
***]])
|
||||||
|
fi
|
||||||
|
if test "$have_libgcrypt" = "no"; then
|
||||||
|
die=yes
|
||||||
|
AC_MSG_NOTICE([[
|
||||||
|
***
|
||||||
|
*** You need libgcrypt to build this program.
|
||||||
|
** This library is for example available at
|
||||||
|
*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/libgcrypt/
|
||||||
|
*** (at least version $NEED_LIBGCRYPT_VERSION is required.)
|
||||||
|
***]])
|
||||||
|
fi
|
||||||
|
if test "$have_libassuan" = "no"; then
|
||||||
|
die=yes
|
||||||
|
AC_MSG_NOTICE([[
|
||||||
|
***
|
||||||
|
*** You need libassuan to build this program.
|
||||||
|
*** This library is for example available at
|
||||||
|
*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/libassuan/
|
||||||
|
*** (at least version $NEED_LIBASSUAN_VERSION is required).
|
||||||
|
***]])
|
||||||
|
fi
|
||||||
|
if test "$have_ksba" = "no"; then
|
||||||
|
die=yes
|
||||||
|
AC_MSG_NOTICE([[
|
||||||
|
***
|
||||||
|
*** You need libksba to build this program.
|
||||||
|
*** This library is for example available at
|
||||||
|
*** ftp://ftp.gnupg.org/pub/gcrypt/alpha/aegypten/
|
||||||
|
*** (at least version $NEED_KSBA_VERSION is required).
|
||||||
|
***]])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$die" = "yes"; then
|
||||||
|
AC_MSG_ERROR([[
|
||||||
|
***
|
||||||
|
*** Required libraries not found. Please consult the above messages
|
||||||
|
*** and install them before running configure again.
|
||||||
|
***]])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Decide what to build
|
# Decide what to build
|
||||||
#
|
#
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
|
2003-08-18 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
|
* Makefile.am: Add OPENSC_LIBS to all programs.
|
||||||
|
|
||||||
|
* scdaemon.c, scdaemon.h: New option --disable-opensc.
|
||||||
|
* card.c (card_open): Implement it.
|
||||||
|
* apdu.c (open_osc_reader, osc_send_apdu): New.
|
||||||
|
(apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not
|
||||||
|
disabled.
|
||||||
|
(error_string) [HAVE_OPENSC]: Use sc_strerror.
|
||||||
|
(send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.
|
||||||
|
|
||||||
|
* card-p15.c (p15_enum_keypairs, p15_prepare_key): Adjusted for
|
||||||
|
libgpg-error.
|
||||||
|
|
||||||
2003-08-14 Timo Schulz <twoaday@freakmail.de>
|
2003-08-14 Timo Schulz <twoaday@freakmail.de>
|
||||||
|
|
||||||
* apdu.c (ct_activate_card): Change the code a little to avoid
|
* apdu.c (ct_activate_card): Change the code a little to avoid
|
||||||
problems with other readers.
|
problems with other readers.
|
||||||
* Always use 'dynload.h' instead of 'dlfcn.h'.
|
* Always use 'dynload.h' instead of 'dlfcn.h'.
|
||||||
|
|
||||||
2003-08-05 Werner Koch <wk@gnupg.org>
|
2003-08-05 Werner Koch <wk@gnupg.org>
|
||||||
|
|
||||||
* app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
|
* app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
|
||||||
|
@ -50,7 +50,7 @@ sc_investigate_SOURCES = \
|
|||||||
|
|
||||||
sc_investigate_LDADD = \
|
sc_investigate_LDADD = \
|
||||||
../jnlib/libjnlib.a ../common/libcommon.a \
|
../jnlib/libjnlib.a ../common/libcommon.a \
|
||||||
$(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl
|
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl
|
||||||
|
|
||||||
|
|
||||||
sc_copykeys_SOURCES = \
|
sc_copykeys_SOURCES = \
|
||||||
@ -64,7 +64,7 @@ sc_copykeys_SOURCES = \
|
|||||||
sc_copykeys_LDADD = \
|
sc_copykeys_LDADD = \
|
||||||
../jnlib/libjnlib.a ../common/libcommon.a \
|
../jnlib/libjnlib.a ../common/libcommon.a \
|
||||||
../common/libsimple-pwquery.a \
|
../common/libsimple-pwquery.a \
|
||||||
$(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl
|
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
237
scd/apdu.c
237
scd/apdu.c
@ -24,6 +24,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
# include <opensc/opensc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "scdaemon.h"
|
#include "scdaemon.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
@ -34,9 +37,9 @@
|
|||||||
insertion of the card (1 = don't wait). */
|
insertion of the card (1 = don't wait). */
|
||||||
|
|
||||||
|
|
||||||
|
/* A structure to collect information pertaining to one reader
|
||||||
/* A global table to keep track of active readers. */
|
slot. */
|
||||||
static struct {
|
struct reader_table_s {
|
||||||
int used; /* True if slot is used. */
|
int used; /* True if slot is used. */
|
||||||
unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */
|
unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */
|
||||||
int is_ctapi; /* This is a ctAPI driver. */
|
int is_ctapi; /* This is a ctAPI driver. */
|
||||||
@ -45,10 +48,21 @@ static struct {
|
|||||||
unsigned long card;
|
unsigned long card;
|
||||||
unsigned long protocol;
|
unsigned long protocol;
|
||||||
} pcsc;
|
} pcsc;
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
int is_osc; /* We are using the OpenSC driver layer. */
|
||||||
|
struct {
|
||||||
|
struct sc_context *ctx;
|
||||||
|
struct sc_card *scard;
|
||||||
|
} osc;
|
||||||
|
#endif /*HAVE_OPENSC*/
|
||||||
int status;
|
int status;
|
||||||
unsigned char atr[33];
|
unsigned char atr[33];
|
||||||
size_t atrlen;
|
size_t atrlen;
|
||||||
} reader_table[MAX_READER];
|
};
|
||||||
|
typedef struct reader_table_s *reader_table_t;
|
||||||
|
|
||||||
|
/* A global table to keep track of active readers. */
|
||||||
|
static struct reader_table_s reader_table[MAX_READER];
|
||||||
|
|
||||||
|
|
||||||
/* ct API function pointer. */
|
/* ct API function pointer. */
|
||||||
@ -142,6 +156,7 @@ new_reader_slot (void)
|
|||||||
}
|
}
|
||||||
reader_table[reader].used = 1;
|
reader_table[reader].used = 1;
|
||||||
reader_table[reader].is_ctapi = 0;
|
reader_table[reader].is_ctapi = 0;
|
||||||
|
reader_table[reader].is_osc = 0;
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +528,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
unsigned long recv_len;
|
unsigned long recv_len;
|
||||||
|
|
||||||
if (DBG_CARD_IO)
|
if (DBG_CARD_IO)
|
||||||
log_printhex (" CT_data:", apdu, apdulen);
|
log_printhex (" PCSC_data:", apdu, apdulen);
|
||||||
|
|
||||||
if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
|
if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
|
||||||
send_pci.protocol = PCSC_PROTOCOL_T1;
|
send_pci.protocol = PCSC_PROTOCOL_T1;
|
||||||
@ -529,10 +544,199 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
log_error ("pcsc_transmit failed: %s (0x%lx)\n",
|
log_error ("pcsc_transmit failed: %s (0x%lx)\n",
|
||||||
pcsc_error_string (err), err);
|
pcsc_error_string (err), err);
|
||||||
|
|
||||||
return err? -1:0;
|
return err? -1:0; /* FIXME: Return appropriate error code. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
/*
|
||||||
|
OpenSC Interface.
|
||||||
|
|
||||||
|
This uses the OpenSC primitives to send APDUs. We need this
|
||||||
|
because we can't mix OpenSC and native (i.e. ctAPI or PC/SC)
|
||||||
|
access to a card for resource conflict reasons.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
open_osc_reader (int portno)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int slot;
|
||||||
|
reader_table_t slotp;
|
||||||
|
|
||||||
|
slot = new_reader_slot ();
|
||||||
|
if (slot == -1)
|
||||||
|
return -1;
|
||||||
|
slotp = reader_table + slot;
|
||||||
|
|
||||||
|
err = sc_establish_context (&slotp->osc.ctx, "scdaemon");
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to establish SC context: %s\n", sc_strerror (err));
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (portno < 0 || portno >= slotp->osc.ctx->reader_count)
|
||||||
|
{
|
||||||
|
log_error ("no card reader available\n");
|
||||||
|
sc_release_context (slotp->osc.ctx);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Redirect to our logging facility. */
|
||||||
|
slotp->osc.ctx->error_file = log_get_stream ();
|
||||||
|
slotp->osc.ctx->debug = opt.debug_sc;
|
||||||
|
slotp->osc.ctx->debug_file = log_get_stream ();
|
||||||
|
|
||||||
|
if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1)
|
||||||
|
{
|
||||||
|
log_error ("no card present\n");
|
||||||
|
sc_release_context (slotp->osc.ctx);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We want the standard ISO driver. */
|
||||||
|
/*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */
|
||||||
|
err = sc_set_card_driver(slotp->osc.ctx, "emv");
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to select the iso7816 driver: %s\n",
|
||||||
|
sc_strerror (err));
|
||||||
|
sc_release_context (slotp->osc.ctx);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now connect the card and hope that OpenSC won't try to be too
|
||||||
|
smart. */
|
||||||
|
err = sc_connect_card (slotp->osc.ctx->reader[portno], 0,
|
||||||
|
&slotp->osc.scard);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to connect card in reader %d: %s\n",
|
||||||
|
portno, sc_strerror (err));
|
||||||
|
sc_release_context (slotp->osc.ctx);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("connected to card in opensc reader %d using driver `%s'\n",
|
||||||
|
portno, slotp->osc.scard->driver->name);
|
||||||
|
|
||||||
|
err = sc_lock (slotp->osc.scard);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("can't lock card in reader %d: %s\n",
|
||||||
|
portno, sc_strerror (err));
|
||||||
|
sc_disconnect_card (slotp->osc.scard, 0);
|
||||||
|
sc_release_context (slotp->osc.ctx);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slotp->osc.scard->atr_len >= DIM (slotp->atr))
|
||||||
|
log_bug ("ATR returned by opensc is too large\n");
|
||||||
|
slotp->atrlen = slotp->osc.scard->atr_len;
|
||||||
|
memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen);
|
||||||
|
|
||||||
|
slotp->is_osc = 1;
|
||||||
|
|
||||||
|
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: OpenSC error code. */
|
||||||
|
static int
|
||||||
|
osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||||
|
unsigned char *buffer, size_t *buflen)
|
||||||
|
{
|
||||||
|
long err;
|
||||||
|
struct sc_apdu a;
|
||||||
|
unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
|
unsigned char result[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
|
|
||||||
|
if (DBG_CARD_IO)
|
||||||
|
log_printhex (" APDU_data:", apdu, apdulen);
|
||||||
|
|
||||||
|
if (apdulen < 4)
|
||||||
|
{
|
||||||
|
log_error ("osc_send_apdu: APDU is too short\n");
|
||||||
|
return SC_ERROR_CMD_TOO_SHORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&a, 0, sizeof a);
|
||||||
|
a.cla = *apdu++;
|
||||||
|
a.ins = *apdu++;
|
||||||
|
a.p1 = *apdu++;
|
||||||
|
a.p2 = *apdu++;
|
||||||
|
apdulen -= 4;
|
||||||
|
|
||||||
|
if (!apdulen)
|
||||||
|
a.cse = SC_APDU_CASE_1;
|
||||||
|
else if (apdulen == 1)
|
||||||
|
{
|
||||||
|
a.le = *apdu? *apdu : 256;
|
||||||
|
apdu++; apdulen--;
|
||||||
|
a.cse = SC_APDU_CASE_2_SHORT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a.lc = *apdu++; apdulen--;
|
||||||
|
if (apdulen < a.lc)
|
||||||
|
{
|
||||||
|
log_error ("osc_send_apdu: APDU shorter than specified in Lc\n");
|
||||||
|
return SC_ERROR_CMD_TOO_SHORT;
|
||||||
|
|
||||||
|
}
|
||||||
|
memcpy(data, apdu, a.lc);
|
||||||
|
apdu += a.lc; apdulen -= a.lc;
|
||||||
|
|
||||||
|
a.data = data;
|
||||||
|
a.datalen = a.lc;
|
||||||
|
|
||||||
|
if (!apdulen)
|
||||||
|
a.cse = SC_APDU_CASE_3_SHORT;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a.le = *apdu? *apdu : 256;
|
||||||
|
apdu++; apdulen--;
|
||||||
|
if (apdulen)
|
||||||
|
{
|
||||||
|
log_error ("osc_send_apdu: APDU larger than specified\n");
|
||||||
|
return SC_ERROR_CMD_TOO_LONG;
|
||||||
|
}
|
||||||
|
a.cse = SC_APDU_CASE_4_SHORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.resp = result;
|
||||||
|
a.resplen = DIM(result);
|
||||||
|
|
||||||
|
err = sc_transmit_apdu (reader_table[slot].osc.scard, &a);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*buflen < 2 || a.resplen > *buflen - 2)
|
||||||
|
{
|
||||||
|
log_error ("osc_send_apdu: provided buffer too short to store result\n");
|
||||||
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
memcpy (buffer, a.resp, a.resplen);
|
||||||
|
buffer[a.resplen] = a.sw1;
|
||||||
|
buffer[a.resplen+1] = a.sw2;
|
||||||
|
*buflen = a.resplen + 2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_OPENSC */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -542,12 +746,23 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
|
|
||||||
/* Open the reader and return an internal slot number or -1 on
|
/* Open the reader and return an internal slot number or -1 on
|
||||||
error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
|
error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
|
||||||
the first USB reader. For PCSC/ the first listed reader. */
|
the first USB reader. For PC/SC the first listed reader). IF
|
||||||
|
OpenSC support is cmpiled in, we first try to use OpenSC. */
|
||||||
int
|
int
|
||||||
apdu_open_reader (const char *portstr)
|
apdu_open_reader (const char *portstr)
|
||||||
{
|
{
|
||||||
static int pcsc_api_loaded, ct_api_loaded;
|
static int pcsc_api_loaded, ct_api_loaded;
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
if (!opt.disable_opensc)
|
||||||
|
{
|
||||||
|
int port = portstr? atoi (portstr) : 0;
|
||||||
|
|
||||||
|
return open_osc_reader (port);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_OPENSC */
|
||||||
|
|
||||||
|
|
||||||
if (opt.ctapi_driver && *opt.ctapi_driver)
|
if (opt.ctapi_driver && *opt.ctapi_driver)
|
||||||
{
|
{
|
||||||
int port = portstr? atoi (portstr) : 32768;
|
int port = portstr? atoi (portstr) : 32768;
|
||||||
@ -648,6 +863,10 @@ error_string (int slot, long rc)
|
|||||||
return "[invalid slot]";
|
return "[invalid slot]";
|
||||||
if (reader_table[slot].is_ctapi)
|
if (reader_table[slot].is_ctapi)
|
||||||
return ct_error_string (rc);
|
return ct_error_string (rc);
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
else if (reader_table[slot].is_osc)
|
||||||
|
return sc_strerror (rc);
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
return pcsc_error_string (rc);
|
return pcsc_error_string (rc);
|
||||||
}
|
}
|
||||||
@ -662,6 +881,10 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
|||||||
return SW_HOST_NO_DRIVER;
|
return SW_HOST_NO_DRIVER;
|
||||||
if (reader_table[slot].is_ctapi)
|
if (reader_table[slot].is_ctapi)
|
||||||
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
else if (reader_table[slot].is_osc)
|
||||||
|
return osc_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ enum cmd_and_opt_values
|
|||||||
oBatch,
|
oBatch,
|
||||||
oReaderPort,
|
oReaderPort,
|
||||||
octapiDriver,
|
octapiDriver,
|
||||||
|
oDisableOpenSC,
|
||||||
|
|
||||||
aTest };
|
aTest };
|
||||||
|
|
||||||
@ -94,6 +95,16 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
|
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
|
||||||
{ oReaderPort, "reader-port", 2, 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")},
|
{ octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")},
|
||||||
|
{ oDisableOpenSC, "disable-opensc", 0,
|
||||||
|
#ifdef HAVE_OPENSC
|
||||||
|
N_("Do not use the OpenSC layer")
|
||||||
|
#else
|
||||||
|
"@"
|
||||||
|
#endif
|
||||||
|
/* end --disable-opensc */},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -368,6 +379,7 @@ main (int argc, char **argv )
|
|||||||
|
|
||||||
case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
|
case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
|
||||||
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
|
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
|
||||||
|
case oDisableOpenSC: opt.disable_opensc = 1; break;
|
||||||
|
|
||||||
default : pargs.err = configfp? 1:2; break;
|
default : pargs.err = configfp? 1:2; break;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ struct {
|
|||||||
int batch; /* batch mode */
|
int batch; /* batch mode */
|
||||||
const char *homedir; /* configuration directory name */
|
const char *homedir; /* configuration directory name */
|
||||||
const char *ctapi_driver; /* Library to access the ctAPI. */
|
const char *ctapi_driver; /* Library to access the ctAPI. */
|
||||||
|
int disable_opensc; /* Disable the sue of the OpenSC framework. */
|
||||||
} opt;
|
} opt;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user