73 Commits
v5.8 ... v5.12

Author SHA1 Message Date
Pol Henarejos
95cae29206 Upgrade to version 5.12
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 17:12:11 +02:00
Pol Henarejos
11c28adbb0 Add more boards with RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 17:11:57 +02:00
Pol Henarejos
661442956d Update readme to add Passkey term.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 12:02:42 +02:00
Pol Henarejos
778c6b038a Fix BOOT press with RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 09:48:27 +02:00
Pol Henarejos
de1c50db4f Replace sdkconfig
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 14:47:49 +02:00
Pol Henarejos
c1e985c9af Use mutex/semaphores for emulation, like in Pico and ESP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 12:42:33 +02:00
Pol Henarejos
4f787eaaba Fix otp in Pico
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 00:34:14 +02:00
Pol Henarejos
b77277b72e Add RP2350 support.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-29 16:57:59 +02:00
Pol Henarejos
02556fcde1 Fix buffer initialization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 20:21:43 +02:00
Pol Henarejos
f234b0dc26 Fix emulation run
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 01:31:19 +02:00
Pol Henarejos
8ba9116454 Fix test
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 01:30:54 +02:00
Pol Henarejos
5a31405244 Improving tests
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 00:10:23 +02:00
Pol Henarejos
902a988350 Fix memory cleanups.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-24 02:34:15 +02:00
Pol Henarejos
6256a9547d Fix build emulation
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-24 00:11:40 +02:00
Pol Henarejos
5568aa7b69 Fixed thread synchronization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 19:25:20 +02:00
Pol Henarejos
5e86745672 Add missing files for ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 15:23:10 +02:00
Pol Henarejos
cffa8e29ff Fix windows build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 14:24:03 +02:00
Pol Henarejos
6c74db9763 Fix warnings.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 13:17:51 +02:00
Pol Henarejos
dac6407134 Fix windows build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 13:17:29 +02:00
Pol Henarejos
f49833291f Major refactor of USB CCID and USB HID interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 10:04:00 +02:00
Pol Henarejos
8c1e002892 select_app now invokes U2F or FIDO depending on the message.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 14:29:25 +02:00
Pol Henarejos
8d49ed5ffc Fix potential crash invoking OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 14:28:09 +02:00
Pol Henarejos
a0d9ad7a3a Increase vStack depending on the number of interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 12:43:15 +02:00
Pol Henarejos
910fb66f3c Fix keepalive
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 16:45:11 +02:00
Pol Henarejos
ed12d6f8e9 Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 13:18:03 +02:00
Pol Henarejos
a9799dc77f Fix CBOR error.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 13:12:04 +02:00
Pol Henarejos
d7d75caecf Fix OATH selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 13:11:48 +02:00
Pol Henarejos
af4eb075c7 Add HID/CCID fixes for ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:09:05 +02:00
Pol Henarejos
0c5280e12a Add support to ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:08:31 +02:00
Pol Henarejos
163e936231 Fix potential bug in CBOR encoding.
It happen if a keepalive packet is sent in the middle of an encoding.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-18 23:59:52 +02:00
Pol Henarejos
1b4dd9bed0 Fix ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-18 23:53:18 +02:00
Pol Henarejos
5b95e35ca9 Upgrade to version 5.10
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:29:40 +02:00
Pol Henarejos
69ec242095 Update README.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:28:09 +02:00
Pol Henarejos
6eb6cd35d0 Merge branch 'development'
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:27:01 +02:00
Pol Henarejos
f21e203093 Fix compilation
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:05:00 +02:00
Pol Henarejos
e96da09a84 Fixes for mbedtls 3.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:04:48 +02:00
Pol Henarejos
6fe16a63e4 Upgrade Pico Keys SDK
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-20 20:04:41 +02:00
Pol Henarejos
d5fe405a87 Fix test bad pub type.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-30 00:32:40 +02:00
Pol Henarejos
54bbc0e9ea Fix return value when bad key type is provided. Fixes #47.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-30 00:31:29 +02:00
Pol Henarejos
b0b0187919 Fix cleared permissions on make credential when UP is not present.
Following 14.1, flags shall be cleared only when UP == true.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-07 20:57:21 +02:00
Pol Henarejos
1f0e1fb8f4 Use latest Pico Keys SDK.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-05-05 00:58:51 +02:00
Pol Henarejos
f3f34cf66b Fix oath crash.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 22:06:00 +01:00
Pol Henarejos
82ed96b2e2 Fix asn1 struct initialization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 21:22:05 +01:00
Pol Henarejos
92d04f9131 Use new asn1 structs.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 18:34:14 +01:00
Pol Henarejos
7a71bf48fc Add -DVIDPID=<VALUE> to build a project with a known VID/PID. Supported values: NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-12-11 18:13:32 +01:00
Pol Henarejos
20a8ef08f0 Upgrade to version 5.8
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 12:01:47 +01:00
Pol Henarejos
e757ad2945 Removing SHORT_TICKET limitation.
It is not used to return the half of ticket, but to combine with static to produce hex scancodes.

Fixes #29.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 11:53:47 +01:00
Pol Henarejos
1ce0d98c34 OTP callbacks must be initialized on ctor.
Fixes #30.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-21 11:50:42 +01:00
Pol Henarejos
96de6efed6 OTP static passwords are 38 bytes length.
A static password uses fixed, uid and key fields (sum 38). However, Yubikey sets short_ticket flag which implies the half of the password is sent.

Fixes #29.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-16 20:16:23 +01:00
Pol Henarejos
195096ad52 otp must be initialized when selection fido or management applets.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-16 20:12:48 +01:00
Pol Henarejos
1ee86f8634 Moving Pico Keys SDK pointer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-16 20:12:01 +01:00
Pol Henarejos
ffb3beb84a Fix build in emulation mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 15:32:25 +01:00
Pol Henarejos
d78d9d10aa Use new names and defines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 15:22:28 +01:00
Pol Henarejos
f8d4f1d02e Use new pico-keys-sdk submodule name.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 14:28:09 +01:00
Pol Henarejos
b493a81ddc Rename old pico-hsm-sdk to the new pico-keys-sdk.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 14:27:57 +01:00
Pol Henarejos
5c20909b03 Move some functions from HID to fido callbacks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 13:01:10 +01:00
Pol Henarejos
27b9e3954a Use get_version_major and get_version_minor as pointers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:57:08 +01:00
Pol Henarejos
440ec5c854 Update SDK to new otp.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:49:42 +01:00
Pol Henarejos
cb2744cab3 Move some OTP functions from HID to OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:49:18 +01:00
Pol Henarejos
5db1014850 Generate a secure key if it is not found.
Should fix #23.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:48:32 +01:00
Pol Henarejos
421bea6421 python-fido2 has a bug which does not allow to use 0xff as ConfigVendorPrototype.
It encodes an uint8_t to int8_t and thus, the command must be <= 0x7f.

Fixes #22.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-02 22:29:28 +01:00
Pol Henarejos
65039c0959 Fixed AUT permission.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-02 22:13:45 +01:00
Pol Henarejos
8e36b4c379 Added support for --pin flag.
It loads Vendor/Ctap2Vendor with uv_token based on provided --pin.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-02 22:08:49 +01:00
Pol Henarejos
3652368542 Added Windows & Linux backend for backup/restore.
Fixes #21

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-02 09:32:19 +01:00
Pol Henarejos
e5d1ef29a4 Fixed OTP read packet through HID interfaces.
Fixes #19.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 17:35:59 +01:00
Pol Henarejos
0fd36806cc Fixed potential crash.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 00:40:56 +01:00
Pol Henarejos
7bf26b28fc Fixed potential memory leak.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-30 16:51:56 +01:00
Pol Henarejos
da94a82487 Fix AID selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:57:53 +02:00
Pol Henarejos
c24be5a631 Adapted to new selection AID method.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:53:06 +02:00
Pol Henarejos
46ce9390bf Added backfall compatibility.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:52:07 +02:00
Pol Henarejos
c1fd5736f9 Update to latest HSM SDK changes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:51:36 +02:00
Pol Henarejos
b1c4ff877e Fix pico_w build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 10:39:21 +02:00
Pol Henarejos
6c85d57412 Added support for LED in Pico W.
Fixed #17.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 10:14:11 +02:00
33 changed files with 744 additions and 806 deletions

