* configure.ac: Removed OpenSC detection and options.

* acinclude.m4: Ditto.

* scdaemon.texi: Removed OpenSC specific options.

* app-p15.c: New.  Basic support for pkcs15 cards without OpenSC.
There are quite a couple of things missing but at least I can use
my old TCOS cards from the Aegypten-1 development for signing.
* app.c (select_application): Detect pkcs15 applications.
* Makefile.am (scdaemon_SOURCES): Removed card.c, card-common.h
and card-p15.c because they are now obsolete. Added app-p15.c.
Removed all OpenSC stuff.
* command.c (do_reset, open_card, cmd_serialno, cmd_learn)
(cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkdecrypt): Removed
all special cases for the old card.c based mechanisms.
* scdaemon.c, apdu.c: Removed all special cases for OpenSC.
This commit is contained in:
Werner Koch 2005-04-27 12:09:21 +00:00
parent a832ff3de0
commit a22750dc1e
16 changed files with 2623 additions and 896 deletions

View File

@ -1,3 +1,8 @@
2005-04-27 Werner Koch <wk@g10code.com>
* configure.ac: Removed OpenSC detection and options.
* acinclude.m4: Ditto.
2005-04-21 Werner Koch <wk@g10code.com> 2005-04-21 Werner Koch <wk@g10code.com>
Released 1.9.16. Released 1.9.16.

5
NEWS
View File

@ -1,6 +1,11 @@
Noteworthy changes in version 1.9.17 Noteworthy changes in version 1.9.17
------------------------------------------------- -------------------------------------------------
* [scdaemon] Support for OpenSC has been removed. Instead a new and
starightforward pkcs#15 modules has been written. As of now it
does allows only signing using TCOS cards but we are going to
enhance it to match all the old capabilities.
Noteworthy changes in version 1.9.16 (2005-04-21) Noteworthy changes in version 1.9.16 (2005-04-21)
------------------------------------------------- -------------------------------------------------

View File

