libcacard: initial commit
libcacard emulates a Common Access Card (CAC) which is a standard
for smartcards. It is used by the emulated ccid card introduced in
a following patch. Docs are available in docs/libcacard.txt
Signed-off-by: Alon Levy <alevy@redhat.com>
---
changes from v24->v25:
 * Fix out of tree builds.
 * Fix build with linux-user targets.
changes from v23->v24: (Jes Sorensen review 2)
 * Makefile.target: use obj-$(CONFIG_*) +=
 * remove unrequired includes, include qemu-common before qemu-thread
  * required adding #define NO_NSPR_10_SUPPORT (harmless)
changes from v22->v23:
 * configure fixes: (reported by Stefan Hajnoczi)
  * test a = b, not a == b (second isn't portable)
  * quote $source_path in case it contains spaces
   - this doesn't really help since there are many other places
     that need similar fixes, not introduced by this patch.
changes from v21->v22:
 * fix configure to not link libcacard if nss not found
    (reported by Stefan Hajnoczi)
 * fix vscclient linkage with simpletrace backend
    (reported by Stefan Hajnoczi)
 * card_7816.c: add missing break in ERROR_DATA_NOT_FOUND
    (reported by William van de Velde)
changes from v20->v21: (Jes Sorensen review)
 * use qemu infrastructure: qemu-thread, qemu-common (qemu_malloc
  and qemu_free), error_report
 * assert instead of ASSERT
 * cosmetic fixes
 * use strpbrk and isspace
 * add --disable-nss --enable-nss here, instead of in the final patch.
 * split vscclient, passthru and docs to following patches.
changes from v19->v20:
 * checkpatch.pl
changes from v15->v16:
Build:
 * don't erase self with distclean
 * fix make clean after make distclean
 * Makefile: make vscclient link quiet
Behavioral:
 * vcard_emul_nss: load coolkey in more situations
 * vscclient:
  * use hton,ntoh
  * send init on connect, only start vevent thread on response
  * read payload after header check, before type switch
  * remove Reconnect
  * update for vscard_common changes, empty Flush implementation
Style/Whitespace:
 * fix wrong variable usage
 * remove unused variable
 * use only C style comments
  * add copyright header
  * fix tabulation
Signed-off-by: Alon Levy <alevy@redhat.com>
libcacard: fix out of tree builds
			
			
This commit is contained in:
		
							parent
							
								
									edbb21363f
								
							
						
					
					
						commit
						111a38b018
					
				
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							@ -141,6 +141,8 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
 | 
				
			|||||||
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 | 
					check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 | 
				
			||||||
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
 | 
					check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
# avoid old build problems by removing potentially incorrect old files
 | 
					# avoid old build problems by removing potentially incorrect old files
 | 
				
			||||||
	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 | 
						rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 | 
				
			||||||
@ -152,7 +154,7 @@ clean:
 | 
				
			|||||||
	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 | 
						rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
 | 
				
			||||||
	rm -f trace-dtrace.h trace-dtrace.h-timestamp
 | 
						rm -f trace-dtrace.h trace-dtrace.h-timestamp
 | 
				
			||||||
	$(MAKE) -C tests clean
 | 
						$(MAKE) -C tests clean
 | 
				
			||||||
	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
 | 
						for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
 | 
				
			||||||
	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 | 
						if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
 | 
				
			||||||
	rm -f $$d/qemu-options.def; \
 | 
						rm -f $$d/qemu-options.def; \
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
@ -163,7 +165,7 @@ distclean: clean
 | 
				
			|||||||
	rm -f roms/seabios/config.mak roms/vgabios/config.mak
 | 
						rm -f roms/seabios/config.mak roms/vgabios/config.mak
 | 
				
			||||||
	rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
 | 
						rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr
 | 
				
			||||||
	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
 | 
						rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
 | 
				
			||||||
	for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \
 | 
						for d in $(TARGET_DIRS) $(QEMULIBS); do \
 | 
				
			||||||
	rm -rf $$d || exit 1 ; \
 | 
						rm -rf $$d || exit 1 ; \
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -352,6 +352,11 @@ user-obj-y += qemu-timer-common.o
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					######################################################################
 | 
				
			||||||
 | 
					# smartcard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
					vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
					vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 | 
				
			||||||
 | 
				
			|||||||
@ -358,6 +358,12 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
endif # CONFIG_SOFTMMU
 | 
					endif # CONFIG_SOFTMMU
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifndef CONFIG_LINUX_USER
 | 
				
			||||||
 | 
					# libcacard needs qemu-thread support, and besides is only needed by devices
 | 
				
			||||||
 | 
					# so not requires with linux-user targets
 | 
				
			||||||
 | 
					obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
 | 
				
			||||||
 | 
					endif # CONFIG_LINUX_USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y += $(addprefix ../, $(trace-obj-y))
 | 
					obj-y += $(addprefix ../, $(trace-obj-y))
 | 
				
			||||||
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 | 
					obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										49
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@ -176,6 +176,7 @@ trace_file="trace"
 | 
				
			|||||||
spice=""
 | 
					spice=""
 | 
				
			||||||
rbd=""
 | 
					rbd=""
 | 
				
			||||||
smartcard=""
 | 
					smartcard=""
 | 
				
			||||||
 | 
					smartcard_nss=""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# parse CC options first
 | 
					# parse CC options first
 | 
				
			||||||
for opt do
 | 
					for opt do
 | 
				
			||||||
@ -729,6 +730,10 @@ for opt do
 | 
				
			|||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
  --enable-smartcard) smartcard="yes"
 | 
					  --enable-smartcard) smartcard="yes"
 | 
				
			||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
 | 
					  --disable-smartcard-nss) smartcard_nss="no"
 | 
				
			||||||
 | 
					  ;;
 | 
				
			||||||
 | 
					  --enable-smartcard-nss) smartcard_nss="yes"
 | 
				
			||||||
 | 
					  ;;
 | 
				
			||||||
  *) echo "ERROR: unknown option $opt"; show_help="yes"
 | 
					  *) echo "ERROR: unknown option $opt"; show_help="yes"
 | 
				
			||||||
  ;;
 | 
					  ;;
 | 
				
			||||||
  esac
 | 
					  esac
 | 
				
			||||||
@ -928,6 +933,8 @@ echo "  --enable-spice           enable spice"
 | 
				
			|||||||
echo "  --enable-rbd             enable building the rados block device (rbd)"
 | 
					echo "  --enable-rbd             enable building the rados block device (rbd)"
 | 
				
			||||||
echo "  --disable-smartcard      disable smartcard support"
 | 
					echo "  --disable-smartcard      disable smartcard support"
 | 
				
			||||||
echo "  --enable-smartcard       enable smartcard support"
 | 
					echo "  --enable-smartcard       enable smartcard support"
 | 
				
			||||||
 | 
					echo "  --disable-smartcard-nss  disable smartcard nss support"
 | 
				
			||||||
 | 
					echo "  --enable-smartcard-nss   enable smartcard nss support"
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo "NOTE: The object files are built at the place where configure is launched"
 | 
					echo "NOTE: The object files are built at the place where configure is launched"
 | 
				
			||||||
exit 1
 | 
					exit 1
 | 
				
			||||||
@ -2311,6 +2318,31 @@ EOF
 | 
				
			|||||||
  fi
 | 
					  fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# check for libcacard for smartcard support
 | 
				
			||||||
 | 
					if test "$smartcard" != "no" ; then
 | 
				
			||||||
 | 
					    smartcard="yes"
 | 
				
			||||||
 | 
					    smartcard_cflags=""
 | 
				
			||||||
 | 
					    # TODO - what's the minimal nss version we support?
 | 
				
			||||||
 | 
					    if test "$smartcard_nss" != "no"; then
 | 
				
			||||||
 | 
					        if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
 | 
				
			||||||
 | 
					            smartcard_nss="yes"
 | 
				
			||||||
 | 
					            smartcard_cflags="-I\$(SRC_PATH)/libcacard"
 | 
				
			||||||
 | 
					            libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
 | 
				
			||||||
 | 
					            libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
 | 
				
			||||||
 | 
					            QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
 | 
				
			||||||
 | 
					            LIBS="$libcacard_libs $LIBS"
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            if test "$smartcard_nss" = "yes"; then
 | 
				
			||||||
 | 
					                feature_not_found "nss"
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					            smartcard_nss="no"
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					if test "$smartcard" = "no" ; then
 | 
				
			||||||
 | 
					    smartcard_nss="no"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################
 | 
					##########################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##########################################
 | 
					##########################################
 | 
				
			||||||
@ -2549,6 +2581,7 @@ echo "Trace output file $trace_file-<pid>"
 | 
				
			|||||||
echo "spice support     $spice"
 | 
					echo "spice support     $spice"
 | 
				
			||||||
echo "rbd support       $rbd"
 | 
					echo "rbd support       $rbd"
 | 
				
			||||||
echo "xfsctl support    $xfs"
 | 
					echo "xfsctl support    $xfs"
 | 
				
			||||||
 | 
					echo "nss used          $smartcard_nss"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if test $sdl_too_old = "yes"; then
 | 
					if test $sdl_too_old = "yes"; then
 | 
				
			||||||
echo "-> Your SDL version is too old - please upgrade to have SDL support"
 | 
					echo "-> Your SDL version is too old - please upgrade to have SDL support"
 | 
				
			||||||
@ -2835,6 +2868,10 @@ if test "$smartcard" = "yes" ; then
 | 
				
			|||||||
  echo "CONFIG_SMARTCARD=y" >> $config_host_mak
 | 
					  echo "CONFIG_SMARTCARD=y" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if test "$smartcard_nss" = "yes" ; then
 | 
				
			||||||
 | 
					  echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# XXX: suppress that
 | 
					# XXX: suppress that
 | 
				
			||||||
if [ "$bsd" = "yes" ] ; then
 | 
					if [ "$bsd" = "yes" ] ; then
 | 
				
			||||||
  echo "CONFIG_BSD=y" >> $config_host_mak
 | 
					  echo "CONFIG_BSD=y" >> $config_host_mak
 | 
				
			||||||
@ -3183,6 +3220,11 @@ fi
 | 
				
			|||||||
if test "$target_darwin_user" = "yes" ; then
 | 
					if test "$target_darwin_user" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
 | 
					  echo "CONFIG_DARWIN_USER=y" >> $config_target_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					if test "$smartcard_nss" = "yes" ; then
 | 
				
			||||||
 | 
					  echo "subdir-$target: subdir-libcacard" >> $config_host_mak
 | 
				
			||||||
 | 
					  echo "libcacard_libs=$libcacard_libs" >> $config_host_mak
 | 
				
			||||||
 | 
					  echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
list=""
 | 
					list=""
 | 
				
			||||||
if test ! -z "$gdb_xml_files" ; then
 | 
					if test ! -z "$gdb_xml_files" ; then
 | 
				
			||||||
  for x in $gdb_xml_files; do
 | 
					  for x in $gdb_xml_files; do
 | 
				
			||||||
@ -3396,6 +3438,13 @@ for hwlib in 32 64; do
 | 
				
			|||||||
  echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
 | 
					  echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "$source_path" != `pwd` ]; then
 | 
				
			||||||
 | 
					    # out of tree build
 | 
				
			||||||
 | 
					    mkdir -p libcacard
 | 
				
			||||||
 | 
					    rm -f libcacard/Makefile
 | 
				
			||||||
 | 
					    ln -s "$source_path/libcacard/Makefile" libcacard/Makefile
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
d=libuser
 | 
					d=libuser
 | 
				
			||||||
