parent
8f7b372d72
commit
d0bc7fc18f
13 changed files with 657 additions and 10 deletions
@ -1 +1 @@ |
||||
Subproject commit b93d1da3a93b83175308e390526b476b1557977a |
||||
Subproject commit 130e9ea9852820e375f1175b678b80d6a5467b05 |
@ -1,4 +1,6 @@ |
||||
SRCS += dongle.c
|
||||
SRCS += \
|
||||
util.c \
|
||||
dongle.c
|
||||
|
||||
include $(ROOT)/src/transport/build.mk |
||||
include $(ROOT)/src/smartcard/build.mk |
||||
|
@ -0,0 +1,13 @@ |
||||
SRCS += \
|
||||
smartcard/emu.c \
|
||||
smartcard/fs.o \
|
||||
smartcard/smartcard.o
|
||||
|
||||
OBJS += \
|
||||
ext/emu8051/libem8051.a
|
||||
|
||||
ext/emu8051/libem8051.a: |
||||
cd $(dir $@) && make CPPFLAGS=-DEM8051_MINIMAL=1 $(notdir $@)
|
||||
|
||||
CPPFLAGS += -I ext/emu8051
|
||||
|
@ -0,0 +1,91 @@ |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "emu.h" |
||||
|
||||
|
||||
int nsl_smartcard_emu_init(struct nsl_smartcard_emu *emu, size_t code_size, size_t ext_data_size) |
||||
{ |
||||
memset(&emu->cpu, 0, sizeof(emu->cpu)); |
||||
emu->cpu.mCodeMem = malloc(code_size); |
||||
if (!emu->cpu.mCodeMem) |
||||
goto err; |
||||
emu->cpu.mCodeMemSize = code_size; |
||||
emu->cpu.mExtData = malloc(ext_data_size); |
||||
if (!emu->cpu.mExtData) |
||||
goto err; |
||||
emu->cpu.mExtDataSize = ext_data_size; |
||||
emu->cpu.mLowerData = malloc(128); |
||||
if (!emu->cpu.mLowerData) |
||||
goto err; |
||||
emu->cpu.mUpperData = malloc(128); |
||||
if (!emu->cpu.mUpperData) |
||||
goto err; |
||||
emu->cpu.mSFR = malloc(128); |
||||
if (!emu->cpu.mSFR) |
||||
goto err; |
||||
|
||||
em8051_reset(&emu->cpu, 0); |
||||
return 0; |
||||
|
||||
err: |
||||
if (emu->cpu.mCodeMem) |
||||
free(emu->cpu.mCodeMem); |
||||
if (emu->cpu.mExtData) |
||||
free(emu->cpu.mExtData); |
||||
if (emu->cpu.mLowerData) |
||||
free(emu->cpu.mLowerData); |
||||
if (emu->cpu.mUpperData) |
||||
free(emu->cpu.mUpperData); |
||||
return 1; |
||||
} |
||||
|
||||
void nsl_smartcard_emu_reset(struct nsl_smartcard_emu *emu, int wipe) |
||||
{ |
||||
em8051_reset(&emu->cpu, wipe); |
||||
} |
||||
|
||||
uint8_t nsl_smartcard_emu_read(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr) |
||||
{ |
||||
switch (bank) { |
||||
case NSL_SMARTCARD_EMU_BANK_CODE: |
||||
return emu->cpu.mCodeMem[addr]; |
||||
case NSL_SMARTCARD_EMU_BANK_DATA: |
||||
if (addr < 128) { |
||||
return emu->cpu.mLowerData[addr]; |
||||
} else { |
||||
return emu->cpu.mUpperData[addr - 128]; |
||||
} |
||||
case NSL_SMARTCARD_EMU_BANK_EXT_DATA: |
||||
return emu->cpu.mExtData[addr]; |
||||
} |
||||
} |
||||
|
||||
void nsl_smartcard_emu_write(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t value) |
||||
{ |
||||
switch (bank) { |
||||
case NSL_SMARTCARD_EMU_BANK_CODE: |
||||
emu->cpu.mCodeMem[addr] = value; |
||||
case NSL_SMARTCARD_EMU_BANK_DATA: |
||||
if (addr < 128) { |
||||
emu->cpu.mLowerData[addr] = value; |
||||
} else { |
||||
emu->cpu.mUpperData[addr - 128] = value; |
||||
} |
||||
case NSL_SMARTCARD_EMU_BANK_EXT_DATA: |
||||
emu->cpu.mExtData[addr] = value; |
||||
} |
||||
} |
||||
|
||||
void nsl_smartcard_emu_read_range(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len) |
||||
{ |
||||
for (size_t i = 0; i < len; i++) { |
||||
buf[i] = nsl_smartcard_emu_read(emu, bank, addr + i); |
||||
} |
||||
} |
||||
|
||||
void nsl_smartcard_emu_write_range(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len) |
||||
{ |
||||
for (size_t i = 0; i < len; i++) { |
||||
nsl_smartcard_emu_write(emu, bank, addr + i, buf[i]); |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
#pragma once |
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
#include <emu8051.h> |
||||
|
||||
struct nsl_smartcard_emu |
||||
{ |
||||
struct em8051 cpu; |
||||
}; |
||||
|
||||
enum nsl_smartcard_emu_bank |
||||
{ |
||||
NSL_SMARTCARD_EMU_BANK_CODE, |
||||
NSL_SMARTCARD_EMU_BANK_DATA, |
||||
NSL_SMARTCARD_EMU_BANK_EXT_DATA, |
||||
}; |
||||
|
||||
int nsl_smartcard_emu_init(struct nsl_smartcard_emu *, size_t code_size, size_t ext_data_size); |
||||
void nsl_smartcard_emu_reset(struct nsl_smartcard_emu *, int wipe); |
||||
|
||||
uint8_t nsl_smartcard_emu_read(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr); |
||||
void nsl_smartcard_emu_write(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t value); |
||||
void nsl_smartcard_emu_read_range(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len); |
||||
void nsl_smartcard_emu_write_range(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len); |
@ -0,0 +1,12 @@ |
||||
enum nsl_smartcard_error |
||||
{ |
||||
NSL_SMARTCARD_ERROR_NONE = 0, |
||||
NSL_SMARTCARD_ERROR_WRONG_TYPE, |
||||
NSL_SMARTCARD_ERROR_WRONG_ID, |
||||
NSL_SMARTCARD_ERROR_WRONG_VALUE, |
||||
NSL_SMARTCARD_ERROR_NOT_FOUND, |
||||
NSL_SMARTCARD_ERROR_IN_USE, |
||||
NSL_SMARTCARD_ERROR_UNAUTHORIZED, |
||||
NSL_SMARTCARD_ERROR_ALREADY_EXISTS, |
||||
NSL_SMARTCARD_ERROR_NO_MEMORY, |
||||
}; |
@ -0,0 +1,219 @@ |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include "fs.h" |
||||
#include "error.h" |
||||
#include "../util.h" |
||||
|
||||
|
||||
#define NSL_SMARTCARD_USER_PIN_DEFAULT "12345678" |
||||
#define NSL_SMARTCARD_DEV_PIN_DEFAULT "123456781234567812345678" |
||||
#define NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF 16 |
||||
|
||||
static inline void init_common(struct nsl_smartcard_file *file, uint16_t id, enum nsl_smartcard_file_type type) |
||||
{ |
||||
file->parent = NULL; |
||||
file->next = NULL; |
||||
file->id = id; |
||||
file->type = type; |
||||
} |
||||
|
||||
static inline int is_authorized(struct nsl_smartcard_file *file, enum nsl_smartcard_auth_level level) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return 0; |
||||
} |
||||
return file->contents.dir.auth >= level; |
||||
} |
||||
|
||||
|
||||
int nsl_smartcard_file_init(struct nsl_smartcard_file *file, uint16_t id, enum nsl_smartcard_file_type type) |
||||
{ |
||||
init_common(file, id, type); |
||||
if (!nsl_smartcard_is_file(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
|
||||
file->contents.file.data = NULL; |
||||
file->contents.file.len = 0; |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_file_read(struct nsl_smartcard_file *file, const uint8_t **data, size_t *len, enum nsl_smartcard_file_type type) |
||||
{ |
||||
if (!nsl_smartcard_is_file(file) || file->type != type) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
switch (file->type) { |
||||
case NSL_SMARTCARD_FILE_EXECUTABLE: |
||||
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) { |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
break; |
||||
case NSL_SMARTCARD_FILE_DATA: |
||||
case NSL_SMARTCARD_FILE_KEY: |
||||
if (!is_authorized(file, NSL_SMARTCARD_AUTH_INTERNAL)) { |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
break; |
||||
default: |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
|
||||
*data = file->contents.file.data; |
||||
*len = file->contents.file.len; |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int nsl_smartcard_dir_init(struct nsl_smartcard_file *file, uint16_t id) |
||||
{ |
||||
init_common(file, id, NSL_SMARTCARD_FILE_DIR); |
||||
|
||||
file->contents.dir.children = NULL; |
||||
file->contents.dir.auth = NSL_SMARTCARD_AUTH_NONE; |
||||
file->contents.dir.auth_attempts = 0; |
||||
memcpy(file->contents.dir.user_pin, NSL_SMARTCARD_USER_PIN_DEFAULT, sizeof(file->contents.dir.user_pin)); |
||||
memcpy(file->contents.dir.dev_pin, NSL_SMARTCARD_DEV_PIN_DEFAULT, sizeof(file->contents.dir.user_pin)); |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_dir_authorize(struct nsl_smartcard_file *file, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
|
||||
const uint8_t *match_pin; |
||||
size_t match_len; |
||||
switch (level) { |
||||
case NSL_SMARTCARD_AUTH_NONE: |
||||
match_pin = NULL; |
||||
match_len = 0; |
||||
break; |
||||
case NSL_SMARTCARD_AUTH_USER: |
||||
match_pin = file->contents.dir.user_pin; |
||||
match_len = sizeof(file->contents.dir.user_pin); |
||||
break; |
||||
case NSL_SMARTCARD_AUTH_DEV: |
||||
match_pin = file->contents.dir.dev_pin; |
||||
match_len = sizeof(file->contents.dir.dev_pin); |
||||
break; |
||||
default: |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
|
||||
if (len != match_len) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
if (nsl_util_memcmp(match_pin, pin, match_len)) { |
||||
if (match_len > NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF && !nsl_util_memcmp(match_pin, pin, NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF)) { |
||||
file->contents.dir.auth_attempts++; |
||||
} |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
|
||||
if (match_len > NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF) { |
||||
file->contents.dir.auth_attempts = 0; |
||||
} |
||||
file->contents.dir.auth = level; |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_dir_change_pin(struct nsl_smartcard_file *file, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
if (!is_authorized(file, level)) { |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
|
||||
uint8_t *target_pin; |
||||
size_t target_len; |
||||
switch (level) { |
||||
case NSL_SMARTCARD_AUTH_USER: |
||||
target_pin = file->contents.dir.user_pin; |
||||
target_len = sizeof(file->contents.dir.user_pin); |
||||
break; |
||||
case NSL_SMARTCARD_AUTH_DEV: |
||||
target_pin = file->contents.dir.dev_pin; |
||||
target_len = sizeof(file->contents.dir.dev_pin); |
||||
break; |
||||
default: |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
if (target_len != len) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
|
||||
memcpy(target_pin, pin, target_len); |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_dir_add(struct nsl_smartcard_file *file, struct nsl_smartcard_file *child) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
if (file->id == NSL_SMARTCARD_ROOT_DIR_ID) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_ID; |
||||
} |
||||
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) { |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
if (child->parent || child->next) { |
||||
return NSL_SMARTCARD_ERROR_IN_USE; |
||||
} |
||||
if (file->id == child->id || (file->parent && file->parent->id == child->id)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_ID; |
||||
} |
||||
if (nsl_smartcard_dir_find(file, child->id, NULL)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_ID; |
||||
} |
||||
child->parent = file; |
||||
child->next = file->contents.dir.children; |
||||
file->contents.dir.children = child; |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_dir_find(struct nsl_smartcard_file *file, uint16_t id, struct nsl_smartcard_file **child) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
for (struct nsl_smartcard_file *f = file->contents.dir.children; f; f = f->next) { |
||||
if (f->id == id) { |
||||
if (child) { |
||||
*child = f; |
||||
} |
||||
return 0; |
||||
} |
||||
} |
||||
return NSL_SMARTCARD_ERROR_NOT_FOUND; |
||||
} |
||||
|
||||
int nsl_smartcard_dir_clear(struct nsl_smartcard_file *file) |
||||
{ |
||||
if (!nsl_smartcard_is_dir(file)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) { |
||||
return NSL_SMARTCARD_ERROR_UNAUTHORIZED; |
||||
} |
||||
|
||||
struct nsl_smartcard_file *prev = NULL, *f = file->contents.dir.children; |
||||
while (f) { |
||||
if (nsl_smartcard_is_dir(f)) { |
||||
nsl_smartcard_dir_clear(f); |
||||
prev = f; |
||||
f = f->next; |
||||
} else { |
||||
struct nsl_smartcard_file *next = f->next; |
||||
free(f); |
||||
prev->next = f; |
||||
f = next; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,81 @@ |
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
|
||||
|
||||
#define NSL_SMARTCARD_USER_PIN_LEN 8 |
||||
#define NSL_SMARTCARD_DEV_PIN_LEN 24 |
||||
#define NSL_SMARTCARD_ROOT_DIR_ID 0x3F00 |
||||
|
||||
|
||||
enum nsl_smartcard_auth_level |
||||
{ |
||||
NSL_SMARTCARD_AUTH_NONE, |
||||
NSL_SMARTCARD_AUTH_USER, |
||||
NSL_SMARTCARD_AUTH_DEV, |
||||
NSL_SMARTCARD_AUTH_INTERNAL, |
||||
}; |
||||
|
||||
enum nsl_smartcard_file_type |
||||
{ |
||||
NSL_SMARTCARD_FILE_EXECUTABLE, |
||||
NSL_SMARTCARD_FILE_DATA, |
||||
NSL_SMARTCARD_FILE_KEY, |
||||
NSL_SMARTCARD_FILE_DIR, |
||||
NSL_SMARTCARD_FILE_MODULE, |
||||
}; |
||||
|
||||
struct nsl_smartcard_file_contents |
||||
{ |
||||
uint8_t *data; |
||||
size_t len; |
||||
}; |
||||
|
||||
struct nsl_smartcard_dir_contents |
||||
{ |
||||
struct nsl_smartcard_file *children; |
||||
uint8_t user_pin[NSL_SMARTCARD_USER_PIN_LEN]; |
||||
uint8_t dev_pin[NSL_SMARTCARD_DEV_PIN_LEN]; |
||||
enum nsl_smartcard_auth_level auth; |
||||
uint8_t auth_attempts; |
||||
}; |
||||
|
||||
struct nsl_smartcard_file |
||||
{ |
||||
struct nsl_smartcard_file *parent; |
||||
struct nsl_smartcard_file *next; |
||||
|
||||
enum nsl_smartcard_file_type type; |
||||
|
||||
uint16_t id; |
||||
union { |
||||
struct nsl_smartcard_file_contents file; |
||||
struct nsl_smartcard_dir_contents dir; |
||||
} contents; |
||||
}; |
||||
|
||||
static inline int nsl_smartcard_is_dir(struct nsl_smartcard_file *file) |
||||
{ |
||||
return file->type == NSL_SMARTCARD_FILE_DIR; |
||||
} |
||||
|
||||
static inline int nsl_smartcard_is_file(struct nsl_smartcard_file *file) |
||||
{ |
||||
switch (file->type) { |
||||
case NSL_SMARTCARD_FILE_DATA: |
||||
case NSL_SMARTCARD_FILE_EXECUTABLE: |
||||
case NSL_SMARTCARD_FILE_KEY: |
||||
return 1; |
||||
default: |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
int nsl_smartcard_file_init(struct nsl_smartcard_file *, uint16_t id, enum nsl_smartcard_file_type type); |
||||
int nsl_smartcard_file_read(struct nsl_smartcard_file *, const uint8_t **data, size_t *len, enum nsl_smartcard_file_type type); |
||||
|
||||
int nsl_smartcard_dir_init(struct nsl_smartcard_file *, uint16_t id); |
||||
int nsl_smartcard_dir_authorize(struct nsl_smartcard_file *, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level); |
||||
int nsl_smartcard_dir_change_pin(struct nsl_smartcard_file *, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level); |
||||
int nsl_smartcard_dir_add(struct nsl_smartcard_file *, struct nsl_smartcard_file *child); |
||||
int nsl_smartcard_dir_find(struct nsl_smartcard_file *, uint16_t id, struct nsl_smartcard_file **child); |
||||
int nsl_smartcard_dir_clear(struct nsl_smartcard_file *); |
@ -0,0 +1,140 @@ |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "smartcard.h" |
||||
#include "error.h" |
||||
#include "../util.h" |
||||
|
||||
#define NSL_SMARTCARD_DIR_SEP "\\" |
||||
|
||||
|
||||
static int parse_file_name(const char *name, uint16_t *id) |
||||
{ |
||||
uint8_t pname[2]; |
||||
if (nsl_util_fromhex(name, pname, sizeof(pname))) { |
||||
return 0; |
||||
} |
||||
*id = (pname[0] << 8) | pname[1]; |
||||
return 1; |
||||
} |
||||
|
||||
|
||||
int nsl_smartcard_init(struct nsl_smartcard *smartcard) |
||||
{ |
||||
smartcard->rootdir = smartcard->curdir = NULL; |
||||
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, const char *name) |
||||
{ |
||||
uint16_t id; |
||||
if (!parse_file_name(name, &id)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
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, char *name) |
||||
{ |
||||
struct nsl_smartcard_file *dir; |
||||
if (!strcmp(name, NSL_SMARTCARD_DIR_SEP)) { |
||||
dir = smartcard->rootdir; |
||||
name += sizeof(NSL_SMARTCARD_DIR_SEP) - 1; |
||||
} else { |
||||
dir = smartcard->curdir; |
||||
} |
||||
if (!dir) { |
||||
return NSL_SMARTCARD_ERROR_NOT_FOUND; |
||||
} |
||||
|
||||
do { |
||||
char *seg = strsep(&name, NSL_SMARTCARD_DIR_SEP); |
||||
uint16_t id; |
||||
if (!parse_file_name(seg, &id)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
if (nsl_smartcard_dir_find(dir, id, &dir)) { |
||||
return NSL_SMARTCARD_ERROR_NOT_FOUND; |
||||
} |
||||
if (!nsl_smartcard_is_dir(dir)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_TYPE; |
||||
} |
||||
} while (name); |
||||
|
||||
smartcard->curdir = dir; |
||||
return 0; |
||||
} |
||||
|
||||
int nsl_smartcard_exec(struct nsl_smartcard *smartcard, const char *name, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen) |
||||
{ |
||||
uint16_t id; |
||||
if (!parse_file_name(name, &id)) { |
||||
return NSL_SMARTCARD_ERROR_WRONG_VALUE; |
||||
} |
||||
if (!smartcard->curdir) { |
||||
return NSL_SMARTCARD_ERROR_NOT_FOUND; |
||||
} |
||||
struct nsl_smartcard_file *file; |
||||
if (nsl_smartcard_dir_find(smartcard->curdir, id, &file)) { |
||||
return NSL_SMARTCARD_ERROR_NOT_FOUND; |
||||
} |
||||
|
||||
const uint8_t *data; |
||||
size_t len; |
||||
int err = nsl_smartcard_file_read(file, &data, &len, NSL_SMARTCARD_FILE_EXECUTABLE); |
||||
if (err) { |
||||
return err; |
||||
} |
||||
|
||||
/* TODO: setup VM and run. */ |
||||
return 0; |
||||
} |
@ -1,10 +1,22 @@ |
||||
#pragma once |
||||
#include <stdint.h> |
||||
|
||||
struct nsl_smartcard { |
||||
#include "fs.h" |
||||
#include "emu.h" |
||||
|
||||
struct nsl_smartcard { |
||||
struct nsl_smartcard_file *rootdir; |
||||
struct nsl_smartcard_file *curdir; |
||||
struct nsl_smartcard_emu emu; |
||||
}; |
||||
|
||||
int nsl_smartcard_init(struct nsl_smartcard *smartcard); |
||||
int nsl_smartcard_reset(struct nsl_smartcard *smartcard); |
||||
int nsl_smartcard_authorize(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level); |
||||
int nsl_smartcard_change_pin(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level); |
||||
|
||||
int nsl_smartcard_mkdir(struct nsl_smartcard *smartcard, const char *dir); |
||||
int nsl_smartcard_chdir(struct nsl_smartcard *smartcard, char *name); |
||||
int nsl_smartcard_exec(struct nsl_smartcard *smarcard, const char *name, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen); |
||||
|
||||
int nsl_smartcard_process(struct nsl_smartcard *smartcard, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen); |
||||
|
@ -0,0 +1,17 @@ |
||||
#include "util.h" |
||||
|
||||
/* taken from: https://github.com/chmike/cst_time_memcmp/blob/f09ad819bb381e7de290844fa1f6429423db8dc9/consttime_memcmp.c */ |
||||
int nsl_util_memcmp(const uint8_t *c1, const uint8_t *c2, size_t len) |
||||
{ |
||||
uint16_t d, r, m; |
||||
volatile uint16_t v; |
||||
|
||||
for (r = 0; len; c1++, c2++, len--) { |
||||
v = ((uint16_t)(uint8_t)r)+255; |
||||
m = v/256-1; |
||||
d = (uint16_t)((int)*c1 - (int)*c2); |
||||
r |= (d & m); |
||||
} |
||||
|
||||
return (int)((int32_t)(int16_t)((uint32_t)r + 0x8000) - 0x8000); |
||||
} |
@ -0,0 +1,32 @@ |
||||
#include <stdint.h> |
||||
#include <ctype.h> |
||||
|
||||
int nsl_util_memcmp(const uint8_t *left, const uint8_t *right, size_t len); |
||||
|
||||
static inline int nsl_util_fromhexdigit(int c) |
||||
{ |
||||
c = tolower(c); |
||||
if (c >= '0' && c <= '9') { |
||||
return c - '0'; |
||||
} |
||||
if (c >= 'a' && c <= 'f') { |
||||
return 10 + (c - 'a'); |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
static inline int nsl_util_fromhex(const char *src, unsigned char *dest, size_t len) |
||||
{ |
||||
while (*src && len--) { |
||||
unsigned char a = nsl_util_fromhexdigit(*src++); |
||||
if (a < 0) { |
||||
return 0; |
||||
} |
||||
unsigned char b = nsl_util_fromhexdigit(*src++); |
||||
if (b < 0) { |
||||
return 0; |
||||
} |
||||
*dest++ = (a << 4) | b; |
||||
} |
||||
return !*src && !len; |
||||
} |
Loading…
Reference in new issue