@ -390,70 +390,3 @@ fi
dnl AM_PATH_OPENSC([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl Test for OpenSC and define OPENSC_CFLAGS and OPENSC_LIBS
dnl
AC_DEFUN([AM_PATH_OPENSC],
[ AC_ARG_WITH(opensc-prefix,
AC_HELP_STRING([--with-opensc-prefix=PFX],
[prefix where OpenSC is installed (optional)]),
opensc_config_prefix="$withval", opensc_config_prefix="")
if test x$opensc_config_prefix != x ; then
opensc_config_args="$opensc_config_args --prefix=$opensc_config_prefix"
if test x${OPENSC_CONFIG+set} != xset ; then
OPENSC_CONFIG=$opensc_config_prefix/bin/opensc-config
fi
fi
AC_PATH_PROG(OPENSC_CONFIG, opensc-config, no)
min_opensc_version=ifelse([$1], ,0.7.0,$1)
AC_MSG_CHECKING(for OpenSC - version >= $min_opensc_version)
ok=no
if test "$OPENSC_CONFIG" != "no" ; then
req_major=`echo $min_opensc_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
req_minor=`echo $min_opensc_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
req_micro=`echo $min_opensc_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
opensc_config_version=`$OPENSC_CONFIG $opensc_config_args --version 2>/dev/null || echo 0.0.0`
major=`echo $opensc_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
minor=`echo $opensc_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
micro=`echo $opensc_config_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
if test "$major" -gt "$req_major"; then
ok=yes
else
if test "$major" -eq "$req_major"; then
if test "$minor" -gt "$req_minor"; then
ok=yes
else
if test "$minor" -eq "$req_minor"; then
if test "$micro" -ge "$req_micro"; then
ok=yes
fi
fi
fi
fi
fi
fi
if test $ok = yes; then
OPENSC_CFLAGS=`$OPENSC_CONFIG $opensc_config_args --cflags`
OPENSC_LIBS=`$OPENSC_CONFIG $opensc_config_args --libs`
OPENSC_LIBS="$OPENSC_LIBS -lpcsclite -lpthread"
AC_MSG_RESULT(yes)
ifelse([$2], , :, [$2])
else
OPENSC_CFLAGS=""
OPENSC_LIBS=""
AC_MSG_RESULT(no)
ifelse([$3], , :, [$3])
fi
AC_SUBST(OPENSC_CFLAGS)
AC_SUBST(OPENSC_LIBS)
])

View File

@ -38,9 +38,6 @@ NEED_LIBASSUAN_VERSION=0.6.9
NEED_KSBA_VERSION=0.9.11 NEED_KSBA_VERSION=0.9.11
NEED_OPENSC_VERSION=0.8.0
PACKAGE=$PACKAGE_NAME PACKAGE=$PACKAGE_NAME
PACKAGE_GT=${PACKAGE_NAME}2 PACKAGE_GT=${PACKAGE_NAME}2
@ -59,7 +56,6 @@ have_gpg_error=no
have_libgcrypt=no have_libgcrypt=no
have_libassuan=no have_libassuan=no
have_ksba=no have_ksba=no
have_opensc=no
have_pth=no have_pth=no
GNUPG_BUILD_PROGRAM(gpg, no) GNUPG_BUILD_PROGRAM(gpg, no)
@ -503,16 +499,6 @@ AC_PATH_PROG(SHRED, shred, /usr/bin/shred)
AC_DEFINE_UNQUOTED(SHRED, AC_DEFINE_UNQUOTED(SHRED,
"${SHRED}", [defines the filename of the shred program]) "${SHRED}", [defines the filename of the shred program])
#
# OpenSC is needed by the SCdaemon - if it is not availbale we can only
# build a limited SCdaemon
#
AM_PATH_OPENSC("$NEED_OPENSC_VERSION",have_opensc=yes,have_opensc=no)
if test $have_opensc = yes; then
AC_DEFINE(HAVE_OPENSC,1,
[defined if the OpenSC library is available])
fi
AM_CONDITIONAL(HAVE_OPENSC, test "$have_opensc" = "yes")
# #
# Check whether the (highly desirable) GNU Pth library is available # Check whether the (highly desirable) GNU Pth library is available
@ -1052,10 +1038,6 @@ if test "$build_scdaemon" = "yes"; then
tmp=", " tmp=", "
missing_pth=yes missing_pth=yes
fi fi
if test $have_opensc = no; then
build_scdaemon_extra="${build_scdaemon_extra}${tmp}no pkcs#15"
tmp=", "
fi
if test -n "$build_scdaemon_extra"; then if test -n "$build_scdaemon_extra"; then
build_scdaemon_extra="(${build_scdaemon_extra})" build_scdaemon_extra="(${build_scdaemon_extra})"
fi fi

View File

@ -1,3 +1,7 @@
2005-04-27 Werner Koch <wk@g10code.com>
* scdaemon.texi: Removed OpenSC specific options.
2005-04-20 Werner Koch <wk@g10code.com> 2005-04-20 Werner Koch <wk@g10code.com>
* gpg-agent.texi (Agent Configuration): New section. * gpg-agent.texi (Agent Configuration): New section.

View File

@ -1,4 +1,4 @@
@c Copyright (C) 2002 Free Software Foundation, Inc. g@c Copyright (C) 2002 Free Software Foundation, Inc.
@c This is part of the GnuPG manual. @c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi. @c For copying conditions, see the file gnupg.texi.
@ -157,10 +157,6 @@ When running in server mode, wait @var{n} seconds before entering the
actual processing loop and print the pid. This gives time to attach a actual processing loop and print the pid. This gives time to attach a
debugger. debugger.
@item --debug-sc @var{n}
@opindex debug-sc
Set the debug level of the OpenSC library to @var{n}.
@item --no-detach @item --no-detach
@opindex no-detach @opindex no-detach
Don't detach the process from the console. This is manly usefule for Don't detach the process from the console. This is manly usefule for
@ -172,10 +168,9 @@ Append all logging output to @var{file}. This is very helpful in
seeing what the agent actually does. seeing what the agent actually does.
@item --reader-port @var{number} @item --reader-port @var{number}
When the program has been build without OpenSC support, this option must This option may be used to specify the port of the card terminal. A
be used to specify the port of the card terminal. A value of 0 refers value of 0 refers to the first serial device; add 32768 to access USB
to the first serial device; add 32768 to access USB devices. The devices. The default is 32768 (first USB device).
default is 32768 (first USB device).
@item --ctapi-driver @var{library} @item --ctapi-driver @var{library}
Use @var{library} to access the smartcard reader. The current default Use @var{library} to access the smartcard reader. The current default
@ -245,9 +240,8 @@ the German signature law and its bylaws (SigG and SigV).
@node PKCS#15 Card @node PKCS#15 Card
@subsection The PKCS#15 card application ``p15'' @subsection The PKCS#15 card application ``p15''
This is common fraqmework for smart card applications; support is only This is common fraqmework for smart card applications. It is used by
available if compiled with support for the OpenSC library. It is used @command{gpgsm}.
by @command{gpgsm}.

View File

@ -1,3 +1,19 @@
2005-04-27 Werner Koch <wk@g10code.com>
Removal of the old OpenSC based code.
* app-p15.c: New. Basic support for pkcs15 cards without OpenSC.
There are quite a couple of things missing but at least I can use
my old TCOS cards from the Aegypten-1 development for signing.
* app.c (select_application): Detect pkcs15 applications.
* Makefile.am (scdaemon_SOURCES): Removed card.c, card-common.h
and card-p15.c because they are now obsolete. Added app-p15.c.
Removed all OpenSC stuff.
* command.c (do_reset, open_card, cmd_serialno, cmd_learn)
(cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkdecrypt): Removed
all special cases for the old card.c based mechanisms.
* scdaemon.c, apdu.c: Removed all special cases for OpenSC.
2005-04-20 Werner Koch <wk@g10code.com> 2005-04-20 Werner Koch <wk@g10code.com>
* command.c: Use GPG_ERR_LOCKED instead of EBUSY. * command.c: Use GPG_ERR_LOCKED instead of EBUSY.

View File

@ -1,4 +1,4 @@
# Copyright (C) 2002, 2003 Free Software Foundation, Inc. # Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
# #
# This file is part of GnuPG. # This file is part of GnuPG.
# #
@ -27,24 +27,15 @@ AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am include $(top_srcdir)/am/cmacros.am
# avoid linking against Pth if we are using OpenSC. AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \
if HAVE_OPENSC $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
pth_libs =
else
pth_libs = $(PTH_LIBS)
endif
AM_CFLAGS = $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
$(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
card_apps = app-openpgp.c app-nks.c app-dinsig.c card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c
scdaemon_SOURCES = \ scdaemon_SOURCES = \
scdaemon.c scdaemon.h \ scdaemon.c scdaemon.h \
command.c card.c \ command.c \
card-common.h \
card-p15.c \
apdu.c apdu.h \ apdu.c apdu.h \
ccid-driver.c ccid-driver.h \ ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \ iso7816.c iso7816.h \
@ -53,8 +44,8 @@ scdaemon_SOURCES = \
scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(pth_libs) $(LIBASSUAN_LIBS) \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBASSUAN_LIBS) \
$(LIBUSB_LIBS) $(OPENSC_LIBS) -lgpg-error $(LIBINTL) $(DL_LIBS) $(LIBUSB_LIBS) -lgpg-error $(LIBINTL) $(DL_LIBS)
sc_copykeys_SOURCES = \ sc_copykeys_SOURCES = \
sc-copykeys.c scdaemon.h \ sc-copykeys.c scdaemon.h \
@ -68,8 +59,8 @@ 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) $(pth_libs) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ $(LIBGCRYPT_LIBS) $(PTH_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \
$(LIBUSB_LIBS) $(OPENSC_LIBS) \ $(LIBUSB_LIBS) \
-lgpg-error @LIBINTL@ @DL_LIBS@ -lgpg-error @LIBINTL@ @DL_LIBS@
pcsc_wrapper_SOURCES = pcsc-wrapper.c pcsc_wrapper_SOURCES = pcsc-wrapper.c

View File

@ -32,12 +32,7 @@
# include <unistd.h> # include <unistd.h>
# include <fcntl.h> # include <fcntl.h>
#endif #endif
#ifdef HAVE_OPENSC
# include <opensc/opensc.h>
# ifdef USE_GNU_PTH
# undef USE_GNU_PTH
# endif
#endif
/* If requested include the definitions for the remote APDU protocol /* If requested include the definitions for the remote APDU protocol
code. */ code. */
@ -119,12 +114,6 @@ struct reader_table_s {
pid_t pid; pid_t pid;
#endif /*NEED_PCSC_WRAPPER*/ #endif /*NEED_PCSC_WRAPPER*/
} pcsc; } pcsc;
#ifdef HAVE_OPENSC
struct {
struct sc_context *ctx;
struct sc_card *scard;
} osc;
#endif /*HAVE_OPENSC*/
#ifdef USE_G10CODE_RAPDU #ifdef USE_G10CODE_RAPDU
struct { struct {
rapdu_t handle; rapdu_t handle;
@ -1770,224 +1759,6 @@ open_ccid_reader (const char *portstr)
#endif /* HAVE_LIBUSB */ #endif /* HAVE_LIBUSB */
#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
close_osc_reader (int slot)
{
/* FIXME: Implement. */
reader_table[slot].used = 0;
return 0;
}
static int
reset_osc_reader (int slot)
{
return SW_HOST_NOT_SUPPORTED;
}
static int
osc_get_status (int slot, unsigned int *status)
{
return SW_HOST_NOT_SUPPORTED;
}
/* 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 SW_HOST_INV_VALUE;
}
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 SW_HOST_INV_VALUE;
}
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 SW_HOST_INV_VALUE;
}
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 SW_HOST_CARD_IO_ERROR;
}
if (*buflen < 2 || a.resplen > *buflen - 2)
{
log_error ("osc_send_apdu: provided buffer too short to store result\n");
return SW_HOST_INV_VALUE;
}
memcpy (buffer, a.resp, a.resplen);
buffer[a.resplen] = a.sw1;
buffer[a.resplen+1] = a.sw2;
*buflen = a.resplen + 2;
return 0;
}
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);
reader_table[slot].close_reader = close_osc_reader;
reader_table[slot].reset_reader = reset_osc_reader;
reader_table[slot].get_status_reader = osc_get_status;
reader_table[slot].send_apdu_reader = osc_send_apdu;
reader_table[slot].dump_status_reader = NULL;
dump_reader_status (slot);
return slot;
}
#endif /* HAVE_OPENSC */
#ifdef USE_G10CODE_RAPDU #ifdef USE_G10CODE_RAPDU
/* /*
@ -2130,7 +1901,7 @@ my_rapdu_get_status (int slot, unsigned int *status)
/* Actually send the APDU of length APDULEN to SLOT and return a /* Actually send the APDU of length APDULEN to SLOT and return a
maximum of *BUFLEN data in BUFFER, the actual returned size will be maximum of *BUFLEN data in BUFFER, the actual returned size will be
set to BUFLEN. Returns: OpenSC error code. */ set to BUFLEN. Returns: APDU error code. */
static int static int
my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen) unsigned char *buffer, size_t *buflen)
@ -2325,8 +2096,7 @@ unlock_slot (int slot)
/* 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 PC/SC the first listed reader). If the first USB reader. For PC/SC the first listed reader). */
OpenSC support is compiled in, we first try to use OpenSC. */
int int
apdu_open_reader (const char *portstr) apdu_open_reader (const char *portstr)
{ {
@ -2352,16 +2122,6 @@ apdu_open_reader (const char *portstr)
#endif /* HAVE_LIBUSB */ #endif /* HAVE_LIBUSB */
#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;

View File

@ -175,7 +175,7 @@ int app_select_nks (app_t app);
int app_select_dinsig (app_t app); int app_select_dinsig (app_t app);
/*-- app-p15.c --*/ /*-- app-p15.c --*/
int app_select_p15 (app_t app); gpg_error_t app_select_p15 (app_t app);
#endif #endif

View File

@ -305,7 +305,7 @@ verify_pin (app_t app,
void *pincb_arg) void *pincb_arg)
{ {
/* Note that force_chv1 is never set but we do it here anyway so /* Note that force_chv1 is never set but we do it here anyway so
that other applications may euse this function. For example it that other applications may reuse this function. For example it
makes sense to set force_chv1 for German signature law cards. makes sense to set force_chv1 for German signature law cards.
NKS is very similar to the DINSIG draft standard. */ NKS is very similar to the DINSIG draft standard. */
if (!app->did_chv1 || app->force_chv1 ) if (!app->did_chv1 || app->force_chv1 )
@ -444,7 +444,7 @@ do_decipher (app_t app, const char *keyidstr,
{ {
static const unsigned char mse_parm[] = { static const unsigned char mse_parm[] = {
0x80, 1, 0x10, /* Select algorithm RSA. */ 0x80, 1, 0x10, /* Select algorithm RSA. */
0x84, 1, 0x81 /* Select locak secret key 1 for descryption. */ 0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
}; };
int rc, i; int rc, i;
int fid; int fid;

File diff suppressed because it is too large Load Diff

View File

@ -125,8 +125,8 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
rc = app_select_openpgp (app); rc = app_select_openpgp (app);
if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
rc = app_select_nks (app); rc = app_select_nks (app);
/* if (rc && is_app_allowed ("p12") && (!name || !strcmp (name, "p12"))) */ if (rc && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
/* rc = app_select_p12 (app); */ rc = app_select_p15 (app);
if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
rc = app_select_dinsig (app); rc = app_select_dinsig (app);
if (rc && name) if (rc && name)
@ -177,7 +177,7 @@ release_application (app_t app)
FF 00 00 = For serial numbers starting with an FF FF 00 00 = For serial numbers starting with an FF
FF 01 00 = Some german p15 cards return an empty serial number so the FF 01 00 = Some german p15 cards return an empty serial number so the
serial number from the EF(TokeInfo is used instead. serial number from the EF(TokenInfo) is used instead.
All other serial number not starting with FF are used as they are. All other serial number not starting with FF are used as they are.
*/ */

View File

@ -129,13 +129,6 @@ do_reset (ctrl_t ctrl, int do_close)
{ {
int slot = ctrl->reader_slot; int slot = ctrl->reader_slot;
if (ctrl->card_ctx)
{
card_close (ctrl->card_ctx);
ctrl->card_ctx = NULL;
xfree (ctrl->in_data.value);
ctrl->in_data.value = NULL;
}
if (ctrl->app_ctx) if (ctrl->app_ctx)
{ {
release_application (ctrl->app_ctx); release_application (ctrl->app_ctx);
@ -259,8 +252,6 @@ open_card (ctrl_t ctrl, const char *apptype)
if (ctrl->app_ctx) if (ctrl->app_ctx)
return 0; /* Already initialized for one specific application. */ return 0; /* Already initialized for one specific application. */
if (ctrl->card_ctx)
return 0; /* Already initialized using a card context. */
if ( IS_LOCKED (ctrl) ) if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED); return gpg_error (GPG_ERR_LOCKED);
@ -274,19 +265,6 @@ open_card (ctrl_t ctrl, const char *apptype)
err = gpg_error (GPG_ERR_CARD); err = gpg_error (GPG_ERR_CARD);
else else
err = select_application (ctrl, slot, apptype, &ctrl->app_ctx); err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
if (!ctrl->app_ctx
&& gpg_err_code (err) != GPG_ERR_CARD_NOT_PRESENT)
{
/* No application found - fall back to old mode. */
/* Note that we should rework the old code to use the
application paradigma too. */
/* If an APPTYPE was requested and it is not pkcs#15, we return
an error here. */
if (apptype && !(!strcmp (apptype, "P15") || !strcmp (apptype, "p15")))
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
else
err = card_open (&ctrl->card_ctx);
}
TEST_CARD_REMOVAL (ctrl, err); TEST_CARD_REMOVAL (ctrl, err);
return map_to_assuan_status (err); return map_to_assuan_status (err);
@ -367,12 +345,10 @@ cmd_serialno (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl, *line? line:NULL))) if ((rc = open_card (ctrl, *line? line:NULL)))
return rc; return rc;
if (ctrl->app_ctx) rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
else
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
if (rc) if (rc)
return map_to_assuan_status (rc); return map_to_assuan_status (rc);
rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp); rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
xfree (serial); xfree (serial);
if (rc < 0) if (rc < 0)
@ -453,7 +429,6 @@ cmd_learn (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
int rc = 0; int rc = 0;
int idx;
if ((rc = open_card (ctrl, NULL))) if ((rc = open_card (ctrl, NULL)))
return rc; return rc;
@ -467,10 +442,7 @@ cmd_learn (assuan_context_t ctx, char *line)
char *serial; char *serial;
time_t stamp; time_t stamp;
if (ctrl->app_ctx) rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
else
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
if (rc) if (rc)
return map_to_assuan_status (rc); return map_to_assuan_status (rc);
rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp); rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
@ -506,87 +478,11 @@ cmd_learn (assuan_context_t ctx, char *line)
free (serial_and_stamp); free (serial_and_stamp);
} }
/* If we are using the modern application paradigma, let the /* Let the application print out its collection of useful status
application print out its collection of useful status
information. */ information. */
if (!rc && ctrl->app_ctx) if (!rc)
rc = app_write_learn_status (ctrl->app_ctx, ctrl); rc = app_write_learn_status (ctrl->app_ctx, ctrl);
/* Return information about the certificates. FIXME: Move this into
an app-p15.c*/
for (idx=0; !rc && !ctrl->app_ctx; idx++)
{
char *certid;
int certtype;
rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
if (!rc)
{
char *buf;
buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
if (!buf)
rc = gpg_error (gpg_err_code_from_errno (errno));
else
{
sprintf (buf, "%d %s", certtype, certid);
assuan_write_status (ctx, "CERTINFO", buf);
xfree (buf);
}
}
xfree (certid);
}
if (rc == -1)
rc = 0;
/* Return information about the keys. FIXME: Move this into an
app-p15.c */
for (idx=0; !rc && !ctrl->app_ctx; idx++)
{
unsigned char keygrip[20];
char *keyid;
int no_cert = 0;
rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid)
{
/* This does happen with an incomplete personalized
card; i.e. during the time we have stored the key on the
card but not stored the certificate; probably becuase it
has not yet been received back from the CA. Note that we
must release KEYID in this case. */
rc = 0;
no_cert = 1;
}
if (!rc)
{
char *buf, *p;
buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
if (!buf)
rc = gpg_error (gpg_err_code_from_errno (errno));
else
{
int i;
if (no_cert)
*p++ = 'X';
else
{
for (i=0; i < 20; i++, p += 2)
sprintf (p, "%02X", keygrip[i]);
}
*p++ = ' ';
strcpy (p, keyid);
assuan_write_status (ctx, "KEYPAIRINFO", buf);
xfree (buf);
}
}
xfree (keyid);
}
if (rc == -1)
rc = 0;
TEST_CARD_REMOVAL (ctrl, rc); TEST_CARD_REMOVAL (ctrl, rc);
return map_to_assuan_status (rc); return map_to_assuan_status (rc);
} }
@ -595,7 +491,7 @@ cmd_learn (assuan_context_t ctx, char *line)
/* READCERT <hexified_certid> /* READCERT <hexified_certid>
Note, that this function may be even be used on a locked card. Note, that this function may even be used on a locked card.
*/ */
static int static int
cmd_readcert (assuan_context_t ctx, char *line) cmd_readcert (assuan_context_t ctx, char *line)
@ -609,18 +505,9 @@ cmd_readcert (assuan_context_t ctx, char *line)
return rc; return rc;
line = xstrdup (line); /* Need a copy of the line. */ line = xstrdup (line); /* Need a copy of the line. */
if (ctrl->app_ctx) rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
{ if (rc)
rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert); log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
if (rc)
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
}
else
{
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
if (rc)
log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
}
xfree (line); xfree (line);
line = NULL; line = NULL;
if (!rc) if (!rc)
@ -641,7 +528,7 @@ cmd_readcert (assuan_context_t ctx, char *line)
Return the public key for the given cert or key ID as an standard Return the public key for the given cert or key ID as an standard
S-Expression. S-Expression.
Note, that this function may be even be used on a locked card. Note, that this function may even be used on a locked card.
*/ */
static int static int
cmd_readkey (assuan_context_t ctx, char *line) cmd_readkey (assuan_context_t ctx, char *line)
@ -652,44 +539,34 @@ cmd_readkey (assuan_context_t ctx, char *line)
size_t ncert, n; size_t ncert, n;
ksba_cert_t kc = NULL; ksba_cert_t kc = NULL;
ksba_sexp_t p; ksba_sexp_t p;
unsigned char *pk;
size_t pklen;
if ((rc = open_card (ctrl, NULL))) if ((rc = open_card (ctrl, NULL)))
return rc; return rc;
line = xstrdup (line); /* Need a copy of the line. */ line = xstrdup (line); /* Need a copy of the line. */
if (ctrl->app_ctx) /* If the application supports the READKEY function we use that.
{ Otherwise we use the old way by extracting it from the
unsigned char *pk; certificate. */
size_t pklen; rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen);
if (!rc)
/* If the application supports the READKEY function we use that. { /* Yeah, got that key - send it back. */
Otherwise we use the old way by extracting it from the rc = assuan_send_data (ctx, pk, pklen);
certificate. */ xfree (pk);
rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen); rc = map_assuan_err (rc);
if (!rc) xfree (line);
{ /* Yeah, got that key - send it back. */ line = NULL;
rc = assuan_send_data (ctx, pk, pklen); goto leave;
xfree (pk);
rc = map_assuan_err (rc);
xfree (line);
line = NULL;
goto leave;
}
if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
else
{
rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
if (rc)
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
}
} }
else
if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION)
log_error ("app_readkey failed: %s\n", gpg_strerror (rc));
else
{ {
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
if (rc) if (rc)
log_error ("card_read_cert failed: %s\n", gpg_strerror (rc)); log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
} }
xfree (line); xfree (line);
line = NULL; line = NULL;
@ -786,8 +663,8 @@ pin_cb (void *opaque, const char *info, char **retstr)
if (rc < 0) if (rc < 0)
return gpg_error (gpg_err_code_from_errno (errno)); return gpg_error (gpg_err_code_from_errno (errno));
/* FIXME: Write an inquire function which returns the result in /* Fixme: Write an inquire function which returns the result in
secure memory */ secure memory and check all futher handling of the PIN. */
rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
free (command); free (command);
if (rc) if (rc)
@ -829,18 +706,12 @@ cmd_pksign (assuan_context_t ctx, char *line)
if (!keyidstr) if (!keyidstr)
return ASSUAN_Out_Of_Core; return ASSUAN_Out_Of_Core;
if (ctrl->app_ctx) rc = app_sign (ctrl->app_ctx,
rc = app_sign (ctrl->app_ctx, keyidstr, GCRY_MD_SHA1,
keyidstr, GCRY_MD_SHA1, pin_cb, ctx,
pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen,
ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen);
&outdata, &outdatalen);
else
rc = card_sign (ctrl->card_ctx,
keyidstr, GCRY_MD_SHA1,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
xfree (keyidstr); xfree (keyidstr);
if (rc) if (rc)
{ {
@ -929,18 +800,12 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
keyidstr = xtrystrdup (line); keyidstr = xtrystrdup (line);
if (!keyidstr) if (!keyidstr)
return ASSUAN_Out_Of_Core; return ASSUAN_Out_Of_Core;
if (ctrl->app_ctx) rc = app_decipher (ctrl->app_ctx,
rc = app_decipher (ctrl->app_ctx, keyidstr,
keyidstr, pin_cb, ctx,
pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen,
ctrl->in_data.value, ctrl->in_data.valuelen, &outdata, &outdatalen);
&outdata, &outdatalen);
else
rc = card_decipher (ctrl->card_ctx,
keyidstr,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
xfree (keyidstr); xfree (keyidstr);
if (rc) if (rc)
{ {

View File

@ -108,7 +108,6 @@ static ARGPARSE_OPTS opts[] = {
{ oDebugAll, "debug-all" ,0, "@"}, { oDebugAll, "debug-all" ,0, "@"},
{ oDebugLevel, "debug-level" ,2, "@"}, { oDebugLevel, "debug-level" ,2, "@"},
{ oDebugWait,"debug-wait",1, "@"}, { oDebugWait,"debug-wait",1, "@"},
{ oDebugSC, "debug-sc", 1, N_("|N|set OpenSC debug level to N")},
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
{ 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")},
@ -121,17 +120,14 @@ static ARGPARSE_OPTS opts[] = {
"@" "@"
#endif #endif
/* end --disable-ccid */}, /* end --disable-ccid */},
{ oDisableOpenSC, "disable-opensc", 0,
#ifdef HAVE_OPENSC
N_("do not use the OpenSC layer")
#else
"@"
#endif
/* end --disable-opensc */},
{ oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")}, { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
{ oDenyAdmin, "deny-admin", 0, "@" }, { oDenyAdmin, "deny-admin", 0, "@" },
{ oDisableApplication, "disable-application", 2, "@"}, { oDisableApplication, "disable-application", 2, "@"},
/* Dummy options to be removed at some point. */
{ oDebugSC, "debug-sc", 1, "@" },
{ oDisableOpenSC, "disable-opensc", 0, "@" },
{0} {0}
}; };
@ -156,14 +152,12 @@ static int maybe_setuid = 1;
static char socket_name[128]; static char socket_name[128];
#ifndef HAVE_OPENSC
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
/* Pth wrapper function definitions. */ /* Pth wrapper function definitions. */
GCRY_THREAD_OPTION_PTH_IMPL; GCRY_THREAD_OPTION_PTH_IMPL;
static void *ticker_thread (void *arg); static void *ticker_thread (void *arg);
#endif /*USE_GNU_PTH*/ #endif /*USE_GNU_PTH*/
#endif /*!HAVE_OPENSC*/
static const char * static const char *
my_strusage (int level) my_strusage (int level)
@ -349,7 +343,6 @@ main (int argc, char **argv )
/* Libgcrypt requires us to register the threading model first. /* Libgcrypt requires us to register the threading model first.
Note that this will also do the pth_init. */ Note that this will also do the pth_init. */
#ifndef HAVE_OPENSC
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
if (err) if (err)
@ -358,7 +351,6 @@ main (int argc, char **argv )
gpg_strerror (err)); gpg_strerror (err));
} }
#endif /*USE_GNU_PTH*/ #endif /*USE_GNU_PTH*/
#endif /*!HAVE_OPENSC*/
/* Check that the libraries are suitable. Do it here because /* Check that the libraries are suitable. Do it here because
the option parsing may need services of the library */ the option parsing may need services of the library */
@ -469,7 +461,7 @@ main (int argc, char **argv )
case oDebugAll: opt.debug = ~0; break; case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugLevel: debug_level = pargs.r.ret_str; break;
case oDebugWait: debug_wait = pargs.r.ret_int; break; case oDebugWait: debug_wait = pargs.r.ret_int; break;
case oDebugSC: opt.debug_sc = pargs.r.ret_int; break; case oDebugSC: break;
case oOptions: case oOptions:
/* config files may not be nested (silently ignore them) */ /* config files may not be nested (silently ignore them) */
@ -495,7 +487,7 @@ main (int argc, char **argv )
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break; case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
case oDisableCCID: opt.disable_ccid = 1; break; case oDisableCCID: opt.disable_ccid = 1; break;
case oDisableOpenSC: opt.disable_opensc = 1; break; case oDisableOpenSC: break;
case oAllowAdmin: opt.allow_admin = 1; break; case oAllowAdmin: opt.allow_admin = 1; break;
case oDenyAdmin: opt.allow_admin = 0; break; case oDenyAdmin: opt.allow_admin = 0; break;
@ -592,9 +584,6 @@ main (int argc, char **argv )
GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER ); GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
#ifdef HAVE_LIBUSB #ifdef HAVE_LIBUSB
printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE ); printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
#endif
#ifdef HAVE_LIBUSB
printf ("disable-opensc:%lu:\n", GC_OPT_FLAG_NONE );
#endif #endif
printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE ); printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE );
@ -612,7 +601,6 @@ main (int argc, char **argv )
if (pipe_server) if (pipe_server)
{ /* This is the simple pipe based server */ { /* This is the simple pipe based server */
#ifndef HAVE_OPENSC
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
pth_attr_t tattr; pth_attr_t tattr;
@ -627,7 +615,6 @@ main (int argc, char **argv )
scd_exit (2); scd_exit (2);
} }
#endif /*USE_GNU_PTH*/ #endif /*USE_GNU_PTH*/
#endif /*!HAVE_OPENSC*/
scd_command_handler (-1); scd_command_handler (-1);
} }
else if (!is_daemon) else if (!is_daemon)
@ -859,7 +846,6 @@ scd_init_default_ctrl (CTRL ctrl)
} }
#ifndef HAVE_OPENSC
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
static void static void
@ -971,4 +957,3 @@ ticker_thread (void *dummy_arg)
return NULL; return NULL;
} }
#endif /*USE_GNU_PTH*/ #endif /*USE_GNU_PTH*/
#endif /*!HAVE_OPENSC*/

