144 lines
3.4 KiB
C
144 lines
3.4 KiB
C
/*
|
|
* Copyright (C) 2012 Frank Morgner
|
|
*
|
|
* This file is part of pcsc-relay.
|
|
*
|
|
* pcsc-relay is free software: you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, either version 3 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* pcsc-relay is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* pcsc-relay. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "pcsc-relay.h"
|
|
#include "vpcd.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
unsigned int viccport = VPCDPORT;
|
|
char *vicchostname = NULL;
|
|
|
|
|
|
|
|
static int _vicc_connect(driver_data_t **driver_data)
|
|
{
|
|
struct vicc_ctx *ctx;
|
|
const long secs = 300;
|
|
|
|
if (!driver_data)
|
|
return 0;
|
|
|
|
|
|
ctx = vicc_init(vicchostname, viccport);
|
|
if (!ctx) {
|
|
RELAY_ERROR("Could not initialize connection to VPCD\n");
|
|
return 0;
|
|
}
|
|
*driver_data = ctx;
|
|
|
|
INFO("Waiting for VPCD on port %hu for %ld seconds\n",
|
|
(unsigned short) viccport, secs);
|
|
if (vicc_connect(ctx, secs, 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vicc_disconnect(driver_data_t *driver_data)
|
|
{
|
|
struct vicc_ctx *ctx = driver_data;
|
|
|
|
vicc_eject(ctx);
|
|
if (vicc_exit(ctx) != 0) {
|
|
RELAY_ERROR("Could not close connection to virtual ICC\n");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int vicc_receive_capdu(driver_data_t *driver_data,
|
|
unsigned char **capdu, size_t *len)
|
|
{
|
|
struct vicc_ctx *ctx = driver_data;
|
|
|
|
int r = 0;
|
|
ssize_t size;
|
|
const unsigned char atr[] = {0x3B, 0x80, 0x80, 0x01, 0x01};
|
|
|
|
if (!len)
|
|
goto err;
|
|
|
|
do {
|
|
size = vicc_transmit(ctx, 0, NULL, capdu);
|
|
|
|
if (size < 0) {
|
|
RELAY_ERROR("could not receive request\n");
|
|
goto err;
|
|
}
|
|
|
|
if (size == VPCD_CTRL_LEN) {
|
|
switch (*capdu[0]) {
|
|
case VPCD_CTRL_OFF:
|
|
case VPCD_CTRL_ON:
|
|
case VPCD_CTRL_RESET:
|
|
// ignore reset, power on, power off
|
|
break;
|
|
case VPCD_CTRL_ATR:
|
|
if (vicc_transmit(ctx, sizeof atr, atr, NULL) < 0) {
|
|
RELAY_ERROR("could not send ATR\n");
|
|
goto err;
|
|
}
|
|
break;
|
|
default:
|
|
RELAY_ERROR("Unknown request: 0x%0X\n", *capdu[0]);
|
|
goto err;
|
|
}
|
|
} else {
|
|
// finaly we got the capdu
|
|
*len = size;
|
|
r = 1;
|
|
}
|
|
} while (!r);
|
|
|
|
err:
|
|
return r;
|
|
}
|
|
|
|
static int vicc_send_rapdu(driver_data_t *driver_data,
|
|
const unsigned char *rapdu, size_t len)
|
|
{
|
|
struct vicc_ctx *ctx = driver_data;
|
|
|
|
if (!ctx || !rapdu)
|
|
return 0;
|
|
|
|
if (vicc_transmit(ctx, len, rapdu, NULL) < 0) {
|
|
RELAY_ERROR("could not send R-APDU\n");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
struct rf_driver driver_vicc = {
|
|
.connect = _vicc_connect,
|
|
.disconnect = vicc_disconnect,
|
|
.receive_capdu = vicc_receive_capdu,
|
|
.send_rapdu = vicc_send_rapdu,
|
|
};
|