24 Commits

Author SHA1 Message Date
Pol Henarejos
3b4ac12d0f Merge branch 'development' into eddsa 2023-09-18 09:02:26 +02:00
Pol Henarejos
7c5bab8b05 Merge branch 'development' into eddsa 2023-09-18 01:38:39 +02:00
Pol Henarejos
21035d649d Upgrade to version 5.7
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 01:38:31 +02:00
Pol Henarejos
abe91823c0 Build firmwares with -eddsa1 suffix.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:29:54 +02:00
Pol Henarejos
91e049b997 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-17 19:28:41 +02:00
Pol Henarejos
8836902dc1 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 15:32:10 +02:00
Pol Henarejos
a019b54d69 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-22 13:27:35 +02:00
Pol Henarejos
3adb1a8422 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-21 19:12:51 +02:00
Pol Henarejos
95a9fe4214 Added flow triggering for eddsa branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:49:58 +02:00
Pol Henarejos
8af7cac57a Added authentication tests with EdDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:48:12 +02:00
Pol Henarejos
7997eefdc8 Fixed EdDSA signature encapsulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:55 +02:00
Pol Henarejos
e18f841a34 Fix Edwards load key.
It did not compute the correct public point.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 16:46:37 +02:00
Pol Henarejos
73b51cabfc Merge branch 'development' into eddsa 2023-08-18 14:10:58 +02:00
Pol Henarejos
ad3b2bbe4b Added EdDSA credential creation test.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 13:07:52 +02:00
Pol Henarejos
b9ad8f4745 Merge branch 'development' into eddsa 2023-08-18 13:07:13 +02:00
Pol Henarejos
8242dc8d80 Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 12:44:52 +02:00
Pol Henarejos
2f6e4d5568 Upgraded COSE key functions to accept EDDSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:40:22 +02:00
Pol Henarejos
911dab031e Merge branch 'development' into eddsa
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-17 01:36:35 +02:00
Pol Henarejos
3a71275bc8 Add EDDSA algorithm in get_info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 18:06:29 +02:00
Pol Henarejos
9f1e879efe Fix OTP applet selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 17:32:17 +02:00
Pol Henarejos
57bf97196d Updated readme.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:48:44 +02:00
Pol Henarejos
e8c8ce4d15 Adding support for EdDSA with Ed25519 curve.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 14:47:34 +02:00
Pol Henarejos
69d618cc6b Point to proper EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:13:58 +02:00
Pol Henarejos
e057f17180 Using Pico HSM SDK EdDSA branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 13:07:01 +02:00
43 changed files with 927 additions and 1029 deletions

4
.github/FUNDING.yml vendored
View File

@@ -1,4 +0,0 @@
# These are supported funding model platforms
github: polhenarejos
custom: ["https://www.paypal.me/polhenarejos"]

View File

