Skip to content

Commit

Permalink
wip: oath config
Browse files Browse the repository at this point in the history
  • Loading branch information
dangfan committed Jan 11, 2024
1 parent d7ada3f commit f82ec90
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 68 deletions.
24 changes: 12 additions & 12 deletions applets/oath/oath.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <hmac.h>
#include <memzero.h>
#include <oath.h>
#include <pass.h>
#include <rand.h>
#include <string.h>

Expand All @@ -30,8 +31,6 @@ int oath_install(const uint8_t reset) {
oath_poweroff();
if (!reset && get_file_size(OATH_FILE) >= 0) return 0;
if (write_file(OATH_FILE, NULL, 0, 0, 1) < 0) return -1;
const uint32_t default_item = 0xffffffff;
if (write_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &default_item, sizeof(default_item)) < 0) return -1;
if (write_attr(OATH_FILE, ATTR_KEY, NULL, 0) < 0) return -1;
uint8_t handle[HANDLE_LEN];
random_buffer(handle, sizeof(handle));
Expand Down Expand Up @@ -166,12 +165,13 @@ static int oath_delete(const CAPDU *capdu, RAPDU *rapdu) {
for (size_t i = 0; i != n_records; ++i) {
if (read_file(OATH_FILE, &record, i * sizeof(OATH_RECORD), sizeof(OATH_RECORD)) < 0) return -1;
if (record.name_len == name_len && memcmp(record.name, name_ptr, name_len) == 0) {
uint32_t default_item;
if (read_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &default_item, sizeof(default_item)) < 0) return -1;
if (default_item == i) { // clear the default set if it is to be deleted
default_item = 0xffffffff;
if (write_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &default_item, sizeof(default_item)) < 0) return -1;
}
// uint32_t default_item;
// if (read_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &default_item, sizeof(default_item)) < 0) return -1;
// if (default_item == i) { // clear the default set if it is to be deleted
// default_item = 0xffffffff;
// if (write_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &default_item, sizeof(default_item)) < 0) return -1;
// }
// TODO: delete pass config

record.name_len = 0;
return write_file(OATH_FILE, &record, i * sizeof(OATH_RECORD), sizeof(OATH_RECORD), 0);
Expand Down Expand Up @@ -417,7 +417,8 @@ int oath_calculate_by_offset(size_t file_offset, uint8_t result[4]) {
}

static int oath_set_default(const CAPDU *capdu, RAPDU *rapdu) {
if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2);
if (P1 != 0x01 && P1 != 0x02) EXCEPT(SW_WRONG_P1P2);
if (P2 != 0x00) EXCEPT(SW_WRONG_P1P2);

uint16_t offset = 0;
if (offset + 1 >= LC) EXCEPT(SW_WRONG_LENGTH);
Expand All @@ -433,7 +434,7 @@ static int oath_set_default(const CAPDU *capdu, RAPDU *rapdu) {
if (size < 0) return -1;
const uint32_t n_records = size / sizeof(OATH_RECORD);
uint32_t i;
uint32_t file_offset;
uint32_t file_offset = 0;
OATH_RECORD record;
for (i = 0; i != n_records; ++i) {
file_offset = i * sizeof(OATH_RECORD);
Expand All @@ -443,8 +444,7 @@ static int oath_set_default(const CAPDU *capdu, RAPDU *rapdu) {
if (i == n_records) EXCEPT(SW_DATA_INVALID);
if ((record.key[0] & OATH_TYPE_MASK) == OATH_TYPE_TOTP) EXCEPT(SW_CONDITIONS_NOT_SATISFIED);

if (write_attr(OATH_FILE, ATTR_DEFAULT_RECORD, &file_offset, sizeof(file_offset)) < 0) return -1;
return 0;
return pass_update_oath(P1 -1, file_offset, record.name_len, record.name);
}

static int oath_calculate(const CAPDU *capdu, RAPDU *rapdu) {
Expand Down
117 changes: 62 additions & 55 deletions applets/pass/pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,37 @@ typedef enum {
typedef struct {
slot_type_t type;
union {
uint8_t password[33]; // 1-byte length + at most 32-byte content
uint32_t oath_offset;
} __packed;
struct {
uint8_t password_len;
uint8_t password[PASS_MAX_PASSWORD_LENGTH];
} __packed;
struct {
uint32_t oath_offset;
uint8_t name_len;
uint8_t name[MAX_NAME_LEN];
} __packed;
};
uint8_t with_enter;
} __packed pass_slot_t;

static pass_slot_t slots[2];

int pass_install(const uint8_t reset) {
if (!reset && get_file_size(PASS_FILE) >= 0) {
if (reset || get_file_size(PASS_FILE) != sizeof(slots)) {
memzero(slots, sizeof(slots));
if (write_file(PASS_FILE, slots, 0, sizeof(slots), 1) < 0) return -1;
} else {
if (read_file(PASS_FILE, slots, 0, sizeof(slots)) < 0) return -1;
return 0;
}

memzero(slots, sizeof(slots));
if (write_file(PASS_FILE, slots, 0, sizeof(slots), 1) < 0) return -1;

return 0;
}

// Dump slots to buffer, return the length of the buffer
// For each slot, the first byte is the type.
// For PASS_SLOT_OFF, there is no more data
// For PASS_SLOT_STATIC, the second byte is with_enter
// For PASS_SLOT_OATH, the next byte is the length of the name, followed by the name, and the next byte is with_enter
static int dump_slot(const pass_slot_t *slot, uint8_t *buffer) {
int length = 0;

Expand All @@ -55,9 +66,12 @@ static int dump_slot(const pass_slot_t *slot, uint8_t *buffer) {
break;

case PASS_SLOT_OATH:
// For OATH, the next 4 bytes are oath_offset
memcpy(&buffer[length], &slot->oath_offset, sizeof(slot->oath_offset));
length += sizeof(slot->oath_offset);
// For OATH, the second byte is the length of the name
buffer[length++] = slot->name_len;
// The next bytes are the name
memcpy(buffer + length, slot->name, slot->name_len);
length += slot->name_len;
// The next byte is with_enter
buffer[length++] = slot->with_enter;
break;
}
Expand All @@ -75,57 +89,50 @@ int pass_read_config(const CAPDU *capdu, RAPDU *rapdu) {
return 0;
}

// P1 for the slot index, 1 for short slot, 2 for long slot
// DATA contains the slot data:
// The first byte is the slot type
// For OFF, there is no more data
// For STATIC, the second byte is the length of the password, followed by the password, and the next byte is with_enter
// OATH is not allowed to be written here
int pass_write_config(const CAPDU *capdu, RAPDU *rapdu) {
size_t index = 0;

for (int i = 0; i < 2; i++) {
if (index >= LC) {
// Data is not enough to parse a slot
EXCEPT(SW_WRONG_LENGTH);
}

const slot_type_t type = DATA[index++];
switch (type) {
case PASS_SLOT_OFF:
slots[i].type = type;
break;

case PASS_SLOT_STATIC:
if (DATA[index] > PASS_MAX_PASSWORD_LENGTH) {
// Password is too long
EXCEPT(SW_WRONG_DATA);
}
slots[i].type = type;
memcpy(slots[i].password, &DATA[index], DATA[index] + 1);
index += DATA[index] + 1;
slots[i].with_enter = DATA[index++];
break;

case PASS_SLOT_OATH:
if (index + sizeof(slots[0].oath_offset) + sizeof(slots[0].with_enter) > LC) {
// Not enough data for PASS_SLOT_OATH
EXCEPT(SW_WRONG_DATA);
}
slots[i].type = type;
memcpy(&slots[i].oath_offset, &DATA[index], sizeof(slots[0].oath_offset));
index += sizeof(slots[0].oath_offset);
slots[i].with_enter = DATA[index++];
break;

default:
// Invalid slot type
EXCEPT(SW_WRONG_DATA);
}
}
if (P1 != 1 && P1 != 2) EXCEPT(SW_WRONG_P1P2);
if (LC < 1) EXCEPT(SW_WRONG_LENGTH);

pass_slot_t *slot = &slots[P1 - 1];
slot->type = (slot_type_t)DATA[0];

switch (slot->type) {
case PASS_SLOT_OFF:
if (LC != 1) EXCEPT(SW_WRONG_LENGTH);
break;

if (index != LC) {
// Extra data present that doesn't fit in the slot structure
EXCEPT(SW_WRONG_LENGTH);
case PASS_SLOT_STATIC:
if (LC < 3) EXCEPT(SW_WRONG_LENGTH);
slot->password_len = DATA[1];
if (slot->password_len > PASS_MAX_PASSWORD_LENGTH) EXCEPT(SW_WRONG_LENGTH);
memcpy(slot->password, DATA + 2, slot->password_len);
slot->with_enter = DATA[2 + slot->password_len];
if (LC != 3 + slot->password_len) EXCEPT(SW_WRONG_LENGTH);
break;

default:
EXCEPT(SW_WRONG_DATA);
}

return write_file(PASS_FILE, slots, 0, sizeof(slots), 1);
}

int pass_update_oath(uint8_t slot_index, uint32_t offset, uint8_t name_len, const uint8_t *name) {
pass_slot_t *slot = &slots[slot_index];
slot->type = PASS_SLOT_OATH;
slot->oath_offset = offset;
slot->name_len = name_len;
memcpy(slot->name, name, name_len);

return write_file(PASS_FILE, slots, 0, sizeof(slots), 1);
}

static int oath_process_offset(uint32_t offset, char *output) {
uint32_t otp_code;
int ret = oath_calculate_by_offset(offset, (uint8_t *)&otp_code);
Expand Down
1 change: 0 additions & 1 deletion include/oath.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include <apdu.h>

#define ATTR_DEFAULT_RECORD 0x01
#define ATTR_KEY 0x02
#define ATTR_HANDLE 0x03

Expand Down
1 change: 1 addition & 0 deletions include/pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ int pass_install(uint8_t reset);
int pass_read_config(const CAPDU *capdu, RAPDU *rapdu);
int pass_write_config(const CAPDU *capdu, RAPDU *rapdu);
int pass_handle_touch(uint8_t touch_type, char *output);
int pass_update_oath(uint8_t slot_index, uint32_t offset, uint8_t name_len, const uint8_t *name);

#endif // CANOKEY_CORE_INCLUDE_PASS_H

0 comments on commit f82ec90

Please sign in to comment.