View File

@ -42,7 +42,6 @@
/* A large struct name "opt" to keep global flags */ /* A large struct name "opt" to keep global flags */
struct { struct {
unsigned int debug; /* debug flags (DBG_foo_VALUE) */ unsigned int debug; /* debug flags (DBG_foo_VALUE) */
int debug_sc; /* OpenSC debug level */
int verbose; /* verbosity level */ int verbose; /* verbosity level */
int quiet; /* be as quiet as possible */ int quiet; /* be as quiet as possible */
int dry_run; /* don't change any persistent data */ int dry_run; /* don't change any persistent data */
@ -51,7 +50,6 @@ struct {
const char *ctapi_driver; /* Library to access the ctAPI. */ const char *ctapi_driver; /* Library to access the ctAPI. */
const char *pcsc_driver; /* Library to access the PC/SC system. */ const char *pcsc_driver; /* Library to access the PC/SC system. */
const char *reader_port; /* NULL or reder port to use. */ const char *reader_port; /* NULL or reder port to use. */
int disable_opensc; /* Disable the use of the OpenSC framework. */
int disable_ccid; /* Disable the use of the internal CCID driver. */ int disable_ccid; /* Disable the use of the internal CCID driver. */
int allow_admin; /* Allow the use of admin commands for certain int allow_admin; /* Allow the use of admin commands for certain
cards. */ cards. */
@ -96,7 +94,6 @@ struct server_control_s {
typedef struct server_control_s *CTRL; typedef struct server_control_s *CTRL;
typedef struct server_control_s *ctrl_t; typedef struct server_control_s *ctrl_t;
typedef struct card_ctx_s *CARD;
typedef struct app_ctx_s *APP; typedef struct app_ctx_s *APP;
typedef struct app_ctx_s *app_t; typedef struct app_ctx_s *app_t;
@ -109,27 +106,5 @@ void scd_command_handler (int);
void send_status_info (CTRL ctrl, const char *keyword, ...); void send_status_info (CTRL ctrl, const char *keyword, ...);
void scd_update_reader_status_file (void); void scd_update_reader_status_file (void);
/*-- card.c --*/
int card_open (CARD *rcard);
void card_close (CARD card);
int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
int card_enum_keypairs (CARD card, int idx,
unsigned char *keygrip,
char **keyid);
int card_enum_certs (CARD card, int idx, char **certid, int *certtype);
int card_read_cert (CARD card, const char *certidstr,
unsigned char **cert, size_t *ncert);
int card_sign (CARD card,
const char *keyidstr, int hashalgo,
int (pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen );
int card_decipher (CARD card, const char *keyidstr,
int (pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
#endif /*SCDAEMON_H*/ #endif /*SCDAEMON_H*/