diff --git a/virtualsmartcard/Makefile b/virtualsmartcard/Makefile index 15a696e..6bc5c80 100644 --- a/virtualsmartcard/Makefile +++ b/virtualsmartcard/Makefile @@ -34,10 +34,14 @@ TARGETS = libvpcd.so configuration virtualsmartcard # top-level rule all: $(TARGETS) -libvpcd.so: vpcd/vpcd.c vpcd/vpcd.h - $(CC) $(LIBPCSCLITE_CFLAGS) $(SO_CFLAGS) $(CFLAGS) -c $< -o $(@:%.so=%.o) - $(LD) $(LDFLAGS) $(@:%.so=%.o) -o $@ -soname=$@.1 -lc - rm -f $(@:%.so=%.o) +ifd.o: vpcd/ifd.c + $(CC) $(SO_CFLAGS) $(CFLAGS) $(LIBPCSCLITE_CFLAGS) -c $< -o $@ + +vpcd.o: vpcd/vpcd.c vpcd/vpcd.h + $(CC) $(SO_CFLAGS) $(CFLAGS) -c $< -o $@ + +libvpcd.so: ifd.o vpcd.o + $(LD) $(LDFLAGS) $^ -o $@ -soname=$@.1 -lc .PHONY: virtualsmartcard virtualsmartcard: @@ -103,6 +107,8 @@ uninstall: .PHONY: clean clean: - rm -f libvpcd.so - rm -f vpcd.conf - rm -f virtualsmartcard + rm -f libvpcd.so \ + ifd.o \ + vpcd.o \ + vpcd.conf \ + virtualsmartcard diff --git a/virtualsmartcard/vpcd/ifd.c b/virtualsmartcard/vpcd/ifd.c new file mode 100644 index 0000000..80ff153 --- /dev/null +++ b/virtualsmartcard/vpcd/ifd.c @@ -0,0 +1,170 @@ +#include +#include + +#include +#include +#include + +#include "vpcd.h" + +/* + * List of Defined Functions Available to IFD_Handler 1.0 + */ +RESPONSECODE +IO_Create_Channel(DWORD channelid) +{ + Log1(PCSC_LOG_DEBUG, ""); + if (vicc_init() < 0) return IFD_COMMUNICATION_ERROR; + + return IFD_SUCCESS; +} + +RESPONSECODE +IO_Close_Channel() +{ + Log1(PCSC_LOG_DEBUG, ""); + RESPONSECODE r = IFD_Eject_ICC(); + if (vicc_exit() < 0) return IFD_COMMUNICATION_ERROR; + + return r; +} + +RESPONSECODE +IFD_Get_Capabilities(DWORD tag, PUCHAR value) +{ + char *atr; + int size; + switch (tag) { + case TAG_IFD_ATR: + + size = vicc_getatr(&atr); + if (size < 0) { + Log1(PCSC_LOG_ERROR, "could not get ATR"); + return IFD_COMMUNICATION_ERROR; + } + Log2(PCSC_LOG_DEBUG, "Got ATR (%d bytes)", size); + + memcpy(value, atr, size); + free(atr); + return IFD_SUCCESS; + + case TAG_IFD_SLOTS_NUMBER: + (*value) = 0; + return IFD_SUCCESS; + + //case TAG_IFD_POLLING_THREAD_KILLABLE: + //return IFD_SUCCESS; + + default: + Log2(PCSC_LOG_DEBUG, "unknown tag %d", (int)tag); + } + + return IFD_ERROR_TAG; +} + +RESPONSECODE +IFD_Set_Capabilities(DWORD tag, PUCHAR value) +{ + return IFD_NOT_SUPPORTED; +} + +RESPONSECODE +IFD_Set_Protocol_Parameters(DWORD protocoltype, UCHAR selectionflags, UCHAR + pts1, UCHAR pts2, UCHAR pts3) +{ + Log1(PCSC_LOG_DEBUG, ""); + return IFD_SUCCESS; +} + +RESPONSECODE +IFD_Power_ICC(DWORD a) +{ + switch (a) { + case IFD_POWER_DOWN: + if (vicc_poweroff() < 0) { + Log1(PCSC_LOG_ERROR, "could not powerdown"); + return IFD_COMMUNICATION_ERROR; + } + break; + case IFD_POWER_UP: + if (vicc_poweron() < 0) { + Log1(PCSC_LOG_ERROR, "could not powerup"); + return IFD_COMMUNICATION_ERROR; + } + break; + case IFD_RESET: + if (vicc_reset() < 0) { + Log1(PCSC_LOG_ERROR, "could not reset"); + return IFD_COMMUNICATION_ERROR; + } + break; + default: + Log2(PCSC_LOG_ERROR, "%d not supported", a); + return IFD_NOT_SUPPORTED; + } + + return IFD_SUCCESS; +} + +RESPONSECODE +IFD_Swallow_ICC() +{ + Log1(PCSC_LOG_DEBUG, ""); + return IFD_NOT_SUPPORTED; +} + +RESPONSECODE +IFD_Eject_ICC() +{ + if (vicc_eject() < 0) { + return IFD_COMMUNICATION_ERROR; + } + return IFD_SUCCESS; +} + +RESPONSECODE +IFD_Confiscate_ICC() +{ + Log1(PCSC_LOG_DEBUG, ""); + return IFD_NOT_SUPPORTED; +} + +RESPONSECODE +IFD_Transmit_to_ICC(SCARD_IO_HEADER SendPci, PUCHAR TxBuffer, DWORD TxLength, + PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci) +{ + Log1(PCSC_LOG_DEBUG, ""); + (*RxLength) = 0; + char *rapdu; + + int size = vicc_transmit(TxLength, (char *) TxBuffer, &rapdu); + if (size < 0) { + Log1(PCSC_LOG_ERROR, "could not send apdu or receive rapdu"); + return IFD_COMMUNICATION_ERROR; + } + + (*RxLength) = size; + RxBuffer = memcpy(RxBuffer, rapdu, size); + free(rapdu); + + return IFD_SUCCESS; +} + +RESPONSECODE +IFD_Is_ICC_Present() +{ + switch (vicc_present()) { + case 0: return IFD_ICC_NOT_PRESENT; + case 1: return IFD_ICC_PRESENT; + default: + Log1(PCSC_LOG_DEBUG, "Could not get ICC state"); + return IFD_COMMUNICATION_ERROR; + } + return IFD_COMMUNICATION_ERROR; +} + +RESPONSECODE +IFD_Is_ICC_Absent() +{ + return IFD_Is_ICC_Present(); +} diff --git a/virtualsmartcard/vpcd/vpcd.c b/virtualsmartcard/vpcd/vpcd.c index 9ec41b6..2a9d605 100644 --- a/virtualsmartcard/vpcd/vpcd.c +++ b/virtualsmartcard/vpcd/vpcd.c @@ -16,156 +16,183 @@ * You should have received a copy of the GNU General Public License along with * virtualsmartcard. If not, see . */ -#include -#include +#include +#include #include -#include -#include +#include +#include +#include +#include + + +#include #include "vpcd.h" +static int server_sock = -1; +static int client_sock = -1; + /* - * List of Defined Functions Available to IFD_Handler 1.0 + * Send all size bytes from buffer to sock */ -RESPONSECODE -IO_Create_Channel(DWORD channelid) -{ - if (vicc_init() < 0) return IFD_COMMUNICATION_ERROR; +static int sendall(int sock, size_t size, const char* buffer); +/* + * Receive size bytes from sock + */ +static char* recvall(int sock, size_t size); - return IFD_SUCCESS; + +int sendall(int sock, size_t size, const char* buffer) { + size_t sent = 0; + int i; + while (sent < size) { + i = send(sock, buffer, size-sent, 0); + if (i < 0) return i; + sent += i; + } + return 0; } -RESPONSECODE -IO_Close_Channel() -{ - RESPONSECODE r = IFD_Eject_ICC(); - if (vicc_exit() < 0) return IFD_COMMUNICATION_ERROR; +char* recvall(int sock, size_t size) { + char* buffer = (char*) malloc(size); + if (buffer == NULL) return NULL; - return r; + if (recv(sock, buffer, size, MSG_WAITALL) < size) { + free(buffer); + return NULL; + } + return buffer; } -RESPONSECODE -IFD_Get_Capabilities(DWORD tag, PUCHAR value) -{ - char * atr; - int size; - switch (tag) { - case TAG_IFD_ATR: - - size = vicc_getatr(&atr); - if (size < 0) { - Log1(PCSC_LOG_ERROR, "could not get ATR"); - return IFD_COMMUNICATION_ERROR; - } - - value = memcpy(value, atr, size); - free(atr); - return IFD_SUCCESS; - - case TAG_IFD_SLOTS_NUMBER: - (*value) = 0; - return IFD_SUCCESS; - - //case TAG_IFD_POLLING_THREAD_KILLABLE: - //return IFD_SUCCESS; - - default: - Log2(PCSC_LOG_DEBUG, "unknown tag %d", (int)tag); +int sendToVICC(uint16_t size, const char* buffer) { + /* send size of message */ + uint16_t i = htons(size); + i = sendall(client_sock, sizeof i, (char *) &i); + if (i<0) { + vicc_eject(); + return i; + } + /* send message */ + i = sendall(client_sock, size, buffer); + if (i<0) { + vicc_eject(); + return i; } - return IFD_ERROR_TAG; + return 0; } -RESPONSECODE -IFD_Set_Capabilities(DWORD tag, PUCHAR value) -{ - return IFD_NOT_SUPPORTED; +/* + * Receive a message from icc + */ +int recvFromVICC(char** buffer) { + /* receive size of message on LENLEN bytes */ + uint16_t *p = (uint16_t *) recvall(client_sock, sizeof *p); + if (p == NULL) { + vicc_eject(); + return -1; + } + uint16_t size = ntohs(*p); + free(p); + + /* receive message */ + *buffer = recvall(client_sock, size); + if (*buffer == NULL) { + vicc_eject(); + return -1; + } + + return size; } -RESPONSECODE -IFD_Set_Protocol_Parameters(DWORD protocoltype, UCHAR selectionflags, UCHAR - pts1, UCHAR pts2, UCHAR pts3) -{ - return IFD_SUCCESS; +int vicc_eject() { + if (client_sock > 0) { + client_sock = close(client_sock); + if (client_sock < 0) { + return -1; + } + } + return 0; } -RESPONSECODE -IFD_Power_ICC(DWORD a) -{ +int vicc_init() { + server_sock = socket(AF_INET, SOCK_STREAM, 0); + if (server_sock < 0) return -1; - if ((a == IFD_POWER_DOWN) || (a == IFD_RESET)) { - if (vicc_poweroff() < 0) { - Log1(PCSC_LOG_ERROR, "could not powerdown"); - return IFD_COMMUNICATION_ERROR; + struct sockaddr_in server_sockaddr; + memset(&server_sockaddr, 0, sizeof(server_sockaddr)); + server_sockaddr.sin_family = PF_INET; + server_sockaddr.sin_port = htons(VPCDPORT); + server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(server_sock, (struct sockaddr*)&server_sockaddr, + sizeof(server_sockaddr)) < 0) return -1; + + if (listen(server_sock, 0) < 0) return -1; + + return 0; +} + +int vicc_exit() { + if (server_sock > 0) { + server_sock = close(server_sock); + if (server_sock < 0) return -1; + } + + return 0; +} + +int vicc_transmit(int apdu_len, const char *apdu, char **rapdu) { + if (sendToVICC(apdu_len, apdu) < 0) return -1; + + return recvFromVICC(rapdu); +} + +int vicc_present() { + if (client_sock > 0) return 1; + else { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(server_sock, &rfds); + + /* Wait up to one microsecond. */ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1; + + if (select(server_sock+1, &rfds, NULL, NULL, &tv) < 0) return -1; + + if (FD_ISSET(server_sock, &rfds)) { + struct sockaddr_in client_sockaddr; + socklen_t client_socklen = sizeof(client_sockaddr); + client_sock = accept(server_sock, + (struct sockaddr*)&client_sockaddr, + &client_socklen); + if (client_sock == -1) return -1; + + return 1; } } - if ((a == IFD_POWER_UP) || (a == IFD_RESET)) { - if (vicc_poweron() < 0) { - Log1(PCSC_LOG_ERROR, "could not powerup"); - return IFD_COMMUNICATION_ERROR; - } - } - - return IFD_SUCCESS; + return 0; } -RESPONSECODE -IFD_Swallow_ICC() -{ - Log1(PCSC_LOG_DEBUG, ""); - return IFD_NOT_SUPPORTED; +int vicc_getatr(char** atr) { + char i = VPCD_CTRL_ATR; + return vicc_transmit(VPCD_CTRL_LEN, &i, atr); } -RESPONSECODE -IFD_Eject_ICC() -{ - if (vicc_eject() < 0) { - return IFD_COMMUNICATION_ERROR; - } - return IFD_SUCCESS; +int vicc_poweron() { + char i = VPCD_CTRL_ON; + return sendToVICC(VPCD_CTRL_LEN, &i); } -RESPONSECODE -IFD_Confiscate_ICC() -{ - Log1(PCSC_LOG_DEBUG, ""); - return IFD_NOT_SUPPORTED; +int vicc_poweroff() { + char i = VPCD_CTRL_OFF; + return sendToVICC(VPCD_CTRL_LEN, &i); } -RESPONSECODE -IFD_Transmit_to_ICC(SCARD_IO_HEADER SendPci, PUCHAR TxBuffer, DWORD TxLength, - PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci) -{ - (*RxLength) = 0; - char *rapdu; - - int size = vicc_transmit(TxLength, (char *) TxBuffer, &rapdu); - if (size < 0) { - Log1(PCSC_LOG_ERROR, "could not send apdu or receive rapdu"); - return IFD_COMMUNICATION_ERROR; - } - - (*RxLength) = size; - RxBuffer = memcpy(RxBuffer, rapdu, size); - free(rapdu); - - return IFD_SUCCESS; -} - -RESPONSECODE -IFD_Is_ICC_Present() -{ - switch (vicc_present()) { - case 0: return IFD_ICC_NOT_PRESENT; - case 1: return IFD_ICC_PRESENT; - default: return IFD_COMMUNICATION_ERROR; - } - return IFD_COMMUNICATION_ERROR; -} - -RESPONSECODE -IFD_Is_ICC_Absent() -{ - return IFD_Is_ICC_Present(); +int vicc_reset() { + char i = VPCD_CTRL_RESET; + return sendToVICC(VPCD_CTRL_LEN, &i); } diff --git a/virtualsmartcard/vpcd/vpcd.h b/virtualsmartcard/vpcd/vpcd.h index 9fc27af..c71ed33 100644 --- a/virtualsmartcard/vpcd/vpcd.h +++ b/virtualsmartcard/vpcd/vpcd.h @@ -16,184 +16,46 @@ * You should have received a copy of the GNU General Public License along with * virtualsmartcard. If not, see . */ -#include -#include -#include -#include -#include -#include +#ifndef _VPCD_H_ +#define _VPCD_H_ -#define PORT 35963 -#define LENLEN 3 -int server_sock = -1; -int client_sock = -1; +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define VPCDPORT 35963 + +#define VPCD_CTRL_LEN 1 + +#define VPCD_CTRL_OFF 0 +#define VPCD_CTRL_ON 1 +#define VPCD_CTRL_RESET 2 +#define VPCD_CTRL_ATR 4 /* - * Send all size bytes from buffer to sock - */ -int sendall(int sock, size_t size, const char* buffer) { - /* send a plain message */ - size_t sent = 0; - int i; - while (sent < size) { - i = send(sock, buffer, size-sent, 0); - if (i < 0) return i; - sent += i; - } - return 0; -} - -/* - * Receive size bytes from sock - */ -char* recvall(int sock, size_t size) { - char* buffer = (char*) malloc(size); - if (buffer == NULL) return NULL; - - if (recv(sock, buffer, size, MSG_WAITALL) < size) { - free(buffer); - return NULL; - } - return buffer; -} - -int vicc_eject() { - if (client_sock > 0) { - client_sock = close(client_sock); - if (client_sock < 0) { - return -1; - } - } - return 0; -} - -/* - * First send length of message to the socket on LENLEN bytes, then send the + * First send length (unsigned integer in network byte order), then send the * message itself to the socket. */ -int sendToVICC(size_t size, const char* buffer) { - /* send size of message on LENLEN bytes */ - char sizebuf[LENLEN]; - size_t i; - for (i = 0; i < LENLEN; i++) - sizebuf[i] = ((size>>8*(LENLEN-i-1)) & 0xff); - - i = sendall(client_sock, LENLEN, sizebuf); - if (i<0) { - vicc_eject(); - return i; - } - i = sendall(client_sock, size, buffer); - if (i<0) { - vicc_eject(); - return i; - } - - return 0; -} - +int sendToVICC(uint16_t size, const char* buffer); /* * Receive a message from icc */ -int recvFromVICC(char** buffer) { - /* receive size of message on LENLEN bytes */ - unsigned char* sizebuffer = (unsigned char*) recvall(client_sock, LENLEN); - if (sizebuffer == NULL) { - vicc_eject(); - return -1; - } +int recvFromVICC(char** buffer); - /* calculate size */ - int size = 0; - int i; - for (i = 0; i < LENLEN; i++) { - size <<= 8; - size += sizebuffer[i]; - } - free(sizebuffer); +int vicc_eject(); +int vicc_init(); +int vicc_exit(); +int vicc_transmit(int apdu_len, const char *apdu, char **rapdu); +int vicc_getatr(char** atr); +int vicc_present(); +int vicc_poweron(); +int vicc_poweroff(); +int vicc_reset(); - /* receive message */ - *buffer = recvall(client_sock, size); - if (*buffer == NULL) { - vicc_eject(); - return -1; - } - - return size; -} - -int vicc_init() { - server_sock = socket(AF_INET, SOCK_STREAM, 0); - if (server_sock < 0) return -1; - - struct sockaddr_in server_sockaddr; - memset(&server_sockaddr, 0, sizeof(server_sockaddr)); - server_sockaddr.sin_family = PF_INET; - server_sockaddr.sin_port = htons(PORT); - server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (bind(server_sock, (struct sockaddr*)&server_sockaddr, - sizeof(server_sockaddr)) < 0) return -1; - - if (listen(server_sock, 0) < 0) return -1; - - return 0; -} - -int vicc_exit() { - if (server_sock > 0) { - server_sock = close(server_sock); - if (server_sock < 0) return -1; - } - - return 0; -} - -int vicc_transmit(int apdu_len, const char *apdu, char **rapdu) { - if (sendToVICC(apdu_len, apdu) < 0) return -1; - - return recvFromVICC(rapdu); -} - -int vicc_getatr(char** atr) { - return vicc_transmit(0, "", atr); -} - -int vicc_present() { - if (client_sock > 0) return 1; - else { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(server_sock, &rfds); - - /* Wait up to one microsecond. */ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1; - - if (select(server_sock+1, &rfds, NULL, NULL, &tv) < 0) return -1; - - if (FD_ISSET(server_sock, &rfds)) { - struct sockaddr_in client_sockaddr; - socklen_t client_socklen = sizeof(client_sockaddr); - client_sock = accept(server_sock, - (struct sockaddr*)&client_sockaddr, - &client_socklen); - if (client_sock == -1) return -1; - - return 1; - } - } - - return 0; -} - -int vicc_poweron() { - char on = 1; - return sendToVICC(1, &on); -} - -int vicc_poweroff() { - char off = 0; - return sendToVICC(1, &off); +#ifdef __cplusplus } +#endif +#endif diff --git a/virtualsmartcard/vpicc/VirtualSmartcard.py b/virtualsmartcard/vpicc/VirtualSmartcard.py index ecb8959..0b27a77 100644 --- a/virtualsmartcard/vpicc/VirtualSmartcard.py +++ b/virtualsmartcard/vpicc/VirtualSmartcard.py @@ -20,10 +20,11 @@ from ConstantDefinitions import * from TLVutils import * from SWutils import SwError, SW from SmartcardFilesystem import prettyprint_anything, MF, DF, CryptoflexMF, TransparentStructureEF -from utils import C_APDU, R_APDU, hexdump, stringtoint, inttostring +from utils import C_APDU, R_APDU, hexdump, inttostring from SmartcardSAM import CardContainer, SAM, PassportSAM, CryptoflexSAM from pickle import dumps, loads import socket, struct, sys, signal, atexit, traceback +import struct class SmartcardOS(object): # {{{ @@ -149,6 +150,9 @@ class SmartcardOS(object): # {{{ def powerDown(self): pass + def reset(self): + pass + @staticmethod def makeATR(**args): # {{{ """Calculate Answer to Reset (ATR) and returns the bitstring. @@ -470,6 +474,17 @@ class CryptoflexOS(SmartcardOS): # {{{ # }}} +# sizeof(int) taken from asizof-package {{{ +_Csizeof_short = len(struct.pack('h', 0)) +# }}} + +VPCD_CTRL_LEN = 1 + +VPCD_CTRL_OFF = 0 +VPCD_CTRL_ON = 1 +VPCD_CTRL_RESET = 2 +VPCD_CTRL_ATR = 4 + class VirtualICC(object): # {{{ def __init__(self, filename,os=None, lenlen=3, host="localhost", port=35963): @@ -503,34 +518,39 @@ class VirtualICC(object): # {{{ return sock def __sendToVPICC(self, msg): - size = inttostring(len(msg), self.lenlen) - self.sock.sendall("%s%s" % (size, msg)) + #size = inttostring(len(msg), self.lenlen) + self.sock.send(struct.pack('!H', len(msg)) + msg) def __recvFromVPICC(self): # receive message size - size = self.sock.recv(self.lenlen) - size = stringtoint(size) + size = struct.unpack('!H', self.sock.recv(_Csizeof_short))[0] # receive and return message - if size == 0: - return "" + if size: + msg = self.sock.recv(size) else: - msg = self.sock.recv(size) - return msg + msg = None + return size, msg def run(self): while True : - msg = self.__recvFromVPICC() - if msg == "": - self.__sendToVPICC(self.os.atr) - elif msg == chr(0): - # powerdown - print "Power Down" - self.os.powerDown() - elif msg == chr(1): - # powerup - print "Power Up" - self.os.powerUp() + (size, msg) = self.__recvFromVPICC() + if not size: + print "error in communication protocol" + elif size == VPCD_CTRL_LEN: + if msg == chr(VPCD_CTRL_OFF): + print "Power Down" + self.os.powerDown() + elif msg == chr(VPCD_CTRL_ON): + print "Power Up" + self.os.powerUp() + elif msg == chr(VPCD_CTRL_RESET): + print "Reset" + self.os.reset() + elif msg == chr(VPCD_CTRL_ATR): + self.__sendToVPICC(self.os.atr) + else: + print "unknown control command" else: print "APDU (%d Bytes):\n%s" % (len(msg),hexdump(msg, short=True)) answer = self.os.execute(msg)