@@ -13,10 +13,10 @@ name: "CodeQL"
on:
push:
branches: [ "main", "development" ]
branches: [ "main", "development", "eddsa" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main", "development" ]
branches: [ "main", "development", "eddsa" ]
schedule:
- cron: '23 5 * * 4'

View File

@@ -13,10 +13,10 @@ name: "Emulation and test"
on:
push:
branches: [ "main", "development" ]
branches: [ "main", "development", "eddsa" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main", "development" ]
branches: [ "main", "development", "eddsa" ]
schedule:
- cron: '23 5 * * 4'

6
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "pico-keys-sdk"]
path = pico-keys-sdk
url = https://github.com/polhenarejos/pico-keys-sdk
[submodule "pico-hsm-sdk"]
path = pico-hsm-sdk
url = ../pico-hsm-sdk

View File

@@ -17,11 +17,6 @@
cmake_minimum_required(VERSION 3.13)
if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
if(ENABLE_EMULATION)
else()
include(pico_sdk_import.cmake)
@@ -38,7 +33,7 @@ pico_sdk_init()
endif()
add_executable(pico_fido)
endif()
option(ENABLE_UP_BUTTON "Enable/disable user presence button" ON)
if(ENABLE_UP_BUTTON)
add_definitions(-DENABLE_UP_BUTTON=1)
@@ -114,51 +109,43 @@ set(SOURCES ${SOURCES}
endif()
set(USB_ITF_HID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
if(ESP_PLATFORM)
project(pico_fido)
endif()
include(pico-hsm-sdk/pico_hsm_sdk_import.cmake)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/fido
)
if(NOT ESP_PLATFORM)
target_sources(pico_fido PUBLIC ${SOURCES})
target_include_directories(pico_fido PUBLIC ${INCLUDES})
target_compile_options(pico_fido PUBLIC
-Wall
)
if (NOT MSVC)
target_compile_options(pico_fido PUBLIC
-Werror
)
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
if (${COMPILER_COLON} GREATER_EQUAL 0)
target_compile_options(pico_fido PUBLIC
-Wno-error=use-after-free
)
endif()
endif(NOT MSVC)
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(pico_fido PUBLIC
-fdata-sections
-ffunction-sections
)
endif(NOT MSVC)
if(APPLE)
target_link_options(pico_fido PUBLIC
-Wl,-dead_strip
)
else()
target_link_options(pico_fido PUBLIC
-Wl,--gc-sections
)
endif (APPLE)
target_link_libraries(pico_fido PRIVATE pthread m)
target_compile_options(pico_fido PUBLIC
-fdata-sections
-ffunction-sections
)
if(APPLE)
target_link_options(pico_fido PUBLIC
-Wl,-dead_strip
)
else()
target_link_options(pico_fido PUBLIC
-Wl,--gc-sections
)
target_link_libraries(pico_fido PRIVATE m)
endif (APPLE)
else()
target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board)
endif()
pico_add_extra_outputs(pico_fido)
target_link_libraries(pico_fido PRIVATE pico_hsm_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
endif()

View File

@@ -1,8 +1,8 @@
# Pico FIDO
This project transforms your Raspberry Pi Pico into an integrated FIDO Passkey, functioning like a standard USB Passkey for authentication.
This project aims at transforming your Raspberry Pico into a FIDO key integrated. The Pico works as a FIDO key, like a normal USB key for authentication.
## Features
Pico FIDO includes the following features:
Pico FIDO has implemented the following features:
- CTAP 2.1 / CTAP 1
- WebAuthn
@@ -10,16 +10,16 @@ Pico FIDO includes the following features:
- HMAC-Secret extension
- CredProtect extension
- User presence enforcement through physical button
- User verification with PIN
- Discoverable credentials (resident keys)
- User Verification with PIN
- Discoverable credentials
- Credential management
- ECDSA authentication
- Support for SECP256R1, SECP384R1, SECP521R1, and SECP256K1 curves
- ECDSA and EDDSA authentication
- Authentication with SECP256R1, SECP384R1, SECP521R1, SECP256K1 and Ed25519 curves
- App registration and login
- Device selection
- Support for vendor configuration
- Support for vendor Config
- Backup with 24 words
- Secure lock to protect the device from flash dumps
- Secure lock to protect the device from flash dumpings
- Permissions support (MC, GA, CM, ACFG, LBW)
- Authenticator configuration
- minPinLength extension
@@ -27,54 +27,50 @@ Pico FIDO includes the following features:
- Enterprise attestation
- credBlobs extension
- largeBlobKey extension
- Large blobs support (2048 bytes max)
- largeBlobs support (2048 bytes máx.)
- OATH (based on YKOATH protocol specification)
- TOTP / HOTP
- Yubikey OTP
- Challenge-response generation
- Emulated keyboard interface
- Button press generates an OTP that is directly typed
- Button press generates an OTP that is written directly is it was typed
- Yubico YKMAN compatible
- Nitrokey nitropy and nitroapp compatible
All features comply with the specifications. If you encounter unexpected behavior or deviations from the specifications, please open an issue.
All these features are compliant with the specification. Therefore, if you detect some behaviour that is not expected or it does not follow the rules of specs, please open an issue.
## Security Considerations
## Security considerations
Pico FIDO is an open platform so be careful. The contents in the flash memory may be easily dumpled and obtain the private/master keys. Therefore, it is not possible to encrypt the content. At least, one key (the master, the supreme key) must be stored in clear text.
Pico FIDO is an open platform, so exercise caution. The flash memory contents can be easily dumped, potentially revealing private/master keys. It is not feasible to encrypt the content, meaning at least one key (the master key) must be stored in clear text.
If the Pico is stolen, the private and secret keys can be accessed.
If the Pico is stolen the contents of private and secret keys can be read.
## Download
Please visit the [Release page](https://github.com/polhenarejos/pico-fido/releases "Release page") to download the UF2 file for your board.
Please, go to the [Release page](https://github.com/polhenarejos/pico-fido/releases "Release page") and download the UF2 file for your board.
Note that UF2 files are shipped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with OpenSC or similar software, you will need to modify the Info.plist of the CCID driver to add these VID/PID values or use the [Pico Patcher tool](https://www.picokeys.com/pico-patcher/).
Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you are planning to use it with OpenSC or similar, you should modify Info.plist of CCID driver to add these VID/PID or use the [Pico Patcher tool](https://www.picokeys.com/pico-patcher/).
Alternatively, you can use the legacy VID/PID patcher with the following command:
```sh
./patch_vidpid.sh VID:PID input_hsm_file.uf2 output_hsm_file.uf2
```
You can use any VID/PID (e.g., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
Alternatively you can use the legacy VID/PID patcher as follows:
`./patch_vidpid.sh VID:PID input_hsm_file.uf2 output_hsm_file.uf2`
For ease of use, the pure-browser option [Pico Patcher tool](https://www.picokeys.com/pico-patcher/) is highly recommended.
You can use whatever VID/PID (i.e., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
Note that the pure-browser option [Pico Patcher tool](https://www.picokeys.com/pico-patcher/) is the most recommended.
## Build
Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive.
Before building, ensure you have installed the toolchain for the Pico and the Pico SDK is properly located in your drive.
```sh
git clone https://github.com/polhenarejos/pico-fido
cd pico-fido
mkdir build
cd build
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678
make
```
git clone https://github.com/polhenarejos/pico-fido
cd pico-fido
mkdir build
cd build
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678
make
Note that `PICO_BOARD`, `USB_VID`, and `USB_PID` are optional. If not provided, the default Pico board and VID/PID `FEFF:FCFD` will be used.
Note that PICO_BOARD, USB_VID and USB_PID are optional. If not provided, pico board and VID/PID FEFF:FCFD will be used.
After `make` finishes, the binary file `pico_fido.uf2` will be generated. Put your Pico board into loading mode by holding the BOOTSEL button while plugging it in, then copy the UF2 file to the new USB mass storage Pico device. Once copied, the Pico mass storage will disconnect automatically, and the Pico board will reset with the new firmware. A blinking LED will indicate that the device is ready to work.
After make ends, the binary file pico_fido.uf2 will be generated. Put your pico board into loading mode, by pushing BOOTSEL button while pluging on, and copy the UF2 to the new fresh usb mass storage Pico device. Once copied, the pico mass storage will be disconnected automatically and the pico board will reset with the new firmware. A blinking led will indicate the device is ready to work.
**Remark:** Pico FIDO uses the HID interface, so VID/PID values are irrelevant in terms of operativity. You can safely use any arbitrary values or the default ones. They are only necessary in case you need to use 3rd-party tools from other vendors.
**Remark:** Pico Fido uses HID interface and thus, VID/PID values are irrelevant in terms of operativity. You can safely use any arbitrary value or the default ones.
## Led blink
Pico FIDO uses the led to indicate the current status. Four states are available:
@@ -100,21 +96,20 @@ While processing, the Pico FIDO is busy and cannot receive additional commands u
## Driver
Pico FIDO uses the `HID` driver, which is present in all operating systems. It should be detected by all OS and browser/applications just like normal USB FIDO keys.
Pico FIDO uses the `HID` driver, present in all OS. It should be detected by all OS and browser/applications, like normal USB FIDO keys.
## Tests
Tests can be found in the `tests` folder. They are based on [FIDO2 tests](https://github.com/solokeys/fido2-tests "FIDO2 tests") from Solokeys but adapted to the [python-fido2](https://github.com/Yubico/python-fido2 "python-fido2") v1.0 package, which is a major refactor from the previous 0.8 version and includes the latest improvements from CTAP 2.1.
Tests can be found at `tests` folder. It is based on [FIDO2 tests](https://github.com/solokeys/fido2-tests "FIDO2 tests") from Solokeys, but adapted to [python-fido2](https://github.com/Yubico/python-fido2 "python-fido2") v1.0 package, which is a major refactor from previous 0.8 version and includes latests improvements from CTAP 2.1.
To run all tests, use:
All tests can be run by
```sh
```
pytest
```
To run a subset of tests, use the `-k <test>` flag:
```sh
or by selecting a subset with `-k <test>` flag:
```
pytest -k test_credprotect
```

View File

@@ -1,87 +1,45 @@
#!/bin/bash
VERSION_MAJOR="5"
VERSION_MINOR="12"
VERSION_MINOR="6-eddsa1"
rm -rf release/*
cd build_release
for board in 0xcb_helios \
adafruit_feather_rp2040_usb_host \
adafruit_feather_rp2040 \
for board in adafruit_feather_rp2040 \
adafruit_itsybitsy_rp2040 \
adafruit_kb2040 \
adafruit_macropad_rp2040 \
adafruit_qtpy_rp2040 \
adafruit_trinkey_qt2040 \
amethyst_fpga \
archi \
arduino_nano_rp2040_connect \
cytron_maker_pi_rp2040 \
datanoisetv_rp2040_dsp \
eetree_gamekit_rp2040 \
garatronic_pybstick26_rp2040 \
gen4_rp2350_24 \
gen4_rp2350_24ct \
gen4_rp2350_24t \
gen4_rp2350_28 \
gen4_rp2350_28ct \
gen4_rp2350_28t \
gen4_rp2350_32 \
gen4_rp2350_32ct \
gen4_rp2350_32t \
gen4_rp2350_35 \
gen4_rp2350_35ct \
gen4_rp2350_35t \
hellbender_2350A_devboard \
ilabs_challenger_rp2350_bconnect \
ilabs_challenger_rp2350_wifi_ble \
ilabs_opendec02 \
melopero_perpetuo_rp2350_lora \
melopero_shake_rp2040 \
metrotech_xerxes_rp2040 \
net8086_usb_interposer \
nullbits_bit_c_pro \
phyx_rick_tny_rp2350 \
pi-plates_micropi \
pico \
pico_w \
pico2 \
pimoroni_badger2040 \
pimoroni_interstate75 \
pimoroni_keybow2040 \
pimoroni_motor2040 \
pimoroni_pga2040 \
pimoroni_pga2350 \
pimoroni_pico_plus2_rp2350 \
pimoroni_picolipo_4mb \
pimoroni_picolipo_16mb \
pimoroni_picosystem \
pimoroni_plasma2040 \
pimoroni_plasma2350 \
pimoroni_servo2040 \
pimoroni_tiny2040 \
pimoroni_tiny2040_2mb \
pimoroni_tiny2350 \
pololu_3pi_2040_robot \
pololu_zumo_2040_robot \
seeed_xiao_rp2040 \
seeed_xiao_rp2350 \
solderparty_rp2040_stamp \
solderparty_rp2040_stamp_carrier \
solderparty_rp2040_stamp_round_carrier \
solderparty_rp2350_stamp_xl \
solderparty_rp2350_stamp \
sparkfun_micromod \
sparkfun_promicro \
sparkfun_promicro_rp2350 \
sparkfun_thingplus \
switchscience_picossci2_conta_base \
switchscience_picossci2_dev_board \
switchscience_picossci2_micro \
switchscience_picossci2_rp2350_breakout \
switchscience_picossci2_tiny \
tinycircuits_thumby_color_rp2350 \
vgaboard \
waveshare_rp2040_lcd_0.96 \
waveshare_rp2040_lcd_1.28 \
@@ -89,10 +47,6 @@ for board in 0xcb_helios \
waveshare_rp2040_plus_4mb \
waveshare_rp2040_plus_16mb \
waveshare_rp2040_zero \
weact_studio_rp2040_2mb \
weact_studio_rp2040_4mb \
weact_studio_rp2040_8mb \
weact_studio_rp2040_16mb \
wiznet_w5100s_evb_pico
do
rm -rf *

View File

@@ -87,7 +87,7 @@ fi
LITTLE_VID="\x${VID:2:2}\x${VID:0:2}"
LITTLE_PID="\x${PID:2:2}\x${PID:0:2}"
perl -pi -e "s/[\x00-\xff]{4}\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01\x00\x00/$LITTLE_VID$LITTLE_PID\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01\x00\x00/" $UF2_FILE_OF
perl -pi -e "s/\xfe\xca\x31\x42\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/$LITTLE_VID$LITTLE_PID\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/" $UF2_FILE_OF
echo "Done!"
echo ""

1
pico-hsm-sdk Submodule

Submodule pico-hsm-sdk added at 5ec98c84aa

Submodule pico-keys-sdk deleted from 9f65a2cfa0

View File

@@ -1,53 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_MODE_PERF=y
CONFIG_MBEDTLS_CMAC_C=y
CONFIG_MBEDTLS_CHACHA20_C=y
CONFIG_MBEDTLS_POLY1305_C=y
CONFIG_MBEDTLS_CHACHAPOLY_C=y
CONFIG_MBEDTLS_HKDF_C=y
CONFIG_MBEDTLS_HARDWARE_ECC=y
CONFIG_MBEDTLS_HARDWARE_GCM=y
# CONFIG_MBEDTLS_HARDWARE_MPI is not set
CONFIG_MBEDTLS_HARDWARE_SHA=y
CONFIG_MBEDTLS_HARDWARE_AES=y
# CONFIG_MBEDTLS_ROM_MD5 is not set
CONFIG_MBEDTLS_SHA512_C=y
CONFIG_MBEDTLS_TLS_DISABLED=y
# CONFIG_MBEDTLS_TLS_ENABLED is not set
# CONFIG_ESP_TLS_USE_DS_PERIPHERAL is not set
# CONFIG_ESP_WIFI_ENABLED is not set
# CONFIG_ESP_WIFI_MBEDTLS_CRYPTO is not set
# CONFIG_ESP_WIFI_MBEDTLS_TLS_CLIENT is not set
# CONFIG_WPA_MBEDTLS_CRYPTO is not set
# CONFIG_MBEDTLS_PSK_MODES is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_RSA is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA is not set
# CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA is not set
# CONFIG_MBEDTLS_SSL_RENEGOTIATION is not set
# CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 is not set
# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set
# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
# CONFIG_MBEDTLS_SSL_ALPN is not set
# CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS is not set
# CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS is not set
# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
# CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA is not set
# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set
# CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA is not set
CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y

View File

@@ -1,6 +0,0 @@
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS . ../../pico-keys-sdk/src ../../pico-keys-sdk/src/fs ../../pico-keys-sdk/src/rng ../../pico-keys-sdk/src/usb ../../pico-keys-sdk/tinycbor/src
REQUIRES bootloader_support esp_partition esp_tinyusb zorxx__neopixel mbedtls efuse
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "pico/stdlib.h"
#endif
#include "hid/ctap_hid.h"
@@ -25,7 +25,6 @@
#include "apdu.h"
#include "management.h"
#include "ctap2_cbor.h"
#include "version.h"
const bool _btrue = true, _bfalse = false;
@@ -41,13 +40,12 @@ int cbor_config(const uint8_t *data, size_t len);
int cbor_vendor(const uint8_t *data, size_t len);
int cbor_large_blobs(const uint8_t *data, size_t len);
extern int cmd_read_config();
const uint8_t aaguid[16] = { 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2")
const uint8_t aaguid[16] =
{ 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2")
const uint8_t *cbor_data = NULL;
size_t cbor_len = 0;
uint8_t cbor_cmd = 0;
uint8_t cmd = 0;
int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
if (len == 0 && cmd == CTAPHID_CBOR) {
@@ -57,6 +55,7 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
DEBUG_DATA(data + 1, len - 1);
}
if (cap_supported(CAP_FIDO2)) {
driver_prepare_response_hid();
if (cmd == CTAPHID_CBOR) {
if (data[0] == CTAP_MAKE_CREDENTIAL) {
return cbor_make_credential(data + 1, len - 1);
@@ -92,58 +91,54 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
else if (cmd == CTAP_VENDOR_CBOR) {
return cbor_vendor(data, len);
}
else if (cmd == 0xC2) {
if (cmd_read_config() == 0x9000) {
memmove(res_APDU-1, res_APDU, res_APDU_size);
res_APDU_size -= 1;
return 0;
}
}
}
return CTAP1_ERR_INVALID_CMD;
}
void cbor_thread(void) {
#ifndef ENABLE_EMULATION
void cbor_thread() {
card_init_core1();
while (1) {
uint32_t m;
queue_remove_blocking(&usb_to_card_q, &m);
uint32_t flag = m + 1;
queue_add_blocking(&card_to_usb_q, &flag);
if (m == EV_EXIT) {
break;
}
apdu.sw = cbor_parse(cbor_cmd, cbor_data, cbor_len);
apdu.sw = cbor_parse(cmd, cbor_data, cbor_len);
if (apdu.sw == 0) {
DEBUG_DATA(res_APDU + 1, res_APDU_size);
}
else {
res_APDU[0] = apdu.sw;
//apdu.sw = 0;
apdu.sw = 0;
}
finished_data_size = res_APDU_size + 1;
flag = EV_EXEC_FINISHED;
uint32_t flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag);
}
#ifdef ESP_PLATFORM
vTaskDelete(NULL);
#endif
}
#endif
int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len) {
cbor_data = data;
cbor_len = len;
cbor_cmd = last_cmd;
ctap_resp->init.data[0] = 0;
cmd = last_cmd;
res_APDU = ctap_resp->init.data + 1;
res_APDU_size = 0;
return 2; // CBOR processing
return 1;
}
CborError COSE_key_params(int crv, int alg, mbedtls_ecp_group *grp, mbedtls_ecp_point *Q, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) {
CborError COSE_key_params(int crv,
int alg,
mbedtls_ecp_group *grp,
mbedtls_ecp_point *Q,
CborEncoder *mapEncoderParent,
CborEncoder *mapEncoder) {
CborError error = CborNoError;
int kty = 1;
if (crv == FIDO2_CURVE_P256 || crv == FIDO2_CURVE_P384 || crv == FIDO2_CURVE_P521 ||
@@ -204,13 +199,21 @@ CborError COSE_key(mbedtls_ecp_keypair *key, CborEncoder *mapEncoderParent,
else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
alg = FIDO2_ALG_ECDH_ES_HKDF_256;
}
else if (key->grp.id == MBEDTLS_ECP_DP_ED25519) {
alg = FIDO2_ALG_EDDSA;
}
return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
}
CborError COSE_key_shared(mbedtls_ecdh_context *key,
CborEncoder *mapEncoderParent,
CborEncoder *mapEncoder) {
int crv = mbedtls_curve_to_fido(key->ctx.mbed_ecdh.grp.id), alg = FIDO2_ALG_ECDH_ES_HKDF_256;
return COSE_key_params(crv, alg, &key->ctx.mbed_ecdh.grp, &key->ctx.mbed_ecdh.Q, mapEncoderParent, mapEncoder);
return COSE_key_params(crv,
alg,
&key->ctx.mbed_ecdh.grp,
&key->ctx.mbed_ecdh.Q,
mapEncoderParent,
mapEncoder);
}
CborError COSE_public_key(int alg, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) {
CborError error = CborNoError;
@@ -223,7 +226,12 @@ CborError COSE_public_key(int alg, CborEncoder *mapEncoderParent, CborEncoder *m
err:
return error;
}
CborError COSE_read_key(CborValue *f, int64_t *kty, int64_t *alg, int64_t *crv, CborByteString *kax, CborByteString *kay) {
CborError COSE_read_key(CborValue *f,
int64_t *kty,
int64_t *alg,
int64_t *crv,
CborByteString *kax,
CborByteString *kay) {
int64_t kkey = 0;
CborError error = CborNoError;
CBOR_PARSE_MAP_START(*f, 0)

View File

@@ -15,11 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/sha256.h"
@@ -27,7 +23,7 @@
#include "cbor.h"
#include "ctap.h"
#include "ctap2_cbor.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#include "hid/ctap_hid.h"
@@ -35,7 +31,7 @@
#include "files.h"
#include "random.h"
#include "crypto_utils.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
uint32_t usage_timer = 0, initial_usage_time_limit = 0;
@@ -173,7 +169,7 @@ int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret) {
int resetPinUvAuthToken() {
uint8_t t[32];
random_gen(NULL, t, sizeof(t));
file_put_data(ef_authtoken, t, sizeof(t));
flash_write_data_to_file(ef_authtoken, t, sizeof(t));
paut.permissions = 0;
paut.data = file_get_data(ef_authtoken);
paut.len = file_get_size(ef_authtoken);
@@ -182,28 +178,28 @@ int resetPinUvAuthToken() {
return 0;
}
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) {
memcpy(out, in, in_len);
return aes_encrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
return aes_encrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len);
}
else if (protocol == 2) {
random_gen(NULL, out, IV_SIZE);
memcpy(out + IV_SIZE, in, in_len);
return aes_encrypt(key + 32, out, 32 * 8, PICO_KEYS_AES_MODE_CBC, out + IV_SIZE, in_len);
return aes_encrypt(key + 32, out, 32 * 8, HSM_AES_MODE_CBC, out + IV_SIZE, in_len);
}
return -1;
}
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) {
memcpy(out, in, in_len);
return aes_decrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
return aes_decrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len);
}
else if (protocol == 2) {
memcpy(out, in + IV_SIZE, in_len - IV_SIZE);
return aes_decrypt(key + 32, in, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len - IV_SIZE);
memcpy(out, in + IV_SIZE, in_len);
return aes_decrypt(key + 32, in, 32 * 8, HSM_AES_MODE_CBC, out, in_len - IV_SIZE);
}
return -1;
@@ -232,11 +228,12 @@ int authenticate(uint8_t protocol,
return 0;
}
int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign) {
int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign) {
uint8_t hmac[32];
//if (paut.in_use == false)
// return -2;
int ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac);
int ret =
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac);
if (ret != 0) {
return ret;
}
@@ -335,7 +332,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
}
CBOR_PARSE_MAP_END(map, 1);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (subcommand == 0x0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
@@ -385,17 +382,18 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t sharedSecret[64];
int ret = ecdh((uint8_t)pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
int ret = ecdh(pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (verify((uint8_t)pinUvAuthProtocol, sharedSecret, newPinEnc.data, (uint16_t)newPinEnc.len, pinUvAuthParam.data) != 0) {
if (verify(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len,
pinUvAuthParam.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
uint8_t paddedNewPin[64];
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, newPinEnc.data, (uint16_t)newPinEnc.len, paddedNewPin);
ret = decrypt(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len, paddedNewPin);
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -419,7 +417,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len;
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
file_put_data(ef_pin, hsh, 2 + 16);
flash_write_data_to_file(ef_pin, hsh, 2 + 16);
low_flash_available();
goto err; //No return
}
@@ -450,7 +448,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t sharedSecret[64];
int ret = ecdh((uint8_t)pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
int ret = ecdh(pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -458,18 +456,20 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
uint8_t tmp[80 + 32];
memcpy(tmp, newPinEnc.data, newPinEnc.len);
memcpy(tmp + newPinEnc.len, pinHashEnc.data, pinHashEnc.len);
if (verify((uint8_t)pinUvAuthProtocol, sharedSecret, tmp, (uint16_t)(newPinEnc.len + pinHashEnc.len), pinUvAuthParam.data) != 0) {
if (verify(pinUvAuthProtocol, sharedSecret, tmp, newPinEnc.len + pinHashEnc.len,
pinUvAuthParam.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data));
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available();
uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64];
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
ret =
decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -489,10 +489,10 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
}
}
pin_data[0] = MAX_PIN_RETRIES;
file_put_data(ef_pin, pin_data, sizeof(pin_data));
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available();
new_pin_mismatches = 0;
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, newPinEnc.data, (uint16_t)newPinEnc.len, paddedNewPin);
ret = decrypt(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len, paddedNewPin);
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -512,7 +512,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (pin_len < minPin) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
uint8_t hsh[34];
uint8_t hsh[33];
hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len;
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
@@ -520,13 +520,13 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 16) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
file_put_data(ef_pin, hsh, 2 + 16);
flash_write_data_to_file(ef_pin, hsh, 2 + 16);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin));
memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin));
tmpf[1] = 0;
file_put_data(ef_minpin, tmpf, file_get_size(ef_minpin));
free(tmpf);
uint8_t *tmp = (uint8_t *) calloc(1, file_get_size(ef_minpin));
memcpy(tmp, file_get_data(ef_minpin), file_get_size(ef_minpin));
tmp[1] = 0;
flash_write_data_to_file(ef_minpin, tmp, file_get_size(ef_minpin));
free(tmp);
}
low_flash_available();
resetPinUvAuthToken();
@@ -565,7 +565,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t sharedSecret[64];
int ret = ecdh((uint8_t)pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
int ret = ecdh(pinUvAuthProtocol, &hkey.ctx.mbed_ecdh.Qp, sharedSecret);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -573,11 +573,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data));
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available();
uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64], poff = ((uint8_t)pinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
uint8_t paddedNewPin[64], poff = (pinUvAuthProtocol - 1) * IV_SIZE;
ret =
decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -598,7 +599,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
}
pin_data[0] = MAX_PIN_RETRIES;
new_pin_mismatches = 0;
file_put_data(ef_pin, pin_data, sizeof(pin_data));
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available();
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
@@ -609,7 +610,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (subcommand == 0x05) {
permissions = CTAP_PERMISSION_MC | CTAP_PERMISSION_GA;
}
paut.permissions = (uint8_t)permissions;
paut.permissions = permissions;
if (rpId.present == true) {
mbedtls_sha256((uint8_t *) rpId.data, rpId.len, paut.rp_id_hash, 0);
paut.has_rp_id = true;
@@ -618,7 +619,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
paut.has_rp_id = false;
}
uint8_t pinUvAuthToken_enc[32 + IV_SIZE];
encrypt((uint8_t)pinUvAuthProtocol, sharedSecret, paut.data, 32, pinUvAuthToken_enc);
encrypt(pinUvAuthProtocol, sharedSecret, paut.data, 32, pinUvAuthToken_enc);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pinUvAuthToken_enc, 32 + poff));
@@ -641,6 +642,6 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -22,7 +22,7 @@
#include "files.h"
#include "apdu.h"
#include "credential.h"
#include "pico_keys.h"
#include "hsm.h"
#include "random.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/chachapoly.h"
@@ -39,8 +39,7 @@ int cbor_config(const uint8_t *data, size_t len) {
CborByteString pinUvAuthParam = { 0 }, vendorAutCt = { 0 };
CborCharString minPinLengthRPIDs[32] = { 0 };
size_t resp_size = 0, raw_subpara_len = 0, minPinLengthRPIDs_len = 0;
CborEncoder encoder;
//CborEncoder mapEncoder;
CborEncoder encoder, mapEncoder;
uint8_t *raw_subpara = NULL;
const bool *forceChangePin = NULL;
@@ -65,7 +64,7 @@ int cbor_config(const uint8_t *data, size_t len) {
raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1);
CBOR_PARSE_MAP_START(_f1, 2)
{
if (subcommand == 0x7f) {
if (subcommand == 0xff) {
CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) {
CBOR_FIELD_GET_UINT(vendorCommandId, 2);
@@ -107,7 +106,7 @@ int cbor_config(const uint8_t *data, size_t len) {
}
CBOR_PARSE_MAP_END(map, 1);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (pinUvAuthParam.present == false) {
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
@@ -119,9 +118,13 @@ int cbor_config(const uint8_t *data, size_t len) {
uint8_t *verify_payload = (uint8_t *) calloc(1, 32 + 1 + 1 + raw_subpara_len);
memset(verify_payload, 0xff, 32);
verify_payload[32] = 0x0d;
verify_payload[33] = (uint8_t)subcommand;
verify_payload[33] = subcommand;
memcpy(verify_payload + 34, raw_subpara, raw_subpara_len);
error = verify((uint8_t)pinUvAuthProtocol, paut.data, verify_payload, (uint16_t)(32 + 1 + 1 + raw_subpara_len), pinUvAuthParam.data);
error = verify(pinUvAuthProtocol,
paut.data,
verify_payload,
32 + 1 + 1 + raw_subpara_len,
pinUvAuthParam.data);
free(verify_payload);
if (error != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -131,7 +134,7 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (subcommand == 0x7f) {
if (subcommand == 0xff) {
if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) {
if (!file_has_data(ef_keydev_enc)) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
@@ -139,9 +142,9 @@ int cbor_config(const uint8_t *data, size_t len) {
if (has_keydev_dec == false) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
file_put_data(ef_keydev, keydev_dec, sizeof(keydev_dec));
flash_write_data_to_file(ef_keydev, keydev_dec, sizeof(keydev_dec));
mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec));
file_put_data(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes
flash_write_data_to_file(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes
low_flash_available();
}
else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) {
@@ -162,16 +165,23 @@ int cbor_config(const uint8_t *data, size_t len) {
random_gen(NULL, key_dev_enc, 12);
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorAutCt.data);
ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, file_get_size(ef_keydev), key_dev_enc, NULL, 0, file_get_data(ef_keydev), key_dev_enc + 12, key_dev_enc + 12 + file_get_size(ef_keydev));
ret = mbedtls_chachapoly_encrypt_and_tag(&chatx,
file_get_size(ef_keydev),
key_dev_enc,
NULL,
0,
file_get_data(ef_keydev),
key_dev_enc + 12,
key_dev_enc + 12 + file_get_size(ef_keydev));
mbedtls_chachapoly_free(&chatx);
if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
file_put_data(ef_keydev_enc, key_dev_enc, sizeof(key_dev_enc));
flash_write_data_to_file(ef_keydev_enc, key_dev_enc, sizeof(key_dev_enc));
mbedtls_platform_zeroize(key_dev_enc, sizeof(key_dev_enc));
file_put_data(ef_keydev, key_dev_enc, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
flash_write_data_to_file(ef_keydev, key_dev_enc, file_get_size(ef_keydev)); // Overwrite ef with 0
flash_write_data_to_file(ef_keydev, NULL, 0); // Set ef to 0 bytes
low_flash_available();
}
else {
@@ -197,15 +207,17 @@ int cbor_config(const uint8_t *data, size_t len) {
if (file_has_data(ef_pin) && file_get_data(ef_pin)[1] < newMinPinLength) {
forceChangePin = ptrue;
}
uint8_t *dataf = (uint8_t *) calloc(1, 2 + minPinLengthRPIDs_len * 32);
dataf[0] = (uint8_t)newMinPinLength;
dataf[1] = forceChangePin == ptrue ? 1 : 0;
for (size_t m = 0; m < minPinLengthRPIDs_len; m++) {
mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data, minPinLengthRPIDs[m].len, dataf + 2 + m * 32, 0);
uint8_t *data = (uint8_t *) calloc(1, 2 + minPinLengthRPIDs_len * 32);
data[0] = newMinPinLength;
data[1] = forceChangePin == ptrue ? 1 : 0;
for (int m = 0; m < minPinLengthRPIDs_len; m++) {
mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data,
minPinLengthRPIDs[m].len,
data + 2 + m * 32,
0);
}
file_put_data(ef_minpin, dataf, (uint16_t)(2 + minPinLengthRPIDs_len * 32));
flash_write_data_to_file(ef_minpin, data, 2 + minPinLengthRPIDs_len * 32);
low_flash_available();
free(dataf);
goto err; //No return
}
else if (subcommand == 0x01) {
@@ -215,13 +227,13 @@ int cbor_config(const uint8_t *data, size_t len) {
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
//CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
//resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
err:
CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(vendorAutCt);
for (size_t i = 0; i < minPinLengthRPIDs_len; i++) {
for (int i = 0; i < minPinLengthRPIDs_len; i++) {
CBOR_FREE_BYTE_STRING(minPinLengthRPIDs[i]);
}
@@ -231,6 +243,6 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -22,7 +22,7 @@
#include "files.h"
#include "apdu.h"
#include "credential.h"
#include "pico_keys.h"
#include "hsm.h"
uint8_t rp_counter = 1;
uint8_t rp_total = 0;
@@ -120,9 +120,10 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (subcommand == 0x01) {
if (verify((uint8_t)pinUvAuthProtocol, paut.data, (const uint8_t *) "\x01", 1, pinUvAuthParam.data) != CborNoError) {
if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *) "\x01", 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (is_preview == false &&
@@ -131,7 +132,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
uint8_t existing = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
if (file_has_data(search_dynamic_file((uint16_t)(EF_CRED + i)))) {
if (file_has_data(search_dynamic_file(EF_CRED + i))) {
existing++;
}
}
@@ -144,10 +145,12 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
else if (subcommand == 0x02 || subcommand == 0x03) {
file_t *rp_ef = NULL;
if (subcommand == 0x02) {
if (verify((uint8_t)pinUvAuthProtocol, paut.data, (const uint8_t *) "\x02", 1, pinUvAuthParam.data) != CborNoError) {
if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *) "\x02", 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) {
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
rp_counter = 1;
@@ -160,7 +163,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_RP + i));
file_t *tef = search_dynamic_file(EF_RP + i);
if (file_has_data(tef) && *file_get_data(tef) > 0) {
if (++skip == rp_counter) {
if (rp_ef == NULL) {
@@ -199,7 +202,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
if (subcommand == 0x04) {
*(raw_subpara - 1) = 0x04;
if (verify((uint8_t)pinUvAuthProtocol, paut.data, raw_subpara - 1, (uint16_t)(raw_subpara_len + 1), pinUvAuthParam.data) != CborNoError) {
if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (is_preview == false &&
@@ -219,7 +223,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
file_t *cred_ef = NULL;
uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *tef = search_dynamic_file(EF_CRED + i);
if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) {
if (++skip == cred_counter) {
if (cred_ef == NULL) {
@@ -239,13 +243,14 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
Credential cred = { 0 };
if (credential_load(file_get_data(cred_ef) + 32, file_get_size(cred_ef) - 32, rpIdHash.data, &cred) != 0) {
if (credential_load(file_get_data(cred_ef) + 32, file_get_size(cred_ef) - 32, rpIdHash.data,
&cred) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key);
if (fido_load_key((int)cred.curve, cred.id.data, &key) != 0) {
if (fido_load_key(cred.curve, cred.id.data, &key) != 0) {
credential_free(&cred);
mbedtls_ecdsa_free(&key);
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
@@ -285,11 +290,13 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
if (cred.userName.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "name"));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userName.data, cred.userName.len));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userName.data,
cred.userName.len));
}
if (cred.userDisplayName.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "displayName"));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userDisplayName.data, cred.userDisplayName.len));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userDisplayName.data,
cred.userDisplayName.len));
}
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -324,11 +331,13 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey)));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey,
sizeof(largeBlobKey)));
mbedtls_platform_zeroize(largeBlobKey, sizeof(largeBlobKey));
}
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, cred.extensions.thirdPartyPayment == ptrue));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder,
cred.extensions.thirdPartyPayment == ptrue));
}
else {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
@@ -342,7 +351,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
*(raw_subpara - 1) = 0x06;
if (verify((uint8_t)pinUvAuthProtocol, paut.data, raw_subpara - 1, (uint16_t)(raw_subpara_len + 1), pinUvAuthParam.data) != CborNoError) {
if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (is_preview == false &&
@@ -351,15 +361,18 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
file_t *ef = search_dynamic_file(EF_CRED + i);
if (file_has_data(ef) &&
memcmp(file_get_data(ef) + 32, credentialId.id.data,
MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
uint8_t *rp_id_hash = file_get_data(ef);
if (delete_file(ef) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) {
file_t *rp_ef = search_dynamic_file((uint16_t)(EF_RP + j));
if (file_has_data(rp_ef) && memcmp(file_get_data(rp_ef) + 1, rp_id_hash, 32) == 0) {
file_t *rp_ef = search_dynamic_file(EF_RP + j);
if (file_has_data(rp_ef) &&
memcmp(file_get_data(rp_ef) + 1, rp_id_hash, 32) == 0) {
uint8_t *rp_data = (uint8_t *) calloc(1, file_get_size(rp_ef));
memcpy(rp_data, file_get_data(rp_ef), file_get_size(rp_ef));
rp_data[0] -= 1;
@@ -367,7 +380,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
delete_file(rp_ef);
}
else {
file_put_data(rp_ef, rp_data, file_get_size(rp_ef));
flash_write_data_to_file(rp_ef, rp_data, file_get_size(rp_ef));
}
free(rp_data);
break;
@@ -384,7 +397,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
*(raw_subpara - 1) = 0x07;
if (verify((uint8_t)pinUvAuthProtocol, paut.data, raw_subpara - 1, (uint16_t)(raw_subpara_len + 1), pinUvAuthParam.data) != CborNoError) {
if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (is_preview == false &&
@@ -393,14 +407,18 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
file_t *ef = search_dynamic_file(EF_CRED + i);
if (file_has_data(ef) &&
memcmp(file_get_data(ef) + 32, credentialId.id.data,
MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
Credential cred = { 0 };
uint8_t *rp_id_hash = file_get_data(ef);
if (credential_load(rp_id_hash + 32, file_get_size(ef) - 32, rp_id_hash, &cred) != 0) {
if (credential_load(rp_id_hash + 32, file_get_size(ef) - 32, rp_id_hash,
&cred) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
if (memcmp(user.id.data, cred.userId.data, MIN(user.id.len, cred.userId.len)) != 0) {
if (memcmp(user.id.data, cred.userId.data,
MIN(user.id.len, cred.userId.len)) != 0) {
credential_free(&cred);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
@@ -408,8 +426,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
size_t newcred_len = 0;
if (credential_create(&cred.rpId, &cred.userId, &user.parent.name,
&user.displayName, &cred.opts, &cred.extensions,
cred.use_sign_count, (int)cred.alg,
(int)cred.curve, newcred, &newcred_len) != 0) {
cred.use_sign_count, cred.alg,
cred.curve, newcred, &newcred_len) != 0) {
credential_free(&cred);
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
@@ -435,8 +453,7 @@ err:
CBOR_FREE_BYTE_STRING(user.displayName);
CBOR_FREE_BYTE_STRING(user.parent.name);
CBOR_FREE_BYTE_STRING(credentialId.type);
CBOR_FREE_BYTE_STRING(credentialId.id);
for (size_t n = 0; n < credentialId.transports_len; n++) {
for (int n = 0; n < credentialId.transports_len; n++) {
CBOR_FREE_BYTE_STRING(credentialId.transports[n]);
}
if (error != CborNoError) {
@@ -445,6 +462,6 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -17,14 +17,14 @@
#include "cbor.h"
#include "ctap.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#include "hid/ctap_hid.h"
#include "fido.h"
#include "files.h"
#include "crypto_utils.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "cbor_make_credential.h"
#include "credential.h"
@@ -43,8 +43,6 @@ uint8_t *datax = NULL;
size_t lenx = 0;
int cbor_get_next_assertion(const uint8_t *data, size_t len) {
(void) data;
(void) len;
CborError error = CborNoError;
if (credentialCounter >= numberOfCredentialsx) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
@@ -203,7 +201,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
uint8_t flags = 0;
uint8_t rp_id_hash[32] = {0};
uint8_t rp_id_hash[32];
mbedtls_sha256((uint8_t *) rpId.data, rpId.len, rp_id_hash, 0);
bool resident = false;
@@ -252,7 +250,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
if (pinUvAuthParam.present == true) { //6.1
int ret = verify((uint8_t)pinUvAuthProtocol, paut.data, clientDataHash.data, (uint16_t)clientDataHash.len, pinUvAuthParam.data);
int ret = verify(pinUvAuthProtocol,
paut.data,
clientDataHash.data,
clientDataHash.len,
pinUvAuthParam.data);
if (ret != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
@@ -280,14 +282,15 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
if (allowList_len > 0) {
for (size_t e = 0; e < allowList_len; e++) {
for (int e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (strcmp(allowList[e].type.data, "public-key") != 0) {
continue;
}
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) {
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash,
&creds[creds_len]) != 0) {
CBOR_FREE_BYTE_STRING(allowList[e].id);
credential_free(&creds[creds_len]);
}
@@ -297,12 +300,17 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
}
else {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
for (int i = 0;
i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST;
i++) {
file_t *ef = search_dynamic_file(EF_CRED + i);
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
int ret = credential_load(file_get_data(ef) + 32, file_get_size(ef) - 32, rp_id_hash, &creds[creds_len]);
int ret = credential_load(file_get_data(ef) + 32,
file_get_size(ef) - 32,
rp_id_hash,
&creds[creds_len]);
if (ret != 0) {
credential_free(&creds[creds_len]);
}
@@ -312,10 +320,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
resident = true;
}
for (size_t i = 0; i < creds_len; i++) {
for (int i = 0; i < creds_len; i++) {
if (creds[i].present == true) {
if (creds[i].extensions.present == true) {
if (creds[i].extensions.credProtect == CRED_PROT_UV_REQUIRED && !(flags & FIDO2_AUT_FLAG_UV)) {
if (creds[i].extensions.credProtect == CRED_PROT_UV_REQUIRED &&
!(flags & FIDO2_AUT_FLAG_UV)) {
credential_free(&creds[i]);
}
else if (creds[i].extensions.credProtect == CRED_PROT_UV_OPTIONAL_WITH_LIST &&
@@ -323,21 +332,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
credential_free(&creds[i]);
}
else {
if (numberOfCredentials != i) {
creds[numberOfCredentials++] = creds[i];
}
else {
numberOfCredentials++;
}
creds[numberOfCredentials++] = creds[i];
}
}
else {
if (numberOfCredentials != i) {
creds[numberOfCredentials++] = creds[i];
}
else {
numberOfCredentials++;
}
creds[numberOfCredentials++] = creds[i];
}
}
}
@@ -407,9 +406,17 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
flags = flagsx;
selcred = &credsx[credentialCounter];
}
mbedtls_ecp_keypair ekey;
mbedtls_ecp_keypair_init(&ekey);
int ret = fido_load_key(selcred->curve, selcred->id.data, &ekey);
if (ret != 0) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
}
int ret = 0;
uint8_t largeBlobKey[32] = {0};
uint8_t largeBlobKey[32];
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
ret = credential_derive_large_blob_key(selcred->id.data, selcred->id.len, largeBlobKey);
if (ret != 0) {
@@ -418,7 +425,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
size_t ext_len = 0;
uint8_t ext[512] = {0};
uint8_t ext[512];
if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0;
@@ -449,7 +456,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "hmac-secret"));
uint8_t sharedSecret[64] = {0};
uint8_t sharedSecret[64];
mbedtls_ecp_point Qp;
mbedtls_ecp_point_init(&Qp);
mbedtls_mpi_lset(&Qp.Z, 1);
@@ -461,23 +468,28 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
mbedtls_ecp_point_free(&Qp);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
ret = ecdh((uint8_t)hmacSecretPinUvAuthProtocol, &Qp, sharedSecret);
int ret = ecdh(hmacSecretPinUvAuthProtocol, &Qp, sharedSecret);
mbedtls_ecp_point_free(&Qp);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (verify((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_auth.data) != 0) {
if (verify(hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, salt_enc.len,
salt_auth.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_EXTENSION_FIRST);
}
uint8_t salt_dec[64] = {0}, poff = ((uint8_t)hmacSecretPinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, (uint16_t)salt_enc.len, salt_dec);
uint8_t salt_dec[64], poff = (hmacSecretPinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt(hmacSecretPinUvAuthProtocol,
sharedSecret,
salt_enc.data,
salt_enc.len,
salt_dec);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t cred_random[64] = {0}, *crd = NULL;
uint8_t cred_random[64], *crd = NULL;
ret = credential_derive_hmac_key(selcred->id.data, selcred->id.len, cred_random);
if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
@@ -489,12 +501,22 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
else {
crd = cred_random;
}
uint8_t out1[64] = {0}, hmac_res[80] = {0};
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec, 32, out1);
if ((uint8_t)salt_enc.len == 64 + poff) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec + 32, 32, out1 + 32);
uint8_t out1[64], hmac_res[80];
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
crd,
32,
salt_dec,
32,
out1);
if (salt_enc.len == 64 + poff) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
crd,
32,
salt_dec + 32,
32,
out1 + 32);
}
encrypt((uint8_t)hmacSecretPinUvAuthProtocol, sharedSecret, out1, (uint16_t)(salt_enc.len - poff), hmac_res);
encrypt(hmacSecretPinUvAuthProtocol, sharedSecret, out1, salt_enc.len - poff, hmac_res);
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, hmac_res, salt_enc.len));
}
if (extensions.thirdPartyPayment != NULL) {
@@ -519,37 +541,60 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags;
*pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
*pa++ = ctr >> 24;
*pa++ = ctr >> 16;
*pa++ = ctr >> 8;
*pa++ = ctr & 0xff;
memcpy(pa, ext, ext_len); pa += ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) {
if (pa - aut_data != aut_data_len) {
CBOR_ERROR(CTAP1_ERR_OTHER);
}
memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[64] = {0}, sig[MBEDTLS_ECDSA_MAX_LEN] = {0};
uint8_t hash[64], sig[MBEDTLS_ECDSA_MAX_LEN];
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey);
ret = fido_load_key((int)selcred->curve, selcred->id.data, &ekey);
if (ret != 0) {
if (derive_key(rp_id_hash, false, selcred->id.data, MBEDTLS_ECP_DP_SECP256R1, &ekey) != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
}
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
}
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
mbedtls_ecdsa_free(&ekey);
if (md != NULL) {
ret = mbedtls_md(md,
aut_data,
aut_data_len + clientDataHash.len,
hash);
ret = mbedtls_ecdsa_write_signature(&ekey,
mbedtls_md_get_type(md),
hash,
mbedtls_md_get_size(md),
sig,
sizeof(sig),
&olen,
random_gen,
NULL);
}
else {
ret = mbedtls_eddsa_write_signature(&ekey,
aut_data,
aut_data_len + clientDataHash.len,
sig,
sizeof(sig),
&olen,
MBEDTLS_EDDSA_PURE,
NULL,
0,
random_gen,
NULL);
}
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
mbedtls_ecp_keypair_free(&ekey);
uint8_t lfields = 3;
if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
@@ -561,7 +606,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
lfields++;
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, lfields));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
@@ -616,26 +661,22 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
err:
CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(rpId);
CBOR_FREE_BYTE_STRING(kax);
CBOR_FREE_BYTE_STRING(kay);
CBOR_FREE_BYTE_STRING(salt_enc);
CBOR_FREE_BYTE_STRING(salt_auth);
if (asserted == false) {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&creds[i]);
}
}
for (size_t m = 0; m < MAX_CREDENTIAL_COUNT_IN_LIST; m++) {
for (int m = 0; m < allowList_len; m++) {
CBOR_FREE_BYTE_STRING(allowList[m].type);
CBOR_FREE_BYTE_STRING(allowList[m].id);
for (size_t n = 0; n < 8; n++) {
for (int n = 0; n < allowList[m].transports_len; n++) {
CBOR_FREE_BYTE_STRING(allowList[m].transports[n]);
}
}
@@ -648,6 +689,6 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -26,7 +26,7 @@
int cbor_get_info() {
CborEncoder encoder, mapEncoder, arrayEncoder, mapEncoder2;
CborError error = CborNoError;
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 15));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
@@ -90,11 +90,14 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 4));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 5));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_EDDSA, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
@@ -133,6 +136,6 @@ err:
if (error != CborNoError) {
return -CTAP2_ERR_INVALID_CBOR;
}
res_APDU_size = (uint16_t)cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1);
return 0;
}

View File

@@ -21,7 +21,7 @@
#include "hid/ctap_hid.h"
#include "files.h"
#include "apdu.h"
#include "pico_keys.h"
#include "hsm.h"
#include "mbedtls/sha256.h"
static uint64_t expectedLength = 0, expectedNextOffset = 0;
@@ -79,7 +79,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (get > 0) {
if (length != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -129,12 +129,13 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
uint8_t verify_data[70] = { 0 };
memset(verify_data, 0xff, 32);
verify_data[32] = 0x0C;
verify_data[34] = offset & 0xFF;
verify_data[35] = (offset >> 8) & 0xFF;
verify_data[36] = (offset >> 16) & 0xFF;
verify_data[37] = (offset >> 24) & 0xFF;
verify_data[34] = offset & 0xff;
verify_data[35] = offset >> 8;
verify_data[36] = offset >> 16;
verify_data[37] = offset >> 24;
mbedtls_sha256(set.data, set.len, verify_data + 38, 0);
if (verify((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) {
if (verify(pinUvAuthProtocol, paut.data, verify_data, sizeof(verify_data),
pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (!(paut.permissions & CTAP_PERMISSION_LBW)) {
@@ -154,7 +155,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
if (expectedLength > 17 && memcmp(sha, temp_lba + expectedLength - 16, 16) != 0) {
CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE);
}
file_put_data(ef_largeblob, temp_lba, (uint16_t)expectedLength);
flash_write_data_to_file(ef_largeblob, temp_lba, expectedLength);
low_flash_available();
}
goto err;
@@ -167,6 +168,6 @@ err:
if (error != CborNoError) {
return -CTAP2_ERR_INVALID_CBOR;
}
res_APDU_size = (uint16_t)cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1);
return 0;
}

View File

@@ -25,7 +25,7 @@
#include "credential.h"
#include "mbedtls/sha256.h"
#include "random.h"
#include "pico_keys.h"
#include "hsm.h"
int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser;
@@ -162,7 +162,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(map, 1);
uint8_t flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32] = {0};
uint8_t rp_id_hash[32];
mbedtls_sha256((uint8_t *) rp.id.data, rp.id.len, rp_id_hash, 0);
if (pinUvAuthParam.present == true) {
@@ -192,7 +192,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
for (unsigned int i = 0; i < pubKeyCredParams_len; i++) {
for (int i = 0; i < pubKeyCredParams_len; i++) {
if (pubKeyCredParams[i].type.present == false) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
@@ -221,15 +221,20 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (curve <= 0) {
curve = FIDO2_CURVE_P256K1;
}
}
else if (pubKeyCredParams[i].alg == FIDO2_ALG_EDDSA) {
if (curve <= 0) {
curve = FIDO2_CURVE_ED25519;
}
}
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass
}
//else {
// CBOR_ERROR(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
//}
else {
CBOR_ERROR(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
}
if (curve > 0 && alg == 0) {
alg = (int)pubKeyCredParams[i].alg;
alg = pubKeyCredParams[i].alg;
}
}
if (curve <= 0) {
@@ -259,7 +264,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
//Unfinished. See 6.1.2.9
}
if (pinUvAuthParam.present == true) { //11.1
int ret = verify((uint8_t)pinUvAuthProtocol, paut.data, clientDataHash.data, (uint16_t)clientDataHash.len, pinUvAuthParam.data);
int ret = verify(pinUvAuthProtocol,
paut.data,
clientDataHash.data,
clientDataHash.len,
pinUvAuthParam.data);
if (ret != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
@@ -279,11 +288,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
}
for (size_t e = 0; e < excludeList_len; e++) { //12.1
for (int e = 0; e < excludeList_len; e++) { //12.1
if (excludeList[e].type.present == false || excludeList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) {
if (strcmp(excludeList[e].type.data, "public-key") != 0) {
continue;
}
Credential ecred;
@@ -291,10 +300,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
&ecred) == 0 &&
(ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED ||
(flags & FIDO2_AUT_FLAG_UV))) {
credential_free(&ecred);
CBOR_ERROR(CTAP2_ERR_CREDENTIAL_EXCLUDED);
}
credential_free(&ecred);
}
if (extensions.largeBlobKey == pfalse ||
@@ -311,16 +318,14 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
}
flags |= FIDO2_AUT_FLAG_UP;
if (options.up == ptrue) {
clearUserPresentFlag();
clearUserVerifiedFlag();
clearPinUvAuthTokenPermissionsExceptLbw();
}
clearUserPresentFlag();
clearUserVerifiedFlag();
clearPinUvAuthTokenPermissionsExceptLbw();
}
const known_app_t *ka = find_app_by_rp_id_hash(rp_id_hash);
uint8_t cred_id[MAX_CRED_ID_LENGTH] = {0};
uint8_t cred_id[MAX_CRED_ID_LENGTH];
size_t cred_id_len = 0;
CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options,
@@ -331,7 +336,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
flags |= FIDO2_AUT_FLAG_UV;
}
size_t ext_len = 0;
uint8_t ext[512] = {0};
uint8_t ext[512];
CborEncoder encoder, mapEncoder, mapEncoder2;
if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
@@ -386,21 +391,21 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED;
}
mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey);
mbedtls_ecp_keypair ekey;
mbedtls_ecp_keypair_init(&ekey);
int ret = fido_load_key(curve, cred_id, &ekey);
if (ret != 0) {
mbedtls_ecdsa_free(&ekey);
mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id);
if (cinfo == NULL) {
mbedtls_ecdsa_free(&ekey);
mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
size_t olen = 0;
uint32_t ctr = get_sign_counter();
uint8_t cbor_buf[1024] = {0};
uint8_t cbor_buf[1024];
cbor_encoder_init(&encoder, cbor_buf, sizeof(cbor_buf), 0);
CBOR_CHECK(COSE_key(&ekey, &encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf);
@@ -410,23 +415,23 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags;
*pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
*pa++ = ctr >> 24;
*pa++ = ctr >> 16;
*pa++ = ctr >> 8;
*pa++ = ctr & 0xff;
memcpy(pa, aaguid, 16); pa += 16;
*pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF;
*pa++ = (uint16_t)cred_id_len & 0xFF;
memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len;
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey);
*pa++ = cred_id_len >> 8;
*pa++ = cred_id_len & 0xff;
memcpy(pa, cred_id, cred_id_len); pa += cred_id_len;
memcpy(pa, cbor_buf, rs); pa += rs;
memcpy(pa, ext, ext_len); pa += ext_len;
if (pa - aut_data != aut_data_len) {
mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER);
}
memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[64] = {0}, sig[MBEDTLS_ECDSA_MAX_LEN] = {0};
uint8_t hash[64], sig[MBEDTLS_ECDSA_MAX_LEN];
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
@@ -434,20 +439,53 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
if (md != NULL) {
ret = mbedtls_md(md,
aut_data,
aut_data_len + clientDataHash.len,
hash);
}
bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
mbedtls_ecdsa_free(&ekey);
mbedtls_ecdsa_init(&ekey);
mbedtls_ecp_keypair_free(&ekey);
mbedtls_ecp_keypair_init(&ekey);
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32);
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
self_attestation = false;
}
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
mbedtls_ecdsa_free(&ekey);
if (md != NULL) {
ret = mbedtls_ecdsa_write_signature(&ekey,
mbedtls_md_get_type(md),
hash,
mbedtls_md_get_size(md),
sig,
sizeof(sig),
&olen,
random_gen,
NULL);
}
else {
ret = mbedtls_eddsa_write_signature(&ekey,
aut_data,
aut_data_len + clientDataHash.len,
sig,
sizeof(sig),
&olen,
MBEDTLS_EDDSA_PURE,
NULL,
0,
random_gen,
NULL);
}
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
mbedtls_ecp_keypair_free(&ekey);
uint8_t largeBlobKey[32] = {0};
uint8_t largeBlobKey[32];
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
ret = credential_derive_large_blob_key(cred_id, cred_id_len, largeBlobKey);
if (ret != 0) {
@@ -455,8 +493,10 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, extensions.largeBlobKey == ptrue && options.rk == ptrue ? 5 : 4));
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder,
extensions.largeBlobKey == ptrue &&
options.rk == ptrue ? 5 : 4));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed"));
@@ -464,9 +504,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aut_data, aut_data_len));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, self_attestation == false || is_nitrokey ? 3 : 2));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2,
self_attestation == false || is_nitrokey ? 3 : 2));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg"));
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation || is_nitrokey ? -alg : -FIDO2_ALG_ES256));
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2,
self_attestation || is_nitrokey ? -alg : -FIDO2_ALG_ES256));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, sig, olen));
if (self_attestation == false || is_nitrokey) {
@@ -480,7 +522,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "x5c"));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder2, &arrEncoder, 1));
CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert), file_get_size(ef_cert)));
CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert),
file_get_size(ef_cert)));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder2, &arrEncoder));
}
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -502,7 +545,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
}
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
err:
CBOR_FREE_BYTE_STRING(clientDataHash);
@@ -512,17 +555,14 @@ err:
CBOR_FREE_BYTE_STRING(user.id);
CBOR_FREE_BYTE_STRING(user.displayName);
CBOR_FREE_BYTE_STRING(user.parent.name);
if (extensions.present == true) {
CBOR_FREE_BYTE_STRING(extensions.credBlob);
}
for (size_t n = 0; n < MAX_CREDENTIAL_COUNT_IN_LIST; n++) {
for (int n = 0; n < pubKeyCredParams_len; n++) {
CBOR_FREE_BYTE_STRING(pubKeyCredParams[n].type);
}
for (size_t m = 0; m < MAX_CREDENTIAL_COUNT_IN_LIST; m++) {
for (int m = 0; m < excludeList_len; m++) {
CBOR_FREE_BYTE_STRING(excludeList[m].type);
CBOR_FREE_BYTE_STRING(excludeList[m].id);
for (size_t n = 0; n < excludeList[m].transports_len; n++) {
for (int n = 0; n < excludeList[m].transports_len; n++) {
CBOR_FREE_BYTE_STRING(excludeList[m].transports[n]);
}
}
@@ -535,6 +575,6 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -18,12 +18,9 @@
#include "file.h"
#include "fido.h"
#include "ctap.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#endif
extern void scan_all();

View File

@@ -21,7 +21,7 @@
#include "hid/ctap_hid.h"
#include "files.h"
#include "apdu.h"
#include "pico_keys.h"
#include "hsm.h"
#include "random.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/chachapoly.h"
@@ -101,7 +101,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
}
CBOR_PARSE_MAP_END(map, 1);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (cmd == CTAP_VENDOR_BACKUP) {
if (vendorCmd == 0x01) {
@@ -121,9 +121,9 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
}
uint8_t zeros[32];
memset(zeros, 0, sizeof(zeros));
file_put_data(ef_keydev_enc, vendorParam.data, (uint16_t)vendorParam.len);
file_put_data(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
flash_write_data_to_file(ef_keydev_enc, vendorParam.data, vendorParam.len);
flash_write_data_to_file(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0
flash_write_data_to_file(ef_keydev, NULL, 0); // Set ef to 0 bytes
low_flash_available();
goto err;
}
@@ -223,7 +223,14 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
size_t keyenc_len = file_get_size(ef_keydev_enc);
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorParam.data);
ret = mbedtls_chachapoly_auth_decrypt(&chatx, sizeof(keydev_dec), keyenc, NULL, 0, keyenc + keyenc_len - 16, keyenc + 12, keydev_dec);
ret = mbedtls_chachapoly_auth_decrypt(&chatx,
sizeof(keydev_dec),
keyenc,
NULL,
0,
keyenc + keyenc_len - 16,
keyenc + 12,
keydev_dec);
mbedtls_chachapoly_free(&chatx);
if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -236,7 +243,10 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buffer[1024];
mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), file_get_size(ef_keydev));
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1,
&ekey,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -246,11 +256,27 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
#ifndef ENABLE_EMULATION
pico_unique_board_id_t rpiid;
pico_get_unique_board_id(&rpiid);
#else
struct {
uint8_t id[8];
} rpiid = { 0 };
#endif
mbedtls_x509write_csr ctx;
mbedtls_x509write_csr_init(&ctx);
snprintf((char *) buffer,
sizeof(buffer),
"C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str);
"C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %02x%02x%02x%02x%02x%02x%02x%02x",
rpiid.id[0],
rpiid.id[1],
rpiid.id[2],
rpiid.id[3],
rpiid.id[4],
rpiid.id[5],
rpiid.id[6],
rpiid.id[7]);
mbedtls_x509write_csr_set_subject_name(&ctx, (char *) buffer);
mbedtls_pk_context key;
mbedtls_pk_init(&key);
@@ -280,7 +306,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
}
file_t *ef_ee_ea = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (ef_ee_ea) {
file_put_data(ef_ee_ea, vendorParam.data, (uint16_t)vendorParam.len);
flash_write_data_to_file(ef_ee_ea, vendorParam.data, vendorParam.len);
}
low_flash_available();
goto err;
@@ -302,7 +328,7 @@ err:
}
return error;
}
res_APDU_size = (uint16_t)resp_size;
res_APDU_size = resp_size;
return 0;
}

View File

@@ -16,7 +16,7 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "ctap.h"
#include "random.h"
@@ -50,7 +50,6 @@ int cmd_authenticate() {
ret = derive_key(req->appId, false, req->keyHandle, MBEDTLS_ECP_DP_SECP256R1, &key);
if (verify_key(req->appId, req->keyHandle, &key) != 0) {
mbedtls_ecdsa_free(&key);
free(tmp_kh);
return SW_INCORRECT_PARAMS();
}
}
@@ -66,30 +65,39 @@ int cmd_authenticate() {
resp->flags = 0;
resp->flags |= P1(apdu) == CTAP_AUTH_ENFORCE ? CTAP_AUTH_FLAG_TUP : 0x0;
uint32_t ctr = get_sign_counter();
resp->ctr[0] = (ctr >> 24) & 0xFF;
resp->ctr[1] = (ctr >> 16) & 0xFF;
resp->ctr[2] = (ctr >> 8) & 0xFF;
resp->ctr[3] = ctr & 0xFF;
resp->ctr[0] = ctr >> 24;
resp->ctr[1] = ctr >> 16;
resp->ctr[2] = ctr >> 8;
resp->ctr[3] = ctr & 0xff;
uint8_t hash[32], sig_base[CTAP_APPID_SIZE + 1 + 4 + CTAP_CHAL_SIZE];
memcpy(sig_base, req->appId, CTAP_APPID_SIZE);
memcpy(sig_base + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t));
memcpy(sig_base + CTAP_APPID_SIZE + 1, resp->ctr, 4);
memcpy(sig_base + CTAP_APPID_SIZE + 1 + 4, req->chal, CTAP_CHAL_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sig_base, sizeof(sig_base), hash);
ret =
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sig_base, sizeof(sig_base), hash);
if (ret != 0) {
mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&key,
MBEDTLS_MD_SHA256,
hash,
32,
(uint8_t *) resp->sig,
CTAP_MAX_EC_SIG_SIZE,
&olen,
random_gen,
NULL);
mbedtls_ecdsa_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();
}
res_APDU_size = 1 + 4 + (uint16_t)olen;
res_APDU_size = 1 + 4 + olen;
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
return SW_OK();
}

View File

@@ -16,7 +16,7 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "ctap.h"
#include "random.h"
@@ -32,25 +32,27 @@ const uint8_t u2f_aid[] = {
int u2f_unload();
int u2f_process_apdu();
int u2f_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_U2F)) {
app_t *u2f_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, u2f_aid + 1, MIN(aid_len, u2f_aid[0])) && cap_supported(CAP_U2F)) {
a->aid = u2f_aid;
a->process_apdu = u2f_process_apdu;
a->unload = u2f_unload;
return CCID_OK;
return a;
}
return CCID_ERR_FILE_NOT_FOUND;
return NULL;
}
INITIALIZER ( u2f_ctor ) {
register_app(u2f_select, u2f_aid);
void __attribute__((constructor)) u2f_ctor() {
register_app(u2f_select);
}
int u2f_unload() {
return CCID_OK;
}
const uint8_t *bogus_firefox = (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
const uint8_t *bogus_firefox =
(const uint8_t *)
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
const uint8_t *bogus_chrome = (const uint8_t *) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
extern int ctap_error(uint8_t error);
@@ -82,20 +84,33 @@ int cmd_register() {
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&key.grp, &key.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (uint8_t *) &resp->pubKey, CTAP_EC_POINT_SIZE);
ret =
mbedtls_ecp_point_write_binary(&key.grp,
&key.Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&olen,
(uint8_t *) &resp->pubKey,
CTAP_EC_POINT_SIZE);
mbedtls_ecdsa_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();
}
uint16_t ef_certdev_size = file_get_size(ef_certdev);
size_t ef_certdev_size = file_get_size(ef_certdev);
memcpy(resp->keyHandleCertSig + KEY_HANDLE_LEN, file_get_data(ef_certdev), ef_certdev_size);
uint8_t hash[32], sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE];
uint8_t hash[32],
sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE];
sign_base[0] = CTAP_REGISTER_HASH_ID;
memcpy(sign_base + 1, req->appId, CTAP_APPID_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE, req->chal, CTAP_CHAL_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig, KEY_HANDLE_LEN);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN, (uint8_t *) &resp->pubKey, CTAP_EC_POINT_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sign_base, sizeof(sign_base), hash);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig,
KEY_HANDLE_LEN);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN,
(uint8_t *) &resp->pubKey,
CTAP_EC_POINT_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
sign_base,
sizeof(sign_base),
hash);
if (ret != 0) {
return SW_EXEC_ERROR();
}
@@ -105,12 +120,21 @@ int cmd_register() {
mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR();
}
ret = mbedtls_ecdsa_write_signature(&key,MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&key,
MBEDTLS_MD_SHA256,
hash,
32,
(uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size,
CTAP_MAX_EC_SIG_SIZE,
&olen,
random_gen,
NULL);
mbedtls_ecdsa_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();
}
res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN + ef_certdev_size + (uint16_t)olen;
res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN +
ef_certdev_size + olen;
return SW_OK();
}

View File

@@ -16,10 +16,10 @@
*/
#include "apdu.h"
#include "pico_keys.h"
#include "hsm.h"
int cmd_version() {
memcpy(res_APDU, "U2F_V2", strlen("U2F_V2"));
res_APDU_size = (uint16_t)strlen("U2F_V2");
res_APDU_size = strlen("U2F_V2");
return SW_OK();
}

View File

@@ -18,7 +18,7 @@
#include "mbedtls/chachapoly.h"
#include "mbedtls/sha256.h"
#include "credential.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#include "hid/ctap_hid.h"
@@ -26,7 +26,7 @@
#include "ctap.h"
#include "random.h"
#include "files.h"
#include "pico_keys.h"
#include "hsm.h"
int credential_derive_chacha_key(uint8_t *outk);
@@ -41,7 +41,14 @@ int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - (4 + 12 + 16), iv, rp_id_hash, 32, tag, cipher, cipher);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx,
cred_id_len - (4 + 12 + 16),
iv,
rp_id_hash,
32,
tag,
cipher,
cipher);
mbedtls_chachapoly_free(&chatx);
return ret;
}
@@ -76,7 +83,8 @@ int credential_create(CborCharString *rpId,
if (extensions->credBlob.present == true &&
extensions->credBlob.len < MAX_CREDBLOB_LENGTH) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credBlob"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, extensions->credBlob.data, extensions->credBlob.len));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, extensions->credBlob.data,
extensions->credBlob.len));
}
if (extensions->credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credProtect"));
@@ -122,7 +130,11 @@ int credential_create(CborCharString *rpId,
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32,
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx,
rs,
iv,
rp_id_hash,
32,
cred_id + 4 + 12,
cred_id + 4 + 12,
cred_id + 4 + 12 + rs);
@@ -143,7 +155,10 @@ err:
return 0;
}
int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, Credential *cred) {
int credential_load(const uint8_t *cred_id,
size_t cred_id_len,
const uint8_t *rp_id_hash,
Credential *cred) {
int ret = 0;
CborError error = CborNoError;
uint8_t *copy_cred_id = (uint8_t *) calloc(1, cred_id_len);
@@ -190,7 +205,9 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
CBOR_FIELD_KEY_TEXT_VAL_UINT(2, "credProtect", cred->extensions.credProtect);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(2, "credBlob", cred->extensions.credBlob);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "largeBlobKey", cred->extensions.largeBlobKey);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "thirdPartyPayment", cred->extensions.thirdPartyPayment);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2,
"thirdPartyPayment",
cred->extensions.thirdPartyPayment);
CBOR_ADVANCE(2);
}
CBOR_PARSE_MAP_END(_f1, 2);
@@ -241,9 +258,6 @@ void credential_free(Credential *cred) {
CBOR_FREE_BYTE_STRING(cred->userName);
CBOR_FREE_BYTE_STRING(cred->userDisplayName);
CBOR_FREE_BYTE_STRING(cred->id);
if (cred->extensions.present) {
CBOR_FREE_BYTE_STRING(cred->extensions.credBlob);
}
cred->present = false;
cred->extensions.present = false;
cred->opts.present = false;
@@ -259,7 +273,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
credential_free(&cred);
return ret;
}
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file(EF_CRED + i);
Credential rcred = { 0 };
if (!file_has_data(ef)) {
@@ -276,7 +290,8 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
credential_free(&rcred);
continue;
}
if (memcmp(rcred.userId.data, cred.userId.data, MIN(rcred.userId.len, cred.userId.len)) == 0) {
if (memcmp(rcred.userId.data, cred.userId.data,
MIN(rcred.userId.len, cred.userId.len)) == 0) {
sloti = i;
credential_free(&rcred);
new_record = false;
@@ -290,13 +305,13 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
uint8_t *data = (uint8_t *) calloc(1, cred_id_len + 32);
memcpy(data, rp_id_hash, 32);
memcpy(data + 32, cred_id, cred_id_len);
file_t *ef = file_new((uint16_t)(EF_CRED + sloti));
file_put_data(ef, data, (uint16_t)cred_id_len + 32);
file_t *ef = file_new(EF_CRED + sloti);
flash_write_data_to_file(ef, data, cred_id_len + 32);
free(data);
if (new_record == true) { //increase rps
sloti = -1;
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
ef = search_dynamic_file(EF_RP + i);
if (!file_has_data(ef)) {
if (sloti == -1) {
@@ -312,21 +327,21 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
if (sloti == -1) {
return -1;
}
ef = search_dynamic_file((uint16_t)(EF_RP + sloti));
ef = search_dynamic_file(EF_RP + sloti);
if (file_has_data(ef)) {
data = (uint8_t *) calloc(1, file_get_size(ef));
memcpy(data, file_get_data(ef), file_get_size(ef));
data[0] += 1;
file_put_data(ef, data, file_get_size(ef));
flash_write_data_to_file(ef, data, file_get_size(ef));
free(data);
}
else {
ef = file_new((uint16_t)(EF_RP + sloti));
ef = file_new(EF_RP + sloti);
data = (uint8_t *) calloc(1, 1 + 32 + cred.rpId.len);
data[0] = 1;
memcpy(data + 1, rp_id_hash, 32);
memcpy(data + 1 + 32, cred.rpId.data, cred.rpId.len);
file_put_data(ef, data, (uint16_t)(1 + 32 + cred.rpId.len));
flash_write_data_to_file(ef, data, 1 + 32 + cred.rpId.len);
free(data);
}
}

View File

@@ -18,9 +18,16 @@
#ifndef _CTAP_H_
#define _CTAP_H_
#ifdef _MSC_VER // Windows
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C" {

View File

@@ -19,11 +19,7 @@
#define _CTAP2_CBOR_H_
#include "cbor.h"
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h"
@@ -159,7 +155,7 @@ typedef struct CborCharString {
#define CBOR_FIELD_GET_KEY_TEXT(_n) \
CBOR_ASSERT(cbor_value_is_text_string(&(_f##_n)) == true); \
char _fd##_n[64] = {0}; \
char _fd##_n[64]; \
size_t _fdl##_n = sizeof(_fd##_n); \
CBOR_CHECK(cbor_value_copy_text_string(&(_f##_n), _fd##_n, &_fdl##_n, &(_f##_n)))

View File

@@ -16,7 +16,7 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "ctap.h"
#include "files.h"
@@ -27,13 +27,12 @@
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
#include "ccid/ccid.h"
#endif
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#include <math.h>
#include "management.h"
#include "hid/ctap_hid.h"
#include "version.h"
#include "ctap_hid.h"
int fido_process_apdu();
int fido_unload();
@@ -54,33 +53,21 @@ const uint8_t atr_fido[] = {
0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40
};
uint8_t fido_get_version_major() {
return PICO_FIDO_VERSION_MAJOR;
}
uint8_t fido_get_version_minor() {
return PICO_FIDO_VERSION_MINOR;
}
int fido_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_FIDO2)) {
app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0])) && cap_supported(CAP_FIDO2)) {
a->aid = fido_aid;
a->process_apdu = fido_process_apdu;
a->unload = fido_unload;
return CCID_OK;
return a;
}
return CCID_ERR_FILE_NOT_FOUND;
return NULL;
}
extern uint8_t (*get_version_major)();
extern uint8_t (*get_version_minor)();
INITIALIZER ( fido_ctor ) {
void __attribute__((constructor)) fido_ctor() {
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
ccid_atr = atr_fido;
#endif
get_version_major = fido_get_version_major;
get_version_minor = fido_get_version_minor;
register_app(fido_select, fido_aid);
register_app(fido_select);
}
int fido_unload() {
@@ -106,6 +93,12 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448;
}
else if (curve == FIDO2_CURVE_ED25519) {
return MBEDTLS_ECP_DP_ED25519;
}
else if (curve == FIDO2_CURVE_ED448) {
return MBEDTLS_ECP_DP_ED448;
}
return MBEDTLS_ECP_DP_NONE;
}
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
@@ -127,10 +120,16 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448;
}
else if (id == MBEDTLS_ECP_DP_ED25519) {
return FIDO2_CURVE_ED25519;
}
else if (id == MBEDTLS_ECP_DP_ED448) {
return FIDO2_CURVE_ED448;
}
return 0;
}
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) {
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key) {
mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
@@ -151,7 +150,7 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
mbedtls_x509write_crt_set_validity(&ctx, "20220901000000", "20720831235959");
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
uint8_t serial[16];
uint8_t serial[20];
random_gen(NULL, serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context key;
@@ -168,7 +167,6 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL);
mbedtls_x509write_crt_free(&ctx);
/* pk cannot be freed, as it is freed later */
//mbedtls_pk_free(&key);
return ret;
@@ -188,7 +186,7 @@ int load_keydev(uint8_t *key) {
return CCID_OK;
}
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) {
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) {
@@ -205,9 +203,8 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
}
}
uint8_t hmac[32], d[32];
size_t olen = 0;
int ret = mbedtls_ecp_write_key_ext(key, &olen, d, sizeof(d));
if (key == &ctx) {
int ret = mbedtls_ecp_write_key(key, d, sizeof(d));
if (key == NULL) {
mbedtls_ecdsa_free(&ctx);
}
if (ret != 0) {
@@ -216,17 +213,26 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, appId, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN);
ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), d, 32, key_base, sizeof(key_base), hmac);
ret =
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
d,
32,
key_base,
sizeof(key_base),
hmac);
mbedtls_platform_zeroize(d, sizeof(d));
return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac));
}
int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) {
int derive_key(const uint8_t *app_id,
bool new_key,
uint8_t *key_handle,
int curve,
mbedtls_ecp_keypair *key) {
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
int r = 0;
memset(outk, 0, sizeof(outk));
if ((r = load_keydev(outk)) != CCID_OK) {
printf("Error loading keydev: %d\n", r);
return r;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
@@ -237,7 +243,15 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
val |= 0x80000000;
memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t));
}
r = mbedtls_hkdf(md_info, &key_handle[i * sizeof(uint32_t)], sizeof(uint32_t), outk, 32, outk + 32, 32, outk, sizeof(outk));
r = mbedtls_hkdf(md_info,
&key_handle[i * sizeof(uint32_t)],
sizeof(uint32_t),
outk,
32,
outk + 32,
32,
outk,
sizeof(outk));
if (r != 0) {
mbedtls_platform_zeroize(outk, sizeof(outk));
return r;
@@ -247,7 +261,9 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, app_id, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, key_handle, KEY_PATH_LEN);
if ((r = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, key_base, sizeof(key_base), key_handle + 32)) != 0) {
if ((r =
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, key_base,
sizeof(key_base), key_handle + 32)) != 0) {
mbedtls_platform_zeroize(outk, sizeof(outk));
return r;
}
@@ -261,11 +277,14 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (cinfo->bit_size % 8 != 0) {
outk[0] >>= 8 - (cinfo->bit_size % 8);
}
r = mbedtls_ecp_read_key(curve, key, outk, (size_t)ceil((float) cinfo->bit_size / 8));
r = mbedtls_ecp_read_key(curve, key, outk, ceil((float) cinfo->bit_size / 8));
mbedtls_platform_zeroize(outk, sizeof(outk));
if (r != 0) {
return r;
}
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
}
mbedtls_platform_zeroize(outk, sizeof(outk));
@@ -286,13 +305,10 @@ int scan_files() {
mbedtls_ecdsa_free(&ecdsa);
return ret;
}
uint8_t kdata[64];
size_t key_size = 0;
ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, kdata, sizeof(kdata));
if (ret != CCID_OK) {
return ret;
}
ret = file_put_data(ef_keydev, kdata, (uint16_t)key_size);
uint8_t kdata[32];
int key_size = mbedtls_mpi_size(&ecdsa.d);
mbedtls_mpi_write_binary(&ecdsa.d, kdata, key_size);
ret = flash_write_data_to_file(ef_keydev, kdata, key_size);
mbedtls_platform_zeroize(kdata, sizeof(kdata));
mbedtls_ecdsa_free(&ecdsa);
if (ret != CCID_OK) {
@@ -307,10 +323,13 @@ int scan_files() {
ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF);
if (ef_certdev) {
if (!file_has_data(ef_certdev)) {
uint8_t cert[2048];
uint8_t cert[4096];
mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), file_get_size(ef_keydev));
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1,
&key,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) {
mbedtls_ecdsa_free(&key);
return ret;
@@ -325,7 +344,7 @@ int scan_files() {
if (ret <= 0) {
return ret;
}
file_put_data(ef_certdev, cert + sizeof(cert) - ret, (uint16_t)ret);
flash_write_data_to_file(ef_certdev, cert + sizeof(cert) - ret, ret);
}
}
else {
@@ -335,7 +354,7 @@ int scan_files() {
if (ef_counter) {
if (!file_has_data(ef_counter)) {
uint32_t v = 0;
file_put_data(ef_counter, (uint8_t *) &v, sizeof(v));
flash_write_data_to_file(ef_counter, (uint8_t *) &v, sizeof(v));
}
}
else {
@@ -347,7 +366,7 @@ int scan_files() {
if (!file_has_data(ef_authtoken)) {
uint8_t t[32];
random_gen(NULL, t, sizeof(t));
file_put_data(ef_authtoken, t, sizeof(t));
flash_write_data_to_file(ef_authtoken, t, sizeof(t));
}
paut.data = file_get_data(ef_authtoken);
paut.len = file_get_size(ef_authtoken);
@@ -357,7 +376,9 @@ int scan_files() {
}
ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
if (!file_has_data(ef_largeblob)) {
file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17);
flash_write_data_to_file(ef_largeblob,
(const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c",
17);
}
low_flash_available();
return CCID_OK;
@@ -368,10 +389,8 @@ void scan_all() {
scan_files();
}
extern void init_otp();
void init_fido() {
scan_all();
init_otp();
}
bool wait_button_pressed() {
@@ -417,7 +436,7 @@ uint8_t get_opts() {
void set_opts(uint8_t opts) {
file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
file_put_data(ef, &opts, sizeof(uint8_t));
flash_write_data_to_file(ef, &opts, sizeof(uint8_t));
low_flash_available();
}

View File

@@ -18,18 +18,14 @@
#ifndef _FIDO_H_
#define _FIDO_H_
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "pico/stdlib.h"
#endif
#ifndef ESP_PLATFORM
#include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecdsa.h"
#include "mbedtls/eddsa.h"
#ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h"
#include "ctap_hid.h"
#else
#include <stdbool.h>
#endif
@@ -45,16 +41,24 @@ extern int derive_key(const uint8_t *app_id,
bool new_key,
uint8_t *key_handle,
int,
mbedtls_ecdsa_context *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *);
mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern bool wait_button_pressed();
extern void init_fido();
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id);
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key);
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key);
extern int load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
extern int encrypt(uint8_t protocol,
const uint8_t *key,
const uint8_t *in,
size_t in_len,
uint8_t *out);
extern int decrypt(uint8_t protocol,
const uint8_t *key,
const uint8_t *in,
size_t in_len,
uint8_t *out);
extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret);
#define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256
@@ -128,6 +132,10 @@ typedef struct pinUvAuthToken {
extern uint32_t user_present_time_limit;
extern pinUvAuthToken_t paut;
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
extern int verify(uint8_t protocol,
const uint8_t *key,
const uint8_t *data,
size_t len,
uint8_t *sign);
#endif //_FIDO_H

View File

@@ -49,7 +49,7 @@ file_t file_entries[] = {
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL,
.ef_structure = 0, .acl = { 0 } } //end
};

View File

@@ -16,7 +16,7 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "version.h"
#include "files.h"
@@ -31,22 +31,22 @@ const uint8_t man_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
};
extern void scan_all();
extern void init_otp();
int man_select(app_t *a, uint8_t force) {
a->process_apdu = man_process_apdu;
a->unload = man_unload;
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
res_APDU_size = (uint16_t)strlen((char *) res_APDU);
apdu.ne = res_APDU_size;
if (force) {
app_t *man_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, man_aid + 1, MIN(aid_len, man_aid[0]))) {
a->aid = man_aid;
a->process_apdu = man_process_apdu;
a->unload = man_unload;
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
res_APDU_size = strlen((char *) res_APDU);
apdu.ne = res_APDU_size;
scan_all();
init_otp();
return a;
}
return CCID_OK;
return NULL;
}
INITIALIZER ( man_ctor ) {
register_app(man_select, man_aid);
void __attribute__((constructor)) man_ctor() {
register_app(man_select);
}
int man_unload() {
@@ -56,12 +56,10 @@ int man_unload() {
bool cap_supported(uint16_t cap) {
file_t *ef = search_dynamic_file(EF_DEV_CONF);
if (file_has_data(ef)) {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
uint16_t tag = 0x0, data_len = file_get_size(ef);
uint8_t *tag_data = NULL, *p = NULL, *data = file_get_data(ef);
size_t tag_len = 0;
while (walk_tlv(data, data_len, &p, &tag, &tag_len, &tag_data)) {
if (tag == TAG_USB_ENABLED) {
uint16_t ecaps = tag_data[0];
if (tag_len == 2) {
@@ -84,7 +82,9 @@ int man_get_config() {
res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH;
res_APDU[res_APDU_size++] = TAG_SERIAL;
res_APDU[res_APDU_size++] = 4;
memcpy(res_APDU + res_APDU_size, pico_serial.id, 4);
#ifndef ENABLE_EMULATION
pico_get_unique_board_id_string((char *) res_APDU + res_APDU_size, 4);
#endif
res_APDU_size += 4;
res_APDU[res_APDU_size++] = TAG_FORM_FACTOR;
res_APDU[res_APDU_size++] = 1;
@@ -116,7 +116,7 @@ int man_get_config() {
memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef));
res_APDU_size += file_get_size(ef);
}
res_APDU[0] = (uint8_t)(res_APDU_size - 1);
res_APDU[0] = res_APDU_size - 1;
return 0;
}
@@ -130,7 +130,7 @@ int cmd_write_config() {
return SW_WRONG_DATA();
}
file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
flash_write_data_to_file(ef, apdu.data + 1, apdu.nc - 1);
low_flash_available();
return SW_OK();
}

View File

@@ -19,7 +19,7 @@
#define _MANAGEMENT_H_
#include <stdlib.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "pico/stdlib.h"
#endif

View File

@@ -16,7 +16,7 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "files.h"
#include "random.h"
@@ -68,9 +68,9 @@ const uint8_t oath_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01
};
int oath_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_OATH)) {
app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0])) && cap_supported(CAP_OATH)) {
a->aid = oath_aid;
a->process_apdu = oath_process_apdu;
a->unload = oath_unload;
res_APDU_size = 0;
@@ -81,7 +81,12 @@ int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8); res_APDU_size += 8;
#ifndef ENABLE_EMULATION
pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size));
res_APDU_size += 8;
#else
memset(res_APDU + res_APDU_size, 0, 8); res_APDU_size += 8;
#endif
if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
random_gen(NULL, challenge, sizeof(challenge));
res_APDU[res_APDU_size++] = TAG_CHALLENGE;
@@ -100,13 +105,13 @@ int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
apdu.ne = res_APDU_size;
return CCID_OK;
return a;
}
return CCID_ERR_FILE_NOT_FOUND;
return NULL;
}
INITIALIZER ( oath_ctor ) {
register_app(oath_select, oath_aid);
void __attribute__((constructor)) oath_ctor() {
register_app(oath_select);
}
int oath_unload() {
@@ -114,11 +119,14 @@ int oath_unload() {
}
file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
size_t ef_tag_len = 0;
uint8_t *ef_tag_data = NULL;
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
asn1_ctx_t ctxi, ef_tag = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (file_has_data(ef) && asn1_find_tag(&ctxi, TAG_NAME, &ef_tag) == true && ef_tag.len == name_len && memcmp(ef_tag.data, name, name_len) == 0) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef) &&
asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_NAME, &ef_tag_len,
&ef_tag_data) == true && ef_tag_len == name_len &&
memcmp(ef_tag_data, name, name_len) == 0) {
return ef;
}
}
@@ -129,40 +137,40 @@ int cmd_put() {
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
size_t key_len = 0, imf_len = 0, name_len = 0;
uint8_t *key = NULL, *imf = NULL, *name = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(&ctxi, TAG_IMF, &imf) == false) {
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_IMF, &imf_len, &imf) == false) {
memcpy(apdu.data + apdu.nc, "\x7a\x08\x00\x00\x00\x00\x00\x00\x00\x00", 10);
apdu.nc += 10;
}
else { //prepend zero-valued bytes
if (imf.len < 8) {
memmove(imf.data + (8 - imf.len), imf.data, imf.len);
memset(imf.data, 0, 8 - imf.len);
*(imf.data - 1) = 8;
apdu.nc += (8 - imf.len);
if (imf_len < 8) {
memmove(imf + (8 - imf_len), imf, imf_len);
memset(imf, 0, 8 - imf_len);
*(imf - 1) = 8;
apdu.nc += (8 - imf_len);
}
}
}
file_t *ef = find_oath_cred(name.data, name.len);
file_t *ef = find_oath_cred(name, name_len);
if (file_has_data(ef)) {
file_put_data(ef, apdu.data, (uint16_t)apdu.nc);
flash_write_data_to_file(ef, apdu.data, apdu.nc);
low_flash_available();
}
else {
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
if (!file_has_data(tef)) {
tef = file_new((uint16_t)(EF_OATH_CRED + i));
file_put_data(tef, apdu.data, (uint16_t)apdu.nc);
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (!file_has_data(ef)) {
ef = file_new(EF_OATH_CRED + i);
flash_write_data_to_file(ef, apdu.data, apdu.nc);
low_flash_available();
return SW_OK();
}
@@ -174,13 +182,13 @@ int cmd_put() {
int cmd_delete() {
size_t tag_len = 0;
uint8_t *tag_data = NULL;
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, ctxo = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &ctxo) == true) {
file_t *ef = find_oath_cred(ctxo.data, ctxo.len);
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &tag_len, &tag_data) == true) {
file_t *ef = find_oath_cred(tag_data, tag_len);
if (ef) {
delete_file(ef);
return SW_OK();
@@ -212,38 +220,38 @@ int cmd_set_code() {
validated = true;
return SW_OK();
}
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
size_t key_len = 0, chal_len = 0, resp_len = 0;
uint8_t *key = NULL, *chal = NULL, *resp = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if (key.len == 0) {
if (key_len == 0) {
delete_file(search_dynamic_file(EF_OATH_CODE));
validated = true;
return SW_OK();
}
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) {
return SW_INCORRECT_PARAMS();
}
const mbedtls_md_info_t *md_info = get_oath_md_info(key.data[0]);
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) {
return SW_INCORRECT_PARAMS();
}
uint8_t hmac[64];
int r = mbedtls_md_hmac(md_info, key.data + 1, key.len - 1, chal.data, chal.len, hmac);
int r = mbedtls_md_hmac(md_info, key + 1, key_len - 1, chal, chal_len, hmac);
if (r != 0) {
return SW_EXEC_ERROR();
}
if (memcmp(hmac, resp.data, resp.len) != 0) {
if (memcmp(hmac, resp, resp_len) != 0) {
return SW_DATA_INVALID();
}
random_gen(NULL, challenge, sizeof(challenge));
file_t *ef = file_new(EF_OATH_CODE);
file_put_data(ef, key.data, key.len);
flash_write_data_to_file(ef, key, key_len);
low_flash_available();
validated = false;
return SW_OK();
@@ -254,7 +262,7 @@ int cmd_reset() {
return SW_INCORRECT_P1P2();
}
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) {
delete_file(ef);
}
@@ -267,19 +275,23 @@ int cmd_reset() {
}
int cmd_list() {
size_t name_len = 0, key_len = 0;
uint8_t *name = NULL, *key = NULL;
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) {
asn1_ctx_t ctxi, key = { 0 }, name = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true && asn1_find_tag(&ctxi, TAG_KEY, &key) == true) {
uint8_t *data = file_get_data(ef);
size_t data_len = file_get_size(ef);
if (asn1_find_tag(data, data_len, TAG_NAME, &name_len,
&name) == true &&
asn1_find_tag(data, data_len, TAG_KEY, &key_len, &key) == true) {
res_APDU[res_APDU_size++] = TAG_NAME_LIST;
res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1);
res_APDU[res_APDU_size++] = key.data[0];
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
res_APDU[res_APDU_size++] = name_len + 1;
res_APDU[res_APDU_size++] = key[0];
memcpy(res_APDU + res_APDU_size, name, name_len); res_APDU_size += name_len;
}
}
}
@@ -288,12 +300,12 @@ int cmd_list() {
}
int cmd_validate() {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
size_t chal_len = 0, resp_len = 0, key_len = 0;
uint8_t *chal = NULL, *resp = NULL, *key = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = search_dynamic_file(EF_OATH_CODE);
@@ -301,21 +313,21 @@ int cmd_validate() {
validated = true;
return SW_DATA_INVALID();
}
key.data = file_get_data(ef);
key.len = file_get_size(ef);
const mbedtls_md_info_t *md_info = get_oath_md_info(key.data[0]);
key = file_get_data(ef);
key_len = file_get_size(ef);
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) {
return SW_INCORRECT_PARAMS();
}
uint8_t hmac[64];
int ret = mbedtls_md_hmac(md_info, key.data + 1, key.len - 1, challenge, sizeof(challenge), hmac);
int ret = mbedtls_md_hmac(md_info, key + 1, key_len - 1, challenge, sizeof(challenge), hmac);
if (ret != 0) {
return SW_EXEC_ERROR();
}
if (memcmp(hmac, resp.data, resp.len) != 0) {
if (memcmp(hmac, resp, resp_len) != 0) {
return SW_DATA_INVALID();
}
ret = mbedtls_md_hmac(md_info, key.data + 1, key.len - 1, chal.data, chal.len, hmac);
ret = mbedtls_md_hmac(md_info, key + 1, key_len - 1, chal, chal_len, hmac);
if (ret != 0) {
return SW_EXEC_ERROR();
}
@@ -328,7 +340,11 @@ int cmd_validate() {
return SW_OK();
}
int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const uint8_t *chal, size_t chal_len) {
int calculate_oath(uint8_t truncate,
const uint8_t *key,
size_t key_len,
const uint8_t *chal,
size_t chal_len) {
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) {
return SW_INCORRECT_PARAMS();
@@ -349,77 +365,77 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
res_APDU[res_APDU_size++] = hmac[offset + 3];
}
else {
res_APDU[res_APDU_size++] = (uint8_t)(hmac_size + 1);
res_APDU[res_APDU_size++] = hmac_size + 1;
res_APDU[res_APDU_size++] = key[1];
memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size;
memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += hmac_size;
}
apdu.ne = res_APDU_size;
return CCID_OK;
}
int cmd_calculate() {
size_t chal_len = 0, name_len = 0, key_len = 0;
uint8_t *chal = NULL, *name = NULL, *key = NULL;
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2();
}
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = find_oath_cred(name.data, name.len);
file_t *ef = find_oath_cred(name, name_len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
asn1_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_IMF, &chal_len,
&chal) == false) {
return SW_INCORRECT_PARAMS();
}
}
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
int ret = calculate_oath(P2(apdu), key, key_len, chal, chal_len);
if (ret != CCID_OK) {
return SW_EXEC_ERROR();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
uint64_t v =
((uint64_t) chal.data[0] << 56) |
((uint64_t) chal.data[1] << 48) |
((uint64_t) chal.data[2] << 40) |
((uint64_t) chal.data[3] << 32) |
((uint64_t) chal.data[4] << 24) |
((uint64_t) chal.data[5] << 16) |
((uint64_t) chal.data[6] << 8) |
(uint64_t) chal.data[7];
((uint64_t) chal[0] <<
56) |
((uint64_t) chal[1] <<
48) |
((uint64_t) chal[2] <<
40) |
((uint64_t) chal[3] <<
32) |
((uint64_t) chal[4] <<
24) | ((uint64_t) chal[5] << 16) | ((uint64_t) chal[6] << 8) | (uint64_t) chal[7];
size_t ef_size = file_get_size(ef);
v++;
uint8_t *tmp = (uint8_t *) calloc(1, ef_size);
memcpy(tmp, file_get_data(ef), ef_size);
asn1_ctx_t ctxt;
asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
asn1_find_tag(&ctxt, TAG_IMF, &chal);
chal.data[0] = (v >> 56) & 0xFF;
chal.data[1] = (v >> 48) & 0xFF;
chal.data[2] = (v >> 40) & 0xFF;
chal.data[3] = (v >> 32) & 0xFF;
chal.data[4] = (v >> 24) & 0xFF;
chal.data[5] = (v >> 16) & 0xFF;
chal.data[6] = (v >> 8) & 0xFF;
chal.data[7] = v & 0xff;
file_put_data(ef, tmp, (uint16_t)ef_size);
asn1_find_tag(tmp, ef_size, TAG_IMF, &chal_len, &chal);
chal[0] = v >> 56;
chal[1] = v >> 48;
chal[2] = v >> 40;
chal[3] = v >> 32;
chal[4] = v >> 24;
chal[5] = v >> 16;
chal[6] = v >> 8;
chal[7] = v & 0xff;
flash_write_data_to_file(ef, tmp, ef_size);
low_flash_available();
free(tmp);
}
@@ -428,47 +444,47 @@ int cmd_calculate() {
}
int cmd_calculate_all() {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
size_t chal_len = 0, name_len = 0, key_len = 0, prop_len = 0;
uint8_t *chal = NULL, *name = NULL, *key = NULL, *prop = NULL;
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2();
}
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
res_APDU_size = 0;
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) {
const uint8_t *ef_data = file_get_data(ef);
size_t ef_len = file_get_size(ef);
asn1_ctx_t ctxe;
asn1_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe);
if (asn1_find_tag(&ctxe, TAG_NAME, &name) == false || asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
if (asn1_find_tag(ef_data, ef_len, TAG_NAME, &name_len,
&name) == false ||
asn1_find_tag(ef_data, ef_len, TAG_KEY, &key_len, &key) == false) {
continue;
}
res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = (uint8_t)name.len;
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
res_APDU[res_APDU_size++] = name_len;
memcpy(res_APDU + res_APDU_size, name, name_len); res_APDU_size += name_len;
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
res_APDU[res_APDU_size++] = TAG_NO_RESPONSE;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
res_APDU[res_APDU_size++] = key[1];
}
else if (asn1_find_tag(&ctxe, TAG_PROPERTY, &prop) == true && (prop.data[0] & PROP_TOUCH)) {
else if (asn1_find_tag(ef_data, ef_len, TAG_PROPERTY, &prop_len,
&prop) == true && (prop[0] & PROP_TOUCH)) {
res_APDU[res_APDU_size++] = TAG_TOUCH_RESPONSE;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
res_APDU[res_APDU_size++] = key[1];
}
else {
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
int ret = calculate_oath(P2(apdu), key, key_len, chal, chal_len);
if (ret != CCID_OK) {
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
res_APDU[res_APDU_size++] = key[1];
}
}
}
@@ -482,105 +498,101 @@ int cmd_send_remaining() {
}
int cmd_set_otp_pin() {
uint8_t hsh[33] = { 0 };
size_t pw_len = 0;
uint8_t *pw = NULL, hsh[33] = { 0 };
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(pw.data, pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh));
double_hash_pin(pw, pw_len, hsh + 1);
flash_write_data_to_file(ef_otp_pin, hsh, sizeof(hsh));
low_flash_available();
return SW_OK();
}
int cmd_change_otp_pin() {
uint8_t hsh[33] = { 0 };
size_t pw_len = 0, new_pw_len = 0;
uint8_t *pw = NULL, *new_pw = NULL, hsh[33] = { 0 };
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 }, new_pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
double_hash_pin(pw.data, pw.len, hsh + 1);
double_hash_pin(pw, pw_len, hsh + 1);
if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (asn1_find_tag(&ctxi, TAG_NEW_PASSWORD, &new_pw) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NEW_PASSWORD, &new_pw_len, &new_pw) == false) {
return SW_INCORRECT_PARAMS();
}
hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(new_pw.data, new_pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh));
double_hash_pin(new_pw, new_pw_len, hsh + 1);
flash_write_data_to_file(ef_otp_pin, hsh, sizeof(hsh));
low_flash_available();
return SW_OK();
}
int cmd_verify_otp_pin() {
uint8_t hsh[33] = { 0 }, data_hsh[33];
size_t pw_len = 0;
uint8_t *pw = NULL, hsh[33] = { 0 }, data_hsh[33];
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
double_hash_pin(pw.data, pw.len, hsh + 1);
double_hash_pin(pw, pw_len, hsh + 1);
memcpy(data_hsh, file_get_data(ef_otp_pin), sizeof(data_hsh));
if (data_hsh[0] == 0 || memcmp(data_hsh + 1, hsh + 1, 32) != 0) {
if (data_hsh[0] > 0) {
data_hsh[0] -= 1;
}
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
flash_write_data_to_file(ef_otp_pin, data_hsh, sizeof(data_hsh));
low_flash_available();
validated = false;
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
data_hsh[0] = MAX_OTP_COUNTER;
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
flash_write_data_to_file(ef_otp_pin, data_hsh, sizeof(data_hsh));
low_flash_available();
validated = true;
return SW_OK();
}
int cmd_verify_hotp() {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
size_t key_len = 0, chal_len = 0, name_len = 0, code_len = 0;
uint8_t *key = NULL, *chal = NULL, *name = NULL, *code = NULL;
uint32_t code_int = 0;
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = find_oath_cred(name.data, name.len);
file_t *ef = find_oath_cred(name, name_len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
asn1_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
if ((key[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
return SW_DATA_INVALID();
}
if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_IMF, &chal_len,
&chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = (code.data[0] << 24) | (code.data[1] << 16) | (code.data[2] << 8) | code.data[3];
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &code_len, &code) == true) {
code_int = (code[0] << 24) | (code[1] << 16) | (code[2] << 8) | code[3];
}
int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len);
int ret = calculate_oath(0x01, key, key_len, chal, chal_len);
if (ret != CCID_OK) {
return SW_EXEC_ERROR();
}
@@ -594,8 +606,7 @@ int cmd_verify_hotp() {
if (res_int != code_int) {
return SW_WRONG_DATA();
}
res_APDU_size = 0;
apdu.ne = 0;
res_APDU_size = apdu.ne = 0;
return SW_OK();
}

View File

@@ -16,22 +16,18 @@
*/
#include "fido.h"
#include "pico_keys.h"
#include "hsm.h"
#include "apdu.h"
#include "files.h"
#include "random.h"
#include "version.h"
#include "asn1.h"
#include "hid/ctap_hid.h"
#include "usb.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifndef ENABLE_EMULATION
#include "bsp/board.h"
#endif
#include "mbedtls/aes.h"
#include "management.h"
#ifndef ENABLE_EMULATION
#include "tusb.h"
#endif
#define FIXED_SIZE 16
#define KEY_SIZE 16
@@ -96,7 +92,6 @@
static uint8_t config_seq = { 1 };
PACK(
typedef struct otp_config {
uint8_t fixed_data[FIXED_SIZE];
uint8_t uid[UID_SIZE];
@@ -108,29 +103,22 @@ typedef struct otp_config {
uint8_t cfg_flags;
uint8_t rfu[2];
uint16_t crc;
}) otp_config_t;
} __attribute__((packed)) otp_config_t;
#define otp_config_size sizeof(otp_config_t)
static const size_t otp_config_size = sizeof(otp_config_t);
uint16_t otp_status();
int otp_process_apdu();
int otp_unload();
#ifndef ENABLE_EMULATION
extern int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
extern uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
int otp_hid_set_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t);
uint16_t otp_hid_get_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t);
#endif
const uint8_t otp_aid[] = {
7,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01
};
int otp_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_OTP)) {
app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0])) && cap_supported(CAP_OTP)) {
a->aid = otp_aid;
a->process_apdu = otp_process_apdu;
a->unload = otp_unload;
if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ||
@@ -144,15 +132,15 @@ int otp_select(app_t *a, uint8_t force) {
memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6;
apdu.ne = res_APDU_size;
return CCID_OK;
return a;
}
return CCID_ERR_FILE_NOT_FOUND;
return NULL;
}
uint8_t modhex_tab[] =
{ 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' };
int encode_modhex(const uint8_t *in, size_t len, uint8_t *out) {
for (size_t l = 0; l < len; l++) {
for (int l = 0; l < len; l++) {
*out++ = modhex_tab[in[l] >> 4];
*out++ = modhex_tab[in[l] & 0xf];
}
@@ -163,7 +151,7 @@ extern void scan_all();
void init_otp() {
if (scanned == false) {
scan_all();
for (uint8_t i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data;
@@ -175,7 +163,7 @@ void init_otp() {
memcpy(new_data, data, sizeof(new_data));
new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data));
flash_write_data_to_file(ef, new_data, sizeof(new_data));
}
}
}
@@ -188,22 +176,6 @@ extern int calculate_oath(uint8_t truncate,
size_t key_len,
const uint8_t *chal,
size_t chal_len);
uint16_t calculate_crc(const uint8_t *data, size_t data_len) {
uint16_t crc = 0xFFFF;
for (size_t idx = 0; idx < data_len; idx++) {
crc ^= data[idx];
for (uint8_t i = 0; i < 8; i++) {
uint16_t j = crc & 0x1;
crc >>= 1;
if (j == 1) {
crc ^= 0x8408;
}
}
}
return crc & 0xFFFF;
}
#ifndef ENABLE_EMULATION
static uint8_t session_counter[2] = { 0 };
#endif
@@ -264,7 +236,7 @@ int otp_button_pressed(uint8_t slot) {
uint8_t new_otp_config[otp_config_size + sizeof(new_chal)];
memcpy(new_otp_config, otp_config, otp_config_size);
memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal));
file_put_data(ef, new_otp_config, sizeof(new_otp_config));
flash_write_data_to_file(ef, new_otp_config, sizeof(new_otp_config));
low_flash_available();
}
if (otp_config->tkt_flags & APPEND_CR) {
@@ -272,11 +244,10 @@ int otp_button_pressed(uint8_t slot) {
}
}
else if (otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET) {
uint8_t fixed_size = FIXED_SIZE + UID_SIZE + KEY_SIZE;
if (otp_config->cfg_flags & SHORT_TICKET) { // Not clear which is the purpose of SHORT_TICKET
//fixed_size /= 2;
if (otp_config->cfg_flags & SHORT_TICKET) {
otp_config->fixed_size /= 2;
}
add_keyboard_buffer(otp_config->fixed_data, fixed_size, false);
add_keyboard_buffer(otp_config->fixed_data, otp_config->fixed_size, false);
if (otp_config->tkt_flags & APPEND_CR) {
append_keyboard_buffer((const uint8_t *) "\x28", 1);
}
@@ -328,23 +299,17 @@ int otp_button_pressed(uint8_t slot) {
memcpy(new_data, data, sizeof(new_data));
new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data));
flash_write_data_to_file(ef, new_data, sizeof(new_data));
low_flash_available();
}
}
#else
(void) slot;
#endif
return 0;
}
INITIALIZER( otp_ctor ) {
register_app(otp_select, otp_aid);
void __attribute__((constructor)) otp_ctor() {
register_app(otp_select);
button_pressed_cb = otp_button_pressed;
#ifndef ENABLE_EMULATION
hid_set_report_cb = otp_hid_set_report_cb;
hid_get_report_cb = otp_hid_get_report_cb;
#endif
}
int otp_unload() {
@@ -395,7 +360,7 @@ int cmd_otp() {
return SW_WRONG_DATA();
}
memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra
file_put_data(ef, apdu.data, otp_config_size + 8);
flash_write_data_to_file(ef, apdu.data, otp_config_size + 8);
low_flash_available();
config_seq++;
return otp_status();
@@ -428,7 +393,7 @@ int cmd_otp() {
(odata->tkt_flags & TKTFLAG_UPDATE_MASK);
odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) |
(odata->cfg_flags & CFGFLAG_UPDATE_MASK);
file_put_data(ef, apdu.data, otp_config_size);
flash_write_data_to_file(ef, apdu.data, otp_config_size);
low_flash_available();
}
}
@@ -442,13 +407,13 @@ int cmd_otp() {
ef1_data = true;
}
if (file_has_data(ef2)) {
file_put_data(ef1, file_get_data(ef2), file_get_size(ef2));
flash_write_data_to_file(ef1, file_get_data(ef2), file_get_size(ef2));
}
else {
delete_file(ef1);
}
if (ef1_data) {
file_put_data(ef2, tmp, sizeof(tmp));
flash_write_data_to_file(ef2, tmp, sizeof(tmp));
}
else {
delete_file(ef2);
@@ -456,7 +421,9 @@ int cmd_otp() {
low_flash_available();
}
else if (p1 == 0x10) {
memcpy(res_APDU, pico_serial.id, 4);
#ifndef ENABLE_EMULATION
pico_get_unique_board_id_string((char *) res_APDU, 4);
#endif
res_APDU_size = 4;
}
else if (p1 == 0x13) {
@@ -484,7 +451,9 @@ int cmd_otp() {
else if (p1 == 0x20 || p1 == 0x28) {
uint8_t challenge[16];
memcpy(challenge, apdu.data, 6);
memcpy(challenge + 6, pico_serial_str, 10);
#ifndef ENABLE_EMULATION
pico_get_unique_board_id_string((char *) challenge + 6, 10);
#endif
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128);
@@ -520,114 +489,3 @@ int otp_process_apdu() {
}
return SW_INS_NOT_SUPPORTED();
}
#ifndef ENABLE_EMULATION
uint8_t otp_frame_rx[70] = {0};
uint8_t otp_frame_tx[70] = {0};
uint8_t otp_exp_seq = 0, otp_curr_seq = 0;
uint8_t otp_header[4] = {0};
extern uint16_t *get_send_buffer_size(uint8_t itf);
int otp_send_frame(uint8_t *frame, size_t frame_len) {
uint16_t crc = calculate_crc(frame, frame_len);
frame[frame_len] = ~crc & 0xff;
frame[frame_len + 1] = ~crc >> 8;
frame_len += 2;
*get_send_buffer_size(ITF_KEYBOARD) = frame_len;
otp_exp_seq = (frame_len / 7);
if (frame_len % 7) {
otp_exp_seq++;
}
otp_curr_seq = 0;
return 0;
}
int otp_hid_set_report_cb(uint8_t itf,
uint8_t report_id,
hid_report_type_t report_type,
uint8_t const *buffer,
uint16_t bufsize)
{
if (itf == ITF_KEYBOARD) {
if (report_type == 3) {
DEBUG_PAYLOAD(buffer, bufsize);
if (buffer[7] == 0xFF) { // reset
*get_send_buffer_size(ITF_KEYBOARD) = 0;
otp_curr_seq = otp_exp_seq = 0;
memset(otp_frame_tx, 0, sizeof(otp_frame_tx));
}
else if (buffer[7] & 0x80) { // a frame
uint8_t rseq = buffer[7] & 0x1F;
if (rseq < 10) {
if (rseq == 0) {
memset(otp_frame_rx, 0, sizeof(otp_frame_rx));
}
memcpy(otp_frame_rx + rseq * 7, buffer, 7);
if (rseq == 9) {
DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = (otp_frame_rx[66] << 8 | otp_frame_rx[65]);
uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) {
uint8_t hdr[5];
apdu.header = hdr;
apdu.data = otp_frame_rx;
apdu.nc = 64;
apdu.rdata = otp_frame_tx;
apdu.header[0] = 0;
apdu.header[1] = 0x01;
apdu.header[2] = slot_id;
apdu.header[3] = 0;
int ret = otp_process_apdu();
if (ret == 0x9000 && res_APDU_size > 0) {
otp_send_frame(apdu.rdata, apdu.rlen);
}
}
else {
printf("[OTP] Bad CRC!\n");
}
}
}
}
}
return 1;
}
return 0;
}
uint16_t otp_hid_get_report_cb(uint8_t itf,
uint8_t report_id,
hid_report_type_t report_type,
uint8_t *buffer,
uint16_t reqlen) {
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
uint16_t send_buffer_size = *get_send_buffer_size(ITF_KEYBOARD);
if (send_buffer_size > 0) {
uint8_t seq = otp_curr_seq++;
memset(buffer, 0, 8);
memcpy(buffer, otp_frame_tx + 7 * seq, MIN(7, send_buffer_size));
buffer[7] = 0x40 | seq;
DEBUG_DATA(buffer, 8);
*get_send_buffer_size(ITF_KEYBOARD) -= MIN(7, send_buffer_size);
}
else if (otp_curr_seq == otp_exp_seq && otp_exp_seq > 0) {
memset(buffer, 0, 7);
buffer[7] = 0x40;
DEBUG_DATA(buffer,8);
otp_curr_seq = otp_exp_seq = 0;
}
else {
res_APDU = buffer;
otp_status();
}
return reqlen;
}
#endif

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_
#define __VERSION_H_
#define PICO_FIDO_VERSION 0x050C
#define PICO_FIDO_VERSION 0x0507
#define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff)
#define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff)

View File

@@ -19,9 +19,7 @@
from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512
import fido2.features
fido2.features.webauthn_json_mapping.enabled = False
from fido2.cose import ES256, ES384, ES512, EdDSA
from utils import ES256K
import pytest
@@ -124,7 +122,7 @@ def test_bad_type_pubKeyCredParams(device):
device.doMC(key_params=["wrong"])
@pytest.mark.parametrize(
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM]
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
)
def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms):
@@ -149,13 +147,11 @@ def test_bad_type_pubKeyCredParams_alg(device):
with pytest.raises(CtapError) as e:
device.doMC(key_params=[{"alg": "7", "type": "public-key"}])
assert e.value.code == CtapError.ERR.CBOR_UNEXPECTED_TYPE
def test_unsupported_algorithm(device):
with pytest.raises(CtapError) as e:
device.doMC(key_params=[{"alg": 1337, "type": "public-key"}])
assert e.value.code == CtapError.ERR.UNSUPPORTED_ALGORITHM
assert e.value.code == CtapError.ERR.CBOR_UNEXPECTED_TYPE
def test_exclude_list(resetdevice):
resetdevice.doMC(exclude_list=[{"id": b"1234", "type": "rot13"}])

