diff --git a/src/fido/cmd_register.c b/src/fido/cmd_register.c index 81f5c38..806deea 100644 --- a/src/fido/cmd_register.c +++ b/src/fido/cmd_register.c @@ -22,6 +22,7 @@ #include "random.h" #include "files.h" #include "hid/ctap_hid.h" +#include "management.h" const uint8_t u2f_aid[] = { 7, @@ -32,7 +33,7 @@ int u2f_unload(); int u2f_process_apdu(); app_t *u2f_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { - if (!memcmp(aid, u2f_aid + 1, MIN(aid_len, u2f_aid[0]))) { + if (!memcmp(aid, u2f_aid + 1, MIN(aid_len, u2f_aid[0])) && cap_supported(CAP_U2F)) { a->aid = u2f_aid; a->process_apdu = u2f_process_apdu; a->unload = u2f_unload; diff --git a/src/fido/fido.c b/src/fido/fido.c index b9f7f7c..080246c 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -31,6 +31,7 @@ #include "bsp/board.h" #endif #include +#include "management.h" int fido_process_apdu(); int fido_unload(); @@ -52,7 +53,7 @@ const uint8_t atr_fido[] = { }; app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { - if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0]))) { + if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0])) && cap_supported(CAP_FIDO2)) { a->aid = fido_aid; a->process_apdu = fido_process_apdu; a->unload = fido_unload; diff --git a/src/fido/files.h b/src/fido/files.h index ee8a211..328eb13 100644 --- a/src/fido/files.h +++ b/src/fido/files.h @@ -29,6 +29,7 @@ #define EF_PIN 0x1080 #define EF_AUTHTOKEN 0x1090 #define EF_MINPINLEN 0x1100 +#define EF_DEV_CONF 0x1122 #define EF_CRED 0xCF00 // Creds at 0xCF00 - 0xCFFF #define EF_RP 0xD000 // RPs at 0xD000 - 0xD0FF #define EF_LARGEBLOB 0x1101 // Large Blob Array diff --git a/src/fido/management.c b/src/fido/management.c index 1e42b5e..bd0be9a 100644 --- a/src/fido/management.c +++ b/src/fido/management.c @@ -19,6 +19,9 @@ #include "hsm.h" #include "apdu.h" #include "version.h" +#include "files.h" +#include "asn1.h" +#include "management.h" int man_process_apdu(); int man_unload(); @@ -27,7 +30,7 @@ const uint8_t man_aid[] = { 8, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 }; - +extern void scan_all(); app_t *man_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { if (!memcmp(aid, man_aid + 1, MIN(aid_len, man_aid[0]))) { a->aid = man_aid; @@ -36,6 +39,7 @@ app_t *man_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { sprintf((char *)res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR); res_APDU_size = strlen((char *)res_APDU); apdu.ne = res_APDU_size; + scan_all(); return a; } return NULL; @@ -49,43 +53,69 @@ int man_unload() { return CCID_OK; } +bool cap_supported(uint16_t cap) { + file_t *ef = search_dynamic_file(EF_DEV_CONF); + if (file_has_data(ef)) { + uint16_t tag = 0x0, data_len = file_get_size(ef); + uint8_t *tag_data = NULL, *p = NULL, *data = file_get_data(ef); + size_t tag_len = 0; + while (walk_tlv(data, data_len, &p, &tag, &tag_len, &tag_data)) { + if (tag == TAG_USB_ENABLED) { + uint16_t ecaps = tag_data[0]; + if (tag_len == 2) { + ecaps = (tag_data[1] << 8) | tag_data[0]; + } + return (ecaps & cap); + } + } + } + return true; +} + int man_get_config() { + file_t *ef = search_dynamic_file(EF_DEV_CONF); res_APDU_size = 0; res_APDU[res_APDU_size++] = 0; // Overall length. Filled later - res_APDU[res_APDU_size++] = 0x01; + res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED; res_APDU[res_APDU_size++] = 2; - res_APDU[res_APDU_size++] = 0x02; - res_APDU[res_APDU_size++] = 0x01 | 0x02 | 0x20; - res_APDU[res_APDU_size++] = 0x02; + res_APDU[res_APDU_size++] = CAP_FIDO2 >> 8; + res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH; + res_APDU[res_APDU_size++] = TAG_SERIAL; res_APDU[res_APDU_size++] = 4; #ifndef ENABLE_EMULATION pico_get_unique_board_id_string((char *) res_APDU + res_APDU_size, 4); #endif res_APDU_size += 4; - res_APDU[res_APDU_size++] = 0x03; - res_APDU[res_APDU_size++] = 2; - res_APDU[res_APDU_size++] = 0x02; - res_APDU[res_APDU_size++] = 0x01 | 0x02 | 0x20; - res_APDU[res_APDU_size++] = 0x04; + res_APDU[res_APDU_size++] = TAG_FORM_FACTOR; res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 0x01; - res_APDU[res_APDU_size++] = 0x05; + res_APDU[res_APDU_size++] = TAG_VERSION; res_APDU[res_APDU_size++] = 3; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = 0; - res_APDU[res_APDU_size++] = 0x08; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = 0x80; - res_APDU[res_APDU_size++] = 0x0A; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = 0x00; - res_APDU[res_APDU_size++] = 0x0D; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = 0x00; - res_APDU[res_APDU_size++] = 0x0E; + res_APDU[res_APDU_size++] = TAG_NFC_SUPPORTED; res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 0x00; + if (!file_has_data(ef)) { + res_APDU[res_APDU_size++] = TAG_USB_ENABLED; + res_APDU[res_APDU_size++] = 2; + res_APDU[res_APDU_size++] = CAP_FIDO2 >> 8; + res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH; + res_APDU[res_APDU_size++] = TAG_DEVICE_FLAGS; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = FLAG_EJECT; + res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = 0x00; + res_APDU[res_APDU_size++] = TAG_NFC_ENABLED; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = 0x00; + } + else { + memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef)); + res_APDU_size += file_get_size(ef); + } res_APDU[0] = res_APDU_size - 1; return 0; } @@ -95,10 +125,22 @@ int cmd_read_config() { return SW_OK(); } +int cmd_write_config() { + if (apdu.data[0] != apdu.nc - 1) { + return SW_WRONG_DATA(); + } + file_t *ef = file_new(EF_DEV_CONF); + flash_write_data_to_file(ef, apdu.data + 1, apdu.nc - 1); + low_flash_available(); + return SW_OK(); +} + #define INS_READ_CONFIG 0x1D +#define INS_WRITE_CONFIG 0x1C static const cmd_t cmds[] = { { INS_READ_CONFIG, cmd_read_config }, + { INS_WRITE_CONFIG, cmd_write_config }, { 0x00, 0x0 } }; diff --git a/src/fido/management.h b/src/fido/management.h new file mode 100644 index 0000000..6a5ff0d --- /dev/null +++ b/src/fido/management.h @@ -0,0 +1,55 @@ +/* + * This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MANAGEMENT_H_ +#define _MANAGEMENT_H_ + +#include +#ifndef ENABLE_EMULATION +#include "pico/stdlib.h" +#endif + +#define TAG_USB_SUPPORTED 0x01 +#define TAG_SERIAL 0x02 +#define TAG_USB_ENABLED 0x03 +#define TAG_FORM_FACTOR 0x04 +#define TAG_VERSION 0x05 +#define TAG_AUTO_EJECT_TIMEOUT 0x06 +#define TAG_CHALRESP_TIMEOUT 0x07 +#define TAG_DEVICE_FLAGS 0x08 +#define TAG_APP_VERSIONS 0x09 +#define TAG_CONFIG_LOCK 0x0A +#define TAG_UNLOCK 0x0B +#define TAG_REBOOT 0x0C +#define TAG_NFC_SUPPORTED 0x0D +#define TAG_NFC_ENABLED 0x0E + +#define CAP_OTP 0x01 +#define CAP_U2F 0x02 +#define CAP_FIDO2 0x200 +#define CAP_OATH 0x20 +#define CAP_PIV 0x10 +#define CAP_OPENPGP 0x08 +#define CAP_HSMAUTH 0x100 + +#define FLAG_REMOTE_WAKEUP 0x40 +#define FLAG_EJECT 0x80 + +extern bool cap_supported(uint16_t cap); +extern int man_get_config(); + +#endif //_MANAGEMENT_H diff --git a/src/fido/oath.c b/src/fido/oath.c index 92a02b2..0e5be64 100644 --- a/src/fido/oath.c +++ b/src/fido/oath.c @@ -23,6 +23,7 @@ #include "version.h" #include "asn1.h" #include "crypto_utils.h" +#include "management.h" #define MAX_OATH_CRED 255 #define CHALLENGE_LEN 8 @@ -36,7 +37,7 @@ #define TAG_T_RESPONSE 0x76 #define TAG_NO_RESPONSE 0x77 #define TAG_PROPERTY 0x78 -#define TAG_VERSION 0x79 +#define TAG_T_VERSION 0x79 #define TAG_IMF 0x7a #define TAG_ALGO 0x7b #define TAG_TOUCH_RESPONSE 0x7c @@ -68,12 +69,12 @@ const uint8_t oath_aid[] = { }; app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { - if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0]))) { + if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0])) && cap_supported(CAP_OATH)) { a->aid = oath_aid; a->process_apdu = oath_process_apdu; a->unload = oath_unload; res_APDU_size = 0; - res_APDU[res_APDU_size++] = TAG_VERSION; + res_APDU[res_APDU_size++] = TAG_T_VERSION; res_APDU[res_APDU_size++] = 3; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; diff --git a/src/fido/otp.c b/src/fido/otp.c index d079612..30faf19 100644 --- a/src/fido/otp.c +++ b/src/fido/otp.c @@ -27,6 +27,7 @@ #include "bsp/board.h" #endif #include "mbedtls/aes.h" +#include "management.h" #define FIXED_SIZE 16 #define KEY_SIZE 16 @@ -114,7 +115,7 @@ const uint8_t otp_aid[] = { }; app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { - if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0]))) { + if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0]) && cap_supported(CAP_OTP))) { a->aid = otp_aid; a->process_apdu = otp_process_apdu; a->unload = otp_unload; @@ -175,6 +176,9 @@ extern int calculate_oath(uint8_t truncate, static uint8_t session_counter[2] = {0}; #endif int otp_button_pressed(uint8_t slot) { + if (!cap_supported(CAP_OTP)) { + return 3; + } init_otp(); #ifndef ENABLE_EMULATION file_t *ef = search_dynamic_file(slot == 1 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); @@ -328,8 +332,6 @@ bool check_crc(const otp_config_t *data) { return crc == 0xF0B8; } -extern int man_get_config(); - int cmd_otp() { uint8_t p1 = P1(apdu), p2 = P2(apdu); if (p2 != 0x00) {