From f82ec90346095069f07906449111123a6dd9321b Mon Sep 17 00:00:00 2001 From: Fan DANG Date: Thu, 11 Jan 2024 22:31:06 +0800 Subject: [PATCH] wip: oath config --- applets/oath/oath.c | 24 ++++----- applets/pass/pass.c | 117 +++++++++++++++++++++++--------------------- include/oath.h | 1 - include/pass.h | 1 + 4 files changed, 75 insertions(+), 68 deletions(-) diff --git a/applets/oath/oath.c b/applets/oath/oath.c index 748cc953..b51c9016 100644 --- a/applets/oath/oath.c +++ b/applets/oath/oath.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -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)); @@ -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); @@ -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); @@ -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); @@ -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) { diff --git a/applets/pass/pass.c b/applets/pass/pass.c index fc31c2aa..09c9b380 100644 --- a/applets/pass/pass.c +++ b/applets/pass/pass.c @@ -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; @@ -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; } @@ -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); diff --git a/include/oath.h b/include/oath.h index fcb379c9..37806607 100644 --- a/include/oath.h +++ b/include/oath.h @@ -4,7 +4,6 @@ #include -#define ATTR_DEFAULT_RECORD 0x01 #define ATTR_KEY 0x02 #define ATTR_HANDLE 0x03 diff --git a/include/pass.h b/include/pass.h index 9aaab1d0..8e4f86ba 100644 --- a/include/pass.h +++ b/include/pass.h @@ -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