View File

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

View File

@@ -1,8 +1,8 @@
# Pico FIDO # Pico FIDO
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. This project transforms your Raspberry Pi Pico into an integrated FIDO Passkey, functioning like a standard USB Passkey for authentication.
## Features ## Features
Pico FIDO has implemented the following features: Pico FIDO includes the following features:
- CTAP 2.1 / CTAP 1 - CTAP 2.1 / CTAP 1
- WebAuthn - WebAuthn
@@ -10,16 +10,16 @@ Pico FIDO has implemented the following features:
- HMAC-Secret extension - HMAC-Secret extension
- CredProtect extension - CredProtect extension
- User presence enforcement through physical button - User presence enforcement through physical button
- User Verification with PIN - User verification with PIN
- Discoverable credentials - Discoverable credentials (resident keys)
- Credential management - Credential management
- ECDSA authentication - ECDSA authentication
- Authentication with SECP256R1, SECP384R1, SECP521R1 and SECP256K1 curves. - Support for SECP256R1, SECP384R1, SECP521R1, and SECP256K1 curves
- App registration and login - App registration and login
- Device selection - Device selection
- Support for vendor Config - Support for vendor configuration
- Backup with 24 words - Backup with 24 words
- Secure lock to protect the device from flash dumpings - Secure lock to protect the device from flash dumps
- Permissions support (MC, GA, CM, ACFG, LBW) - Permissions support (MC, GA, CM, ACFG, LBW)
- Authenticator configuration - Authenticator configuration
- minPinLength extension - minPinLength extension
@@ -27,50 +27,54 @@ Pico FIDO has implemented the following features:
- Enterprise attestation - Enterprise attestation
- credBlobs extension - credBlobs extension
- largeBlobKey extension - largeBlobKey extension
- largeBlobs support (2048 bytes máx.) - Large blobs support (2048 bytes max)
- OATH (based on YKOATH protocol specification) - OATH (based on YKOATH protocol specification)
- TOTP / HOTP - TOTP / HOTP
- Yubikey OTP - Yubikey OTP
- Challenge-response generation - Challenge-response generation
- Emulated keyboard interface - Emulated keyboard interface
- Button press generates an OTP that is written directly is it was typed - Button press generates an OTP that is directly typed
- Yubico YKMAN compatible - Yubico YKMAN compatible
- Nitrokey nitropy and nitroapp compatible - Nitrokey nitropy and nitroapp compatible
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. All features comply with the specifications. If you encounter unexpected behavior or deviations from the specifications, 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.
If the Pico is stolen the contents of private and secret keys can be read. 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.
## Download ## Download
Please, go to the [Release page](https://github.com/polhenarejos/pico-fido/releases "Release page") and download the UF2 file for your board. Please visit the [Release page](https://github.com/polhenarejos/pico-fido/releases "Release page") to download the UF2 file for your board.
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/). 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/).
Alternatively you can use the legacy VID/PID patcher as follows: Alternatively, you can use the legacy VID/PID patcher with the following command:
`./patch_vidpid.sh VID:PID input_hsm_file.uf2 output_hsm_file.uf2` ```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.
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. For ease of use, the pure-browser option [Pico Patcher tool](https://www.picokeys.com/pico-patcher/) is highly recommended.
Note that the pure-browser option [Pico Patcher tool](https://www.picokeys.com/pico-patcher/) is the most recommended.
## Build ## Build
Before building, ensure you have installed the toolchain for the Pico and the Pico SDK is properly located in your drive. Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive.
git clone https://github.com/polhenarejos/pico-fido ```sh
cd pico-fido git clone https://github.com/polhenarejos/pico-fido
mkdir build cd pico-fido
cd build mkdir build
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678 cd build
make 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, pico board and VID/PID FEFF:FCFD will be used. 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.
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. 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.
**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. **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.
## Led blink ## Led blink
Pico FIDO uses the led to indicate the current status. Four states are available: Pico FIDO uses the led to indicate the current status. Four states are available:
@@ -96,20 +100,21 @@ While processing, the Pico FIDO is busy and cannot receive additional commands u
## Driver ## Driver
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. 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.
## Tests ## Tests
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. 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.
All tests can be run by To run all tests, use:
``` ```sh
pytest pytest
``` ```
or by selecting a subset with `-k <test>` flag: To run a subset of tests, use the `-k <test>` flag:
```
```sh
pytest -k test_credprotect pytest -k test_credprotect
``` ```

View File

