├── .github └── workflows │ └── build.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── apdu.c ├── applets.c ├── applets │ ├── admin │ │ └── admin.c │ ├── ctap │ │ ├── cose-key.h │ │ ├── ctap-errors.h │ │ ├── ctap-internal.h │ │ ├── ctap-parser.c │ │ ├── ctap-parser.h │ │ ├── ctap.c │ │ ├── secret.c │ │ ├── secret.h │ │ ├── u2f.c │ │ └── u2f.h │ ├── meta │ │ └── meta.c │ ├── ndef │ │ └── ndef.c │ ├── oath │ │ └── oath.c │ ├── openpgp │ │ ├── key.c │ │ ├── key.h │ │ └── openpgp.c │ └── piv │ │ └── piv.c ├── cert │ ├── attestation-ca-cert.cnf │ ├── attestation-device-cert.cnf │ ├── gen_attestation_ca.sh │ ├── gen_attestation_devive_cert.sh │ ├── u2f_aaguid.bin │ ├── u2f_cert.bin │ └── u2f_cert_key.bin ├── common.c ├── crypto │ ├── aes.c │ ├── algo.c │ ├── block-cipher.c │ ├── crypto-util.c │ ├── des.c │ ├── ecc.c │ ├── esp32_ed25519.c │ ├── hmac.c │ ├── include │ │ ├── aes.h │ │ ├── algo.h │ │ ├── block-cipher.h │ │ ├── crypto-util.h │ │ ├── des.h │ │ ├── ecc.h │ │ ├── esp32_ed25519.h │ │ ├── hmac.h │ │ ├── memzero.h │ │ ├── rand.h │ │ ├── rsa.h │ │ ├── sha.h │ │ ├── sha3.h │ │ └── sm3.h │ ├── memzero.c │ ├── rand.c │ ├── rsa.c │ ├── sha.c │ ├── sha3.c │ └── sm3.c ├── device.c ├── fs.c ├── idf_component.yml ├── include │ ├── admin.h │ ├── apdu.h │ ├── applets.h │ ├── ccid.h │ ├── ccid_device.h │ ├── common.h │ ├── ctap.h │ ├── ctaphid.h │ ├── device-config-default.h │ ├── device.h │ ├── fs.h │ ├── key.h │ ├── meta.h │ ├── ndef.h │ ├── nfc.h │ ├── oath.h │ ├── openpgp.h │ ├── pin.h │ └── piv.h ├── key.c ├── littlefs │ ├── lfs.c │ ├── lfs.h │ ├── lfs_util.c │ └── lfs_util.h ├── main.c ├── pin.c └── usb │ ├── ccid │ ├── ccid.c │ └── ccid_device.c │ └── ctaphid │ └── ctaphid.c ├── sdkconfig.defaults └── u2f_partitions.csv /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | targets: [esp32s2, esp32s3] 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v4 16 | - name: ESP-IDF Build 17 | uses: espressif/esp-idf-ci-action@v1 18 | with: 19 | esp_idf_version: v5.1.2 20 | target: ${{ matrix.targets }} 21 | - name: Package binaries 22 | uses: actions/upload-artifact@v4 23 | with: 24 | name: ${{ matrix.targets }}_binaries 25 | path: | 26 | build/esp32_u2f.bin 27 | build/partition_table/partition-table.bin 28 | build/bootloader/bootloader.bin 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about build system see 2 | # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html 3 | # The following five lines of boilerplate have to be in your project's 4 | # CMakeLists in this exact order for cmake to work correctly 5 | cmake_minimum_required(VERSION 3.16) 6 | 7 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 8 | project(esp32_u2f) 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | Supported Targets | ESP32-S2 | ESP32-S3 | 2 | | ----------------- | -------- | -------- | 3 | 4 | # ESP32 U2F Security Key. 5 | 6 | Turns your cheap ESP32 U2F token. 7 | 8 | ### Hardware Required 9 | 10 | Any ESP board that have USB-OTG supported. 11 | 12 | ### Flash Example 13 | 14 | > **WARNING** 15 | > using erase_flash will lose all stored keys 16 | 17 | ``` 18 | # Erase first 1MB size 19 | esptool erase_region 0x0 0x100000 20 | ``` 21 | 22 | Flash binaries: 23 | 24 | esp32s2 25 | bootloader address is 0x1000 26 | 27 | ``` 28 | esptool --chip esp32s2 write_flash --flash_mode dio --flash_size 2MB --flash_freq 80m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 esp32_u2f.bin 29 | ``` 30 | 31 | esp32s3 32 | bootloader address is 0x0 33 | 34 | ``` 35 | esptool --chip esp32s3 write_flash --flash_mode dio --flash_size 2MB --flash_freq 80m 0x0 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 esp32_u2f.bin 36 | ``` 37 | 38 | ### Tools 39 | 40 | [espressif esptool](https://github.com/espressif/esptool/releases) 41 | 42 | ### License 43 | 44 | [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html) 45 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS "device.c" "main.c" "common.c" "fs.c" "apdu.c" "applets.c" "fs.c" "key.c" "pin.c" 3 | "usb/ccid/ccid_device.c" "usb/ccid/ccid.c" "usb/ctaphid/ctaphid.c" 4 | "applets/admin/admin.c" "applets/ctap/ctap.c" "applets/ctap/ctap-parser.c" "applets/ctap/secret.c" "applets/ctap/u2f.c" "applets/meta/meta.c" "applets/oath/oath.c" "applets/ndef/ndef.c" "applets/openpgp/key.c" "applets/openpgp/openpgp.c" "applets/piv/piv.c" 5 | "crypto/ecc.c" "crypto/hmac.c" "crypto/algo.c" "crypto/sha.c" "crypto/sha3.c" "crypto/memzero.c" "crypto/rand.c" "crypto/sm3.c" "crypto/block-cipher.c" "crypto/aes.c" "crypto/rsa.c" "crypto/des.c" "crypto/esp32_ed25519.c" 6 | "littlefs/lfs.c" "littlefs/lfs_util.c" 7 | INCLUDE_DIRS "include" "crypto/include" "littlefs" 8 | REQUIRES driver mbedtls efuse esp_partition esp_timer 9 | EMBED_FILES "cert/u2f_cert.bin" "cert/u2f_cert_key.bin" "cert/u2f_aaguid.bin" 10 | ) 11 | 12 | option(USE_MBEDCRYPTO "Use mbed-crypto as the crypto library" ON) 13 | if (USE_MBEDCRYPTO) 14 | add_definitions(-DUSE_MBEDCRYPTO) 15 | endif (USE_MBEDCRYPTO) -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "ESP32 U2F GPIO Configuration" 2 | 3 | orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" 4 | 5 | config BLINK_GPIO 6 | int "Blink GPIO number" 7 | range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX 8 | default 15 if IDF_TARGET_ESP32S2 9 | default 48 if IDF_TARGET_ESP32S3 10 | default 8 11 | help 12 | GPIO number (IOxx) to blink on and off the LED. 13 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. 14 | 15 | config BUTTON_ENABLE 16 | bool "enable Button support" 17 | default n 18 | help 19 | Use button to confirm enter,Default use automatically enter 20 | 21 | config BUTTON_GPIO 22 | depends on BUTTON_ENABLE 23 | int "Button GPIO number" 24 | range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX 25 | default 0 26 | help 27 | Button number (IOxx) to button click. 28 | 29 | endmenu -------------------------------------------------------------------------------- /main/apdu.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | enum APPLET { 15 | APPLET_NULL, 16 | APPLET_PIV, 17 | APPLET_FIDO, 18 | APPLET_OATH, 19 | APPLET_ADMIN, 20 | APPLET_OPENPGP, 21 | APPLET_NDEF, 22 | APPLET_META, 23 | APPLET_ENUM_END, 24 | } current_applet; 25 | 26 | enum PIV_STATE { 27 | PIV_STATE_GET_DATA, 28 | PIV_STATE_GET_DATA_RESPONSE, 29 | PIV_STATE_OTHER, 30 | }; 31 | 32 | static const uint8_t PIV_AID[] = {0xA0, 0x00, 0x00, 0x03, 0x08}; 33 | static const uint8_t OATH_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01}; 34 | static const uint8_t ADMIN_AID[] = {0xF0, 0x00, 0x00, 0x00, 0x00}; 35 | static const uint8_t OPENPGP_AID[] = {0xD2, 0x76, 0x00, 0x01, 0x24, 0x01}; 36 | static const uint8_t FIDO_AID[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; 37 | static const uint8_t NDEF_AID[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01}; 38 | static const uint8_t META_AID[] = {0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17}; 39 | 40 | static const uint8_t *const AID[] = { 41 | [APPLET_NULL] = NULL, [APPLET_PIV] = PIV_AID, [APPLET_FIDO] = FIDO_AID, [APPLET_OATH] = OATH_AID, 42 | [APPLET_ADMIN] = ADMIN_AID, [APPLET_OPENPGP] = OPENPGP_AID, [APPLET_NDEF] = NDEF_AID, [APPLET_META] = META_AID, 43 | }; 44 | 45 | static const uint8_t AID_Size[] = { 46 | [APPLET_NULL] = 0, 47 | [APPLET_PIV] = sizeof(PIV_AID), 48 | [APPLET_FIDO] = sizeof(FIDO_AID), 49 | [APPLET_OATH] = sizeof(OATH_AID), 50 | [APPLET_ADMIN] = sizeof(ADMIN_AID), 51 | [APPLET_OPENPGP] = sizeof(OPENPGP_AID), 52 | [APPLET_NDEF] = sizeof(NDEF_AID), 53 | [APPLET_META] = sizeof(META_AID), 54 | }; 55 | 56 | static volatile uint32_t buffer_owner = BUFFER_OWNER_NONE; 57 | static uint8_t chaining_buffer[APDU_BUFFER_SIZE]; 58 | static CAPDU_CHAINING capdu_chaining = { 59 | .capdu.data = chaining_buffer, 60 | }; 61 | static RAPDU_CHAINING rapdu_chaining = { 62 | .rapdu.data = chaining_buffer, 63 | }; 64 | 65 | int build_capdu(CAPDU *capdu, const uint8_t *cmd, uint16_t len) { 66 | if (len < 4) return -1; 67 | CLA = cmd[0]; 68 | INS = cmd[1]; 69 | P1 = cmd[2]; 70 | P2 = cmd[3]; 71 | LC = 0; 72 | LE = 0; 73 | 74 | if (len == 4) // Case 1 75 | return 0; 76 | LC = cmd[4]; 77 | if (len == 5) { // Case 2S 78 | LE = LC; 79 | LC = 0; 80 | if (LE == 0) LE = 0x100; 81 | } else if (LC > 0 && len == 5 + LC) { // Case 3S 82 | memmove(DATA, cmd + 5, LC); 83 | LE = 0x100; 84 | } else if (LC > 0 && len == 6 + LC) { // Case 4S 85 | memmove(DATA, cmd + 5, LC); 86 | LE = cmd[5 + LC]; 87 | if (LE == 0) LE = 0x100; 88 | } else if (len == 7) { // Case 2E 89 | if (LC != 0) return -1; 90 | LE = (cmd[5] << 8) | cmd[6]; 91 | if (LE == 0) LE = 0x10000; 92 | } else { 93 | if (LC != 0 || len < 7) return -1; 94 | LC = (cmd[5] << 8) | cmd[6]; 95 | if (LC == 0) return -1; 96 | if (len == 7 + LC) { // Case 3E 97 | memmove(DATA, cmd + 7, LC); 98 | LE = 0x10000; 99 | return 0; 100 | } else if (len == 9 + LC) { // Case 4E 101 | memmove(DATA, cmd + 7, LC); 102 | LE = (cmd[7 + LC] << 8) | cmd[8 + LC]; 103 | if (LE == 0) LE = 0x10000; 104 | } else 105 | return -1; 106 | } 107 | return 0; 108 | } 109 | 110 | int apdu_input(CAPDU_CHAINING *ex, const CAPDU *sh) { 111 | restart: 112 | if (!ex->in_chaining) { 113 | ex->capdu.cla = sh->cla & 0xEF; 114 | ex->capdu.ins = sh->ins; 115 | ex->capdu.p1 = sh->p1; 116 | ex->capdu.p2 = sh->p2; 117 | ex->capdu.lc = 0; 118 | } else if (ex->capdu.cla != (sh->cla & 0xEF) || ex->capdu.ins != sh->ins || ex->capdu.p1 != sh->p1 || 119 | ex->capdu.p2 != sh->p2) { 120 | ex->in_chaining = 0; 121 | goto restart; 122 | } 123 | ex->in_chaining = 1; 124 | if (ex->capdu.lc + sh->lc > APDU_BUFFER_SIZE) return APDU_CHAINING_OVERFLOW; 125 | memcpy(ex->capdu.data + ex->capdu.lc, sh->data, sh->lc); 126 | ex->capdu.lc += sh->lc; 127 | 128 | if (sh->cla & 0x10) // not last block 129 | return APDU_CHAINING_NOT_LAST_BLOCK; 130 | else { 131 | ex->in_chaining = 0; 132 | ex->capdu.le = sh->le; 133 | return APDU_CHAINING_LAST_BLOCK; 134 | } 135 | } 136 | 137 | int apdu_output(RAPDU_CHAINING *ex, RAPDU *sh) { 138 | uint16_t to_send = ex->rapdu.len - ex->sent; 139 | if (to_send > sh->len) to_send = sh->len; 140 | memcpy(sh->data, ex->rapdu.data + ex->sent, to_send); 141 | sh->len = to_send; 142 | ex->sent += to_send; 143 | if (ex->sent < ex->rapdu.len) { 144 | if (ex->rapdu.len - ex->sent > 0xFF) 145 | sh->sw = 0x61FF; 146 | else 147 | sh->sw = 0x6100 + (ex->rapdu.len - ex->sent); 148 | } else 149 | sh->sw = ex->rapdu.sw; 150 | return 0; 151 | } 152 | 153 | void process_apdu(CAPDU *capdu, RAPDU *rapdu) { 154 | static enum PIV_STATE piv_state; 155 | if (current_applet == APPLET_PIV) { 156 | // Offload some APDU chaining commands of PIV applet, 157 | // because the length of concatenated payloads may exceed chaining buffer size. 158 | if (INS == PIV_INS_GET_DATA) 159 | piv_state = PIV_STATE_GET_DATA; 160 | else if ((piv_state == PIV_STATE_GET_DATA || piv_state == PIV_STATE_GET_DATA_RESPONSE) && INS == 0xC0) 161 | piv_state = PIV_STATE_GET_DATA_RESPONSE; 162 | else 163 | piv_state = PIV_STATE_OTHER; 164 | if (piv_state == PIV_STATE_GET_DATA || piv_state == PIV_STATE_GET_DATA_RESPONSE || INS == PIV_INS_PUT_DATA) { 165 | LE = MIN(LE, APDU_BUFFER_SIZE); // Always clamp the Le to valid range 166 | piv_process_apdu(capdu, rapdu); 167 | return; 168 | } 169 | } 170 | int ret = apdu_input(&capdu_chaining, capdu); 171 | if (ret == APDU_CHAINING_NOT_LAST_BLOCK) { 172 | LL = 0; 173 | SW = SW_NO_ERROR; 174 | } else if (ret == APDU_CHAINING_LAST_BLOCK) { 175 | capdu = &capdu_chaining.capdu; 176 | LE = MIN(LE, APDU_BUFFER_SIZE); 177 | if ((CLA == 0x80 || CLA == 0x00) && INS == 0xC0) { // GET RESPONSE 178 | rapdu->len = LE; 179 | apdu_output(&rapdu_chaining, rapdu); 180 | return; 181 | } 182 | rapdu_chaining.sent = 0; 183 | if (CLA == 0x00 && INS == 0xA4 && P1 == 0x04 && P2 == 0x00) { 184 | uint8_t i, end = APPLET_ENUM_END; 185 | for (i = APPLET_NULL + 1; i != end; ++i) { 186 | if (LC >= AID_Size[i] && memcmp(DATA, AID[i], AID_Size[i]) == 0) { 187 | if (i == APPLET_NDEF && !cfg_is_ndef_enable()) { 188 | LL = 0; 189 | SW = SW_FILE_NOT_FOUND; 190 | DBG_MSG("NDEF is disable\n"); 191 | return; 192 | } 193 | if (i == APPLET_PIV) piv_state = PIV_STATE_OTHER; // Reset `piv_state` 194 | if (i != current_applet) applets_poweroff(); 195 | current_applet = i; 196 | DBG_MSG("applet switched to: %d\n", current_applet); 197 | break; 198 | } 199 | } 200 | if (i == end) { 201 | LL = 0; 202 | SW = SW_FILE_NOT_FOUND; 203 | DBG_MSG("applet not found\n"); 204 | return; 205 | } 206 | } 207 | switch (current_applet) { 208 | case APPLET_OPENPGP: 209 | openpgp_process_apdu(capdu, &rapdu_chaining.rapdu); 210 | rapdu->len = LE; 211 | apdu_output(&rapdu_chaining, rapdu); 212 | break; 213 | case APPLET_PIV: 214 | piv_process_apdu(capdu, &rapdu_chaining.rapdu); 215 | rapdu->len = LE; 216 | apdu_output(&rapdu_chaining, rapdu); 217 | break; 218 | case APPLET_FIDO: 219 | #ifdef TEST 220 | if (CLA == 0x00 && INS == 0xEE && LC == 0x04 && memcmp(DATA, "\x12\x56\xAB\xF0", 4) == 0) { 221 | printf("MAGIC REBOOT command received!\r\n"); 222 | testmode_set_initial_ticks(0); 223 | testmode_set_initial_ticks(device_get_tick()); 224 | ctap_install(0); 225 | SW = 0x9000; 226 | LL = 0; 227 | break; 228 | } 229 | if (CLA == 0x00 && INS == 0xEF) { 230 | testmode_inject_error(P1, P2, LC, DATA); 231 | SW = 0x9000; 232 | LL = 0; 233 | break; 234 | } 235 | #endif 236 | ctap_process_apdu(capdu, &rapdu_chaining.rapdu); 237 | rapdu->len = LE; 238 | apdu_output(&rapdu_chaining, rapdu); 239 | break; 240 | case APPLET_OATH: 241 | oath_process_apdu(capdu, rapdu); 242 | break; 243 | case APPLET_ADMIN: 244 | admin_process_apdu(capdu, rapdu); 245 | break; 246 | case APPLET_NDEF: 247 | ndef_process_apdu(capdu, rapdu); 248 | break; 249 | case APPLET_META: 250 | meta_process_apdu(capdu, rapdu); 251 | break; 252 | default: 253 | LL = 0; 254 | SW = SW_FILE_NOT_FOUND; 255 | } 256 | } else { 257 | LL = 0; 258 | SW = SW_CHECKING_ERROR; 259 | } 260 | } 261 | 262 | int acquire_apdu_buffer(uint8_t owner) { 263 | device_atomic_compare_and_swap(&buffer_owner, BUFFER_OWNER_NONE, owner); 264 | return buffer_owner == owner ? 0 : -1; 265 | } 266 | 267 | int release_apdu_buffer(uint8_t owner) { 268 | device_atomic_compare_and_swap(&buffer_owner, owner, BUFFER_OWNER_NONE); 269 | return buffer_owner == BUFFER_OWNER_NONE ? 0 : -1; 270 | } 271 | -------------------------------------------------------------------------------- /main/applets.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void applets_install(void) { 11 | openpgp_install(0); 12 | piv_install(0); 13 | oath_install(0); 14 | ctap_install(0); 15 | admin_install(0); 16 | ndef_install(0); 17 | } 18 | 19 | void applets_poweroff(void) { 20 | piv_poweroff(); 21 | oath_poweroff(); 22 | admin_poweroff(); 23 | openpgp_poweroff(); 24 | ndef_poweroff(); 25 | } 26 | -------------------------------------------------------------------------------- /main/applets/admin/admin.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define PIN_RETRY_COUNTER 3 14 | #define SN_FILE "sn" 15 | #define CFG_FILE "admin_cfg" 16 | 17 | static pin_t pin = {.min_length = 6, .max_length = PIN_MAX_LENGTH, .is_validated = 0, .path = "admin-pin"}; 18 | 19 | static const admin_device_config_t default_cfg = {.led_normally_on = 1, .ndef_en = 1, .webusb_landing_en = 1, .kbd_with_return_en = 1}; 20 | 21 | static admin_device_config_t current_config; 22 | 23 | __attribute__((weak)) int admin_vendor_specific(const CAPDU *capdu, RAPDU *rapdu) { 24 | UNUSED(capdu); 25 | UNUSED(rapdu); 26 | return 0; 27 | } 28 | 29 | __attribute__((weak)) int admin_vendor_version(const CAPDU *capdu, RAPDU *rapdu) { 30 | UNUSED(capdu); 31 | UNUSED(rapdu); 32 | return 0; 33 | } 34 | 35 | __attribute__((weak)) int admin_vendor_hw_variant(const CAPDU *capdu, RAPDU *rapdu) { 36 | UNUSED(capdu); 37 | UNUSED(rapdu); 38 | return 0; 39 | } 40 | 41 | __attribute__((weak)) int admin_vendor_hw_sn(const CAPDU *capdu, RAPDU *rapdu) { 42 | UNUSED(capdu); 43 | UNUSED(rapdu); 44 | return 0; 45 | } 46 | 47 | uint8_t cfg_is_led_normally_on(void) { return current_config.led_normally_on; } 48 | 49 | uint8_t cfg_is_kbd_interface_enable(void) { return current_config.kbd_interface_en; } 50 | 51 | uint8_t cfg_is_ndef_enable(void) { return current_config.ndef_en; } 52 | 53 | uint8_t cfg_is_webusb_landing_enable(void) { return current_config.webusb_landing_en; } 54 | 55 | uint8_t cfg_is_kbd_with_return_enable(void) { return current_config.kbd_with_return_en; } 56 | 57 | void admin_poweroff(void) { pin.is_validated = 0; } 58 | 59 | int admin_install(const uint8_t reset) { 60 | admin_poweroff(); 61 | if (reset || get_file_size(CFG_FILE) != sizeof(admin_device_config_t)) { 62 | current_config = default_cfg; 63 | if (write_file(CFG_FILE, ¤t_config, 0, sizeof(current_config), 1) < 0) return -1; 64 | } else { 65 | if (read_file(CFG_FILE, ¤t_config, 0, sizeof(current_config)) < 0) return -1; 66 | } 67 | if (reset || get_file_size(pin.path) < 0) { 68 | if (pin_create(&pin, "123456", 6, PIN_RETRY_COUNTER) < 0) return -1; 69 | } 70 | return 0; 71 | } 72 | 73 | static int admin_verify(const CAPDU *capdu, RAPDU *rapdu) { 74 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 75 | if (LC == 0) { 76 | if (pin.is_validated) return 0; 77 | const int retries = pin_get_retries(&pin); 78 | if (retries < 0) return -1; 79 | EXCEPT(SW_PIN_RETRIES + retries); 80 | } 81 | uint8_t ctr; 82 | const int err = pin_verify(&pin, DATA, LC, &ctr); 83 | if (err == PIN_IO_FAIL) return -1; 84 | if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH); 85 | if (ctr == 0) EXCEPT(SW_AUTHENTICATION_BLOCKED); 86 | if (err == PIN_AUTH_FAIL) EXCEPT(SW_PIN_RETRIES + ctr); 87 | return 0; 88 | } 89 | 90 | static int admin_change_pin(const CAPDU *capdu, RAPDU *rapdu) { 91 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 92 | const int err = pin_update(&pin, DATA, LC); 93 | if (err == PIN_IO_FAIL) return -1; 94 | if (err == PIN_LENGTH_INVALID) EXCEPT(SW_WRONG_LENGTH); 95 | return 0; 96 | } 97 | 98 | static int admin_write_sn(const CAPDU *capdu, RAPDU *rapdu) { 99 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 100 | if (LC != 0x04) EXCEPT(SW_WRONG_LENGTH); 101 | if (get_file_size(SN_FILE) >= 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 102 | return write_file(SN_FILE, DATA, 0, LC, 1); 103 | } 104 | 105 | static int admin_read_sn(const CAPDU *capdu, RAPDU *rapdu) { 106 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 107 | if (LE < 4) EXCEPT(SW_WRONG_LENGTH); 108 | 109 | fill_sn(RDATA); 110 | LL = 4; 111 | 112 | return 0; 113 | } 114 | 115 | static int admin_config(const CAPDU *capdu, RAPDU *rapdu) { 116 | switch (P1) { 117 | case ADMIN_P1_CFG_LED_ON: 118 | current_config.led_normally_on = P2 & 1; 119 | break; 120 | case ADMIN_P1_CFG_KBDIFACE: 121 | current_config.kbd_interface_en = P2 & 1; 122 | break; 123 | case ADMIN_P1_CFG_NDEF: 124 | current_config.ndef_en = P2 & 1; 125 | break; 126 | case ADMIN_P1_CFG_WEBUSB_LANDING: 127 | current_config.webusb_landing_en = P2 & 1; 128 | break; 129 | case ADMIN_P1_CFG_KBD_WITH_RETURN: 130 | current_config.kbd_with_return_en = P2 & 1; 131 | break; 132 | default: 133 | EXCEPT(SW_WRONG_P1P2); 134 | } 135 | const int ret = write_file(CFG_FILE, ¤t_config, 0, sizeof(current_config), 1); 136 | stop_blinking(); 137 | return ret; 138 | } 139 | 140 | static int admin_read_config(const CAPDU *capdu, RAPDU *rapdu) { 141 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 142 | if (LE < 5) EXCEPT(SW_WRONG_LENGTH); 143 | 144 | RDATA[0] = current_config.led_normally_on; 145 | RDATA[1] = current_config.kbd_interface_en; 146 | RDATA[2] = ndef_get_read_only(); 147 | RDATA[3] = current_config.ndef_en; 148 | RDATA[4] = current_config.webusb_landing_en; 149 | RDATA[5] = current_config.kbd_with_return_en; 150 | LL = 6; 151 | 152 | return 0; 153 | } 154 | 155 | static int admin_flash_usage(const CAPDU *capdu, RAPDU *rapdu) { 156 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 157 | if (LE < 2) EXCEPT(SW_WRONG_LENGTH); 158 | 159 | RDATA[0] = get_fs_usage(); 160 | RDATA[1] = get_fs_size(); 161 | LL = 2; 162 | 163 | return 0; 164 | } 165 | 166 | static int admin_factory_reset(const CAPDU *capdu, RAPDU *rapdu) { 167 | int ret; 168 | if (P1 != 0x00) EXCEPT(SW_WRONG_P1P2); 169 | if (LC != 5) EXCEPT(SW_WRONG_LENGTH); 170 | if (memcmp(DATA, "RESET", 5) != 0) EXCEPT(SW_WRONG_DATA); 171 | #ifndef FUZZ 172 | ret = pin_get_retries(&pin); 173 | if (ret > 0) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 174 | 175 | if (is_nfc()) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 176 | if (strong_user_presence_test() < 0) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED); 177 | #endif 178 | 179 | DBG_MSG("factory reset begins\n"); 180 | ret = openpgp_install(1); 181 | if (ret < 0) return ret; 182 | ret = piv_install(1); 183 | if (ret < 0) return ret; 184 | ret = oath_install(1); 185 | if (ret < 0) return ret; 186 | ret = ctap_install(1); 187 | if (ret < 0) return ret; 188 | ret = ndef_install(1); 189 | if (ret < 0) return ret; 190 | ret = admin_install(1); 191 | if (ret < 0) return ret; 192 | return 0; 193 | } 194 | 195 | void fill_sn(uint8_t *buf) { 196 | const int err = read_file(SN_FILE, buf, 0, 4); 197 | if (err != 4) memset(buf, 0, 4); 198 | } 199 | 200 | int admin_process_apdu(const CAPDU *capdu, RAPDU *rapdu) { 201 | LL = 0; 202 | SW = SW_NO_ERROR; 203 | 204 | int ret = 0; 205 | switch (INS) { 206 | case ADMIN_INS_SELECT: 207 | if (P1 != 0x04 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 208 | return 0; 209 | 210 | case ADMIN_INS_READ_VERSION: 211 | if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 212 | if (P1 == 0) 213 | ret = admin_vendor_version(capdu, rapdu); 214 | else if (P1 == 1) 215 | ret = admin_vendor_hw_variant(capdu, rapdu); 216 | goto done; 217 | 218 | case ADMIN_INS_READ_SN: 219 | if (P1 > 1 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 220 | if (P1 == 0) 221 | ret = admin_read_sn(capdu, rapdu); 222 | else if (P1 == 1) 223 | ret = admin_vendor_hw_sn(capdu, rapdu); 224 | goto done; 225 | 226 | case ADMIN_INS_FACTORY_RESET: 227 | ret = admin_factory_reset(capdu, rapdu); 228 | goto done; 229 | 230 | case ADMIN_INS_VERIFY: 231 | ret = admin_verify(capdu, rapdu); 232 | goto done; 233 | 234 | default: 235 | break; 236 | } 237 | 238 | #ifndef FUZZ 239 | if (!pin.is_validated) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED); 240 | #endif 241 | 242 | switch (INS) { 243 | case ADMIN_INS_WRITE_FIDO_PRIVATE_KEY: 244 | ret = ctap_install_private_key(capdu, rapdu); 245 | break; 246 | case ADMIN_INS_WRITE_FIDO_CERT: 247 | ret = ctap_install_cert(capdu, rapdu); 248 | break; 249 | case ADMIN_INS_RESET_OPENPGP: 250 | ret = openpgp_install(1); 251 | break; 252 | case ADMIN_INS_RESET_PIV: 253 | ret = piv_install(1); 254 | break; 255 | case ADMIN_INS_RESET_OATH: 256 | ret = oath_install(1); 257 | break; 258 | case ADMIN_INS_RESET_NDEF: 259 | ret = ndef_install(1); 260 | break; 261 | case ADMIN_INS_TOGGLE_NDEF_READ_ONLY: 262 | ret = ndef_toggle_read_only(capdu, rapdu); 263 | break; 264 | case ADMIN_INS_RESET_CTAP: 265 | ret = ctap_install(1); 266 | break; 267 | case ADMIN_INS_READ_CTAP_SM2_CONFIG: 268 | ret = ctap_read_sm2_config(capdu, rapdu); 269 | break; 270 | case ADMIN_INS_WRITE_CTAP_SM2_CONFIG: 271 | ret = ctap_write_sm2_config(capdu, rapdu); 272 | break; 273 | case ADMIN_INS_CHANGE_PIN: 274 | ret = admin_change_pin(capdu, rapdu); 275 | break; 276 | case ADMIN_INS_WRITE_SN: 277 | ret = admin_write_sn(capdu, rapdu); 278 | break; 279 | case ADMIN_INS_CONFIG: 280 | ret = admin_config(capdu, rapdu); 281 | break; 282 | case ADMIN_INS_FLASH_USAGE: 283 | ret = admin_flash_usage(capdu, rapdu); 284 | break; 285 | case ADMIN_INS_READ_CONFIG: 286 | ret = admin_read_config(capdu, rapdu); 287 | break; 288 | case ADMIN_INS_VENDOR_SPECIFIC: 289 | ret = admin_vendor_specific(capdu, rapdu); 290 | break; 291 | default: 292 | EXCEPT(SW_INS_NOT_SUPPORTED); 293 | } 294 | 295 | done: 296 | if (ret < 0) EXCEPT(SW_UNABLE_TO_PROCESS); 297 | return 0; 298 | } 299 | -------------------------------------------------------------------------------- /main/applets/ctap/cose-key.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_FIDO2_COSE_KEY_H_ 3 | #define CANOKEY_CORE_FIDO2_COSE_KEY_H_ 4 | 5 | #define COSE_KEY_LABEL_KTY 1 6 | #define COSE_KEY_LABEL_ALG 3 7 | #define COSE_KEY_LABEL_CRV -1 8 | #define COSE_KEY_LABEL_X -2 9 | #define COSE_KEY_LABEL_Y -3 10 | 11 | #define COSE_KEY_KTY_OKP 1 12 | #define COSE_KEY_KTY_EC2 2 13 | 14 | #define COSE_KEY_CRV_P256 1 15 | #define COSE_KEY_CRV_ED25519 6 16 | 17 | #define COSE_ALG_ES256 -7 18 | #define COSE_ALG_EDDSA -8 19 | #define COSE_ALG_ECDH_ES_HKDF_256 -25 20 | 21 | #endif // CANOKEY_CORE_FIDO2_COSE_KEY_H_ 22 | -------------------------------------------------------------------------------- /main/applets/ctap/ctap-errors.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_FIDO2_CTAP_ERRORS_H_ 3 | #define CANOKEY_CORE_FIDO2_CTAP_ERRORS_H_ 4 | 5 | #define CTAP1_ERR_SUCCESS 0x00 6 | #define CTAP1_ERR_INVALID_COMMAND 0x01 7 | #define CTAP1_ERR_INVALID_PARAMETER 0x02 8 | #define CTAP1_ERR_INVALID_LENGTH 0x03 9 | #define CTAP1_ERR_INVALID_SEQ 0x04 10 | #define CTAP1_ERR_TIMEOUT 0x05 11 | #define CTAP1_ERR_CHANNEL_BUSY 0x06 12 | #define CTAP1_ERR_LOCK_REQUIRED 0x0A 13 | #define CTAP1_ERR_INVALID_CHANNEL 0x0B 14 | #define CTAP2_ERR_CBOR_UNEXPECTED_TYPE 0x11 15 | #define CTAP2_ERR_INVALID_CBOR 0x12 16 | #define CTAP2_ERR_MISSING_PARAMETER 0x14 17 | #define CTAP2_ERR_LIMIT_EXCEEDED 0x15 18 | #define CTAP2_ERR_FP_DATABASE_FULL 0x17 19 | #define CTAP2_ERR_LARGE_BLOB_STORAGE_FULL 0x18 20 | #define CTAP2_ERR_CREDENTIAL_EXCLUDED 0x19 21 | #define CTAP2_ERR_PROCESSING 0x21 22 | #define CTAP2_ERR_INVALID_CREDENTIAL 0x22 23 | #define CTAP2_ERR_USER_ACTION_PENDING 0x23 24 | #define CTAP2_ERR_OPERATION_PENDING 0x24 25 | #define CTAP2_ERR_NO_OPERATIONS 0x25 26 | #define CTAP2_ERR_UNSUPPORTED_ALGORITHM 0x26 27 | #define CTAP2_ERR_OPERATION_DENIED 0x27 28 | #define CTAP2_ERR_KEY_STORE_FULL 0x28 29 | #define CTAP2_ERR_UNSUPPORTED_OPTION 0x2B 30 | #define CTAP2_ERR_INVALID_OPTION 0x2C 31 | #define CTAP2_ERR_KEEPALIVE_CANCEL 0x2D 32 | #define CTAP2_ERR_NO_CREDENTIALS 0x2E 33 | #define CTAP2_ERR_USER_ACTION_TIMEOUT 0x2F 34 | #define CTAP2_ERR_NOT_ALLOWED 0x30 35 | #define CTAP2_ERR_PIN_INVALID 0x31 36 | #define CTAP2_ERR_PIN_BLOCKED 0x32 37 | #define CTAP2_ERR_PIN_AUTH_INVALID 0x33 38 | #define CTAP2_ERR_PIN_AUTH_BLOCKED 0x34 39 | #define CTAP2_ERR_PIN_NOT_SET 0x35 40 | #define CTAP2_ERR_PUAT_REQUIRED 0x36 41 | #define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37 42 | #define CTAP2_ERR_REQUEST_TOO_LARGE 0x39 43 | #define CTAP2_ERR_ACTION_TIMEOUT 0x3A 44 | #define CTAP2_ERR_UP_REQUIRED 0x3B 45 | #define CTAP2_ERR_UV_BLOCKED 0x3C 46 | #define CTAP2_ERR_INTEGRITY_FAILURE 0x3D 47 | #define CTAP2_ERR_INVALID_SUBCOMMAND 0x3E 48 | #define CTAP2_ERR_UV_INVALID 0x3F 49 | #define CTAP2_ERR_UNAUTHORIZED_PERMISSION 0x40 50 | #define CTAP1_ERR_OTHER 0x7F 51 | #define CTAP2_ERR_SPEC_LAST 0xDF 52 | #define CTAP2_ERR_EXTENSION_FIRST 0xE0 53 | #define CTAP2_ERR_EXTENSION_LAST 0xEF 54 | #define CTAP2_ERR_VENDOR_FIRST 0xF0 55 | #define CTAP2_ERR_UNHANDLED_REQUEST 0xF1 56 | #define CTAP2_ERR_VENDOR_LAST 0xFF 57 | 58 | #endif // CANOKEY_CORE_FIDO2_CTAP_ERRORS_H_ 59 | -------------------------------------------------------------------------------- /main/applets/ctap/ctap-parser.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_FIDO2_CTAP_PARSER_H_ 3 | #define CANOKEY_CORE_FIDO2_CTAP_PARSER_H_ 4 | 5 | #include "ctap-internal.h" 6 | #include 7 | #include 8 | 9 | uint8_t parse_user(user_entity *user, CborValue *val); 10 | uint8_t parse_verify_pub_key_cred_params(CborValue *val, int32_t *alg_type); 11 | uint8_t parse_credential_descriptor(CborValue *arr, uint8_t *id); 12 | uint8_t parse_public_key_credential_list(CborValue *lst); 13 | uint8_t parse_options(CTAP_options *options, CborValue *val); 14 | uint8_t parse_cose_key(CborValue *val, uint8_t *public_key); 15 | uint8_t parse_make_credential(CborParser *parser, CTAP_make_credential *mc, const uint8_t *buf, size_t len); 16 | uint8_t parse_get_assertion(CborParser *parser, CTAP_get_assertion *ga, const uint8_t *buf, size_t len); 17 | uint8_t parse_client_pin(CborParser *parser, CTAP_client_pin *cp, const uint8_t *buf, size_t len); 18 | uint8_t parse_credential_management(CborParser *parser, CTAP_credential_management *cm, const uint8_t *buf, size_t len); 19 | uint8_t parse_large_blobs(CborParser *parser, CTAP_large_blobs *lb, const uint8_t *buf, size_t len); 20 | 21 | #endif // CANOKEY_CORE_FIDO2_CTAP_PARSER_H_ 22 | -------------------------------------------------------------------------------- /main/applets/ctap/secret.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_FIDO2_SECRET_H_ 3 | #define CANOKEY_CORE_FIDO2_SECRET_H_ 4 | 5 | #include "ctap-internal.h" 6 | #include 7 | 8 | // utility functions 9 | void cp_begin_using_uv_auth_token(bool user_is_present); 10 | void cp_pin_uv_auth_token_usage_timer_observer(void); 11 | bool cp_get_user_present_flag_value(void); 12 | bool cp_get_user_verified_flag_value(void); 13 | void cp_clear_user_present_flag(void); 14 | void cp_clear_user_verified_flag(void); 15 | void cp_clear_pin_uv_auth_token_permissions_except_lbw(void); 16 | void cp_stop_using_pin_uv_auth_token(void); 17 | 18 | // pin auth protocol 19 | void cp_initialize(void); 20 | void cp_regenerate(void); 21 | void cp_reset_pin_uv_auth_token(void); 22 | void cp_get_public_key(uint8_t *buf); 23 | int cp_decapsulate(uint8_t *buf, int pin_protocol); 24 | int cp_encrypt(const uint8_t *key, const uint8_t *in, size_t in_size, uint8_t *out, int pin_protocol); 25 | int cp_encrypt_pin_token(const uint8_t *key, uint8_t *out, int pin_protocol); 26 | int cp_decrypt(const uint8_t *key, const uint8_t *in, size_t in_size, uint8_t *out, int pin_protocol); 27 | bool cp_verify(const uint8_t *key, size_t key_len, const uint8_t *msg, size_t msg_len, const uint8_t *sig, int pin_protocol); 28 | bool cp_verify_pin_token(const uint8_t *msg, size_t msg_len, const uint8_t *sig, int pin_protocol); 29 | 30 | void cp_set_permission(int new_permissions); 31 | bool cp_has_permission(int permission); 32 | bool cp_has_associated_rp_id(void); 33 | bool cp_verify_rp_id(const uint8_t *rp_id_hash); 34 | void cp_associate_rp_id(const uint8_t *rp_id_hash); 35 | key_type_t cose_alg_to_key_type(int alg); 36 | 37 | int increase_counter(uint32_t *counter); 38 | int generate_key_handle(credential_id *kh, uint8_t *pubkey, int32_t alg_type, uint8_t dc, uint8_t cp); 39 | size_t sign_with_device_key(const uint8_t *input, size_t input_len, uint8_t *sig); 40 | int sign_with_private_key(int32_t alg_type, ecc_key_t *key, const uint8_t *input, size_t len, uint8_t *sig); 41 | int verify_key_handle(const credential_id *kh, ecc_key_t *key); 42 | bool check_credential_protect_requirements(credential_id *kh, bool with_cred_list, bool uv); 43 | int get_cert(uint8_t *buf); 44 | bool has_pin(void); 45 | int set_pin(uint8_t *buf, uint8_t length); 46 | int verify_pin_hash(uint8_t *buf); 47 | int get_pin_retries(void); 48 | int set_pin_retries(uint8_t ctr); 49 | int make_hmac_secret_output(uint8_t *nonce, uint8_t *salt, uint8_t len, uint8_t *output, bool uv); 50 | int make_large_blob_key(uint8_t *nonce, uint8_t *output); 51 | 52 | #endif // CANOKEY_CORE_FIDO2_SECRET_H_ 53 | -------------------------------------------------------------------------------- /main/applets/ctap/u2f.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include "u2f.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ctap-internal.h" 13 | #include "secret.h" 14 | #include "cose-key.h" 15 | 16 | int u2f_register(const CAPDU *capdu, RAPDU *rapdu) { 17 | if (LC != 64) EXCEPT(SW_WRONG_LENGTH); 18 | 19 | if (!is_nfc()) { 20 | start_blinking(2); 21 | if (get_touch_result() == TOUCH_NO) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 22 | set_touch_result(TOUCH_NO); 23 | stop_blinking(); 24 | } 25 | 26 | U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *) DATA; 27 | U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *) RDATA; 28 | credential_id kh; 29 | uint8_t digest[SHA256_DIGEST_LENGTH]; 30 | uint8_t pubkey[PUB_KEY_SIZE]; 31 | 32 | memcpy(kh.rp_id_hash, req->appId, U2F_APPID_SIZE); 33 | int err = generate_key_handle(&kh, pubkey, COSE_ALG_ES256, 0, CRED_PROTECT_VERIFICATION_OPTIONAL); 34 | if (err < 0) return err; 35 | 36 | // there are overlaps between req and resp 37 | sha256_init(); 38 | sha256_update((uint8_t[]) {0x00}, 1); 39 | sha256_update(req->appId, U2F_APPID_SIZE); 40 | sha256_update(req->chal, U2F_CHAL_SIZE); 41 | 42 | // build response 43 | // REGISTER ID (1) 44 | resp->registerId = U2F_REGISTER_ID; 45 | // PUBLIC KEY (65) 46 | resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED; 47 | memcpy(resp->pubKey.x, pubkey, PUB_KEY_SIZE); // accessing out of bounds is intentional. 48 | // KEY HANDLE LENGTH (1) 49 | resp->keyHandleLen = sizeof(credential_id); 50 | // KEY HANDLE (128) 51 | memcpy(resp->keyHandleCertSig, &kh, sizeof(credential_id)); 52 | // CERTIFICATE (var) 53 | int cert_len = read_file(CTAP_CERT_FILE, resp->keyHandleCertSig + sizeof(credential_id), 0, U2F_MAX_ATT_CERT_SIZE); 54 | if (cert_len < 0) return cert_len; 55 | // SIG (var) 56 | sha256_update((const uint8_t *) &kh, sizeof(credential_id)); 57 | sha256_update((const uint8_t *) &resp->pubKey, U2F_EC_PUB_KEY_SIZE + 1); 58 | sha256_final(digest); 59 | size_t signature_len = sign_with_device_key(digest, PRIVATE_KEY_LENGTH[SECP256R1], 60 | resp->keyHandleCertSig + sizeof(credential_id) + cert_len); 61 | LL = 67 + sizeof(credential_id) + cert_len + signature_len; 62 | 63 | return 0; 64 | } 65 | 66 | int u2f_authenticate(const CAPDU *capdu, RAPDU *rapdu) { 67 | U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *) DATA; 68 | U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *) RDATA; 69 | CTAP_auth_data auth_data; 70 | size_t len; 71 | ecc_key_t key; // TODO: cleanup 72 | 73 | if (LC != sizeof(U2F_AUTHENTICATE_REQ)) EXCEPT(SW_WRONG_DATA); // required by FIDO Conformance Tool 74 | if (req->keyHandleLen != sizeof(credential_id)) EXCEPT(SW_WRONG_LENGTH); 75 | if (memcmp(req->appId, ((credential_id *)req->keyHandle)->rp_id_hash, U2F_APPID_SIZE) != 0) EXCEPT(SW_WRONG_DATA); 76 | uint8_t err = verify_key_handle((credential_id *)req->keyHandle, &key); 77 | if (err) EXCEPT(SW_WRONG_DATA); 78 | 79 | if (P1 == U2F_AUTH_CHECK_ONLY) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 80 | if (!is_nfc()) { 81 | start_blinking(2); 82 | if (get_touch_result() == TOUCH_NO) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 83 | set_touch_result(TOUCH_NO); 84 | stop_blinking(); 85 | } 86 | 87 | len = sizeof(auth_data); 88 | uint8_t flags = FLAGS_UP; 89 | err = ctap_make_auth_data(req->appId, (uint8_t *) &auth_data, flags, NULL, 0, &len, COSE_ALG_ES256, false, 0); 90 | if (err) EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 91 | 92 | sha256_init(); 93 | sha256_update((const uint8_t *) &auth_data, U2F_APPID_SIZE + 1 + sizeof(auth_data.sign_count)); 94 | sha256_update(req->chal, U2F_CHAL_SIZE); 95 | sha256_final(req->appId); 96 | memcpy(resp, &auth_data.flags, 1 + sizeof(auth_data.sign_count)); 97 | ecc_sign(SECP256R1, &key, req->appId, PRIVATE_KEY_LENGTH[SECP256R1], resp->sig); 98 | memzero(&key, sizeof(key)); 99 | size_t signature_len = ecdsa_sig2ansi(U2F_EC_KEY_SIZE, resp->sig, resp->sig); 100 | LL = signature_len + 5; 101 | 102 | return 0; 103 | } 104 | 105 | int u2f_version(const CAPDU *capdu, RAPDU *rapdu) { 106 | if (LC != 0) EXCEPT(SW_WRONG_LENGTH); 107 | LL = 6; 108 | memcpy(RDATA, "U2F_V2", 6); 109 | return 0; 110 | } 111 | 112 | int u2f_select(const CAPDU *capdu __attribute__((unused)), RAPDU *rapdu) { 113 | LL = 6; 114 | memcpy(RDATA, "U2F_V2", 6); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /main/applets/ctap/u2f.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef __U2F_H_INCLUDED__ 3 | #define __U2F_H_INCLUDED__ 4 | 5 | #include 6 | #include 7 | 8 | #include "ctap-internal.h" 9 | 10 | // General constants 11 | #define U2F_EC_KEY_SIZE 32 // EC key size in bytes 12 | #define U2F_EC_PUB_KEY_SIZE 64 // EC public key size in bytes 13 | #define U2F_KH_SIZE sizeof(credential_id) // Key handle size 14 | #define U2F_MAX_ATT_CERT_SIZE 1152 // Max size of attestation certificate 15 | #define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature 16 | #define U2F_CTR_SIZE 4 // Size of counter field 17 | #define U2F_APPID_SIZE 32 // Size of application id 18 | #define U2F_CHAL_SIZE 32 // Size of challenge 19 | 20 | // EC (uncompressed) point 21 | #define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format 22 | 23 | typedef struct { 24 | uint8_t pointFormat; // Point type 25 | uint8_t x[U2F_EC_KEY_SIZE]; // X-value 26 | uint8_t y[U2F_EC_KEY_SIZE]; // Y-value 27 | } U2F_EC_POINT; 28 | 29 | // U2F native commands 30 | #define U2F_REGISTER 0x01 // Registration command 31 | #define U2F_AUTHENTICATE 0x02 // Authenticate/sign command 32 | #define U2F_VERSION 0x03 // Read version string command 33 | #define U2F_SELECT 0xA4 34 | 35 | // U2F_CMD_REGISTER command defines 36 | #define U2F_REGISTER_ID 0x05 // Version 2 registration identifier 37 | 38 | typedef struct { 39 | uint8_t chal[U2F_CHAL_SIZE]; // Challenge 40 | uint8_t appId[U2F_APPID_SIZE]; // Application id 41 | } U2F_REGISTER_REQ; 42 | 43 | typedef struct { 44 | uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) 45 | U2F_EC_POINT pubKey; // Generated public key 46 | uint8_t keyHandleLen; // Length of key handle 47 | uint8_t keyHandleCertSig[U2F_KH_SIZE + // Key handle 48 | U2F_MAX_ATT_CERT_SIZE + // Attestation certificate 49 | U2F_MAX_EC_SIG_SIZE]; // Registration signature 50 | } U2F_REGISTER_RESP; 51 | 52 | // Authentication control byte 53 | #define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign 54 | #define U2F_AUTH_CHECK_ONLY 0x07 // Check only 55 | #define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set 56 | 57 | typedef struct { 58 | uint8_t chal[U2F_CHAL_SIZE]; // Challenge 59 | uint8_t appId[U2F_APPID_SIZE]; // Application id 60 | uint8_t keyHandleLen; // Length of key handle 61 | uint8_t keyHandle[U2F_KH_SIZE]; // Key handle 62 | } U2F_AUTHENTICATE_REQ; 63 | 64 | typedef struct { 65 | uint8_t flags; // U2F_AUTH_FLAG_ values 66 | uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) 67 | uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature 68 | } U2F_AUTHENTICATE_RESP; 69 | 70 | #endif // __U2F_H_INCLUDED__ -------------------------------------------------------------------------------- /main/applets/meta/meta.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | #define TAG_USB_SUPPORT 0x01 6 | #define TAG_SN 0x02 7 | #define TAG_USB_ENABLED 0x03 8 | #define TAG_FORM_FACTOR 0x04 9 | #define TAG_NFC_SUPPORT 0x0D 10 | #define TAG_NFC_ENABLED 0x0E 11 | 12 | int meta_process_apdu(const CAPDU *capdu, RAPDU *rapdu) { 13 | LL = 0; 14 | SW = SW_NO_ERROR; 15 | 16 | switch (INS) { 17 | case META_INS_SELECT: 18 | if (P1 != 0x04 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 19 | memcpy(RDATA, "5.5.5", 5); // a fake version 20 | LL = 5; 21 | break; 22 | 23 | case META_INS_READ_META: 24 | if (P1 != 0x00 || P2 != 0x00) EXCEPT(SW_WRONG_P1P2); 25 | RDATA[0] = 25; 26 | RDATA[1] = TAG_USB_SUPPORT; // FIDO2|OATH|PIV|OPENPGP|U2F 27 | RDATA[2] = 2; 28 | RDATA[3] = 0x02; 29 | RDATA[4] = 0x3A; 30 | RDATA[5] = TAG_SN; 31 | RDATA[6] = 4; 32 | fill_sn(RDATA + 7); 33 | RDATA[11] = TAG_FORM_FACTOR; 34 | RDATA[12] = 1; 35 | RDATA[13] = 0x41; 36 | RDATA[14] = TAG_USB_ENABLED; // FIDO2|OATH|PIV|OPENPGP|U2F 37 | RDATA[15] = 2; 38 | RDATA[16] = 0x02; 39 | RDATA[17] = 0x3A; 40 | RDATA[18] = TAG_NFC_SUPPORT; // FIDO2|OATH|PIV|OPENPGP|U2F 41 | RDATA[19] = 2; 42 | RDATA[20] = 0x02; 43 | RDATA[21] = 0x3A; 44 | RDATA[22] = TAG_NFC_ENABLED; // FIDO2|OATH|PIV|OPENPGP|U2F 45 | RDATA[23] = 2; 46 | RDATA[24] = 0x02; 47 | RDATA[25] = 0x3A; 48 | LL = 26; 49 | break; 50 | 51 | default: 52 | EXCEPT(SW_INS_NOT_SUPPORTED); 53 | } 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /main/applets/ndef/ndef.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | #define CC_FILE "E103" // file identifier also 0xE103 6 | #define NDEF_FILE "NDEF" 7 | #define NDEF_MSG_MAX_LENGTH 1022 8 | #define NDEF_FILE_MAX_LENGTH (NDEF_MSG_MAX_LENGTH + 2) 9 | #define CC_LENGTH 15 10 | 11 | static uint8_t current_cc[CC_LENGTH]; 12 | static const uint8_t default_cc[CC_LENGTH] = { 13 | 0x00, 0x0F, // len 14 | 0x20, // version, 2.0 15 | HI(NDEF_FILE_MAX_LENGTH), LO(NDEF_FILE_MAX_LENGTH), // mle 16 | HI(NDEF_FILE_MAX_LENGTH), LO(NDEF_FILE_MAX_LENGTH), // mlc 17 | // the following are tlv data 18 | 0x04, // t 19 | 0x06, // l 20 | 0x00, 0x01, // file id 21 | HI(NDEF_FILE_MAX_LENGTH), LO(NDEF_FILE_MAX_LENGTH), // max_size 22 | 0x00, // read access without any security 23 | 0x00 // write access without any security 24 | }; 25 | 26 | #define CC_R (current_cc[13]) 27 | #define CC_W (current_cc[14]) 28 | 29 | static enum { NONE, CC, NDEF } selected; 30 | 31 | void ndef_poweroff(void) { selected = NONE; } 32 | 33 | int ndef_get_read_only(void) { 34 | return CC_W == 0xFF ? 1 : 0; 35 | } 36 | 37 | int ndef_toggle_read_only(const CAPDU *capdu, RAPDU *rapdu) { 38 | switch (P1) { 39 | case 0x00: // read and write 40 | CC_W = 0x00; 41 | break; 42 | case 0x01: // read only 43 | CC_W = 0xFF; 44 | break; 45 | default: 46 | EXCEPT(SW_WRONG_P1P2); 47 | } 48 | if (write_file(CC_FILE, ¤t_cc, 0, sizeof(current_cc), 1) < 0) return -1; 49 | return 0; 50 | } 51 | 52 | int ndef_create_init_ndef() { 53 | const char *init_data = "\x00\x11\xD1\x01\x0D\x55\x04""canokeys.org"; 54 | if (write_file(NDEF_FILE, init_data, 0, 19, 1) < -1) return -1; 55 | if (truncate_file(NDEF_FILE, NDEF_FILE_MAX_LENGTH) < -1) return -1; // Fill the file with zeros 56 | return 0; 57 | } 58 | 59 | int ndef_install(const uint8_t reset) { 60 | ndef_poweroff(); 61 | if (reset || get_file_size(CC_FILE) != sizeof(current_cc) || get_file_size(NDEF_FILE) <= 0) { 62 | memcpy(current_cc, default_cc, sizeof(current_cc)); 63 | if (ndef_create_init_ndef() < 0) return -1; 64 | if (write_file(CC_FILE, ¤t_cc, 0, sizeof(current_cc), 1) < 0) return -1; 65 | } else { 66 | if (read_file(CC_FILE, ¤t_cc, 0, sizeof(current_cc)) < 0) return -1; 67 | // should check sanity, by standard 68 | } 69 | return 0; 70 | } 71 | 72 | int ndef_select(const CAPDU *capdu, RAPDU *rapdu) { 73 | if (P1 == 0x04 && P2 == 0x00) return 0; 74 | if (P1 != 0x00 || P2 != 0x0C) EXCEPT(SW_WRONG_P1P2); 75 | if (LC < 2) EXCEPT(SW_WRONG_LENGTH); 76 | if (DATA[0] == 0xE1 && DATA[1] == 0x03) 77 | selected = CC; 78 | else if (DATA[0] == 0x00 && DATA[1] == 0x01) 79 | selected = NDEF; 80 | else 81 | EXCEPT(SW_FILE_NOT_FOUND); 82 | return 0; 83 | } 84 | 85 | int ndef_read_binary(const CAPDU *capdu, RAPDU *rapdu) { 86 | const uint16_t offset = (uint16_t)(P1 << 8) | P2; 87 | if (offset > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 88 | if (LE > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 89 | 90 | switch (selected) { 91 | case CC: 92 | if (offset + LE > CC_LENGTH) EXCEPT(SW_WRONG_LENGTH); 93 | if (read_file(CC_FILE, RDATA, offset, LE) < 0) return -1; 94 | LL = LE; 95 | break; 96 | case NDEF: 97 | if (CC_R != 0x00) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED); 98 | if (offset + LE > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 99 | if (read_file(NDEF_FILE, RDATA, offset, LE) < 0) return -1; 100 | LL = LE; 101 | break; 102 | case NONE: 103 | EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 104 | } 105 | return 0; 106 | } 107 | 108 | int ndef_update(const CAPDU *capdu, RAPDU *rapdu) { 109 | const uint16_t offset = (uint16_t)(P1 << 8) | P2; 110 | if (offset > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 111 | if (LC > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 112 | 113 | switch (selected) { 114 | case CC: 115 | // do not allow change CC, only modified via admin 116 | EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 117 | case NDEF: 118 | if (CC_W != 0x00) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED); 119 | if (offset + LC > NDEF_FILE_MAX_LENGTH) EXCEPT(SW_WRONG_LENGTH); 120 | if (write_file(NDEF_FILE, DATA, offset, LC, 0) < 0) return -1; 121 | break; 122 | case NONE: 123 | EXCEPT(SW_CONDITIONS_NOT_SATISFIED); 124 | } 125 | return 0; 126 | } 127 | 128 | int ndef_process_apdu(const CAPDU *capdu, RAPDU *rapdu) { 129 | LL = 0; 130 | SW = SW_NO_ERROR; 131 | 132 | int ret; 133 | switch (INS) { 134 | case NDEF_INS_SELECT: 135 | ret = ndef_select(capdu, rapdu); 136 | break; 137 | case NDEF_INS_READ_BINARY: 138 | ret = ndef_read_binary(capdu, rapdu); 139 | break; 140 | case NDEF_INS_UPDATE: 141 | ret = ndef_update(capdu, rapdu); 142 | break; 143 | default: 144 | EXCEPT(SW_INS_NOT_SUPPORTED); 145 | } 146 | if (ret < 0) EXCEPT(SW_UNABLE_TO_PROCESS); 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /main/applets/openpgp/key.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include "key.h" 3 | #include 4 | 5 | #define ATTR_FINGERPRINT 0x00 6 | #define ATTR_DATETIME 0x01 7 | 8 | int openpgp_key_get_fingerprint(const char *path, void *buf) { 9 | return read_attr(path, ATTR_FINGERPRINT, buf, KEY_FINGERPRINT_LENGTH); 10 | } 11 | 12 | int openpgp_key_set_fingerprint(const char *path, const void *buf) { 13 | return write_attr(path, ATTR_FINGERPRINT, buf, KEY_FINGERPRINT_LENGTH); 14 | } 15 | 16 | int openpgp_key_get_datetime(const char *path, void *buf) { 17 | return read_attr(path, ATTR_DATETIME, buf, KEY_DATETIME_LENGTH); 18 | } 19 | 20 | int openpgp_key_set_datetime(const char *path, const void *buf) { 21 | return write_attr(path, ATTR_DATETIME, buf, KEY_DATETIME_LENGTH); 22 | } 23 | -------------------------------------------------------------------------------- /main/applets/openpgp/key.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_OPENPGP_KEY_H 3 | #define CANOKEY_CORE_OPENPGP_KEY_H 4 | 5 | #include 6 | 7 | #define KEY_FINGERPRINT_LENGTH 20 8 | #define KEY_DATETIME_LENGTH 4 9 | #define MAX_ATTR_LENGTH 13 10 | 11 | int openpgp_key_get_fingerprint(const char *path, void *buf); 12 | int openpgp_key_set_fingerprint(const char *path, const void *buf); 13 | int openpgp_key_get_datetime(const char *path, void *buf); 14 | int openpgp_key_set_datetime(const char *path, const void *buf); 15 | 16 | #endif // CANOKEY_CORE_OPENPGP_KEY_H 17 | -------------------------------------------------------------------------------- /main/cert/attestation-ca-cert.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = distinguished_name_sec 3 | attributes = attributes_sec 4 | prompt = no 5 | 6 | [attributes_sec] 7 | 8 | [distinguished_name_sec] 9 | CN = CanoKeys FIDO Attestation Root CA No.1 10 | 11 | [ca_extensions_sec] 12 | subjectKeyIdentifier = hash 13 | basicConstraints = CA:TRUE, pathlen:0 14 | keyUsage = critical, cRLSign, keyCertSign 15 | -------------------------------------------------------------------------------- /main/cert/attestation-device-cert.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = distinguished_name_sec 3 | attributes = attributes_sec 4 | req_extensions = extensions_sec 5 | prompt = no 6 | 7 | [attributes_sec] 8 | 9 | [distinguished_name_sec] 10 | CN = CanoKey Serial 123456 11 | OU = Authenticator Attestation 12 | O = CanoKeys 13 | C = CN 14 | 15 | [extensions_sec] 16 | # subjectKeyIdentifier = hash 17 | basicConstraints = CA:FALSE 18 | # AAGUID: should match the value in ctap.c (the prefix "04 10" is required for ASN.1 encoding) 19 | 1.3.6.1.4.1.45724.1.1.4 = DER:04:10:24:4e:b2:9e:e0:90:4e:49:81:fe:1f:20:f8:d3:b8:f4 20 | # fido-u2f-authenticator-transports-extension-v1.2-ps-20170411.html 21 | # 1.3.6.1.4.1.45724.2.1.1 = DER:03:02:04:30 22 | -------------------------------------------------------------------------------- /main/cert/gen_attestation_ca.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | openssl genrsa -out ca.key 2048 4 | openssl req -config ./attestation-ca-cert.cnf -extensions ca_extensions_sec -x509 -days 7120 -new -key ca.key -nodes -out ca.pem 5 | echo 01 >ca.srl # create the serial file -------------------------------------------------------------------------------- /main/cert/gen_attestation_devive_cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | openssl ecparam -out ec_key.pem -name secp256r1 -genkey -out dev.key 4 | openssl req -config ./attestation-device-cert.cnf -new -key dev.key -nodes -out dev.csr 5 | openssl x509 -extfile ./attestation-device-cert.cnf -extensions extensions_sec -days 3560 -req -in dev.csr -CA ca.pem -CAserial ca.srl -CAkey ca.key -out dev.pem 6 | openssl x509 -outform der -in dev.pem -out u2f_cert.bin 7 | rm dev.csr 8 | 9 | openssl ec -in dev.key -outform DER -no_public | tail -c +8 | head -c 32 > u2f_cert_key.bin 10 | 11 | -------------------------------------------------------------------------------- /main/cert/u2f_aaguid.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocover/esp32_u2f/1fdcde3f83fe40654e8b412966c6b2d7d1cea1ec/main/cert/u2f_aaguid.bin -------------------------------------------------------------------------------- /main/cert/u2f_cert.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocover/esp32_u2f/1fdcde3f83fe40654e8b412966c6b2d7d1cea1ec/main/cert/u2f_cert.bin -------------------------------------------------------------------------------- /main/cert/u2f_cert_key.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocover/esp32_u2f/1fdcde3f83fe40654e8b412966c6b2d7d1cea1ec/main/cert/u2f_cert_key.bin -------------------------------------------------------------------------------- /main/common.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | uint16_t tlv_get_length_safe(const uint8_t *data, const size_t len, int *fail, size_t *length_size) { 6 | uint16_t ret = 0; 7 | if (len < 1) { 8 | *fail = 1; 9 | } else if (data[0] < 0x80) { 10 | ret = data[0]; 11 | *length_size = 1; 12 | *fail = 0; 13 | } else if (data[0] == 0x81) { 14 | if (len < 2) { 15 | *fail = 1; 16 | } else { 17 | ret = data[1]; 18 | *length_size = 2; 19 | *fail = 0; 20 | } 21 | } else if (data[0] == 0x82) { 22 | if (len < 3) { 23 | *fail = 1; 24 | } else { 25 | ret = (uint16_t)(data[1] << 8u) | data[2]; 26 | *length_size = 3; 27 | *fail = 0; 28 | } 29 | } else { 30 | *fail = 1; 31 | } 32 | 33 | if (*fail == 0 && ret + *length_size > len) { 34 | // length does not overflow, 35 | // but data does 36 | *fail = 1; 37 | } 38 | 39 | return ret; 40 | } 41 | -------------------------------------------------------------------------------- /main/crypto/aes.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #ifdef USE_MBEDCRYPTO 4 | #include 5 | 6 | static int aes(const void *in, void *out, const void *key, int keybits, int mode) { 7 | mbedtls_aes_context aes; 8 | mbedtls_aes_init(&aes); 9 | int ret; 10 | if (mode == MBEDTLS_AES_ENCRYPT) 11 | ret = mbedtls_aes_setkey_enc(&aes, key, keybits); 12 | else 13 | ret = mbedtls_aes_setkey_dec(&aes, key, keybits); 14 | if (ret < 0) return -1; 15 | mbedtls_aes_crypt_ecb(&aes, mode, in, out); 16 | return 0; 17 | } 18 | #endif 19 | 20 | __attribute__((weak)) int aes128_enc(const uint8_t *in, uint8_t *out, const uint8_t *key) { 21 | #ifdef USE_MBEDCRYPTO 22 | return aes(in, out, key, 128, MBEDTLS_AES_ENCRYPT); 23 | #else 24 | (void)in; 25 | (void)out; 26 | (void)key; 27 | return 0; 28 | #endif 29 | } 30 | 31 | __attribute__((weak)) int aes128_dec(const uint8_t *in, uint8_t *out, const uint8_t *key) { 32 | #ifdef USE_MBEDCRYPTO 33 | return aes(in, out, key, 128, MBEDTLS_AES_DECRYPT); 34 | #else 35 | (void)in; 36 | (void)out; 37 | (void)key; 38 | return 0; 39 | #endif 40 | } 41 | 42 | __attribute__((weak)) int aes256_enc(const uint8_t *in, uint8_t *out, const uint8_t *key) { 43 | #ifdef USE_MBEDCRYPTO 44 | return aes(in, out, key, 256, MBEDTLS_AES_ENCRYPT); 45 | #else 46 | (void)in; 47 | (void)out; 48 | (void)key; 49 | return 0; 50 | #endif 51 | } 52 | 53 | __attribute__((weak)) int aes256_dec(const uint8_t *in, uint8_t *out, const uint8_t *key) { 54 | #ifdef USE_MBEDCRYPTO 55 | return aes(in, out, key, 256, MBEDTLS_AES_DECRYPT); 56 | #else 57 | (void)in; 58 | (void)out; 59 | (void)key; 60 | return 0; 61 | #endif 62 | } 63 | -------------------------------------------------------------------------------- /main/crypto/algo.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | 4 | const size_t PRIVATE_KEY_LENGTH[KEY_TYPE_PKC_END] = {32, 32, 48, 32, 32, 32, 128, 192, 256}; 5 | const size_t PUBLIC_KEY_LENGTH[KEY_TYPE_PKC_END] = {64, 64, 96, 64, 32, 32, 256, 384, 512}; 6 | const size_t SIGNATURE_LENGTH[KEY_TYPE_PKC_END] = {64, 64, 96, 64, 64, 64, 256, 384, 512}; 7 | -------------------------------------------------------------------------------- /main/crypto/block-cipher.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | 6 | static void xor_buf(const uint8_t *in, uint8_t *out, size_t len); 7 | static void increment_iv(uint8_t *iv, uint8_t block_size); 8 | 9 | int block_cipher_enc(block_cipher_config *cfg) { 10 | if (cfg->block_size % 8 != 0 || cfg->in_size % cfg->block_size != 0) return -1; 11 | 12 | uint8_t buf_in[cfg->block_size], iv_buf[cfg->block_size]; 13 | int blocks = cfg->in_size / cfg->block_size; 14 | 15 | if (cfg->mode != ECB) { 16 | if (cfg->iv == NULL) return -1; 17 | memcpy(iv_buf, cfg->iv, cfg->block_size); 18 | } 19 | 20 | int ret = 0; 21 | for (int idx = 0; idx < blocks; idx++) { 22 | switch (cfg->mode) { 23 | case ECB: 24 | ret = cfg->encrypt(cfg->in + idx * cfg->block_size, cfg->out + idx * cfg->block_size, cfg->key); 25 | break; 26 | case CBC: 27 | memcpy(buf_in, cfg->in + idx * cfg->block_size, cfg->block_size); 28 | xor_buf(iv_buf, buf_in, cfg->block_size); 29 | ret = cfg->encrypt(buf_in, cfg->out + idx * cfg->block_size, cfg->key); 30 | if (ret < 0) break; 31 | ret = cfg->encrypt(buf_in, iv_buf, cfg->key); 32 | memcpy(cfg->out + idx * cfg->block_size, iv_buf, cfg->block_size); 33 | break; 34 | case CFB: 35 | ret = cfg->encrypt(iv_buf, iv_buf, cfg->key); 36 | xor_buf(cfg->in + idx * cfg->block_size, iv_buf, cfg->block_size); 37 | memcpy(cfg->out + idx * cfg->block_size, iv_buf, cfg->block_size); 38 | break; 39 | case OFB: 40 | ret = cfg->encrypt(iv_buf, iv_buf, cfg->key); 41 | memcpy(buf_in, cfg->in + idx * cfg->block_size, cfg->block_size); 42 | xor_buf(iv_buf, buf_in, cfg->block_size); 43 | memcpy(cfg->out + idx * cfg->block_size, buf_in, cfg->block_size); 44 | break; 45 | case CTR: 46 | ret = cfg->encrypt(iv_buf, buf_in, cfg->key); 47 | xor_buf(cfg->in + idx * cfg->block_size, buf_in, cfg->block_size); 48 | memcpy(cfg->out + idx * cfg->block_size, buf_in, cfg->block_size); 49 | increment_iv(iv_buf, cfg->block_size); 50 | break; 51 | default: 52 | ret = -1; 53 | break; 54 | } 55 | if (ret < 0) break; 56 | } 57 | 58 | memzero(buf_in, sizeof(buf_in)); 59 | memzero(iv_buf, sizeof(iv_buf)); 60 | return ret; 61 | } 62 | 63 | int block_cipher_dec(block_cipher_config *cfg) { 64 | if (cfg->block_size % 8 != 0 || cfg->in_size % cfg->block_size != 0) return -1; 65 | 66 | uint8_t buf_in[cfg->block_size], iv_buf[cfg->block_size]; 67 | int blocks = cfg->in_size / cfg->block_size; 68 | 69 | if (cfg->mode != ECB) { 70 | if (cfg->iv == NULL) return -1; 71 | memcpy(iv_buf, cfg->iv, cfg->block_size); 72 | } 73 | 74 | int ret = 0; 75 | for (int idx = 0; idx < blocks; idx++) { 76 | switch (cfg->mode) { 77 | case ECB: 78 | ret = cfg->decrypt(cfg->in + idx * cfg->block_size, cfg->out + idx * cfg->block_size, cfg->key); 79 | break; 80 | case CBC: 81 | memcpy(buf_in, cfg->in + idx * cfg->block_size, cfg->block_size); 82 | ret = cfg->decrypt(buf_in, cfg->out + idx * cfg->block_size, cfg->key); 83 | xor_buf(iv_buf, cfg->out + idx * cfg->block_size, cfg->block_size); 84 | memcpy(iv_buf, buf_in, cfg->block_size); 85 | break; 86 | case CFB: 87 | ret = cfg->encrypt(iv_buf, iv_buf, cfg->key); 88 | memcpy(buf_in, cfg->in + idx * cfg->block_size, cfg->block_size); 89 | xor_buf(cfg->in + idx * cfg->block_size, iv_buf, cfg->block_size); 90 | memcpy(cfg->out + idx * cfg->block_size, iv_buf, cfg->block_size); 91 | memcpy(iv_buf, buf_in, cfg->block_size); 92 | break; 93 | case OFB: 94 | ret = cfg->encrypt(iv_buf, iv_buf, cfg->key); 95 | memcpy(buf_in, cfg->in + idx * cfg->block_size, cfg->block_size); 96 | xor_buf(iv_buf, buf_in, cfg->block_size); 97 | memcpy(cfg->out + idx * cfg->block_size, buf_in, cfg->block_size); 98 | break; 99 | case CTR: 100 | ret = cfg->encrypt(iv_buf, buf_in, cfg->key); 101 | xor_buf(cfg->in + idx * cfg->block_size, buf_in, cfg->block_size); 102 | memcpy(cfg->out + idx * cfg->block_size, buf_in, cfg->block_size); 103 | increment_iv(iv_buf, cfg->block_size); 104 | break; 105 | default: 106 | ret = -1; 107 | break; 108 | } 109 | if (ret < 0) break; 110 | } 111 | 112 | memzero(buf_in, sizeof(buf_in)); 113 | memzero(iv_buf, sizeof(iv_buf)); 114 | return ret; 115 | } 116 | 117 | static void xor_buf(const uint8_t *in, uint8_t *out, size_t len) { 118 | size_t idx; 119 | 120 | for (idx = 0; idx < len; idx++) 121 | out[idx] ^= in[idx]; 122 | } 123 | 124 | static void increment_iv(uint8_t *iv, uint8_t block_size) { 125 | for (int idx = block_size - 1; idx >= 0; idx--) { 126 | iv[idx]++; 127 | if (iv[idx] != 0) break; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /main/crypto/crypto-util.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | __attribute__((weak)) void raise_exception(void) {} 6 | 7 | void print_hex(const uint8_t *buf, size_t len) { 8 | for (size_t i = 0; i < len; ++i) 9 | printf("%02X", buf[i]); 10 | printf("\n"); 11 | } 12 | 13 | int memcmp(const void *p, const void *q, size_t len) { 14 | volatile size_t equal = 0, notequal = 0; 15 | for (size_t i = 0; i != len; ++i) 16 | if (((uint8_t*)p)[i] == ((uint8_t*)q)[i]) 17 | ++equal; 18 | else 19 | ++notequal; 20 | if (equal + notequal != len) raise_exception(); 21 | if (equal == len) 22 | return 0; 23 | else 24 | return -1; 25 | } 26 | 27 | void random_delay(void) { 28 | uint16_t delay = random32() & 0xFFFF; 29 | for (volatile uint16_t i = 0; i != delay; ++i) 30 | __asm volatile("nop"); 31 | } 32 | -------------------------------------------------------------------------------- /main/crypto/hmac.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | void hmac_sha1_Init(HMAC_SHA1_CTX *hctx, const uint8_t *key, const size_t keylen) { 29 | uint8_t i_key_pad[SHA1_BLOCK_LENGTH]; 30 | memzero(i_key_pad, SHA1_BLOCK_LENGTH); 31 | if (keylen > SHA1_BLOCK_LENGTH) { 32 | sha1_raw(key, keylen, i_key_pad); 33 | } else { 34 | memcpy(i_key_pad, key, keylen); 35 | } 36 | for (int i = 0; i < SHA1_BLOCK_LENGTH; i++) { 37 | hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; 38 | i_key_pad[i] ^= 0x36; 39 | } 40 | sha1_init(); 41 | sha1_update(i_key_pad, SHA1_BLOCK_LENGTH); 42 | memzero(i_key_pad, sizeof(i_key_pad)); 43 | } 44 | 45 | void hmac_sha1_Update(const HMAC_SHA1_CTX *hctx, const uint8_t *msg, const size_t msglen) { 46 | (void) hctx; 47 | sha1_update(msg, msglen); 48 | } 49 | 50 | void hmac_sha1_Final(HMAC_SHA1_CTX *hctx, uint8_t *hmac) { 51 | sha1_final(hmac); 52 | sha1_init(); 53 | sha1_update(hctx->o_key_pad, SHA1_BLOCK_LENGTH); 54 | sha1_update(hmac, SHA1_DIGEST_LENGTH); 55 | sha1_final(hmac); 56 | memzero(hctx, sizeof(HMAC_SHA1_CTX)); 57 | } 58 | 59 | void hmac_sha1(const uint8_t *key, const size_t keylen, const uint8_t *msg, const size_t msglen, uint8_t *hmac) { 60 | HMAC_SHA1_CTX hctx; 61 | hmac_sha1_Init(&hctx, key, keylen); 62 | hmac_sha1_Update(&hctx, msg, msglen); 63 | hmac_sha1_Final(&hctx, hmac); 64 | } 65 | 66 | void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const size_t keylen) { 67 | uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; 68 | memzero(i_key_pad, SHA256_BLOCK_LENGTH); 69 | if (keylen > SHA256_BLOCK_LENGTH) { 70 | sha256_raw(key, keylen, i_key_pad); 71 | } else { 72 | memcpy(i_key_pad, key, keylen); 73 | } 74 | for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { 75 | hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; 76 | i_key_pad[i] ^= 0x36; 77 | } 78 | sha256_init(); 79 | sha256_update(i_key_pad, SHA256_BLOCK_LENGTH); 80 | memzero(i_key_pad, sizeof(i_key_pad)); 81 | } 82 | 83 | void hmac_sha256_Update(const HMAC_SHA256_CTX *hctx, const uint8_t *msg, const size_t msglen) { 84 | (void) hctx; 85 | sha256_update(msg, msglen); 86 | } 87 | 88 | void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { 89 | sha256_final(hmac); 90 | sha256_init(); 91 | sha256_update(hctx->o_key_pad, SHA256_BLOCK_LENGTH); 92 | sha256_update(hmac, SHA256_DIGEST_LENGTH); 93 | sha256_final(hmac); 94 | memzero(hctx, sizeof(HMAC_SHA256_CTX)); 95 | } 96 | 97 | void hmac_sha256(const uint8_t *key, const size_t keylen, const uint8_t *msg, const size_t msglen, uint8_t *hmac) { 98 | HMAC_SHA256_CTX hctx; 99 | hmac_sha256_Init(&hctx, key, keylen); 100 | hmac_sha256_Update(&hctx, msg, msglen); 101 | hmac_sha256_Final(&hctx, hmac); 102 | } 103 | 104 | void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const size_t keylen) { 105 | uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; 106 | memzero(i_key_pad, SHA512_BLOCK_LENGTH); 107 | if (keylen > SHA512_BLOCK_LENGTH) { 108 | sha512_raw(key, keylen, i_key_pad); 109 | } else { 110 | memcpy(i_key_pad, key, keylen); 111 | } 112 | for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { 113 | hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; 114 | i_key_pad[i] ^= 0x36; 115 | } 116 | sha512_init(); 117 | sha512_update(i_key_pad, SHA512_BLOCK_LENGTH); 118 | memzero(i_key_pad, sizeof(i_key_pad)); 119 | } 120 | 121 | void hmac_sha512_Update(const HMAC_SHA512_CTX *hctx, const uint8_t *msg, const size_t msglen) { 122 | (void) hctx; 123 | sha512_update(msg, msglen); 124 | } 125 | 126 | void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { 127 | sha512_final(hmac); 128 | sha512_init(); 129 | sha512_update(hctx->o_key_pad, SHA512_BLOCK_LENGTH); 130 | sha512_update(hmac, SHA512_DIGEST_LENGTH); 131 | sha512_final(hmac); 132 | memzero(hctx, sizeof(HMAC_SHA512_CTX)); 133 | } 134 | 135 | void hmac_sha512(const uint8_t *key, const size_t keylen, const uint8_t *msg, const size_t msglen, uint8_t *hmac) { 136 | HMAC_SHA512_CTX hctx; 137 | hmac_sha512_Init(&hctx, key, keylen); 138 | hmac_sha512_Update(&hctx, msg, msglen); 139 | hmac_sha512_Final(&hctx, hmac); 140 | } 141 | -------------------------------------------------------------------------------- /main/crypto/include/aes.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_AES_H 3 | #define CANOKEY_CRYPTO_AES_H 4 | 5 | #include 6 | 7 | /** 8 | * The AES functions all encrypt only one block. 9 | * To invoke them, you should use the functions provided in block-cipher.h 10 | */ 11 | 12 | int aes128_enc(const uint8_t *in, uint8_t *out, const uint8_t *key); 13 | int aes128_dec(const uint8_t *in, uint8_t *out, const uint8_t *key); 14 | int aes256_enc(const uint8_t *in, uint8_t *out, const uint8_t *key); 15 | int aes256_dec(const uint8_t *in, uint8_t *out, const uint8_t *key); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /main/crypto/include/algo.h: -------------------------------------------------------------------------------- 1 | #ifndef CANOKEY_CRYPTO_ALGO_H 2 | #define CANOKEY_CRYPTO_ALGO_H 3 | 4 | #include 5 | 6 | typedef enum { 7 | SECP256R1, 8 | SECP256K1, 9 | SECP384R1, 10 | SM2, 11 | ED25519, 12 | X25519, 13 | RSA2048, 14 | RSA3072, 15 | RSA4096, 16 | KEY_TYPE_PKC_END, 17 | TDEA, 18 | AES128, 19 | AES256, 20 | } key_type_t; 21 | 22 | extern const size_t PRIVATE_KEY_LENGTH[KEY_TYPE_PKC_END]; 23 | extern const size_t PUBLIC_KEY_LENGTH[KEY_TYPE_PKC_END]; 24 | extern const size_t SIGNATURE_LENGTH[KEY_TYPE_PKC_END]; 25 | 26 | #define IS_ECC(type) ((type) == SECP256R1 || (type) == SECP256K1 || (type) == SECP384R1 || (type) == SM2 || (type) == ED25519 || (type) == X25519) 27 | #define IS_SHORT_WEIERSTRASS(type) ((type) == SECP256R1 || (type) == SECP256K1 || (type) == SECP384R1 || (type) == SM2) 28 | #define IS_RSA(type) ((type) == RSA2048 || (type) == RSA3072 || (type) == RSA4096) 29 | 30 | #endif // CANOKEY_CRYPTO_ALGO_H 31 | -------------------------------------------------------------------------------- /main/crypto/include/block-cipher.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_BLOCK_CIPHER_H 3 | #define CANOKEY_CRYPTO_BLOCK_CIPHER_H 4 | 5 | #include 6 | #include 7 | 8 | enum BLOCK_CIPHER_MODE { ECB, CBC, CFB, OFB, CTR }; 9 | 10 | typedef struct { 11 | enum BLOCK_CIPHER_MODE mode; 12 | const uint8_t *in; 13 | size_t in_size; 14 | uint8_t *out; 15 | const uint8_t *iv; 16 | const uint8_t *key; 17 | uint8_t block_size; 18 | int (*encrypt)(const uint8_t *in, uint8_t *out, const uint8_t *key); 19 | int (*decrypt)(const uint8_t *in, uint8_t *out, const uint8_t *key); 20 | } block_cipher_config; 21 | 22 | int block_cipher_enc(block_cipher_config *cfg); 23 | int block_cipher_dec(block_cipher_config *cfg); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /main/crypto/include/crypto-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef _UTILS_H 3 | #define _UTILS_H 4 | 5 | #include 6 | #include 7 | 8 | void raise_exception(void); 9 | void print_hex(const uint8_t *buf, size_t len); 10 | int memcmp(const void *p, const void *q, size_t len); 11 | void random_delay(void); 12 | 13 | #endif //_UTILS_H 14 | -------------------------------------------------------------------------------- /main/crypto/include/des.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_DES_H_ 3 | #define CANOKEY_CRYPTO_DES_H_ 4 | 5 | #include 6 | 7 | /** 8 | * The DES functions all encrypt only one block. 9 | * To invoke them, you should use the functions provided in block-cipher.h 10 | */ 11 | 12 | int des_enc(const uint8_t *in, uint8_t *out, const uint8_t *key); 13 | int des_dec(const uint8_t *in, uint8_t *out, const uint8_t *key); 14 | int tdes_enc(const uint8_t *in, uint8_t *out, const uint8_t *key); 15 | int tdes_dec(const uint8_t *in, uint8_t *out, const uint8_t *key); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /main/crypto/include/ecc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_ECC_H 3 | #define CANOKEY_CRYPTO_ECC_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX_EC_PRIVATE_KEY 68 10 | #define MAX_EC_PUBLIC_KEY 132 11 | 12 | typedef struct { 13 | uint8_t pri[MAX_EC_PRIVATE_KEY]; 14 | uint8_t pub[MAX_EC_PUBLIC_KEY]; 15 | } ecc_key_t; 16 | 17 | extern const uint8_t SM2_ID_DEFAULT[]; 18 | 19 | void swap_big_number_endian(uint8_t buf[32]); 20 | 21 | /** 22 | * Generate an ECDSA key pair 23 | * 24 | * @param type ECC algorithm 25 | * @param key Pointer to the generated key 26 | * 27 | * @return 0: Success, -1: Error 28 | */ 29 | int ecc_generate(key_type_t type, ecc_key_t *key); 30 | 31 | /** 32 | * Verify the given private key. 33 | * 34 | * @param type ECC algorithm 35 | * @param key Pointer to the key 36 | * 37 | * @return 1: verified, 0: not verified 38 | */ 39 | int ecc_verify_private_key(key_type_t type, ecc_key_t *key); 40 | 41 | /** 42 | * Compute the corresponding public key using the private key 43 | * 44 | * @param type ECC algorithm 45 | * @param key Pointer to the key 46 | * 47 | * @return 0: Success, -1: Error 48 | */ 49 | int ecc_complete_key(key_type_t type, ecc_key_t *key); 50 | 51 | /** 52 | * Sign the given data or digest 53 | * 54 | * @param type ECC algorithm 55 | * @param key Pointer to the key 56 | * @param data_or_digest The data (for ED25519) or the digest (for other algorithms) 57 | * @param sig The output buffer 58 | * 59 | * @return 0: Success, -1: Error 60 | */ 61 | int ecc_sign(key_type_t type, const ecc_key_t *key, const uint8_t *data_or_digest, size_t len, uint8_t *sig); 62 | 63 | /** 64 | * Convert r,s signature to ANSI X9.62 format 65 | * 66 | * @param key_len Length of the key 67 | * @param input The original signature 68 | * @param output ANSI X9.62 format. The buffer should be at least 2 * key_size + 6 bytes. The buffer can be identical 69 | * to the input. 70 | * 71 | * @return Length of signature 72 | */ 73 | size_t ecdsa_sig2ansi(uint8_t key_len, const uint8_t *input, uint8_t *output); 74 | 75 | /** 76 | * Compute Z specified by SM2 77 | * 78 | * @param id User's ID. The first byte contains the length and followed by the ID. 79 | * @param key Pointer to the key 80 | * @param z The output buffer 81 | * 82 | * @return 0: Success, -1: Error 83 | */ 84 | int sm2_z(const uint8_t *id, const ecc_key_t *key, uint8_t *z); 85 | 86 | /** 87 | * Compute ECDH result 88 | * 89 | * @param type ECC algorithm 90 | * @param priv_key The private key s 91 | * @param receiver_pub_key The receiver's public key P 92 | * @param out s*P 93 | * 94 | * @return 0: Success, -1: Error 95 | */ 96 | int ecdh(key_type_t type, const uint8_t *priv_key, const uint8_t *receiver_pub_key, uint8_t *out); 97 | 98 | // Below types and functions should not be used in canokey-core 99 | 100 | /** 101 | * Generate an ECDSA key pair 102 | * 103 | * @param type ECC algorithm 104 | * @param key Pointer to the generated key 105 | * 106 | * @return 0: Success, -1: Error 107 | */ 108 | int K__short_weierstrass_generate(key_type_t type, ecc_key_t *key); 109 | 110 | /** 111 | * Verify the given private key. 112 | * 113 | * @param type ECC algorithm 114 | * @param key Pointer to the key 115 | * 116 | * @return 1: verified, 0: not verified 117 | */ 118 | int K__short_weierstrass_verify_private_key(const key_type_t type, const ecc_key_t *key); 119 | 120 | /** 121 | * Compute the corresponding public key using the private key 122 | * 123 | * @param type ECC algorithm 124 | * @param key Pointer to the key 125 | * 126 | * @return 0: Success, -1: Error 127 | */ 128 | int K__short_weierstrass_complete_key(key_type_t type, ecc_key_t *key); 129 | 130 | /** 131 | * Sign the given data or digest 132 | * 133 | * @param type ECC algorithm 134 | * @param key Pointer to the key 135 | * @param data_or_digest The data (for ED25519) or the digest (for other algorithms) 136 | * @param sig The output buffer 137 | * 138 | * @return 0: Success, -1: Error 139 | */ 140 | int K__short_weierstrass_sign(key_type_t type, const ecc_key_t *key, const uint8_t *data_or_digest, size_t len, uint8_t *sig); 141 | 142 | /** 143 | * Compute ECDH result 144 | * 145 | * @param type ECC algorithm 146 | * @param priv_key The private key s 147 | * @param receiver_pub_key The receiver's public key P 148 | * @param out s*P 149 | * 150 | * @return 0: Success, -1: Error 151 | */ 152 | int K__short_weierstrass_ecdh(key_type_t type, const uint8_t *priv_key, const uint8_t *receiver_pub_key, uint8_t *out); 153 | 154 | typedef unsigned char K__ed25519_signature[64]; 155 | typedef unsigned char K__ed25519_public_key[32]; 156 | typedef unsigned char K__ed25519_secret_key[32]; 157 | typedef unsigned char K__x25519_key[32]; 158 | 159 | /** 160 | * Calculate public key from private key 161 | * 162 | * @param sk Input private key 163 | * @param pk Output public key 164 | */ 165 | void K__ed25519_publickey(const K__ed25519_secret_key sk, K__ed25519_public_key pk); 166 | 167 | /** 168 | * Calculate Ed25519 signature of data 169 | * 170 | * @param m Input data 171 | * @param mlen Length of data 172 | * @param sk Private key 173 | * @param pk Public key 174 | * @param rs Output signature 175 | */ 176 | void K__ed25519_sign(const unsigned char *m, size_t mlen, const K__ed25519_secret_key sk, 177 | const K__ed25519_public_key pk, K__ed25519_signature rs); 178 | 179 | /** 180 | * Calculate shared_secret = private_key * public_key, the second step of X25519 181 | * 182 | * Note: X25519 spec uses little endian, but we use big endian here 183 | * 184 | * @param shared_secret Shared secret in big endian 185 | * @param private_key Valid private key in big endian 186 | * @param public_key Public key in big endian 187 | */ 188 | void K__x25519(K__x25519_key shared_secret, const K__x25519_key private_key, const K__x25519_key public_key); 189 | 190 | #endif 191 | -------------------------------------------------------------------------------- /main/crypto/include/esp32_ed25519.h: -------------------------------------------------------------------------------- 1 | #ifndef ESP32_ED25519_H_ 2 | #define ESP32_ED25519_H_ 3 | 4 | #include 5 | 6 | 7 | //Length of EdDSA private keys 8 | #define ED25519_PRIVATE_KEY_LEN 32 9 | //Length of EdDSA public keys 10 | #define ED25519_PUBLIC_KEY_LEN 32 11 | //Length of EdDSA signatures 12 | #define ED25519_SIGNATURE_LEN 64 13 | 14 | //Ed25519ph flag 15 | #define ED25519_PH_FLAG 1 16 | //Prehash function output size 17 | #define ED25519_PH_SIZE 64 18 | 19 | typedef struct 20 | { 21 | uint32_t x[8]; 22 | uint32_t y[8]; 23 | uint32_t z[8]; 24 | uint32_t t[8]; 25 | } Ed25519Point; 26 | 27 | typedef struct 28 | { 29 | uint8_t k[64]; 30 | uint8_t p[32]; 31 | uint8_t r[32]; 32 | uint8_t s[32]; 33 | Ed25519Point ka; 34 | Ed25519Point rb; 35 | Ed25519Point sb; 36 | Ed25519Point u; 37 | Ed25519Point v; 38 | uint32_t a[8]; 39 | uint32_t b[8]; 40 | uint32_t c[8]; 41 | uint32_t d[8]; 42 | uint32_t e[8]; 43 | uint32_t f[8]; 44 | uint32_t g[8]; 45 | uint32_t h[8]; 46 | } Ed25519State; 47 | 48 | int ed25519GeneratePublicKey(const uint8_t *privateKey, uint8_t *publicKey); 49 | 50 | int ed25519GenerateSignature(const uint8_t *privateKey, 51 | const uint8_t *publicKey, const void *message, size_t messageLen, 52 | const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature); 53 | 54 | #endif -------------------------------------------------------------------------------- /main/crypto/include/hmac.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __HMAC_H__ 25 | #define __HMAC_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #define SHA1_BLOCK_LENGTH 64 32 | #define SHA1_DIGEST_LENGTH 20 33 | #define SHA256_BLOCK_LENGTH 64 34 | #define SHA256_DIGEST_LENGTH 32 35 | #define SHA512_BLOCK_LENGTH 128 36 | #define SHA512_DIGEST_LENGTH 64 37 | 38 | typedef struct _HMAC_SHA1_CTX { 39 | uint8_t o_key_pad[SHA1_BLOCK_LENGTH]; 40 | } HMAC_SHA1_CTX; 41 | 42 | typedef struct _HMAC_SHA256_CTX { 43 | uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; 44 | } HMAC_SHA256_CTX; 45 | 46 | typedef struct _HMAC_SHA512_CTX { 47 | uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; 48 | } HMAC_SHA512_CTX; 49 | 50 | void hmac_sha1_Init(HMAC_SHA1_CTX *hctx, const uint8_t *key, size_t keylen); 51 | void hmac_sha1_Update(const HMAC_SHA1_CTX *hctx, const uint8_t *msg, size_t msglen); 52 | void hmac_sha1_Final(HMAC_SHA1_CTX *hctx, uint8_t *hmac); 53 | void hmac_sha1(const uint8_t *key, size_t keylen, const uint8_t *msg, size_t msglen, uint8_t *hmac); 54 | 55 | void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, size_t keylen); 56 | void hmac_sha256_Update(const HMAC_SHA256_CTX *hctx, const uint8_t *msg, size_t msglen); 57 | void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); 58 | void hmac_sha256(const uint8_t *key, size_t keylen, const uint8_t *msg, size_t msglen, uint8_t *hmac); 59 | 60 | void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, size_t keylen); 61 | void hmac_sha512_Update(const HMAC_SHA512_CTX *hctx, const uint8_t *msg, size_t msglen); 62 | void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); 63 | void hmac_sha512(const uint8_t *key, size_t keylen, const uint8_t *msg, size_t msglen, uint8_t *hmac); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /main/crypto/include/memzero.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef __MEMZERO_H__ 3 | #define __MEMZERO_H__ 4 | 5 | #include 6 | 7 | void memzero(void *pnt, size_t len); 8 | 9 | #endif -------------------------------------------------------------------------------- /main/crypto/include/rand.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __RAND_H__ 25 | #define __RAND_H__ 26 | 27 | #include 28 | #include 29 | 30 | /** 31 | * Get random 32-bit number 32 | * 33 | * @return random number 34 | */ 35 | uint32_t random32(void); 36 | 37 | /** 38 | * Randomize the content of buffer 39 | * 40 | * @param buf Buffer 41 | * @param len Length of buffer 42 | */ 43 | void random_buffer(uint8_t *buf, size_t len); 44 | 45 | /** 46 | * Get a random number from uniform distribution of [0, n) 47 | * 48 | * @param n Random range 49 | * @return random number 50 | */ 51 | uint32_t random_uniform(uint32_t n); 52 | 53 | /** 54 | * Shuffle bytes randomly 55 | * 56 | * @param str Data 57 | * @param len Length of data 58 | */ 59 | void random_permute(char *buf, size_t len); 60 | 61 | int mbedtls_rnd(void *ctx, unsigned char *buf, size_t n); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /main/crypto/include/rsa.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_RSA_H_ 3 | #define CANOKEY_CRYPTO_RSA_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define RSA_N_BIT_MAX 4096 10 | #define E_LENGTH 4 11 | #define PQ_LENGTH_MAX (RSA_N_BIT_MAX / 16) 12 | 13 | typedef struct { 14 | uint16_t nbits; 15 | alignas(4) uint8_t e[E_LENGTH]; 16 | alignas(4) uint8_t p[PQ_LENGTH_MAX]; 17 | alignas(4) uint8_t q[PQ_LENGTH_MAX]; 18 | alignas(4) uint8_t dp[PQ_LENGTH_MAX]; 19 | alignas(4) uint8_t dq[PQ_LENGTH_MAX]; 20 | alignas(4) uint8_t qinv[PQ_LENGTH_MAX]; 21 | } rsa_key_t; 22 | 23 | /** 24 | * Generate a new RSA key. We always set e = 65537. 25 | * 26 | * @param key The generated key. 27 | * @param nbits The size of the public key in bits. 28 | * 29 | * @return 0 on success. 30 | */ 31 | int rsa_generate_key(rsa_key_t *key, uint16_t nbits); 32 | 33 | /** 34 | * Compute the public key given a RSA private key. 35 | * 36 | * @param key The given private key. 37 | * @param n The corresponding public key. 38 | * 39 | * @return 0 on success. 40 | */ 41 | int rsa_get_public_key(rsa_key_t *key, uint8_t *n); 42 | 43 | /** 44 | * Compute private key operation, used in sign or decrypt. 45 | * 46 | * @param key The given private key. 47 | * @param input Input data. 48 | * @param output Output data. 49 | * 50 | * @return 0 on success. 51 | */ 52 | int rsa_private(const rsa_key_t *key, const uint8_t *input, uint8_t *output); 53 | 54 | int rsa_sign_pkcs_v15(const rsa_key_t *key, const uint8_t *data, size_t len, uint8_t *sig); 55 | 56 | int rsa_decrypt_pkcs_v15(const rsa_key_t *key, const uint8_t *in, size_t *olen, uint8_t *out, uint8_t *invalid_padding); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /main/crypto/include/sha.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_SHA_H_ 3 | #define CANOKEY_CRYPTO_SHA_H_ 4 | 5 | #include 6 | #include 7 | 8 | #define SHA1_BLOCK_LENGTH 64 9 | #define SHA1_DIGEST_LENGTH 20 10 | #define SHA256_BLOCK_LENGTH 64 11 | #define SHA256_DIGEST_LENGTH 32 12 | #define SHA512_BLOCK_LENGTH 128 13 | #define SHA512_DIGEST_LENGTH 64 14 | 15 | void sha1_init(void); 16 | void sha1_update(const uint8_t *data, uint16_t len); 17 | void sha1_final(uint8_t digest[SHA1_DIGEST_LENGTH]); 18 | void sha1_raw(const uint8_t *data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]); 19 | void sha256_init(void); 20 | void sha256_update(const uint8_t *data, uint16_t len); 21 | void sha256_final(uint8_t digest[SHA256_DIGEST_LENGTH]); 22 | void sha256_raw(const uint8_t *data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]); 23 | void sha512_init(void); 24 | void sha512_update(const uint8_t *data, uint16_t len); 25 | void sha512_final(uint8_t digest[SHA512_DIGEST_LENGTH]); 26 | void sha512_raw(const uint8_t *data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]); 27 | 28 | #include "sha3.h" 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /main/crypto/include/sha3.h: -------------------------------------------------------------------------------- 1 | /* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). 2 | * based on the 3 | * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 4 | * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche 5 | * 6 | * Copyright: 2013 Aleksey Kravchenko 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a 9 | * copy of this software and associated documentation files (the "Software"), 10 | * to deal in the Software without restriction, including without limitation 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | * and/or sell copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! 18 | */ 19 | 20 | #ifndef __SHA3_H__ 21 | #define __SHA3_H__ 22 | 23 | #include 24 | #include 25 | 26 | // GCC Predefined Macros 27 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 28 | #define BYTE_ORDER BIG_ENDIAN 29 | #endif 30 | 31 | #define sha3_224_hash_size 28 32 | #define sha3_256_hash_size 32 33 | #define sha3_384_hash_size 48 34 | #define sha3_512_hash_size 64 35 | #define sha3_max_permutation_size 25 36 | #define sha3_max_rate_in_qwords 24 37 | 38 | #define SHA3_224_BLOCK_LENGTH 144 39 | #define SHA3_256_BLOCK_LENGTH 136 40 | #define SHA3_384_BLOCK_LENGTH 104 41 | #define SHA3_512_BLOCK_LENGTH 72 42 | 43 | #define SHA3_224_DIGEST_LENGTH sha3_224_hash_size 44 | #define SHA3_256_DIGEST_LENGTH sha3_256_hash_size 45 | #define SHA3_384_DIGEST_LENGTH sha3_384_hash_size 46 | #define SHA3_512_DIGEST_LENGTH sha3_512_hash_size 47 | 48 | /** 49 | * SHA3 Algorithm context. 50 | */ 51 | typedef struct SHA3_CTX { 52 | /* 1600 bits algorithm hashing state */ 53 | uint64_t hash[sha3_max_permutation_size]; 54 | /* 1536-bit buffer for leftovers */ 55 | uint64_t message[sha3_max_rate_in_qwords]; 56 | /* count of bytes in the message[] buffer */ 57 | unsigned rest; 58 | /* size of a message block processed at once */ 59 | unsigned block_size; 60 | } SHA3_CTX; 61 | 62 | /* methods for calculating the hash function */ 63 | 64 | void sha3_224_Init(SHA3_CTX *ctx); 65 | void sha3_256_Init(SHA3_CTX *ctx); 66 | void sha3_384_Init(SHA3_CTX *ctx); 67 | void sha3_512_Init(SHA3_CTX *ctx); 68 | void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size); 69 | void sha3_Final(SHA3_CTX *ctx, unsigned char *result); 70 | 71 | #define keccak_224_Init sha3_224_Init 72 | #define keccak_256_Init sha3_256_Init 73 | #define keccak_384_Init sha3_384_Init 74 | #define keccak_512_Init sha3_512_Init 75 | #define keccak_Update sha3_Update 76 | void keccak_Final(SHA3_CTX *ctx, unsigned char *result); 77 | void keccak_256(const unsigned char *data, size_t len, unsigned char *digest); 78 | void keccak_512(const unsigned char *data, size_t len, unsigned char *digest); 79 | 80 | void sha3_256(const unsigned char *data, size_t len, unsigned char *digest); 81 | void sha3_512(const unsigned char *data, size_t len, unsigned char *digest); 82 | 83 | #endif /* __SHA3_H__ */ 84 | -------------------------------------------------------------------------------- /main/crypto/include/sm3.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CRYPTO_SM3_H_ 3 | #define CANOKEY_CRYPTO_SM3_H_ 4 | 5 | #include 6 | #include 7 | 8 | #define SM3_BLOCK_LENGTH 64 9 | #define SM3_DIGEST_LENGTH 32 10 | 11 | void sm3_init(void); 12 | void sm3_update(const uint8_t *data, uint16_t len); 13 | void sm3_final(uint8_t digest[SM3_DIGEST_LENGTH]); 14 | void sm3_raw(const uint8_t *data, size_t len, uint8_t digest[SM3_DIGEST_LENGTH]); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /main/crypto/memzero.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | #include 4 | 5 | void memzero(void *pnt, size_t len) { 6 | 7 | memset(pnt, 0, len); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /main/crypto/rand.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include "esp_random.h" 26 | 27 | 28 | __attribute__((weak)) uint32_t random32(void) { 29 | return esp_random(); 30 | } 31 | 32 | __attribute__((weak)) void random_buffer(uint8_t *buf, size_t len) { 33 | esp_fill_random(buf, len); 34 | } 35 | 36 | uint32_t random_uniform(uint32_t n) { 37 | uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); 38 | while ((x = random32()) >= max) 39 | ; 40 | return x / (max / n); 41 | } 42 | 43 | void random_permute(char *str, size_t len) { 44 | for (int i = len - 1; i >= 1; i--) { 45 | int j = random_uniform(i + 1); 46 | char t = str[j]; 47 | str[j] = str[i]; 48 | str[i] = t; 49 | } 50 | } 51 | 52 | int mbedtls_rnd(void *ctx, unsigned char *buf, size_t n) { 53 | (void)ctx; 54 | esp_fill_random(buf, n); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /main/crypto/rsa.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef USE_MBEDCRYPTO 7 | #include 8 | #endif 9 | 10 | static int pkcs1_v15_add_padding(const void *in, uint16_t in_len, uint8_t *out, uint16_t out_len) { 11 | if (out_len < 11 || in_len > out_len - 11) return -1; 12 | uint16_t pad_size = out_len - in_len - 3; 13 | memmove(out + pad_size + 3, in, in_len); 14 | out[0] = 0x00; 15 | out[1] = 0x01; 16 | memset(out + 2, 0xFF, pad_size); 17 | out[2 + pad_size] = 0x00; 18 | return 0; 19 | } 20 | 21 | static int pkcs1_v15_remove_padding(const uint8_t *in, uint16_t in_len, uint8_t *out) { 22 | if (in_len < 11) return -1; 23 | if (in[0] != 0x00 || in[1] != 0x02) return -1; 24 | uint16_t i; 25 | for (i = 2; i < in_len; ++i) 26 | if (in[i] == 0x00) break; 27 | if (i == in_len || i - 2 < 8) return -1; 28 | memmove(out, in + i + 1, in_len - (i + 1)); 29 | return in_len - (i + 1); 30 | } 31 | 32 | __attribute__((weak)) int rsa_generate_key(rsa_key_t *key, uint16_t nbits) { 33 | int ret = 0; 34 | #ifdef USE_MBEDCRYPTO 35 | mbedtls_rsa_context rsa; 36 | mbedtls_rsa_init(&rsa); 37 | if (mbedtls_rsa_gen_key(&rsa, mbedtls_rnd, NULL, nbits, 65537) < 0) { 38 | ret = -1; 39 | goto cleanup; 40 | } 41 | key->nbits = nbits; 42 | int pq_len = nbits / 16; 43 | if (mbedtls_rsa_export_raw(&rsa, NULL, 0, key->p, pq_len, key->q, pq_len, NULL, 0, key->e, 4) < 0) { 44 | ret = -1; 45 | goto cleanup; 46 | } 47 | cleanup: 48 | mbedtls_rsa_free(&rsa); 49 | #else 50 | (void)key; 51 | (void)nbits; 52 | #endif 53 | return ret; 54 | } 55 | 56 | __attribute__((weak)) int rsa_get_public_key(rsa_key_t *key, uint8_t *n) { 57 | int ret = 0; 58 | #ifdef USE_MBEDCRYPTO 59 | mbedtls_rsa_context rsa; 60 | mbedtls_rsa_init(&rsa); 61 | int pq_len = key->nbits / 16; 62 | if (mbedtls_rsa_import_raw(&rsa, NULL, 0, key->p, pq_len, key->q, pq_len, NULL, 0, key->e, 4) < 0) { 63 | ret = -1; 64 | goto cleanup; 65 | } 66 | if (mbedtls_rsa_complete(&rsa) < 0) { 67 | ret = -1; 68 | goto cleanup; 69 | } 70 | if (mbedtls_rsa_export_raw(&rsa, n, pq_len * 2, NULL, 0, NULL, 0, NULL, 0, NULL, 0) < 0) { 71 | ret = -1; 72 | goto cleanup; 73 | } 74 | cleanup: 75 | mbedtls_rsa_free(&rsa); 76 | #else 77 | (void)key; 78 | (void)n; 79 | #endif 80 | return ret; 81 | } 82 | 83 | __attribute__((weak)) int rsa_private(const rsa_key_t *key, const uint8_t *input, uint8_t *output) { 84 | int ret = 0; 85 | #ifdef USE_MBEDCRYPTO 86 | mbedtls_rsa_context rsa; 87 | mbedtls_rsa_init(&rsa); 88 | int pq_len = key->nbits / 16; 89 | if (mbedtls_rsa_import_raw(&rsa, NULL, 0, key->p, pq_len, key->q, pq_len, NULL, 0, key->e, 4) < 0) { 90 | ret = -1; 91 | goto cleanup; 92 | } 93 | if (mbedtls_rsa_complete(&rsa) < 0) { 94 | ret = -1; 95 | goto cleanup; 96 | } 97 | if (mbedtls_rsa_private(&rsa, mbedtls_rnd, NULL, input, output) < 0) { 98 | ret = -1; 99 | goto cleanup; 100 | } 101 | cleanup: 102 | mbedtls_rsa_free(&rsa); 103 | #else 104 | (void)key; 105 | (void)input; 106 | (void)output; 107 | #endif 108 | return ret; 109 | } 110 | 111 | int rsa_sign_pkcs_v15(const rsa_key_t *key, const uint8_t *data, const size_t len, uint8_t *sig) { 112 | if (pkcs1_v15_add_padding(data, len, sig, key->nbits / 8) < 0) return -1; 113 | return rsa_private(key, sig, sig); 114 | } 115 | 116 | int rsa_decrypt_pkcs_v15(const rsa_key_t *key, const uint8_t *in, size_t *olen, uint8_t *out, uint8_t *invalid_padding) { 117 | *invalid_padding = 0; 118 | if (rsa_private(key, in, out) < 0) return -1; 119 | const int len = pkcs1_v15_remove_padding(out, key->nbits / 8, out); 120 | if (len < 0) { 121 | *invalid_padding = 1; 122 | return -1; 123 | } 124 | *olen = len; 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /main/crypto/sha.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | #ifdef USE_MBEDCRYPTO 6 | #include 7 | #include 8 | #include 9 | 10 | static mbedtls_sha1_context sha1; 11 | static mbedtls_sha256_context sha256; 12 | static mbedtls_sha512_context sha512; 13 | #endif 14 | 15 | __attribute__((weak)) void sha1_init() { 16 | #ifdef USE_MBEDCRYPTO 17 | mbedtls_sha1_init(&sha1); 18 | mbedtls_sha1_starts(&sha1); 19 | #endif 20 | } 21 | 22 | __attribute__((weak)) void sha1_update(const uint8_t *data, uint16_t len) { 23 | #ifdef USE_MBEDCRYPTO 24 | mbedtls_sha1_update(&sha1, data, len); 25 | #else 26 | (void)data; 27 | (void)len; 28 | #endif 29 | } 30 | 31 | __attribute__((weak)) void sha1_final(uint8_t digest[SHA1_DIGEST_LENGTH]) { 32 | #ifdef USE_MBEDCRYPTO 33 | mbedtls_sha1_finish(&sha1, digest); 34 | mbedtls_sha1_free(&sha1); 35 | #else 36 | (void)digest; 37 | #endif 38 | } 39 | 40 | void sha1_raw(const uint8_t *data, const size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { 41 | sha1_init(); 42 | sha1_update(data, len); 43 | sha1_final(digest); 44 | } 45 | 46 | __attribute__((weak)) void sha256_init() { 47 | #ifdef USE_MBEDCRYPTO 48 | mbedtls_sha256_init(&sha256); 49 | mbedtls_sha256_starts(&sha256, 0); 50 | #endif 51 | } 52 | 53 | __attribute__((weak)) void sha256_update(const uint8_t *data, uint16_t len) { 54 | #ifdef USE_MBEDCRYPTO 55 | mbedtls_sha256_update(&sha256, data, len); 56 | #else 57 | (void)data; 58 | (void)len; 59 | #endif 60 | } 61 | 62 | __attribute__((weak)) void sha256_final(uint8_t digest[SHA256_DIGEST_LENGTH]) { 63 | #ifdef USE_MBEDCRYPTO 64 | mbedtls_sha256_finish(&sha256, digest); 65 | mbedtls_sha256_free(&sha256); 66 | #else 67 | (void)digest; 68 | #endif 69 | } 70 | 71 | void sha256_raw(const uint8_t *data, const size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { 72 | sha256_init(); 73 | sha256_update(data, len); 74 | sha256_final(digest); 75 | } 76 | 77 | __attribute__((weak)) void sha512_init() { 78 | #ifdef USE_MBEDCRYPTO 79 | mbedtls_sha512_init(&sha512); 80 | mbedtls_sha512_starts(&sha512, 0); 81 | #endif 82 | } 83 | 84 | __attribute__((weak)) void sha512_update(const uint8_t *data, uint16_t len) { 85 | #ifdef USE_MBEDCRYPTO 86 | mbedtls_sha512_update(&sha512, data, len); 87 | #else 88 | (void)data; 89 | (void)len; 90 | #endif 91 | } 92 | 93 | __attribute__((weak)) void sha512_final(uint8_t digest[SHA512_DIGEST_LENGTH]) { 94 | #ifdef USE_MBEDCRYPTO 95 | mbedtls_sha512_finish(&sha512, digest); 96 | mbedtls_sha512_free(&sha512); 97 | #else 98 | (void)digest; 99 | #endif 100 | } 101 | 102 | void sha512_raw(const uint8_t *data, const size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { 103 | sha512_init(); 104 | sha512_update(data, len); 105 | sha512_final(digest); 106 | } 107 | -------------------------------------------------------------------------------- /main/crypto/sha3.c: -------------------------------------------------------------------------------- 1 | /* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). 2 | * based on the 3 | * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 4 | * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche 5 | * 6 | * Copyright: 2013 Aleksey Kravchenko 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a 9 | * copy of this software and associated documentation files (the "Software"), 10 | * to deal in the Software without restriction, including without limitation 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | * and/or sell copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "sha3.h" 25 | 26 | static void swap_copy_u64_to_str(void *to, const void *from, size_t length); 27 | 28 | #ifndef LITTLE_ENDIAN 29 | #define LITTLE_ENDIAN 1234 30 | #define BIG_ENDIAN 4321 31 | #endif 32 | 33 | #ifndef BYTE_ORDER 34 | #define BYTE_ORDER LITTLE_ENDIAN 35 | #endif 36 | 37 | #if BYTE_ORDER == LITTLE_ENDIAN 38 | #define le2me_64(x) (x) 39 | #define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) 40 | #else 41 | #define le2me_64(x) __builtin_bswap64(x) 42 | #define me64_to_le_str(to, from, length) swap_copy_u64_to_str((to), (from), (length)) 43 | #endif 44 | 45 | #define I64(x) x##LL 46 | #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) 47 | #define IS_ALIGNED_64(p) (0 == (7 & ((int)(const char *)(p)))) 48 | 49 | /* constants */ 50 | #define NumberOfRounds 24 51 | 52 | /* SHA3 (Keccak) constants for 24 rounds */ 53 | static uint64_t keccak_round_constants[NumberOfRounds] = { 54 | I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), 55 | I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), 56 | I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), 57 | I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), 58 | I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), 59 | I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)}; 60 | 61 | __attribute__((unused)) static void swap_copy_u64_to_str(void *to, const void *from, const size_t length) { 62 | /* if all pointers and length are 64-bits aligned */ 63 | if (0 == (((int)(char *)to | (int)(char *)from | length) & 7)) { 64 | /* copy aligned memory block as 64-bit integers */ 65 | const uint64_t *src = from; 66 | const uint64_t *end = (const uint64_t *)((const char *)src + length); 67 | uint64_t *dst = to; 68 | while (src < end) 69 | *dst++ = __builtin_bswap64(*src++); 70 | } else { 71 | char *dst = to; 72 | for (size_t index = 0; index < length; index++) 73 | *dst++ = ((char *)from)[index ^ 7]; 74 | } 75 | } 76 | 77 | /* Initializing a sha3 context for given number of output bits */ 78 | static void keccak_Init(SHA3_CTX *ctx, const unsigned bits) { 79 | /* NB: The Keccak capacity parameter = bits * 2 */ 80 | const unsigned rate = 1600 - bits * 2; 81 | 82 | memzero(ctx, sizeof(SHA3_CTX)); 83 | ctx->block_size = rate / 8; 84 | assert(rate <= 1600 && (rate % 64) == 0); 85 | } 86 | 87 | /** 88 | * Initialize context before calculating hash. 89 | * 90 | * @param ctx context to initialize 91 | */ 92 | void sha3_224_Init(SHA3_CTX *ctx) { keccak_Init(ctx, 224); } 93 | 94 | /** 95 | * Initialize context before calculating hash. 96 | * 97 | * @param ctx context to initialize 98 | */ 99 | void sha3_256_Init(SHA3_CTX *ctx) { keccak_Init(ctx, 256); } 100 | 101 | /** 102 | * Initialize context before calculating hash. 103 | * 104 | * @param ctx context to initialize 105 | */ 106 | void sha3_384_Init(SHA3_CTX *ctx) { keccak_Init(ctx, 384); } 107 | 108 | /** 109 | * Initialize context before calculating hash. 110 | * 111 | * @param ctx context to initialize 112 | */ 113 | void sha3_512_Init(SHA3_CTX *ctx) { keccak_Init(ctx, 512); } 114 | 115 | /* Keccak theta() transformation */ 116 | static void keccak_theta(uint64_t *A) { 117 | unsigned int x; 118 | uint64_t C[5], D[5]; 119 | 120 | for (x = 0; x < 5; x++) { 121 | C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; 122 | } 123 | D[0] = ROTL64(C[1], 1) ^ C[4]; 124 | D[1] = ROTL64(C[2], 1) ^ C[0]; 125 | D[2] = ROTL64(C[3], 1) ^ C[1]; 126 | D[3] = ROTL64(C[4], 1) ^ C[2]; 127 | D[4] = ROTL64(C[0], 1) ^ C[3]; 128 | 129 | for (x = 0; x < 5; x++) { 130 | A[x] ^= D[x]; 131 | A[x + 5] ^= D[x]; 132 | A[x + 10] ^= D[x]; 133 | A[x + 15] ^= D[x]; 134 | A[x + 20] ^= D[x]; 135 | } 136 | } 137 | 138 | /* Keccak pi() transformation */ 139 | static void keccak_pi(uint64_t *A) { 140 | const uint64_t A1 = A[1]; 141 | A[1] = A[6]; 142 | A[6] = A[9]; 143 | A[9] = A[22]; 144 | A[22] = A[14]; 145 | A[14] = A[20]; 146 | A[20] = A[2]; 147 | A[2] = A[12]; 148 | A[12] = A[13]; 149 | A[13] = A[19]; 150 | A[19] = A[23]; 151 | A[23] = A[15]; 152 | A[15] = A[4]; 153 | A[4] = A[24]; 154 | A[24] = A[21]; 155 | A[21] = A[8]; 156 | A[8] = A[16]; 157 | A[16] = A[5]; 158 | A[5] = A[3]; 159 | A[3] = A[18]; 160 | A[18] = A[17]; 161 | A[17] = A[11]; 162 | A[11] = A[7]; 163 | A[7] = A[10]; 164 | A[10] = A1; 165 | /* note: A[ 0] is left as is */ 166 | } 167 | 168 | /* Keccak chi() transformation */ 169 | static void keccak_chi(uint64_t *A) { 170 | for (int i = 0; i < 25; i += 5) { 171 | const uint64_t A0 = A[0 + i], A1 = A[1 + i]; 172 | A[0 + i] ^= ~A1 & A[2 + i]; 173 | A[1 + i] ^= ~A[2 + i] & A[3 + i]; 174 | A[2 + i] ^= ~A[3 + i] & A[4 + i]; 175 | A[3 + i] ^= ~A[4 + i] & A0; 176 | A[4 + i] ^= ~A0 & A1; 177 | } 178 | } 179 | 180 | static void sha3_permutation(uint64_t *state) { 181 | for (int round = 0; round < NumberOfRounds; round++) { 182 | keccak_theta(state); 183 | 184 | /* apply Keccak rho() transformation */ 185 | state[1] = ROTL64(state[1], 1); 186 | state[2] = ROTL64(state[2], 62); 187 | state[3] = ROTL64(state[3], 28); 188 | state[4] = ROTL64(state[4], 27); 189 | state[5] = ROTL64(state[5], 36); 190 | state[6] = ROTL64(state[6], 44); 191 | state[7] = ROTL64(state[7], 6); 192 | state[8] = ROTL64(state[8], 55); 193 | state[9] = ROTL64(state[9], 20); 194 | state[10] = ROTL64(state[10], 3); 195 | state[11] = ROTL64(state[11], 10); 196 | state[12] = ROTL64(state[12], 43); 197 | state[13] = ROTL64(state[13], 25); 198 | state[14] = ROTL64(state[14], 39); 199 | state[15] = ROTL64(state[15], 41); 200 | state[16] = ROTL64(state[16], 45); 201 | state[17] = ROTL64(state[17], 15); 202 | state[18] = ROTL64(state[18], 21); 203 | state[19] = ROTL64(state[19], 8); 204 | state[20] = ROTL64(state[20], 18); 205 | state[21] = ROTL64(state[21], 2); 206 | state[22] = ROTL64(state[22], 61); 207 | state[23] = ROTL64(state[23], 56); 208 | state[24] = ROTL64(state[24], 14); 209 | 210 | keccak_pi(state); 211 | keccak_chi(state); 212 | 213 | /* apply iota(state, round) */ 214 | *state ^= keccak_round_constants[round]; 215 | } 216 | } 217 | 218 | /** 219 | * The core transformation. Process the specified block of data. 220 | * 221 | * @param hash the algorithm state 222 | * @param block the message block to process 223 | * @param block_size the size of the processed block in bytes 224 | */ 225 | static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) { 226 | /* expanded loop */ 227 | hash[0] ^= le2me_64(block[0]); 228 | hash[1] ^= le2me_64(block[1]); 229 | hash[2] ^= le2me_64(block[2]); 230 | hash[3] ^= le2me_64(block[3]); 231 | hash[4] ^= le2me_64(block[4]); 232 | hash[5] ^= le2me_64(block[5]); 233 | hash[6] ^= le2me_64(block[6]); 234 | hash[7] ^= le2me_64(block[7]); 235 | hash[8] ^= le2me_64(block[8]); 236 | /* if not sha3-512 */ 237 | if (block_size > 72) { 238 | hash[9] ^= le2me_64(block[9]); 239 | hash[10] ^= le2me_64(block[10]); 240 | hash[11] ^= le2me_64(block[11]); 241 | hash[12] ^= le2me_64(block[12]); 242 | /* if not sha3-384 */ 243 | if (block_size > 104) { 244 | hash[13] ^= le2me_64(block[13]); 245 | hash[14] ^= le2me_64(block[14]); 246 | hash[15] ^= le2me_64(block[15]); 247 | hash[16] ^= le2me_64(block[16]); 248 | /* if not sha3-256 */ 249 | if (block_size > 136) { 250 | hash[17] ^= le2me_64(block[17]); 251 | #ifdef FULL_SHA3_FAMILY_SUPPORT 252 | /* if not sha3-224 */ 253 | if (block_size > 144) { 254 | hash[18] ^= le2me_64(block[18]); 255 | hash[19] ^= le2me_64(block[19]); 256 | hash[20] ^= le2me_64(block[20]); 257 | hash[21] ^= le2me_64(block[21]); 258 | hash[22] ^= le2me_64(block[22]); 259 | hash[23] ^= le2me_64(block[23]); 260 | hash[24] ^= le2me_64(block[24]); 261 | } 262 | #endif 263 | } 264 | } 265 | } 266 | /* make a permutation of the hash */ 267 | sha3_permutation(hash); 268 | } 269 | 270 | #define SHA3_FINALIZED 0x80000000 271 | 272 | /** 273 | * Calculate message hash. 274 | * Can be called repeatedly with chunks of the message to be hashed. 275 | * 276 | * @param ctx the algorithm context containing current hashing state 277 | * @param msg message chunk 278 | * @param size length of the message chunk 279 | */ 280 | void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) { 281 | const size_t idx = ctx->rest; 282 | const size_t block_size = ctx->block_size; 283 | 284 | if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ 285 | ctx->rest = (ctx->rest + size) % block_size; 286 | 287 | /* fill partial block */ 288 | if (idx) { 289 | const size_t left = block_size - idx; 290 | memcpy((char *)ctx->message + idx, msg, size < left ? size : left); 291 | if (size < left) return; 292 | 293 | /* process partial block */ 294 | sha3_process_block(ctx->hash, ctx->message, block_size); 295 | msg += left; 296 | size -= left; 297 | } 298 | while (size >= block_size) { 299 | uint64_t *aligned_message_block; 300 | if (IS_ALIGNED_64(msg)) { 301 | /* the most common case is processing of an already aligned message 302 | without copying it */ 303 | aligned_message_block = (uint64_t *)(void *)msg; 304 | } else { 305 | memcpy(ctx->message, msg, block_size); 306 | aligned_message_block = ctx->message; 307 | } 308 | 309 | sha3_process_block(ctx->hash, aligned_message_block, block_size); 310 | msg += block_size; 311 | size -= block_size; 312 | } 313 | if (size) { 314 | memcpy(ctx->message, msg, size); /* save leftovers */ 315 | } 316 | } 317 | 318 | /** 319 | * Store calculated hash into the given array. 320 | * 321 | * @param ctx the algorithm context containing current hashing state 322 | * @param result calculated hash in binary form 323 | */ 324 | void sha3_Final(SHA3_CTX *ctx, unsigned char *result) { 325 | const size_t digest_length = 100 - ctx->block_size / 2; 326 | const size_t block_size = ctx->block_size; 327 | 328 | if (!(ctx->rest & SHA3_FINALIZED)) { 329 | /* clear the rest of the data queue */ 330 | memzero((char *)ctx->message + ctx->rest, block_size - ctx->rest); 331 | ((char *)ctx->message)[ctx->rest] |= 0x06; 332 | ((char *)ctx->message)[block_size - 1] |= 0x80; 333 | 334 | /* process final block */ 335 | sha3_process_block(ctx->hash, ctx->message, block_size); 336 | ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ 337 | } 338 | 339 | assert(block_size > digest_length); 340 | if (result) me64_to_le_str(result, ctx->hash, digest_length); 341 | memzero(ctx, sizeof(SHA3_CTX)); 342 | } 343 | 344 | /** 345 | * Store calculated hash into the given array. 346 | * 347 | * @param ctx the algorithm context containing current hashing state 348 | * @param result calculated hash in binary form 349 | */ 350 | void keccak_Final(SHA3_CTX *ctx, unsigned char *result) { 351 | const size_t digest_length = 100 - ctx->block_size / 2; 352 | const size_t block_size = ctx->block_size; 353 | 354 | if (!(ctx->rest & SHA3_FINALIZED)) { 355 | /* clear the rest of the data queue */ 356 | memzero((char *)ctx->message + ctx->rest, block_size - ctx->rest); 357 | ((char *)ctx->message)[ctx->rest] |= 0x01; 358 | ((char *)ctx->message)[block_size - 1] |= 0x80; 359 | 360 | /* process final block */ 361 | sha3_process_block(ctx->hash, ctx->message, block_size); 362 | ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ 363 | } 364 | 365 | assert(block_size > digest_length); 366 | if (result) me64_to_le_str(result, ctx->hash, digest_length); 367 | memzero(ctx, sizeof(SHA3_CTX)); 368 | } 369 | 370 | void keccak_256(const unsigned char *data, const size_t len, unsigned char *digest) { 371 | SHA3_CTX ctx; 372 | keccak_256_Init(&ctx); 373 | keccak_Update(&ctx, data, len); 374 | keccak_Final(&ctx, digest); 375 | } 376 | 377 | void keccak_512(const unsigned char *data, const size_t len, unsigned char *digest) { 378 | SHA3_CTX ctx; 379 | keccak_512_Init(&ctx); 380 | keccak_Update(&ctx, data, len); 381 | keccak_Final(&ctx, digest); 382 | } 383 | 384 | void sha3_256(const unsigned char *data, const size_t len, unsigned char *digest) { 385 | SHA3_CTX ctx; 386 | sha3_256_Init(&ctx); 387 | sha3_Update(&ctx, data, len); 388 | sha3_Final(&ctx, digest); 389 | } 390 | 391 | void sha3_512(const unsigned char *data, const size_t len, unsigned char *digest) { 392 | SHA3_CTX ctx; 393 | sha3_512_Init(&ctx); 394 | sha3_Update(&ctx, data, len); 395 | sha3_Final(&ctx, digest); 396 | } 397 | -------------------------------------------------------------------------------- /main/crypto/sm3.c: -------------------------------------------------------------------------------- 1 | // Modified from https://github.com/AyrA/sm3/blob/master/sm3.c (Dec 24, 2023) 2 | // 3 | // MIT License 4 | // 5 | // Copyright (c) 2019 Kevin Gut 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all 15 | // copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | // SOFTWARE. 24 | 25 | #include "sm3.h" 26 | #include 27 | 28 | #ifdef USE_MBEDCRYPTO 29 | typedef struct { 30 | uint32_t digest[8]; 31 | int nblocks; 32 | unsigned char block[64]; 33 | int num; 34 | } sm3_ctx_t; 35 | 36 | static sm3_ctx_t ctx; 37 | static void sm3_compress(uint32_t digest[8], const unsigned char block[64]); 38 | #endif 39 | 40 | __attribute__((weak)) void sm3_init(void) { 41 | #ifdef USE_MBEDCRYPTO 42 | ctx.digest[0] = 0x7380166F; 43 | ctx.digest[1] = 0x4914B2B9; 44 | ctx.digest[2] = 0x172442D7; 45 | ctx.digest[3] = 0xDA8A0600; 46 | ctx.digest[4] = 0xA96F30BC; 47 | ctx.digest[5] = 0x163138AA; 48 | ctx.digest[6] = 0xE38DEE4D; 49 | ctx.digest[7] = 0xB0FB0E4E; 50 | 51 | ctx.nblocks = 0; 52 | ctx.num = 0; 53 | #endif 54 | } 55 | 56 | __attribute__((weak)) void sm3_update(const uint8_t *data, uint16_t len) { 57 | #ifdef USE_MBEDCRYPTO 58 | if (ctx.num) { 59 | const unsigned int left = SM3_BLOCK_LENGTH - ctx.num; 60 | if (len < left) { 61 | memcpy(ctx.block + ctx.num, data, len); 62 | ctx.num += len; 63 | return; 64 | } else { 65 | memcpy(ctx.block + ctx.num, data, left); 66 | sm3_compress(ctx.digest, ctx.block); 67 | ctx.nblocks++; 68 | data += left; 69 | len -= left; 70 | } 71 | } 72 | while (len >= SM3_BLOCK_LENGTH) { 73 | sm3_compress(ctx.digest, data); 74 | ctx.nblocks++; 75 | data += SM3_BLOCK_LENGTH; 76 | len -= SM3_BLOCK_LENGTH; 77 | } 78 | ctx.num = len; 79 | if (len) { 80 | memcpy(ctx.block, data, len); 81 | } 82 | #else 83 | (void)data; 84 | (void)len; 85 | #endif 86 | } 87 | 88 | __attribute__((weak)) void sm3_final(uint8_t digest[SM3_DIGEST_LENGTH]) { 89 | #ifdef USE_MBEDCRYPTO 90 | unsigned int i; 91 | uint32_t *pdigest = (uint32_t *)digest; 92 | uint32_t *count = (uint32_t *)(ctx.block + SM3_BLOCK_LENGTH - 8); 93 | 94 | ctx.block[ctx.num] = 0x80; 95 | 96 | if (ctx.num + 9 <= SM3_BLOCK_LENGTH) { 97 | memset(ctx.block + ctx.num + 1, 0, SM3_BLOCK_LENGTH - ctx.num - 9); 98 | } else { 99 | memset(ctx.block + ctx.num + 1, 0, SM3_BLOCK_LENGTH - ctx.num - 1); 100 | sm3_compress(ctx.digest, ctx.block); 101 | memset(ctx.block, 0, SM3_BLOCK_LENGTH - 8); 102 | } 103 | 104 | count[0] = __builtin_bswap32(ctx.nblocks >> 23); 105 | count[1] = __builtin_bswap32((ctx.nblocks << 9) + (ctx.num << 3)); 106 | 107 | sm3_compress(ctx.digest, ctx.block); 108 | for (i = 0; i < sizeof(ctx.digest) / sizeof(ctx.digest[0]); i++) { 109 | pdigest[i] = __builtin_bswap32(ctx.digest[i]); 110 | } 111 | #else 112 | (void)digest; 113 | #endif 114 | } 115 | 116 | #ifdef USE_MBEDCRYPTO 117 | #define ROTATELEFT(X,n) (((X)<<(n)) | ((X)>>(32-(n)))) 118 | 119 | #define P0(x) ((x) ^ ROTATELEFT((x),9) ^ ROTATELEFT((x),17)) 120 | #define P1(x) ((x) ^ ROTATELEFT((x),15) ^ ROTATELEFT((x),23)) 121 | 122 | #define FF0(x,y,z) ( (x) ^ (y) ^ (z)) 123 | #define FF1(x,y,z) (((x) & (y)) | ( (x) & (z)) | ( (y) & (z))) 124 | 125 | #define GG0(x,y,z) ( (x) ^ (y) ^ (z)) 126 | #define GG1(x,y,z) (((x) & (y)) | ( (~(x)) & (z)) ) 127 | 128 | void sm3_compress(uint32_t digest[8], const unsigned char block[64]) { 129 | int j; 130 | uint32_t W[68], W1[64]; 131 | const uint32_t *pblock = (const uint32_t *)block; 132 | 133 | uint32_t A = digest[0]; 134 | uint32_t B = digest[1]; 135 | uint32_t C = digest[2]; 136 | uint32_t D = digest[3]; 137 | uint32_t E = digest[4]; 138 | uint32_t F = digest[5]; 139 | uint32_t G = digest[6]; 140 | uint32_t H = digest[7]; 141 | uint32_t SS1, SS2, TT1, TT2, T[64]; 142 | 143 | for (j = 0; j < 16; j++) { 144 | W[j] = __builtin_bswap32(pblock[j]); 145 | } 146 | for (j = 16; j < 68; j++) { 147 | W[j] = P1(W[j-16] ^ W[j-9] ^ ROTATELEFT(W[j-3],15)) ^ ROTATELEFT(W[j - 13], 7) ^ W[j - 6];; 148 | } 149 | for (j = 0; j < 64; j++) { 150 | W1[j] = W[j] ^ W[j + 4]; 151 | } 152 | 153 | for (j = 0; j < 16; j++) { 154 | 155 | T[j] = 0x79CC4519; 156 | SS1 = ROTATELEFT((ROTATELEFT(A,12) + E + ROTATELEFT(T[j],j)), 7); 157 | SS2 = SS1 ^ ROTATELEFT(A, 12); 158 | TT1 = FF0(A, B, C) + D + SS2 + W1[j]; 159 | TT2 = GG0(E, F, G) + H + SS1 + W[j]; 160 | D = C; 161 | C = ROTATELEFT(B, 9); 162 | B = A; 163 | A = TT1; 164 | H = G; 165 | G = ROTATELEFT(F, 19); 166 | F = E; 167 | E = P0(TT2); 168 | } 169 | 170 | for (j = 16; j < 64; j++) { 171 | 172 | T[j] = 0x7A879D8A; 173 | SS1 = ROTATELEFT((ROTATELEFT(A,12) + E + ROTATELEFT(T[j],j)), 7); 174 | SS2 = SS1 ^ ROTATELEFT(A, 12); 175 | TT1 = FF1(A, B, C) + D + SS2 + W1[j]; 176 | TT2 = GG1(E, F, G) + H + SS1 + W[j]; 177 | D = C; 178 | C = ROTATELEFT(B, 9); 179 | B = A; 180 | A = TT1; 181 | H = G; 182 | G = ROTATELEFT(F, 19); 183 | F = E; 184 | E = P0(TT2); 185 | } 186 | 187 | digest[0] ^= A; 188 | digest[1] ^= B; 189 | digest[2] ^= C; 190 | digest[3] ^= D; 191 | digest[4] ^= E; 192 | digest[5] ^= F; 193 | digest[6] ^= G; 194 | digest[7] ^= H; 195 | } 196 | #endif 197 | 198 | void sm3_raw(const uint8_t *data, size_t len, uint8_t digest[SM3_DIGEST_LENGTH]) { 199 | sm3_init(); 200 | sm3_update(data, len); 201 | sm3_final(digest); 202 | } 203 | -------------------------------------------------------------------------------- /main/fs.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | 5 | static lfs_t lfs; 6 | 7 | static uint8_t file_buffer[LFS_CACHE_SIZE]; 8 | 9 | static struct lfs_file_config file_config = { 10 | .buffer = file_buffer 11 | }; 12 | 13 | int fs_format(const struct lfs_config *cfg) { return lfs_format(&lfs, cfg); } 14 | 15 | int fs_mount(const struct lfs_config *cfg) { return lfs_mount(&lfs, cfg); } 16 | 17 | int read_file(const char *path, void *buf, lfs_soff_t off, lfs_size_t len) { 18 | lfs_file_t f; 19 | lfs_ssize_t read_length; 20 | int err = lfs_file_opencfg(&lfs, &f, path, LFS_O_RDONLY, &file_config); 21 | if (err < 0) return err; 22 | err = lfs_file_seek(&lfs, &f, off, LFS_SEEK_SET); 23 | if (err < 0) goto err_close; 24 | read_length = lfs_file_read(&lfs, &f, buf, len); 25 | if (read_length < 0) { 26 | err = read_length; 27 | goto err_close; 28 | } 29 | err = lfs_file_close(&lfs, &f); 30 | if (err < 0) return err; 31 | return read_length; 32 | 33 | err_close: 34 | lfs_file_close(&lfs, &f); 35 | return err; 36 | } 37 | 38 | int write_file(const char *path, const void *buf, lfs_soff_t off, lfs_size_t len, uint8_t trunc) { 39 | lfs_file_t f; 40 | #ifdef TEST 41 | if (testmode_err_triggered(path, true)) { 42 | return LFS_ERR_IO; 43 | } 44 | #endif 45 | int flags = LFS_O_WRONLY | LFS_O_CREAT; 46 | if (trunc) flags |= LFS_O_TRUNC; 47 | int err = lfs_file_opencfg(&lfs, &f, path, flags, &file_config); 48 | if (err < 0) return err; 49 | err = lfs_file_seek(&lfs, &f, off, LFS_SEEK_SET); 50 | if (err < 0) goto err_close; 51 | if (len > 0) { 52 | err = lfs_file_write(&lfs, &f, buf, len); 53 | if (err < 0) goto err_close; 54 | } 55 | err = lfs_file_close(&lfs, &f); 56 | if (err < 0) return err; 57 | return 0; 58 | err_close: 59 | lfs_file_close(&lfs, &f); 60 | return err; 61 | } 62 | 63 | int append_file(const char *path, const void *buf, lfs_size_t len) { 64 | lfs_file_t f; 65 | int err = lfs_file_opencfg(&lfs, &f, path, LFS_O_WRONLY | LFS_O_CREAT, &file_config); 66 | if (err < 0) return err; 67 | err = lfs_file_seek(&lfs, &f, 0, LFS_SEEK_END); 68 | if (err < 0) goto err_close; 69 | if (len > 0) { 70 | err = lfs_file_write(&lfs, &f, buf, len); 71 | if (err < 0) goto err_close; 72 | } 73 | err = lfs_file_close(&lfs, &f); 74 | if (err < 0) return err; 75 | return 0; 76 | err_close: 77 | lfs_file_close(&lfs, &f); 78 | return err; 79 | } 80 | 81 | int truncate_file(const char *path, lfs_size_t len) { 82 | lfs_file_t f; 83 | int flags = LFS_O_WRONLY | LFS_O_CREAT; 84 | int err = lfs_file_opencfg(&lfs, &f, path, flags, &file_config); 85 | if (err < 0) return err; 86 | err = lfs_file_truncate(&lfs, &f, len); 87 | if (err < 0) goto err_close; 88 | err = lfs_file_close(&lfs, &f); 89 | if (err < 0) return err; 90 | return 0; 91 | err_close: 92 | lfs_file_close(&lfs, &f); 93 | return err; 94 | } 95 | 96 | int read_attr(const char *path, uint8_t attr, void *buf, lfs_size_t len) { 97 | return lfs_getattr(&lfs, path, attr, buf, len); 98 | } 99 | 100 | int write_attr(const char *path, uint8_t attr, const void *buf, lfs_size_t len) { 101 | return lfs_setattr(&lfs, path, attr, buf, len); 102 | } 103 | 104 | int get_file_size(const char *path) { 105 | lfs_file_t f; 106 | int err = lfs_file_opencfg(&lfs, &f, path, LFS_O_RDONLY, &file_config); 107 | if (err < 0) return err; 108 | int size = lfs_file_size(&lfs, &f); 109 | if (size < 0) { 110 | err = size; 111 | goto err_close; 112 | } 113 | err = lfs_file_close(&lfs, &f); 114 | if (err < 0) return err; 115 | return size; 116 | err_close: 117 | lfs_file_close(&lfs, &f); 118 | return err; 119 | } 120 | 121 | int get_fs_size(void) { return (int) (lfs.cfg->block_size * lfs.cfg->block_count) / 1024; } 122 | 123 | int get_fs_usage(void) { 124 | int blocks = lfs_fs_size(&lfs); 125 | if (blocks < 0) return blocks; 126 | return (int) (lfs.cfg->block_size * blocks) / 1024; 127 | } 128 | 129 | int fs_rename(const char *old, const char *new) { return lfs_rename(&lfs, old, new); } 130 | -------------------------------------------------------------------------------- /main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/tinyusb: "~0.14.3" 4 | espressif/esp_tinyusb: "~1.4.2" 5 | espressif/cbor: "~0.6.0" 6 | idf: "^5.0" -------------------------------------------------------------------------------- /main/include/admin.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_ADMIN_ADMIN_H_ 3 | #define CANOKEY_CORE_ADMIN_ADMIN_H_ 4 | 5 | #include 6 | 7 | #define ADMIN_INS_WRITE_FIDO_PRIVATE_KEY 0x01 8 | #define ADMIN_INS_WRITE_FIDO_CERT 0x02 9 | #define ADMIN_INS_RESET_OPENPGP 0x03 10 | #define ADMIN_INS_RESET_PIV 0x04 11 | #define ADMIN_INS_RESET_OATH 0x05 12 | #define ADMIN_INS_RESET_NDEF 0x07 13 | #define ADMIN_INS_TOGGLE_NDEF_READ_ONLY 0x08 14 | #define ADMIN_INS_RESET_CTAP 0x09 15 | #define ADMIN_INS_READ_CTAP_SM2_CONFIG 0x11 16 | #define ADMIN_INS_WRITE_CTAP_SM2_CONFIG 0x12 17 | #define ADMIN_INS_VERIFY 0x20 18 | #define ADMIN_INS_CHANGE_PIN 0x21 19 | #define ADMIN_INS_WRITE_SN 0x30 20 | #define ADMIN_INS_READ_VERSION 0x31 21 | #define ADMIN_INS_READ_SN 0x32 22 | #define ADMIN_INS_CONFIG 0x40 23 | #define ADMIN_INS_FLASH_USAGE 0x41 24 | #define ADMIN_INS_READ_CONFIG 0x42 25 | #define ADMIN_INS_FACTORY_RESET 0x50 26 | #define ADMIN_INS_SELECT 0xA4 27 | #define ADMIN_INS_VENDOR_SPECIFIC 0xFF 28 | 29 | #define ADMIN_P1_CFG_LED_ON 0x01 30 | #define ADMIN_P1_CFG_KBDIFACE 0x03 31 | #define ADMIN_P1_CFG_NDEF 0x04 32 | #define ADMIN_P1_CFG_WEBUSB_LANDING 0x05 33 | #define ADMIN_P1_CFG_KBD_WITH_RETURN 0x06 34 | 35 | typedef struct { 36 | uint32_t reserved; 37 | uint32_t led_normally_on : 1; 38 | uint32_t unused : 1; 39 | uint32_t kbd_interface_en : 1; 40 | uint32_t ndef_en : 1; 41 | uint32_t webusb_landing_en : 1; 42 | uint32_t kbd_with_return_en : 1; 43 | } __packed admin_device_config_t; 44 | 45 | void admin_poweroff(void); 46 | int admin_install(uint8_t reset); 47 | int admin_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 48 | int admin_vendor_specific(const CAPDU *capdu, RAPDU *rapdu); 49 | int admin_vendor_version(const CAPDU *capdu, RAPDU *rapdu); 50 | int admin_vendor_hw_variant(const CAPDU *capdu, RAPDU *rapdu); 51 | int admin_vendor_hw_sn(const CAPDU *capdu, RAPDU *rapdu); 52 | 53 | uint8_t cfg_is_led_normally_on(void); 54 | uint8_t cfg_is_kbd_interface_enable(void); 55 | uint8_t cfg_is_ndef_enable(void); 56 | uint8_t cfg_is_webusb_landing_enable(void); 57 | uint8_t cfg_is_kbd_with_return_enable(void); 58 | 59 | #endif // CANOKEY_CORE_ADMIN_ADMIN_H_ 60 | -------------------------------------------------------------------------------- /main/include/apdu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE__APDU_H 3 | #define CANOKEY_CORE__APDU_H 4 | 5 | #include "common.h" 6 | 7 | typedef struct { 8 | uint8_t *data; 9 | uint8_t cla; 10 | uint8_t ins; 11 | uint8_t p1; 12 | uint8_t p2; 13 | uint32_t le; // Le can be 65536 bytes long as per ISO7816-3 14 | uint16_t lc; 15 | } __packed CAPDU; 16 | 17 | typedef struct { 18 | uint8_t *data; 19 | uint16_t len; 20 | uint16_t sw; 21 | } __packed RAPDU; 22 | 23 | // Command status responses 24 | 25 | #define SW_NO_ERROR 0x9000 26 | #define SW_TERMINATED 0x6285 27 | #define SW_PIN_RETRIES 0x63C0 28 | #define SW_WRONG_LENGTH 0x6700 29 | #define SW_UNABLE_TO_PROCESS 0x6900 30 | #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 31 | #define SW_AUTHENTICATION_BLOCKED 0x6983 32 | #define SW_DATA_INVALID 0x6984 33 | #define SW_CONDITIONS_NOT_SATISFIED 0x6985 34 | #define SW_COMMAND_NOT_ALLOWED 0x6986 35 | #define SW_WRONG_DATA 0x6A80 36 | #define SW_FILE_NOT_FOUND 0x6A82 37 | #define SW_NOT_ENOUGH_SPACE 0x6A84 38 | #define SW_WRONG_P1P2 0x6A86 39 | #define SW_REFERENCE_DATA_NOT_FOUND 0x6A88 40 | #define SW_INS_NOT_SUPPORTED 0x6D00 41 | #define SW_CLA_NOT_SUPPORTED 0x6E00 42 | #define SW_CHECKING_ERROR 0x6F00 43 | #define SW_ERROR_WHILE_RECEIVING 0x6600 44 | 45 | // Macros 46 | 47 | #define CLA capdu->cla 48 | #define INS capdu->ins 49 | #define P1 capdu->p1 50 | #define P2 capdu->p2 51 | #define LC capdu->lc 52 | #define LE capdu->le 53 | #define DATA capdu->data 54 | #define RDATA rapdu->data 55 | #define SW rapdu->sw 56 | #define LL rapdu->len 57 | 58 | #define EXCEPT(sw_code) \ 59 | do { \ 60 | SW = sw_code; \ 61 | return 0; \ 62 | } while (0) 63 | 64 | // Chainings 65 | 66 | #define APDU_CHAINING_NOT_LAST_BLOCK 0x01 67 | #define APDU_CHAINING_LAST_BLOCK 0x02 68 | #define APDU_CHAINING_OVERFLOW 0x03 69 | 70 | typedef struct { 71 | CAPDU capdu; 72 | uint8_t in_chaining; 73 | } CAPDU_CHAINING; 74 | 75 | typedef struct { 76 | RAPDU rapdu; 77 | uint16_t sent; 78 | } RAPDU_CHAINING; 79 | 80 | extern uint8_t *global_buffer; 81 | 82 | enum { 83 | BUFFER_OWNER_NONE = 1, 84 | BUFFER_OWNER_CCID, 85 | BUFFER_OWNER_WEBUSB, 86 | BUFFER_OWNER_USBD, // store the configuration descriptor during a control transfer 87 | }; 88 | 89 | void init_apdu_buffer(void); // implement in ccid.c for reusing the ccid buffer 90 | int acquire_apdu_buffer(uint8_t owner); 91 | int release_apdu_buffer(uint8_t owner); 92 | 93 | int build_capdu(CAPDU *capdu, const uint8_t *cmd, uint16_t len); 94 | int apdu_input(CAPDU_CHAINING *ex, const CAPDU *sh); 95 | int apdu_output(RAPDU_CHAINING *ex, RAPDU *sh); 96 | void process_apdu(CAPDU *capdu, RAPDU *rapdu); 97 | 98 | #endif // CANOKEY_CORE__APDU_H -------------------------------------------------------------------------------- /main/include/applets.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #ifndef APPLETS_H_ 3 | #define APPLETS_H_ 4 | 5 | void applets_install(void); 6 | void applets_poweroff(void); 7 | 8 | #endif // APPLETS_H_ 9 | -------------------------------------------------------------------------------- /main/include/ccid.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef _CCID_H_ 3 | #define _CCID_H_ 4 | 5 | #include 6 | 7 | #define ABDATA_SIZE (APDU_BUFFER_SIZE + 2) 8 | #define CCID_CMD_HEADER_SIZE 10 9 | #define CCID_NUMBER_OF_SLOTS 1 10 | #define TIME_EXTENSION_PERIOD 1500 11 | 12 | typedef struct { 13 | uint8_t bMessageType; /* Offset = 0*/ 14 | uint32_t dwLength; /* Offset = 1, The length field (dwLength) is the length 15 | of the message not including the 10-byte header.*/ 16 | uint8_t bSlot; /* Offset = 5*/ 17 | uint8_t bSeq; /* Offset = 6*/ 18 | uint8_t bSpecific_0; /* Offset = 7*/ 19 | uint8_t bSpecific_1; /* Offset = 8*/ 20 | uint8_t bSpecific_2; /* Offset = 9*/ 21 | uint8_t *abData; /* Offset = 10*/ 22 | } __packed ccid_bulkout_data_t; 23 | 24 | typedef struct { 25 | uint8_t bMessageType; /* Offset = 0*/ 26 | uint32_t dwLength; /* Offset = 1*/ 27 | uint8_t bSlot; /* Offset = 5, Same as Bulk-OUT message */ 28 | uint8_t bSeq; /* Offset = 6, Same as Bulk-OUT message */ 29 | uint8_t bStatus; /* Offset = 7, Slot status as defined in § 6.2.6*/ 30 | uint8_t bError; /* Offset = 8, Slot error as defined in § 6.2.6*/ 31 | uint8_t bSpecific; /* Offset = 9*/ 32 | uint8_t abData[ABDATA_SIZE]; /* Offset = 10*/ 33 | } __packed ccid_bulkin_data_t; 34 | 35 | typedef struct { 36 | uint8_t bMessageType; /* Offset = 0*/ 37 | uint32_t dwLength; /* Offset = 1*/ 38 | uint8_t bSlot; /* Offset = 5, Same as Bulk-OUT message */ 39 | uint8_t bSeq; /* Offset = 6, Same as Bulk-OUT message */ 40 | uint8_t bStatus; /* Offset = 7, Slot status as defined in § 6.2.6*/ 41 | uint8_t bError; /* Offset = 8, Slot error as defined in § 6.2.6*/ 42 | uint8_t bSpecific; /* Offset = 9*/ 43 | } __packed empty_ccid_bulkin_data_t; 44 | 45 | /******************************************************************************/ 46 | /* ERROR CODES for USB Bulk In Messages : bError */ 47 | /******************************************************************************/ 48 | 49 | #define SLOT_NO_ERROR 0x81 50 | #define SLOTERROR_UNKNOWN 0x82 51 | 52 | #define SLOTERROR_BAD_LENTGH 0x01 53 | #define SLOTERROR_BAD_SLOT 0x05 54 | #define SLOTERROR_BAD_POWERSELECT 0x07 55 | #define SLOTERROR_BAD_PROTOCOLNUM 0x07 56 | #define SLOTERROR_BAD_CLOCKCOMMAND 0x07 57 | #define SLOTERROR_BAD_ABRFU_3B 0x07 58 | #define SLOTERROR_BAD_BMCHANGES 0x07 59 | #define SLOTERROR_BAD_BFUNCTION_MECHANICAL 0x07 60 | #define SLOTERROR_BAD_ABRFU_2B 0x08 61 | #define SLOTERROR_BAD_LEVELPARAMETER 0x08 62 | #define SLOTERROR_BAD_FIDI 0x0A 63 | #define SLOTERROR_BAD_T01CONVCHECKSUM 0x0B 64 | #define SLOTERROR_BAD_GUARDTIME 0x0C 65 | #define SLOTERROR_BAD_WAITINGINTEGER 0x0D 66 | #define SLOTERROR_BAD_CLOCKSTOP 0x0E 67 | #define SLOTERROR_BAD_IFSC 0x0F 68 | #define SLOTERROR_BAD_NAD 0x10 69 | #define SLOTERROR_BAD_DWLENGTH 0x08 /* Used in PC_to_RDR_XfrBlock*/ 70 | 71 | #define SLOTERROR_CMD_ABORTED 0xFF 72 | #define SLOTERROR_ICC_MUTE 0xFE 73 | #define SLOTERROR_XFR_PARITY_ERROR 0xFD 74 | #define SLOTERROR_XFR_OVERRUN 0xFC 75 | #define SLOTERROR_HW_ERROR 0xFB 76 | #define SLOTERROR_BAD_ATR_TS 0xF8 77 | #define SLOTERROR_BAD_ATR_TCK 0xF7 78 | #define SLOTERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xF6 79 | #define SLOTERROR_ICC_CLASS_NOT_SUPPORTED 0xF5 80 | #define SLOTERROR_PROCEDURE_BYTE_CONFLICT 0xF4 81 | #define SLOTERROR_DEACTIVATED_PROTOCOL 0xF3 82 | #define SLOTERROR_BUSY_WITH_AUTO_SEQUENCE 0xF2 83 | #define SLOTERROR_PIN_TIMEOUT 0xF0 84 | #define SLOTERROR_PIN_CANCELLED 0xEF 85 | #define SLOTERROR_CMD_SLOT_BUSY 0xE0 86 | #define SLOTERROR_CMD_NOT_SUPPORTED 0x00 87 | 88 | #define BM_ICC_PRESENT_ACTIVE 0x00 89 | #define BM_ICC_PRESENT_INACTIVE 0x01 90 | #define BM_ICC_NO_ICC_PRESENT 0x02 91 | 92 | #define BM_COMMAND_STATUS_OFFSET 0x06 93 | #define BM_COMMAND_STATUS_NO_ERROR 0x00 94 | #define BM_COMMAND_STATUS_FAILED (0x01 << BM_COMMAND_STATUS_OFFSET) 95 | #define BM_COMMAND_STATUS_TIME_EXTN (0x02 << BM_COMMAND_STATUS_OFFSET) 96 | 97 | #define LEN_RDR_TO_PC_SLOTSTATUS 10 98 | 99 | typedef enum { 100 | CHK_PARAM_SLOT = 1, 101 | CHK_PARAM_DWLENGTH = (1 << 1), 102 | CHK_PARAM_abRFU2 = (1 << 2), 103 | CHK_PARAM_abRFU3 = (1 << 3), 104 | CHK_PARAM_CARD_PRESENT = (1 << 4), 105 | CHK_PARAM_ABORT = (1 << 5), 106 | CHK_ACTIVE_STATE = (1 << 6) 107 | } ChkParam_t; 108 | 109 | #define PC_TO_RDR_ICCPOWERON 0x62 110 | #define PC_TO_RDR_ICCPOWEROFF 0x63 111 | #define PC_TO_RDR_GETSLOTSTATUS 0x65 112 | #define PC_TO_RDR_XFRBLOCK 0x6F 113 | #define PC_TO_RDR_GETPARAMETERS 0x6C 114 | #define PC_TO_RDR_RESETPARAMETERS 0x6D 115 | #define PC_TO_RDR_SETPARAMETERS 0x61 116 | #define PC_TO_RDR_ESCAPE 0x6B 117 | #define PC_TO_RDR_ICCCLOCK 0x6E 118 | #define PC_TO_RDR_T0APDU 0x6A 119 | #define PC_TO_RDR_SECURE 0x69 120 | #define PC_TO_RDR_MECHANICAL 0x71 121 | #define PC_TO_RDR_ABORT 0x72 122 | #define PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY 0x73 123 | 124 | #define RDR_TO_PC_DATABLOCK 0x80 125 | #define RDR_TO_PC_SLOTSTATUS 0x81 126 | #define RDR_TO_PC_PARAMETERS 0x82 127 | #define RDR_TO_PC_ESCAPE 0x83 128 | #define RDR_TO_PC_DATARATEANDCLOCKFREQUENCY 0x84 129 | 130 | uint8_t CCID_Init(void); 131 | uint8_t CCID_OutEvent(uint8_t *data, uint8_t len); 132 | void CCID_Loop(void); 133 | void CCID_TimeExtensionLoop(void* argc); 134 | uint8_t PC_to_RDR_XfrBlock(void); // Exported for test purposes 135 | 136 | #endif //_CCID_H_ 137 | -------------------------------------------------------------------------------- /main/include/ccid_device.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEVICE_CCID_H_ 2 | #define _DEVICE_CCID_H_ 3 | 4 | #include "tusb.h" 5 | #include "ccid.h" 6 | 7 | #define CFG_TUD_CCID (1) 8 | 9 | #define CFG_TUD_CCID_EP_BUFSIZE 64 10 | 11 | // Starting endpoints; adjusted elsewhere as needed 12 | #define CCID_EPOUT (0x02) 13 | #define CCID_EPIN (0x82) 14 | 15 | #define CCID_HDR_SZ (10) // CCID message header size 16 | #define CCID_DESC_SZ (54) // CCID function descriptor size 17 | #define CCID_DESC_TYPE_CCID (0x21) // CCID Descriptor 18 | 19 | #define CCID_VERSION (0x0110) 20 | #define CCID_IFSD (ABDATA_SIZE) 21 | #define CCID_FEATURES (0x40000 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02) 22 | #define CCID_MSGLEN (CCID_IFSD + CCID_HDR_SZ) 23 | #define CCID_CLAGET (0xFF) 24 | #define CCID_CLAENV (0xFF) 25 | 26 | #define CFG_TUD_CCID_TX_BUFSIZE CCID_MSGLEN*8 27 | #define CFG_TUD_CCID_RX_BUFSIZE CCID_MSGLEN*8 28 | 29 | #define TUD_CCID_DESC_LEN (9 + CCID_DESC_SZ + 7 + 7) 30 | 31 | // CCID Descriptor Template 32 | // Interface number, string index, EP notification address and size, EP data address (out, in) and size. 33 | #define TUD_CCID_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ 34 | /* CCID Interface */\ 35 | 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_SMART_CARD, 0, 0, _stridx,\ 36 | /* CCID Function, version, max slot index, supported voltages and protocols */\ 37 | CCID_DESC_SZ, CCID_DESC_TYPE_CCID, U16_TO_U8S_LE(CCID_VERSION), 0, 0x7, U32_TO_U8S_LE(3),\ 38 | /* default clock, maximum clock, num clocks, current datarate, max datarate */\ 39 | U32_TO_U8S_LE(4000), U32_TO_U8S_LE(5000), 0, U32_TO_U8S_LE(9600), U32_TO_U8S_LE(625000),\ 40 | /* num datarates, max IFSD, sync. protocols, mechanical, features */\ 41 | 0, U32_TO_U8S_LE(CCID_IFSD), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0), U32_TO_U8S_LE(CCID_FEATURES),\ 42 | /* max msg len, get response CLA, envelope CLA, LCD layout, PIN support, max busy slots */\ 43 | U32_TO_U8S_LE(CCID_MSGLEN), CCID_CLAGET, CCID_CLAENV, U16_TO_U8S_LE(0), 0, 1,\ 44 | \ 45 | /* Endpoint Out */\ 46 | 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\ 47 | /* Endpoint In */\ 48 | 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0\ 49 | 50 | 51 | typedef struct { 52 | uint8_t itf_num; 53 | uint8_t ep_in; 54 | uint8_t ep_out; 55 | 56 | tu_fifo_t rx_ff; // nothing is cleared on reset from here on 57 | tu_fifo_t tx_ff; 58 | uint8_t rx_ff_buf[CFG_TUD_CCID_RX_BUFSIZE]; 59 | uint8_t tx_ff_buf[CFG_TUD_CCID_TX_BUFSIZE]; 60 | 61 | CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CCID_EP_BUFSIZE]; 62 | CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CCID_EP_BUFSIZE]; 63 | } ccidd_interface_t; 64 | 65 | TU_ATTR_WEAK void tud_ccid_rx_cb(uint8_t itf); 66 | TU_ATTR_WEAK void tud_ccid_tx_cb(uint8_t itf, uint16_t xferred_bytes); 67 | 68 | bool tud_ccid_n_mounted(uint8_t itf); 69 | uint32_t tud_ccid_n_available(uint8_t itf); 70 | uint32_t tud_ccid_n_read(uint8_t itf, void *buffer, uint32_t bufsize); 71 | uint32_t tud_ccid_n_write(uint8_t itf, void const*buffer, uint32_t bufsize); 72 | uint32_t tud_ccid_write_n_flush(ccidd_interface_t *p_itf); 73 | 74 | static inline uint32_t tud_ccid_read (void* buffer, uint32_t bufsize) 75 | { 76 | return tud_ccid_n_read(0, buffer, bufsize); 77 | } 78 | 79 | static inline uint32_t tud_ccid_write (void const* buffer, uint32_t bufsize) 80 | { 81 | return tud_ccid_n_write(0, buffer, bufsize); 82 | } 83 | 84 | static inline uint32_t tud_ccid_write_flush (void) 85 | { 86 | return tud_ccid_write_n_flush(0); 87 | } 88 | 89 | static inline uint32_t tud_ccid_available(void) { return tud_ccid_n_available(0); } 90 | 91 | static inline bool tud_ccid_mounted(void) { return tud_ccid_n_mounted(0); } 92 | 93 | #endif //_CCID_H_ -------------------------------------------------------------------------------- /main/include/common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_INCLUDE_COMMON_H 3 | #define CANOKEY_CORE_INCLUDE_COMMON_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define APDU_BUFFER_SIZE 1340 13 | 14 | #ifdef DEBUG_OUTPUT 15 | #include 16 | #include 17 | #define DBG_MSG(format, ...) printf("[DBG] %s(%d): " format, __func__, __LINE__, ##__VA_ARGS__) 18 | #define ERR_MSG(format, ...) printf("[ERR] %s(%d): " format, __func__, __LINE__, ##__VA_ARGS__) 19 | #define DBG_KEY_META(meta) printf("[DBG] %s(%d): type: %d, origin: %d, usage: %d, pin: %d, touch: %d\n", __func__, __LINE__, (meta)->type, (meta)->origin, (meta)->usage, (meta)->pin_policy, (meta)->touch_policy); 20 | #define PRINT_HEX(...) print_hex(__VA_ARGS__) 21 | #else 22 | #define DBG_MSG(...) do {} while(0) 23 | #define ERR_MSG(...) do {} while(0) 24 | #define DBG_KEY_META(...) do {} while(0) 25 | #define PRINT_HEX(...) do {} while(0) 26 | #endif 27 | 28 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 29 | #define htobe32(x) (x) 30 | #define htobe16(x) (x) 31 | #define letoh32(x) __builtin_bswap32(x) 32 | #define htole32(x) __builtin_bswap32(x) 33 | #define be32toh(x) (x) 34 | #else 35 | #define htobe32(x) __builtin_bswap32(x) 36 | #define htobe16(x) __builtin_bswap16(x) 37 | #define letoh32(x) (x) 38 | #define htole32(x) (x) 39 | #define be32toh(x) __builtin_bswap32(x) 40 | #endif 41 | 42 | #define LO(x) ((uint8_t)((x)&0x00FF)) 43 | #define HI(x) ((uint8_t)(((x)&0xFF00) >> 8)) 44 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 45 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 46 | #define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0) 47 | 48 | #define UNUSED(x) ((void)(x)) 49 | #define __weak __attribute__((weak)) 50 | //#define __packed __attribute__((packed)) 51 | 52 | 53 | // get length of tlv with bounds checking 54 | uint16_t tlv_get_length_safe(const uint8_t *data, const size_t len, int *fail, size_t *length_size); 55 | 56 | /** 57 | * Fill a 4-byte serial number 58 | * @param buf buffer to be filled 59 | */ 60 | void fill_sn(uint8_t *buf); 61 | 62 | #endif // CANOKEY_CORE_INCLUDE_COMMON_H 63 | -------------------------------------------------------------------------------- /main/include/ctap.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_FIDO2_FIDO2_H_ 3 | #define CANOKEY_CORE_FIDO2_FIDO2_H_ 4 | 5 | #include 6 | #include 7 | 8 | uint8_t ctap_install(uint8_t reset); 9 | int ctap_install_private_key(const CAPDU *capdu, RAPDU *rapdu); 10 | int ctap_install_cert(const CAPDU *capdu, RAPDU *rapdu); 11 | int ctap_read_sm2_config(const CAPDU *capdu, RAPDU *rapdu); 12 | int ctap_write_sm2_config(const CAPDU *capdu, RAPDU *rapdu); 13 | int ctap_process_cbor(uint8_t *req, size_t req_len, uint8_t *resp, size_t *resp_len); 14 | int ctap_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 15 | int ctap_wink(void); 16 | 17 | #endif // CANOKEY_CORE_FIDO2_FIDO2_H_ 18 | -------------------------------------------------------------------------------- /main/include/ctaphid.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef __CTAPHID_H_INCLUDED__ 3 | #define __CTAPHID_H_INCLUDED__ 4 | 5 | #include 6 | 7 | #define HID_RPT_SIZE 64 // Default size of raw HID report 8 | 9 | // Frame layout - command- and continuation frames 10 | 11 | #define CID_BROADCAST 0xffffffff // Broadcast channel id 12 | #define TYPE_MASK 0x80 // Frame type mask 13 | #define TYPE_INIT 0x80 // Initial frame identifier 14 | #define TYPE_CONT 0x00 // Continuation frame identifier 15 | 16 | typedef struct { 17 | uint32_t cid; // Channel identifier 18 | union { 19 | uint8_t type; // Frame type - b7 defines type 20 | struct { 21 | uint8_t cmd; // Command - b7 set 22 | uint8_t bcnth; // Message byte count - high part 23 | uint8_t bcntl; // Message byte count - low part 24 | uint8_t data[HID_RPT_SIZE - 7]; // Data payload 25 | } init; 26 | struct { 27 | uint8_t seq; // Sequence number - b7 cleared 28 | uint8_t data[HID_RPT_SIZE - 5]; // Data payload 29 | } cont; 30 | }; 31 | } CTAPHID_FRAME; 32 | 33 | #define FRAME_TYPE(f) ((f).type & TYPE_MASK) 34 | #define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) 35 | #define MSG_LEN(f) ((f).init.bcnth * 256 + (f).init.bcntl) 36 | #define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) 37 | 38 | // General constants 39 | 40 | #define CTAPHID_IF_VERSION 2 // Current interface implementation version 41 | #define CTAPHID_TRANS_TIMEOUT 800 // Default message timeout in ms 42 | 43 | // CTAPHID native commands 44 | 45 | #define CTAPHID_PING (TYPE_INIT | 0x01) 46 | #define CTAPHID_MSG (TYPE_INIT | 0x03) 47 | #define CTAPHID_LOCK (TYPE_INIT | 0x04) 48 | #define CTAPHID_INIT (TYPE_INIT | 0x06) 49 | #define CTAPHID_WINK (TYPE_INIT | 0x08) 50 | #define CTAPHID_CBOR (TYPE_INIT | 0x10) 51 | #define CTAPHID_CANCEL (TYPE_INIT | 0x11) 52 | #define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3b) 53 | #define CTAPHID_ERROR (TYPE_INIT | 0x3f) 54 | 55 | // CTAPHID_INIT command defines 56 | 57 | #define INIT_NONCE_SIZE 8 // Size of channel initialization challenge 58 | 59 | #define CAPABILITY_WINK 0x01 60 | #define CAPABILITY_CBOR 0x04 61 | #define CAPABILITY_NMSG 0x08 62 | 63 | typedef struct { 64 | uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce 65 | } CTAPHID_INIT_REQ; 66 | 67 | typedef struct { 68 | uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce 69 | uint32_t cid; // Channel identifier 70 | uint8_t versionInterface; // Interface version 71 | uint8_t versionMajor; // Major version number 72 | uint8_t versionMinor; // Minor version number 73 | uint8_t versionBuild; // Build version number 74 | uint8_t capFlags; // Capabilities flags 75 | } __packed CTAPHID_INIT_RESP; 76 | 77 | // Low-level error codes. Return as negatives. 78 | 79 | #define ERR_NONE 0x00 // No error 80 | #define ERR_INVALID_CMD 0x01 // Invalid command 81 | #define ERR_INVALID_PAR 0x02 // Invalid parameter 82 | #define ERR_INVALID_LEN 0x03 // Invalid message length 83 | #define ERR_INVALID_SEQ 0x04 // Invalid message sequencing 84 | #define ERR_MSG_TIMEOUT 0x05 // Message has timed out 85 | #define ERR_CHANNEL_BUSY 0x06 // Channel busy 86 | #define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock 87 | #define ERR_INVALID_CID 0x0b 88 | #define ERR_OTHER 0x7f // Other unspecified error 89 | 90 | #define KEEPALIVE_STATUS_PROCESSING 1 91 | #define KEEPALIVE_STATUS_UPNEEDED 2 92 | 93 | #define LOOP_SUCCESS 0x00 94 | #define LOOP_CANCEL 0x01 95 | 96 | #define MAX_CTAP_BUFSIZE 1300 97 | 98 | typedef struct { 99 | uint32_t cid; 100 | uint16_t bcnt_total; 101 | uint16_t bcnt_current; 102 | uint32_t expire; 103 | uint8_t state; 104 | uint8_t cmd; 105 | uint8_t seq; 106 | uint8_t data[MAX_CTAP_BUFSIZE]; 107 | } CTAPHID_Channel; 108 | 109 | uint8_t CTAPHID_Init(void); 110 | uint8_t CTAPHID_OutEvent(uint8_t *data); 111 | void CTAPHID_SendKeepAlive(uint8_t status); 112 | uint8_t CTAPHID_Loop(uint8_t wait_for_user); 113 | 114 | #endif // __CTAPHID_H_INCLUDED__ 115 | -------------------------------------------------------------------------------- /main/include/device-config-default.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef __DEVICE_CONFIG_DEFAULT__H__ 3 | #define __DEVICE_CONFIG_DEFAULT__H__ 4 | 5 | #define USB_MAX_EP0_SIZE 16 6 | 7 | #endif /* __DEVICE_CONFIG_DEFAULT__H__ */ 8 | -------------------------------------------------------------------------------- /main/include/device.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | #ifndef _DEVICE_H_ 4 | #define _DEVICE_H_ 5 | 6 | #include "common.h" 7 | #include 8 | #include "spinlock.h" 9 | 10 | #define TOUCH_NO 0 11 | #define TOUCH_SHORT 1 12 | #define TOUCH_LONG 2 13 | 14 | #define USER_PRESENCE_OK 0 15 | #define USER_PRESENCE_CANCEL 1 16 | #define USER_PRESENCE_TIMEOUT 2 17 | 18 | #define WAIT_ENTRY_CCID 0 19 | #define WAIT_ENTRY_CTAPHID 1 20 | 21 | // CCID Bulk State machine 22 | #define CCID_STATE_IDLE 0 23 | #define CCID_STATE_RECEIVE_DATA 1 24 | #define CCID_STATE_DATA_IN 2 25 | #define CCID_STATE_DATA_IN_WITH_ZLP 3 26 | #define CCID_STATE_PROCESS_DATA 4 27 | 28 | typedef enum { CTAPHID_IDLE = 0, CTAPHID_BUSY } CTAPHID_StateTypeDef; 29 | 30 | // functions should be implemented by device 31 | /** 32 | * Delay processing for specific milliseconds 33 | * 34 | * @param ms Time to delay 35 | */ 36 | void device_delay(int ms); 37 | uint32_t device_get_tick(void); 38 | 39 | /** 40 | * Get a spinlock. 41 | * 42 | * @param lock The lock handler, which should be pointed to a uint32_t variable. 43 | * @param blocking If we should wait the lock to be released. 44 | * 45 | * @return 0 for locking successfully, -1 for failure. 46 | */ 47 | int device_spinlock_lock(spinlock_t *lock, uint32_t blocking); 48 | 49 | /** 50 | * Unlock the specific handler. 51 | * 52 | * @param lock The lock handler. 53 | */ 54 | void device_spinlock_unlock(spinlock_t *lock); 55 | 56 | /** 57 | * Update the value of a variable atomically. 58 | * 59 | * @param var The address of variable to update. 60 | * @param expect The current value of variable. 61 | * @param var The new value of variable. 62 | */ 63 | int device_atomic_compare_and_swap(volatile uint32_t *var, uint32_t expect, uint32_t update); 64 | 65 | void led_on(void); 66 | void led_off(void); 67 | void device_set_timeout(void (*callback)(void*), uint16_t timeout); 68 | 69 | // NFC related 70 | /** 71 | * Enable FM chip by pull down CSN 72 | */ 73 | void fm_csn_low(void); 74 | 75 | /** 76 | * Disable FM chip by pull up CSN 77 | */ 78 | void fm_csn_high(void); 79 | #if NFC_CHIP == NFC_CHIP_FM11NC 80 | void spi_transmit(const uint8_t *buf, uint8_t len); 81 | void spi_receive(uint8_t *buf, uint8_t len); 82 | #elif NFC_CHIP == NFC_CHIP_FM11NT 83 | void i2c_start(void); 84 | void i2c_stop(void); 85 | void scl_delay(void); 86 | uint8_t i2c_read_ack(void); 87 | void i2c_send_ack(void); 88 | void i2c_send_nack(void); 89 | void i2c_write_byte(uint8_t data); 90 | uint8_t i2c_read_byte(void); 91 | #endif 92 | 93 | // only for test 94 | int testmode_emulate_user_presence(void); 95 | int testmode_get_is_nfc_mode(void); 96 | void testmode_set_initial_ticks(uint32_t ticks); 97 | void testmode_inject_error(uint8_t p1, uint8_t p2, uint16_t len, const uint8_t *data); 98 | bool testmode_err_triggered(const char* filename, bool file_wr); 99 | 100 | // ----------------------------------------------------------------------------------- 101 | 102 | // platform independent functions 103 | uint8_t wait_for_user_presence(uint8_t entry); 104 | int strong_user_presence_test(void); 105 | int send_keepalive_during_processing(uint8_t entry); 106 | void device_loop(uint8_t has_touch); 107 | uint8_t is_nfc(void); 108 | void set_nfc_state(uint8_t state); 109 | uint8_t get_touch_result(void); 110 | void set_touch_result(uint8_t result); 111 | void device_update_led_btn(void *pvParam); 112 | /** 113 | * Blink for several time 114 | * @param sec duration, 0 for infinite 115 | * @param interval controls blinking frequency 116 | */ 117 | void start_blinking_interval(uint8_t sec, uint32_t interval); 118 | static inline void start_blinking(uint8_t sec) { 119 | if (!is_nfc()) start_blinking_interval(sec, 200); 120 | } 121 | static inline void start_quick_blinking(uint8_t sec) { 122 | if (!is_nfc()) start_blinking_interval(sec, 25); 123 | } 124 | void stop_blinking(void); 125 | uint8_t device_is_blinking(void); 126 | 127 | void device_init(void); 128 | void device_recv_data(uint8_t const* data,uint16_t len); 129 | void device_loop(uint8_t has_touch); 130 | void device_send_response(uint8_t *data, uint8_t len); 131 | void device_get_aaguid(uint8_t *data, uint8_t len); 132 | 133 | #endif 134 | 135 | -------------------------------------------------------------------------------- /main/include/fs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_INCLUDE_FS_H 3 | #define CANOKEY_CORE_INCLUDE_FS_H 4 | 5 | #include 6 | 7 | #define LFS_CACHE_SIZE 512 8 | 9 | int fs_format(const struct lfs_config *cfg); 10 | int fs_mount(const struct lfs_config *cfg); 11 | int read_file(const char *path, void *buf, lfs_soff_t off, lfs_size_t len); 12 | int write_file(const char *path, const void *buf, lfs_soff_t off, lfs_size_t len, uint8_t trunc); 13 | int append_file(const char *path, const void *buf, lfs_size_t len); 14 | int truncate_file(const char *path, lfs_size_t len); 15 | int read_attr(const char *path, uint8_t attr, void *buf, lfs_size_t len); 16 | int write_attr(const char *path, uint8_t attr, const void *buf, lfs_size_t len); 17 | int get_file_size(const char *path); 18 | int fs_rename(const char *old, const char *new); 19 | 20 | /** 21 | * Get the total size (in KiB) of the file system. 22 | * 23 | * @return The total file system size. 24 | */ 25 | int get_fs_size(void); 26 | 27 | /** 28 | * Get the used size (in KiB) of the file system. 29 | * 30 | * @return The used file system size. 31 | */ 32 | int get_fs_usage(void); 33 | 34 | #endif // CANOKEY_CORE_INCLUDE_FS_H 35 | -------------------------------------------------------------------------------- /main/include/key.h: -------------------------------------------------------------------------------- 1 | #ifndef CANOKEY_CORE_KEY_H 2 | #define CANOKEY_CORE_KEY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define KEY_ERR_LENGTH (-1) 10 | #define KEY_ERR_DATA (-2) 11 | #define KEY_ERR_PROC (-3) 12 | 13 | typedef enum { 14 | SIGN = 0x01, 15 | ENCRYPT = 0x02, 16 | KEY_AGREEMENT = 0x04, 17 | } key_usage_t; 18 | 19 | typedef enum { 20 | KEY_ORIGIN_NOT_PRESENT = 0x00, 21 | KEY_ORIGIN_GENERATED = 0x01, 22 | KEY_ORIGIN_IMPORTED = 0x02, 23 | } key_origin_t; 24 | 25 | typedef enum { 26 | PIN_POLICY_NEVER = 0x01, 27 | PIN_POLICY_ONCE = 0x02, 28 | PIN_POLICY_ALWAYS = 0x03, 29 | } pin_policy_t; 30 | 31 | typedef enum { 32 | TOUCH_POLICY_DEFAULT = 0x00, // disabled in both OpenPGP and PIV 33 | TOUCH_POLICY_NEVER = 0x01, // not used in OpenPGP; the same as default in PIV 34 | TOUCH_POLICY_ALWAYS = 0x02, // not used in OpenPGP; enabled in PIV without cache 35 | TOUCH_POLICY_CACHED = 0x03, // enabled in OpenPGP; enabled in PIV with cache 36 | TOUCH_POLICY_PERMANENT = 0x04, // permanently enabled in OpenPGP; not used in PIV 37 | } touch_policy_t; 38 | 39 | typedef struct { 40 | key_type_t type; 41 | key_origin_t origin; 42 | key_usage_t usage; 43 | pin_policy_t pin_policy; 44 | touch_policy_t touch_policy; 45 | } key_meta_t; 46 | 47 | typedef struct { 48 | key_meta_t meta; 49 | union { 50 | rsa_key_t rsa; 51 | ecc_key_t ecc; 52 | uint8_t data[0]; 53 | }; 54 | } ck_key_t; 55 | 56 | 57 | /** 58 | * Encode public key 59 | * 60 | * @param key key type 61 | * @param buf buffer 62 | * @param include_length encode the length or not 63 | * @return encoded length 64 | */ 65 | int ck_encode_public_key(ck_key_t *key, uint8_t *buf, bool include_length); 66 | 67 | /** 68 | * Parse the key imported to PIV 69 | * 70 | * @param key parsed key. origin will be set to KEY_ORIGIN_IMPORTED. 71 | * @param buf data buffer that contains the key 72 | * @param buf_len data buffer length 73 | * @return 0 for success. Negative values for errors. 74 | */ 75 | int ck_parse_piv(ck_key_t *key, const uint8_t *buf, size_t buf_len); 76 | 77 | int ck_parse_piv_policies(ck_key_t *key, const uint8_t *buf, size_t buf_len); 78 | 79 | int ck_parse_openpgp(ck_key_t *key, const uint8_t *buf, size_t buf_len); 80 | 81 | int ck_read_key_metadata(const char *path, key_meta_t *meta); 82 | 83 | int ck_write_key_metadata(const char *path, const key_meta_t *meta); 84 | 85 | int ck_read_key(const char *path, ck_key_t *key); 86 | 87 | int ck_write_key(const char *path, const ck_key_t *key); 88 | 89 | int ck_generate_key(ck_key_t *key); 90 | 91 | int ck_sign(const ck_key_t *key, const uint8_t *input, size_t input_len, uint8_t *sig); 92 | 93 | #endif // CANOKEY_CORE_KEY_H 94 | -------------------------------------------------------------------------------- /main/include/meta.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_INCLUDE_META_H 3 | #define CANOKEY_CORE_INCLUDE_META_H 4 | 5 | #include 6 | 7 | #define META_INS_SELECT 0xA4 8 | #define META_INS_READ_META 0x1D 9 | 10 | int meta_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 11 | 12 | #endif // CANOKEY_CORE_INCLUDE_META_H 13 | -------------------------------------------------------------------------------- /main/include/ndef.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_INCLUDE_NDEF_H 3 | #define CANOKEY_CORE_INCLUDE_NDEF_H 4 | 5 | #include 6 | 7 | #define NDEF_INS_SELECT 0xA4 8 | #define NDEF_INS_READ_BINARY 0xB0 9 | #define NDEF_INS_UPDATE 0xD6 10 | 11 | void ndef_poweroff(void); 12 | int ndef_install(uint8_t reset); 13 | int ndef_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 14 | int ndef_get_read_only(void); 15 | int ndef_toggle_read_only(const CAPDU *capdu, RAPDU *rapdu); 16 | 17 | #endif // CANOKEY_CORE_INCLUDE_NDEF_H 18 | -------------------------------------------------------------------------------- /main/include/nfc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef _NFC_H_ 3 | #define _NFC_H_ 4 | 5 | #define NFC_CHIP_FM11NC 0 6 | #define NFC_CHIP_FM11NT 1 7 | #define NFC_CHIP_NA -1 8 | 9 | #ifndef NFC_CHIP 10 | #define NFC_CHIP NFC_CHIP_NA 11 | #endif 12 | 13 | #if NFC_CHIP == NFC_CHIP_FM11NC 14 | 15 | #define FM_REG_FIFO_FLUSH 0x1 16 | #define FM_REG_FIFO_WORDCNT 0x2 17 | #define FM_REG_RF_STATUS 0x3 18 | #define FM_REG_RF_TXEN 0x4 19 | #define FM_REG_RF_BAUD 0x5 20 | #define FM_REG_RF_RATS 0x6 21 | #define FM_REG_MAIN_IRQ 0x7 22 | #define FM_REG_FIFO_IRQ 0x8 23 | #define FM_REG_AUX_IRQ 0x9 24 | #define FM_REG_MAIN_IRQ_MASK 0xA 25 | #define FM_REG_FIFO_IRQ_MASK 0xB 26 | #define FM_REG_AUX_IRQ_MASK 0xC 27 | #define FM_REG_NFC_CFG 0xD 28 | #define FM_REG_REGU_CFG 0xE 29 | 30 | #define FM_EEPROM_ATQA 0x03A0 31 | #define FM_EEPROM_ATS 0x03B0 32 | 33 | #define RF_STATE_MASK 0xE0 34 | 35 | #elif NFC_CHIP == NFC_CHIP_FM11NT 36 | 37 | #define FM_REG_USER_CFG0 0xFFE0 38 | #define FM_REG_USER_CFG1 0xFFE1 39 | #define FM_REG_USER_CFG2 0xFFE2 40 | #define FM_REG_RESET_SILENCE 0xFFE6 41 | #define FM_REG_STATUS 0xFFE7 42 | #define FM_REG_VOUT_EN_CFG 0xFFE9 43 | #define FM_REG_VOUT_RES_CFG 0xFFEA 44 | #define FM_REG_FIFO_ACCESS 0xFFF0 45 | #define FM_REG_FIFO_FLUSH 0xFFF1 46 | #define FM_REG_FIFO_WORDCNT 0xFFF2 47 | #define FM_REG_RF_STATUS 0xFFF3 48 | #define FM_REG_RF_TXEN 0xFFF4 49 | #define FM_REG_RF_CFG 0xFFF5 50 | #define FM_REG_RF_RATS 0xFFF6 51 | #define FM_REG_MAIN_IRQ 0xFFF7 52 | #define FM_REG_FIFO_IRQ 0xFFF8 53 | #define FM_REG_AUX_IRQ 0xFFF9 54 | #define FM_REG_MAIN_IRQ_MASK 0xFFFA 55 | #define FM_REG_FIFO_IRQ_MASK 0xFFFB 56 | #define FM_REG_AUX_IRQ_MASK 0xFFFC 57 | 58 | #define FM_EEPROM_SN 0x0000 59 | #define FM_EEPROM_USER_CFG0 0x0390 60 | #define FM_EEPROM_USER_CFG1 0x0391 61 | #define FM_EEPROM_USER_CFG2 0x0392 62 | #define FM_EEPROM_ATS 0x03B0 63 | #define FM_EEPROM_ATQA 0x03BC 64 | #define FM_EEPROM_CRC8 0x03BB 65 | 66 | #endif 67 | 68 | #define MAIN_IRQ_AUX (1 << 0) 69 | #define MAIN_IRQ_FIFO (1 << 1) 70 | #define MAIN_IRQ_ARBIT (1 << 2) 71 | #define MAIN_IRQ_TX_DONE (1 << 3) 72 | #define MAIN_IRQ_RX_DONE (1 << 4) 73 | #define MAIN_IRQ_RX_START (1 << 5) 74 | #define MAIN_IRQ_ACTIVE (1 << 6) 75 | #define MAIN_IRQ_RF_ON (1 << 7) 76 | 77 | #define FIFO_IRQ_OVERFLOW (1 << 2) 78 | #define FIFO_IRQ_WATER_LEVEL (1 << 3) 79 | 80 | #define AUX_IRQ_ERROR_MASK 0x78 81 | 82 | #define PCB_MASK 0xC0 83 | #define PCB_I_BLOCK 0x00 84 | #define PCB_R_BLOCK 0x80 85 | #define PCB_S_BLOCK 0xC0 86 | #define PCB_I_CHAINING 0x10 87 | 88 | #define R_BLOCK_MASK 0xB2 89 | #define R_ACK 0xA2 90 | #define R_NAK 0xB2 91 | 92 | #define S_WTX 0xF2 93 | 94 | #define NFC_STATE_IDLE 0x00 95 | #define NFC_STATE_BUSY 0x01 96 | 97 | void nfc_init(void); 98 | void nfc_handler(void); 99 | void nfc_loop(void); 100 | 101 | #endif // _NFC_H_ 102 | -------------------------------------------------------------------------------- /main/include/oath.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_OATH_OATH_H_ 3 | #define CANOKEY_CORE_OATH_OATH_H_ 4 | 5 | #include 6 | 7 | #define ATTR_DEFAULT_RECORD 0x01 8 | #define ATTR_KEY 0x02 9 | #define ATTR_HANDLE 0x03 10 | 11 | #define OATH_TAG_NAME 0x71 12 | #define OATH_TAG_NAME_LIST 0x72 13 | #define OATH_TAG_KEY 0x73 14 | #define OATH_TAG_CHALLENGE 0x74 15 | #define OATH_TAG_FULL_RESPONSE 0x75 16 | #define OATH_TAG_RESPONSE 0x76 17 | #define OATH_TAG_NO_RESP 0x77 18 | #define OATH_TAG_PROPERTY 0x78 19 | #define OATH_TAG_VERSION 0x79 20 | #define OATH_TAG_COUNTER 0x7A 21 | #define OATH_TAG_ALGORITHM 0x7B 22 | #define OATH_TAG_REQ_TOUCH 0x7C 23 | 24 | #define OATH_INS_PUT 0x01 25 | #define OATH_INS_DELETE 0x02 26 | #define OATH_INS_SET_CODE 0x03 27 | #define OATH_INS_RENAME 0x05 28 | #define OATH_INS_LIST 0xA1 29 | #define OATH_INS_CALCULATE 0xA2 30 | #define OATH_INS_VALIDATE 0xA3 31 | #define OATH_INS_SELECT 0xA4 32 | #define OATH_INS_SEND_REMAINING 0xA5 33 | #define OATH_INS_SET_DEFAULT 0x55 34 | 35 | #define OATH_ALG_MASK 0x0F 36 | #define OATH_ALG_SHA1 0x01 37 | #define OATH_ALG_SHA256 0x02 38 | #define OATH_ALG_SHA512 0x03 39 | 40 | #define OATH_TYPE_MASK 0xF0 41 | #define OATH_TYPE_HOTP 0x10 42 | #define OATH_TYPE_TOTP 0x20 43 | 44 | #define OATH_PROP_INC 0x01 45 | #define OATH_PROP_TOUCH 0x02 46 | #define OATH_PROP_ALL_FLAGS 0x03 // OR of flags above 47 | 48 | #define MAX_NAME_LEN 64 49 | #define MAX_KEY_LEN 66 // 64 + 2 for algo & digits 50 | #define MAX_CHALLENGE_LEN 8 51 | #define HANDLE_LEN 8 52 | #define KEY_LEN 16 53 | 54 | typedef struct { 55 | uint8_t name_len; 56 | uint8_t name[MAX_NAME_LEN]; 57 | uint8_t key_len; 58 | // Byte 0 is type(higher half)/algorithm(lower half). 59 | // Byte 1 is number of digits. 60 | // Remaining is the secret. 61 | uint8_t key[MAX_KEY_LEN]; 62 | uint8_t prop; 63 | uint8_t challenge[MAX_CHALLENGE_LEN]; 64 | } __packed OATH_RECORD; 65 | 66 | void oath_poweroff(void); 67 | int oath_install(uint8_t reset); 68 | int oath_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 69 | int oath_process_one_touch(char *output, size_t maxlen); 70 | 71 | #endif // CANOKEY_CORE_OATH_OATH_H_ 72 | -------------------------------------------------------------------------------- /main/include/openpgp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_OPENPGP_OPENPGP_H 3 | #define CANOKEY_CORE_OPENPGP_OPENPGP_H 4 | 5 | #include 6 | 7 | #define OPENPGP_INS_SELECT 0xA4 8 | #define OPENPGP_INS_SELECT_DATA 0xA5 9 | #define OPENPGP_INS_GET_DATA 0xCA 10 | #define OPENPGP_INS_GET_NEXT_DATA 0xCC 11 | #define OPENPGP_INS_VERIFY 0x20 12 | #define OPENPGP_INS_CHANGE_REFERENCE_DATA 0x24 13 | #define OPENPGP_INS_RESET_RETRY_COUNTER 0x2C 14 | #define OPENPGP_INS_INTERNAL_AUTHENTICATE 0x88 15 | #define OPENPGP_INS_PSO 0x2A 16 | #define OPENPGP_INS_PUT_DATA 0xDA 17 | #define OPENPGP_INS_IMPORT_KEY 0xDB 18 | #define OPENPGP_INS_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 19 | #define OPENPGP_INS_TERMINATE 0xE6 20 | #define OPENPGP_INS_ACTIVATE 0x44 21 | 22 | #define TAG_AID 0x4F 23 | #define TAG_LOGIN 0x5E 24 | #define TAG_URL 0x5F50 25 | #define TAG_HISTORICAL_BYTES 0x5F52 26 | #define TAG_CARDHOLDER_RELATED_DATA 0x65 27 | #define TAG_NAME 0x5B 28 | #define TAG_LANG 0x5F2D 29 | #define TAG_SEX 0x5F35 30 | #define TAG_APPLICATION_RELATED_DATA 0x6E 31 | #define TAG_DISCRETIONARY_DATA_OBJECTS 0x73 32 | #define TAG_EXTENDED_CAPABILITIES 0xC0 33 | #define TAG_ALGORITHM_ATTRIBUTES_SIG 0xC1 34 | #define TAG_ALGORITHM_ATTRIBUTES_DEC 0xC2 35 | #define TAG_ALGORITHM_ATTRIBUTES_AUT 0xC3 36 | #define TAG_PW_STATUS 0xC4 37 | #define TAG_KEY_FINGERPRINTS 0xC5 38 | #define TAG_CA_FINGERPRINTS 0xC6 39 | #define TAG_KEY_SIG_FINGERPRINT 0xC7 40 | #define TAG_KEY_DEC_FINGERPRINT 0xC8 41 | #define TAG_KEY_AUT_FINGERPRINT 0xC9 42 | #define TAG_KEY_CA1_FINGERPRINT 0xCA 43 | #define TAG_KEY_CA2_FINGERPRINT 0xCB 44 | #define TAG_KEY_CA3_FINGERPRINT 0xCC 45 | #define TAG_KEY_GENERATION_DATES 0xCD 46 | #define TAG_KEY_SIG_GENERATION_DATES 0xCE 47 | #define TAG_KEY_DEC_GENERATION_DATES 0xCF 48 | #define TAG_KEY_AUT_GENERATION_DATES 0xD0 49 | #define TAG_RESETTING_CODE 0xD3 50 | #define TAG_SECURITY_SUPPORT_TEMPLATE 0x7A 51 | #define TAG_DIGITAL_SIG_COUNTER 0x93 52 | #define TAG_CARDHOLDER_CERTIFICATE 0x7F21 53 | #define TAG_EXTENDED_LENGTH_INFO 0x7F66 54 | #define TAG_GENERAL_FEATURE_MANAGEMENT 0x7F74 55 | #define TAG_KEY_INFO 0xDE 56 | #define TAG_ALGORITHM_INFORMATION 0xFA 57 | #define TAG_UIF_SIG 0xD6 58 | #define TAG_UIF_DEC 0xD7 59 | #define TAG_UIF_AUT 0xD8 60 | #define TAG_UIF_CACHE_TIME 0x0102 61 | 62 | void openpgp_poweroff(void); 63 | int openpgp_install(uint8_t reset); 64 | int openpgp_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 65 | 66 | #endif // CANOKEY_CORE_OPENPGP_OPENPGP_H 67 | -------------------------------------------------------------------------------- /main/include/pin.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_SRC_PIN_H 3 | #define CANOKEY_CORE_SRC_PIN_H 4 | 5 | #include 6 | 7 | typedef struct { 8 | uint8_t min_length; 9 | uint8_t max_length; 10 | uint8_t is_validated; 11 | char path[]; 12 | } pin_t; 13 | 14 | #define PIN_IO_FAIL -1 15 | #define PIN_AUTH_FAIL -2 16 | #define PIN_LENGTH_INVALID -3 17 | #define PIN_MAX_LENGTH 64 18 | 19 | int pin_create(const pin_t *pin, const void *buf, uint8_t len, 20 | uint8_t max_retries); 21 | int pin_verify(pin_t *pin, const void *buf, uint8_t len, uint8_t *retries); 22 | int pin_update(pin_t *pin, const void *buf, uint8_t len); 23 | int pin_get_size(const pin_t *pin); 24 | int pin_get_retries(const pin_t *pin); 25 | int pin_get_default_retries(const pin_t *pin); 26 | int pin_clear(const pin_t *pin); 27 | 28 | #endif // CANOKEY_CORE_SRC_PIN_H 29 | -------------------------------------------------------------------------------- /main/include/piv.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 */ 2 | #ifndef CANOKEY_CORE_INCLUDE_PIV_H_ 3 | #define CANOKEY_CORE_INCLUDE_PIV_H_ 4 | 5 | #include 6 | 7 | #define PIV_INS_VERIFY 0x20 8 | #define PIV_INS_CHANGE_REFERENCE_DATA 0x24 9 | #define PIV_INS_RESET_RETRY_COUNTER 0x2C 10 | #define PIV_INS_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 11 | #define PIV_INS_GENERAL_AUTHENTICATE 0x87 12 | #define PIV_INS_SELECT 0xA4 13 | #define PIV_INS_GET_DATA_RESPONSE 0xC0 14 | #define PIV_INS_GET_DATA 0xCB 15 | #define PIV_INS_PUT_DATA 0xDB 16 | #define PIV_INS_GET_METADATA 0xF7 17 | #define PIV_INS_GET_SERIAL 0xF8 18 | #define PIV_INS_RESET 0xFB 19 | #define PIV_INS_GET_VERSION 0xFD 20 | #define PIV_INS_IMPORT_ASYMMETRIC_KEY 0xFE 21 | #define PIV_INS_SET_MANAGEMENT_KEY 0xFF 22 | 23 | #define PIV_INS_ALGORITHM_EXTENSION 0xEE 24 | 25 | typedef struct { 26 | uint8_t enabled; 27 | uint8_t ed25519; 28 | uint8_t rsa3072; 29 | uint8_t rsa4096; 30 | uint8_t x25519; 31 | uint8_t secp256k1; 32 | uint8_t sm2; 33 | } __packed piv_algorithm_extension_config_t; 34 | 35 | int piv_install(uint8_t reset); 36 | void piv_poweroff(void); 37 | int piv_process_apdu(const CAPDU *capdu, RAPDU *rapdu); 38 | 39 | #endif // CANOKEY_CORE_INCLUDE_PIV_H_ 40 | -------------------------------------------------------------------------------- /main/key.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include "ecc.h" 3 | #include "memzero.h" 4 | #include 5 | #include 6 | 7 | #define KEY_META_ATTR 0xFF 8 | #define CEIL_DIV_SQRT2 0xB504F334 9 | #define MAX_KEY_TEMPLATE_LENGTH 0x16 10 | 11 | int ck_encode_public_key(ck_key_t *key, uint8_t *buf, bool include_length) { 12 | int off = 0; 13 | 14 | switch (key->meta.type) { 15 | case SECP256R1: 16 | case SECP256K1: 17 | case SECP384R1: 18 | case SM2: 19 | if (include_length) { 20 | buf[off++] = PUBLIC_KEY_LENGTH[key->meta.type] + 3; // tag, length, and 0x04 21 | } 22 | buf[off++] = 0x86; 23 | buf[off++] = PUBLIC_KEY_LENGTH[key->meta.type] + 1; // 0x04 24 | buf[off++] = 0x04; 25 | memcpy(&buf[off], key->ecc.pub, PUBLIC_KEY_LENGTH[key->meta.type]); 26 | off += PUBLIC_KEY_LENGTH[key->meta.type]; 27 | break; 28 | 29 | case ED25519: 30 | case X25519: 31 | if (include_length) { 32 | buf[off++] = PUBLIC_KEY_LENGTH[key->meta.type] + 2; // tag, length 33 | } 34 | buf[off++] = 0x86; 35 | buf[off++] = PUBLIC_KEY_LENGTH[key->meta.type]; 36 | memcpy(&buf[off], key->ecc.pub, PUBLIC_KEY_LENGTH[key->meta.type]); 37 | if (key->meta.type == X25519) { 38 | swap_big_number_endian(&buf[off]); // Public key of x25519 is encoded in little endian 39 | } 40 | off += PUBLIC_KEY_LENGTH[key->meta.type]; 41 | break; 42 | 43 | case RSA2048: 44 | case RSA3072: 45 | case RSA4096: 46 | if (include_length) { // 3-byte length 47 | buf[off++] = 0x82; 48 | // 6 = modulus: tag (1), length (3); exponent: tag (1), length (1) 49 | buf[off++] = HI(6 + PUBLIC_KEY_LENGTH[key->meta.type] + E_LENGTH); 50 | buf[off++] = LO(6 + PUBLIC_KEY_LENGTH[key->meta.type] + E_LENGTH); 51 | } 52 | buf[off++] = 0x81; // modulus 53 | buf[off++] = 0x82; 54 | buf[off++] = HI(PUBLIC_KEY_LENGTH[key->meta.type]); 55 | buf[off++] = LO(PUBLIC_KEY_LENGTH[key->meta.type]); 56 | rsa_get_public_key(&key->rsa, &buf[off]); 57 | off += PUBLIC_KEY_LENGTH[key->meta.type]; 58 | buf[off++] = 0x82; // exponent 59 | buf[off++] = E_LENGTH; 60 | memcpy(&buf[off], key->rsa.e, E_LENGTH); 61 | off += E_LENGTH; 62 | break; 63 | 64 | default: 65 | return -1; 66 | } 67 | 68 | return off; 69 | } 70 | 71 | int ck_parse_piv_policies(ck_key_t *key, const uint8_t *buf, size_t buf_len) { 72 | const uint8_t *end = buf + buf_len; 73 | 74 | while (buf < end) { 75 | switch (*buf++) { 76 | case 0xAA: 77 | DBG_MSG("May have pin policy\n"); 78 | if (buf < end && *buf++ != 0x01) { 79 | DBG_MSG("Wrong length for pin policy\n"); 80 | return KEY_ERR_LENGTH; 81 | } 82 | if (buf < end && (*buf > PIN_POLICY_ALWAYS || *buf < PIN_POLICY_NEVER)) { 83 | DBG_MSG("Wrong data for pin policy\n"); 84 | return KEY_ERR_DATA; 85 | } 86 | key->meta.pin_policy = *buf++; 87 | break; 88 | 89 | case 0xAB: 90 | DBG_MSG("May have touch policy\n"); 91 | if (buf < end && *buf++ != 0x01) { 92 | DBG_MSG("Wrong length for touch policy\n"); 93 | return KEY_ERR_LENGTH; 94 | } 95 | if (buf < end && (*buf > TOUCH_POLICY_CACHED || *buf < TOUCH_POLICY_NEVER)) { 96 | DBG_MSG("Wrong data for touch policy\n"); 97 | return KEY_ERR_DATA; 98 | } 99 | key->meta.touch_policy = *buf++; 100 | break; 101 | 102 | default: 103 | buf = end; 104 | break; 105 | } 106 | } 107 | 108 | return 0; 109 | } 110 | 111 | int ck_parse_piv(ck_key_t *key, const uint8_t *buf, size_t buf_len) { 112 | memzero(key->data, sizeof(rsa_key_t)); 113 | key->meta.origin = KEY_ORIGIN_IMPORTED; 114 | 115 | const uint8_t *p = buf; 116 | 117 | switch (key->meta.type) { 118 | case SECP256R1: 119 | case SECP256K1: 120 | case SECP384R1: 121 | case SM2: 122 | case ED25519: 123 | case X25519: { 124 | 125 | if (buf_len < PRIVATE_KEY_LENGTH[key->meta.type] + 2) { 126 | DBG_MSG("too short\n"); 127 | return KEY_ERR_LENGTH; 128 | } 129 | if (*p++ != 0x06) { 130 | DBG_MSG("invalid tag\n"); 131 | return KEY_ERR_DATA; 132 | } 133 | if (*p++ != PRIVATE_KEY_LENGTH[key->meta.type]) { 134 | DBG_MSG("invalid private key length\n"); 135 | return KEY_ERR_LENGTH; 136 | } 137 | memcpy(key->ecc.pri, p, PRIVATE_KEY_LENGTH[key->meta.type]); 138 | if (!ecc_verify_private_key(key->meta.type, &key->ecc)) { 139 | memzero(key, sizeof(ck_key_t)); 140 | return KEY_ERR_DATA; 141 | } 142 | if (ecc_complete_key(key->meta.type, &key->ecc) < 0) { 143 | memzero(key, sizeof(ck_key_t)); 144 | return KEY_ERR_PROC; 145 | } 146 | p += PRIVATE_KEY_LENGTH[key->meta.type]; 147 | break; 148 | } 149 | 150 | case RSA2048: 151 | case RSA3072: 152 | case RSA4096: { 153 | int fail; 154 | size_t length_size; 155 | 156 | key->rsa.nbits = PRIVATE_KEY_LENGTH[key->meta.type] * 16; 157 | *(uint32_t *)key->rsa.e = htobe32(65537); 158 | 159 | uint8_t *data_ptr[] = {key->rsa.p, key->rsa.q, key->rsa.dp, key->rsa.dq, key->rsa.qinv}; 160 | 161 | for (int i = 1; i <= 5; ++i) { 162 | if ((size_t)(p - buf) >= buf_len) return KEY_ERR_LENGTH; 163 | if (*p++ != i) return KEY_ERR_DATA; 164 | const size_t len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 165 | if (fail) return KEY_ERR_LENGTH; 166 | if (len > PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 167 | p += length_size; 168 | memcpy(data_ptr[i - 1] + (PRIVATE_KEY_LENGTH[key->meta.type] - len), p, len); 169 | p += len; 170 | } 171 | 172 | if (be32toh(*(uint32_t *)key->rsa.p) < CEIL_DIV_SQRT2 || be32toh(*(uint32_t *)key->rsa.q) < CEIL_DIV_SQRT2) { 173 | memzero(key, sizeof(ck_key_t)); 174 | return KEY_ERR_DATA; 175 | } 176 | 177 | break; 178 | } 179 | 180 | default: 181 | return -1; 182 | } 183 | 184 | return ck_parse_piv_policies(key, p, buf + buf_len - p); 185 | } 186 | 187 | /* 188 | * RSA: 189 | * 7F48 xx Cardholder private key template 190 | * 91 xx e 191 | * 92 xx p 192 | * 93 xx q 193 | * 94 xx qinv 194 | * 95 xx dp 195 | * 96 xx dq 196 | * 5F48 xx Concatenation of key data as defined in DO 7F48 197 | * 198 | * ECC: 199 | * 7F48 xx Cardholder private key template 200 | * 92 xx private key 201 | * 99 xx public key (optional) 202 | * 5F48 xx Concatenation of key data as defined in DO 7F48 203 | */ 204 | int ck_parse_openpgp(ck_key_t *key, const uint8_t *buf, size_t buf_len) { 205 | memzero(key->data, sizeof(rsa_key_t)); 206 | key->meta.origin = KEY_ORIGIN_IMPORTED; 207 | 208 | const uint8_t *p = buf; 209 | int fail; 210 | size_t length_size; 211 | 212 | // Cardholder private key template 213 | if ((size_t)(p + 2 - buf) >= buf_len) return KEY_ERR_LENGTH; 214 | if (*p++ != 0x7F || *p++ != 0x48) return KEY_ERR_DATA; 215 | size_t len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 216 | if (fail) return KEY_ERR_LENGTH; 217 | if (len > MAX_KEY_TEMPLATE_LENGTH) return KEY_ERR_DATA; 218 | p += length_size; 219 | const uint8_t *data_tag = p + len; // saved for tag 5F48 220 | 221 | switch (key->meta.type) { 222 | case SECP256R1: 223 | case SECP256K1: 224 | case SECP384R1: 225 | case SM2: 226 | case ED25519: 227 | case X25519: { 228 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 229 | if (*p++ != 0x92) return KEY_ERR_DATA; 230 | const size_t data_pri_key_len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 231 | if (fail) return KEY_ERR_LENGTH; 232 | if (data_pri_key_len > PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 233 | p += length_size; 234 | 235 | size_t data_pub_key_len = 0; // this is optional 236 | if (p < data_tag) { 237 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 238 | if (*p++ == 0x99) { 239 | data_pub_key_len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 240 | if (fail) return KEY_ERR_LENGTH; 241 | if (data_pub_key_len > PUBLIC_KEY_LENGTH[key->meta.type] + 1) return KEY_ERR_DATA; 242 | } 243 | } 244 | 245 | // Concatenation of key data 246 | p = data_tag; 247 | if ((size_t)(p + 2 - buf) >= buf_len) return KEY_ERR_LENGTH; 248 | if (*p++ != 0x5F || *p++ != 0x48) return KEY_ERR_DATA; 249 | len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 250 | if (fail || len != data_pri_key_len + data_pub_key_len) return KEY_ERR_DATA; 251 | p += length_size; 252 | const int n_leading_zeros = PRIVATE_KEY_LENGTH[key->meta.type] - data_pri_key_len; 253 | if ((size_t)(p + data_pri_key_len - buf) > buf_len) return KEY_ERR_LENGTH; 254 | memcpy(key->ecc.pri + n_leading_zeros, p, data_pri_key_len); 255 | 256 | if (!ecc_verify_private_key(key->meta.type, &key->ecc)) { 257 | memzero(key, sizeof(ck_key_t)); 258 | return KEY_ERR_DATA; 259 | } 260 | if (ecc_complete_key(key->meta.type, &key->ecc) < 0) { 261 | memzero(key, sizeof(ck_key_t)); 262 | return KEY_ERR_PROC; 263 | } 264 | 265 | return 0; 266 | } 267 | 268 | case RSA2048: 269 | case RSA3072: 270 | case RSA4096: { 271 | // 0x91: e 272 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 273 | if (*p++ != 0x91) return KEY_ERR_DATA; 274 | len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 275 | if (fail) return KEY_ERR_LENGTH; 276 | if (len != E_LENGTH) return KEY_ERR_DATA; 277 | p += length_size; 278 | 279 | // 0x92: p 280 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 281 | if (*p++ != 0x92) return KEY_ERR_DATA; 282 | len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 283 | if (fail) return KEY_ERR_LENGTH; 284 | if (len != PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 285 | p += length_size; 286 | 287 | // 0x93: q 288 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 289 | if (*p++ != 0x93) return KEY_ERR_DATA; 290 | len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 291 | if (fail) return KEY_ERR_LENGTH; 292 | if (len != PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 293 | p += length_size; 294 | 295 | // 0x94: qinv, may be less than p/q's length 296 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 297 | if (*p++ != 0x94) return KEY_ERR_DATA; 298 | const size_t qinv_len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 299 | if (fail) return KEY_ERR_LENGTH; 300 | if (qinv_len > PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 301 | p += length_size; 302 | 303 | // 0x94: dp, may be less than p/q's length 304 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 305 | if (*p++ != 0x95) return KEY_ERR_DATA; 306 | const size_t dp_len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 307 | if (fail) return KEY_ERR_LENGTH; 308 | if (dp_len > PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 309 | p += length_size; 310 | 311 | // 0x94: dq, may be less than p/q's length 312 | if ((size_t)(p + 1 - buf) >= buf_len) return KEY_ERR_LENGTH; 313 | if (*p++ != 0x96) return KEY_ERR_DATA; 314 | const size_t dq_len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 315 | if (fail) return KEY_ERR_LENGTH; 316 | if (dq_len > PRIVATE_KEY_LENGTH[key->meta.type]) return KEY_ERR_DATA; 317 | 318 | // Concatenation of key data 319 | p = data_tag; 320 | if ((size_t)(p + 2 - buf) >= buf_len) return KEY_ERR_LENGTH; 321 | if (*p++ != 0x5F || *p++ != 0x48) return KEY_ERR_DATA; 322 | len = tlv_get_length_safe(p, buf_len - (p - buf), &fail, &length_size); 323 | if (fail) return KEY_ERR_LENGTH; 324 | if (len != PRIVATE_KEY_LENGTH[key->meta.type] * 2 + qinv_len + dp_len + dq_len + E_LENGTH) return KEY_ERR_DATA; 325 | p += length_size; 326 | 327 | if ((size_t)(p + len - buf) > buf_len) return KEY_ERR_LENGTH; 328 | key->rsa.nbits = PRIVATE_KEY_LENGTH[key->meta.type] * 16; 329 | memcpy(key->rsa.e, p, E_LENGTH); 330 | p += E_LENGTH; 331 | memcpy(key->rsa.p, p, PRIVATE_KEY_LENGTH[key->meta.type]); 332 | p += PRIVATE_KEY_LENGTH[key->meta.type]; 333 | memcpy(key->rsa.q, p, PRIVATE_KEY_LENGTH[key->meta.type]); 334 | p += PRIVATE_KEY_LENGTH[key->meta.type]; 335 | memcpy(key->rsa.qinv + PRIVATE_KEY_LENGTH[key->meta.type] - qinv_len, p, qinv_len); 336 | p += qinv_len; 337 | memcpy(key->rsa.dp + PRIVATE_KEY_LENGTH[key->meta.type] - dp_len, p, dp_len); 338 | p += dp_len; 339 | memcpy(key->rsa.dq + PRIVATE_KEY_LENGTH[key->meta.type] - dq_len, p, dq_len); 340 | if (be32toh(*(uint32_t *)key->rsa.p) < CEIL_DIV_SQRT2 || be32toh(*(uint32_t *)key->rsa.q) < CEIL_DIV_SQRT2) { 341 | memzero(key, sizeof(ck_key_t)); 342 | return KEY_ERR_DATA; 343 | } 344 | 345 | return 0; 346 | } 347 | 348 | default: 349 | return -1; 350 | } 351 | } 352 | 353 | int ck_read_key_metadata(const char *path, key_meta_t *meta) { 354 | return read_attr(path, KEY_META_ATTR, meta, sizeof(key_meta_t)); 355 | } 356 | 357 | int ck_write_key_metadata(const char *path, const key_meta_t *meta) { 358 | return write_attr(path, KEY_META_ATTR, meta, sizeof(key_meta_t)); 359 | } 360 | 361 | int ck_read_key(const char *path, ck_key_t *key) { 362 | const int err = ck_read_key_metadata(path, &key->meta); 363 | if (err < 0) return err; 364 | return read_file(path, key->data, 0, sizeof(rsa_key_t)); 365 | } 366 | 367 | int ck_write_key(const char *path, const ck_key_t *key) { 368 | const int err = write_file(path, key->data, 0, sizeof(rsa_key_t), 1); 369 | if (err < 0) return err; 370 | return ck_write_key_metadata(path, &key->meta); 371 | } 372 | 373 | int ck_generate_key(ck_key_t *key) { 374 | key->meta.origin = KEY_ORIGIN_GENERATED; 375 | 376 | if (IS_ECC(key->meta.type)) { 377 | if (ecc_generate(key->meta.type, &key->ecc) < 0) { 378 | memzero(key, sizeof(ck_key_t)); 379 | return -1; 380 | } 381 | return 0; 382 | } else if (IS_RSA(key->meta.type)) { 383 | if (rsa_generate_key(&key->rsa, PUBLIC_KEY_LENGTH[key->meta.type] * 8) < 0) { 384 | memzero(key, sizeof(ck_key_t)); 385 | return -1; 386 | } 387 | return 0; 388 | } else { 389 | return -1; 390 | } 391 | } 392 | 393 | int ck_sign(const ck_key_t *key, const uint8_t *input, size_t input_len, uint8_t *sig) { 394 | DBG_MSG("Data: "); 395 | PRINT_HEX(input, input_len); 396 | if (IS_ECC(key->meta.type)) { 397 | DBG_MSG("Private Key: "); 398 | PRINT_HEX(key->ecc.pri, PRIVATE_KEY_LENGTH[key->meta.type]); 399 | DBG_MSG("Public Key: "); 400 | PRINT_HEX(key->ecc.pub, PUBLIC_KEY_LENGTH[key->meta.type]); 401 | if (ecc_sign(key->meta.type, &key->ecc, input, input_len, sig) < 0) { 402 | ERR_MSG("ECC signing failed\n"); 403 | DBG_KEY_META(&key->meta); 404 | return -1; 405 | } 406 | } else if (IS_RSA(key->meta.type)) { 407 | DBG_MSG("Key: "); 408 | PRINT_HEX(key->rsa.p, PRIVATE_KEY_LENGTH[key->meta.type]); 409 | PRINT_HEX(key->rsa.q, PRIVATE_KEY_LENGTH[key->meta.type]); 410 | if (rsa_sign_pkcs_v15(&key->rsa, input, input_len, sig) < 0) { 411 | ERR_MSG("RSA signing failed\n"); 412 | DBG_KEY_META(&key->meta); 413 | return -1; 414 | } 415 | } else { 416 | return -1; 417 | } 418 | DBG_MSG("Sig: "); 419 | PRINT_HEX(sig, SIGNATURE_LENGTH[key->meta.type]); 420 | return SIGNATURE_LENGTH[key->meta.type]; 421 | } 422 | -------------------------------------------------------------------------------- /main/littlefs/lfs_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lfs util functions 3 | * 4 | * Copyright (c) 2022, The littlefs authors. 5 | * Copyright (c) 2017, Arm Limited. All rights reserved. 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | */ 8 | #include "lfs_util.h" 9 | 10 | // Only compile if user does not provide custom config 11 | #ifndef LFS_CONFIG 12 | 13 | 14 | // Software CRC implementation with small lookup table 15 | uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { 16 | static const uint32_t rtable[16] = { 17 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 18 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 19 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 20 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, 21 | }; 22 | 23 | const uint8_t *data = buffer; 24 | 25 | for (size_t i = 0; i < size; i++) { 26 | crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; 27 | crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; 28 | } 29 | 30 | return crc; 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /main/littlefs/lfs_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lfs utility functions 3 | * 4 | * Copyright (c) 2022, The littlefs authors. 5 | * Copyright (c) 2017, Arm Limited. All rights reserved. 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | */ 8 | #ifndef LFS_UTIL_H 9 | #define LFS_UTIL_H 10 | 11 | // Users can override lfs_util.h with their own configuration by defining 12 | // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). 13 | // 14 | // If LFS_CONFIG is used, none of the default utils will be emitted and must be 15 | // provided by the config file. To start, I would suggest copying lfs_util.h 16 | // and modifying as needed. 17 | #ifdef LFS_CONFIG 18 | #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) 19 | #define LFS_STRINGIZE2(x) #x 20 | #include LFS_STRINGIZE(LFS_CONFIG) 21 | #else 22 | 23 | // System includes 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifndef LFS_NO_MALLOC 30 | #include 31 | #endif 32 | #ifndef LFS_NO_ASSERT 33 | #include 34 | #endif 35 | #if !defined(LFS_NO_DEBUG) || \ 36 | !defined(LFS_NO_WARN) || \ 37 | !defined(LFS_NO_ERROR) || \ 38 | defined(LFS_YES_TRACE) 39 | #include 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | extern "C" 44 | { 45 | #endif 46 | 47 | 48 | // Macros, may be replaced by system specific wrappers. Arguments to these 49 | // macros must not have side-effects as the macros can be removed for a smaller 50 | // code footprint 51 | 52 | // Logging functions 53 | #ifndef LFS_TRACE 54 | #ifdef LFS_YES_TRACE 55 | #define LFS_TRACE_(fmt, ...) \ 56 | printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 57 | #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") 58 | #else 59 | #define LFS_TRACE(...) 60 | #endif 61 | #endif 62 | 63 | #ifndef LFS_DEBUG 64 | #ifndef LFS_NO_DEBUG 65 | #define LFS_DEBUG_(fmt, ...) \ 66 | printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 67 | #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") 68 | #else 69 | #define LFS_DEBUG(...) 70 | #endif 71 | #endif 72 | 73 | #ifndef LFS_WARN 74 | #ifndef LFS_NO_WARN 75 | #define LFS_WARN_(fmt, ...) \ 76 | printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 77 | #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") 78 | #else 79 | #define LFS_WARN(...) 80 | #endif 81 | #endif 82 | 83 | #ifndef LFS_ERROR 84 | #ifndef LFS_NO_ERROR 85 | #define LFS_ERROR_(fmt, ...) \ 86 | printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 87 | #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") 88 | #else 89 | #define LFS_ERROR(...) 90 | #endif 91 | #endif 92 | 93 | // Runtime assertions 94 | #ifndef LFS_ASSERT 95 | #ifndef LFS_NO_ASSERT 96 | #define LFS_ASSERT(test) assert(test) 97 | #else 98 | #define LFS_ASSERT(test) 99 | #endif 100 | #endif 101 | 102 | 103 | // Builtin functions, these may be replaced by more efficient 104 | // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more 105 | // expensive basic C implementation for debugging purposes 106 | 107 | // Min/max functions for unsigned 32-bit numbers 108 | static inline uint32_t lfs_max(uint32_t a, uint32_t b) { 109 | return (a > b) ? a : b; 110 | } 111 | 112 | static inline uint32_t lfs_min(uint32_t a, uint32_t b) { 113 | return (a < b) ? a : b; 114 | } 115 | 116 | // Align to nearest multiple of a size 117 | static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { 118 | return a - (a % alignment); 119 | } 120 | 121 | static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { 122 | return lfs_aligndown(a + alignment-1, alignment); 123 | } 124 | 125 | // Find the smallest power of 2 greater than or equal to a 126 | static inline uint32_t lfs_npw2(uint32_t a) { 127 | #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) 128 | return 32 - __builtin_clz(a-1); 129 | #else 130 | uint32_t r = 0; 131 | uint32_t s; 132 | a -= 1; 133 | s = (a > 0xffff) << 4; a >>= s; r |= s; 134 | s = (a > 0xff ) << 3; a >>= s; r |= s; 135 | s = (a > 0xf ) << 2; a >>= s; r |= s; 136 | s = (a > 0x3 ) << 1; a >>= s; r |= s; 137 | return (r | (a >> 1)) + 1; 138 | #endif 139 | } 140 | 141 | // Count the number of trailing binary zeros in a 142 | // lfs_ctz(0) may be undefined 143 | static inline uint32_t lfs_ctz(uint32_t a) { 144 | #if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) 145 | return __builtin_ctz(a); 146 | #else 147 | return lfs_npw2((a & -a) + 1) - 1; 148 | #endif 149 | } 150 | 151 | // Count the number of binary ones in a 152 | static inline uint32_t lfs_popc(uint32_t a) { 153 | #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) 154 | return __builtin_popcount(a); 155 | #else 156 | a = a - ((a >> 1) & 0x55555555); 157 | a = (a & 0x33333333) + ((a >> 2) & 0x33333333); 158 | return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; 159 | #endif 160 | } 161 | 162 | // Find the sequence comparison of a and b, this is the distance 163 | // between a and b ignoring overflow 164 | static inline int lfs_scmp(uint32_t a, uint32_t b) { 165 | return (int)(unsigned)(a - b); 166 | } 167 | 168 | // Convert between 32-bit little-endian and native order 169 | static inline uint32_t lfs_fromle32(uint32_t a) { 170 | #if (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ 171 | (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ 172 | (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 173 | return a; 174 | #elif !defined(LFS_NO_INTRINSICS) && ( \ 175 | (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ 176 | (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ 177 | (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) 178 | return __builtin_bswap32(a); 179 | #else 180 | return (((uint8_t*)&a)[0] << 0) | 181 | (((uint8_t*)&a)[1] << 8) | 182 | (((uint8_t*)&a)[2] << 16) | 183 | (((uint8_t*)&a)[3] << 24); 184 | #endif 185 | } 186 | 187 | static inline uint32_t lfs_tole32(uint32_t a) { 188 | return lfs_fromle32(a); 189 | } 190 | 191 | // Convert between 32-bit big-endian and native order 192 | static inline uint32_t lfs_frombe32(uint32_t a) { 193 | #if !defined(LFS_NO_INTRINSICS) && ( \ 194 | (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ 195 | (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ 196 | (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) 197 | return __builtin_bswap32(a); 198 | #elif (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ 199 | (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ 200 | (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) 201 | return a; 202 | #else 203 | return (((uint8_t*)&a)[0] << 24) | 204 | (((uint8_t*)&a)[1] << 16) | 205 | (((uint8_t*)&a)[2] << 8) | 206 | (((uint8_t*)&a)[3] << 0); 207 | #endif 208 | } 209 | 210 | static inline uint32_t lfs_tobe32(uint32_t a) { 211 | return lfs_frombe32(a); 212 | } 213 | 214 | // Calculate CRC-32 with polynomial = 0x04c11db7 215 | uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); 216 | 217 | // Allocate memory, only used if buffers are not provided to littlefs 218 | // Note, memory must be 64-bit aligned 219 | static inline void *lfs_malloc(size_t size) { 220 | #ifndef LFS_NO_MALLOC 221 | return malloc(size); 222 | #else 223 | (void)size; 224 | return NULL; 225 | #endif 226 | } 227 | 228 | // Deallocate memory, only used if buffers are not provided to littlefs 229 | static inline void lfs_free(void *p) { 230 | #ifndef LFS_NO_MALLOC 231 | free(p); 232 | #else 233 | (void)p; 234 | #endif 235 | } 236 | 237 | 238 | #ifdef __cplusplus 239 | } /* extern "C" */ 240 | #endif 241 | 242 | #endif 243 | #endif 244 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD 3 | * 4 | * SPDX-License-Identifier: Unlicense OR CC0-1.0 5 | */ 6 | 7 | #include 8 | #include "esp_log.h" 9 | #include "freertos/FreeRTOS.h" 10 | #include "freertos/task.h" 11 | #include "tinyusb.h" 12 | #include "class/hid/hid_device.h" 13 | #include "driver/gpio.h" 14 | #include "sdkconfig.h" 15 | #include "device.h" 16 | #include "ccid_device.h" 17 | 18 | static const char *TAG = "main"; 19 | 20 | /************* TinyUSB descriptors ****************/ 21 | #define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN + TUD_CCID_DESC_LEN ) 22 | 23 | static const tusb_desc_device_t hid_u2f_device_desc = { 24 | .bLength = sizeof(hid_u2f_device_desc), 25 | .bDescriptorType = TUSB_DESC_DEVICE, 26 | .bcdUSB = 0x0200, 27 | .bDeviceClass = TUSB_CLASS_MISC, 28 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 29 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 30 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 31 | #if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID 32 | .idVendor = USB_ESPRESSIF_VID, 33 | #else 34 | .idVendor = CONFIG_TINYUSB_DESC_CUSTOM_VID, 35 | #endif 36 | 37 | #if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID 38 | .idProduct = 0x4004, 39 | #else 40 | .idProduct = CONFIG_TINYUSB_DESC_CUSTOM_PID, 41 | #endif 42 | 43 | .bcdDevice = CONFIG_TINYUSB_DESC_BCD_DEVICE, 44 | .iManufacturer = 0x01, 45 | .iProduct = 0x02, 46 | .iSerialNumber = 0x03, 47 | .bNumConfigurations = 0x01}; 48 | 49 | static char const *u2f_string_descriptor[] = { 50 | (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) 51 | CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, // 1: Manufacturer 52 | CONFIG_TINYUSB_DESC_PRODUCT_STRING, // 2: Product 53 | CONFIG_TINYUSB_DESC_SERIAL_STRING, // 3: Serials 54 | }; 55 | /** 56 | * @brief HID report descriptor 57 | * 58 | * In this example we implement Keyboard + Mouse HID device, 59 | * so we must define both report descriptors 60 | */ 61 | const uint8_t u2f_report_descriptor[] = { 62 | TUD_HID_REPORT_DESC_FIDO_U2F(CFG_TUD_HID_EP_BUFSIZE)}; 63 | 64 | /** 65 | * @brief Configuration descriptor 66 | * 67 | * This is a simple configuration descriptor that defines 1 configuration and 1 HID interface 68 | */ 69 | 70 | static const uint8_t u2f_configuration_descriptor[] = { 71 | // Configuration number, interface count, string index, total length, attribute, power in mA 72 | TUD_CONFIG_DESCRIPTOR(1, 2, 0, TUSB_DESC_TOTAL_LEN, 0, 100), 73 | 74 | // Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval 75 | TUD_HID_INOUT_DESCRIPTOR(0, 2, HID_ITF_PROTOCOL_NONE, sizeof(u2f_report_descriptor), 0x01, 0x80 | 0x01, CFG_TUD_HID_EP_BUFSIZE, 5), 76 | 77 | TUD_CCID_DESCRIPTOR(1, 2, CCID_EPOUT, CCID_EPIN, CFG_TUD_CCID_EP_BUFSIZE), 78 | 79 | }; 80 | 81 | /********* TinyUSB HID callbacks ***************/ 82 | 83 | // Invoked when received GET HID REPORT DESCRIPTOR request 84 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 85 | uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) 86 | { 87 | 88 | // We use only one interface and one HID report descriptor, so we can ignore parameter 'instance' 89 | return u2f_report_descriptor; 90 | } 91 | 92 | // Invoked when received GET_REPORT control request 93 | // Application must fill buffer report's content and return its length. 94 | // Return zero will cause the stack to STALL request 95 | uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) 96 | { 97 | (void)instance; 98 | (void)report_id; 99 | (void)report_type; 100 | (void)buffer; 101 | (void)reqlen; 102 | 103 | return 0; 104 | } 105 | 106 | // Invoked when received SET_REPORT control request or 107 | // received data on OUT endpoint ( Report ID = 0, Type = 0 ) 108 | void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) 109 | { 110 | device_recv_data(buffer, bufsize); 111 | } 112 | 113 | /********* Application ***************/ 114 | 115 | void app_main(void) 116 | { 117 | 118 | device_init(); 119 | 120 | ESP_LOGI(TAG, "USB initialization"); 121 | const tinyusb_config_t tusb_cfg = { 122 | .device_descriptor = &hid_u2f_device_desc, 123 | .string_descriptor = u2f_string_descriptor, 124 | .string_descriptor_count = sizeof(u2f_string_descriptor) / sizeof(u2f_string_descriptor[0]), 125 | .external_phy = false, 126 | .configuration_descriptor = u2f_configuration_descriptor, 127 | }; 128 | 129 | ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); 130 | ESP_LOGI(TAG, "USB initialization DONE"); 131 | 132 | while (1) 133 | { 134 | device_loop(0); 135 | 136 | vTaskDelay(pdMS_TO_TICKS(50)); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /main/pin.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define RETRY_ATTR 0 9 | #define DEFAULT_RETRY_ATTR 1 10 | 11 | int pin_create(const pin_t *pin, const void *buf, uint8_t len, uint8_t max_retries) { 12 | int err = write_file(pin->path, buf, 0, len, 1); 13 | if (err < 0) return PIN_IO_FAIL; 14 | err = write_attr(pin->path, RETRY_ATTR, &max_retries, sizeof(max_retries)); 15 | if (err < 0) return PIN_IO_FAIL; 16 | err = write_attr(pin->path, DEFAULT_RETRY_ATTR, &max_retries, sizeof(max_retries)); 17 | if (err < 0) return PIN_IO_FAIL; 18 | return 0; 19 | } 20 | 21 | int pin_verify(pin_t *pin, const void *buf, uint8_t len, uint8_t *retries) { 22 | pin->is_validated = 0; 23 | if (len < pin->min_length || len > pin->max_length) return PIN_LENGTH_INVALID; 24 | uint8_t ctr; 25 | int err = read_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 26 | if (err < 0) return PIN_IO_FAIL; 27 | if (retries) *retries = ctr; 28 | if (ctr == 0) return PIN_AUTH_FAIL; 29 | uint8_t pin_buf[PIN_MAX_LENGTH]; 30 | int real_len = read_file(pin->path, pin_buf, 0, PIN_MAX_LENGTH); 31 | if (real_len < 0) return PIN_IO_FAIL; 32 | if (((real_len != (int)len) - memcmp(buf, pin_buf, len)) != 0) { // the two conditions should be both evaluated 33 | --ctr; 34 | if (retries) *retries = ctr; 35 | err = write_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 36 | if (err < 0) { 37 | memzero(pin_buf, sizeof(pin_buf)); 38 | return PIN_IO_FAIL; 39 | } 40 | memzero(pin_buf, sizeof(pin_buf)); 41 | #ifndef FUZZ // skip verification while fuzzing 42 | return PIN_AUTH_FAIL; 43 | #endif 44 | } 45 | pin->is_validated = 1; 46 | err = read_attr(pin->path, DEFAULT_RETRY_ATTR, &ctr, sizeof(ctr)); 47 | if (err < 0) { 48 | memzero(pin_buf, sizeof(pin_buf)); 49 | return PIN_IO_FAIL; 50 | } 51 | err = write_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 52 | if (err < 0) { 53 | memzero(pin_buf, sizeof(pin_buf)); 54 | return PIN_IO_FAIL; 55 | } 56 | memzero(pin_buf, sizeof(pin_buf)); 57 | return 0; 58 | } 59 | 60 | int pin_update(pin_t *pin, const void *buf, uint8_t len) { 61 | if (len < pin->min_length || len > pin->max_length) return PIN_LENGTH_INVALID; 62 | pin->is_validated = 0; 63 | int err = write_file(pin->path, buf, 0, len, 1); 64 | if (err < 0) return PIN_IO_FAIL; 65 | uint8_t ctr; 66 | err = read_attr(pin->path, DEFAULT_RETRY_ATTR, &ctr, sizeof(ctr)); 67 | if (err < 0) return PIN_IO_FAIL; 68 | err = write_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 69 | if (err < 0) return PIN_IO_FAIL; 70 | return 0; 71 | } 72 | 73 | int pin_get_size(const pin_t *pin) { return get_file_size(pin->path); } 74 | 75 | int pin_get_retries(const pin_t *pin) { 76 | if (pin_get_size(pin) == 0) return 0; 77 | uint8_t ctr; 78 | int err = read_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 79 | if (err < 0) return PIN_IO_FAIL; 80 | return ctr; 81 | } 82 | 83 | int pin_get_default_retries(const pin_t *pin) { 84 | if (pin_get_size(pin) == 0) return 0; 85 | uint8_t ctr; 86 | int err = read_attr(pin->path, DEFAULT_RETRY_ATTR, &ctr, sizeof(ctr)); 87 | if (err < 0) return PIN_IO_FAIL; 88 | return ctr; 89 | } 90 | 91 | int pin_clear(const pin_t *pin) { 92 | int err = write_file(pin->path, NULL, 0, 0, 1); 93 | if (err < 0) return PIN_IO_FAIL; 94 | uint8_t ctr; 95 | err = read_attr(pin->path, DEFAULT_RETRY_ATTR, &ctr, sizeof(ctr)); 96 | if (err < 0) return PIN_IO_FAIL; 97 | err = write_attr(pin->path, RETRY_ATTR, &ctr, sizeof(ctr)); 98 | if (err < 0) return PIN_IO_FAIL; 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /main/usb/ccid/ccid_device.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "esp_log.h" 3 | #include "tusb.h" 4 | #include "device/usbd.h" 5 | #include "device/usbd_pvt.h" 6 | #include "device/dcd.h" 7 | #include "ccid_device.h" 8 | 9 | #define TAG "CCID" 10 | 11 | #define ITF_MEM_RESET_SIZE offsetof(ccidd_interface_t, rx_ff) 12 | 13 | // TODO: multiple instances to be tested & completed 14 | CFG_TUSB_MEM_SECTION static ccidd_interface_t _ccidd_itf[CFG_TUD_CCID]; 15 | 16 | //--------------------------------------------------------------------+ 17 | // Read API 18 | //--------------------------------------------------------------------+ 19 | static void _prep_out_transaction(ccidd_interface_t *p_itf) 20 | { 21 | uint8_t const rhport = 0; 22 | uint16_t available = tu_fifo_remaining(&p_itf->rx_ff); 23 | 24 | TU_VERIFY(available >= sizeof(p_itf->epout_buf), ); // This pre-check reduces endpoint claiming 25 | TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); // claim endpoint 26 | 27 | available = tu_fifo_remaining(&p_itf->rx_ff); // fifo can be changed before endpoint is claimed 28 | if (available >= sizeof(p_itf->epout_buf)) 29 | { 30 | usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, sizeof(p_itf->epout_buf)); 31 | } 32 | else 33 | { 34 | usbd_edpt_release(rhport, p_itf->ep_out); // Release endpoint since we don't make any transfer 35 | } 36 | } 37 | 38 | uint32_t tud_ccid_n_read(uint8_t itf, void *buffer, uint32_t bufsize) 39 | { 40 | ccidd_interface_t *p_itf = &_ccidd_itf[itf]; 41 | TU_VERIFY(p_itf->ep_out); 42 | 43 | uint32_t const num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, bufsize); 44 | _prep_out_transaction(p_itf); 45 | return num_read; 46 | } 47 | 48 | //--------------------------------------------------------------------+ 49 | // Write API 50 | //--------------------------------------------------------------------+ 51 | uint32_t tud_ccid_write_n_flush(ccidd_interface_t *p_itf) 52 | { 53 | if (!tu_fifo_count(&p_itf->tx_ff)) // No data to send 54 | return 0; 55 | 56 | uint8_t const rhport = 0; 57 | TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_in), 0); // skip if previous transfer not complete 58 | 59 | uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); 60 | if (count) 61 | { 62 | TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0); 63 | return count; 64 | } 65 | else 66 | { 67 | usbd_edpt_release(rhport, p_itf->ep_in); // Release endpoint since we don't make any transfer 68 | return 0; 69 | } 70 | } 71 | 72 | uint32_t tud_ccid_n_write(uint8_t itf, void const *buffer, uint32_t bufsize) 73 | { 74 | ccidd_interface_t *p_itf = &_ccidd_itf[itf]; 75 | TU_VERIFY(p_itf->ep_in); 76 | 77 | uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize); 78 | return tud_ccid_write_n_flush(p_itf) > 0 ? ret : 0; 79 | } 80 | 81 | //--------------------------------------------------------------------+ 82 | // USBD Driver API 83 | //--------------------------------------------------------------------+ 84 | static void ccid_init(void) 85 | { 86 | tu_memclr(&_ccidd_itf, sizeof(_ccidd_itf)); 87 | 88 | for (uint8_t i = 0; i < CFG_TUD_CCID; i++) 89 | { 90 | ccidd_interface_t *p_itf = &_ccidd_itf[i]; 91 | tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_CCID_RX_BUFSIZE, 1, false); 92 | tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_CCID_TX_BUFSIZE, 1, false); 93 | } 94 | } 95 | 96 | static void ccid_reset(uint8_t rhport) 97 | { 98 | (void)rhport; 99 | 100 | for (uint8_t i = 0; i < CFG_TUD_CCID; i++) 101 | { 102 | ccidd_interface_t *p_itf = &_ccidd_itf[i]; 103 | tu_memclr(p_itf, ITF_MEM_RESET_SIZE); 104 | tu_fifo_clear(&p_itf->rx_ff); 105 | tu_fifo_clear(&p_itf->tx_ff); 106 | } 107 | } 108 | 109 | static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) 110 | { 111 | if (desc_itf->bInterfaceClass != TUSB_CLASS_SMART_CARD) 112 | return 0; // not our interface class 113 | 114 | // desc_intf->bInterfaceSubClass == 0 && desc_intf->bInterfaceProtocol == 0 115 | uint16_t drv_len = sizeof(tusb_desc_interface_t); 116 | TU_VERIFY(max_len >= drv_len, 0); 117 | 118 | uint8_t const *p_desc = (uint8_t const *)desc_itf; 119 | 120 | //------------- CCID descriptor -------------// 121 | p_desc = tu_desc_next(p_desc); 122 | TU_ASSERT(CCID_DESC_TYPE_CCID == tu_desc_type(p_desc), 0); 123 | drv_len += tu_desc_len(p_desc); 124 | 125 | ccidd_interface_t *p_itf = NULL; 126 | for (uint8_t i = 0; i < CFG_TUD_CCID; i++) 127 | { // Find available interface 128 | if (_ccidd_itf[i].ep_in == 0 && _ccidd_itf[i].ep_out == 0) 129 | { 130 | p_itf = &_ccidd_itf[i]; 131 | break; 132 | } 133 | } 134 | TU_ASSERT(p_itf); 135 | 136 | p_itf->itf_num = desc_itf->bInterfaceNumber; 137 | (void)p_itf->itf_num; 138 | 139 | //------------- Endpoint Descriptor -------------// 140 | p_desc = tu_desc_next(p_desc); 141 | uint8_t numEp = desc_itf->bNumEndpoints; 142 | TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, numEp, TUSB_XFER_BULK, &p_itf->ep_out, &p_itf->ep_in), 0); 143 | drv_len += numEp * sizeof(tusb_desc_endpoint_t); 144 | 145 | if (p_itf->ep_out) 146 | { 147 | _prep_out_transaction(p_itf); 148 | } 149 | 150 | if (p_itf->ep_in) 151 | { 152 | tud_ccid_write_n_flush(p_itf); 153 | } 154 | 155 | return drv_len; 156 | } 157 | 158 | static bool ccid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) 159 | { 160 | return false; // no control transfers supported 161 | } 162 | 163 | static bool ccid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) 164 | { 165 | (void)rhport; 166 | (void)result; 167 | 168 | uint8_t itf; 169 | ccidd_interface_t *p_itf; 170 | 171 | for (itf = 0; itf < CFG_TUD_CCID; itf++) 172 | { // Identify which interface to use 173 | p_itf = &_ccidd_itf[itf]; 174 | if ((ep_addr == p_itf->ep_out) || (ep_addr == p_itf->ep_in)) 175 | break; 176 | } 177 | TU_ASSERT(itf < CFG_TUD_CCID); 178 | 179 | if (ep_addr == p_itf->ep_out) 180 | { // receive new data 181 | tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t)xferred_bytes); 182 | 183 | if (tud_ccid_rx_cb) // invoke receive callback if available 184 | tud_ccid_rx_cb(itf); 185 | 186 | _prep_out_transaction(p_itf); // prepare for next 187 | } 188 | else if (ep_addr == p_itf->ep_in) 189 | { 190 | if (tud_ccid_tx_cb) 191 | tud_ccid_tx_cb(itf, (uint16_t)xferred_bytes); 192 | 193 | tud_ccid_write_n_flush(p_itf); 194 | } 195 | 196 | return true; 197 | } 198 | 199 | uint32_t tud_ccid_n_available(uint8_t itf) { return tu_fifo_count(&_ccidd_itf[itf].rx_ff); } 200 | 201 | bool tud_ccid_n_mounted(uint8_t itf) { 202 | // Return true if the interface is mounted 203 | return _ccidd_itf[itf].ep_in && _ccidd_itf[itf].ep_out; 204 | } 205 | 206 | // static void ccid_sof(uint8_t rhport, uint32_t frame_count) { }// optional 207 | 208 | static usbd_class_driver_t const _ccid_driver = { 209 | #if CFG_TUSB_DEBUG >= 2 210 | .name = "CCID", // 211 | #endif 212 | .init = ccid_init, // 213 | .reset = ccid_reset, // 214 | .open = ccid_open, // 215 | .control_xfer_cb = ccid_control_xfer_cb, // 216 | .xfer_cb = ccid_xfer_cb, // 217 | .sof = NULL}; 218 | 219 | usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) 220 | { // callback to add application driver 221 | *driver_count = 1; 222 | return &_ccid_driver; 223 | } -------------------------------------------------------------------------------- /main/usb/ctaphid/ctaphid.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "device.h" 7 | 8 | static CTAPHID_FRAME frame; 9 | static CTAPHID_Channel channel; 10 | static volatile uint8_t has_frame; 11 | static CAPDU apdu_cmd; 12 | static RAPDU apdu_resp; 13 | 14 | 15 | const uint16_t ISIZE = sizeof(frame.init.data); 16 | const uint16_t CSIZE = sizeof(frame.cont.data); 17 | 18 | uint8_t CTAPHID_Init(void) 19 | { 20 | channel.state = CTAPHID_IDLE; 21 | has_frame = 0; 22 | return 0; 23 | } 24 | 25 | uint8_t CTAPHID_OutEvent(uint8_t *data) 26 | { 27 | if (has_frame) 28 | { 29 | ERR_MSG("overrun\n"); 30 | return 0; 31 | } 32 | memcpy(&frame, data, sizeof(frame)); 33 | has_frame = 1; 34 | return 0; 35 | } 36 | 37 | static void CTAPHID_SendFrame(void) 38 | { 39 | device_send_response((uint8_t *)&frame, sizeof(CTAPHID_FRAME)); 40 | } 41 | 42 | static void CTAPHID_SendResponse(uint32_t cid, uint8_t cmd, uint8_t *data, uint16_t len) 43 | { 44 | uint16_t off = 0; 45 | size_t copied; 46 | uint8_t seq = 0; 47 | 48 | memset(&frame, 0, sizeof(frame)); 49 | frame.cid = cid; 50 | frame.type = TYPE_INIT; 51 | frame.init.cmd |= cmd; 52 | frame.init.bcnth = (uint8_t)((len >> 8) & 0xFF); 53 | frame.init.bcntl = (uint8_t)(len & 0xFF); 54 | 55 | copied = MIN(len, ISIZE); 56 | if (!data) 57 | return; 58 | memcpy(frame.init.data, data, copied); 59 | CTAPHID_SendFrame(); 60 | off += copied; 61 | 62 | while (len > off) 63 | { 64 | memset(&frame.cont, 0, sizeof(frame.cont)); 65 | frame.cont.seq = (uint8_t)seq++; 66 | copied = MIN(len - off, CSIZE); 67 | memcpy(frame.cont.data, data + off, copied); 68 | CTAPHID_SendFrame(); 69 | off += copied; 70 | } 71 | } 72 | 73 | static void CTAPHID_SendErrorResponse(uint32_t cid, uint8_t code) 74 | { 75 | DBG_MSG("error code 0x%x\n", (int)code); 76 | memset(&frame, 0, sizeof(frame)); 77 | frame.cid = cid; 78 | frame.init.cmd = CTAPHID_ERROR; 79 | frame.init.bcnth = 0; 80 | frame.init.bcntl = 1; 81 | frame.init.data[0] = code; 82 | CTAPHID_SendFrame(); 83 | } 84 | 85 | static void CTAPHID_Execute_Init(void) 86 | { 87 | CTAPHID_INIT_RESP *resp = (CTAPHID_INIT_RESP *)channel.data; 88 | uint32_t resp_cid; 89 | if (channel.cid == CID_BROADCAST) 90 | random_buffer((uint8_t *)&resp_cid, 4); 91 | else 92 | resp_cid = channel.cid; 93 | resp->cid = resp_cid; 94 | resp->versionInterface = CTAPHID_IF_VERSION; // Interface version 95 | resp->versionMajor = 1; // Major version number 96 | resp->versionMinor = 0; // Minor version number 97 | resp->versionBuild = 0; // Build version number 98 | resp->capFlags = CAPABILITY_CBOR; // Capabilities flags 99 | CTAPHID_SendResponse(channel.cid, channel.cmd, (uint8_t *)resp, sizeof(CTAPHID_INIT_RESP)); 100 | } 101 | 102 | static void CTAPHID_Execute_Msg(void) 103 | { 104 | CAPDU *capdu = &apdu_cmd; 105 | RAPDU *rapdu = &apdu_resp; 106 | CLA = channel.data[0]; 107 | INS = channel.data[1]; 108 | P1 = channel.data[2]; 109 | P2 = channel.data[3]; 110 | LC = (channel.data[5] << 8) | channel.data[6]; 111 | DATA = &channel.data[7]; 112 | LE = 0x10000; 113 | RDATA = channel.data; 114 | DBG_MSG("C: "); 115 | PRINT_HEX(channel.data, channel.bcnt_total); 116 | ctap_process_apdu(capdu, rapdu); 117 | channel.data[LL] = HI(SW); 118 | channel.data[LL + 1] = LO(SW); 119 | DBG_MSG("R: "); 120 | PRINT_HEX(RDATA, LL + 2); 121 | CTAPHID_SendResponse(channel.cid, channel.cmd, channel.data, LL + 2); 122 | } 123 | 124 | static void CTAPHID_Execute_Cbor(void) 125 | { 126 | DBG_MSG("C: "); 127 | PRINT_HEX(channel.data, channel.bcnt_total); 128 | size_t len = sizeof(channel.data); 129 | ctap_process_cbor(channel.data, channel.bcnt_total, channel.data, &len); 130 | DBG_MSG("R: "); 131 | PRINT_HEX(channel.data, len); 132 | CTAPHID_SendResponse(channel.cid, CTAPHID_CBOR, channel.data, len); 133 | } 134 | 135 | uint8_t CTAPHID_Loop(uint8_t wait_for_user) 136 | { 137 | uint8_t ret = LOOP_SUCCESS; 138 | if (channel.state == CTAPHID_BUSY && device_get_tick() > channel.expire) 139 | { 140 | DBG_MSG("CTAP Timeout\n"); 141 | channel.state = CTAPHID_IDLE; 142 | CTAPHID_SendErrorResponse(channel.cid, ERR_MSG_TIMEOUT); 143 | } 144 | 145 | if (!has_frame) 146 | return LOOP_SUCCESS; 147 | 148 | if (frame.cid == 0 || (frame.cid == CID_BROADCAST && frame.init.cmd != CTAPHID_INIT)) 149 | { 150 | CTAPHID_SendErrorResponse(frame.cid, ERR_INVALID_CID); 151 | goto consume_frame; 152 | } 153 | if (channel.state == CTAPHID_BUSY && frame.cid != channel.cid) 154 | { 155 | CTAPHID_SendErrorResponse(frame.cid, ERR_CHANNEL_BUSY); 156 | goto consume_frame; 157 | } 158 | 159 | channel.cid = frame.cid; 160 | 161 | if (FRAME_TYPE(frame) == TYPE_INIT) 162 | { 163 | // DBG_MSG("CTAP init frame, cmd=0x%x\n", (int)frame.init.cmd); 164 | if (!wait_for_user && channel.state == CTAPHID_BUSY && frame.init.cmd != CTAPHID_INIT) 165 | { // self abort is ok 166 | DBG_MSG("wait_for_user=%d, cmd=0x%x\n", (int)wait_for_user, (int)frame.init.cmd); 167 | channel.state = CTAPHID_IDLE; 168 | CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_SEQ); 169 | goto consume_frame; 170 | } 171 | channel.bcnt_total = (uint16_t)MSG_LEN(frame); 172 | if (channel.bcnt_total > MAX_CTAP_BUFSIZE) 173 | { 174 | DBG_MSG("bcnt_total=%hu exceeds MAX_CTAP_BUFSIZE\n", channel.bcnt_total); 175 | CTAPHID_SendErrorResponse(frame.cid, ERR_INVALID_LEN); 176 | goto consume_frame; 177 | } 178 | uint16_t copied; 179 | channel.bcnt_current = copied = MIN(channel.bcnt_total, ISIZE); 180 | channel.state = CTAPHID_BUSY; 181 | channel.cmd = frame.init.cmd; 182 | channel.seq = 0; 183 | memcpy(channel.data, frame.init.data, copied); 184 | channel.expire = device_get_tick() + CTAPHID_TRANS_TIMEOUT; 185 | } 186 | else 187 | { 188 | // DBG_MSG("CTAP cont frame, state=%d cmd=0x%x seq=%d\n", (int)channel.state, (int)channel.cmd, (int)FRAME_SEQ(frame)); 189 | if (channel.state == CTAPHID_IDLE) 190 | goto consume_frame; // ignore spurious continuation packet 191 | if (FRAME_SEQ(frame) != channel.seq++) 192 | { 193 | DBG_MSG("seq=%d\n", (int)FRAME_SEQ(frame)); 194 | channel.state = CTAPHID_IDLE; 195 | CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_SEQ); 196 | goto consume_frame; 197 | } 198 | uint16_t copied; 199 | copied = MIN(channel.bcnt_total - channel.bcnt_current, CSIZE); 200 | memcpy(channel.data + channel.bcnt_current, frame.cont.data, copied); 201 | channel.bcnt_current += copied; 202 | } 203 | has_frame = 0; 204 | 205 | if (channel.bcnt_current == channel.bcnt_total) 206 | { 207 | channel.expire = UINT32_MAX; 208 | switch (channel.cmd) 209 | { 210 | case CTAPHID_MSG: 211 | DBG_MSG("MSG\n"); 212 | if (wait_for_user) 213 | CTAPHID_SendErrorResponse(channel.cid, ERR_CHANNEL_BUSY); 214 | else if (channel.bcnt_total < 4) // APDU CLA...P2 215 | CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_LEN); 216 | else 217 | CTAPHID_Execute_Msg(); 218 | break; 219 | case CTAPHID_CBOR: 220 | DBG_MSG("CBOR\n"); 221 | if (wait_for_user) 222 | CTAPHID_SendErrorResponse(channel.cid, ERR_CHANNEL_BUSY); 223 | else if (channel.bcnt_total == 0) 224 | CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_LEN); 225 | else 226 | CTAPHID_Execute_Cbor(); 227 | break; 228 | case CTAPHID_INIT: 229 | DBG_MSG("INIT\n"); 230 | if (wait_for_user) 231 | CTAPHID_SendErrorResponse(channel.cid, ERR_CHANNEL_BUSY); 232 | else 233 | CTAPHID_Execute_Init(); 234 | break; 235 | case CTAPHID_PING: 236 | DBG_MSG("PING\n"); 237 | if (wait_for_user) 238 | CTAPHID_SendErrorResponse(channel.cid, ERR_CHANNEL_BUSY); 239 | else 240 | CTAPHID_SendResponse(channel.cid, channel.cmd, channel.data, channel.bcnt_total); 241 | break; 242 | case CTAPHID_WINK: 243 | DBG_MSG("WINK\n"); 244 | if (!wait_for_user) 245 | ctap_wink(); 246 | CTAPHID_SendResponse(channel.cid, channel.cmd, channel.data, 0); 247 | break; 248 | case CTAPHID_CANCEL: 249 | DBG_MSG("CANCEL when wait_for_user=%d\n", (int)wait_for_user); 250 | ret = LOOP_CANCEL; 251 | break; 252 | default: 253 | DBG_MSG("Invalid CMD 0x%x\n", (int)channel.cmd); 254 | CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_CMD); 255 | break; 256 | } 257 | channel.state = CTAPHID_IDLE; 258 | } 259 | 260 | consume_frame: 261 | has_frame = 0; 262 | return ret; 263 | } 264 | 265 | void CTAPHID_SendKeepAlive(uint8_t status) 266 | { 267 | memset(&frame, 0, sizeof(frame)); 268 | frame.cid = channel.cid; 269 | frame.type = TYPE_INIT; 270 | frame.init.cmd |= CTAPHID_KEEPALIVE; 271 | frame.init.bcnth = 0; 272 | frame.init.bcntl = 1; 273 | frame.init.data[0] = status; 274 | CTAPHID_SendFrame(); 275 | } -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration 3 | # 4 | CONFIG_TINYUSB_DESC_PRODUCT_STRING="U2F Token" 5 | CONFIG_TINYUSB_HID_COUNT=1 6 | 7 | CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 8 | CONFIG_PARTITION_TABLE_CUSTOM=y 9 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="u2f_partitions.csv" 10 | CONFIG_PARTITION_TABLE_FILENAME="u2f_partitions.csv" 11 | -------------------------------------------------------------------------------- /u2f_partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs,data,nvs,0x9000,24K, 3 | phy_init,data,phy,0xf000,4K, 4 | factory,app,factory,0x10000,0xF0000, 5 | lfs,data,undefined,0x100000,0x100000 --------------------------------------------------------------------------------