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-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: | ||||
| # 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 | ||||
| @ -152,7 +154,7 @@ clean: | ||||
| 	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp | ||||
| 	rm -f trace-dtrace.h trace-dtrace.h-timestamp | ||||
| 	$(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; \
 | ||||
| 	rm -f $$d/qemu-options.def; \
 | ||||
|         done | ||||
| @ -163,7 +165,7 @@ distclean: clean | ||||
| 	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-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 ; \
 | ||||
|         done | ||||
| 
 | ||||
|  | ||||
| @ -352,6 +352,11 @@ user-obj-y += qemu-timer-common.o | ||||
| 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+=$(SDL_CFLAGS) | ||||
|  | ||||
| @ -358,6 +358,12 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) | ||||
| 
 | ||||
| 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-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										49
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @ -176,6 +176,7 @@ trace_file="trace" | ||||
| spice="" | ||||
| rbd="" | ||||
| smartcard="" | ||||
| smartcard_nss="" | ||||
| 
 | ||||
| # parse CC options first | ||||
| for opt do | ||||
| @ -729,6 +730,10 @@ for opt do | ||||
|   ;; | ||||
|   --enable-smartcard) smartcard="yes" | ||||
|   ;; | ||||
|   --disable-smartcard-nss) smartcard_nss="no" | ||||
|   ;; | ||||
|   --enable-smartcard-nss) smartcard_nss="yes" | ||||
|   ;; | ||||
|   *) echo "ERROR: unknown option $opt"; show_help="yes" | ||||
|   ;; | ||||
|   esac | ||||
| @ -928,6 +933,8 @@ echo "  --enable-spice           enable spice" | ||||
| echo "  --enable-rbd             enable building the rados block device (rbd)" | ||||
| echo "  --disable-smartcard      disable 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 "NOTE: The object files are built at the place where configure is launched" | ||||
| exit 1 | ||||
| @ -2311,6 +2318,31 @@ EOF | ||||
|   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 "rbd support       $rbd" | ||||
| echo "xfsctl support    $xfs" | ||||
| echo "nss used          $smartcard_nss" | ||||
| 
 | ||||
| if test $sdl_too_old = "yes"; then | ||||
| 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 | ||||
| fi | ||||
| 
 | ||||
| if test "$smartcard_nss" = "yes" ; then | ||||
|   echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak | ||||
| fi | ||||
| 
 | ||||
| # XXX: suppress that | ||||
| if [ "$bsd" = "yes" ] ; then | ||||
|   echo "CONFIG_BSD=y" >> $config_host_mak | ||||
| @ -3183,6 +3220,11 @@ fi | ||||
| if test "$target_darwin_user" = "yes" ; then | ||||
|   echo "CONFIG_DARWIN_USER=y" >> $config_target_mak | ||||
| 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="" | ||||
| if test ! -z "$gdb_xml_files" ; then | ||||
|   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 | ||||
| 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 | ||||
| mkdir -p $d | ||||
| 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
	 Robert Relyea
						Robert Relyea