mkdir -p $d
 | 
					mkdir -p $d
 | 
				
			||||||
symlink $source_path/Makefile.user $d/Makefile
 | 
					symlink $source_path/Makefile.user $d/Makefile
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								libcacard/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								libcacard/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					-include ../config-host.mak
 | 
				
			||||||
 | 
					-include $(SRC_PATH)/Makefile.objs
 | 
				
			||||||
 | 
					-include $(SRC_PATH)/rules.mak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(CONFIG_WIN32),y)
 | 
				
			||||||
 | 
					QEMU_THREAD=qemu-thread-win32.o
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					QEMU_THREAD=qemu-thread-posix.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QEMU_CFLAGS+=-I../
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										403
									
								
								libcacard/cac.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								libcacard/cac.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,403 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * implement the applets for the CAC card.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cac.h"
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vcard_emul.h"
 | 
				
			||||||
 | 
					#include "card_7816.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAC_GET_PROPERTIES  0x56
 | 
				
			||||||
 | 
					#define CAC_GET_ACR         0x4c
 | 
				
			||||||
 | 
					#define CAC_READ_BUFFER     0x52
 | 
				
			||||||
 | 
					#define CAC_UPDATE_BUFFER   0x58
 | 
				
			||||||
 | 
					#define CAC_SIGN_DECRYPT    0x42
 | 
				
			||||||
 | 
					#define CAC_GET_CERTIFICATE 0x36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* private data for PKI applets */
 | 
				
			||||||
 | 
					typedef struct CACPKIAppletDataStruct {
 | 
				
			||||||
 | 
					    unsigned char *cert;
 | 
				
			||||||
 | 
					    int cert_len;
 | 
				
			||||||
 | 
					    unsigned char *cert_buffer;
 | 
				
			||||||
 | 
					    int cert_buffer_len;
 | 
				
			||||||
 | 
					    unsigned char *sign_buffer;
 | 
				
			||||||
 | 
					    int sign_buffer_len;
 | 
				
			||||||
 | 
					    VCardKey *key;
 | 
				
			||||||
 | 
					} CACPKIAppletData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * CAC applet private data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct VCardAppletPrivateStruct {
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        CACPKIAppletData pki_data;
 | 
				
			||||||
 | 
					        void *reserved;
 | 
				
			||||||
 | 
					    } u;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * handle all the APDU's that are common to all CAC applets
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (apdu->a_ins) {
 | 
				
			||||||
 | 
					    case VCARD7816_INS_SELECT_FILE:
 | 
				
			||||||
 | 
					        if (apdu->a_p1 != 0x02) {
 | 
				
			||||||
 | 
					            /* let the 7816 code handle applet switches */
 | 
				
			||||||
 | 
					            return VCARD_NEXT;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* handle file id setting */
 | 
				
			||||||
 | 
					        if (apdu->a_Lc != 2) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                VCARD7816_STATUS_ERROR_DATA_INVALID);
 | 
				
			||||||
 | 
					            return VCARD_DONE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* CAC 1.0 only supports ef = 0 */
 | 
				
			||||||
 | 
					        ef = apdu->a_body[0] | (apdu->a_body[1] << 8);
 | 
				
			||||||
 | 
					        if (ef != 0) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
 | 
				
			||||||
 | 
					            return VCARD_DONE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    case VCARD7816_INS_GET_RESPONSE:
 | 
				
			||||||
 | 
					    case VCARD7816_INS_VERIFY:
 | 
				
			||||||
 | 
					        /* let the 7816 code handle these */
 | 
				
			||||||
 | 
					        return VCARD_NEXT;
 | 
				
			||||||
 | 
					    case CAC_GET_PROPERTIES:
 | 
				
			||||||
 | 
					    case CAC_GET_ACR:
 | 
				
			||||||
 | 
					        /* skip these for now, this will probably be needed */
 | 
				
			||||||
 | 
					        *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *response = vcard_make_response(
 | 
				
			||||||
 | 
					        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    return VCARD_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  reset the inter call state between applet selects
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					cac_applet_pki_reset(VCard *card, int channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardAppletPrivate *applet_private = NULL;
 | 
				
			||||||
 | 
					    CACPKIAppletData *pki_applet = NULL;
 | 
				
			||||||
 | 
					    applet_private = vcard_get_current_applet_private(card, channel);
 | 
				
			||||||
 | 
					    assert(applet_private);
 | 
				
			||||||
 | 
					    pki_applet = &(applet_private->u.pki_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pki_applet->cert_buffer = NULL;
 | 
				
			||||||
 | 
					    if (pki_applet->sign_buffer) {
 | 
				
			||||||
 | 
					        qemu_free(pki_applet->sign_buffer);
 | 
				
			||||||
 | 
					        pki_applet->sign_buffer = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pki_applet->cert_buffer_len = 0;
 | 
				
			||||||
 | 
					    pki_applet->sign_buffer_len = 0;
 | 
				
			||||||
 | 
					    return VCARD_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                            VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CACPKIAppletData *pki_applet = NULL;
 | 
				
			||||||
 | 
					    VCardAppletPrivate *applet_private = NULL;
 | 
				
			||||||
 | 
					    int size, next;
 | 
				
			||||||
 | 
					    unsigned char *sign_buffer;
 | 
				
			||||||
 | 
					    vcard_7816_status_t status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
 | 
				
			||||||
 | 
					    assert(applet_private);
 | 
				
			||||||
 | 
					    pki_applet = &(applet_private->u.pki_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (apdu->a_ins) {
 | 
				
			||||||
 | 
					    case CAC_UPDATE_BUFFER:
 | 
				
			||||||
 | 
					        *response = vcard_make_response(
 | 
				
			||||||
 | 
					            VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    case CAC_GET_CERTIFICATE:
 | 
				
			||||||
 | 
					        if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        assert(pki_applet->cert != NULL);
 | 
				
			||||||
 | 
					        size = apdu->a_Le;
 | 
				
			||||||
 | 
					        if (pki_applet->cert_buffer == NULL) {
 | 
				
			||||||
 | 
					            pki_applet->cert_buffer = pki_applet->cert;
 | 
				
			||||||
 | 
					            pki_applet->cert_buffer_len = pki_applet->cert_len;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        size = MIN(size, pki_applet->cert_buffer_len);
 | 
				
			||||||
 | 
					        next = MIN(255, pki_applet->cert_buffer_len - size);
 | 
				
			||||||
 | 
					        *response = vcard_response_new_bytes(
 | 
				
			||||||
 | 
					                        card, pki_applet->cert_buffer, size,
 | 
				
			||||||
 | 
					                        apdu->a_Le, next ?
 | 
				
			||||||
 | 
					                        VCARD7816_SW1_WARNING_CHANGE :
 | 
				
			||||||
 | 
					                        VCARD7816_SW1_SUCCESS,
 | 
				
			||||||
 | 
					                        next);
 | 
				
			||||||
 | 
					        pki_applet->cert_buffer += size;
 | 
				
			||||||
 | 
					        pki_applet->cert_buffer_len -= size;
 | 
				
			||||||
 | 
					        if ((*response == NULL) || (next == 0)) {
 | 
				
			||||||
 | 
					            pki_applet->cert_buffer = NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*response == NULL) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    case CAC_SIGN_DECRYPT:
 | 
				
			||||||
 | 
					        if (apdu->a_p2 != 0) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                             VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        size = apdu->a_Lc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sign_buffer = realloc(pki_applet->sign_buffer,
 | 
				
			||||||
 | 
					                      pki_applet->sign_buffer_len+size);
 | 
				
			||||||
 | 
					        if (sign_buffer == NULL) {
 | 
				
			||||||
 | 
					            qemu_free(pki_applet->sign_buffer);
 | 
				
			||||||
 | 
					            pki_applet->sign_buffer = NULL;
 | 
				
			||||||
 | 
					            pki_applet->sign_buffer_len = 0;
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
 | 
				
			||||||
 | 
					            return VCARD_DONE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
 | 
				
			||||||
 | 
					        size += pki_applet->sign_buffer_len;
 | 
				
			||||||
 | 
					        switch (apdu->a_p1) {
 | 
				
			||||||
 | 
					        case  0x80:
 | 
				
			||||||
 | 
					            /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
 | 
				
			||||||
 | 
					             * the rest */
 | 
				
			||||||
 | 
					            pki_applet->sign_buffer = sign_buffer;
 | 
				
			||||||
 | 
					            pki_applet->sign_buffer_len = size;
 | 
				
			||||||
 | 
					            *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
 | 
				
			||||||
 | 
					            return VCARD_DONE;
 | 
				
			||||||
 | 
					        case 0x00:
 | 
				
			||||||
 | 
					            /* we now have the whole buffer, do the operation, result will be
 | 
				
			||||||
 | 
					             * in the sign_buffer */
 | 
				
			||||||
 | 
					            status = vcard_emul_rsa_op(card, pki_applet->key,
 | 
				
			||||||
 | 
					                                       sign_buffer, size);
 | 
				
			||||||
 | 
					            if (status != VCARD7816_STATUS_SUCCESS) {
 | 
				
			||||||
 | 
					                *response = vcard_make_response(status);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            *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);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					           *response = vcard_make_response(
 | 
				
			||||||
 | 
					                                VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        qemu_free(sign_buffer);
 | 
				
			||||||
 | 
					        pki_applet->sign_buffer = NULL;
 | 
				
			||||||
 | 
					        pki_applet->sign_buffer_len = 0;
 | 
				
			||||||
 | 
					        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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                           VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                                  VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (apdu->a_ins) {
 | 
				
			||||||
 | 
					    case CAC_READ_BUFFER:
 | 
				
			||||||
 | 
					    case CAC_UPDATE_BUFFER:
 | 
				
			||||||
 | 
					        *response = vcard_make_response(
 | 
				
			||||||
 | 
					                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return cac_common_process_apdu(card, apdu, response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * utilities for creating and destroying the private applet data
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CACPKIAppletData *pki_applet_data = NULL;
 | 
				
			||||||
 | 
					    if (pki_applet_data == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pki_applet_data = &(applet_private->u.pki_data);
 | 
				
			||||||
 | 
					    if (pki_applet_data->cert != NULL) {
 | 
				
			||||||
 | 
					        qemu_free(pki_applet_data->cert);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (pki_applet_data->sign_buffer != NULL) {
 | 
				
			||||||
 | 
					        qemu_free(pki_applet_data->sign_buffer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (pki_applet_data->key != NULL) {
 | 
				
			||||||
 | 
					        vcard_emul_delete_key(pki_applet_data->key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_free(applet_private);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VCardAppletPrivate *
 | 
				
			||||||
 | 
					cac_new_pki_applet_private(const unsigned char *cert,
 | 
				
			||||||
 | 
					                           int cert_len, VCardKey *key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CACPKIAppletData *pki_applet_data = NULL;
 | 
				
			||||||
 | 
					    VCardAppletPrivate *applet_private = NULL;
 | 
				
			||||||
 | 
					    applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    pki_applet_data->sign_buffer_len = 0;
 | 
				
			||||||
 | 
					    pki_applet_data->key = NULL;
 | 
				
			||||||
 | 
					    pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1);
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * if we want to support compression, then we simply change the 0 to a 1
 | 
				
			||||||
 | 
					     * and compress the cert data with libz
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    pki_applet_data->cert[0] = 0; /* not compressed */
 | 
				
			||||||
 | 
					    memcpy(&pki_applet_data->cert[1], cert, cert_len);
 | 
				
			||||||
 | 
					    pki_applet_data->cert_len = cert_len+1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pki_applet_data->key = key;
 | 
				
			||||||
 | 
					    return applet_private;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * create a new cac applet which links to a given cert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardApplet *
 | 
				
			||||||
 | 
					cac_new_pki_applet(int i, const unsigned char *cert,
 | 
				
			||||||
 | 
					                   int cert_len, VCardKey *key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardAppletPrivate *applet_private = NULL;
 | 
				
			||||||
 | 
					    VCardApplet *applet = NULL;
 | 
				
			||||||
 | 
					    unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
 | 
				
			||||||
 | 
					    int pki_aid_len = sizeof(pki_aid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pki_aid[pki_aid_len-1] = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    applet_private = cac_new_pki_applet_private(cert, cert_len, key);
 | 
				
			||||||
 | 
					    if (applet_private == NULL) {
 | 
				
			||||||
 | 
					        goto failure;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
 | 
				
			||||||
 | 
					                              pki_aid, pki_aid_len);
 | 
				
			||||||
 | 
					    if (applet == NULL) {
 | 
				
			||||||
 | 
					        goto failure;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_set_applet_private(applet, applet_private,
 | 
				
			||||||
 | 
					                             cac_delete_pki_applet_private);
 | 
				
			||||||
 | 
					    applet_private = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return applet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					failure:
 | 
				
			||||||
 | 
					    if (applet_private != NULL) {
 | 
				
			||||||
 | 
					        cac_delete_pki_applet_private(applet_private);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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(VReader *reader, VCard *card,
 | 
				
			||||||
 | 
					              const char *params,
 | 
				
			||||||
 | 
					              unsigned char * const *cert,
 | 
				
			||||||
 | 
					              int cert_len[],
 | 
				
			||||||
 | 
					              VCardKey *key[] /* adopt the keys*/,
 | 
				
			||||||
 | 
					              int cert_count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    VCardApplet *applet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* CAC Cards are VM Cards */
 | 
				
			||||||
 | 
					    vcard_set_type(card, VCARD_VM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* create one PKI applet for each cert */
 | 
				
			||||||
 | 
					    for (i = 0; i < cert_count; i++) {
 | 
				
			||||||
 | 
					        applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
 | 
				
			||||||
 | 
					        if (applet == NULL) {
 | 
				
			||||||
 | 
					            goto failure;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vcard_add_applet(card, applet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* create a default blank container applet */
 | 
				
			||||||
 | 
					    applet = vcard_new_applet(cac_applet_container_process_apdu,
 | 
				
			||||||
 | 
					                              NULL, cac_default_container_aid,
 | 
				
			||||||
 | 
					                              sizeof(cac_default_container_aid));
 | 
				
			||||||
 | 
					    if (applet == NULL) {
 | 
				
			||||||
 | 
					        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:
 | 
				
			||||||
 | 
					    return VCARD_FAIL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								libcacard/cac.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								libcacard/cac.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * defines the entry point for the cac card. Only used by cac.c anc
 | 
				
			||||||
 | 
					 * vcard_emul_type.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef 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
 | 
				
			||||||
							
								
								
									
										763
									
								
								libcacard/card_7816.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										763
									
								
								libcacard/card_7816.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,763 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Implement the 7816 portion of the card spec
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vcard_emul.h"
 | 
				
			||||||
 | 
					#include "card_7816.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * set the status bytes based on the status word
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned char sw1, sw2;
 | 
				
			||||||
 | 
					    response->b_status = status; /* make sure the status and swX representations
 | 
				
			||||||
 | 
					                                  * are consistent */
 | 
				
			||||||
 | 
					    sw1 = (status >> 8) & 0xff;
 | 
				
			||||||
 | 
					    sw2 = status & 0xff;
 | 
				
			||||||
 | 
					    response->b_sw1 = sw1;
 | 
				
			||||||
 | 
					    response->b_sw2 = sw2;
 | 
				
			||||||
 | 
					    response->b_data[response->b_len] = sw1;
 | 
				
			||||||
 | 
					    response->b_data[response->b_len+1] = sw2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * set the status bytes in a response buffer
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vcard_response_set_status_bytes(VCardResponse *response,
 | 
				
			||||||
 | 
					                               unsigned char sw1, unsigned char sw2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    response->b_status = sw1 << 8 | sw2;
 | 
				
			||||||
 | 
					    response->b_sw1 = sw1;
 | 
				
			||||||
 | 
					    response->b_sw2 = sw2;
 | 
				
			||||||
 | 
					    response->b_data[response->b_len] = sw1;
 | 
				
			||||||
 | 
					    response->b_data[response->b_len+1] = sw2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * allocate a VCardResponse structure, plus space for the data buffer, and
 | 
				
			||||||
 | 
					 * set up everything but the resonse bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardResponse *
 | 
				
			||||||
 | 
					vcard_response_new_data(unsigned char *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardResponse *new_response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
 | 
				
			||||||
 | 
					    new_response->b_data = qemu_malloc(len + 2);
 | 
				
			||||||
 | 
					    memcpy(new_response->b_data, buf, len);
 | 
				
			||||||
 | 
					    new_response->b_total_len = len+2;
 | 
				
			||||||
 | 
					    new_response->b_len = len;
 | 
				
			||||||
 | 
					    new_response->b_type = VCARD_MALLOC;
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_set_buffer_response(card, buffer_response);
 | 
				
			||||||
 | 
					    return response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * general buffer to hold results from APDU calls
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardResponse *
 | 
				
			||||||
 | 
					vcard_response_new(VCard *card, unsigned char *buf,
 | 
				
			||||||
 | 
					                   int len, int Le, vcard_7816_status_t 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_response_set_status(new_response, status);
 | 
				
			||||||
 | 
					    return new_response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * general buffer to hold results from APDU calls
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardResponse *
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_response_set_status_bytes(new_response, sw1, sw2);
 | 
				
			||||||
 | 
					    return new_response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * get a new Reponse buffer that only has a status.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardResponse *
 | 
				
			||||||
 | 
					vcard_response_new_status(vcard_7816_status_t status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardResponse *new_response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    vcard_response_set_status(new_response, status);
 | 
				
			||||||
 | 
					    return new_response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * same as above, but specify the status as separate bytes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardResponse *
 | 
				
			||||||
 | 
					vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardResponse *new_response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse));
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    vcard_response_set_status_bytes(new_response, sw1, sw2);
 | 
				
			||||||
 | 
					    return new_response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * free the response buffer. The Buffer has a type to handle the buffer
 | 
				
			||||||
 | 
					 * allocated in other ways than through malloc.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_response_delete(VCardResponse *response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (response == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (response->b_type) {
 | 
				
			||||||
 | 
					    case VCARD_MALLOC:
 | 
				
			||||||
 | 
					        /* everything was malloc'ed */
 | 
				
			||||||
 | 
					        if (response->b_data) {
 | 
				
			||||||
 | 
					            qemu_free(response->b_data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        qemu_free(response);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VCARD_MALLOC_DATA:
 | 
				
			||||||
 | 
					        /* only the data buffer was malloc'ed */
 | 
				
			||||||
 | 
					        if (response->b_data) {
 | 
				
			||||||
 | 
					            qemu_free(response->b_data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VCARD_MALLOC_STRUCT:
 | 
				
			||||||
 | 
					        /* only the structure was malloc'ed */
 | 
				
			||||||
 | 
					        qemu_free(response);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VCARD_STATIC:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * decode the class bit and set our generic type field, channel, and
 | 
				
			||||||
 | 
					 * secure messaging values.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static vcard_7816_status_t
 | 
				
			||||||
 | 
					vcard_apdu_set_class(VCardAPDU *apdu) {
 | 
				
			||||||
 | 
					    apdu->a_channel = 0;
 | 
				
			||||||
 | 
					    apdu->a_secure_messaging = 0;
 | 
				
			||||||
 | 
					    apdu->a_type = apdu->a_cla & 0xf0;
 | 
				
			||||||
 | 
					    apdu->a_gen_type = VCARD_7816_ISO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* parse the class  tables 8 & 9 of the 7816-4 Part 4 spec */
 | 
				
			||||||
 | 
					    switch (apdu->a_type) {
 | 
				
			||||||
 | 
					        /* we only support the basic types */
 | 
				
			||||||
 | 
					    case 0x00:
 | 
				
			||||||
 | 
					    case 0x80:
 | 
				
			||||||
 | 
					    case 0x90:
 | 
				
			||||||
 | 
					    case 0xa0:
 | 
				
			||||||
 | 
					        apdu->a_channel = apdu->a_cla & 3;
 | 
				
			||||||
 | 
					        apdu->a_secure_messaging = apdu->a_cla & 0xe;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0xb0:
 | 
				
			||||||
 | 
					    case 0xc0:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case 0x10:
 | 
				
			||||||
 | 
					    case 0x20:
 | 
				
			||||||
 | 
					    case 0x30:
 | 
				
			||||||
 | 
					    case 0x40:
 | 
				
			||||||
 | 
					    case 0x50:
 | 
				
			||||||
 | 
					    case 0x60:
 | 
				
			||||||
 | 
					    case 0x70:
 | 
				
			||||||
 | 
					        /* Reserved for future use */
 | 
				
			||||||
 | 
					        apdu->a_gen_type = VCARD_7816_RFU;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0xd0:
 | 
				
			||||||
 | 
					    case 0xe0:
 | 
				
			||||||
 | 
					    case 0xf0:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        apdu->a_gen_type =
 | 
				
			||||||
 | 
					            (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * set the Le and Lc fiels according to table 5 of the
 | 
				
			||||||
 | 
					 * 7816-4 part 4 spec
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static vcard_7816_status_t
 | 
				
			||||||
 | 
					vcard_apdu_set_length(VCardAPDU *apdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int L, Le;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* process according to table 5 of the 7816-4 Part 4 spec.
 | 
				
			||||||
 | 
					     * variable names match the variables in the spec */
 | 
				
			||||||
 | 
					    L = apdu->a_len-4; /* fixed APDU header */
 | 
				
			||||||
 | 
					    apdu->a_Lc = 0;
 | 
				
			||||||
 | 
					    apdu->a_Le = 0;
 | 
				
			||||||
 | 
					    apdu->a_body = NULL;
 | 
				
			||||||
 | 
					    switch (L) {
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					        /* 1 minimal apdu */
 | 
				
			||||||
 | 
					        return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					    case 1:
 | 
				
			||||||
 | 
					        /* 2S only return values apdu */
 | 
				
			||||||
 | 
					        /*   zero maps to 256 here */
 | 
				
			||||||
 | 
					        apdu->a_Le = apdu->a_header->ah_Le ?
 | 
				
			||||||
 | 
					                         apdu->a_header->ah_Le : 256;
 | 
				
			||||||
 | 
					        return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        /* if the ah_Le byte is zero and we have more than
 | 
				
			||||||
 | 
					         * 1 byte in the header, then we must be using extended Le and Lc.
 | 
				
			||||||
 | 
					         * process the extended now. */
 | 
				
			||||||
 | 
					        if (apdu->a_header->ah_Le == 0) {
 | 
				
			||||||
 | 
					            if (L < 3) {
 | 
				
			||||||
 | 
					                /* coding error, need at least 3 bytes */
 | 
				
			||||||
 | 
					                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            /* calculate the first extended value. Could be either Le or Lc */
 | 
				
			||||||
 | 
					            Le = (apdu->a_header->ah_body[0] << 8)
 | 
				
			||||||
 | 
					               || apdu->a_header->ah_body[1];
 | 
				
			||||||
 | 
					            if (L == 3) {
 | 
				
			||||||
 | 
					                /* 2E extended, return data only */
 | 
				
			||||||
 | 
					                /*   zero maps to 65536 */
 | 
				
			||||||
 | 
					                apdu->a_Le = Le ? Le : 65536;
 | 
				
			||||||
 | 
					                return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (Le == 0) {
 | 
				
			||||||
 | 
					                /* reserved for future use, probably for next time we need
 | 
				
			||||||
 | 
					                 * to extend the lengths */
 | 
				
			||||||
 | 
					                return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            /* we know that the first extended value is Lc now */
 | 
				
			||||||
 | 
					            apdu->a_Lc = Le;
 | 
				
			||||||
 | 
					            apdu->a_body = &apdu->a_header->ah_body[2];
 | 
				
			||||||
 | 
					            if (L == Le+3) {
 | 
				
			||||||
 | 
					                /* 3E extended, only body parameters */
 | 
				
			||||||
 | 
					                return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (L == Le+5) {
 | 
				
			||||||
 | 
					                /* 4E extended, parameters and return data */
 | 
				
			||||||
 | 
					                Le = (apdu->a_data[apdu->a_len-2] << 8)
 | 
				
			||||||
 | 
					                   || apdu->a_data[apdu->a_len-1];
 | 
				
			||||||
 | 
					                apdu->a_Le = Le ? Le : 65536;
 | 
				
			||||||
 | 
					                return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /* not extended */
 | 
				
			||||||
 | 
					        apdu->a_Lc = apdu->a_header->ah_Le;
 | 
				
			||||||
 | 
					        apdu->a_body = &apdu->a_header->ah_body[0];
 | 
				
			||||||
 | 
					        if (L ==  apdu->a_Lc + 1) {
 | 
				
			||||||
 | 
					            /* 3S only body parameters */
 | 
				
			||||||
 | 
					            return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (L ==  apdu->a_Lc + 2) {
 | 
				
			||||||
 | 
					            /* 4S parameters and return data */
 | 
				
			||||||
 | 
					            Le = apdu->a_data[apdu->a_len-1];
 | 
				
			||||||
 | 
					            apdu->a_Le = Le ?  Le : 256;
 | 
				
			||||||
 | 
					            return VCARD7816_STATUS_SUCCESS;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return VCARD7816_STATUS_ERROR_WRONG_LENGTH;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * create a new APDU from a raw set of bytes. This will decode all the
 | 
				
			||||||
 | 
					 * above fields. users of VCARDAPDU's can then depend on the already decoded
 | 
				
			||||||
 | 
					 * values.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardAPDU *
 | 
				
			||||||
 | 
					vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardAPDU *new_apdu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
 | 
				
			||||||
 | 
					    if (len < 4) {
 | 
				
			||||||
 | 
					        *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH;
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_apdu = (VCardAPDU *)qemu_malloc(sizeof(VCardAPDU));
 | 
				
			||||||
 | 
					    new_apdu->a_data = qemu_malloc(len);
 | 
				
			||||||
 | 
					    memcpy(new_apdu->a_data, raw_apdu, len);
 | 
				
			||||||
 | 
					    new_apdu->a_len = len;
 | 
				
			||||||
 | 
					    *status = vcard_apdu_set_class(new_apdu);
 | 
				
			||||||
 | 
					    if (*status != VCARD7816_STATUS_SUCCESS) {
 | 
				
			||||||
 | 
					        qemu_free(new_apdu);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *status = vcard_apdu_set_length(new_apdu);
 | 
				
			||||||
 | 
					    if (*status != VCARD7816_STATUS_SUCCESS) {
 | 
				
			||||||
 | 
					        qemu_free(new_apdu);
 | 
				
			||||||
 | 
					        new_apdu = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new_apdu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_apdu_delete(VCardAPDU *apdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (apdu == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (apdu->a_data) {
 | 
				
			||||||
 | 
					        qemu_free(apdu->a_data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_free(apdu);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * declare response buffers for all the 7816 defined error codes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID)
 | 
				
			||||||
 | 
					VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * return a single response code. This function cannot fail. It will always
 | 
				
			||||||
 | 
					 * return a response.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardResponse *
 | 
				
			||||||
 | 
					vcard_make_response(vcard_7816_status_t status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardResponse *response = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (status) {
 | 
				
			||||||
 | 
					    /* known 7816 response codes */
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_SUCCESS:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_SUCCESS);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_RET_CORUPT:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_RET_CORUPT);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_CHANGE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_CHANGE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_WARNING_FILE_FILLED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_WARNING_FILE_FILLED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_EXC_ERROR:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_EXC_ERROR);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_EXC_ERROR_CHANGE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_EXC_ERROR_CHANGE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_WRONG_LENGTH:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_WRONG_LENGTH);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_DATA_INVALID:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_DATA_INVALID);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_DATA_NO_EF:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_DATA_NO_EF);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_INS_CODE_INVALID:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_INS_CODE_INVALID);
 | 
				
			||||||
 | 
					    case VCARD7816_STATUS_ERROR_CLA_INVALID:
 | 
				
			||||||
 | 
					        return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_CLA_INVALID);
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					         * hold it */
 | 
				
			||||||
 | 
					        response = vcard_response_new_status(status);
 | 
				
			||||||
 | 
					        if (response == NULL) {
 | 
				
			||||||
 | 
					            /* couldn't allocate the buffer, return memmory error */
 | 
				
			||||||
 | 
					            return VCARD_RESPONSE_GET_STATIC(
 | 
				
			||||||
 | 
					                        VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(response);
 | 
				
			||||||
 | 
					    return response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Add File card support here if you need it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                                   VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* TODO: if we want to support a virtual file system card, we do it here.
 | 
				
			||||||
 | 
					     * It would probably be a pkcs #15 card type */
 | 
				
			||||||
 | 
					    *response = vcard_make_response(
 | 
				
			||||||
 | 
					                    VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					    return VCARD_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * VM card (including java cards)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static VCardStatus
 | 
				
			||||||
 | 
					vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                          VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int bytes_to_copy, next_byte_count, count;
 | 
				
			||||||
 | 
					    VCardApplet *current_applet;
 | 
				
			||||||
 | 
					    VCardBufferResponse *buffer_response;
 | 
				
			||||||
 | 
					    vcard_7816_status_t status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* parse the class first */
 | 
				
			||||||
 | 
					    if (apdu->a_gen_type !=  VCARD_7816_ISO) {
 | 
				
			||||||
 | 
					        *response = vcard_make_response(
 | 
				
			||||||
 | 
					                        VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* use a switch so that if we need to support secure channel stuff later,
 | 
				
			||||||
 | 
					     * we know where to put it */
 | 
				
			||||||
 | 
					    switch (apdu->a_secure_messaging) {
 | 
				
			||||||
 | 
					    case 0x0: /* no SM */
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0x4: /* proprietary SM */
 | 
				
			||||||
 | 
					    case 0x8: /* header not authenticated */
 | 
				
			||||||
 | 
					    case 0xc: /* header authenticated */
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        /* for now, don't try to support secure channel stuff in the
 | 
				
			||||||
 | 
					         * virtual card. */
 | 
				
			||||||
 | 
					        *response = vcard_make_response(
 | 
				
			||||||
 | 
					                        VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        return VCARD_DONE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* now parse the instruction */
 | 
				
			||||||
 | 
					    switch (apdu->a_ins) {
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_GET_CHALLENGE: /* secure channel op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_ERASE_BINARY: /* applet control op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_READ_BINARY: /* applet control op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_WRITE_BINARY: /* applet control op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_UPDATE_BINARY: /* applet control op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_READ_RECORD: /* file op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_WRITE_RECORD: /* file op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_UPDATE_RECORD: /* file op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_APPEND_RECORD: /* file op */
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_ENVELOPE:
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_PUT_DATA:
 | 
				
			||||||
 | 
					        *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case  VCARD7816_INS_SELECT_FILE:
 | 
				
			||||||
 | 
					        if (apdu->a_p1 != 0x04) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* 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);
 | 
				
			||||||
 | 
					        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:
 | 
				
			||||||
 | 
					        if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_ERROR_WRONG_PARAMETERS);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (apdu->a_Lc == 0) {
 | 
				
			||||||
 | 
					                /* handle pin count if possible */
 | 
				
			||||||
 | 
					                count = vcard_emul_get_login_count(card);
 | 
				
			||||||
 | 
					                if (count < 0) {
 | 
				
			||||||
 | 
					                    *response = vcard_make_response(
 | 
				
			||||||
 | 
					                                    VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    if (count > 0xf) {
 | 
				
			||||||
 | 
					                        count = 0xf;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    *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);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                    status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc);
 | 
				
			||||||
 | 
					                *response = vcard_make_response(status);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case VCARD7816_INS_GET_RESPONSE:
 | 
				
			||||||
 | 
					        buffer_response = vcard_get_buffer_response(card);
 | 
				
			||||||
 | 
					        if (!buffer_response) {
 | 
				
			||||||
 | 
					            *response = vcard_make_response(
 | 
				
			||||||
 | 
					                            VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
 | 
				
			||||||
 | 
					            /* handle error */
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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(
 | 
				
			||||||
 | 
					                        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;
 | 
				
			||||||
 | 
					        buffer_response->len -= bytes_to_copy;
 | 
				
			||||||
 | 
					        if (*response == NULL || (next_byte_count == 0)) {
 | 
				
			||||||
 | 
					            vcard_set_buffer_response(card, NULL);
 | 
				
			||||||
 | 
					            vcard_buffer_response_delete(buffer_response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (*response == NULL) {
 | 
				
			||||||
 | 
					            *response =
 | 
				
			||||||
 | 
					                vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case VCARD7816_INS_GET_DATA:
 | 
				
			||||||
 | 
					        *response =
 | 
				
			||||||
 | 
					            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        *response =
 | 
				
			||||||
 | 
					            vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* response should have been set somewhere */
 | 
				
			||||||
 | 
					    assert(*response != NULL);
 | 
				
			||||||
 | 
					    return VCARD_DONE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * APDU processing starts here. This routes the card processing stuff to the
 | 
				
			||||||
 | 
					 * right location.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					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) {
 | 
				
			||||||
 | 
					        /* the PTS responses aren't really responses either */
 | 
				
			||||||
 | 
					        *response = vcard_response_new_data(apdu->a_data, apdu->a_len);
 | 
				
			||||||
 | 
					        /* PTS responses have no status bytes */
 | 
				
			||||||
 | 
					        (*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) {
 | 
				
			||||||
 | 
					        return status;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (vcard_get_type(card)) {
 | 
				
			||||||
 | 
					    case VCARD_FILE_SYSTEM:
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								libcacard/card_7816.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								libcacard/card_7816.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Implement the 7816 portion of the card spec
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef CARD_7816_H
 | 
				
			||||||
 | 
					#define CARD_7816_H  1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "card_7816t.h"
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * constructors for VCardResponse's
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* response from a return buffer and a status */
 | 
				
			||||||
 | 
					VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len,
 | 
				
			||||||
 | 
					                                  int Le, vcard_7816_status_t status);
 | 
				
			||||||
 | 
					/* response from a return buffer and status bytes */
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					/* response from just status: NOTE this cannot fail, it will alwyas return a
 | 
				
			||||||
 | 
					 * valid response, if it can't allocate memory, the response will be
 | 
				
			||||||
 | 
					 * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */
 | 
				
			||||||
 | 
					VCardResponse *vcard_make_response(vcard_7816_status_t 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vcard_response_delete(VCardResponse *response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * constructor for VCardAPDU
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len,
 | 
				
			||||||
 | 
					                          unsigned short *status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * destructor for VCardAPDU
 | 
				
			||||||
 | 
					 *  Can be called with a NULL apdu
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vcard_apdu_delete(VCardAPDU *apdu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * APDU processing starts here. This routes the card processing stuff to the
 | 
				
			||||||
 | 
					 * right location. Always returns a valid response.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                               VCardResponse **response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										165
									
								
								libcacard/card_7816t.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								libcacard/card_7816t.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Implement the 7816 portion of the card spec
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef CARD_7816T_H
 | 
				
			||||||
 | 
					#define CARD_7816T_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef unsigned short vcard_7816_status_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VCardResponseStruct {
 | 
				
			||||||
 | 
					    unsigned char *b_data;
 | 
				
			||||||
 | 
					    vcard_7816_status_t b_status;
 | 
				
			||||||
 | 
					    unsigned char b_sw1;
 | 
				
			||||||
 | 
					    unsigned char b_sw2;
 | 
				
			||||||
 | 
					    int b_len;
 | 
				
			||||||
 | 
					    int b_total_len;
 | 
				
			||||||
 | 
					    enum VCardResponseBufferType {
 | 
				
			||||||
 | 
					        VCARD_MALLOC,
 | 
				
			||||||
 | 
					        VCARD_MALLOC_DATA,
 | 
				
			||||||
 | 
					        VCARD_MALLOC_STRUCT,
 | 
				
			||||||
 | 
					        VCARD_STATIC
 | 
				
			||||||
 | 
					    } b_type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \
 | 
				
			||||||
 | 
					static const VCardResponse VCardResponse##stat = \
 | 
				
			||||||
 | 
					        {(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \
 | 
				
			||||||
 | 
					         ((stat) & 0xff), 0, 2, VCARD_STATIC};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \
 | 
				
			||||||
 | 
					static const VCardResponse VCARDResponse##sw1 = \
 | 
				
			||||||
 | 
					        {(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \
 | 
				
			||||||
 | 
					         (sw1), (sw2), 0, 2, VCARD_STATIC};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* cast away the const, callers need may need to 'free' the
 | 
				
			||||||
 | 
					 * result, and const implies that they don't */
 | 
				
			||||||
 | 
					#define VCARD_RESPONSE_GET_STATIC(name) \
 | 
				
			||||||
 | 
					        ((VCardResponse *)(&VCardResponse##name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VCARD_7816_ISO,
 | 
				
			||||||
 | 
					    VCARD_7816_RFU,
 | 
				
			||||||
 | 
					    VCARD_7816_PTS,
 | 
				
			||||||
 | 
					    VCARD_7816_PROPIETARY
 | 
				
			||||||
 | 
					} VCardAPDUType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 7816 header. All APDU's have this header.
 | 
				
			||||||
 | 
					 * They must be laid out in this order.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct VCardAPDUHeader {
 | 
				
			||||||
 | 
					    unsigned char ah_cla;
 | 
				
			||||||
 | 
					    unsigned char ah_ins;
 | 
				
			||||||
 | 
					    unsigned char ah_p1;
 | 
				
			||||||
 | 
					    unsigned char ah_p2;
 | 
				
			||||||
 | 
					    unsigned char ah_Le;
 | 
				
			||||||
 | 
					    unsigned char ah_body[1]; /* indefinate length */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 7816 APDU structure. The raw bytes are stored in the union and can be
 | 
				
			||||||
 | 
					 * accessed directly through u.data (which is aliased as a_data).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Names of the fields match the 7816 documentation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct VCardAPDUStruct {
 | 
				
			||||||
 | 
					    int a_len;                /* length of the whole buffer, including header */
 | 
				
			||||||
 | 
					    int a_Lc;                 /* 7816 Lc (parameter length) value */
 | 
				
			||||||
 | 
					    int a_Le;                 /* 7816 Le (expected result length) value */
 | 
				
			||||||
 | 
					    unsigned char *a_body;    /* pointer to the parameter */
 | 
				
			||||||
 | 
					    int a_channel;            /* decoded channel */
 | 
				
			||||||
 | 
					    int a_secure_messaging;   /* decoded secure messaging type */
 | 
				
			||||||
 | 
					    int a_type;               /* decoded type from cla (top nibble of class) */
 | 
				
			||||||
 | 
					    VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        struct VCardAPDUHeader *header;
 | 
				
			||||||
 | 
					        unsigned char   *data;
 | 
				
			||||||
 | 
					    } u;
 | 
				
			||||||
 | 
					/* give the subfields a unified look */
 | 
				
			||||||
 | 
					#define a_header u.header
 | 
				
			||||||
 | 
					#define a_data u.data
 | 
				
			||||||
 | 
					#define a_cla a_header->ah_cla /* class */
 | 
				
			||||||
 | 
					#define a_ins a_header->ah_ins /* instruction */
 | 
				
			||||||
 | 
					#define a_p1 a_header->ah_p1   /* parameter 1 */
 | 
				
			||||||
 | 
					#define a_p2 a_header->ah_p2   /* parameter 2 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 7816 status codes */
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_SUCCESS                              0x9000
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING                              0x6200
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_RET_CORUPT                   0x6281
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE            0x6282
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED        0x6283
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID           0x6284
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_CHANGE                       0x6300
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_WARNING_FILE_FILLED                  0x6381
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_EXC_ERROR                            0x6400
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_EXC_ERROR_CHANGE                     0x6500
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE             0x6581
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_WRONG_LENGTH                   0x6700
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED              0x6800
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED          0x6881
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED           0x6882
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED          0x6900
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED         0x6982
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED         0x6983
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_DATA_INVALID                   0x6984
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED        0x6985
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_DATA_NO_EF                     0x6986
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING              0x6987
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT            0x6988
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS               0x6a00
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA       0x6a80
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED         0x6a81
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND                 0x6a82
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND               0x6a83
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE              0x6a84
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT            0x6a85
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT                0x6a86
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT          0x6a87
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND                 0x6a88
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2             0x6b00
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID               0x6d00
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_CLA_INVALID                    0x6e00
 | 
				
			||||||
 | 
					#define VCARD7816_STATUS_ERROR_GENERAL                        0x6f00
 | 
				
			||||||
 | 
					/* 7816 sw1 codes */
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_SUCCESS               0x90
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_RESPONSE_BYTES        0x61
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_WARNING               0x62
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_WARNING_CHANGE        0x63
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_EXC_ERROR             0x64
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_EXC_ERROR_CHANGE      0x65
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_ERROR_WRONG_LENGTH    0x67
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_CLA_ERROR             0x68
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_COMMAND_ERROR         0x69
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_P1_P2_ERROR           0x6a
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_LE_ERROR              0x6c
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_INS_ERROR             0x6d
 | 
				
			||||||
 | 
					#define VCARD7816_SW1_CLA_NOT_SUPPORTED     0x6e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 7816 Instructions */
 | 
				
			||||||
 | 
					#define VCARD7816_INS_MANAGE_CHANNEL        0x70
 | 
				
			||||||
 | 
					#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82
 | 
				
			||||||
 | 
					#define VCARD7816_INS_GET_CHALLENGE         0x84
 | 
				
			||||||
 | 
					#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88
 | 
				
			||||||
 | 
					#define VCARD7816_INS_ERASE_BINARY          0x0e
 | 
				
			||||||
 | 
					#define VCARD7816_INS_READ_BINARY           0xb0
 | 
				
			||||||
 | 
					#define VCARD7816_INS_WRITE_BINARY          0xd0
 | 
				
			||||||
 | 
					#define VCARD7816_INS_UPDATE_BINARY         0xd6
 | 
				
			||||||
 | 
					#define VCARD7816_INS_READ_RECORD           0xb2
 | 
				
			||||||
 | 
					#define VCARD7816_INS_WRITE_RECORD          0xd2
 | 
				
			||||||
 | 
					#define VCARD7816_INS_UPDATE_RECORD         0xdc
 | 
				
			||||||
 | 
					#define VCARD7816_INS_APPEND_RECORD         0xe2
 | 
				
			||||||
 | 
					#define VCARD7816_INS_ENVELOPE              0xc2
 | 
				
			||||||
 | 
					#define VCARD7816_INS_PUT_DATA              0xda
 | 
				
			||||||
 | 
					#define VCARD7816_INS_GET_DATA              0xca
 | 
				
			||||||
 | 
					#define VCARD7816_INS_SELECT_FILE           0xa4
 | 
				
			||||||
 | 
					#define VCARD7816_INS_VERIFY                0x20
 | 
				
			||||||
 | 
					#define VCARD7816_INS_GET_RESPONSE          0xc0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										106
									
								
								libcacard/event.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								libcacard/event.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * event queue implementation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This code is licensed under the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "qemu-thread.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vreader.h"
 | 
				
			||||||
 | 
					#include "vevent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VEvent *
 | 
				
			||||||
 | 
					vevent_new(VEventType type, VReader *reader, VCard *card)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VEvent *new_vevent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_vevent = (VEvent *)qemu_malloc(sizeof(VEvent));
 | 
				
			||||||
 | 
					    new_vevent->next = NULL;
 | 
				
			||||||
 | 
					    new_vevent->type = type;
 | 
				
			||||||
 | 
					    new_vevent->reader = vreader_reference(reader);
 | 
				
			||||||
 | 
					    new_vevent->card = vcard_reference(card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new_vevent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vevent_delete(VEvent *vevent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (vevent == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_free(vevent->reader);
 | 
				
			||||||
 | 
					    vcard_free(vevent->card);
 | 
				
			||||||
 | 
					    qemu_free(vevent);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * VEvent queue management
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VEvent *vevent_queue_head;
 | 
				
			||||||
 | 
					static VEvent *vevent_queue_tail;
 | 
				
			||||||
 | 
					static QemuMutex vevent_queue_lock;
 | 
				
			||||||
 | 
					static QemuCond vevent_queue_condition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vevent_queue_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_init(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    qemu_cond_init(&vevent_queue_condition);
 | 
				
			||||||
 | 
					    vevent_queue_head = vevent_queue_tail = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vevent_queue_vevent(VEvent *vevent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vevent->next = NULL;
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    if (vevent_queue_head) {
 | 
				
			||||||
 | 
					        assert(vevent_queue_tail);
 | 
				
			||||||
 | 
					        vevent_queue_tail->next = vevent;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        vevent_queue_head = vevent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vevent_queue_tail = vevent;
 | 
				
			||||||
 | 
					    qemu_cond_signal(&vevent_queue_condition);
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* must have lock */
 | 
				
			||||||
 | 
					static VEvent *
 | 
				
			||||||
 | 
					vevent_dequeue_vevent(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VEvent *vevent = NULL;
 | 
				
			||||||
 | 
					    if (vevent_queue_head) {
 | 
				
			||||||
 | 
					        vevent = vevent_queue_head;
 | 
				
			||||||
 | 
					        vevent_queue_head = vevent->next;
 | 
				
			||||||
 | 
					        vevent->next = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return vevent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VEvent *vevent_wait_next_vevent(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VEvent *vevent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    while ((vevent = vevent_dequeue_vevent()) == NULL) {
 | 
				
			||||||
 | 
					        qemu_cond_wait(&vevent_queue_condition, &vevent_queue_lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    return vevent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VEvent *vevent_get_next_vevent(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VEvent *vevent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    vevent = vevent_dequeue_vevent();
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&vevent_queue_lock);
 | 
				
			||||||
 | 
					    return vevent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								libcacard/eventt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								libcacard/eventt.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef EVENTT_H
 | 
				
			||||||
 | 
					#define EVENTT_H 1
 | 
				
			||||||
 | 
					#include "vreadert.h"
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct VEventStruct VEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VEVENT_READER_INSERT,
 | 
				
			||||||
 | 
					    VEVENT_READER_REMOVE,
 | 
				
			||||||
 | 
					    VEVENT_CARD_INSERT,
 | 
				
			||||||
 | 
					    VEVENT_CARD_REMOVE,
 | 
				
			||||||
 | 
					    VEVENT_LAST,
 | 
				
			||||||
 | 
					} VEventType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VEventStruct {
 | 
				
			||||||
 | 
					    VEvent *next;
 | 
				
			||||||
 | 
					    VEventType type;
 | 
				
			||||||
 | 
					    VReader *reader;
 | 
				
			||||||
 | 
					    VCard *card;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								libcacard/link_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libcacard/link_test.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCardStatus cac_card_init(const char *flags, VCard *card,
 | 
				
			||||||
 | 
					                const unsigned char *cert[],
 | 
				
			||||||
 | 
					                int cert_len[], VCardKey *key[] /* adopt the keys*/,
 | 
				
			||||||
 | 
					                int cert_count);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * this will crash... just test the linkage right now
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCard *card; /* no constructor yet */
 | 
				
			||||||
 | 
					    cac_card_init("", card, NULL, 0, NULL, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										339
									
								
								libcacard/vcard.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								libcacard/vcard.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,339 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * implement the Java card standard.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vcard_emul.h"
 | 
				
			||||||
 | 
					#include "card_7816t.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VCardAppletStruct {
 | 
				
			||||||
 | 
					    VCardApplet   *next;
 | 
				
			||||||
 | 
					    VCardProcessAPDU process_apdu;
 | 
				
			||||||
 | 
					    VCardResetApplet reset_applet;
 | 
				
			||||||
 | 
					    unsigned char *aid;
 | 
				
			||||||
 | 
					    int aid_len;
 | 
				
			||||||
 | 
					    void *applet_private;
 | 
				
			||||||
 | 
					    VCardAppletPrivateFree applet_private_free;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VCardStruct {
 | 
				
			||||||
 | 
					    int reference_count;
 | 
				
			||||||
 | 
					    VCardApplet *applet_list;
 | 
				
			||||||
 | 
					    VCardApplet *current_applet[MAX_CHANNEL];
 | 
				
			||||||
 | 
					    VCardBufferResponse *vcard_buffer_response;
 | 
				
			||||||
 | 
					    VCardType type;
 | 
				
			||||||
 | 
					    VCardEmul *vcard_private;
 | 
				
			||||||
 | 
					    VCardEmulFree vcard_private_free;
 | 
				
			||||||
 | 
					    VCardGetAtr vcard_get_atr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCardBufferResponse *
 | 
				
			||||||
 | 
					vcard_buffer_response_new(unsigned char *buffer, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardBufferResponse *new_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_buffer = (VCardBufferResponse *)qemu_malloc(sizeof(VCardBufferResponse));
 | 
				
			||||||
 | 
					    new_buffer->buffer = (unsigned char *)qemu_malloc(size);
 | 
				
			||||||
 | 
					    memcpy(new_buffer->buffer, buffer, size);
 | 
				
			||||||
 | 
					    new_buffer->buffer_len = size;
 | 
				
			||||||
 | 
					    new_buffer->current = new_buffer->buffer;
 | 
				
			||||||
 | 
					    new_buffer->len = size;
 | 
				
			||||||
 | 
					    return new_buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_buffer_response_delete(VCardBufferResponse *buffer_response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (buffer_response == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (buffer_response->buffer) {
 | 
				
			||||||
 | 
					        qemu_free(buffer_response->buffer);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_free(buffer_response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * clean up state after a reset
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_reset(VCard *card, VCardPower power)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * applet utilities
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* constructor */
 | 
				
			||||||
 | 
					VCardApplet *
 | 
				
			||||||
 | 
					vcard_new_applet(VCardProcessAPDU applet_process_function,
 | 
				
			||||||
 | 
					                 VCardResetApplet applet_reset_function,
 | 
				
			||||||
 | 
					                 unsigned char *aid, int aid_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardApplet *applet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    applet = (VCardApplet *)qemu_malloc(sizeof(VCardApplet));
 | 
				
			||||||
 | 
					    applet->next = NULL;
 | 
				
			||||||
 | 
					    applet->applet_private = NULL;
 | 
				
			||||||
 | 
					    applet->applet_private_free = NULL;
 | 
				
			||||||
 | 
					    applet->process_apdu = applet_process_function;
 | 
				
			||||||
 | 
					    applet->reset_applet = applet_reset_function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    applet->aid = qemu_malloc(aid_len);
 | 
				
			||||||
 | 
					    memcpy(applet->aid, aid, aid_len);
 | 
				
			||||||
 | 
					    applet->aid_len = aid_len;
 | 
				
			||||||
 | 
					    return applet;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* destructor */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_delete_applet(VCardApplet *applet)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (applet == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (applet->applet_private_free) {
 | 
				
			||||||
 | 
					        applet->applet_private_free(applet->applet_private);
 | 
				
			||||||
 | 
					        applet->applet_private = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (applet->aid) {
 | 
				
			||||||
 | 
					        qemu_free(applet->aid);
 | 
				
			||||||
 | 
					        applet->aid = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_free(applet);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* accessor */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private,
 | 
				
			||||||
 | 
					                         VCardAppletPrivateFree private_free)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (applet->applet_private_free) {
 | 
				
			||||||
 | 
					        applet->applet_private_free(applet->applet_private);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    applet->applet_private = private;
 | 
				
			||||||
 | 
					    applet->applet_private_free = private_free;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCard *
 | 
				
			||||||
 | 
					vcard_new(VCardEmul *private, VCardEmulFree private_free)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCard *new_card;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_card = (VCard *)qemu_malloc(sizeof(VCard));
 | 
				
			||||||
 | 
					    new_card->applet_list = NULL;
 | 
				
			||||||
 | 
					    for (i = 0; i < MAX_CHANNEL; i++) {
 | 
				
			||||||
 | 
					        new_card->current_applet[i] = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    new_card->vcard_buffer_response = NULL;
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCard *
 | 
				
			||||||
 | 
					vcard_reference(VCard *vcard)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (vcard == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard->reference_count++;
 | 
				
			||||||
 | 
					    return vcard;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_free(VCard *vcard)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardApplet *current_applet = NULL;
 | 
				
			||||||
 | 
					    VCardApplet *next_applet = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (vcard == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard->reference_count--;
 | 
				
			||||||
 | 
					    if (vcard->reference_count != 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (vcard->vcard_private_free) {
 | 
				
			||||||
 | 
					        (*vcard->vcard_private_free)(vcard->vcard_private);
 | 
				
			||||||
 | 
					        vcard->vcard_private_free = 0;
 | 
				
			||||||
 | 
					        vcard->vcard_private = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (current_applet = vcard->applet_list; current_applet;
 | 
				
			||||||
 | 
					                                        current_applet = next_applet) {
 | 
				
			||||||
 | 
					        next_applet = current_applet->next;
 | 
				
			||||||
 | 
					        vcard_delete_applet(current_applet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_buffer_response_delete(vcard->vcard_buffer_response);
 | 
				
			||||||
 | 
					    qemu_free(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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardApplet *
 | 
				
			||||||
 | 
					vcard_find_applet(VCard *card, unsigned char *aid, int aid_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardApplet *current_applet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (current_applet = card->applet_list; current_applet;
 | 
				
			||||||
 | 
					                                        current_applet = current_applet->next) {
 | 
				
			||||||
 | 
					        if (current_applet->aid_len != aid_len) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (memcmp(current_applet->aid, aid, aid_len) == 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(channel < MAX_CHANNEL);
 | 
				
			||||||
 | 
					    card->current_applet[channel] = applet;
 | 
				
			||||||
 | 
					    /* reset the applet */
 | 
				
			||||||
 | 
					    if (applet && applet->reset_applet) {
 | 
				
			||||||
 | 
					        applet->reset_applet(card, channel);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCardAppletPrivate *
 | 
				
			||||||
 | 
					vcard_get_current_applet_private(VCard *card, int channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardApplet *applet = card->current_applet[channel];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (applet == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return applet->applet_private;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCardStatus
 | 
				
			||||||
 | 
					vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu,
 | 
				
			||||||
 | 
					                          VCardResponse **response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (card->current_applet[apdu->a_channel]) {
 | 
				
			||||||
 | 
					        return card->current_applet[apdu->a_channel]->process_apdu(
 | 
				
			||||||
 | 
					                                                        card, apdu, response);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return VCARD_NEXT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Accessor functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* accessor functions for the response buffer */
 | 
				
			||||||
 | 
					VCardBufferResponse *
 | 
				
			||||||
 | 
					vcard_get_buffer_response(VCard *card)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return card->vcard_buffer_response;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    card->vcard_buffer_response = buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* accessor functions for the type */
 | 
				
			||||||
 | 
					VCardType
 | 
				
			||||||
 | 
					vcard_get_type(VCard *card)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return card->type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vcard_set_type(VCard *card, VCardType type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    card->type = type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* accessor for private data */
 | 
				
			||||||
 | 
					VCardEmul *
 | 
				
			||||||
 | 
					vcard_get_private(VCard *vcard)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return vcard->vcard_private;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								libcacard/vcard.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								libcacard/vcard.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef VCARD_H
 | 
				
			||||||
 | 
					#define VCARD_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * response buffer constructors and destructors.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * response buffers are used when we need to return more data than will fit in
 | 
				
			||||||
 | 
					 * a normal APDU response (nominally 254 bytes).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardBufferResponse *vcard_buffer_response_new(unsigned char *buffer, int size);
 | 
				
			||||||
 | 
					void vcard_buffer_response_delete(VCardBufferResponse *buffer_response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * clean up state on reset
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vcard_reset(VCard *card, VCardPower power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * applet utilities
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Constructor for a VCardApplet
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function,
 | 
				
			||||||
 | 
					                              VCardResetApplet applet_reset_function,
 | 
				
			||||||
 | 
					                              unsigned char *aid, int aid_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * destructor for a VCardApplet
 | 
				
			||||||
 | 
					 *  Can be called with a NULL applet
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vcard_delete_applet(VCardApplet *applet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* accessor - set the card type specific private data */
 | 
				
			||||||
 | 
					void vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *_private,
 | 
				
			||||||
 | 
					                              VCardAppletPrivateFree private_free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* set type of vcard */
 | 
				
			||||||
 | 
					void vcard_set_type(VCard *card, VCardType type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * utilities interacting with the current applet
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* add a new applet to a card */
 | 
				
			||||||
 | 
					VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet);
 | 
				
			||||||
 | 
					/* find the applet on the card with the given aid */
 | 
				
			||||||
 | 
					VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len);
 | 
				
			||||||
 | 
					/* set the following applet to be current on the given channel */
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					                                      VCardResponse **response);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * VCard utilities
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* constructor */
 | 
				
			||||||
 | 
					VCard *vcard_new(VCardEmul *_private, VCardEmulFree private_free);
 | 
				
			||||||
 | 
					/* get a reference */
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer);
 | 
				
			||||||
 | 
					/* accessor functions for the type */
 | 
				
			||||||
 | 
					VCardType vcard_get_type(VCard *card);
 | 
				
			||||||
 | 
					/* get the private data */
 | 
				
			||||||
 | 
					VCardEmul *vcard_get_private(VCard *card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										65
									
								
								libcacard/vcard_emul.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								libcacard/vcard_emul.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the actual card emulator.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * These functions can be implemented in different ways on different platforms
 | 
				
			||||||
 | 
					 * using the underlying system primitives. For Linux it uses NSS, though direct
 | 
				
			||||||
 | 
					 * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
 | 
				
			||||||
 | 
					 * used. On Windows CAPI could be used.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef VCARD_EMUL_H
 | 
				
			||||||
 | 
					#define VCARD_EMUL_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "card_7816t.h"
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vcard_emul_type.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * types
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VCARD_EMUL_OK = 0,
 | 
				
			||||||
 | 
					    VCARD_EMUL_FAIL,
 | 
				
			||||||
 | 
					    /* return values by vcard_emul_init */
 | 
				
			||||||
 | 
					    VCARD_EMUL_INIT_ALREADY_INITED,
 | 
				
			||||||
 | 
					} VCardEmulError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* options are emul specific. call card_emul_parse_args to change a string
 | 
				
			||||||
 | 
					 * To an options struct */
 | 
				
			||||||
 | 
					typedef struct VCardEmulOptionsStruct VCardEmulOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Login functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* return the number of login attempts still possible on the card. if unknown,
 | 
				
			||||||
 | 
					 * return -1 */
 | 
				
			||||||
 | 
					int vcard_emul_get_login_count(VCard *card);
 | 
				
			||||||
 | 
					/* login into the card, return the 7816 status word (sw2 || sw1) */
 | 
				
			||||||
 | 
					vcard_7816_status_t vcard_emul_login(VCard *card, unsigned char *pin,
 | 
				
			||||||
 | 
					                                     int pin_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * key functions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/* delete a key */
 | 
				
			||||||
 | 
					void vcard_emul_delete_key(VCardKey *key);
 | 
				
			||||||
 | 
					/* RSA sign/decrypt with the key, signature happens 'in place' */
 | 
				
			||||||
 | 
					vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key,
 | 
				
			||||||
 | 
					                                  unsigned char *buffer, int buffer_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vcard_emul_reset(VCard *card, VCardPower power);
 | 
				
			||||||
 | 
					void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Re-insert of a card that has been removed by force removal */
 | 
				
			||||||
 | 
					VCardEmulError vcard_emul_force_card_insert(VReader *vreader);
 | 
				
			||||||
 | 
					/* Force a card removal even if the card is not physically removed */
 | 
				
			||||||
 | 
					VCardEmulError vcard_emul_force_card_remove(VReader *vreader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VCardEmulOptions *vcard_emul_options(const char *args);
 | 
				
			||||||
 | 
					VCardEmulError vcard_emul_init(const VCardEmulOptions *options);
 | 
				
			||||||
 | 
					void vcard_emul_replay_insertion_events(void);
 | 
				
			||||||
 | 
					void vcard_emul_usage(void);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										1157
									
								
								libcacard/vcard_emul_nss.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1157
									
								
								libcacard/vcard_emul_nss.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										57
									
								
								libcacard/vcard_emul_type.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								libcacard/vcard_emul_type.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					#include "vcard_emul_type.h"
 | 
				
			||||||
 | 
					#include "cac.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);
 | 
				
			||||||
 | 
					    /* 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								libcacard/vcard_emul_type.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								libcacard/vcard_emul_type.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  This header file abstracts the different card types. The goal is new card
 | 
				
			||||||
 | 
					 *  types can easily be added by simply changing this file and
 | 
				
			||||||
 | 
					 *  vcard_emul_type.c. It is currently not a requirement to dynamically add new
 | 
				
			||||||
 | 
					 *  card types.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef VCARD_EMUL_TYPE_H
 | 
				
			||||||
 | 
					#define VCARD_EMUL_TYPE_H 1
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					#include "vreadert.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * types
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					     VCARD_EMUL_NONE = 0,
 | 
				
			||||||
 | 
					     VCARD_EMUL_CAC,
 | 
				
			||||||
 | 
					     VCARD_EMUL_PASSTHRU
 | 
				
			||||||
 | 
					} VCardEmulType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* functions used by the rest of the emulator */
 | 
				
			||||||
 | 
					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(const char *type_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										64
									
								
								libcacard/vcardt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								libcacard/vcardt.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef VCARDT_H
 | 
				
			||||||
 | 
					#define VCARDT_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * these should come from some common spice header file
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#ifndef MIN
 | 
				
			||||||
 | 
					#define MIN(x, y) ((x) > (y) ? (y) : (x))
 | 
				
			||||||
 | 
					#define MAX(x, y) ((x) > (y) ? (x) : (y))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct VCardStruct VCard;
 | 
				
			||||||
 | 
					typedef struct VCardAPDUStruct VCardAPDU;
 | 
				
			||||||
 | 
					typedef struct VCardResponseStruct VCardResponse;
 | 
				
			||||||
 | 
					typedef struct VCardBufferResponseStruct VCardBufferResponse;
 | 
				
			||||||
 | 
					typedef struct VCardAppletStruct VCardApplet;
 | 
				
			||||||
 | 
					typedef struct VCardAppletPrivateStruct VCardAppletPrivate;
 | 
				
			||||||
 | 
					typedef struct VCardKeyStruct VCardKey;  /* opaque */
 | 
				
			||||||
 | 
					typedef struct VCardEmulStruct VCardEmul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_CHANNEL 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* create an ATR with appropriate historical bytes */
 | 
				
			||||||
 | 
					#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \
 | 
				
			||||||
 | 
					                               'V', 'C', 'A', 'R', 'D', '_'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VCARD_DONE,
 | 
				
			||||||
 | 
					    VCARD_NEXT,
 | 
				
			||||||
 | 
					    VCARD_FAIL
 | 
				
			||||||
 | 
					} VCardStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VCARD_FILE_SYSTEM,
 | 
				
			||||||
 | 
					    VCARD_VM,
 | 
				
			||||||
 | 
					    VCARD_DIRECT
 | 
				
			||||||
 | 
					} VCardType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VCARD_POWER_ON,
 | 
				
			||||||
 | 
					    VCARD_POWER_OFF
 | 
				
			||||||
 | 
					} VCardPower;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					    int buffer_len;
 | 
				
			||||||
 | 
					    unsigned char *current;
 | 
				
			||||||
 | 
					    int len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										27
									
								
								libcacard/vevent.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								libcacard/vevent.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef EVENT_H
 | 
				
			||||||
 | 
					#define EVENT_H 1
 | 
				
			||||||
 | 
					#include "eventt.h"
 | 
				
			||||||
 | 
					#include "vreadert.h"
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VEvent *vevent_new(VEventType type, VReader *reader, VCard *card);
 | 
				
			||||||
 | 
					void vevent_delete(VEvent *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * VEvent queueing services
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vevent_queue_vevent(VEvent *);
 | 
				
			||||||
 | 
					void vevent_queue_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  VEvent dequeing services
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VEvent *vevent_wait_next_vevent(void);
 | 
				
			||||||
 | 
					VEvent *vevent_get_next_vevent(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										513
									
								
								libcacard/vreader.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								libcacard/vreader.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,513 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * emulate the reader
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qemu-common.h"
 | 
				
			||||||
 | 
					#include "qemu-thread.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vcard.h"
 | 
				
			||||||
 | 
					#include "vcard_emul.h"
 | 
				
			||||||
 | 
					#include "card_7816.h"
 | 
				
			||||||
 | 
					#include "vreader.h"
 | 
				
			||||||
 | 
					#include "vevent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VReaderStruct {
 | 
				
			||||||
 | 
					    int    reference_count;
 | 
				
			||||||
 | 
					    VCard *card;
 | 
				
			||||||
 | 
					    char *name;
 | 
				
			||||||
 | 
					    vreader_id_t id;
 | 
				
			||||||
 | 
					    QemuMutex lock;
 | 
				
			||||||
 | 
					    VReaderEmul  *reader_private;
 | 
				
			||||||
 | 
					    VReaderEmulFree reader_private_free;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* manage locking */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					vreader_lock(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&reader->lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					vreader_unlock(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&reader->lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * vreader constructor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VReader *
 | 
				
			||||||
 | 
					vreader_new(const char *name, VReaderEmul *private,
 | 
				
			||||||
 | 
					            VReaderEmulFree private_free)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReader *reader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reader = (VReader *)qemu_malloc(sizeof(VReader));
 | 
				
			||||||
 | 
					    qemu_mutex_init(&reader->lock);
 | 
				
			||||||
 | 
					    reader->reference_count = 1;
 | 
				
			||||||
 | 
					    reader->name = name ? strdup(name) : NULL;
 | 
				
			||||||
 | 
					    reader->card = NULL;
 | 
				
			||||||
 | 
					    reader->id = (vreader_id_t)-1;
 | 
				
			||||||
 | 
					    reader->reader_private = private;
 | 
				
			||||||
 | 
					    reader->reader_private_free = private_free;
 | 
				
			||||||
 | 
					    return reader;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* get a reference */
 | 
				
			||||||
 | 
					VReader*
 | 
				
			||||||
 | 
					vreader_reference(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (reader == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_lock(reader);
 | 
				
			||||||
 | 
					    reader->reference_count++;
 | 
				
			||||||
 | 
					    vreader_unlock(reader);
 | 
				
			||||||
 | 
					    return reader;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* free a reference */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vreader_free(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (reader == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_lock(reader);
 | 
				
			||||||
 | 
					    if (reader->reference_count-- > 1) {
 | 
				
			||||||
 | 
					        vreader_unlock(reader);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_unlock(reader);
 | 
				
			||||||
 | 
					    if (reader->card) {
 | 
				
			||||||
 | 
					        vcard_free(reader->card);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (reader->name) {
 | 
				
			||||||
 | 
					        qemu_free(reader->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (reader->reader_private_free) {
 | 
				
			||||||
 | 
					        reader->reader_private_free(reader->reader_private);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_free(reader);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VCard *
 | 
				
			||||||
 | 
					vreader_get_card(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCard *card;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vreader_lock(reader);
 | 
				
			||||||
 | 
					    card = vcard_reference(reader->card);
 | 
				
			||||||
 | 
					    vreader_unlock(reader);
 | 
				
			||||||
 | 
					    return card;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_card_is_present(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCard *card = vreader_get_card(reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (card == NULL) {
 | 
				
			||||||
 | 
					        return VREADER_NO_CARD;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_free(card);
 | 
				
			||||||
 | 
					    return VREADER_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vreader_id_t
 | 
				
			||||||
 | 
					vreader_get_id(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (reader == NULL) {
 | 
				
			||||||
 | 
					        return (vreader_id_t)-1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return reader->id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_set_id(VReader *reader, vreader_id_t 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCard *card = vreader_get_card(reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (card == NULL) {
 | 
				
			||||||
 | 
					        return VREADER_NO_CARD;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * clean up our state
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    vcard_reset(card, power);
 | 
				
			||||||
 | 
					    if (atr) {
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return vreader_reset(reader, VCARD_POWER_ON, atr, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_power_off(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_xfr_bytes(VReader *reader,
 | 
				
			||||||
 | 
					                  unsigned char *send_buf, int send_buf_len,
 | 
				
			||||||
 | 
					                  unsigned char *receive_buf, int *receive_buf_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VCardAPDU *apdu;
 | 
				
			||||||
 | 
					    VCardResponse *response = NULL;
 | 
				
			||||||
 | 
					    VCardStatus card_status;
 | 
				
			||||||
 | 
					    unsigned short status;
 | 
				
			||||||
 | 
					    VCard *card = vreader_get_card(reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (card == NULL) {
 | 
				
			||||||
 | 
					        return VREADER_NO_CARD;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
 | 
				
			||||||
 | 
					    if (apdu == NULL) {
 | 
				
			||||||
 | 
					        response = vcard_make_response(status);
 | 
				
			||||||
 | 
					        card_status = VCARD_DONE;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        card_status = vcard_process_apdu(card, apdu, &response);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(card_status == VCARD_DONE);
 | 
				
			||||||
 | 
					    if (card_status == VCARD_DONE) {
 | 
				
			||||||
 | 
					        int size = MIN(*receive_buf_len, response->b_total_len);
 | 
				
			||||||
 | 
					        memcpy(receive_buf, response->b_data, size);
 | 
				
			||||||
 | 
					        *receive_buf_len = size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vcard_response_delete(response);
 | 
				
			||||||
 | 
					    vcard_apdu_delete(apdu);
 | 
				
			||||||
 | 
					    vcard_free(card); /* free our reference */
 | 
				
			||||||
 | 
					    return VREADER_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VReaderListStruct {
 | 
				
			||||||
 | 
					    VReaderListEntry *head;
 | 
				
			||||||
 | 
					    VReaderListEntry *tail;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VReaderListEntryStruct {
 | 
				
			||||||
 | 
					    VReaderListEntry *next;
 | 
				
			||||||
 | 
					    VReaderListEntry *prev;
 | 
				
			||||||
 | 
					    VReader *reader;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VReaderListEntry *
 | 
				
			||||||
 | 
					vreader_list_entry_new(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderListEntry *new_reader_list_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_reader_list_entry = (VReaderListEntry *)
 | 
				
			||||||
 | 
					                               qemu_malloc(sizeof(VReaderListEntry));
 | 
				
			||||||
 | 
					    new_reader_list_entry->next = NULL;
 | 
				
			||||||
 | 
					    new_reader_list_entry->prev = NULL;
 | 
				
			||||||
 | 
					    new_reader_list_entry->reader = vreader_reference(reader);
 | 
				
			||||||
 | 
					    return new_reader_list_entry;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_list_entry_delete(VReaderListEntry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (entry == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_free(entry->reader);
 | 
				
			||||||
 | 
					    qemu_free(entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VReaderList *
 | 
				
			||||||
 | 
					vreader_list_new(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderList *new_reader_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_reader_list = (VReaderList *)qemu_malloc(sizeof(VReaderList));
 | 
				
			||||||
 | 
					    new_reader_list->head = NULL;
 | 
				
			||||||
 | 
					    new_reader_list->tail = NULL;
 | 
				
			||||||
 | 
					    return new_reader_list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vreader_list_delete(VReaderList *list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderListEntry *current_entry;
 | 
				
			||||||
 | 
					    VReaderListEntry *next_entry = NULL;
 | 
				
			||||||
 | 
					    for (current_entry = vreader_list_get_first(list); current_entry;
 | 
				
			||||||
 | 
					         current_entry = next_entry) {
 | 
				
			||||||
 | 
					        next_entry = vreader_list_get_next(current_entry);
 | 
				
			||||||
 | 
					        vreader_list_entry_delete(current_entry);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    list->head = NULL;
 | 
				
			||||||
 | 
					    list->tail = NULL;
 | 
				
			||||||
 | 
					    qemu_free(list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderListEntry *
 | 
				
			||||||
 | 
					vreader_list_get_first(VReaderList *list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return list ? list->head : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderListEntry *
 | 
				
			||||||
 | 
					vreader_list_get_next(VReaderListEntry *current)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return current ? current->next : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReader *
 | 
				
			||||||
 | 
					vreader_list_get_reader(VReaderListEntry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return entry ? vreader_reference(entry->reader) : NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_queue(VReaderList *list, VReaderListEntry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (entry == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    entry->next = NULL;
 | 
				
			||||||
 | 
					    entry->prev = list->tail;
 | 
				
			||||||
 | 
					    if (list->head) {
 | 
				
			||||||
 | 
					        list->tail->next = entry;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        list->head = entry;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    list->tail = entry;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (entry == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (entry->next == NULL) {
 | 
				
			||||||
 | 
					        list->tail = entry->prev;
 | 
				
			||||||
 | 
					    } else if (entry->prev == NULL) {
 | 
				
			||||||
 | 
					        list->head = entry->next;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        entry->prev->next = entry->next;
 | 
				
			||||||
 | 
					        entry->next->prev = entry->prev;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ((list->tail == NULL) || (list->head == NULL)) {
 | 
				
			||||||
 | 
					        list->head = list->tail = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    entry->next = entry->prev = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VReaderList *vreader_list;
 | 
				
			||||||
 | 
					static QemuMutex vreader_list_mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_list_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vreader_list = vreader_list_new();
 | 
				
			||||||
 | 
					    qemu_mutex_init(&vreader_list_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_list_lock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_lock(&vreader_list_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					vreader_list_unlock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_mutex_unlock(&vreader_list_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VReaderList *
 | 
				
			||||||
 | 
					vreader_copy_list(VReaderList *list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderList *new_list = NULL;
 | 
				
			||||||
 | 
					    VReaderListEntry *current_entry = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_list = vreader_list_new();
 | 
				
			||||||
 | 
					    if (new_list == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (current_entry = vreader_list_get_first(list); current_entry;
 | 
				
			||||||
 | 
					         current_entry = vreader_list_get_next(current_entry)) {
 | 
				
			||||||
 | 
					        VReader *reader = vreader_list_get_reader(current_entry);
 | 
				
			||||||
 | 
					        VReaderListEntry *new_entry = vreader_list_entry_new(reader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vreader_free(reader);
 | 
				
			||||||
 | 
					        vreader_queue(new_list, new_entry);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new_list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderList *
 | 
				
			||||||
 | 
					vreader_get_reader_list(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderList *new_reader_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vreader_list_lock();
 | 
				
			||||||
 | 
					    new_reader_list = vreader_copy_list(vreader_list);
 | 
				
			||||||
 | 
					    vreader_list_unlock();
 | 
				
			||||||
 | 
					    return new_reader_list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReader *
 | 
				
			||||||
 | 
					vreader_get_reader_by_id(vreader_id_t id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReader *reader = NULL;
 | 
				
			||||||
 | 
					    VReaderListEntry *current_entry = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (id == (vreader_id_t) -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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderListEntry *reader_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reader_entry = vreader_list_entry_new(reader);
 | 
				
			||||||
 | 
					    if (reader_entry == NULL) {
 | 
				
			||||||
 | 
					        return VREADER_OUT_OF_MEMORY;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_list_lock();
 | 
				
			||||||
 | 
					    vreader_queue(vreader_list, reader_entry);
 | 
				
			||||||
 | 
					    vreader_list_unlock();
 | 
				
			||||||
 | 
					    vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
 | 
				
			||||||
 | 
					    return VREADER_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_remove_reader(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    VReaderListEntry *current_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vreader_list_lock();
 | 
				
			||||||
 | 
					    for (current_entry = vreader_list_get_first(vreader_list); current_entry;
 | 
				
			||||||
 | 
					         current_entry = vreader_list_get_next(current_entry)) {
 | 
				
			||||||
 | 
					        if (current_entry->reader == reader) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vreader_dequeue(vreader_list, current_entry);
 | 
				
			||||||
 | 
					    vreader_list_unlock();
 | 
				
			||||||
 | 
					    vreader_list_entry_delete(current_entry);
 | 
				
			||||||
 | 
					    vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
 | 
				
			||||||
 | 
					    return VREADER_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
 | 
				
			||||||
 | 
					 * state. Separated from vreader_insert_card to allow replaying events
 | 
				
			||||||
 | 
					 * for a given state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vreader_queue_card_event(VReader *reader)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vevent_queue_vevent(vevent_new(
 | 
				
			||||||
 | 
					        reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
 | 
				
			||||||
 | 
					        reader->card));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * insert/remove a new card. for removal, card == NULL
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VReaderStatus
 | 
				
			||||||
 | 
					vreader_insert_card(VReader *reader, VCard *card)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vreader_lock(reader);
 | 
				
			||||||
 | 
					    if (reader->card) {
 | 
				
			||||||
 | 
					        /* decrement reference count */
 | 
				
			||||||
 | 
					        vcard_free(reader->card);
 | 
				
			||||||
 | 
					        reader->card = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reader->card = vcard_reference(card);
 | 
				
			||||||
 | 
					    vreader_unlock(reader);
 | 
				
			||||||
 | 
					    vreader_queue_card_event(reader);
 | 
				
			||||||
 | 
					    return VREADER_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * initialize all the static reader structures
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					vreader_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vreader_list_init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										55
									
								
								libcacard/vreader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								libcacard/vreader.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef VREADER_H
 | 
				
			||||||
 | 
					#define VREADER_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eventt.h"
 | 
				
			||||||
 | 
					#include "vreadert.h"
 | 
				
			||||||
 | 
					#include "vcardt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * calls for reader front end
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					VReaderStatus vreader_power_on(VReader *reader, unsigned char *atr, int *len);
 | 
				
			||||||
 | 
					VReaderStatus vreader_power_off(VReader *reader);
 | 
				
			||||||
 | 
					VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf,
 | 
				
			||||||
 | 
					                                int send_buf_len, unsigned char *receive_buf,
 | 
				
			||||||
 | 
					                                int *receive_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* constructor */
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					void vreader_queue_card_event(VReader *reader);
 | 
				
			||||||
 | 
					const char *vreader_get_name(VReader *reader);
 | 
				
			||||||
 | 
					vreader_id_t vreader_get_id(VReader *reader);
 | 
				
			||||||
 | 
					VReaderStatus vreader_set_id(VReader *reader, vreader_id_t id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* list operations */
 | 
				
			||||||
 | 
					VReaderList *vreader_get_reader_list(void);
 | 
				
			||||||
 | 
					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(vreader_id_t id);
 | 
				
			||||||
 | 
					VReader *vreader_get_reader_by_name(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * list tools for vcard_emul
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void vreader_init(void);
 | 
				
			||||||
 | 
					VReaderStatus vreader_add_reader(VReader *reader);
 | 
				
			||||||
 | 
					VReaderStatus vreader_remove_reader(VReader *reader);
 | 
				
			||||||
 | 
					VReaderStatus vreader_insert_card(VReader *reader, VCard *card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										24
									
								
								libcacard/vreadert.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								libcacard/vreadert.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
				
			||||||
 | 
					 * See the COPYING.LIB file in the top-level directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef VREADERT_H
 | 
				
			||||||
 | 
					#define VREADERT_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VREADER_OK = 0,
 | 
				
			||||||
 | 
					    VREADER_NO_CARD,
 | 
				
			||||||
 | 
					    VREADER_OUT_OF_MEMORY
 | 
				
			||||||
 | 
					} VReaderStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef unsigned int vreader_id_t;
 | 
				
			||||||
 | 
					typedef struct VReaderStruct VReader;
 | 
				
			||||||
 | 
					typedef struct VReaderListStruct VReaderList;
 | 
				
			||||||
 | 
					typedef struct VReaderListEntryStruct VReaderListEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct VReaderEmulStruct VReaderEmul;
 | 
				
			||||||
 | 
					typedef void (*VReaderEmulFree)(VReaderEmul *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user