nonsenselock/src/smartcard/smartcard.c

172 lines
4.8 KiB
C

#include <stdlib.h>
#include <string.h>
#include "smartcard.h"
#include "error.h"
#include "../util.h"
static void set_error(struct nsl_smartcard *smartcard, uint8_t sw1, uint8_t sw2)
{
smartcard->apdu.response.status[0] = sw1;
smartcard->apdu.response.status[1] = sw2;
smartcard->apdu.response.len = 0;
}
int nsl_smartcard_init(struct nsl_smartcard *smartcard)
{
smartcard->rootdir = smartcard->curdir = NULL;
memset(smartcard->handles, 0, sizeof(smartcard->handles));
smartcard->last_handle = 0;
memset(smartcard->standard_handlers, 0, sizeof(smartcard->standard_handlers));
memset(smartcard->proprietary_handlers, 0, sizeof(smartcard->proprietary_handlers));
nsl_smartcard_emu_init(&smartcard->emu, 0xFFFF, 0xFFFF);
return nsl_smartcard_reset(smartcard);
}
int nsl_smartcard_reset(struct nsl_smartcard *smartcard)
{
smartcard->curdir = smartcard->rootdir;
nsl_smartcard_emu_reset(&smartcard->emu, 1);
return 0;
}
int nsl_smartcard_authorize(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
return nsl_smartcard_dir_authorize(smartcard->curdir, pin, len, level);
}
int nsl_smartcard_change_pin(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
return nsl_smartcard_dir_authorize(smartcard->curdir, pin, len, level);
}
int nsl_smartcard_mkdir(struct nsl_smartcard *smartcard, nsl_smartcart_file_id_t id)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
struct nsl_smartcard_file *parent = smartcard->curdir;
if (nsl_smartcard_dir_find(parent, id, NULL)) {
return NSL_SMARTCARD_ERROR_ALREADY_EXISTS;
}
struct nsl_smartcard_file *dir = malloc(sizeof(*dir));
if (!dir) {
return NSL_SMARTCARD_ERROR_NO_MEMORY;
}
int err = nsl_smartcard_dir_init(dir, id);
if (err) {
goto err;
}
err = nsl_smartcard_dir_add(parent, dir);
if (err) {
goto err;
}
return 0;
err:
free(dir);
return err;
}
int nsl_smartcard_chdir(struct nsl_smartcard *smartcard, nsl_smartcart_file_id_t id)
{
struct nsl_smartcard_file *dir;
if (id == NSL_SMARTCARD_CUR_DIR_ID) {
dir = smartcard->curdir;
} else if (id == NSL_SMARTCARD_ROOT_DIR_ID) {
dir = smartcard->rootdir;
} else {
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
int err = nsl_smartcard_dir_find(smartcard->curdir, id, &dir);
if (err) {
return err;
}
}
smartcard->curdir = dir;
return 0;
}
int nsl_smartcard_exec(struct nsl_smartcard *smartcard, nsl_smartcart_file_id_t id, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
struct nsl_smartcard_handle *handle;
int err = nsl_smartcard_open(smartcard, id, &handle);
if (err) {
return err;
}
/* TODO: setup VM and run. */
return 0;
}
int nsl_smartcard_open(struct nsl_smartcard *smartcard, nsl_smartcart_file_id_t id, struct nsl_smartcard_handle **handle)
{
size_t nhandles = sizeof(smartcard->handles) / sizeof(*smartcard->handles);
size_t cur = smartcard->last_handle + 1;
for (size_t i = 0; i < nhandles; i++, cur++) {
cur %= nhandles;
if (!nsl_smartcard_handle_is_valid(&smartcard->handles[cur])) {
break;
}
}
struct nsl_smartcard_handle *h = &smartcard->handles[cur];
if (nsl_smartcard_handle_is_valid(h)) {
return NSL_SMARTCARD_ERROR_NO_MEMORY;
}
struct nsl_smartcard_file *file;
int err = nsl_smartcard_dir_find(smartcard->curdir, id, &file);
if (err) {
return err;
}
err = nsl_smartcard_file_open(file, h);
if (err) {
return err;
}
smartcard->last_handle = cur;
*handle = h;
return 0;
}
int nsl_smartcard_process(struct nsl_smartcard *smartcard, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen)
{
int err = nsl_smartcard_apdu_read_command(&smartcard->apdu, inbuf, inlen);
if (!err) {
nsl_smartcard_handler_t handler;
if (smartcard->apdu.command.class & 0x80) {
handler = smartcard->proprietary_handlers[smartcard->apdu.command.instruction];
} else {
handler = smartcard->standard_handlers[smartcard->apdu.command.instruction];
}
if (handler) {
err = handler(smartcard, &smartcard->apdu);
} else {
set_error(smartcard, NSL_SMARTCARD_APDU_STATUS_ERROR_UNK_COMMAND, 0);
}
}
nsl_smartcard_apdu_write_response(&smartcard->apdu, outbuf, &outlen);
return err;
}