diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b9e20c..7abe779 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/piv.c + ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/management.c ) set(INCLUDES ${INCLUDES} diff --git a/src/openpgp/files.h b/src/openpgp/files.h index e75e1f2..e6fd717 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -161,4 +161,6 @@ #define EF_PIV_RETIRED19 0xc11f #define EF_PIV_RETIRED20 0xc120 +#define EF_DEV_CONF 0x1122 + #endif diff --git a/src/openpgp/management.c b/src/openpgp/management.c new file mode 100644 index 0000000..751f8b0 --- /dev/null +++ b/src/openpgp/management.c @@ -0,0 +1,154 @@ +/* + * 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 . + */ + +#include "pico_keys.h" +#include "apdu.h" +#include "version.h" +#include "files.h" +#include "asn1.h" +#include "management.h" + +int man_process_apdu(); +int man_unload(); + +const uint8_t man_aid[] = { + 8, + 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 +}; + +extern void init_piv(); +int man_select(app_t *a) { + a->process_apdu = man_process_apdu; + a->unload = man_unload; + sprintf((char *) res_APDU, "%d.%d.0", PIV_VERSION_MAJOR, PIV_VERSION_MINOR); + res_APDU_size = strlen((char *) res_APDU); + apdu.ne = res_APDU_size; + init_piv(); + return CCID_OK; +} + +void __attribute__((constructor)) man_ctor() { + register_app(man_select, man_aid); +} + +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; + uint8_t *tag_data = NULL, *p = NULL; + uint16_t tag_len = 0; + asn1_ctx_t ctxi; + asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); + while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { + if (tag == TAG_USB_ENABLED) { + uint16_t ecaps = tag_data[0]; + if (tag_len == 2) { + ecaps = (tag_data[0] << 8) | tag_data[1]; + } + 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++] = TAG_USB_SUPPORTED; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = CAP_PIV | CAP_OPENPGP; + 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++] = TAG_FORM_FACTOR; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = 0x01; + res_APDU[res_APDU_size++] = TAG_VERSION; + res_APDU[res_APDU_size++] = 3; + res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR; + res_APDU[res_APDU_size++] = PIV_VERSION_MINOR; + res_APDU[res_APDU_size++] = 0; + 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++] = 1; + res_APDU[res_APDU_size++] = CAP_PIV | CAP_OPENPGP; + 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; +} + +int cmd_read_config() { + man_get_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); + file_put_data(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 } +}; + +int man_process_apdu() { + if (CLA(apdu) != 0x00) { + return SW_CLA_NOT_SUPPORTED(); + } + for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { + if (cmd->ins == INS(apdu)) { + int r = cmd->cmd_handler(); + return r; + } + } + return SW_INS_NOT_SUPPORTED(); +} diff --git a/src/openpgp/management.h b/src/openpgp/management.h new file mode 100644 index 0000000..6a5ff0d --- /dev/null +++ b/src/openpgp/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/openpgp/piv.c b/src/openpgp/piv.c index 6ca4af2..5914e1a 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -70,10 +70,6 @@ uint8_t yk_aid[] = { 8, 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x1, 0x1 }; -uint8_t mgmt_aid[] = { - 8, - 0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 -}; bool has_pwpiv = false; uint8_t session_pwpiv[32]; @@ -318,7 +314,6 @@ int piv_select_aid(app_t *a) { void __attribute__((constructor)) piv_ctor() { register_app(piv_select_aid, piv_aid); register_app(piv_select_aid, yk_aid); - register_app(piv_select_aid, mgmt_aid); } static int cmd_version() {