172 lines
4.8 KiB
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;
|
|
}
|