- added functions for a smartcard reset

- changed communication protocol via socket, length is coded in network byteorder
- splitted vpcd.[h|c] into more files, added include-guards


git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@18 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2010-01-13 21:33:13 +00:00
parent b4862e9be6
commit b0f3ce24e5
5 changed files with 402 additions and 317 deletions

View File

@@ -34,10 +34,14 @@ TARGETS = libvpcd.so configuration virtualsmartcard
# top-level rule # top-level rule
all: $(TARGETS) all: $(TARGETS)
libvpcd.so: vpcd/vpcd.c vpcd/vpcd.h ifd.o: vpcd/ifd.c
$(CC) $(LIBPCSCLITE_CFLAGS) $(SO_CFLAGS) $(CFLAGS) -c $< -o $(@:%.so=%.o) $(CC) $(SO_CFLAGS) $(CFLAGS) $(LIBPCSCLITE_CFLAGS) -c $< -o $@
$(LD) $(LDFLAGS) $(@:%.so=%.o) -o $@ -soname=$@.1 -lc
rm -f $(@:%.so=%.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 .PHONY: virtualsmartcard
virtualsmartcard: virtualsmartcard:
@@ -103,6 +107,8 @@ uninstall:
.PHONY: clean .PHONY: clean
clean: clean:
rm -f libvpcd.so rm -f libvpcd.so \
rm -f vpcd.conf ifd.o \
rm -f virtualsmartcard vpcd.o \
vpcd.conf \
virtualsmartcard

170
virtualsmartcard/vpcd/ifd.c Normal file
View File

@@ -0,0 +1,170 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ifdhandler.h>
#include <debuglog.h>
#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();
}

View File