View File

@@ -19,7 +19,7 @@
from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512
from fido2.cose import ES256, ES384, ES512, EdDSA
from utils import verify, ES256K
import pytest
@@ -49,7 +49,7 @@ def test_empty_allowList(device):
assert e.value.code == CtapError.ERR.NO_CREDENTIALS
@pytest.mark.parametrize(
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM]
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
)
def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms):

View File

@@ -69,12 +69,12 @@ def test_hmac_secret_entropy(device, MCHmacSecret, hmac, salts
#print(shannon_entropy(auth.authenticator_data.extensions['hmac-secret']))
if len(salts) == 1:
assert shannon_entropy(auth.authenticator_data.extensions['hmac-secret']) > 4.5
assert shannon_entropy(ext["hmacGetSecret"]['output1']) > 4.5
assert shannon_entropy(auth.authenticator_data.extensions['hmac-secret']) > 4.6
assert shannon_entropy(ext["hmacGetSecret"]['output1']) > 4.6
if len(salts) == 2:
assert shannon_entropy(auth.authenticator_data.extensions['hmac-secret']) > 5.4
assert shannon_entropy(ext["hmacGetSecret"]['output1']) > 4.5
assert shannon_entropy(ext["hmacGetSecret"]['output2']) > 4.5
assert shannon_entropy(ext["hmacGetSecret"]['output1']) > 4.6
assert shannon_entropy(ext["hmacGetSecret"]['output2']) > 4.6
def get_output(device, MCHmacSecret, hmac, salts):
hout = {'salt1':salts[0]}

View File

@@ -196,13 +196,16 @@ class TestHID(object):
device.set_cid(cid2) # send ping on 2nd channel
device.send_raw("\x81\x00\x39")
cmd, r = device.recv_raw() # busy response
time.sleep(0.1)
device.send_raw("\x00")
cmd, r = device.recv_raw() # busy response
device.set_cid(cid1) # finish 1st channel ping
device.send_raw("\x00")
device.set_cid(cid2)
assert cmd == 0xBF
assert r[0] == CtapError.ERR.CHANNEL_BUSY
@@ -210,11 +213,9 @@ class TestHID(object):
cmd, r = device.recv_raw() # ping response
assert cmd == 0x81
assert len(r) == 0x39
cmd, r = device.recv_raw() # ping response
def test_cid_0(self, device):
device.reset()
time.sleep(0.1)
device.set_cid(b"\x00\x00\x00\x00")
device.send_raw(
"\x86\x00\x08\x11\x22\x33\x44\x55\x66\x77\x88", cid="\x00\x00\x00\x00"

View File

@@ -23,6 +23,7 @@ import sys
import argparse
import platform
from binascii import hexlify
from words import words
from threading import Event
from typing import Mapping, Any, Optional, Callable
import struct
@@ -32,7 +33,7 @@ from enum import IntEnum, unique
try:
from fido2.ctap2.config import Config
from fido2.ctap2 import Ctap2, ClientPin, PinProtocolV2
from fido2.ctap2 import Ctap2
from fido2.hid import CtapHidDevice, CTAPHID
from fido2.utils import bytes2int, int2bytes
from fido2 import cbor
@@ -57,6 +58,14 @@ except:
from enum import IntEnum
from binascii import hexlify
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
def get_pki_data(url, data=None, method='GET'):
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; '
'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
@@ -81,7 +90,6 @@ class VendorConfig(Config):
class CMD(IntEnum):
CONFIG_AUT_ENABLE = 0x03e43f56b34285e2
CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9
CONFIG_VENDOR_PROTOTYPE = 0x7f
class RESP(IntEnum):
KEY_AGREEMENT = 0x01
@@ -91,7 +99,7 @@ class VendorConfig(Config):
def enable_device_aut(self, ct):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
Config.CMD.VENDOR_PROTOTYPE,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_ENABLE,
VendorConfig.PARAM.VENDOR_AUT_CT: ct
@@ -100,7 +108,7 @@ class VendorConfig(Config):
def disable_device_aut(self):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PROTOTYPE,
Config.CMD.VENDOR_PROTOTYPE,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_AUT_DISABLE
},
@@ -222,7 +230,7 @@ class Vendor:
self.__key_enc = None
self.__iv = None
self.vcfg = VendorConfig(ctap, pin_uv_protocol=pin_uv_protocol, pin_uv_token=pin_uv_token)
self.vcfg = VendorConfig(ctap)
def _call(self, cmd, sub_cmd, params=None):
if params:
@@ -244,14 +252,6 @@ class Vendor:
return self.ctap.vendor(cmd, sub_cmd, params, pin_uv_protocol, pin_uv_param)
def backup_save(self, filename):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
from words import words
ret = self._call(
Vendor.CMD.VENDOR_BACKUP,
Vendor.SUBCMD.ENABLE,
@@ -270,14 +270,6 @@ class Vendor:
print(f'{(c+1):02d} - {words[coef]}')
def backup_load(self, filename):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
from words import words
d = 0
if (d == 0):
for c in range(24):
@@ -357,13 +349,6 @@ class Vendor:
)
def _get_key_device(self):
if (platform.system() == 'Windows' or platform.system() == 'Linux'):
from secure_key import windows as skey
elif (platform.system() == 'Darwin'):
from secure_key import macos as skey
else:
print('ERROR: platform not supported')
sys.exit(-1)
return skey.get_secure_key()
def get_skey(self):
@@ -396,7 +381,6 @@ class Vendor:
def parse_args():
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers(title="commands", dest="command")
parser.add_argument('-p','--pin', help='Specify the PIN of the device.', required=True)
parser_secure = subparser.add_parser('secure', help='Manages security of Pico Fido.')
parser_secure.add_argument('subcommand', choices=['enable', 'disable', 'unlock'], help='Enables, disables or unlocks the security.')
@@ -442,17 +426,15 @@ def attestation(vdr, args):
vdr.upload_ea(cert.public_bytes(Encoding.DER))
def main(args):
print('Pico Fido Tool v1.6')
print('Pico Fido Tool v1.4')
print('Author: Pol Henarejos')
print('Report bugs to https://github.com/polhenarejos/pico-fido/issues')
print('')
print('')
dev = next(CtapHidDevice.list_devices(), None)
ctap = Ctap2Vendor(dev)
client_pin = ClientPin(ctap)
token = client_pin.get_pin_token(args.pin, permissions=ClientPin.PERMISSION.AUTHENTICATOR_CFG)
vdr = Vendor(ctap, pin_uv_protocol=PinProtocolV2(), pin_uv_token=token)
vdr = Vendor(Ctap2Vendor(dev))
if (args.command == 'secure'):
secure(vdr, args)

View File

@@ -51,9 +51,7 @@ def get_secure_key():
try:
backend = get_backend(False)
key = backend.get_password(DOMAIN, USERNAME)[0]
if (key is None):
raise TypeError
except (keyring.errors.KeyringError, TypeError):
except keyring.errors.KeyringError:
try:
key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault
except keyring.errors.PasswordSetError:

View File

@@ -1,44 +0,0 @@
import sys
DOMAIN = "PicoKeys.com"
USERNAME = "Pico-Fido"
try:
import keyring
except:
print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyring`')
sys.exit(-1)
try:
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, load_pem_private_key
from cryptography.hazmat.primitives.asymmetric import ec
except:
print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`')
sys.exit(-1)
def generate_secure_key():
pkey = ec.generate_private_key(ec.SECP256R1())
set_secure_key(pkey)
return keyring.get_password(DOMAIN, USERNAME)
def get_d(key):
return load_pem_private_key(key, password=None).private_numbers().private_value.to_bytes(32, 'big')
def set_secure_key(pk):
try:
keyring.delete_password(DOMAIN, USERNAME)
except:
pass
keyring.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()).decode())
def get_secure_key():
key = None
try:
key = keyring.get_password(DOMAIN, USERNAME)
if (key is None):
raise TypeError
except (keyring.errors.KeyringError, TypeError):
key = generate_secure_key()
return get_d(key.encode())