diff options
author | Robert Relyea <rrelyea@redhat.com> | 2010-10-03 14:34:43 +0200 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2010-10-03 14:36:55 +0200 |
commit | a256875a5947dbea1d6a066698e2948071519714 (patch) | |
tree | 47a5100e5df60178ab4eb5b41a1beb83498fafe6 | |
parent | b1a3c160735ccbf0ba5539e957d400660ebb6ec3 (diff) |
passthru and multiple reader support.
New Features, library:
- added passthru mode: pass thru can be used either as a card_type and an
existing emulator, or as it's own emulator. When used as it's own emulator,
only the passhthru card type is supported. Enabling Passhtru is a compile
time option (you can build without it). It is still selected for at run-time
- added argument parsing code for the NSS emulator. This allows the argument
structure to move back to the emulator dependent directory. (This allows
other emulators to be implemented without the application needing to know
about emulator specific stuff.
- added functions to get the reader name and id, and have the caller set
the reader id.
- added vevent_get_next_vevent() - non-blocking event grabber.
- added string arguments to the card_type_init functions (currently not used).
- added VCARD_DIRECT card type which passes all the apdus the the card type's
last applet.
- added function to optionally get the ATR from the card type emul instead
of the emulator. NOTE: apps should now call vcard_get_atr rather than
vcard_emul_get_atr.
- Fixed the VCARD_ATR_PREFIX to take a constant signifying the number of
additional historical bytes for the card emulator.
- added usage statment.
New Features, vscclient.c
- vscclient now handles multiple readers, assuming multiple readers are
defined in qemu.
- vscclient now calls the emul to parse the command line arguments.
- vscclient has an option to enable passthru
- vscclient now passes the real reader name to qemu
- vscclient has 2 new commands:
debug [level] -- sets the various levels of debugging output on the fly.
list -- lists all the active readers, their card state and their name.
-rw-r--r-- | Makefile | 875 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | README | 38 | ||||
-rw-r--r-- | cac.c | 79 | ||||
-rw-r--r-- | cac.h | 18 | ||||
-rw-r--r-- | card_7816.c | 84 | ||||
-rw-r--r-- | card_7816.h | 15 | ||||
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | event.c | 11 | ||||
-rw-r--r-- | mutex.h | 18 | ||||
-rw-r--r-- | passthru.c | 589 | ||||
-rw-r--r-- | passthru.h | 50 | ||||
-rw-r--r-- | vcard.c | 64 | ||||
-rw-r--r-- | vcard.h | 5 | ||||
-rw-r--r-- | vcard_emul.h | 19 | ||||
-rw-r--r-- | vcard_emul_nss.c | 269 | ||||
-rw-r--r-- | vcard_emul_type.c | 102 | ||||
-rw-r--r-- | vcard_emul_type.h | 11 | ||||
-rw-r--r-- | vcardt.h | 11 | ||||
-rw-r--r-- | vevent.h | 6 | ||||
-rw-r--r-- | vreader.c | 93 | ||||
-rw-r--r-- | vreader.h | 10 | ||||
-rw-r--r-- | vreadert.h | 1 | ||||
-rw-r--r-- | vscclient.c | 358 |
24 files changed, 1609 insertions, 1135 deletions
diff --git a/Makefile b/Makefile deleted file mode 100644 index 53d0c13..0000000 --- a/Makefile +++ /dev/null @@ -1,875 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - - - - - -pkgdatadir = $(datadir)/cac_card -pkgincludedir = $(includedir)/cac_card -pkglibdir = $(libdir)/cac_card -pkglibexecdir = $(libexecdir)/cac_card -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = x86_64-unknown-linux-gnu -host_triplet = x86_64-unknown-linux-gnu -bin_PROGRAMS = vscclient$(EXEEXT) -subdir = . -DIST_COMMON = README $(am__configure_deps) \ - $(libcac_cardinclude_HEADERS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in $(srcdir)/cac_card.pc.in \ - $(srcdir)/config.h.in $(top_srcdir)/configure AUTHORS COPYING \ - ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ - install-sh ltmain.sh missing -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = cac_card.pc -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ - "$(DESTDIR)$(pkgconfigdir)" \ - "$(DESTDIR)$(libcac_cardincludedir)" -LTLIBRARIES = $(lib_LTLIBRARIES) -am__DEPENDENCIES_1 = -libcac_card_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -am__objects_1 = -am_libcac_card_la_OBJECTS = cac.lo card_7816.lo event.lo \ - vcard_emul_nss.lo vcard_emul_type.lo vcard.lo vreader.lo \ - $(am__objects_1) -libcac_card_la_OBJECTS = $(am_libcac_card_la_OBJECTS) -PROGRAMS = $(bin_PROGRAMS) -am_vscclient_OBJECTS = vscclient.$(OBJEXT) $(am__objects_1) -vscclient_OBJECTS = $(am_vscclient_OBJECTS) -vscclient_DEPENDENCIES = $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I. -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libcac_card_la_SOURCES) $(vscclient_SOURCES) -DIST_SOURCES = $(libcac_card_la_SOURCES) $(vscclient_SOURCES) -DATA = $(pkgconfig_DATA) -HEADERS = $(libcac_cardinclude_HEADERS) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - { test ! -d "$(distdir)" \ - || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -fr "$(distdir)"; }; } -DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 -GZIP_ENV = --best -distuninstallcheck_listfiles = find . -type f -print -distcleancheck_listfiles = find . -type f -print -ACLOCAL = ${SHELL} /store/src/spice_upstream/cac_card/missing --run aclocal-1.11 -AMTAR = ${SHELL} /store/src/spice_upstream/cac_card/missing --run tar -AR = ar -AUTOCONF = ${SHELL} /store/src/spice_upstream/cac_card/missing --run autoconf -AUTOHEADER = ${SHELL} /store/src/spice_upstream/cac_card/missing --run autoheader -AUTOMAKE = ${SHELL} /store/src/spice_upstream/cac_card/missing --run automake-1.11 -AWK = gawk -CAC_CARD_NONPKGCONFIG_LIBS = -pthread -CAC_CARD_REQUIRES = nss -CAC_COMMON_SRCDIR = -CAC_LT_VERSION = 1:0:2 -CAC_NONPKGCONFIG_CFLAGS = -CC = ccache gcc -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -O0 -CPP = ccache gcc -E -CPPFLAGS = -CYGPATH_W = echo -DEFS = -DHAVE_CONFIG_H -DEPDIR = .deps -DSYMUTIL = -DUMPBIN = -ECHO_C = -ECHO_N = -n -ECHO_T = -EGREP = /bin/grep -E -EXEEXT = -FGREP = /bin/grep -F -GREP = /bin/grep -INSTALL = /usr/bin/install -c -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -LD = /usr/bin/ld -m elf_x86_64 -LDFLAGS = -LIBOBJS = -LIBS = -LIBTOOL = $(SHELL) $(top_builddir)/libtool -LIPO = -LN_S = ln -s -LTLIBOBJS = -MAINT = # -MAKEINFO = ${SHELL} /store/src/spice_upstream/cac_card/missing --run makeinfo -MKDIR_P = /bin/mkdir -p -NM = /usr/bin/nm -B -NMEDIT = -NSS_CFLAGS = -I/usr/include/nss3 -I/usr/include/nspr4 -NSS_LIBS = -lssl3 -lsmime3 -lnss3 -lnssutil3 -lplds4 -lplc4 -lnspr4 -lpthread -ldl -OBJDUMP = objdump -OBJEXT = o -OTOOL = -OTOOL64 = -PACKAGE = cac_card -PACKAGE_BUGREPORT = -PACKAGE_NAME = cac_card -PACKAGE_STRING = cac_card 0.0.1 -PACKAGE_TARNAME = cac_card -PACKAGE_URL = -PACKAGE_VERSION = 0.0.1 -PATH_SEPARATOR = : -PKG_CONFIG = /usr/bin/pkg-config -PKG_CONFIG_LIBDIR = -PKG_CONFIG_PATH = /store/upstream/lib/pkgconfig:/store/upstream/share/pkgconfig: -PYTHON = /usr/bin/python2 -RANLIB = ranlib -SED = /bin/sed -SET_MAKE = -SHELL = /bin/sh -STRIP = strip -VERSION = 0.0.1 -abs_builddir = /store/src/spice_upstream/cac_card -abs_srcdir = /store/src/spice_upstream/cac_card -abs_top_builddir = /store/src/spice_upstream/cac_card -abs_top_srcdir = /store/src/spice_upstream/cac_card -ac_ct_CC = ccache gcc -ac_ct_DUMPBIN = -am__include = include -am__leading_dot = . -am__quote = -am__tar = ${AMTAR} chof - "$$tardir" -am__untar = ${AMTAR} xf - -bindir = ${exec_prefix}/bin -build = x86_64-unknown-linux-gnu -build_alias = -build_cpu = x86_64 -build_os = linux-gnu -build_vendor = unknown -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = x86_64-unknown-linux-gnu -host_alias = -host_cpu = x86_64 -host_os = linux-gnu -host_vendor = unknown -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = ${SHELL} /store/src/spice_upstream/cac_card/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -mandir = ${datarootdir}/man -mkdir_p = /bin/mkdir -p -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /store/upstream -program_transform_name = s,x,x, -psdir = ${docdir} -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -sysconfdir = ${prefix}/etc -target_alias = -top_build_prefix = -top_builddir = . -top_srcdir = . -NULL = -INCLUDES = \ - -I. \ - $(NSS_CFLAGS) \ - $(NULL) - -lib_LTLIBRARIES = libcac_card.la -libcac_card_la_LIBADD = \ - $(NSS_LIBS) \ - $(NULL) - -libcac_card_la_SOURCES = \ - cac.c \ - card_7816.c \ - event.c \ - vcard_emul_nss.c \ - vcard_emul_type.c \ - vcard.c \ - vreader.c \ - $(NULL) - -libcac_cardincludedir = $(includedir)/cac_card -libcac_cardinclude_HEADERS = \ - vcard.h \ - vcardt.h \ - card_7816.h \ - card_7816t.h \ - vreader.h \ - vreadert.h \ - vevent.h \ - eventt.h \ - vcard_emul.h \ - vcard_emul_type.h \ - vscard_common.h \ - $(NULL) - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = cac_card.pc -vscclient_SOURCES = \ - vscclient.c \ - $(NULL) - -vscclient_LDADD = \ - -lcac_card \ - $(NULL) - -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -am--refresh: - @: -$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: # $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): # $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @if test ! -f $@; then \ - rm -f stamp-h1; \ - $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ - else :; fi - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: # $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -cac_card.pc: $(top_builddir)/config.status $(srcdir)/cac_card.pc.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libcac_card.la: $(libcac_card_la_OBJECTS) $(libcac_card_la_DEPENDENCIES) - $(LINK) -rpath $(libdir) $(libcac_card_la_OBJECTS) $(libcac_card_la_LIBADD) $(LIBS) -install-binPROGRAMS: $(bin_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - for p in $$list; do echo "$$p $$p"; done | \ - sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p || test -f $$p1; \ - then echo "$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ - -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ - sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-binPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(bindir)" && rm -f $$files - -clean-binPROGRAMS: - @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -vscclient$(EXEEXT): $(vscclient_OBJECTS) $(vscclient_DEPENDENCIES) - @rm -f vscclient$(EXEEXT) - $(LINK) $(vscclient_OBJECTS) $(vscclient_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -include ./$(DEPDIR)/cac.Plo -include ./$(DEPDIR)/card_7816.Plo -include ./$(DEPDIR)/event.Plo -include ./$(DEPDIR)/vcard.Plo -include ./$(DEPDIR)/vcard_emul_nss.Plo -include ./$(DEPDIR)/vcard_emul_type.Plo -include ./$(DEPDIR)/vreader.Plo -include ./$(DEPDIR)/vscclient.Po - -.c.o: - $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< - $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -# source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -# $(COMPILE) -c $< - -.c.obj: - $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` - $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -# source='$<' object='$@' libtool=no \ -# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -# $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: - $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< - $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -# source='$<' object='$@' libtool=yes \ -# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -# $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt -install-pkgconfigDATA: $(pkgconfig_DATA) - @$(NORMAL_INSTALL) - test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ - done - -uninstall-pkgconfigDATA: - @$(NORMAL_UNINSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files -install-libcac_cardincludeHEADERS: $(libcac_cardinclude_HEADERS) - @$(NORMAL_INSTALL) - test -z "$(libcac_cardincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libcac_cardincludedir)" - @list='$(libcac_cardinclude_HEADERS)'; test -n "$(libcac_cardincludedir)" || list=; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libcac_cardincludedir)'"; \ - $(INSTALL_HEADER) $$files "$(DESTDIR)$(libcac_cardincludedir)" || exit $$?; \ - done - -uninstall-libcac_cardincludeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(libcac_cardinclude_HEADERS)'; test -n "$(libcac_cardincludedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(libcac_cardincludedir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(libcac_cardincludedir)" && rm -f $$files - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__remove_distdir) -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -dist-lzma: distdir - tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma - $(am__remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz - $(am__remove_distdir) - -dist-tarZ: distdir - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__remove_distdir) - -dist-shar: distdir - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__remove_distdir) - -dist dist-all: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 - $(am__remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lzma*) \ - lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir); chmod a+w $(distdir) - mkdir $(distdir)/_build - mkdir $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build \ - && ../configure --srcdir=.. --prefix="$$dc_install_base" \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @$(am__cd) '$(distuninstallcheck_dir)' \ - && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) \ - config.h -install-binPROGRAMS: install-libLTLIBRARIES - -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(libcac_cardincludedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ - clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-libcac_cardincludeHEADERS \ - install-pkgconfigDATA - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-binPROGRAMS install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ - uninstall-libcac_cardincludeHEADERS uninstall-pkgconfigDATA - -.MAKE: all install-am install-strip - -.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ - clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ - clean-libtool ctags dist dist-all dist-bzip2 dist-gzip \ - dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \ - distclean distclean-compile distclean-generic distclean-hdr \ - distclean-libtool distclean-tags distcleancheck distdir \ - distuninstallcheck dvi dvi-am html html-am info info-am \ - install install-am install-binPROGRAMS install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-libLTLIBRARIES \ - install-libcac_cardincludeHEADERS install-man install-pdf \ - install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ - uninstall-libcac_cardincludeHEADERS uninstall-pkgconfigDATA - - -doclean: - rm -f $(OBJS) link_test __htest.c __test.o vscclient - -# -# Test targets.... -# - -# make sure our includes are self supporting -header_test: - @for i in $(INCLUDE) ; do \ - echo "#include \"$$i\"" > __htest.c ;\ - echo "#include \"$$i\"" >> __htest.c ;\ - cat __htest.c ; \ - cc -c __htest.c ;\ - done - @rm __htest.c __htest.o - -# make sure we don't have any missing symbols -link_test: link_test.c $(OBJS) - cc -o link_test link_test.c $(OBJS) $(LDFLAGS) - -# Do all the tests at once -tests: all link_test header_test - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/Makefile.am b/Makefile.am index 5f6f4e9..beb45b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,12 +3,15 @@ NULL = INCLUDES= \ -I. \ $(NSS_CFLAGS) \ + $(PCSC_CFLAGS) \ + $(USE_PASSTHRU) \ $(NULL) lib_LTLIBRARIES = libcac_card.la libcac_card_la_LIBADD = \ $(NSS_LIBS) \ + $(PCSC_LIBS) \ $(NULL) @@ -16,6 +19,7 @@ libcac_card_la_SOURCES= \ cac.c \ card_7816.c \ event.c \ + passthru.c \ vcard_emul_nss.c \ vcard_emul_type.c \ vcard.c \ @@ -37,7 +37,7 @@ this is in vcard_emul_nss.c. 3) Emulation for new types of cards. The current implementation emulates the original DoD CAC standard with separate pki containers. This emulator lives in -cac.c. More than one smart card emulator could be included. Other cards could +cac.c. More than one card type emulator could be included. Other cards could be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc. -------------------- @@ -125,25 +125,37 @@ that the CCID reader can call are: vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return VREADER_NO_CARD. - /* not yet implemented */ - VReaderStatus vreader_get_reader_name(VReader *reader, char *name, - int *len); + const char *vreader_get_name(VReader *reader); - /* not yet implemented */ - VReaderID vreader_get_reader_id(VReader *reader); + This function returns the name of the reader. The name comes from the card + emulator level and is usually related to the name of the physical reader. + + VReaderID vreader_get_id(VReader *reader); + + This function returns the id of a reader. All readers start out with an id + of -1. The application can set the id with vreader_set_id. + + VReaderStatus vreader_get_id(VReader *reader, VReaderID id); + + This function sets the reader id. The application is responsible for making + sure that the id is unique for all readers it is actively using. - /* not yet implemented */ VReader *vreader_find_reader_by_id(VReaderID id); - Event *event_wait_next_event(); + This function returns the reader which matches the id. If two readers match, + only one is returned. The function returns NULL if the id is -1. + + Event *vevent_wait_next_vevent(); This function blocks waiting for reader and card insertion events. There will be one event for each card insertion, each card removal, each reader insertion and each reader removal. At start up, events are created for all the initial readers found, as well as all the cards that are inserted. - /* not yet implemented */ - Event *event_get_next_event(); [ not blocking ] + Event *vevent_get_next_vevent(); + + This function returns a pending event if it exists, otherwise it returns + NULL. It does not block. ---------------- Card Type Emulator: Adding a New Virtual Card Type @@ -446,9 +458,9 @@ functions: void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len); Return the virtual ATR for the card. By convention this should be the value - VCARD_ATR_PREFIX followed by several ascii bytes related to this particular - emulator. For instance the NSS emulator returns {VCARD_ATR_PREFIX, - 'N', 'S', 'S' }. Do ot return more data then *atr_len; + VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this + particular emulator. For instance the NSS emulator returns + {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len; void vcard_emul_reset(VCard *card, VCardPower power) @@ -29,7 +29,10 @@ typedef struct CACPKIAppletDataStruct { * CAC applet private data */ struct VCardAppletPrivateStruct { - CACPKIAppletData pki_data; + union { + CACPKIAppletData pki_data; + void *reserved; + } u; }; /* @@ -83,7 +86,7 @@ cac_applet_pki_reset(VCard *card, int channel) CACPKIAppletData *pki_applet = NULL; applet_private = vcard_get_current_applet_private(card, channel); ASSERT(applet_private); - pki_applet = &(applet_private->pki_data); + pki_applet = &(applet_private->u.pki_data); pki_applet->cert_buffer = NULL; if (pki_applet->sign_buffer) { @@ -107,7 +110,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **respon applet_private = vcard_get_current_applet_private(card, apdu->a_channel); ASSERT(applet_private); - pki_applet = &(applet_private->pki_data); + pki_applet = &(applet_private->u.pki_data); switch (apdu->a_ins) { case CAC_UPDATE_BUFFER: @@ -126,7 +129,8 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **respon } size = MIN(size, pki_applet->cert_buffer_len); next = MIN(255, pki_applet->cert_buffer_len - size); - *response = vcard_response_new_bytes(pki_applet->cert_buffer, size, next ? + *response = vcard_response_new_bytes(card, pki_applet->cert_buffer, size, + apdu->a_Le, next ? VCARD7816_SW1_WARNING_CHANGE : VCARD7816_SW1_SUCCESS, next); @@ -171,30 +175,8 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **respon *response = vcard_make_response(status); break; } - /* if the size is too large for a single return, use the deferred - * buffer response */ - if (size >= 256) { - buffer_response = vcard_get_buffer_response(card); - if (buffer_response) { - vcard_set_buffer_response(card, NULL); - vcard_buffer_response_delete(buffer_response); - } - buffer_response = vcard_buffer_response_new(sign_buffer, size); - if (buffer_response == NULL) { - *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - break; - } - *response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, - size & 0xff); - if (*response == NULL) { - vcard_buffer_response_delete(buffer_response); - *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } else { - vcard_set_buffer_response(card,buffer_response); - } - break; - } - *response = vcard_response_new(sign_buffer, size, VCARD7816_STATUS_SUCCESS); + *response = vcard_response_new(card, sign_buffer, size, + apdu->a_Le, VCARD7816_STATUS_SUCCESS); if (*response == NULL) { *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); } @@ -217,6 +199,28 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **respon } +static VCardStatus +cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) +{ + int size, next; + unsigned char *sign_buffer; + VCard7816Status status; + + + switch (apdu->a_ins) { + case CAC_UPDATE_BUFFER: + *response = vcard_make_response(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); + return VCARD_DONE; + case CAC_READ_BUFFER: + /* new CAC call, go ahead and use the old version for now */ + /* TODO: implement */ + *response = vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; + } + return cac_common_process_apdu(card, apdu, response); +} + + /* * TODO: if we ever want to support general CAC middleware, we will need to implement * the various containers. @@ -248,7 +252,7 @@ cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) if (pki_applet_data == NULL) { return; } - pki_applet_data = &(applet_private->pki_data); + pki_applet_data = &(applet_private->u.pki_data); if (pki_applet_data->cert != NULL) { free(pki_applet_data->cert); } @@ -271,7 +275,7 @@ cac_new_pki_applet_private(const unsigned char *cert, int cert_len, VCardKey *ke if (applet_private == NULL) { goto fail; } - pki_applet_data= &(applet_private->pki_data); + pki_applet_data= &(applet_private->u.pki_data); pki_applet_data->cert_buffer = NULL; pki_applet_data->cert_buffer_len = 0; pki_applet_data->sign_buffer = NULL; @@ -296,6 +300,7 @@ fail: if (applet_private) { cac_delete_pki_applet_private(applet_private); } + return NULL; } @@ -335,13 +340,14 @@ failure: static unsigned char cac_default_container_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; +static unsigned char cac_id_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; /* * Initialize the cac card. This is the only public function in this file. All * the rest are connected through function pointers. */ VCardStatus -cac_card_init(VCard *card, - const char *flags, +cac_card_init(VReader *reader, VCard *card, + const char *params, unsigned char * const *cert, int cert_len[], VCardKey *key[] /* adopt the keys*/, @@ -370,6 +376,15 @@ cac_card_init(VCard *card, goto failure; } vcard_add_applet(card, applet); + + /* create a default blank container applet */ + applet = vcard_new_applet(cac_applet_id_process_apdu, + NULL, cac_id_aid, + sizeof(cac_id_aid)); + if (applet == NULL) { + goto failure; + } + vcard_add_applet(card, applet); return VCARD_DONE; failure: @@ -0,0 +1,18 @@ +/* + * defines the entry point for the cac card. Only used by cac.c anc vcard_emul_type.c + */ +#ifdef CAC_H +#define CAC_H 1 +#include "vcard.h" +#include "vreader.h" +/* + * Initialize the cac card. This is the only public function in this file. All + * the rest are connected through function pointers. + */ +VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params, + unsigned char * const *cert, int cert_len[], VCardKey *key[] /* adopt the keys*/, + int cert_count); + +/* not yet implemented */ +VCardStatus cac_is_cac_card(VReader *reader); +#endif diff --git a/card_7816.c b/card_7816.c index c5875ae..dc8a717 100644 --- a/card_7816.c +++ b/card_7816.c @@ -30,7 +30,7 @@ vcard_response_set_status(VCardResponse *response, VCard7816Status status) * set the status bytes in a response buffer */ static void -vcard_response_set_status_bytes(VCardResponse *response, +vcard_response_set_status_bytes(VCardResponse *response, unsigned char sw1, unsigned char sw2) { response->b_status = sw1 << 8 | sw2; @@ -44,7 +44,7 @@ vcard_response_set_status_bytes(VCardResponse *response, * allocate a VCardResponse structure, plus space for the data buffer, and * set up everything but the resonse bytes. */ -static VCardResponse * +VCardResponse * vcard_response_new_data(unsigned char *buf, int len) { VCardResponse *new_response; @@ -65,13 +65,40 @@ vcard_response_new_data(unsigned char *buf, int len) return new_response; } +static VCardResponse * +vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) +{ + VCardResponse *response; + VCardBufferResponse *buffer_response; + + buffer_response =vcard_get_buffer_response(card); + if (buffer_response) { + vcard_set_buffer_response(card, NULL); + vcard_buffer_response_delete(buffer_response); + } + buffer_response = vcard_buffer_response_new(buf, len); + if (buffer_response == NULL) { + return NULL; + } + response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, len > 255 ? 0 : len); + if (response == NULL) { + NULL; + } + vcard_set_buffer_response(card,buffer_response); + return response; +} + /* * general buffer to hold results from APDU calls */ VCardResponse * -vcard_response_new(unsigned char *buf, int len, VCard7816Status status) +vcard_response_new(VCard *card, unsigned char *buf, int len, int Le, VCard7816Status status) { VCardResponse *new_response; + + if (len > Le) { + return vcard_init_buffer_response(card, buf, len); + } new_response = vcard_response_new_data(buf,len); if (new_response == NULL) { return NULL; @@ -84,10 +111,14 @@ vcard_response_new(unsigned char *buf, int len, VCard7816Status status) * general buffer to hold results from APDU calls */ VCardResponse * -vcard_response_new_bytes(unsigned char *buf, int len, +vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, unsigned char sw1, unsigned char sw2) { VCardResponse *new_response; + + if (len > Le) { + return vcard_init_buffer_response(card, buf, len); + } new_response = vcard_response_new_data(buf,len); if (new_response == NULL) { return NULL; @@ -111,7 +142,7 @@ vcard_response_new_status(VCard7816Status status) new_response->b_data = &new_response->b_sw1; new_response->b_len = 0; new_response->b_total_len = 2; - new_response->b_type == VCARD_MALLOC_STRUCT; + new_response->b_type = VCARD_MALLOC_STRUCT; vcard_response_set_status(new_response,status); return new_response; } @@ -131,7 +162,7 @@ vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) new_response->b_data = &new_response->b_sw1; new_response->b_len = 0; new_response->b_total_len = 2; - new_response->b_type == VCARD_MALLOC_STRUCT; + new_response->b_type = VCARD_MALLOC_STRUCT; vcard_response_set_status_bytes(new_response, sw1, sw2); return new_response; } @@ -176,7 +207,7 @@ vcard_response_delete(VCardResponse *response) */ static VCard7816Status vcard_apdu_set_class(VCardAPDU *apdu) { - apdu->a_channel = 0; + apdu->a_channel = 0; apdu->a_secure_messaging = 0; apdu->a_type = apdu->a_cla & 0xf0; apdu->a_gen_type = VCARD_7816_ISO; @@ -237,7 +268,7 @@ vcard_apdu_set_length(VCardAPDU *apdu) case 1: /* 2S only return values apdu */ /* zero maps to 256 here */ - apdu->a_Le = apdu->a_header->ah_Le ? + apdu->a_Le = apdu->a_header->ah_Le ? apdu->a_header->ah_Le : 256; return VCARD7816_STATUS_SUCCESS; default: @@ -258,7 +289,7 @@ vcard_apdu_set_length(VCardAPDU *apdu) return VCARD7816_STATUS_SUCCESS; } if (Le == 0) { - /* reserved for future use, probably for next time we need + /* reserved for future use, probably for next time we need * to extend the lengths */ return VCARD7816_STATUS_ERROR_WRONG_LENGTH; } @@ -478,7 +509,7 @@ vcard_make_response(VCard7816Status status) case VCARD7816_STATUS_ERROR_GENERAL: return VCARD_RESPONSE_GET_STATIC(VCARD7816_STATUS_ERROR_GENERAL); default: - /* we don't know this status code, create a response buffer to + /* we don't know this status code, create a response buffer to * hold it */ response = vcard_response_new_status(status); if (response == NULL) { @@ -562,12 +593,17 @@ vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response /* side effect, deselect the current applet if no applet has been found */ current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); vcard_select_applet(card, apdu->a_channel, current_applet); - *response = vcard_make_response(current_applet != NULL ? - VCARD7816_STATUS_SUCCESS : - VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); + if (current_applet) { + unsigned char *aid; + int aid_len; + aid = vcard_applet_get_aid(current_applet, &aid_len); + *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, VCARD7816_STATUS_SUCCESS); + } else { + *response = vcard_make_response(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); + } break; - case VCARD7816_INS_VERIFY: + case VCARD7816_INS_VERIFY: if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { *response = vcard_make_response(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); } else { @@ -580,7 +616,7 @@ vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response if (count > 0xf) { count = 0xf; } - *response = vcard_response_new_status_bytes(VCARD7816_SW1_WARNING_CHANGE, + *response = vcard_response_new_status_bytes(VCARD7816_SW1_WARNING_CHANGE, 0xc0 | count); if (*response == NULL) { *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); @@ -601,8 +637,9 @@ vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response } bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); - *response = vcard_response_new_bytes(buffer_response->current, bytes_to_copy, - next_byte_count ? + *response = vcard_response_new_bytes(card, buffer_response->current, bytes_to_copy, + apdu->a_Le, + next_byte_count ? VCARD7816_SW1_RESPONSE_BYTES: VCARD7816_SW1_SUCCESS, next_byte_count); buffer_response->current += bytes_to_copy; @@ -639,6 +676,7 @@ VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) { VCardStatus status; + VCardBufferResponse *buffer_response; /* first handle any PTS commands, which aren't really APDU's */ if (apdu->a_type == VCARD_7816_PTS) { @@ -648,6 +686,14 @@ vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) (*response)->b_total_len = (*response)->b_len; return VCARD_DONE; } + buffer_response = vcard_get_buffer_response(card); + if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { + /* clear out buffer_response, return an error */ + vcard_set_buffer_response(card,NULL); + vcard_buffer_response_delete(buffer_response); + *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); + return VCARD_DONE; + } status = vcard_process_applet_apdu(card, apdu, response); if (status != VCARD_NEXT) { @@ -658,6 +704,10 @@ vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) return vcard7816_file_system_process_apdu(card,apdu,response); case VCARD_VM: return vcard7816_vm_process_apdu(card,apdu,response); + case VCARD_DIRECT: + /* if we are type direct, then the applet should handle everything */ + assert("VCARD_DIRECT: applet failure"); + break; } *response = vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); return VCARD_DONE; diff --git a/card_7816.h b/card_7816.h index 64faa4f..dcaea04 100644 --- a/card_7816.h +++ b/card_7816.h @@ -12,9 +12,10 @@ * constructors for VCardResponse's */ /* response from a return buffer and a status */ -VCardResponse *vcard_response_new(unsigned char *buf, int len, VCard7816Status status); +VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len, + int Le, VCard7816Status status); /* response from a return buffer and status bytes */ -VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len, +VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, unsigned char sw1, unsigned char sw2); /* response from just status bytes */ VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2); @@ -23,9 +24,13 @@ VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, unsigned char * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */ VCardResponse *vcard_make_response(VCard7816Status status); +/* create a raw response (status has already been encoded */ +VCardResponse *vcard_response_new_data(unsigned char *buf, int len); -/* + + +/* * destructor for VCardResponse. * Can be called with a NULL response */ @@ -36,7 +41,7 @@ void vcard_response_delete(VCardResponse *response); */ VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len, unsigned short *status); -/* +/* * destructor for VCardAPDU * Can be called with a NULL apdu */ @@ -45,7 +50,7 @@ void vcard_apdu_delete(VCardAPDU *apdu); /* * Constructor for a VCardApplet */ -VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function, +VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function, VCardResetApplet applet_reset_function, unsigned char *aid, int aid_len); diff --git a/configure.ac b/configure.ac index 1e42e1e..8fb910c 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,20 @@ else fi ]) +dnl handle the passthru option. passthru allows you to access the cards directly +AC_ARG_ENABLE(passthru, +AC_HELP_STRING([--enable-passthru], [allow passthru mode]), +set_passthru="$enableval",) + +if test "${set_passthru}" = "yes" ; then +PKG_CHECK_MODULES(PCSC,libpcsclite) +AC_SUBST(PCSC_CFLAGS) +AC_SUBST(PCSC_LIBS) +CAC_CARD_REQUIRES+=" pcsc-lite" +USE_PASSTHRU=-DUSE_PASSTHRU +AC_SUBST(USE_PASSTHRU) +fi + AC_SUBST(CAC_COMMON_SRCDIR) AC_SUBST(CAC_CARD_REQUIRES) AC_SUBST(CAC_NONPKGCONFIG_CFLAGS) @@ -102,3 +102,14 @@ vevent_wait_next_vevent() return vevent; } +VEvent * +vevent_get_next_vevent() +{ + VEvent *vevent; + + MUTEX_LOCK(vevent_queue_lock); + vevent = vevent_dequeue_vevent(); + MUTEX_UNLOCK(vevent_queue_lock); + return vevent; +} + @@ -16,6 +16,11 @@ License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +/* + * This header file provides a way of mapping windows and linux thread calls to a set of macros. + * Ideally this would be shared by whatever subsystem we link with. + */ + #ifndef _H_MUTEX #define _H_MUTEX #ifdef _WIN32 @@ -28,16 +33,25 @@ typedef CONDITION_VARIABLE condition_t; #define CONDITION_INIT(cond) InitializeConditionVariable(&cond) #define CONDITION_WAIT(cond,mutex) SleepConditionVariableCS(&cond,&mutex,INFINTE) #define CONDITION_NOTIFY(cond) WakeConditionVariable(&cond) +typedef DWORD thread_t; +typedef HANDLE thread_status_t; +#define THREAD_CREATE(tid, func, arg) \ + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, &tid) +#define THREAD_SUCCESS(status) ((status) != NULL) #else #include <pthread.h> typedef pthread_mutex_t mutex_t; -#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL); +#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL) #define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex) #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex) typedef pthread_cond_t condition_t; -#define CONDITION_INIT(cond) pthread_cond_init(&cond, NULL); +#define CONDITION_INIT(cond) pthread_cond_init(&cond, NULL) #define CONDITION_WAIT(cond,mutex) pthread_cond_wait(&cond,&mutex) #define CONDITION_NOTIFY(cond) pthread_cond_signal(&cond) +typedef pthread_t thread_t; +typedef int thread_status_t; +#define THREAD_CREATE(tid, func, arg) pthread_create(&tid, NULL, func, arg) +#define THREAD_SUCCESS(status) ((status) == 0) #endif #endif // _H_MUTEX diff --git a/passthru.c b/passthru.c new file mode 100644 index 0000000..bc16013 --- /dev/null +++ b/passthru.c @@ -0,0 +1,589 @@ +/* + * implement the applets for the CAC card. + */ +#ifdef USE_PASSTHRU +#include "vcard.h" +#include "vcard_emul.h" +#include "card_7816.h" +#include "vreader.h" +#include "mutex.h" +#include "vcard_emul.h" +#include "passthru.h" +#include <stdlib.h> +#include <string.h> +#include <pcsclite.h> + +/* + * Passthru applet private data + */ +struct VCardAppletPrivateStruct { + char *reader_name; + /* pcsc-lite parameters */ + SCARDHANDLE hCard; + DWORD hProtocol; + SCARD_IO_REQUEST *send_io; + unsigned char atr[MAX_ATR_SIZE]; + int atr_len; +}; + +static SCARDCONTEXT global_context = 0; + +#define MAX_RESPONSE_LENGTH 261 /*65537 */ +/* + * handle all the APDU's that are common to all CAC applets + */ +static VCardStatus +passthru_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) +{ + LONG rv; + unsigned char buf[MAX_RESPONSE_LENGTH]; + DWORD len = MAX_RESPONSE_LENGTH; + VCardAppletPrivate *applet_private = NULL; + SCARD_IO_REQUEST receive_io; + + applet_private = vcard_get_current_applet_private(card, 0); + if (applet_private == NULL) { + *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); + return VCARD_DONE; + } + + rv = SCardTransmit(applet_private->hCard,applet_private->send_io, + apdu->a_data, apdu->a_len, &receive_io, buf, &len); + if (rv != SCARD_S_SUCCESS) { + *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); + return VCARD_DONE; + } + + *response = vcard_response_new_data(buf,len); + if (*response == NULL) { + *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } else { + (*response)->b_total_len = (*response)->b_len; + } + return VCARD_DONE; +} + +static void +passthru_card_set_atr(VCard *card, unsigned char *atr, int atr_len) +{ + VCardAppletPrivate *applet_private = NULL; + applet_private = vcard_get_current_applet_private(card, 0); + if (applet_private == NULL) { + return; + } + applet_private->atr_len = MIN(atr_len, sizeof(applet_private->atr)); + memcpy(applet_private->atr, atr, applet_private->atr_len); +} + +static void passthru_card_get_atr(VCard *card, unsigned char *atr, int *atr_len) +{ + VCardAppletPrivate *applet_private = NULL; + SCARD_READERSTATE *state; + + applet_private = vcard_get_current_applet_private(card, 0); + if ((applet_private == NULL) || (applet_private->atr_len == 0)) { + vcard_emul_get_atr(card, atr, atr_len); + return; + } + *atr_len = MIN(applet_private->atr_len, *atr_len); + memcpy(atr,applet_private->atr,*atr_len); + return; +} + +/* + * resest the inter call state between applet selects + */ +static VCardStatus +passthru_reset(VCard *card, int channel) +{ + return VCARD_DONE; +} + +static VCardStatus +passthru_pcsc_lite_init() +{ + LONG rv; + if (global_context != 0) { + return VCARD_DONE; + } + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &global_context); + if (rv != SCARD_S_SUCCESS) { + return VCARD_FAIL; + } + return VCARD_DONE; +} + +/* + * match if s1 is completely contained in s2 + */ +static int +string_match(const char *s1, const char *s2) +{ + int len = strlen(s1); + const char *start; + + for (start = strchr(s2, *s1); start; start = strchr(start+1, *s1)) { + if (strncmp(start, s1, len) == 0) { + return 1; + } + } + return 0; +} + + +/* + * Look for the reader that best matches the name for VReader + */ +static char * +passthru_get_reader_name(VReader *reader) +{ + const char *reader_name = vreader_get_name(reader); + char *reader_list = NULL; + char *reader_entry = NULL; + char *reader_match = NULL; + DWORD reader_string_length; + VCardStatus status; + LONG rv; + + if (reader_name == NULL) { + return NULL; + } + + status = passthru_pcsc_lite_init(); + if (status != VCARD_DONE) { + return NULL; + } + + + /* find the existing reader names */ + rv = SCardListReaders(global_context, NULL, NULL, &reader_string_length); + if (rv != SCARD_S_SUCCESS) { + return NULL; + } + reader_list = (char *)malloc(reader_string_length); + rv = SCardListReaders(global_context, NULL, reader_list, &reader_string_length); + if (rv != SCARD_S_SUCCESS) { + goto cleanup; + } + + /* match that name */ + for (reader_entry= reader_list;*reader_entry; + reader_entry += strlen(reader_entry)+1) { + if (string_match(reader_entry, reader_name)) { + reader_match = strdup(reader_entry); + break; + } + } +cleanup: + if (reader_list) { + free(reader_list); + } + return reader_match; +} + + +/* + * utilities for creating and destroying the private applet data + */ +static void +passthru_delete_applet_private(VCardAppletPrivate *applet_private) +{ + if (applet_private == NULL) { + return; + } + if (applet_private->hCard) { + SCardDisconnect(applet_private->hCard,SCARD_LEAVE_CARD); + } + if (applet_private->reader_name != NULL) { + free(applet_private->reader_name); + } + free(applet_private); +} + +static VCardAppletPrivate * +passthru_new_applet_private(VReader *reader) +{ + VCardAppletPrivate *applet_private = NULL; + LONG rv; + + applet_private = (VCardAppletPrivate *)malloc(sizeof(VCardAppletPrivate)); + + if (applet_private == NULL) { + goto fail; + } + applet_private->hCard = 0; + applet_private->reader_name = NULL; + + applet_private->reader_name = passthru_get_reader_name(reader); + if (applet_private->reader_name == NULL) { + goto fail; + } + + rv = SCardConnect( global_context, applet_private->reader_name, + SCARD_SHARE_DIRECT, SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, &applet_private->hCard, + &applet_private->hProtocol); + if (rv != SCARD_S_SUCCESS) { + goto fail; + } + + if (applet_private->hProtocol == SCARD_PROTOCOL_T0) { + applet_private->send_io = SCARD_PCI_T0; + } else { + applet_private->send_io = SCARD_PCI_T1; + } + applet_private->atr_len = 0; + return applet_private; + +fail: + if (applet_private) { + passthru_delete_applet_private(applet_private); + } + return NULL; +} + + +/* + * create a new applet which links to our override function. + */ +static VCardApplet * +passthru_new_applet(VReader *reader) +{ + VCardAppletPrivate *applet_private = NULL; + VCardApplet *applet = NULL; + unsigned char passthru_aid[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int passthru_aid_len = sizeof (passthru_aid); + + applet_private = passthru_new_applet_private(reader); + if (applet_private == NULL) { + goto failure; + } + applet = vcard_new_applet(passthru_process_apdu, passthru_reset, + passthru_aid, passthru_aid_len); + if (applet == NULL) { + goto failure; + } + vcard_set_applet_private(applet, applet_private, + passthru_delete_applet_private); + applet_private = NULL; + + return applet; + +failure: + if (applet_private != NULL) { + passthru_delete_applet_private(applet_private); + } + return NULL; +} + + + +/* + * Initialize the card. This is the only 'card type emulator' portion of this + * the rest are connected through function pointers. + */ +VCardStatus +passthru_card_init(VReader *vreader, VCard *card, + const char *flags, + unsigned char * const *cert, + int cert_len[], + VCardKey *key[] /* adopt the keys*/, + int cert_count) +{ + int i; + VCardApplet *applet; + + /* Don't do soft emulation of the 7816, pass everything to the card */ + vcard_set_type(card,VCARD_DIRECT); + + applet = passthru_new_applet(vreader); + if (applet == NULL) { + goto failure; + } + + vcard_add_applet(card, applet); + + /* we are adopting the keys, so free them now (since we don't use them) */ + for (i=0; i < cert_count; i++) { + vcard_emul_delete_key(key[i]); + } + + return VCARD_DONE; + +failure: + return VCARD_FAIL; +} + +/* + * + * + * + * Begin passthru_emul code. This emulator only works with the passthru card type. + * + * + * + * + */ + +/* + * Get the state entry that matches this reader. If none found, return NULL + */ +static SCARD_READERSTATE_A * +passthru_get_reader_state(SCARD_READERSTATE_A *reader_states, int reader_count, char *name) +{ + int i; + + for (i=0; i < reader_count; i++) { + if (name== NULL && reader_states[i].szReader == NULL) { + return &reader_states[i]; + } + if (name == NULL) continue; + if (reader_states[i].szReader == NULL) continue; + if (strcmp(name, reader_states[i].szReader) == 0) { + return &reader_states[i]; + } + } + return NULL; +} + +/* + * find a card slot that has been cleared out + */ +static SCARD_READERSTATE_A * +passthru_get_blank_reader(SCARD_READERSTATE_A *reader_states, int reader_count) +{ + return passthru_get_reader_state(reader_states, reader_count, NULL); +} + + +/* + * This is the main work of the emulator, handling the thread that looks for changes in the + * readers and the cards. + */ +static void * +passthru_emul_event_thread(void *args) +{ + char *reader_list = NULL; + int reader_list_len = 0; + SCARD_READERSTATE_A *reader_states = NULL; + int reader_count = 0; /* number of active readers */ + int max_reader_count = 0; /* size of the reader_state array (including inactive readers) */ + LONG rv; + int timeout=1000; + int i; + + do { + /* variables to hold on to our new values until we are ready to replace our old values */ + char *new_reader_list = NULL; + int new_reader_list_len = 0; + int new_reader_count = 0; + + /* other temps */ + char * reader_entry; + VReader *reader; + + /* + * First check to see if the reader list has changed + */ + rv = SCardListReaders(global_context, NULL, NULL, &new_reader_list_len); + if (rv != SCARD_S_SUCCESS) { + goto next; + } + /* + * If the names have changed, we need to update our list and states. + * This is where we detect reader insertions and removals. + */ + if (new_reader_list_len != reader_list_len) { + /* update the list */ + new_reader_list = (char *)malloc(new_reader_list_len); + if (new_reader_list == NULL) { + goto next; + } + rv = SCardListReaders(global_context, NULL, new_reader_list, &new_reader_list_len); + if (rv != SCARD_S_SUCCESS) { + free(new_reader_list); + goto next; + } + /* clear out our event state */ + for (i=0; i < reader_count; i++) { + reader_states[i].dwEventState = 0; + } + /* count the readers and mark the ones that are still with us */ + for (reader_entry = new_reader_list; *reader_entry; + reader_entry += strlen(reader_entry)+1) { + SCARD_READERSTATE_A *this_state; + new_reader_count++; + /* if the reader is still on the list, mark it present */ + this_state = passthru_get_reader_state(reader_states, reader_count, + reader_entry); + if (this_state) { + this_state->dwEventState = SCARD_STATE_PRESENT; + } + } + /* eject any removed readers */ + for (i=0; i < reader_count; i++) { + if (reader_states[i].dwEventState == SCARD_STATE_PRESENT) { + reader_states[i].dwEventState = 0; + continue; + } + reader = vreader_get_reader_by_name(reader_states[i].szReader); + vreader_remove_reader(reader); + vreader_free(reader); + reader_states[i].szReader = NULL; + } + /* handle the shrinking list */ + if (new_reader_count < reader_count) { + /* fold all the valid entries at the end of our reader_states array up into + * those locations vacated by ejected readers. */ + for (i=reader_count-1; i < (new_reader_count -1); i--) { + if (reader_states[i].szReader) { + SCARD_READERSTATE_A *blank_reader; + blank_reader = passthru_get_blank_reader(reader_states, + new_reader_count); + assert(blank_reader); + *blank_reader = reader_states[i]; + reader_states[i].szReader = NULL; + } + } + } + /* handle the growing list */ + if (new_reader_count > max_reader_count) { + SCARD_READERSTATE_A *new_reader_states; + + /* grow the list */ + new_reader_states = (SCARD_READERSTATE_A *)realloc(reader_states, + sizeof(SCARD_READERSTATE_A)*new_reader_count); + if (new_reader_states) { + /* successful, update our current state */ + reader_states = new_reader_states; + max_reader_count = new_reader_count; + } else { + new_reader_count = max_reader_count; /* couldn't get enough space to handle + * all the new readers */ + } + /* mark our new entries as empty */ + for (i=reader_count; i > new_reader_count; i++) { + reader_states[i].szReader = NULL; + } + } + /* now walk the reader list, updating the state */ + for (reader_entry = new_reader_list; *reader_entry; + reader_entry += strlen(reader_entry)+1) { + SCARD_READERSTATE_A *this_state; + this_state = passthru_get_reader_state(reader_states, new_reader_count, + reader_entry); + if (this_state) { + /* replace the old copy of the string with the new copy. This will allow us + * to free reader_list at the end */ + reader_states->szReader = reader_entry; + continue; + } + /* this is a new reader, add it to the list */ + this_state = passthru_get_blank_reader(reader_states, new_reader_count); + if (!this_state) { + continue; /* this can happen of we couldn't get enough slots in the grow list */ + } + this_state->szReader = reader_entry; + this_state->dwCurrentState = SCARD_STATE_UNAWARE; + reader = vreader_new(reader_entry, NULL, NULL); + if (reader) { + vreader_add_reader(reader); + } + vreader_free(reader); + } + /* finally update our current variables */ + free(reader_list); + reader_list = new_reader_list; + reader_list_len = new_reader_list_len; + reader_count = new_reader_count; + } +next: + rv = SCardGetStatusChange(global_context, timeout, reader_states, reader_count); + if (rv == SCARD_E_TIMEOUT) { + continue; /* check for new readers */ + } + if (rv != SCARD_S_SUCCESS) { + VCardStatus status; + /* try resetting the pcsc_lite subsystem */ + /* SCardReleaseContext(global_context); + printf("***** SCard failure %x\n", rv); + global_context = 0; /* should close it */ + status = passthru_pcsc_lite_init(); + /*assert(status == CARD_DONE); */ + sleep(1); + continue; + } + /* deal with card insertion/removal */ + for (i=0; i < reader_count ; i++) { + if ((reader_states[i].dwEventState & SCARD_STATE_CHANGED) == 0) { + continue; + } + reader_states[i].dwCurrentState = reader_states[i].dwEventState; + reader = vreader_get_reader_by_name(reader_states[i].szReader); + if (reader == NULL) { + continue; + } + if (reader_states[i].dwEventState & SCARD_STATE_EMPTY) { + if (vreader_card_is_present(reader) == VREADER_OK) { + vreader_insert_card(reader, NULL); + } + } + if (reader_states[i].dwEventState & SCARD_STATE_PRESENT) { + VCard *card; + VCardStatus status = VCARD_FAIL; + /* if there already was a card present, eject it before we insert the new one */ + if (vreader_card_is_present(reader) == VREADER_OK) { + vreader_insert_card(reader, NULL); + } + + card = vcard_new(NULL, NULL); + if (card != NULL) { + status = passthru_card_init(reader, card, "", NULL, NULL, NULL, 0); + passthru_card_set_atr(card, reader_states[i].rgbAtr, reader_states[i].cbAtr); + vcard_set_atr_func(card, passthru_card_get_atr); + } + if (status == VCARD_DONE) { + vreader_insert_card(reader, card); + } + vcard_free(card); + } + vreader_free(reader); + } + + } while (1); + return NULL; +} + +/* + * Initializing the passthru emul is simply initializing pcsc-lite and launching the event + * thread. + */ +VCardStatus +passthru_emul_init(VCardEmulOptions *options) +{ + thread_t tid; + thread_status_t tstatus; + VCardStatus status; + + vreader_init(); + vevent_queue_init(); + + status = passthru_pcsc_lite_init(); + if (status != VCARD_DONE) { + return status; + } + + /* launch reader thread */ + tstatus = THREAD_CREATE(tid, passthru_emul_event_thread, NULL); + if (!THREAD_SUCCESS(tstatus)) { + return VCARD_FAIL; + } + return VCARD_DONE; +} + + +VCardEmulOptions * +passthru_emul_options(const char *args) +{ + return NULL; +} +#endif diff --git a/passthru.h b/passthru.h new file mode 100644 index 0000000..b62123d --- /dev/null +++ b/passthru.h @@ -0,0 +1,50 @@ +/* + * passthru card type emulator and passhtru emulator. + * + * passhtru card type emulator can be used with other low level card emulators, + * as long as they can recognize card insertion and removals. + * + * the passthru vcard_emulator, can only use passthru card types. + * + * Be careful using passthru. 1) passthru does not know the locking state of + * the card from the guest side, and thus does not try to get locks. This means + * client access can interfere with the guest use of the card. 2) passthru does + * not provide the guest and client unique login states for the card. That + * means that it is possible for the guest to access private data on the + * card without authenticating. You have been warned. + * + * Passthru is most useful in the following cases: 1) provisioning. Card type + * emulators cannot emulate the open platform secure connections because the + * client software does not have access to the global platform keys on the + * card. Passthru drives these apdu's directly to the card. 2) odd cards. If + * you have guest software the knows how to access the card, but no client + * side PKCS #11 module, then passthru can provide access to those cards. + */ + +#ifndef PASSTHRU_H +#define PASSTHRU_H 1 + +#include "vcard.h" +#include "vcard_emul.h" +#include "vreader.h" + +/* + * Initialize the card. This is the only 'card type emulator' portion of this + * the rest are connected through function pointers. NOTE: certs are ignorned, + * keys are freed. + */ +VCardStatus passthru_card_init(VReader *vreader, VCard *card, + const char *flags, unsigned char * const *cert, int cert_len[], + VCardKey *key[], int cert_count); + +/* + * Use this instead of vcard_emul_init to initialize passthru. + * passthru is the exception to the rule that only one emul can be compiled + * at once. NOTE: you can still have only one emul active at once. The + * passhtru card type emul, however can be used with other emuls. + * + * passthru does not support other card type emuls. + */ +VCardStatus passthru_emul_init(VCardEmulOptions *options); +VCardEmulOptions *passthru_emul_options(const char *args); +#endif @@ -25,6 +25,7 @@ struct VCardStruct { VCardType type; VCardEmul *vcard_private; VCardEmulFree vcard_private_free; + VCardGetAtr vcard_get_atr; }; VCardBufferResponse * @@ -67,15 +68,28 @@ vcard_buffer_response_delete(VCardBufferResponse *buffer_response) void vcard_reset(VCard *card, VCardPower power) { - card->current_applet[0] = NULL; - card->current_applet[1] = NULL; - card->current_applet[2] = NULL; - card->current_applet[3] = NULL; + int i; + VCardApplet *applet = NULL; + + if (card->type == VCARD_DIRECT) { + /* select the last applet */ + VCardApplet *current_applet = NULL; + for (current_applet = card->applet_list; current_applet; + current_applet = current_applet->next) { + applet = current_applet; + } + } + for (i=0; i < MAX_CHANNEL; i++) { + card->current_applet[i] = applet; + } if (card->vcard_buffer_response) { vcard_buffer_response_delete(card->vcard_buffer_response); card->vcard_buffer_response = NULL; } vcard_emul_reset(card, power); + if (applet) { + applet->reset_applet(card, 0); + } } /* applet utilities */ @@ -130,7 +144,7 @@ vcard_delete_applet(VCardApplet *applet) /* accessor */ void -vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, +vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, VCardAppletPrivateFree private_free) { if (applet->applet_private_free) { @@ -155,6 +169,7 @@ vcard_new(VCardEmul *private, VCardEmulFree private_free) new_card->type = VCARD_VM; new_card->vcard_private = private; new_card->vcard_private_free = private_free; + new_card->vcard_get_atr = NULL; new_card->reference_count = 1; return new_card; } @@ -197,17 +212,41 @@ vcard_free(VCard *vcard) return; } +void +vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len) +{ + if (vcard->vcard_get_atr) { + (*vcard->vcard_get_atr)(vcard, atr, atr_len); + return; + } + vcard_emul_get_atr(vcard, atr, atr_len); +} + +void +vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr) +{ + card-> vcard_get_atr = vcard_get_atr; +} + VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet) { applet->next = card->applet_list; card->applet_list = applet; + /* if our card-type is direct, always call the applet */ + if (card->type == VCARD_DIRECT) { + int i; + + for (i=0; i < MAX_CHANNEL; i++) { + card->current_applet[i] = applet; + } + } return VCARD_DONE; } /* - * manage applets + * manage applets */ VCardApplet * vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) @@ -226,6 +265,17 @@ vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) return current_applet; } +unsigned char * +vcard_applet_get_aid(VCardApplet *applet, int *aid_len) +{ + if (applet == NULL) { + return NULL; + } + *aid_len = applet->aid_len; + return applet->aid; +} + + void vcard_select_applet(VCard *card, int channel, VCardApplet *applet) { @@ -267,7 +317,7 @@ vcard_get_buffer_response(VCard *card) return card->vcard_buffer_response; } -void +void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer) { card->vcard_buffer_response = buffer; @@ -45,6 +45,8 @@ VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len); void vcard_select_applet(VCard *card, int channel, VCardApplet *applet); /* get the card type specific private data on the given channel */ VCardAppletPrivate * vcard_get_current_applet_private(VCard *card, int channel); +/* fetch the applet's id */ +unsigned char *vcard_applet_get_aid(VCardApplet *applet, int *aid_len); /* process the apdu for the current selected applet/file */ VCardStatus vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, @@ -58,6 +60,9 @@ VCard * vcard_new(VCardEmul *_private, VCardEmulFree private_free); VCard * vcard_reference(VCard *); /* destructor (reference counted) */ void vcard_free(VCard *); +/* get the atr from the card */ +void vcard_get_atr(VCard *card, unsigned char *atr, int *atr_len); +void vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr); /* accessor functions for the response buffer */ VCardBufferResponse *vcard_get_buffer_response(VCard *card); diff --git a/vcard_emul.h b/vcard_emul.h index f8bc8e3..ddd9e65 100644 --- a/vcard_emul.h +++ b/vcard_emul.h @@ -22,22 +22,9 @@ typedef enum { VCARD_EMUL_FAIL } VCardEmulError; +/* options are emul specific. call card_emul_parse_args to change a string + * To an options struct */ typedef struct VCardEmulOptionsStruct VCardEmulOptions; -typedef struct VirtualReaderOptionsStruct VirtualReaderOptions; - -struct VirtualReaderOptionsStruct { - char *name; - VCardEmulType card_type; - char **cert_name; - int cert_count; -}; - -struct VCardEmulOptionsStruct { - void *nss_db; - VirtualReaderOptions *vreader; - int vreader_count; - VCardEmulType hw_card_type; -}; /* * Login functions @@ -59,5 +46,7 @@ VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key, void vcard_emul_reset(VCard *card, VCardPower power); void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len); +VCardEmulOptions *vcard_emul_options(const char *args); VCardEmulError vcard_emul_init(const VCardEmulOptions *options); +void vcard_emul_usage(void); #endif diff --git a/vcard_emul_nss.c b/vcard_emul_nss.c index e6a9435..fa93630 100644 --- a/vcard_emul_nss.c +++ b/vcard_emul_nss.c @@ -35,14 +35,41 @@ struct VCardKeyStruct { SECKEYPrivateKey *key; }; + +typedef struct VirtualReaderOptionsStruct VirtualReaderOptions; + struct VReaderEmulStruct { PK11SlotInfo *slot; VCardEmulType default_type; + char *type_params; PRBool present; int series; VCard *saved_vcard; }; +/* + * NSS Specific options + */ +struct VirtualReaderOptionsStruct { + char *name; + char *vname; + VCardEmulType card_type; + char *type_params; + char **cert_name; + int cert_count; +}; + +struct VCardEmulOptionsStruct { + void *nss_db; + VirtualReaderOptions *vreader; + int vreader_count; + VCardEmulType hw_card_type; + char *hw_type_params; + PRBool use_hw; +}; + +static int nss_emul_init = 0; + /* if we have more that just the slot, define * VCardEmulStruct here */ @@ -100,7 +127,7 @@ vcard_emul_delete_card(VCardEmul *vcard_emul) } static PK11SlotInfo * -vcard_emul_get_slot(VCard *card) +vcard_emul_card_get_slot(VCard *card) { /* note, the card is holding the reference, no need to get another one */ return (PK11SlotInfo *)vcard_get_private(card); @@ -133,7 +160,7 @@ vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) void vcard_emul_delete_key(VCardKey *key) { - if (key == NULL) { + if (!nss_emul_init || (key == NULL)) { return; } if (key->key) { @@ -191,14 +218,15 @@ vcard_emul_map_error(int error) VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key, unsigned char *buffer, int buffer_size) { - SECKEYPrivateKey *priv_key = vcard_emul_get_nss_key(key); + SECKEYPrivateKey *priv_key; int signature_len; SECStatus rv; - if (key == NULL) { + if ((!nss_emul_init) || (key == NULL)) { /* couldn't get the key, indicate that we aren't logged in */ return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; } + priv_key = vcard_emul_get_nss_key(key); /* * this is only true of the rsa signature @@ -229,11 +257,15 @@ vcard_emul_get_login_count(VCard *card) VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin, int pin_len) { - PK11SlotInfo *slot = vcard_emul_get_slot(card); + PK11SlotInfo *slot; char *pin_string = NULL; int i; SECStatus rv; + if (!nss_emul_init) { + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; + } + slot = vcard_emul_card_get_slot(card); /* We depend on the PKCS #11 module internal login state here because we * create a separate process to handle each guest instance. If we needed to handle multiple * guests from one process, then we would need to keep a lot of extra state in our card @@ -263,9 +295,15 @@ vcard_emul_login(VCard *card, unsigned char *pin, int pin_len) void vcard_emul_reset(VCard *card, VCardPower power) { - PK11SlotInfo *slot = vcard_emul_get_slot(card); + PK11SlotInfo *slot; + + if (!nss_emul_init) { + return; + } + /* if we reset the card (either power on or power off), we loose our login state */ /* TODO: we may also need to send insertion/removal events? */ + slot = vcard_emul_card_get_slot(card); (void)PK11_Logout(slot); return; } @@ -297,7 +335,7 @@ vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot) * create a new reader emul */ static VReaderEmul * -vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type) +vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params) { VReaderEmul *new_reader_emul; @@ -308,6 +346,7 @@ vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type) new_reader_emul->slot = PK11_ReferenceSlot(slot); new_reader_emul->default_type = type; + new_reader_emul->type_params = strdup(params); new_reader_emul->present = PR_FALSE; new_reader_emul->series = 0; new_reader_emul->saved_vcard = NULL; @@ -323,11 +362,14 @@ vreader_emul_delete(VReaderEmul *vreader_emul) if (vreader_emul->slot) { PK11_FreeSlot(vreader_emul->slot); } + if (vreader_emul->type_params) { + free(vreader_emul->type_params); + } free(vreader_emul); } /* - * TODO: move this to emulater non-specific directory + * TODO: move this to emulater non-specific file */ static VCardEmulType vcard_emul_get_type(VReader *vreader) @@ -341,13 +383,40 @@ vcard_emul_get_type(VReader *vreader) return vcard_emul_type_select(vreader); } +/* + * TODO: move this to emulater non-specific file + */ +static const char * +vcard_emul_get_type_params(VReader *vreader) +{ + VReaderEmul *vreader_emul; + + vreader_emul = vreader_get_private(vreader); + if (vreader_emul && vreader_emul->type_params) { + return vreader_emul->type_params; + } + + return ""; +} + +/* pull the slot out of the reader private data */ +static PK11SlotInfo * +vcard_emul_reader_get_slot(VReader *vreader) +{ + VReaderEmul *vreader_emul = vreader_get_private(vreader); + if (vreader_emul == NULL) { + return NULL; + } + return vreader_emul->slot; +} /* - * Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate - * historical bytes for any software emulated card. The remaining bytes can be - * used to indicate the actual emulator + * Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate historical bytes for + * any software emulated card. The remaining bytes can be used to indicate the actual emulator */ -const static unsigned char nss_atr[] = { VCARD_ATR_PREFIX, 'N', 'S', 'S' }; +const static unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }; +/*const static unsigned char nss_atr[] = { 0x3B, 0x6B, 0, 0, 0x80, 0x65, 0xB0, + 0x83, 1, 4, 0x74, 0x83, 0, 0x90, 0 }; */ void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) { @@ -355,9 +424,6 @@ vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) ASSERT(atr != NULL); memcpy(atr, nss_atr, len); - // set the hb_length correctly (length of historical bytes), second byte, T1 - // last nibble. Windows usbccid.sys needs this to be correct. - atr[1] = (atr[1] & 0xf0) + sizeof(nss_atr) - VCARD_ATR_MAIN_LENGTH; *atr_len = len; return; } @@ -366,16 +432,28 @@ vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) * create a new card from certs and keys */ static VCard * -vcard_emul_make_card(PK11SlotInfo *slot, VCardEmulType type, +vcard_emul_make_card(VReader *reader, unsigned char * const *certs, int *cert_len, VCardKey *keys[], int cert_count) { VCardEmul *vcard_emul; VCard *vcard; + PK11SlotInfo *slot; + VCardEmulType type; + const char *params; + + type = vcard_emul_get_type(reader); /* ignore the inserted card */ if (type == VCARD_EMUL_NONE) { return NULL; } + slot = vcard_emul_reader_get_slot(reader); + if (slot == NULL) { + return NULL; + } + + params = vcard_emul_get_type_params(reader); + /* params these can be NULL */ vcard_emul = vcard_emul_new_card(slot); if (vcard_emul == NULL) { @@ -386,7 +464,7 @@ vcard_emul_make_card(PK11SlotInfo *slot, VCardEmulType type, vcard_emul_delete_card(vcard_emul); return NULL; } - vcard_init(vcard, type, "", certs, cert_len, keys, cert_count); + vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count); return vcard; } @@ -395,7 +473,7 @@ vcard_emul_make_card(PK11SlotInfo *slot, VCardEmulType type, * 'clone' a physical card as a virtual card */ static VCard * -vcard_emul_mirror_card(PK11SlotInfo *slot, VCardEmulType type) +vcard_emul_mirror_card(VReader *vreader) { /* * lookup certs using the C_FindObjects. The Stan Cert handle won't give @@ -406,8 +484,13 @@ vcard_emul_mirror_card(PK11SlotInfo *slot, VCardEmulType type) unsigned char **certs; int *cert_len; VCardKey **keys; + PK11SlotInfo *slot; PRBool ret; + slot = vcard_emul_reader_get_slot(vreader); + if (slot == NULL) { + return NULL; + } firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); if (firstObj == NULL) { @@ -458,10 +541,11 @@ vcard_emul_mirror_card(PK11SlotInfo *slot, VCardEmulType type) } /* now create the card */ - return vcard_emul_make_card(slot, type, certs, cert_len, keys, cert_count); + return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); } static VCardEmulType default_card_type = VCARD_EMUL_NONE; +static char *default_type_params = ""; /* * This thread looks for card and reader insertions and puts events on the event queue @@ -483,8 +567,8 @@ vcard_emul_event_thread(void *arg) vreader = vcard_emul_find_vreader_from_slot(slot); if (vreader == NULL) { /* new vreader */ - vreader_emul = vreader_emul_new(slot, default_card_type); - vreader = vreader_new(vreader_emul, vreader_emul_delete); + vreader_emul = vreader_emul_new(slot, default_card_type, default_type_params); + vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); PK11_FreeSlot(slot); slot == NULL; vreader_add_reader(vreader); @@ -500,8 +584,7 @@ vcard_emul_event_thread(void *arg) if (vreader_emul->present) { vreader_insert_card(vreader, NULL); } - type = vcard_emul_get_type(vreader); - vcard = vcard_emul_mirror_card(slot, type); + vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_free(vcard); } @@ -545,7 +628,7 @@ vcard_emul_new_event_thread(SECMODModule *module) module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); } -static const VCardEmulOptions default_options = { NULL, NULL, 0, VCARD_EMUL_CAC }; +static const VCardEmulOptions default_options = { NULL, NULL, 0, VCARD_EMUL_CAC, "", PR_TRUE }; /* * NSS needs the app to supply a password prompt. In our case the only time the password is @@ -571,7 +654,7 @@ vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg) VCardEmulError vcard_emul_force_card_remove(VReader *vreader) { - if (vreader_card_is_present(vreader) != VREADER_OK) { + if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) { return VCARD_EMUL_FAIL; /* card is already removed */ } @@ -584,12 +667,13 @@ vcard_emul_force_card_remove(VReader *vreader) VCardEmulError vcard_emul_force_card_insert(VReader *vreader) { - VReaderEmul *vreader_emul = vreader_get_private(vreader); + VReaderEmul *vreader_emul; VCard *vcard; - if (vreader_card_is_present(vreader) == VREADER_OK) { - return VCARD_EMUL_FAIL; /* card is already inserted */ + if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) { + return VCARD_EMUL_FAIL; /* card is already removed */ } + vreader_emul = vreader_get_private(vreader); /* if it's a softcard, get the saved vcard from the reader emul structure */ if (vreader_emul->saved_vcard) { @@ -600,7 +684,7 @@ vcard_emul_force_card_insert(VReader *vreader) /* physical card has been removed, not way to reinsert it */ return VCARD_EMUL_FAIL; } - vcard = vcard_emul_mirror_card(vreader_emul->slot, vcard_emul_get_type(vreader)); + vcard = vcard_emul_mirror_card(vreader); } vreader_insert_card(vreader, vcard); vcard_free(vcard); @@ -648,13 +732,15 @@ vcard_emul_init(const VCardEmulOptions *options) int *cert_len; VCardKey **keys; PK11SlotInfo *slot; + char reader_name[25]; slot = PK11_FindSlotByName(options->vreader[i].name); if (slot == NULL) { continue; } - vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type); - vreader = vreader_new(vreader_emul, vreader_emul_delete); + vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, + options->vreader[i].type_params); + vreader = vreader_new(options->vreader[i].vname, vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); cert_count = options->vreader[i].cert_count; @@ -678,8 +764,7 @@ vcard_emul_init(const VCardEmulOptions *options) cert_count++; } if (cert_count) { - VCard *vcard = vcard_emul_make_card(slot, options->vreader[i].card_type, certs, - cert_len, keys, cert_count); + VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); /* allow insertion and removal of soft cards */ @@ -690,6 +775,12 @@ vcard_emul_init(const VCardEmulOptions *options) } } + /* if we aren't suppose to use hw, skip looking up hardware tokens */ + if (!options->use_hw) { + nss_emul_init = has_readers; + return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; + } + /* make sure we have some PKCS #11 module loaded */ module_lock = SECMOD_GetDefaultModuleListLock(); module_list = SECMOD_GetDefaultModuleList(); @@ -718,6 +809,7 @@ vcard_emul_init(const VCardEmulOptions *options) /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; + default_type_params = strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { @@ -735,8 +827,8 @@ vcard_emul_init(const VCardEmulOptions *options) if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { continue; } - vreader_emul = vreader_emul_new(slot, options->hw_card_type); - vreader = vreader_new(vreader_emul, vreader_emul_delete); + vreader_emul = vreader_emul_new(slot, options->hw_card_type, options->hw_type_params); + vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); has_readers = PR_TRUE; @@ -746,7 +838,7 @@ vcard_emul_init(const VCardEmulOptions *options) VCardEmulType type; VCard *vcard; type = vcard_emul_get_type(vreader); - vcard = vcard_emul_mirror_card(slot, type); + vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); vcard_free(vcard); @@ -757,6 +849,7 @@ vcard_emul_init(const VCardEmulOptions *options) } } SECMOD_ReleaseReadLock(module_lock); + nss_emul_init = has_readers; return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; } @@ -765,7 +858,7 @@ vcard_emul_init(const VCardEmulOptions *options) * Silly little functions to help parsing our argument string */ static char * -copy_string(char *str, int str_len) +copy_string(const char *str, int str_len) { char *new_str; @@ -776,7 +869,7 @@ copy_string(char *str, int str_len) } static int -count_tokens(char *str, char token, char token_end) +count_tokens(const char *str, char token, char token_end) { int count = 0; @@ -791,8 +884,8 @@ count_tokens(char *str, char token, char token_end) return count; } -static char * -find_token(char *str, char token, char token_end) +static const char * +find_token(const char *str, char token, char token_end) { /* just do the blind simple thing */ for (;*str;str++) { @@ -803,8 +896,8 @@ find_token(char *str, char token, char token_end) return str; } -static char * -strip(char *str) +static const char * +strip(const char *str) { for(;*str; str++) { if ((*str != ' ') && (*str != '\n') && (*str != '\t') && (*str != '\r')) { @@ -814,8 +907,8 @@ strip(char *str) return str; } -static char * -find_blank(char *str) +static const char * +find_blank(const char *str) { for(;*str; str++) { if ((*str == ' ') || (*str == '\n') || (*str == '\t') || (*str == '\r')) { @@ -833,7 +926,7 @@ static VCardEmulOptions options; #define READER_STEP 4 VCardEmulOptions * -vcard_emul_parse_args(char *args) +vcard_emul_options(const char *args) { int reader_count = 0; VCardEmulOptions *opts; @@ -847,11 +940,13 @@ vcard_emul_parse_args(char *args) if (*args == ',') { continue; } - /* soft=(slot_name,emul_type,cert_1,cert_2,cert_3...) */ + /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1,cert_2,cert_3...) */ if (strncmp(args,"soft=",5) == 0) { - char *name; + const char *name; + const char *vname; + const char *type_params; VCardEmulType type; - int name_length, count, i; + int name_length, vname_length, type_params_length, count, i; VirtualReaderOptions *vreaderOpt; args = strip(args+5); @@ -867,7 +962,18 @@ vcard_emul_parse_args(char *args) args++; continue; } + args = strip(args+1); name_length = args - name; + vname = args; + args = find_token(args+1,',',')'); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + vname_length = args - name; args = strip(args+1); type = vcard_emul_type_from_string(args); args = find_token(args,',',')'); @@ -879,9 +985,21 @@ vcard_emul_parse_args(char *args) continue; } args = strip(args++); + type_params=args; + args = find_token(args+1,',',')'); if (*args == 0) { break; } + if (*args == ')') { + args++; + continue; + } + type_params_length = args - name; + args = strip(args++); + if (*args == 0) { + break; + } + if (opts->vreader_count >= reader_count) { reader_count += READER_STEP; vreaderOpt = realloc(opts->vreader, reader_count); @@ -892,12 +1010,14 @@ vcard_emul_parse_args(char *args) opts->vreader = vreaderOpt; vreaderOpt = &vreaderOpt[opts->vreader_count]; vreaderOpt->name = copy_string(name, name_length); + vreaderOpt->vname = copy_string(vname, vname_length); vreaderOpt->card_type = type; + vreaderOpt->type_params = copy_string(name, name_length); count = count_tokens(args,',',')') +1; vreaderOpt->cert_count = count; vreaderOpt->cert_name = (char **)malloc(count*sizeof(char *)); for (i=0; i < count; i++) { - char *cert = strip(args); + const char *cert = strip(args); args = find_token(args, ',', ')'); vreaderOpt->cert_name[i] = copy_string(cert, args-cert); } @@ -905,13 +1025,30 @@ vcard_emul_parse_args(char *args) args++; } opts->vreader_count++; - } else if (strncmp(args,"hw=",3) == 0) { - args = strip(args+3); + /* use_hw= */ + } else if (strncmp(args,"use_hw=",7) == 0) { + args = strip(args+7); + if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') { + opts->use_hw = PR_FALSE; + } else { + opts->use_hw = PR_TRUE; + } + args = find_blank(args); + /* hw_type= */ + } else if (strncmp(args,"hw_type=",8) == 0) { + args = strip(args+8); opts->hw_card_type = vcard_emul_type_from_string(args); args = find_blank(args); + /* hw_params= */ + } else if (strncmp(args,"hw_params=",10) == 0) { + const char *params; + args = strip(args+10); + params= args; + args = find_blank(args); + opts->hw_type_params = copy_string(params, args-params); /* db="/data/base/path" */ } else if (strncmp(args,"db=",3) == 0) { - char *db; + const char *db; args = strip(args+3); if (*args != '"') { continue; @@ -928,3 +1065,31 @@ vcard_emul_parse_args(char *args) return opts; } + +void +vcard_emul_usage(void) +{ + fprintf(stderr, "emul args: comma separated list of the following arguments\n"); + fprintf(stderr, " db={nss_database} (default sql:/etc/pki/nssdb)\n"); + fprintf(stderr, " use_hw=[yes|no] (default yes)\n"); + fprintf(stderr, " hw_type={card_type_to_emulate} (default CAC)\n"); + fprintf(stderr, " hw_param={param_for_card} (default \"\")\n"); + fprintf(stderr, " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n" + " {cert1},{cert2},{cert3} (default none)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " {nss_database} The location of the NSS cert & key database\n"); + fprintf(stderr, " {card_type_to_emulate} What card interface to present to the guest\n"); + fprintf(stderr, " {param_for_card} Card interface specific parameters\n"); + fprintf(stderr, " {slot_name} NSS slot that contains the certs\n"); + fprintf(stderr, " {vreader_name} Virutal reader name to present to the guest\n"); + fprintf(stderr, " {certN} Nickname of the certificate n on the virtual card\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "These parameters come as a single string separated by blanks or newlines."); + fprintf(stderr, "\n"); + fprintf(stderr, "Unless use_hw is set to no, all tokens that look like removable hardware\n" + "tokens will be presented to the guest using the emulator specified by \n" + "hw_type, and parameters of hw_param.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "If more one or more soft= parameters are specified, these readers will be\n" + "presented to the guest\n"); +} diff --git a/vcard_emul_type.c b/vcard_emul_type.c index 95d3a9e..9893605 100644 --- a/vcard_emul_type.c +++ b/vcard_emul_type.c @@ -1,44 +1,58 @@ -/*
- * This file contains utility functions which abstract the different card types.
- * The goal is that new card types can easily be added by simply changing this file and
- * vcard_emul_type.h. It is currently not a requirement to dynamically add new card types.
- */
-
-#include "vcardt.h"
-#include "vcard_emul_type.h"
-
-VCardStatus vcard_init(VCard *vcard, VCardEmulType type, const char * flags,
- unsigned char *const *cert, int cert_len[],
- VCardKey *key[], int cert_count)
-{
- switch (type) {
- case VCARD_EMUL_NONE:
- break;
- case VCARD_EMUL_CAC:
- return cac_card_init(vcard, flags, cert, cert_len, key, cert_count);
- /* add new ones here */
- default:
- break;
- }
- return VCARD_FAIL;
-}
-
-VCardEmulType vcard_emul_type_select(VReader *vreader)
-{
-#ifdef notdef
- /* since there is only one emulator no need to call this function */
- if (cac_is_cac_card(vreader) == VCARD_DONE) {
- return VCARD_EMUL_CAC;
- }
-#endif
- /* return the default */
- return VCARD_EMUL_CAC;
-}
-
-VCardEmulType vcard_emul_type_from_string(char *type_string)
-{
- if (strcasecmp(type_string,"CAC") == 0) {
- return VCARD_EMUL_CAC;
- }
- return VCARD_EMUL_NONE;
-}
+/* + * This file contains utility functions which abstract the different card types. + * The goal is that new card types can easily be added by simply changing this file and + * vcard_emul_type.h. It is currently not a requirement to dynamically add new card types. + */ + +#include "vcardt.h" +#include "vcard_emul_type.h" +#include "cac.h" +#include "passthru.h" + +VCardStatus vcard_init(VReader *vreader, VCard *vcard, + VCardEmulType type, const char * params, + unsigned char *const *cert, int cert_len[], + VCardKey *key[], int cert_count) +{ + switch (type) { + case VCARD_EMUL_NONE: + break; + case VCARD_EMUL_CAC: + return cac_card_init(vreader, vcard, params, + cert, cert_len, key, cert_count); +#ifdef USE_PASSTHRU + case VCARD_EMUL_PASSTHRU: + return passthru_card_init(vreader, vcard, params, + cert, cert_len, key, cert_count); +#endif + /* add new ones here */ + default: + break; + } + return VCARD_FAIL; +} + +VCardEmulType vcard_emul_type_select(VReader *vreader) +{ +#ifdef notdef + /* since there is only one emulator no need to call this function */ + if (cac_is_cac_card(vreader) == VCARD_DONE) { + return VCARD_EMUL_CAC; + } +#endif + /* return the default */ + return VCARD_EMUL_CAC; +} + +VCardEmulType vcard_emul_type_from_string(const char *type_string) +{ + if (strcasecmp(type_string,"CAC") == 0) { + return VCARD_EMUL_CAC; + } +#ifdef USE_PASSTHRU + if (strcasecmp(type_string,"PASSTHRU") == 0) { + return VCARD_EMUL_PASSTHRU; + } +#endif + return VCARD_EMUL_NONE; +} diff --git a/vcard_emul_type.h b/vcard_emul_type.h index a17dbbd..529420c 100644 --- a/vcard_emul_type.h +++ b/vcard_emul_type.h @@ -14,18 +14,15 @@ */
typedef enum {
VCARD_EMUL_NONE =0,
- VCARD_EMUL_CAC
+ VCARD_EMUL_CAC,
+ VCARD_EMUL_PASSTHRU
} VCardEmulType;
/* functions used by the rest of the emulator */
-VCardStatus vcard_init(VCard *vcard, VCardEmulType type, const char * flags,
+VCardStatus vcard_init(VReader *vreader, VCard *vcard, VCardEmulType type, const char *params,
unsigned char * const *cert, int cert_len[], VCardKey *key[],
int cert_count);
VCardEmulType vcard_emul_type_select(VReader *vreader);
-VCardEmulType vcard_emul_type_from_string(char *type_string);
+VCardEmulType vcard_emul_type_from_string(const char *type_string);
-/* forward declarations of emul type functions used by vcard_emul_type.c */
-VCardStatus cac_card_init(VCard *vcard, const char * flags, unsigned char *const *cert,
- int cert_len[], VCardKey *key[], int cert_count);
-VCardStatus cac_is_cac_card(VReader *reader);
#endif
@@ -28,10 +28,9 @@ typedef struct VCardEmulStruct VCardEmul; #define MAX_CHANNEL 4 /* create an ATR with appropriate historical bytes */ -#define VCARD_ATR_PREFIX 0x3b, 0x7f, 0x13, 0x00, 0xff, 'V', 'C', 'A', 'R', 'D', '_' +#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \ + 'V', 'C', 'A', 'R', 'D', '_' -/* length of non historical bytes part */ -#define VCARD_ATR_MAIN_LENGTH 5 typedef enum { VCARD_DONE, @@ -41,7 +40,8 @@ typedef enum { typedef enum { VCARD_FILE_SYSTEM, - VCARD_VM + VCARD_VM, + VCARD_DIRECT } VCardType; typedef enum { @@ -49,11 +49,12 @@ typedef enum { VCARD_POWER_OFF } VCardPower; -typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, +typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, VCardResponse **response); typedef VCardStatus (*VCardResetApplet)(VCard *card, int channel); typedef void (*VCardAppletPrivateFree) (VCardAppletPrivate *); typedef void (*VCardEmulFree) (VCardEmul *); +typedef void (*VCardGetAtr) (VCard *, unsigned char *atr, int *atr_len); struct VCardBufferResponseStruct { unsigned char *buffer; @@ -15,6 +15,12 @@ void vevent_delete(VEvent *); */ void vevent_queue_vevent(VEvent *); void vevent_queue_init(); + +/* + * VEvent dequeing services + */ VEvent *vevent_wait_next_vevent(); +VEvent *vevent_get_next_vevent(); + #endif @@ -21,6 +21,8 @@ struct VReaderStruct { int reference_count; VCard *card; + char *name; + VReaderID id; mutex_t lock; VReaderEmul *reader_private; VReaderEmulFree reader_private_free; @@ -43,7 +45,8 @@ vreader_unlock(VReader *reader) * vreader constructor */ VReader * -vreader_new(VReaderEmul *private, VReaderEmulFree private_free) +vreader_new(const char *name, VReaderEmul *private, + VReaderEmulFree private_free) { VReader *reader; @@ -53,7 +56,9 @@ vreader_new(VReaderEmul *private, VReaderEmulFree private_free) } MUTEX_INIT(reader->lock); reader->reference_count = 1; + reader->name = name ? strdup(name) : NULL; reader->card = NULL; + reader->id = (VReaderID)-1; reader->reader_private = private; reader->reader_private_free = private_free; return reader; @@ -88,6 +93,9 @@ vreader_free(VReader *reader) if (reader->card) { vcard_free(reader->card); } + if (reader->name) { + free(reader->name); + } if (reader->reader_private_free) { reader->reader_private_free(reader->reader_private); } @@ -118,12 +126,40 @@ vreader_card_is_present(VReader *reader) return VREADER_OK; } +VReaderID +vreader_get_id(VReader *reader) +{ + if (reader == NULL) { + return (VReaderID)-1; + } + return reader->id; +} + +VReaderStatus +vreader_set_id(VReader *reader, VReaderID id) +{ + if (reader == NULL) { + return VREADER_NO_CARD; + } + reader->id = id; + return VREADER_OK; +} + +const char * +vreader_get_name(VReader *reader) +{ + if (reader == NULL) { + return NULL; + } + return reader->name; +} + VReaderEmul * vreader_get_private(VReader *reader) { return reader->reader_private; } - + static VReaderStatus vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) { @@ -132,19 +168,19 @@ vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) if (card == NULL) { return VREADER_NO_CARD; } - /* + /* * clean up our state */ vcard_reset(card, power); if (atr) { - vcard_emul_get_atr(card, atr, len); + vcard_get_atr(card, atr, len); } vcard_free(card); /* free our reference */ return VREADER_OK; } VReaderStatus -vreader_power_on(VReader *reader, unsigned char *atr, int *len) +vreader_power_on(VReader *reader, unsigned char *atr, int *len) { VReaderStatus status; @@ -159,7 +195,7 @@ vreader_power_off(VReader *reader) VReaderStatus -vreader_xfr_bytes(VReader *reader, +vreader_xfr_bytes(VReader *reader, unsigned char *send_buf, int send_buf_len, unsigned char *receive_buf, int *receive_buf_len) { @@ -355,7 +391,6 @@ vreader_copy_list(VReaderList *list) vreader_free(reader); vreader_queue(new_list, new_entry); } - vreader_list_unlock(); return new_list; } @@ -370,6 +405,50 @@ vreader_get_reader_list() return new_reader_list; } +VReader * +vreader_get_reader_by_id(VReaderID id) +{ + VReader *reader = NULL; + VReaderListEntry *current_entry = NULL; + + if (id == (VReaderID) -1) { + return NULL; + } + + vreader_list_lock(); + for (current_entry = vreader_list_get_first(vreader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *creader = vreader_list_get_reader(current_entry); + if (creader->id == id) { + reader = creader; + break; + } + vreader_free(creader); + } + vreader_list_unlock(); + return reader; +} + +VReader * +vreader_get_reader_by_name(const char *name) +{ + VReader *reader = NULL; + VReaderListEntry *current_entry = NULL; + + vreader_list_lock(); + for (current_entry = vreader_list_get_first(vreader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *creader = vreader_list_get_reader(current_entry); + if (strcmp(creader->name, name) == 0) { + reader = creader; + break; + } + vreader_free(creader); + } + vreader_list_unlock(); + return reader; +} + /* called from card_emul to initialize the readers */ VReaderStatus vreader_add_reader(VReader *reader) @@ -20,13 +20,19 @@ VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf, VReaderList *vreader_get_reader_list(); /* constructor */ -VReader *vreader_new(VReaderEmul *emul_private, VReaderEmulFree private_free); +VReader *vreader_new(const char *readerName, VReaderEmul *emul_private, + VReaderEmulFree private_free); /* get a new reference to a reader */ VReader *vreader_reference(VReader *reader); /* "destructor" (readers are reference counted) */ void vreader_free(VReader *reader); + +/* accessors */ VReaderEmul *vreader_get_private(VReader *); VReaderStatus vreader_card_is_present(VReader *reader); +const char *vreader_get_name(VReader *reader); +VReaderID vreader_get_id(VReader *reader); +VReaderStatus vreader_set_id(VReader *reader, VReaderID id); /* list operations */ VReaderList *vreader_get_reader_list(); @@ -34,6 +40,8 @@ void vreader_list_delete(VReaderList *list); VReader *vreader_list_get_reader(VReaderListEntry *entry); VReaderListEntry *vreader_list_get_first(VReaderList *list); VReaderListEntry *vreader_list_get_next(VReaderListEntry *list); +VReader *vreader_get_reader_by_id(VReaderID id); +VReader *vreader_get_reader_by_name(const char *name); /* * list tools for vcard_emul @@ -11,6 +11,7 @@ typedef enum { VREADER_OUT_OF_MEMORY } VReaderStatus; +typedef unsigned int VReaderID; typedef struct VReaderStruct VReader; typedef struct VReaderListStruct VReaderList; typedef struct VReaderListEntryStruct VReaderListEntry; diff --git a/vscclient.c b/vscclient.c index 40ad64d..2c3cf7f 100644 --- a/vscclient.c +++ b/vscclient.c @@ -14,6 +14,7 @@ #include "vreader.h" #include "vcard_emul.h" #include "vevent.h" +#include "passthru.h" #include "mutex.h" @@ -21,7 +22,7 @@ typedef unsigned char BYTE; typedef unsigned long LONG; -int verbose = 10; +int verbose = 0; int sock; @@ -32,14 +33,21 @@ PrintByteArray ( ) { int i; for (i=0; i < nSize; i++) { - printf ("%X ", arrBytes[i]); + printf ("%02X ", arrBytes[i]); } printf ("\n"); } void PrintUsage () { - printf ("vscclient [-c <certname> ..] <host> <port> \n"); + printf ("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] <host> <port> \n", +#ifdef USE_PASSTHRU + " -p"); + printf (" -p use passthrough mode\n"); +#else + ""); +#endif + vcard_emul_usage(); } static mutex_t write_lock; @@ -47,7 +55,8 @@ static mutex_t write_lock; int SendMsg ( VSCMsgType type, - void *msg, + uint32_t reader_id, + const void *msg, unsigned int length ) { LONG rv; @@ -55,6 +64,10 @@ SendMsg ( MUTEX_LOCK(write_lock); + if (verbose > 10) { + printf("sending type=%d id=%d, len =%d (0x%x)\n", type, reader_id, length, length); + } + mhHeader.type = type; mhHeader.reader_id = 0; mhHeader.length = length; @@ -87,6 +100,9 @@ SendMsg ( return (0); } +static VReader *pending_reader = NULL; +static mutex_t pending_reader_lock; +static condition_t pending_reader_condition; #define MAX_ATR_LEN 40 static void * @@ -96,38 +112,102 @@ event_thread(void *arg) unsigned char atr[ MAX_ATR_LEN]; int atr_len = MAX_ATR_LEN; VEvent *event = NULL; + unsigned int reader_id; while (1) { + const char *reader_name; + event = vevent_wait_next_vevent(); if (event == NULL) { break; } - if (event->reader != reader) { - vevent_delete(event); - continue; + reader_id = vreader_get_id(event->reader); + if (reader_id == VSCARD_UNDEFINED_READER_ID && event->type != VEVENT_READER_INSERT) { + /* ignore events from readers qemu has rejected */ + /* if qemu is still deciding on this reader, wait to see if need to forward this + * event */ + MUTEX_LOCK(pending_reader_lock); + if (!pending_reader || (pending_reader != event->reader)) { + /* wasn't for a pending reader, this reader has already been rejected by qemu */ + MUTEX_UNLOCK(pending_reader_lock); + vevent_delete(event); + continue; + } + /* this reader hasn't been told it's status from qemu yet, wait for that status */ + while (pending_reader != NULL) { + CONDITION_WAIT(pending_reader_condition,pending_reader_lock); + } + MUTEX_UNLOCK(pending_reader_lock); + /* now recheck the id */ + reader_id = vreader_get_id(event->reader); + if (reader_id == VSCARD_UNDEFINED_READER_ID) { + /* this reader was rejected */ + vevent_delete(event); + continue; + } + /* reader was accepted, now forward the event */ } switch (event->type) { case VEVENT_READER_INSERT: - /* future, tell qemu to insert a new CCID reader */ + /* tell qemu to insert a new CCID reader */ + /* wait until qemu has responded to our first reader insert + * before we send a second. That way we won't confuse the responses */ + MUTEX_LOCK(pending_reader_lock); + while (pending_reader != NULL) { + CONDITION_WAIT(pending_reader_condition,pending_reader_lock); + } + pending_reader = vreader_reference(event->reader); + MUTEX_UNLOCK(pending_reader_lock); + reader_name = vreader_get_name(event->reader); + if (verbose > 10) { + printf (" READER INSERT: %s\n", reader_name); + } + SendMsg ( + VSC_ReaderAdd, + reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */ + NULL, 0 + /*reader_name, + strlen(reader_name) */ + ); + break; case VEVENT_READER_REMOVE: /* future, tell qemu that an old CCID reader has been removed */ + if (verbose > 10) { + printf (" READER REMOVE: %d \n", reader_id); + } + SendMsg( + VSC_ReaderRemove, + reader_id, + NULL, + 0 + ); break; case VEVENT_CARD_INSERT: /* get the ATR (intended as a response to a power on from the reader */ - vreader_power_on(reader, atr, &atr_len); + atr_len = MAX_ATR_LEN; + vreader_power_on(event->reader, atr, &atr_len); /* ATR call functions as a Card Insert event */ + if (verbose > 10) { + printf (" CARD INSERT %d: ", reader_id); + PrintByteArray (atr, atr_len); + } SendMsg ( VSC_ATR, + reader_id, atr, atr_len ); break; case VEVENT_CARD_REMOVE: // Card removed + if (verbose > 10) { + printf (" CARD REMOVE %d: \n", reader_id); + } SendMsg ( VSC_CardRemove, + reader_id, NULL, 0 ); @@ -138,35 +218,135 @@ event_thread(void *arg) return NULL; } + +unsigned int +get_id_from_string(char *string, unsigned int default_id) +{ + unsigned int id = atoi(string); + + /* don't accidentally swith to zero because no numbers have been supplied */ + if ((id == 0) && *string != '0') { + return default_id; + } + return id; +} + void -do_command(VReader *reader) +do_command(void) { char inbuf[255]; char *string; VCardEmulError error; + static unsigned int default_reader_id = 0; + unsigned int reader_id; + VReader *reader = NULL; + reader_id = default_reader_id; string = fgets(inbuf, sizeof(inbuf), stdin); if (string != NULL) { if (strncmp(string,"exit",4) == 0) { - SendMsg ( - VSC_ReaderRemove, - NULL, - 0 - ); + /* remove all the readers */ + VReaderList *list = vreader_get_reader_list(); + VReaderListEntry *reader_entry; + printf("Active Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + VReaderID reader_id; + reader_id=vreader_get_id(reader); + if (reader_id == -1) continue; + /* be nice and signal card removal first (qemu probably should do this itself) */ + if (vreader_card_is_present(reader) == VCARD_DONE) { + SendMsg ( + VSC_CardRemove, + reader_id, + NULL, + 0 + ); + } + SendMsg ( + VSC_ReaderRemove, + reader_id, + NULL, + 0 + ); + } exit(0); } else if (strncmp(string,"insert",6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], reader_id); + } + reader = vreader_get_reader_by_id(reader_id); error = vcard_emul_force_card_insert(reader); - printf("insert, returned %d\n", error); + printf("insert %s, returned %d\n", reader ? vreader_get_name(reader) + : "invalid reader", error); } else if (strncmp(string,"remove",6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], reader_id); + } + reader = vreader_get_reader_by_id(reader_id); error = vcard_emul_force_card_remove(reader); - printf("remove, returned %d\n", error); + printf("remove %s, returned %d\n", reader ? vreader_get_name(reader) + : "invalid reader", error); + } else if (strncmp(string,"select",6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], VSCARD_UNDEFINED_READER_ID); + } + if (reader_id != VSCARD_UNDEFINED_READER_ID) { + reader = vreader_get_reader_by_id(reader_id); + } + if (reader) { + printf("Selecting reader %d, %s\n", reader_id, + vreader_get_name(reader)); + default_reader_id = reader_id; + } else { + printf("Reader with id %d not found\n", reader_id); + } + } else if (strncmp(string,"debug",5) == 0) { + if (string[5] == ' ') { + verbose = get_id_from_string(&string[6],0); + } + printf ("debug level = %d\n", verbose); + } else if (strncmp(string,"list",4) == 0) { + VReaderList *list = vreader_get_reader_list(); + VReaderListEntry *reader_entry; + printf("Active Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + VReaderID reader_id; + reader_id=vreader_get_id(reader); + if (reader_id == -1) continue; + + printf("%3d %s %s\n",reader_id, + vreader_card_is_present(reader) == VCARD_DONE ? + "CARD_PRESENT": " ", + vreader_get_name(reader)); + } + printf("Inactive Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + VReaderID reader_id; + reader_id=vreader_get_id(reader); + if (reader_id != -1) continue; + + printf("INA %s %s\n", + vreader_card_is_present(reader) == VCARD_DONE ? + "CARD_PRESENT": " ", + vreader_get_name(reader)); + } } else if (*string != 0) { printf("valid commands: \n"); - printf("insert\n"); - printf("remove\n"); + printf("insert [reader_id]\n"); + printf("remove [reader_id]\n"); + printf("select reader_id\n"); + printf("list\n"); + printf("debug [level]\n"); printf("exit\n"); } } + vreader_free(reader); printf("> "); fflush(stdout); } @@ -186,6 +366,7 @@ main ( struct addrinfo* server; VSCMsgHeader mhHeader; + VSCMsgError *error_msg; LONG rv; int dwSendLength; @@ -193,28 +374,19 @@ main ( BYTE pbRecvBuffer[APDUBufSize]; BYTE pbSendBuffer[APDUBufSize]; VReaderStatus reader_status; - VReaderList *reader_list; - VReader *reader; + VReader *reader = NULL; + VCardEmulOptions *command_line_options = NULL; pthread_t thread_id; + int passthru = 0; char* cert_names[MAX_CERTS]; + char* emul_args = NULL; int cert_count = 0; int c; int ret; - VirtualReaderOptions command_line_readers[] = { - { - .name = "", - .card_type = VCARD_EMUL_CAC, - .cert_name = cert_names, - .cert_count = 0, - } - }; - const VCardEmulOptions command_line_options = { - "/etc/pki/nssdb", command_line_readers, 1, VCARD_EMUL_CAC - }; - while ((c = getopt(argc, argv, "c:")) != -1) { + while ((c = getopt(argc, argv, "c:e:pd:")) != -1) { switch (c) { case 'c': if (cert_count >= MAX_CERTS) { @@ -223,16 +395,60 @@ main ( } cert_names[cert_count++] = optarg; break; + case 'e': + emul_args = optarg; + break; + case 'p': +#ifdef USE_PASSTHRU + passthru = 1; +#else + PrintUsage(); + exit(4); +#endif + break; + case 'd': + verbose = get_id_from_string(optarg,1); + break; } } - command_line_readers[0].cert_count = cert_count; - if (argc - optind != 2) { PrintUsage(); exit (4); } + if (!passthru && cert_count > 0) { + char *new_args; + int len, i; + /* if we've given some -c options, we clearly we want do so some software emulation. + * add that emulation now. this is NSS Emulator specific */ + if (emul_args == NULL) { + emul_args = "db=\"/etc/pki/nssdb\""; + } +#define SOFT_STRING " soft=(,Virtual Reader,CAC,," + len = strlen(emul_args) + strlen(SOFT_STRING) + 2; /* 2 == close paren & null */ + for (i=0; i < MAX_CERTS; i++) { + len +=strlen(cert_names[i])+1; /* 1 == comma */ + } + new_args = malloc(len); + strcpy(new_args,emul_args); + strcat(new_args,SOFT_STRING); + for (i=0; i < MAX_CERTS; i++) { + strcat(new_args,cert_names[i]+1); + strcat(new_args,","); + } + strcat(new_args,")"); + emul_args = new_args; + } + if (emul_args) { +#ifdef USE_PASSTHRU + command_line_options = passthru ? passthru_emul_options(emul_args) : +#else + command_line_options = +#endif + vcard_emul_options(emul_args); + } + sock = socket ( AF_INET, SOCK_STREAM, @@ -270,21 +486,17 @@ if (verbose) printf ("Connected (sizeof Header=%d)!\n", sizeof (mhHeader)); MUTEX_INIT(write_lock); + MUTEX_INIT(pending_reader_lock); + CONDITION_INIT(pending_reader_condition); - vcard_emul_init(cert_count > 0 ? &command_line_options : NULL); - - SendMsg ( - VSC_ReaderAdd, - NULL, - 0 - ); - /* - * the emulator can handle more than one reader at once, right now this - * test program can only handle a single reader. - */ - reader_list = vreader_get_reader_list(); - reader = vreader_list_get_reader(vreader_list_get_first(reader_list)); +#ifdef USE_PASSTHRU + if (passthru) { + passthru_emul_init(command_line_options); + } else +#endif + vcard_emul_init(command_line_options); + /* launch the event_thread. This will trigger reader adds for all the existing readers */ rv = pthread_create(&thread_id, NULL, event_thread, reader); if (rv < 0) { perror("pthread_create"); @@ -301,6 +513,7 @@ if (verbose) FD_SET(1,&fds); FD_SET(sock,&fds); + /* waiting on input from the socket */ rv = select(sock+1, &fds, NULL, NULL, NULL); if (rv < 0) { /* handle error */ @@ -308,7 +521,7 @@ if (verbose) return (7); } if (FD_ISSET(1,&fds)) { - do_command(reader); + do_command(); } if (!FD_ISSET(sock,&fds)) { continue; @@ -319,13 +532,19 @@ if (verbose) &mhHeader, sizeof (mhHeader) ); - if (rv < 0) { + if (rv < sizeof(mhHeader)) { /* Error */ - printf ("header read error\n"); + if (rv < 0) { + perror("header read error\n"); + } else { + printf ("header short read %d\n", rv); + } return (8); } if (verbose) - printf ("Header: type=%d, length=%d\n", mhHeader.type, mhHeader.length); + printf ("Header: type=%d, reader_id=%d length=%d (0x%x)\n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); switch (mhHeader.type) { case VSC_APDU: rv = read ( @@ -346,17 +565,19 @@ if (verbose) { /* Transmit recieved APDU */ dwSendLength = mhHeader.length; dwRecvLength = sizeof(pbRecvBuffer); + reader = vreader_get_reader_by_id(mhHeader.reader_id); reader_status = vreader_xfr_bytes(reader, pbSendBuffer, dwSendLength, pbRecvBuffer, &dwRecvLength); if (reader_status == VREADER_OK) { mhHeader.length = dwRecvLength; if (verbose) { - printf (" send APDU: "); + printf (" send response: "); PrintByteArray (pbRecvBuffer, mhHeader.length); } SendMsg ( VSC_APDU, + mhHeader.reader_id, pbRecvBuffer, dwRecvLength ); @@ -364,13 +585,44 @@ if (verbose) { rv = reader_status; /* warning: not meaningful */ SendMsg ( VSC_Error, + mhHeader.reader_id, &rv, sizeof (LONG) ); } + vreader_free(reader); + reader = NULL; /* we've freed it, don't use it by accident again */ break; + case VSC_ReaderAddResponse: + MUTEX_LOCK(pending_reader_lock); + if (pending_reader) { + vreader_set_id(pending_reader, mhHeader.reader_id); + vreader_free(pending_reader); + pending_reader = NULL; + CONDITION_NOTIFY(pending_reader_condition); + } + MUTEX_UNLOCK(pending_reader_lock); + break; + case VSC_Error: + rv = read ( + sock, + pbSendBuffer, + mhHeader.length + ); + error_msg = (VSCMsgError *) pbSendBuffer; + if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) { + /* clear pending reader, qemu can't handle any more */ + MUTEX_LOCK(pending_reader_lock); + if (pending_reader) { + pending_reader = NULL; + /* make sure the event loop doesn't hang */ + CONDITION_NOTIFY(pending_reader_condition); + } + MUTEX_UNLOCK(pending_reader_lock); + } default: printf ("Default\n"); + return 0; } } while (rv >= 0); |