@@ -16,156 +16,183 @@
* You should have received a copy of the GNU General Public License along with * You should have received a copy of the GNU General Public License along with
* virtualsmartcard. If not, see <http://www.gnu.org/licenses/>. * virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <arpa/inet.h>
#include <stdlib.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <ifdhandler.h> #include <sys/socket.h>
#include <debuglog.h> #include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "vpcd.h" #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 static int sendall(int sock, size_t size, const char* buffer);
IO_Create_Channel(DWORD channelid) /*
{ * Receive size bytes from sock
if (vicc_init() < 0) return IFD_COMMUNICATION_ERROR; */
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 char* recvall(int sock, size_t size) {
IO_Close_Channel() char* buffer = (char*) malloc(size);
{ if (buffer == NULL) return NULL;
RESPONSECODE r = IFD_Eject_ICC();
if (vicc_exit() < 0) return IFD_COMMUNICATION_ERROR;
return r; if (recv(sock, buffer, size, MSG_WAITALL) < size) {
free(buffer);
return NULL;
}
return buffer;
} }
RESPONSECODE int sendToVICC(uint16_t size, const char* buffer) {
IFD_Get_Capabilities(DWORD tag, PUCHAR value) /* send size of message */
{ uint16_t i = htons(size);
char * atr; i = sendall(client_sock, sizeof i, (char *) &i);
int size; if (i<0) {
switch (tag) { vicc_eject();
case TAG_IFD_ATR: return i;
}
size = vicc_getatr(&atr); /* send message */
if (size < 0) { i = sendall(client_sock, size, buffer);
Log1(PCSC_LOG_ERROR, "could not get ATR"); if (i<0) {
return IFD_COMMUNICATION_ERROR; vicc_eject();
return i;
} }
value = memcpy(value, atr, size); return 0;
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; /*
* 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;
} }
RESPONSECODE return size;
IFD_Set_Capabilities(DWORD tag, PUCHAR value)
{
return IFD_NOT_SUPPORTED;
} }
RESPONSECODE int vicc_eject() {
IFD_Set_Protocol_Parameters(DWORD protocoltype, UCHAR selectionflags, UCHAR if (client_sock > 0) {
pts1, UCHAR pts2, UCHAR pts3) client_sock = close(client_sock);
{ if (client_sock < 0) {
return IFD_SUCCESS; return -1;
}
}
return 0;
} }
RESPONSECODE int vicc_init() {
IFD_Power_ICC(DWORD a) server_sock = socket(AF_INET, SOCK_STREAM, 0);
{ if (server_sock < 0) return -1;
if ((a == IFD_POWER_DOWN) || (a == IFD_RESET)) { struct sockaddr_in server_sockaddr;
if (vicc_poweroff() < 0) { memset(&server_sockaddr, 0, sizeof(server_sockaddr));
Log1(PCSC_LOG_ERROR, "could not powerdown"); server_sockaddr.sin_family = PF_INET;
return IFD_COMMUNICATION_ERROR; 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)) { return 0;
if (vicc_poweron() < 0) {
Log1(PCSC_LOG_ERROR, "could not powerup");
return IFD_COMMUNICATION_ERROR;
}
} }
return IFD_SUCCESS; int vicc_getatr(char** atr) {
char i = VPCD_CTRL_ATR;
return vicc_transmit(VPCD_CTRL_LEN, &i, atr);
} }
RESPONSECODE int vicc_poweron() {
IFD_Swallow_ICC() char i = VPCD_CTRL_ON;
{ return sendToVICC(VPCD_CTRL_LEN, &i);
Log1(PCSC_LOG_DEBUG, "");
return IFD_NOT_SUPPORTED;
} }
RESPONSECODE int vicc_poweroff() {
IFD_Eject_ICC() char i = VPCD_CTRL_OFF;
{ return sendToVICC(VPCD_CTRL_LEN, &i);
if (vicc_eject() < 0) {
return IFD_COMMUNICATION_ERROR;
}
return IFD_SUCCESS;
} }
RESPONSECODE int vicc_reset() {
IFD_Confiscate_ICC() char i = VPCD_CTRL_RESET;
{ return sendToVICC(VPCD_CTRL_LEN, &i);
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)
{
(*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();
} }

View File

@@ -16,184 +16,46 @@
* You should have received a copy of the GNU General Public License along with * You should have received a copy of the GNU General Public License along with
* virtualsmartcard. If not, see <http://www.gnu.org/licenses/>. * virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <sys/types.h> #ifndef _VPCD_H_
#include <sys/socket.h> #define _VPCD_H_
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define PORT 35963 #include <stdint.h>
#define LENLEN 3
int server_sock = -1; #ifdef __cplusplus
int client_sock = -1; 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 * First send length (unsigned integer in network byte order), then send the
*/
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
* message itself to the socket. * message itself to the socket.
*/ */
int sendToVICC(size_t size, const char* buffer) { int sendToVICC(uint16_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;
}
/* /*
* Receive a message from icc * Receive a message from icc
*/ */
int recvFromVICC(char** buffer) { int recvFromVICC(char** buffer);
/* receive size of message on LENLEN bytes */
unsigned char* sizebuffer = (unsigned char*) recvall(client_sock, LENLEN); int vicc_eject();
if (sizebuffer == NULL) { int vicc_init();
vicc_eject(); int vicc_exit();
return -1; int vicc_transmit(int apdu_len, const char *apdu, char **rapdu);
} int vicc_getatr(char** atr);
int vicc_present();
/* calculate size */ int vicc_poweron();
int size = 0; int vicc_poweroff();
int i; int vicc_reset();
for (i = 0; i < LENLEN; i++) {
size <<= 8; #ifdef __cplusplus
size += sizebuffer[i];
}
free(sizebuffer);
/* 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);
} }
#endif
#endif

View File

@@ -20,10 +20,11 @@ from ConstantDefinitions import *
from TLVutils import * from TLVutils import *
from SWutils import SwError, SW from SWutils import SwError, SW
from SmartcardFilesystem import prettyprint_anything, MF, DF, CryptoflexMF, TransparentStructureEF 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 SmartcardSAM import CardContainer, SAM, PassportSAM, CryptoflexSAM
from pickle import dumps, loads from pickle import dumps, loads
import socket, struct, sys, signal, atexit, traceback import socket, struct, sys, signal, atexit, traceback
import struct
class SmartcardOS(object): # {{{ class SmartcardOS(object): # {{{
@@ -149,6 +150,9 @@ class SmartcardOS(object): # {{{
def powerDown(self): def powerDown(self):
pass pass
def reset(self):
pass
@staticmethod @staticmethod
def makeATR(**args): # {{{ def makeATR(**args): # {{{
"""Calculate Answer to Reset (ATR) and returns the bitstring. """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): # {{{ class VirtualICC(object): # {{{
def __init__(self, filename,os=None, lenlen=3, host="localhost", port=35963): def __init__(self, filename,os=None, lenlen=3, host="localhost", port=35963):
@@ -503,34 +518,39 @@ class VirtualICC(object): # {{{
return sock return sock
def __sendToVPICC(self, msg): def __sendToVPICC(self, msg):
size = inttostring(len(msg), self.lenlen) #size = inttostring(len(msg), self.lenlen)
self.sock.sendall("%s%s" % (size, msg)) self.sock.send(struct.pack('!H', len(msg)) + msg)
def __recvFromVPICC(self): def __recvFromVPICC(self):
# receive message size # receive message size
size = self.sock.recv(self.lenlen) size = struct.unpack('!H', self.sock.recv(_Csizeof_short))[0]
size = stringtoint(size)
# receive and return message # receive and return message
if size == 0: if size:
return ""
else:
msg = self.sock.recv(size) msg = self.sock.recv(size)
return msg else:
msg = None
return size, msg
def run(self): def run(self):
while True : while True :
msg = self.__recvFromVPICC() (size, msg) = self.__recvFromVPICC()
if msg == "": if not size:
self.__sendToVPICC(self.os.atr) print "error in communication protocol"
elif msg == chr(0): elif size == VPCD_CTRL_LEN:
# powerdown if msg == chr(VPCD_CTRL_OFF):
print "Power Down" print "Power Down"
self.os.powerDown() self.os.powerDown()
elif msg == chr(1): elif msg == chr(VPCD_CTRL_ON):
# powerup
print "Power Up" print "Power Up"
self.os.powerUp() 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: else:
print "APDU (%d Bytes):\n%s" % (len(msg),hexdump(msg, short=True)) print "APDU (%d Bytes):\n%s" % (len(msg),hexdump(msg, short=True))
answer = self.os.execute(msg) answer = self.os.execute(msg)