提交 7b02f544 编写于 作者: M Marc-André Lureau

libcacard: use the standalone project

libcacard is now a standalone project hosted with the Spice project (see
the 2.5.0 release announcement), remove it from qemu tree.

Use the library if found during configure or if --enable-smartcard.
Signed-off-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: NMichael Tokarev <mjt@tls.msk.ru>
Reviewed-by: NPaolo Bonzini <pbonzini@redhat.com>
Tested-by: NPaolo Bonzini <pbonzini@redhat.com>
上级 684bb577
......@@ -19,7 +19,6 @@
/trace/generated-ust.c
/ui/shader/texture-blit-frag.h
/ui/shader/texture-blit-vert.h
/libcacard/trace/generated-tracers.c
*-timestamp
/*-softmmu
/*-darwin-user
......
......@@ -163,9 +163,6 @@ dummy := $(call unnest-vars,, \
ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
endif
ifeq ($(CONFIG_SMARTCARD_NSS),y)
include $(SRC_PATH)/libcacard/Makefile
endif
all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
......
......@@ -32,18 +32,6 @@ crypto-aes-obj-y = crypto/
qom-obj-y = qom/
######################################################################
# smartcard
libcacard-y += libcacard/cac.o libcacard/event.o
libcacard-y += libcacard/vcard.o libcacard/vreader.o
libcacard-y += libcacard/vcard_emul_nss.o
libcacard-y += libcacard/vcard_emul_type.o
libcacard-y += libcacard/card_7816.o
libcacard-y += libcacard/vcardt.o
libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS)
libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS)
######################################################################
# Target independent part of system emulation. The long term path is to
# suppress *all* target specific code in case of system emulation, i.e. a
......@@ -85,8 +73,6 @@ common-obj-y += backends/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
common-obj-$(CONFIG_FDT) += device_tree.o
######################################################################
......
......@@ -302,7 +302,7 @@ trace_backends="nop"
trace_file="trace"
spice=""
rbd=""
smartcard_nss=""
smartcard=""
libusb=""
usb_redir=""
opengl=""
......@@ -1039,9 +1039,9 @@ for opt do
;;
--enable-xfsctl) xfs="yes"
;;
--disable-smartcard-nss) smartcard_nss="no"
--disable-smartcard) smartcard="no"
;;
--enable-smartcard-nss) smartcard_nss="yes"
--enable-smartcard) smartcard="yes"
;;
--disable-libusb) libusb="no"
;;
......@@ -1354,7 +1354,7 @@ disabled with --disable-FEATURE, default is enabled if available:
rbd rados block device (rbd)
libiscsi iscsi support
libnfs nfs support
smartcard-nss smartcard nss support
smartcard smartcard support (libcacard)
libusb libusb (for usb passthrough)
usb-redir usb network redirection support
lzo support of lzo compression library
......@@ -3810,34 +3810,20 @@ EOF
fi
fi
# check for libcacard for smartcard support
# check for smartcard support
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
cat > $TMPC << EOF
#include <pk11pub.h>
int main(void) { PK11_FreeSlot(0); return 0; }
EOF
# FIXME: do not include $glib_* in here
nss_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs"
nss_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags"
test_cflags="$nss_cflags"
# The header files in nss < 3.13.3 have a bug which causes them to
# emit a warning. If we're going to compile QEMU with -Werror, then
# test that the headers don't have this bug. Otherwise we would pass
# the configure test but fail to compile QEMU later.
if test "$werror" = "yes"; then
test_cflags="-Werror $test_cflags"
fi
if test -n "$libtool" &&
$pkg_config --atleast-version=3.12.8 nss && \
compile_prog "$test_cflags" "$nss_libs"; then
smartcard_nss="yes"
if test "$smartcard" != "no"; then
if $pkg_config libcacard; then
libcacard_cflags=$($pkg_config --cflags libcacard)
libcacard_libs=$($pkg_config --libs libcacard)
QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags"
libs_softmmu="$libs_softmmu $libcacard_libs"
smartcard="yes"
else
if test "$smartcard_nss" = "yes"; then
feature_not_found "nss" "Install nss devel >= 3.12.8"
if test "$smartcard" = "yes"; then
feature_not_found "smartcard" "Install libcacard devel"
fi
smartcard_nss="no"
smartcard="no"
fi
fi
......@@ -4618,7 +4604,7 @@ echo "spice support $spice"
fi
echo "rbd support $rbd"
echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "smartcard support $smartcard"
echo "libusb $libusb"
echo "usb net redir $usb_redir"
echo "OpenGL support $opengl"
......@@ -4995,10 +4981,8 @@ if test "$spice" = "yes" ; then
echo "CONFIG_SPICE=y" >> $config_host_mak
fi
if test "$smartcard_nss" = "yes" ; then
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
echo "NSS_LIBS=$nss_libs" >> $config_host_mak
echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak
if test "$smartcard" = "yes" ; then
echo "CONFIG_SMARTCARD=y" >> $config_host_mak
fi
if test "$libusb" = "yes" ; then
......
此差异已折叠。
......@@ -23,9 +23,8 @@ common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
ifeq ($(CONFIG_USB_SMARTCARD),y)
common-obj-y += dev-smartcard-reader.o
common-obj-y += ccid-card-passthru.o
common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
ccid-card-emulated.o-cflags := -I$(SRC_PATH)/libcacard
common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o
common-obj-$(CONFIG_SMARTCARD) += ccid-card-emulated.o
endif
ifeq ($(CONFIG_POSIX),y)
......
......@@ -12,7 +12,7 @@
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "ccid.h"
#include "libcacard/vscard_common.h"
#include "cacard/vscard_common.h"
#define DPRINTF(card, lvl, fmt, ...) \
do { \
......
libcacard_includedir=$(includedir)/cacard
TOOLS += vscclient$(EXESUF)
# objects linked into a shared library, built with libtool with -fPIC if required
libcacard-obj-y = $(libcacard-y)
libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y))
# libtool will build the .o files, too
$(libcacard-obj-y): | $(libcacard-lobj-y)
all: libcacard.la libcacard.pc
vscclient$(EXESUF): libcacard/vscclient.o libcacard.la
$(call LINK,$^)
#########################################################################
# Rules for building libcacard standalone library
libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \
-export-symbols $(SRC_PATH)/libcacard/libcacard.syms
# Prevent libcacard.so linking against the entire world of 3rd party libs
libcacard.la: LIBS =
libcacard.la: $(libcacard-lobj-y)
$(call LINK,$^)
libcacard.pc: $(SRC_PATH)/libcacard/libcacard.pc.in
$(call quiet-command,sed -e 's|@LIBDIR@|$(libdir)|' \
-e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \
-e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \
-e 's|@PREFIX@|$(prefix)|' $< > libcacard.pc,\
" GEN $@")
.PHONY: install-libcacard
install: install-libcacard
install-libcacard: libcacard.pc libcacard.la
$(INSTALL_DIR) "$(DESTDIR)$(libdir)"
$(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig"
$(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)"
$(INSTALL_LIB) libcacard.la "$(DESTDIR)$(libdir)"
$(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig"
for inc in $(SRC_PATH)/libcacard/*.h; do \
$(INSTALL_DATA) $$inc "$(DESTDIR)$(libcacard_includedir)"; \
done
/*
* 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 "glib-compat.h"
#include <string.h>
#include <stdbool.h>
#include "cac.h"
#include "vcard.h"
#include "vcard_emul.h"
#include "card_7816.h"
/* 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;
VCardStatus ret = VCARD_FAIL;
switch (apdu->a_ins) {
case VCARD7816_INS_SELECT_FILE:
if (apdu->a_p1 != 0x02) {
/* let the 7816 code handle applet switches */
ret = VCARD_NEXT;
break;
}
/* handle file id setting */
if (apdu->a_Lc != 2) {
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_DATA_INVALID);
ret = VCARD_DONE;
break;
}
/* 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);
ret = VCARD_DONE;
break;
}
*response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
ret = VCARD_DONE;
break;
case VCARD7816_INS_GET_RESPONSE:
case VCARD7816_INS_VERIFY:
/* let the 7816 code handle these */
ret = VCARD_NEXT;
break;
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);
ret = VCARD_DONE;
break;
default:
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
ret = VCARD_DONE;
break;
}
return ret;
}
/*
* reset the inter call state between applet selects
*/
static VCardStatus
cac_applet_pki_reset(VCard *card, int channel)
{
VCardAppletPrivate *applet_private;
CACPKIAppletData *pki_applet;
applet_private = vcard_get_current_applet_private(card, channel);
assert(applet_private);
pki_applet = &(applet_private->u.pki_data);
pki_applet->cert_buffer = NULL;
g_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;
VCardAppletPrivate *applet_private;
int size, next;
unsigned char *sign_buffer;
bool retain_sign_buffer = FALSE;
vcard_7816_status_t status;
VCardStatus ret = VCARD_FAIL;
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);
ret = VCARD_DONE;
break;
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);
}
ret = VCARD_DONE;
break;
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 = g_realloc(pki_applet->sign_buffer,
pki_applet->sign_buffer_len + size);
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);
retain_sign_buffer = TRUE;
break;
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;
}
if (!retain_sign_buffer) {
g_free(sign_buffer);
pki_applet->sign_buffer = NULL;
pki_applet->sign_buffer_len = 0;
}
ret = VCARD_DONE;
break;
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);
ret = VCARD_DONE;
break;
default:
ret = cac_common_process_apdu(card, apdu, response);
break;
}
return ret;
}
static VCardStatus
cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
VCardResponse **response)
{
VCardStatus ret = VCARD_FAIL;
switch (apdu->a_ins) {
case CAC_UPDATE_BUFFER:
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
ret = VCARD_DONE;
break;
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);
ret = VCARD_DONE;
break;
default:
ret = cac_common_process_apdu(card, apdu, response);
break;
}
return ret;
}
/*
* 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)
{
VCardStatus ret = VCARD_FAIL;
switch (apdu->a_ins) {
case CAC_READ_BUFFER:
case CAC_UPDATE_BUFFER:
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
ret = VCARD_DONE;
break;
default:
ret = cac_common_process_apdu(card, apdu, response);
break;
}
return ret;
}
/*
* utilities for creating and destroying the private applet data
*/
static void
cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
{
CACPKIAppletData *pki_applet_data;
if (applet_private == NULL) {
return;
}
pki_applet_data = &(applet_private->u.pki_data);
g_free(pki_applet_data->cert);
g_free(pki_applet_data->sign_buffer);
if (pki_applet_data->key != NULL) {
vcard_emul_delete_key(pki_applet_data->key);
}
g_free(applet_private);
}
static VCardAppletPrivate *
cac_new_pki_applet_private(const unsigned char *cert,
int cert_len, VCardKey *key)
{
CACPKIAppletData *pki_applet_data;
VCardAppletPrivate *applet_private;
applet_private = g_new0(VCardAppletPrivate, 1);
pki_applet_data = &(applet_private->u.pki_data);
pki_applet_data->cert = (unsigned char *)g_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;
VCardApplet *applet;
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;
}
/*
* 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"
#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
/*
* 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
此差异已折叠。
/*
* 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 always 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
/*
* 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_PROPRIETARY
} 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]; /* indefinite 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
/*
* 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 "glib-compat.h"
#include "vcard.h"
#include "vreader.h"
#include "vevent.h"
VEvent *
vevent_new(VEventType type, VReader *reader, VCard *card)
{
VEvent *new_vevent;
new_vevent = g_new(VEvent, 1);
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);
g_free(vevent);
}
/*
* VEvent queue management
*/
static VEvent *vevent_queue_head;
static VEvent *vevent_queue_tail;
static CompatGMutex vevent_queue_lock;
static CompatGCond vevent_queue_condition;
void vevent_queue_init(void)
{
vevent_queue_head = vevent_queue_tail = NULL;
}
void
vevent_queue_vevent(VEvent *vevent)
{
vevent->next = NULL;
g_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;
g_cond_signal(&vevent_queue_condition);
g_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;
g_mutex_lock(&vevent_queue_lock);
while ((vevent = vevent_dequeue_vevent()) == NULL) {
g_cond_wait(&vevent_queue_condition, &vevent_queue_lock);
}
g_mutex_unlock(&vevent_queue_lock);
return vevent;
}
VEvent *vevent_get_next_vevent(void)
{
VEvent *vevent;
g_mutex_lock(&vevent_queue_lock);
vevent = vevent_dequeue_vevent();
g_mutex_unlock(&vevent_queue_lock);
return vevent;
}
/*
* 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
prefix=@PREFIX@
exec_prefix=${prefix}
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
Name: cacard
Description: CA Card library
Version: @VERSION@
Requires.private: nss glib-2.0
Libs: -L${libdir} -lcacard
Libs.private:
Cflags: -I${includedir}
cac_card_init
cac_is_cac_card
vcard_add_applet
vcard_apdu_delete
vcard_apdu_new
vcard_applet_get_aid
vcard_buffer_response_delete
vcard_buffer_response_new
vcard_delete_applet
vcard_emul_delete_key
vcard_emul_force_card_insert
vcard_emul_force_card_remove
vcard_emul_get_atr
vcard_emul_get_login_count
vcard_emul_init
vcard_emul_login
vcard_emul_options
vcard_emul_replay_insertion_events
vcard_emul_reset
vcard_emul_rsa_op
vcard_emul_type_from_string
vcard_emul_type_select
vcard_emul_usage
vcard_find_applet
vcard_free
vcard_get_atr
vcard_get_buffer_response
vcard_get_current_applet_private
vcard_get_private
vcard_get_type
vcard_init
vcard_make_response
vcard_new
vcard_new_applet
vcard_process_apdu
vcard_process_applet_apdu
vcard_reference
vcard_reset
vcard_response_delete
vcard_response_new
vcard_response_new_bytes
vcard_response_new_data
vcard_response_new_status_bytes
vcard_select_applet
vcard_set_applet_private
vcard_set_atr_func
vcard_set_buffer_response
vcard_set_type
vevent_delete
vevent_get_next_vevent
vevent_new
vevent_queue_init
vevent_queue_vevent
vevent_wait_next_vevent
vreader_add_reader
vreader_card_is_present
vreader_free
vreader_get_id
vreader_get_name
vreader_get_private
vreader_get_reader_by_id
vreader_get_reader_by_name
vreader_get_reader_list
vreader_init
vreader_insert_card
vreader_list_delete
vreader_list_get_first
vreader_list_get_next
vreader_list_get_reader
vreader_new
vreader_power_off
vreader_power_on
vreader_queue_card_event
vreader_reference
vreader_remove_reader
vreader_set_id
vreader_xfr_bytes
/*
* 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);
}
/*
* 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 "glib-compat.h"
#include <string.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 = g_new(VCardBufferResponse, 1);
new_buffer->buffer = (unsigned char *)g_memdup(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;
}
g_free(buffer_response->buffer);
g_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 = g_new0(VCardApplet, 1);
applet->process_apdu = applet_process_function;
applet->reset_applet = applet_reset_function;
applet->aid = g_memdup(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);
}
g_free(applet->aid);
g_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;
new_card = g_new0(VCard, 1);
new_card->type = VCARD_VM;
new_card->vcard_private = private;
new_card->vcard_private_free = private_free;
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;
VCardApplet *next_applet;
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);
}
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);
g_free(vcard);
}
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);
/* If using an emulated card, make sure to log out of any already logged in
* session. */
vcard_emul_logout(card);
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;
}
/*
* 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
/*
* 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);
void vcard_emul_logout(VCard *card);
/*
* 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
此差异已折叠。
/*
* 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;
}
/*
* 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
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "vcardt.h"
#include "vcardt_internal.h"
/* create an ATR with appropriate historical bytes */
#define ATR_TS_DIRECT_CONVENTION 0x3b
#define ATR_TA_PRESENT 0x10
#define ATR_TB_PRESENT 0x20
#define ATR_TC_PRESENT 0x40
#define ATR_TD_PRESENT 0x80
unsigned char *vcard_alloc_atr(const char *postfix, int *atr_len)
{
int postfix_len;
const char prefix[] = "VCARD_";
const char default_postfix[] = "DEFAULT";
const int prefix_len = sizeof(prefix) - 1;
int total_len;
unsigned char *atr;
if (postfix == NULL) {
postfix = default_postfix;
}
postfix_len = strlen(postfix);
total_len = 3 + prefix_len + postfix_len;
atr = g_malloc(total_len);
atr[0] = ATR_TS_DIRECT_CONVENTION;
atr[1] = ATR_TD_PRESENT + prefix_len + postfix_len;
atr[2] = 0x00;
memcpy(&atr[3], prefix, prefix_len);
memcpy(&atr[3 + prefix_len], postfix, postfix_len);
if (atr_len) {
*atr_len = total_len;
}
return atr;
}
/*
* 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
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
#ifndef VCARDT_INTERNAL_H
#define VCARDT_INTERNAL_H
unsigned char *vcard_alloc_atr(const char *postfix, int *atr_len);
#endif
/*
* 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
/*
* 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.
*/
#ifdef G_LOG_DOMAIN
#undef G_LOG_DOMAIN
#endif
#define G_LOG_DOMAIN "libcacard"
#include "glib-compat.h"
#include <string.h>
#include "vcard.h"
#include "vcard_emul.h"
#include "card_7816.h"
#include "vreader.h"
#include "vevent.h"
#include "cac.h" /* just for debugging defines */
#define LIBCACARD_LOG_DOMAIN "libcacard"
struct VReaderStruct {
int reference_count;
VCard *card;
char *name;
vreader_id_t id;
CompatGMutex lock;
VReaderEmul *reader_private;
VReaderEmulFree reader_private_free;
};
/*
* Debug helpers
*/
static const char *
apdu_ins_to_string(int ins)
{
switch (ins) {
case VCARD7816_INS_MANAGE_CHANNEL:
return "manage channel";
case VCARD7816_INS_EXTERNAL_AUTHENTICATE:
return "external authenticate";
case VCARD7816_INS_GET_CHALLENGE:
return "get challenge";
case VCARD7816_INS_INTERNAL_AUTHENTICATE:
return "internal authenticate";
case VCARD7816_INS_ERASE_BINARY:
return "erase binary";
case VCARD7816_INS_READ_BINARY:
return "read binary";
case VCARD7816_INS_WRITE_BINARY:
return "write binary";
case VCARD7816_INS_UPDATE_BINARY:
return "update binary";
case VCARD7816_INS_READ_RECORD:
return "read record";
case VCARD7816_INS_WRITE_RECORD:
return "write record";
case VCARD7816_INS_UPDATE_RECORD:
return "update record";
case VCARD7816_INS_APPEND_RECORD:
return "append record";
case VCARD7816_INS_ENVELOPE:
return "envelope";
case VCARD7816_INS_PUT_DATA:
return "put data";
case VCARD7816_INS_GET_DATA:
return "get data";
case VCARD7816_INS_SELECT_FILE:
return "select file";
case VCARD7816_INS_VERIFY:
return "verify";
case VCARD7816_INS_GET_RESPONSE:
return "get response";
case CAC_GET_PROPERTIES:
return "get properties";
case CAC_GET_ACR:
return "get acr";
case CAC_READ_BUFFER:
return "read buffer";
case CAC_UPDATE_BUFFER:
return "update buffer";
case CAC_SIGN_DECRYPT:
return "sign decrypt";
case CAC_GET_CERTIFICATE:
return "get certificate";
}
return "unknown";
}
/* manage locking */
static inline void
vreader_lock(VReader *reader)
{
g_mutex_lock(&reader->lock);
}
static inline void
vreader_unlock(VReader *reader)
{
g_mutex_unlock(&reader->lock);
}
/*
* vreader constructor
*/
VReader *
vreader_new(const char *name, VReaderEmul *private,
VReaderEmulFree private_free)
{
VReader *reader;
reader = g_new(VReader, 1);
g_mutex_init(&reader->lock);
reader->reference_count = 1;
reader->name = g_strdup(name);
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);
g_mutex_clear(&reader->lock);
if (reader->card) {
vcard_free(reader->card);
}
g_free(reader->name);
if (reader->reader_private_free) {
reader->reader_private_free(reader->reader_private);
}
g_free(reader);
}
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 {
g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s",
__func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2,
apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins));
card_status = vcard_process_apdu(card, apdu, &response);
if (response) {
g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)",
__func__, response->b_status, response->b_sw1,
response->b_sw2, response->b_len, response->b_total_len);
}
}
assert(card_status == VCARD_DONE && response);
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 = g_new0(VReaderListEntry, 1);
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);
g_free(entry);
}
static VReaderList *
vreader_list_new(void)
{
VReaderList *new_reader_list;
new_reader_list = g_new0(VReaderList, 1);
return new_reader_list;
}
void
vreader_list_delete(VReaderList *list)
{
VReaderListEntry *current_entry;
VReaderListEntry *next_entry;
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);
}
g_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 CompatGMutex vreader_list_mutex;
static void
vreader_list_init(void)
{
vreader_list = vreader_list_new();
}
static void
vreader_list_lock(void)
{
g_mutex_lock(&vreader_list_mutex);
}
static void
vreader_list_unlock(void)
{
g_mutex_unlock(&vreader_list_mutex);
}
static VReaderList *
vreader_copy_list(VReaderList *list)
{
VReaderList *new_list;
VReaderListEntry *current_entry;
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;
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;
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();
}
/*
* 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
/*
* 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
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册