@@ -1,45 +1,87 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="5" VERSION_MAJOR="5"
VERSION_MINOR="8" VERSION_MINOR="12"
rm -rf release/* rm -rf release/*
cd build_release cd build_release
for board in adafruit_feather_rp2040 \ for board in 0xcb_helios \
adafruit_feather_rp2040_usb_host \
adafruit_feather_rp2040 \
adafruit_itsybitsy_rp2040 \ adafruit_itsybitsy_rp2040 \
adafruit_kb2040 \ adafruit_kb2040 \
adafruit_macropad_rp2040 \ adafruit_macropad_rp2040 \
adafruit_qtpy_rp2040 \ adafruit_qtpy_rp2040 \
adafruit_trinkey_qt2040 \ adafruit_trinkey_qt2040 \
amethyst_fpga \
archi \
arduino_nano_rp2040_connect \ arduino_nano_rp2040_connect \
cytron_maker_pi_rp2040 \
datanoisetv_rp2040_dsp \ datanoisetv_rp2040_dsp \
eetree_gamekit_rp2040 \ eetree_gamekit_rp2040 \
garatronic_pybstick26_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 \ melopero_shake_rp2040 \
metrotech_xerxes_rp2040 \
net8086_usb_interposer \
nullbits_bit_c_pro \ nullbits_bit_c_pro \
phyx_rick_tny_rp2350 \
pi-plates_micropi \
pico \ pico \
pico_w \ pico_w \
pico2 \
pimoroni_badger2040 \ pimoroni_badger2040 \
pimoroni_interstate75 \ pimoroni_interstate75 \
pimoroni_keybow2040 \ pimoroni_keybow2040 \
pimoroni_motor2040 \ pimoroni_motor2040 \
pimoroni_pga2040 \ pimoroni_pga2040 \
pimoroni_pga2350 \
pimoroni_pico_plus2_rp2350 \
pimoroni_picolipo_4mb \ pimoroni_picolipo_4mb \
pimoroni_picolipo_16mb \ pimoroni_picolipo_16mb \
pimoroni_picosystem \ pimoroni_picosystem \
pimoroni_plasma2040 \ pimoroni_plasma2040 \
pimoroni_plasma2350 \
pimoroni_servo2040 \ pimoroni_servo2040 \
pimoroni_tiny2040 \ pimoroni_tiny2040 \
pimoroni_tiny2040_2mb \ pimoroni_tiny2040_2mb \
pimoroni_tiny2350 \
pololu_3pi_2040_robot \ pololu_3pi_2040_robot \
pololu_zumo_2040_robot \
seeed_xiao_rp2040 \ seeed_xiao_rp2040 \
seeed_xiao_rp2350 \
solderparty_rp2040_stamp \ solderparty_rp2040_stamp \
solderparty_rp2040_stamp_carrier \ solderparty_rp2040_stamp_carrier \
solderparty_rp2040_stamp_round_carrier \ solderparty_rp2040_stamp_round_carrier \
solderparty_rp2350_stamp_xl \
solderparty_rp2350_stamp \
sparkfun_micromod \ sparkfun_micromod \
sparkfun_promicro \ sparkfun_promicro \
sparkfun_promicro_rp2350 \
sparkfun_thingplus \ 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 \ vgaboard \
waveshare_rp2040_lcd_0.96 \ waveshare_rp2040_lcd_0.96 \
waveshare_rp2040_lcd_1.28 \ waveshare_rp2040_lcd_1.28 \
@@ -47,6 +89,10 @@ for board in adafruit_feather_rp2040 \
waveshare_rp2040_plus_4mb \ waveshare_rp2040_plus_4mb \
waveshare_rp2040_plus_16mb \ waveshare_rp2040_plus_16mb \
waveshare_rp2040_zero \ waveshare_rp2040_zero \
weact_studio_rp2040_2mb \
weact_studio_rp2040_4mb \
weact_studio_rp2040_8mb \
weact_studio_rp2040_16mb \
wiznet_w5100s_evb_pico wiznet_w5100s_evb_pico
do do
rm -rf * rm -rf *

53
sdkconfig.defaults Normal file
View File

@@ -0,0 +1,53 @@
# 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

6
src/fido/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ENABLE_EMULATION #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif #endif
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
@@ -43,12 +43,11 @@ int cbor_large_blobs(const uint8_t *data, size_t len);
extern int cmd_read_config(); extern int cmd_read_config();
const uint8_t aaguid[16] = 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")
{ 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; const uint8_t *cbor_data = NULL;
size_t cbor_len = 0; size_t cbor_len = 0;
uint8_t cmd = 0; uint8_t cbor_cmd = 0;
int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
if (len == 0 && cmd == CTAPHID_CBOR) { if (len == 0 && cmd == CTAPHID_CBOR) {
@@ -58,7 +57,6 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
DEBUG_DATA(data + 1, len - 1); DEBUG_DATA(data + 1, len - 1);
} }
if (cap_supported(CAP_FIDO2)) { if (cap_supported(CAP_FIDO2)) {
driver_prepare_response_hid();
if (cmd == CTAPHID_CBOR) { if (cmd == CTAPHID_CBOR) {
if (data[0] == CTAP_MAKE_CREDENTIAL) { if (data[0] == CTAP_MAKE_CREDENTIAL) {
return cbor_make_credential(data + 1, len - 1); return cbor_make_credential(data + 1, len - 1);
@@ -96,6 +94,7 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
} }
else if (cmd == 0xC2) { else if (cmd == 0xC2) {
if (cmd_read_config() == 0x9000) { if (cmd_read_config() == 0x9000) {
memmove(res_APDU-1, res_APDU, res_APDU_size);
res_APDU_size -= 1; res_APDU_size -= 1;
return 0; return 0;
} }
@@ -104,50 +103,47 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
return CTAP1_ERR_INVALID_CMD; return CTAP1_ERR_INVALID_CMD;
} }
#ifndef ENABLE_EMULATION void cbor_thread(void) {
void cbor_thread() {
card_init_core1(); card_init_core1();
while (1) { while (1) {
uint32_t m; uint32_t m;
queue_remove_blocking(&usb_to_card_q, &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) { if (m == EV_EXIT) {
break; break;
} }
apdu.sw = cbor_parse(cmd, cbor_data, cbor_len); apdu.sw = cbor_parse(cbor_cmd, cbor_data, cbor_len);
if (apdu.sw == 0) { if (apdu.sw == 0) {
DEBUG_DATA(res_APDU + 1, res_APDU_size); DEBUG_DATA(res_APDU + 1, res_APDU_size);
} }
else { else {
res_APDU[0] = apdu.sw; res_APDU[0] = apdu.sw;
apdu.sw = 0; //apdu.sw = 0;
} }
finished_data_size = res_APDU_size + 1; finished_data_size = res_APDU_size + 1;
uint32_t flag = EV_EXEC_FINISHED; flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag); 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) { int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len) {
cbor_data = data; cbor_data = data;
cbor_len = len; cbor_len = len;
cmd = last_cmd; cbor_cmd = last_cmd;
ctap_resp->init.data[0] = 0;
res_APDU = ctap_resp->init.data + 1; res_APDU = ctap_resp->init.data + 1;
res_APDU_size = 0; res_APDU_size = 0;
return 1; return 2; // CBOR processing
} }
CborError COSE_key_params(int crv, CborError COSE_key_params(int crv, int alg, mbedtls_ecp_group *grp, mbedtls_ecp_point *Q, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) {
int alg,
mbedtls_ecp_group *grp,
mbedtls_ecp_point *Q,
CborEncoder *mapEncoderParent,
CborEncoder *mapEncoder) {
CborError error = CborNoError; CborError error = CborNoError;
int kty = 1; int kty = 1;
if (crv == FIDO2_CURVE_P256 || crv == FIDO2_CURVE_P384 || crv == FIDO2_CURVE_P521 || if (crv == FIDO2_CURVE_P256 || crv == FIDO2_CURVE_P384 || crv == FIDO2_CURVE_P521 ||
@@ -214,12 +210,7 @@ CborError COSE_key_shared(mbedtls_ecdh_context *key,
CborEncoder *mapEncoderParent, CborEncoder *mapEncoderParent,
CborEncoder *mapEncoder) { CborEncoder *mapEncoder) {
int crv = mbedtls_curve_to_fido(key->ctx.mbed_ecdh.grp.id), alg = FIDO2_ALG_ECDH_ES_HKDF_256; int crv = mbedtls_curve_to_fido(key->ctx.mbed_ecdh.grp.id), alg = FIDO2_ALG_ECDH_ES_HKDF_256;
return COSE_key_params(crv, return COSE_key_params(crv, alg, &key->ctx.mbed_ecdh.grp, &key->ctx.mbed_ecdh.Q, mapEncoderParent, mapEncoder);
alg,
&key->ctx.mbed_ecdh.grp,
&key->ctx.mbed_ecdh.Q,
mapEncoderParent,
mapEncoder);
} }
CborError COSE_public_key(int alg, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) { CborError COSE_public_key(int alg, CborEncoder *mapEncoderParent, CborEncoder *mapEncoder) {
CborError error = CborNoError; CborError error = CborNoError;
@@ -232,12 +223,7 @@ CborError COSE_public_key(int alg, CborEncoder *mapEncoderParent, CborEncoder *m
err: err:
return error; return error;
} }
CborError COSE_read_key(CborValue *f, CborError COSE_read_key(CborValue *f, int64_t *kty, int64_t *alg, int64_t *crv, CborByteString *kax, CborByteString *kay) {
int64_t *kty,
int64_t *alg,
int64_t *crv,
CborByteString *kax,
CborByteString *kay) {
int64_t kkey = 0; int64_t kkey = 0;
CborError error = CborNoError; CborError error = CborNoError;
CBOR_PARSE_MAP_START(*f, 0) CBOR_PARSE_MAP_START(*f, 0)

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,7 +26,7 @@
int cbor_get_info() { int cbor_get_info() {
CborEncoder encoder, mapEncoder, arrayEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, arrayEncoder, mapEncoder2;
CborError error = CborNoError; CborError error = CborNoError;
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 15)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 15));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
@@ -133,6 +133,6 @@ err:
if (error != CborNoError) { if (error != CborNoError) {
return -CTAP2_ERR_INVALID_CBOR; return -CTAP2_ERR_INVALID_CBOR;
} }
res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1); res_APDU_size = (uint16_t)cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
return 0; return 0;
} }

View File

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

View File

@@ -162,7 +162,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
uint8_t flags = FIDO2_AUT_FLAG_AT; uint8_t flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32]; uint8_t rp_id_hash[32] = {0};
mbedtls_sha256((uint8_t *) rp.id.data, rp.id.len, rp_id_hash, 0); mbedtls_sha256((uint8_t *) rp.id.data, rp.id.len, rp_id_hash, 0);
if (pinUvAuthParam.present == true) { 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); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
} }
for (int i = 0; i < pubKeyCredParams_len; i++) { for (unsigned int i = 0; i < pubKeyCredParams_len; i++) {
if (pubKeyCredParams[i].type.present == false) { if (pubKeyCredParams[i].type.present == false) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
} }
@@ -225,11 +225,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) { else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass // pass
} }
else { //else {
CBOR_ERROR(CTAP2_ERR_CBOR_UNEXPECTED_TYPE); // CBOR_ERROR(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
} //}
if (curve > 0 && alg == 0) { if (curve > 0 && alg == 0) {
alg = pubKeyCredParams[i].alg; alg = (int)pubKeyCredParams[i].alg;
} }
} }
if (curve <= 0) { if (curve <= 0) {
@@ -259,11 +259,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
//Unfinished. See 6.1.2.9 //Unfinished. See 6.1.2.9
} }
if (pinUvAuthParam.present == true) { //11.1 if (pinUvAuthParam.present == true) { //11.1
int ret = verify(pinUvAuthProtocol, int ret = verify((uint8_t)pinUvAuthProtocol, paut.data, clientDataHash.data, (uint16_t)clientDataHash.len, pinUvAuthParam.data);
paut.data,
clientDataHash.data,
clientDataHash.len,
pinUvAuthParam.data);
if (ret != CborNoError) { if (ret != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
@@ -283,11 +279,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
for (int e = 0; e < excludeList_len; e++) { //12.1 for (size_t e = 0; e < excludeList_len; e++) { //12.1
if (excludeList[e].type.present == false || excludeList[e].id.present == false) { if (excludeList[e].type.present == false || excludeList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
} }
if (strcmp(excludeList[e].type.data, "public-key") != 0) { if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) {
continue; continue;
} }
Credential ecred; Credential ecred;
@@ -295,8 +291,10 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
&ecred) == 0 && &ecred) == 0 &&
(ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED || (ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED ||
(flags & FIDO2_AUT_FLAG_UV))) { (flags & FIDO2_AUT_FLAG_UV))) {
credential_free(&ecred);
CBOR_ERROR(CTAP2_ERR_CREDENTIAL_EXCLUDED); CBOR_ERROR(CTAP2_ERR_CREDENTIAL_EXCLUDED);
} }
credential_free(&ecred);
} }
if (extensions.largeBlobKey == pfalse || if (extensions.largeBlobKey == pfalse ||
@@ -313,14 +311,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
flags |= FIDO2_AUT_FLAG_UP; flags |= FIDO2_AUT_FLAG_UP;
clearUserPresentFlag(); if (options.up == ptrue) {
clearUserVerifiedFlag(); clearUserPresentFlag();
clearPinUvAuthTokenPermissionsExceptLbw(); clearUserVerifiedFlag();
clearPinUvAuthTokenPermissionsExceptLbw();
}
} }
const known_app_t *ka = find_app_by_rp_id_hash(rp_id_hash); const known_app_t *ka = find_app_by_rp_id_hash(rp_id_hash);
uint8_t cred_id[MAX_CRED_ID_LENGTH]; uint8_t cred_id[MAX_CRED_ID_LENGTH] = {0};
size_t cred_id_len = 0; size_t cred_id_len = 0;
CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options, CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options,
@@ -331,7 +331,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
flags |= FIDO2_AUT_FLAG_UV; flags |= FIDO2_AUT_FLAG_UV;
} }
size_t ext_len = 0; size_t ext_len = 0;
uint8_t ext[512]; uint8_t ext[512] = {0};
CborEncoder encoder, mapEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, mapEncoder2;
if (extensions.present == true) { if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
@@ -400,7 +400,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
size_t olen = 0; size_t olen = 0;
uint32_t ctr = get_sign_counter(); uint32_t ctr = get_sign_counter();
uint8_t cbor_buf[1024]; uint8_t cbor_buf[1024] = {0};
cbor_encoder_init(&encoder, cbor_buf, sizeof(cbor_buf), 0); cbor_encoder_init(&encoder, cbor_buf, sizeof(cbor_buf), 0);
CBOR_CHECK(COSE_key(&ekey, &encoder, &mapEncoder)); CBOR_CHECK(COSE_key(&ekey, &encoder, &mapEncoder));
size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf); size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf);
@@ -410,23 +410,23 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t *pa = aut_data; uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32; memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags; *pa++ = flags;
*pa++ = ctr >> 24; *pa++ = (ctr >> 24) & 0xFF;
*pa++ = ctr >> 16; *pa++ = (ctr >> 16) & 0xFF;
*pa++ = ctr >> 8; *pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xff; *pa++ = ctr & 0xFF;
memcpy(pa, aaguid, 16); pa += 16; memcpy(pa, aaguid, 16); pa += 16;
*pa++ = cred_id_len >> 8; *pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF;
*pa++ = cred_id_len & 0xff; *pa++ = (uint16_t)cred_id_len & 0xFF;
memcpy(pa, cred_id, cred_id_len); pa += cred_id_len; memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len;
memcpy(pa, cbor_buf, rs); pa += rs; memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
memcpy(pa, ext, ext_len); pa += ext_len; memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if (pa - aut_data != aut_data_len) { if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
memcpy(pa, clientDataHash.data, clientDataHash.len); memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[64], sig[MBEDTLS_ECDSA_MAX_LEN]; uint8_t hash[64] = {0}, sig[MBEDTLS_ECDSA_MAX_LEN] = {0};
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) { if (ekey.grp.id == MBEDTLS_ECP_DP_SECP384R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
@@ -434,10 +434,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) { else if (ekey.grp.id == MBEDTLS_ECP_DP_SECP521R1) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
} }
ret = mbedtls_md(md, ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
aut_data,
aut_data_len + clientDataHash.len,
hash);
bool self_attestation = true; bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
@@ -447,18 +444,10 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
self_attestation = false; self_attestation = false;
} }
ret = mbedtls_ecdsa_write_signature(&ekey, 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_md_get_type(md),
hash,
mbedtls_md_get_size(md),
sig,
sizeof(sig),
&olen,
random_gen,
NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
uint8_t largeBlobKey[32]; uint8_t largeBlobKey[32] = {0};
if (extensions.largeBlobKey == ptrue && options.rk == ptrue) { if (extensions.largeBlobKey == ptrue && options.rk == ptrue) {
ret = credential_derive_large_blob_key(cred_id, cred_id_len, largeBlobKey); ret = credential_derive_large_blob_key(cred_id, cred_id_len, largeBlobKey);
if (ret != 0) { if (ret != 0) {
@@ -466,10 +455,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, extensions.largeBlobKey == ptrue && options.rk == ptrue ? 5 : 4));
extensions.largeBlobKey == ptrue &&
options.rk == ptrue ? 5 : 4));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed"));
@@ -477,11 +464,9 @@ 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_byte_string(&mapEncoder, aut_data, aut_data_len));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, self_attestation == false || is_nitrokey ? 3 : 2));
self_attestation == false || is_nitrokey ? 3 : 2));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg"));
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation || is_nitrokey ? -alg : -FIDO2_ALG_ES256));
self_attestation || is_nitrokey ? -alg : -FIDO2_ALG_ES256));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, sig, olen)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, sig, olen));
if (self_attestation == false || is_nitrokey) { if (self_attestation == false || is_nitrokey) {
@@ -495,8 +480,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "x5c")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "x5c"));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder2, &arrEncoder, 1)); CBOR_CHECK(cbor_encoder_create_array(&mapEncoder2, &arrEncoder, 1));
CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert), CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert), file_get_size(ef_cert)));
file_get_size(ef_cert)));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder2, &arrEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder2, &arrEncoder));
} }
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -518,7 +502,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
ctr++; ctr++;
flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr)); file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available(); low_flash_available();
err: err:
CBOR_FREE_BYTE_STRING(clientDataHash); CBOR_FREE_BYTE_STRING(clientDataHash);
@@ -528,14 +512,17 @@ err:
CBOR_FREE_BYTE_STRING(user.id); CBOR_FREE_BYTE_STRING(user.id);
CBOR_FREE_BYTE_STRING(user.displayName); CBOR_FREE_BYTE_STRING(user.displayName);
CBOR_FREE_BYTE_STRING(user.parent.name); CBOR_FREE_BYTE_STRING(user.parent.name);
for (int n = 0; n < pubKeyCredParams_len; n++) { if (extensions.present == true) {
CBOR_FREE_BYTE_STRING(extensions.credBlob);
}
for (size_t n = 0; n < MAX_CREDENTIAL_COUNT_IN_LIST; n++) {
CBOR_FREE_BYTE_STRING(pubKeyCredParams[n].type); CBOR_FREE_BYTE_STRING(pubKeyCredParams[n].type);
} }
for (int m = 0; m < excludeList_len; m++) { for (size_t m = 0; m < MAX_CREDENTIAL_COUNT_IN_LIST; m++) {
CBOR_FREE_BYTE_STRING(excludeList[m].type); CBOR_FREE_BYTE_STRING(excludeList[m].type);
CBOR_FREE_BYTE_STRING(excludeList[m].id); CBOR_FREE_BYTE_STRING(excludeList[m].id);
for (int n = 0; n < excludeList[m].transports_len; n++) { for (size_t n = 0; n < excludeList[m].transports_len; n++) {
CBOR_FREE_BYTE_STRING(excludeList[m].transports[n]); CBOR_FREE_BYTE_STRING(excludeList[m].transports[n]);
} }
} }
@@ -548,6 +535,6 @@ err:
} }
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = (uint16_t)resp_size;
return 0; return 0;
} }

View File

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

View File

@@ -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_PARSE_MAP_END(map, 1);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_CBOR_PAYLOAD, 0);
if (cmd == CTAP_VENDOR_BACKUP) { if (cmd == CTAP_VENDOR_BACKUP) {
if (vendorCmd == 0x01) { 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]; uint8_t zeros[32];
memset(zeros, 0, sizeof(zeros)); memset(zeros, 0, sizeof(zeros));
flash_write_data_to_file(ef_keydev_enc, vendorParam.data, vendorParam.len); file_put_data(ef_keydev_enc, vendorParam.data, (uint16_t)vendorParam.len);
flash_write_data_to_file(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0 file_put_data(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 file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
low_flash_available(); low_flash_available();
goto err; goto err;
} }
@@ -223,14 +223,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
size_t keyenc_len = file_get_size(ef_keydev_enc); size_t keyenc_len = file_get_size(ef_keydev_enc);
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorParam.data); mbedtls_chachapoly_setkey(&chatx, vendorParam.data);
ret = mbedtls_chachapoly_auth_decrypt(&chatx, ret = mbedtls_chachapoly_auth_decrypt(&chatx, sizeof(keydev_dec), keyenc, NULL, 0, keyenc + keyenc_len - 16, keyenc + 12, keydev_dec);
sizeof(keydev_dec),
keyenc,
NULL,
0,
keyenc + keyenc_len - 16,
keyenc + 12,
keydev_dec);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -243,10 +236,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buffer[1024]; uint8_t buffer[1024];
mbedtls_ecdsa_context ekey; mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecdsa_init(&ekey);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), file_get_size(ef_keydev));
&ekey,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -256,27 +246,11 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); 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 ctx;
mbedtls_x509write_csr_init(&ctx); mbedtls_x509write_csr_init(&ctx);
snprintf((char *) buffer, snprintf((char *) buffer,
sizeof(buffer), sizeof(buffer),
"C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %02x%02x%02x%02x%02x%02x%02x%02x", "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str);
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_x509write_csr_set_subject_name(&ctx, (char *) buffer);
mbedtls_pk_context key; mbedtls_pk_context key;
mbedtls_pk_init(&key); mbedtls_pk_init(&key);
@@ -306,7 +280,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); file_t *ef_ee_ea = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (ef_ee_ea) { if (ef_ee_ea) {
flash_write_data_to_file(ef_ee_ea, vendorParam.data, vendorParam.len); file_put_data(ef_ee_ea, vendorParam.data, (uint16_t)vendorParam.len);
} }
low_flash_available(); low_flash_available();
goto err; goto err;
@@ -328,7 +302,7 @@ err:
} }
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = (uint16_t)resp_size;
return 0; return 0;
} }

View File

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

View File

@@ -32,7 +32,8 @@ const uint8_t u2f_aid[] = {
int u2f_unload(); int u2f_unload();
int u2f_process_apdu(); int u2f_process_apdu();
int u2f_select(app_t *a) { int u2f_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_U2F)) { if (cap_supported(CAP_U2F)) {
a->process_apdu = u2f_process_apdu; a->process_apdu = u2f_process_apdu;
a->unload = u2f_unload; a->unload = u2f_unload;
@@ -41,7 +42,7 @@ int u2f_select(app_t *a) {
return CCID_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
void __attribute__((constructor)) u2f_ctor() { INITIALIZER ( u2f_ctor ) {
register_app(u2f_select, u2f_aid); register_app(u2f_select, u2f_aid);
} }
@@ -49,9 +50,7 @@ int u2f_unload() {
return CCID_OK; return CCID_OK;
} }
const uint8_t *bogus_firefox = 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 *)
"\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"; const uint8_t *bogus_chrome = (const uint8_t *) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
extern int ctap_error(uint8_t error); extern int ctap_error(uint8_t error);
@@ -83,33 +82,20 @@ int cmd_register() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
ret = ret = mbedtls_ecp_point_write_binary(&key.grp, &key.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (uint8_t *) &resp->pubKey, CTAP_EC_POINT_SIZE);
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); mbedtls_ecdsa_free(&key);
if (ret != 0) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t ef_certdev_size = file_get_size(ef_certdev); uint16_t ef_certdev_size = file_get_size(ef_certdev);
memcpy(resp->keyHandleCertSig + KEY_HANDLE_LEN, file_get_data(ef_certdev), ef_certdev_size); memcpy(resp->keyHandleCertSig + KEY_HANDLE_LEN, file_get_data(ef_certdev), ef_certdev_size);
uint8_t hash[32], uint8_t hash[32], sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE];
sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE];
sign_base[0] = CTAP_REGISTER_HASH_ID; sign_base[0] = CTAP_REGISTER_HASH_ID;
memcpy(sign_base + 1, req->appId, CTAP_APPID_SIZE); 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, req->chal, CTAP_CHAL_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig, memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig, KEY_HANDLE_LEN);
KEY_HANDLE_LEN); memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN, (uint8_t *) &resp->pubKey, CTAP_EC_POINT_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN, ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sign_base, sizeof(sign_base), hash);
(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) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -119,21 +105,12 @@ int cmd_register() {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
ret = mbedtls_ecdsa_write_signature(&key, 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_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); mbedtls_ecdsa_free(&key);
if (ret != 0) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN + res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN + ef_certdev_size + (uint16_t)olen;
ef_certdev_size + olen;
return SW_OK(); return SW_OK();
} }

View File

@@ -20,6 +20,6 @@
int cmd_version() { int cmd_version() {
memcpy(res_APDU, "U2F_V2", strlen("U2F_V2")); memcpy(res_APDU, "U2F_V2", strlen("U2F_V2"));
res_APDU_size = strlen("U2F_V2"); res_APDU_size = (uint16_t)strlen("U2F_V2");
return SW_OK(); return SW_OK();
} }

View File

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

View File

@@ -18,16 +18,9 @@
#ifndef _CTAP_H_ #ifndef _CTAP_H_
#define _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 <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

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

View File

@@ -27,12 +27,12 @@
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) #if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
#include "ccid/ccid.h" #include "ccid/ccid.h"
#endif #endif
#ifndef ENABLE_EMULATION #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "bsp/board.h" #include "bsp/board.h"
#endif #endif
#include <math.h> #include <math.h>
#include "management.h" #include "management.h"
#include "ctap_hid.h" #include "hid/ctap_hid.h"
#include "version.h" #include "version.h"
int fido_process_apdu(); int fido_process_apdu();
@@ -43,7 +43,7 @@ pinUvAuthToken_t paut = { 0 };
uint8_t keydev_dec[32]; uint8_t keydev_dec[32];
bool has_keydev_dec = false; bool has_keydev_dec = false;
const uint8_t _fido_aid[] = { const uint8_t fido_aid[] = {
8, 8,
0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01 0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01
}; };
@@ -61,7 +61,8 @@ uint8_t fido_get_version_minor() {
return PICO_FIDO_VERSION_MINOR; return PICO_FIDO_VERSION_MINOR;
} }
int fido_select(app_t *a) { int fido_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_FIDO2)) { if (cap_supported(CAP_FIDO2)) {
a->process_apdu = fido_process_apdu; a->process_apdu = fido_process_apdu;
a->unload = fido_unload; a->unload = fido_unload;
@@ -72,25 +73,13 @@ int fido_select(app_t *a) {
extern uint8_t (*get_version_major)(); extern uint8_t (*get_version_major)();
extern uint8_t (*get_version_minor)(); extern uint8_t (*get_version_minor)();
extern const uint8_t *fido_aid;
extern void (*init_fido_cb)();
extern void (*cbor_thread_func)();
extern int (*cbor_process_cb)(uint8_t, const uint8_t *, size_t);
extern void cbor_thread();
extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len);
void __attribute__((constructor)) fido_ctor() { INITIALIZER ( fido_ctor ) {
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) #if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
ccid_atr = atr_fido; ccid_atr = atr_fido;
#endif #endif
get_version_major = fido_get_version_major; get_version_major = fido_get_version_major;
get_version_minor = fido_get_version_minor; get_version_minor = fido_get_version_minor;
fido_aid = _fido_aid;
init_fido_cb = init_fido;
#ifndef ENABLE_EMULATION
cbor_thread_func = cbor_thread;
#endif
cbor_process_cb = cbor_process;
register_app(fido_select, fido_aid); register_app(fido_select, fido_aid);
} }
@@ -162,7 +151,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_validity(&ctx, "20220901000000", "20720831235959");
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO"); 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"); mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
uint8_t serial[20]; uint8_t serial[16];
random_gen(NULL, serial, sizeof(serial)); random_gen(NULL, serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial)); mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context key; mbedtls_pk_context key;
@@ -179,6 +168,7 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
MBEDTLS_X509_KU_KEY_CERT_SIGN); MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL); 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 */ /* pk cannot be freed, as it is freed later */
//mbedtls_pk_free(&key); //mbedtls_pk_free(&key);
return ret; return ret;
@@ -215,8 +205,9 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
} }
} }
uint8_t hmac[32], d[32]; uint8_t hmac[32], d[32];
int ret = mbedtls_ecp_write_key(key, d, sizeof(d)); size_t olen = 0;
if (key == NULL) { int ret = mbedtls_ecp_write_key_ext(key, &olen, d, sizeof(d));
if (key == &ctx) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
} }
if (ret != 0) { if (ret != 0) {
@@ -225,26 +216,17 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, appId, CTAP_APPID_SIZE); memcpy(key_base, appId, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN); memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN);
ret = ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), d, 32, key_base, sizeof(key_base), hmac);
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)); mbedtls_platform_zeroize(d, sizeof(d));
return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac)); return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac));
} }
int derive_key(const uint8_t *app_id, int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) {
bool new_key,
uint8_t *key_handle,
int curve,
mbedtls_ecdsa_context *key) {
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
int r = 0; int r = 0;
memset(outk, 0, sizeof(outk)); memset(outk, 0, sizeof(outk));
if ((r = load_keydev(outk)) != CCID_OK) { if ((r = load_keydev(outk)) != CCID_OK) {
printf("Error loading keydev: %d\n", r);
return r; return r;
} }
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
@@ -255,15 +237,7 @@ int derive_key(const uint8_t *app_id,
val |= 0x80000000; val |= 0x80000000;
memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t)); memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t));
} }
r = mbedtls_hkdf(md_info, r = mbedtls_hkdf(md_info, &key_handle[i * sizeof(uint32_t)], sizeof(uint32_t), outk, 32, outk + 32, 32, outk, sizeof(outk));
&key_handle[i * sizeof(uint32_t)],
sizeof(uint32_t),
outk,
32,
outk + 32,
32,
outk,
sizeof(outk));
if (r != 0) { if (r != 0) {
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
return r; return r;
@@ -273,9 +247,7 @@ int derive_key(const uint8_t *app_id,
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, app_id, CTAP_APPID_SIZE); memcpy(key_base, app_id, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, key_handle, KEY_PATH_LEN); memcpy(key_base + CTAP_APPID_SIZE, key_handle, KEY_PATH_LEN);
if ((r = 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_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)); mbedtls_platform_zeroize(outk, sizeof(outk));
return r; return r;
} }
@@ -289,7 +261,7 @@ int derive_key(const uint8_t *app_id,
if (cinfo->bit_size % 8 != 0) { if (cinfo->bit_size % 8 != 0) {
outk[0] >>= 8 - (cinfo->bit_size % 8); outk[0] >>= 8 - (cinfo->bit_size % 8);
} }
r = mbedtls_ecp_read_key(curve, key, outk, ceil((float) cinfo->bit_size / 8)); r = mbedtls_ecp_read_key(curve, key, outk, (size_t)ceil((float) cinfo->bit_size / 8));
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
if (r != 0) { if (r != 0) {
return r; return r;
@@ -314,10 +286,13 @@ int scan_files() {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return ret; return ret;
} }
uint8_t kdata[32]; uint8_t kdata[64];
int key_size = mbedtls_mpi_size(&ecdsa.d); size_t key_size = 0;
mbedtls_mpi_write_binary(&ecdsa.d, kdata, key_size); ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, kdata, sizeof(kdata));
ret = flash_write_data_to_file(ef_keydev, kdata, key_size); if (ret != CCID_OK) {
return ret;
}
ret = file_put_data(ef_keydev, kdata, (uint16_t)key_size);
mbedtls_platform_zeroize(kdata, sizeof(kdata)); mbedtls_platform_zeroize(kdata, sizeof(kdata));
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
if (ret != CCID_OK) { if (ret != CCID_OK) {
@@ -332,13 +307,10 @@ int scan_files() {
ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF); ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF);
if (ef_certdev) { if (ef_certdev) {
if (!file_has_data(ef_certdev)) { if (!file_has_data(ef_certdev)) {
uint8_t cert[4096]; uint8_t cert[2048];
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), file_get_size(ef_keydev));
&key,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return ret; return ret;
@@ -353,7 +325,7 @@ int scan_files() {
if (ret <= 0) { if (ret <= 0) {
return ret; return ret;
} }
flash_write_data_to_file(ef_certdev, cert + sizeof(cert) - ret, ret); file_put_data(ef_certdev, cert + sizeof(cert) - ret, (uint16_t)ret);
} }
} }
else { else {
@@ -363,7 +335,7 @@ int scan_files() {
if (ef_counter) { if (ef_counter) {
if (!file_has_data(ef_counter)) { if (!file_has_data(ef_counter)) {
uint32_t v = 0; uint32_t v = 0;
flash_write_data_to_file(ef_counter, (uint8_t *) &v, sizeof(v)); file_put_data(ef_counter, (uint8_t *) &v, sizeof(v));
} }
} }
else { else {
@@ -375,7 +347,7 @@ int scan_files() {
if (!file_has_data(ef_authtoken)) { if (!file_has_data(ef_authtoken)) {
uint8_t t[32]; uint8_t t[32];
random_gen(NULL, t, sizeof(t)); random_gen(NULL, t, sizeof(t));
flash_write_data_to_file(ef_authtoken, t, sizeof(t)); file_put_data(ef_authtoken, t, sizeof(t));
} }
paut.data = file_get_data(ef_authtoken); paut.data = file_get_data(ef_authtoken);
paut.len = file_get_size(ef_authtoken); paut.len = file_get_size(ef_authtoken);
@@ -385,9 +357,7 @@ int scan_files() {
} }
ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF); ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
if (!file_has_data(ef_largeblob)) { if (!file_has_data(ef_largeblob)) {
flash_write_data_to_file(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);
(const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c",
17);
} }
low_flash_available(); low_flash_available();
return CCID_OK; return CCID_OK;
@@ -447,7 +417,7 @@ uint8_t get_opts() {
void set_opts(uint8_t opts) { void set_opts(uint8_t opts) {
file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF); file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
flash_write_data_to_file(ef, &opts, sizeof(uint8_t)); file_put_data(ef, &opts, sizeof(uint8_t));
low_flash_available(); low_flash_available();
} }

View File

@@ -18,13 +18,18 @@
#ifndef _FIDO_H_ #ifndef _FIDO_H_
#define _FIDO_H_ #define _FIDO_H_
#ifndef ENABLE_EMULATION #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif #endif
#ifndef ESP_PLATFORM
#include "common.h" #include "common.h"
#else
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#include "ctap_hid.h" #include "hid/ctap_hid.h"
#else #else
#include <stdbool.h> #include <stdbool.h>
#endif #endif
@@ -48,16 +53,8 @@ extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id); 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_ecdsa_context *key);
extern int load_keydev(uint8_t *key); extern int load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
const uint8_t *key, extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
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); extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret);
#define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256 #define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256
@@ -131,10 +128,6 @@ typedef struct pinUvAuthToken {
extern uint32_t user_present_time_limit; extern uint32_t user_present_time_limit;
extern pinUvAuthToken_t paut; extern pinUvAuthToken_t paut;
extern int verify(uint8_t protocol, extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
const uint8_t *key,
const uint8_t *data,
size_t len,
uint8_t *sign);
#endif //_FIDO_H #endif //_FIDO_H

View File

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

View File

@@ -32,18 +32,20 @@ const uint8_t man_aid[] = {
}; };
extern void scan_all(); extern void scan_all();
extern void init_otp(); extern void init_otp();
int man_select(app_t *a) { int man_select(app_t *a, uint8_t force) {
a->process_apdu = man_process_apdu; a->process_apdu = man_process_apdu;
a->unload = man_unload; a->unload = man_unload;
sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR); sprintf((char *) res_APDU, "%d.%d.0", PICO_FIDO_VERSION_MAJOR, PICO_FIDO_VERSION_MINOR);
res_APDU_size = strlen((char *) res_APDU); res_APDU_size = (uint16_t)strlen((char *) res_APDU);
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
scan_all(); if (force) {
init_otp(); scan_all();
init_otp();
}
return CCID_OK; return CCID_OK;
} }
void __attribute__((constructor)) man_ctor() { INITIALIZER ( man_ctor ) {
register_app(man_select, man_aid); register_app(man_select, man_aid);
} }
@@ -54,10 +56,12 @@ int man_unload() {
bool cap_supported(uint16_t cap) { bool cap_supported(uint16_t cap) {
file_t *ef = search_dynamic_file(EF_DEV_CONF); file_t *ef = search_dynamic_file(EF_DEV_CONF);
if (file_has_data(ef)) { if (file_has_data(ef)) {
uint16_t tag = 0x0, data_len = file_get_size(ef); uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL, *data = file_get_data(ef); uint8_t *tag_data = NULL, *p = NULL;
size_t tag_len = 0; uint16_t tag_len = 0;
while (walk_tlv(data, data_len, &p, &tag, &tag_len, &tag_data)) { asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == TAG_USB_ENABLED) { if (tag == TAG_USB_ENABLED) {
uint16_t ecaps = tag_data[0]; uint16_t ecaps = tag_data[0];
if (tag_len == 2) { if (tag_len == 2) {
@@ -80,9 +84,7 @@ int man_get_config() {
res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH; res_APDU[res_APDU_size++] = CAP_OTP | CAP_U2F | CAP_OATH;
res_APDU[res_APDU_size++] = TAG_SERIAL; res_APDU[res_APDU_size++] = TAG_SERIAL;
res_APDU[res_APDU_size++] = 4; res_APDU[res_APDU_size++] = 4;
#ifndef ENABLE_EMULATION memcpy(res_APDU + res_APDU_size, pico_serial.id, 4);
pico_get_unique_board_id_string((char *) res_APDU + res_APDU_size, 4);
#endif
res_APDU_size += 4; res_APDU_size += 4;
res_APDU[res_APDU_size++] = TAG_FORM_FACTOR; res_APDU[res_APDU_size++] = TAG_FORM_FACTOR;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
@@ -114,7 +116,7 @@ int man_get_config() {
memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef)); memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef));
res_APDU_size += file_get_size(ef); res_APDU_size += file_get_size(ef);
} }
res_APDU[0] = res_APDU_size - 1; res_APDU[0] = (uint8_t)(res_APDU_size - 1);
return 0; return 0;
} }
@@ -128,7 +130,7 @@ int cmd_write_config() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = file_new(EF_DEV_CONF); file_t *ef = file_new(EF_DEV_CONF);
flash_write_data_to_file(ef, apdu.data + 1, apdu.nc - 1); file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
low_flash_available(); low_flash_available();
return SW_OK(); return SW_OK();
} }

View File

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

View File

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

View File

@@ -23,11 +23,15 @@
#include "version.h" #include "version.h"
#include "asn1.h" #include "asn1.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#ifndef ENABLE_EMULATION #include "usb.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "bsp/board.h" #include "bsp/board.h"
#endif #endif
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include "management.h" #include "management.h"
#ifndef ENABLE_EMULATION
#include "tusb.h"
#endif
#define FIXED_SIZE 16 #define FIXED_SIZE 16
#define KEY_SIZE 16 #define KEY_SIZE 16
@@ -92,6 +96,7 @@
static uint8_t config_seq = { 1 }; static uint8_t config_seq = { 1 };
PACK(
typedef struct otp_config { typedef struct otp_config {
uint8_t fixed_data[FIXED_SIZE]; uint8_t fixed_data[FIXED_SIZE];
uint8_t uid[UID_SIZE]; uint8_t uid[UID_SIZE];
@@ -103,9 +108,9 @@ typedef struct otp_config {
uint8_t cfg_flags; uint8_t cfg_flags;
uint8_t rfu[2]; uint8_t rfu[2];
uint16_t crc; uint16_t crc;
} __attribute__((packed)) otp_config_t; }) otp_config_t;
static const size_t otp_config_size = sizeof(otp_config_t); #define otp_config_size sizeof(otp_config_t)
uint16_t otp_status(); uint16_t otp_status();
int otp_process_apdu(); int otp_process_apdu();
@@ -123,7 +128,8 @@ const uint8_t otp_aid[] = {
0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01
}; };
int otp_select(app_t *a) { int otp_select(app_t *a, uint8_t force) {
(void) force;
if (cap_supported(CAP_OTP)) { if (cap_supported(CAP_OTP)) {
a->process_apdu = otp_process_apdu; a->process_apdu = otp_process_apdu;
a->unload = otp_unload; a->unload = otp_unload;
@@ -146,7 +152,7 @@ int otp_select(app_t *a) {
uint8_t modhex_tab[] = uint8_t modhex_tab[] =
{ 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' }; { '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) { int encode_modhex(const uint8_t *in, size_t len, uint8_t *out) {
for (int l = 0; l < len; l++) { for (size_t l = 0; l < len; l++) {
*out++ = modhex_tab[in[l] >> 4]; *out++ = modhex_tab[in[l] >> 4];
*out++ = modhex_tab[in[l] & 0xf]; *out++ = modhex_tab[in[l] & 0xf];
} }
@@ -157,7 +163,7 @@ extern void scan_all();
void init_otp() { void init_otp() {
if (scanned == false) { if (scanned == false) {
scan_all(); scan_all();
for (int i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i); file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
uint8_t *data = file_get_data(ef); uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data; otp_config_t *otp_config = (otp_config_t *) data;
@@ -169,7 +175,7 @@ void init_otp() {
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
new_data[otp_config_size] = counter >> 8; new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff; new_data[otp_config_size + 1] = counter & 0xff;
flash_write_data_to_file(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
} }
} }
} }
@@ -258,7 +264,7 @@ int otp_button_pressed(uint8_t slot) {
uint8_t new_otp_config[otp_config_size + sizeof(new_chal)]; 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, otp_config_size);
memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal)); memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal));
flash_write_data_to_file(ef, new_otp_config, sizeof(new_otp_config)); file_put_data(ef, new_otp_config, sizeof(new_otp_config));
low_flash_available(); low_flash_available();
} }
if (otp_config->tkt_flags & APPEND_CR) { if (otp_config->tkt_flags & APPEND_CR) {
@@ -322,15 +328,17 @@ int otp_button_pressed(uint8_t slot) {
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
new_data[otp_config_size] = counter >> 8; new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff; new_data[otp_config_size + 1] = counter & 0xff;
flash_write_data_to_file(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
low_flash_available(); low_flash_available();
} }
} }
#else
(void) slot;
#endif #endif
return 0; return 0;
} }
void __attribute__((constructor)) otp_ctor() { INITIALIZER( otp_ctor ) {
register_app(otp_select, otp_aid); register_app(otp_select, otp_aid);
button_pressed_cb = otp_button_pressed; button_pressed_cb = otp_button_pressed;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
@@ -387,7 +395,7 @@ int cmd_otp() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra
flash_write_data_to_file(ef, apdu.data, otp_config_size + 8); file_put_data(ef, apdu.data, otp_config_size + 8);
low_flash_available(); low_flash_available();
config_seq++; config_seq++;
return otp_status(); return otp_status();
@@ -420,7 +428,7 @@ int cmd_otp() {
(odata->tkt_flags & TKTFLAG_UPDATE_MASK); (odata->tkt_flags & TKTFLAG_UPDATE_MASK);
odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) | odata->cfg_flags = (otpc->cfg_flags & ~CFGFLAG_UPDATE_MASK) |
(odata->cfg_flags & CFGFLAG_UPDATE_MASK); (odata->cfg_flags & CFGFLAG_UPDATE_MASK);
flash_write_data_to_file(ef, apdu.data, otp_config_size); file_put_data(ef, apdu.data, otp_config_size);
low_flash_available(); low_flash_available();
} }
} }
@@ -434,13 +442,13 @@ int cmd_otp() {
ef1_data = true; ef1_data = true;
} }
if (file_has_data(ef2)) { if (file_has_data(ef2)) {
flash_write_data_to_file(ef1, file_get_data(ef2), file_get_size(ef2)); file_put_data(ef1, file_get_data(ef2), file_get_size(ef2));
} }
else { else {
delete_file(ef1); delete_file(ef1);
} }
if (ef1_data) { if (ef1_data) {
flash_write_data_to_file(ef2, tmp, sizeof(tmp)); file_put_data(ef2, tmp, sizeof(tmp));
} }
else { else {
delete_file(ef2); delete_file(ef2);
@@ -448,9 +456,7 @@ int cmd_otp() {
low_flash_available(); low_flash_available();
} }
else if (p1 == 0x10) { else if (p1 == 0x10) {
#ifndef ENABLE_EMULATION memcpy(res_APDU, pico_serial.id, 4);
pico_get_unique_board_id_string((char *) res_APDU, 4);
#endif
res_APDU_size = 4; res_APDU_size = 4;
} }
else if (p1 == 0x13) { else if (p1 == 0x13) {
@@ -478,9 +484,7 @@ int cmd_otp() {
else if (p1 == 0x20 || p1 == 0x28) { else if (p1 == 0x20 || p1 == 0x28) {
uint8_t challenge[16]; uint8_t challenge[16];
memcpy(challenge, apdu.data, 6); memcpy(challenge, apdu.data, 6);
#ifndef ENABLE_EMULATION memcpy(challenge + 6, pico_serial_str, 10);
pico_get_unique_board_id_string((char *) challenge + 6, 10);
#endif
mbedtls_aes_context ctx; mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx); mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128); mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128);
@@ -546,39 +550,43 @@ int otp_hid_set_report_cb(uint8_t itf,
uint8_t const *buffer, uint8_t const *buffer,
uint16_t bufsize) uint16_t bufsize)
{ {
if (report_type == 3) { if (itf == ITF_KEYBOARD) {
DEBUG_PAYLOAD(buffer, bufsize); if (report_type == 3) {
if (itf == ITF_KEYBOARD && buffer[7] == 0xFF) { // reset DEBUG_PAYLOAD(buffer, bufsize);
*get_send_buffer_size(ITF_KEYBOARD) = 0; if (buffer[7] == 0xFF) { // reset
otp_curr_seq = otp_exp_seq = 0; *get_send_buffer_size(ITF_KEYBOARD) = 0;
memset(otp_frame_tx, 0, sizeof(otp_frame_tx)); 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; else if (buffer[7] & 0x80) { // a frame
if (rseq < 10) { uint8_t rseq = buffer[7] & 0x1F;
if (rseq == 0) { if (rseq < 10) {
memset(otp_frame_rx, 0, sizeof(otp_frame_rx)); 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) {
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 { memcpy(otp_frame_rx + rseq * 7, buffer, 7);
printf("[OTP] Bad CRC!\n"); 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");
}
} }
} }
} }
@@ -615,8 +623,8 @@ uint16_t otp_hid_get_report_cb(uint8_t itf,
otp_curr_seq = otp_exp_seq = 0; otp_curr_seq = otp_exp_seq = 0;
} }
else { else {
res_APDU = buffer;
otp_status(); otp_status();
memcpy(buffer, res_APDU, 7);
} }
return reqlen; return reqlen;

View File

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

View File

@@ -20,6 +20,8 @@
from fido2.client import CtapError from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512 from fido2.cose import ES256, ES384, ES512
import fido2.features
fido2.features.webauthn_json_mapping.enabled = False
from utils import ES256K from utils import ES256K
import pytest import pytest
@@ -147,11 +149,13 @@ def test_bad_type_pubKeyCredParams_alg(device):
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
device.doMC(key_params=[{"alg": "7", "type": "public-key"}]) device.doMC(key_params=[{"alg": "7", "type": "public-key"}])
assert e.value.code == CtapError.ERR.CBOR_UNEXPECTED_TYPE
def test_unsupported_algorithm(device): def test_unsupported_algorithm(device):
with pytest.raises(CtapError) as e: with pytest.raises(CtapError) as e:
device.doMC(key_params=[{"alg": 1337, "type": "public-key"}]) device.doMC(key_params=[{"alg": 1337, "type": "public-key"}])
assert e.value.code == CtapError.ERR.CBOR_UNEXPECTED_TYPE assert e.value.code == CtapError.ERR.UNSUPPORTED_ALGORITHM
def test_exclude_list(resetdevice): def test_exclude_list(resetdevice):
resetdevice.doMC(exclude_list=[{"id": b"1234", "type": "rot13"}]) resetdevice.doMC(exclude_list=[{"id": b"1234", "type": "rot13"}])

View File

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

View File

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