/* * 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 . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcsc-relay.h" #include "vpcd.h" #include #include #include 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(NULL, vpcdport); 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) vpcdport, 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 == 1) { switch (*capdu[0]) { case 0x00: case 0x01: case 0x02: // ignore reset, power on, power off break; case 0x03: 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, };