29 Commits

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

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

View File

@@ -13,13 +13,12 @@ name: "CodeQL"
on: on:
push: push:
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ "main", "development" ] branches: [ "main", "development", "eddsa" ]
schedule: schedule:
- cron: '23 5 * * 4' - cron: '23 5 * * 4'
workflow_dispatch:
jobs: jobs:
analyze: analyze:
@@ -36,7 +35,6 @@ jobs:
language: [ 'cpp', 'python' ] language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
mode: [ 'pico', 'esp32', 'local' ]
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -44,7 +42,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v2
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@@ -68,7 +66,7 @@ jobs:
- run: | - run: |
echo "Run, Build Application using script" echo "Run, Build Application using script"
./workflows/autobuild.sh ${{ matrix.mode }} ./workflows/autobuild.sh
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v2

View File

@@ -1,35 +0,0 @@
name: "Nightly deploy"
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
nightly:
name: Deploy nightly
strategy:
fail-fast: false
matrix:
refs: [main, development]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ matrix.refs }}
submodules: 'recursive'
- name : Build
env:
PICO_SDK_PATH: ../pico-sdk
run: |
./workflows/autobuild.sh pico
./build_pico_fido.sh
./workflows/autobuild.sh esp32
- name: Update nightly release
uses: pyTooling/Actions/releaser@main
with:
tag: nightly-${{ matrix.refs }}
rm: true
token: ${{ secrets.GITHUB_TOKEN }}
files: release/*.*

View File

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

View File

@@ -18,8 +18,6 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
if(ESP_PLATFORM) if(ESP_PLATFORM)
set(DEBUG_APDU 1)
set(DENABLE_POWER_ON_RESET 0)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src) set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else() else()
@@ -41,6 +39,14 @@ endif()
add_executable(pico_fido) add_executable(pico_fido)
endif() endif()
option(ENABLE_UP_BUTTON "Enable/disable user presence button" ON)
if(ENABLE_UP_BUTTON)
add_definitions(-DENABLE_UP_BUTTON=1)
message(STATUS "User presence with button: \t enabled")
else()
add_definitions(-DENABLE_UP_BUTTON=0)
message(STATUS "User presence with button: \t disabled")
endif(ENABLE_UP_BUTTON)
option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON) option(ENABLE_POWER_ON_RESET "Enable/disable power cycle on reset" ON)
if(ENABLE_POWER_ON_RESET) if(ENABLE_POWER_ON_RESET)
@@ -71,7 +77,6 @@ endif(ENABLE_OTP_APP)
if(ENABLE_OTP_APP OR ENABLE_OATH_APP) if(ENABLE_OTP_APP OR ENABLE_OATH_APP)
set(USB_ITF_CCID 1) set(USB_ITF_CCID 1)
set(USB_ITF_WCID 1)
else() else()
set(USB_ITF_CCID 0) set(USB_ITF_CCID 0)
endif() endif()
@@ -79,7 +84,6 @@ endif()
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/kek.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c
@@ -111,7 +115,6 @@ 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)
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/fido/version.h" 1)
if(ESP_PLATFORM) if(ESP_PLATFORM)
project(pico_fido) project(pico_fido)
endif() endif()
@@ -157,6 +160,5 @@ if(ENABLE_EMULATION)
target_link_libraries(pico_fido PRIVATE pthread m) target_link_libraries(pico_fido PRIVATE pthread m)
else() else()
target_link_libraries(pico_fido PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id pico_aon_timer tinyusb_device tinyusb_board) 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)
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif() endif()
endif() endif()

View File

@@ -1,5 +1,5 @@
# Pico FIDO # Pico FIDO
This project transforms your Raspberry Pi Pico or ESP32 microcontroller into an integrated FIDO Passkey, functioning like a standard USB Passkey 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 includes the following features: Pico FIDO includes the following features:
@@ -13,8 +13,8 @@ Pico FIDO includes the following features:
- User verification with PIN - User verification with PIN
- Discoverable credentials (resident keys) - Discoverable credentials (resident keys)
- Credential management - Credential management
- ECDSA authentication - ECDSA and EDDSA authentication
- Support for SECP256R1, SECP384R1, SECP521R1, and SECP256K1 curves - Support for SECP256R1, SECP384R1, SECP521R1, SECP256K1 and Ed25519 curves
- App registration and login - App registration and login
- Device selection - Device selection
- Support for vendor configuration - Support for vendor configuration
@@ -30,68 +30,51 @@ Pico FIDO includes the following features:
- Large blobs support (2048 bytes max) - Large blobs support (2048 bytes max)
- OATH (based on YKOATH protocol specification) - OATH (based on YKOATH protocol specification)
- TOTP / HOTP - TOTP / HOTP
- Yubikey One Time Password - Yubikey OTP
- Challenge-response generation - Challenge-response generation
- Emulated keyboard interface - Emulated keyboard interface
- Button press generates an OTP that is directly 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
- Secure Boot and Secure Lock in RP2350 and ESP32-S3 MCUs
- One Time Programming to store the master key that encrypts all resident keys and seeds.
- Rescue interface to allow recovery of the device if it becomes unresponsive or undetectable.
- LED customization with Pico Commissioner.
All features comply with the specifications. If you encounter unexpected behavior or deviations from the specifications, 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
Microcontrollers RP2350 and ESP32-S3 are designed to support secure environments when Secure Boot is enabled, and optionally, Secure Lock. These features allow a master key encryption key (MKEK) to be stored in a one-time programmable (OTP) memory region, which is inaccessible from outside secure code. This master key is then used to encrypt all private and secret keys on the device, protecting sensitive data from potential flash memory dumps.
**However**, the RP2040 microcontroller lacks this level of security hardware, meaning that it cannot provide the same protection. Data stored on its flash memory, including private or master keys, can be easily accessed or dumped, as encryption of the master key itself is not feasible. Consequently, if an RP2040 device is stolen, any stored private or secret keys may be exposed. 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
**If you own an ESP32-S3 board, go to [ESP32 Flasher](https://www.picokeys.com/esp32-flasher/) for flashing your Pico FIDO.** Please visit the [Release page](https://github.com/polhenarejos/pico-fido/releases "Release page") to download the UF2 file for your board.
If you own a Raspberry Pico (RP2040 or RP2350), go to [Download page](https://www.picokeys.com/getting-started/), select your vendor and model and download the proper firmware; or go to [Release page](https://www.github.com/polhenarejos/pico-fido/releases/) and download the UF2 file for your board. Note that UF2 files are shipped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with OpenSC or similar software, you will need to modify the Info.plist of the CCID driver to add these VID/PID values or use the [Pico Patcher tool](https://www.picokeys.com/pico-patcher/).
Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with other proprietary tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner"). Alternatively, you can use the legacy VID/PID patcher with the following command:
```sh
./patch_vidpid.sh VID:PID input_hsm_file.uf2 output_hsm_file.uf2
```
You can use any VID/PID (e.g., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
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 Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") is the most recommended. ## Build
## Build for Raspberry Pico
Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive. Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive.
```sh ```sh
git clone https://github.com/polhenarejos/pico-fido git clone https://github.com/polhenarejos/pico-fido
git submodule update --init --recursive
cd pico-fido cd pico-fido
mkdir build mkdir build
cd build cd build
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678 PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678
make 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.
Additionally, you can pass the `VIDPID=value` parameter to build the firmware with a known VID/PID. The supported values are: 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.
- `NitroHSM` 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.
- `NitroFIDO2`
- `NitroStart`
- `NitroPro`
- `Nitro3`
- `Yubikey5`
- `YubikeyNeo`
- `YubiHSM`
- `Gnuk`
- `GnuPG`
After running `make`, the binary file `pico_fido.uf2` will be generated. To load this onto your Pico board: **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.
1. Put the Pico board into loading mode by holding the `BOOTSEL` button while plugging it in.
2. Copy the `pico_fido.uf2` file to the new USB mass storage device that appears.
3. Once the file is copied, the Pico mass storage device will automatically disconnect, and the Pico board will reset with the new firmware.
4. A blinking LED will indicate that the device is ready to work.
## 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:

View File

@@ -1,15 +1,9 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="6" VERSION_MAJOR="5"
VERSION_MINOR="2" VERSION_MINOR="12-eddsa1"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
#fi
rm -rf release/* rm -rf release/*
mkdir -p build_release
mkdir -p release
cd build_release cd build_release
for board in 0xcb_helios \ for board in 0xcb_helios \
@@ -102,7 +96,8 @@ for board in 0xcb_helios \
wiznet_w5100s_evb_pico wiznet_w5100s_evb_pico
do do
rm -rf * rm -rf *
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" cmake .. -DPICO_BOARD=$board PICO_SDK_PATH=../../pico-sdk cmake .. -DPICO_BOARD=$board
make -j`nproc` make -kj20
mv pico_fido.uf2 ../release/pico_fido_$board-$SUFFIX.uf2 mv pico_fido.uf2 ../release/pico_fido_$board-$VERSION_MAJOR.$VERSION_MINOR.uf2
done done

View File

@@ -18,20 +18,9 @@ if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_P
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif () endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
endif()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
if (NOT PICO_SDK_PATH) if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT) if (PICO_SDK_FETCH_FROM_GIT)
@@ -40,22 +29,11 @@ if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT_PATH) if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif () endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17 FetchContent_Declare(
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") pico_sdk
FetchContent_Declare( GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
pico_sdk GIT_TAG master
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk )
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
endif ()
if (NOT pico_sdk) if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK") message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk) FetchContent_Populate(pico_sdk)

View File

@@ -4,7 +4,6 @@
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1 IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y CONFIG_TINYUSB=y
CONFIG_TINYUSB_TASK_STACK_SIZE=16384
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
@@ -12,7 +11,6 @@ CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_WL_SECTOR_SIZE_512=y CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_MODE_PERF=y CONFIG_WL_SECTOR_MODE_PERF=y
COMPILER_OPTIMIZATION="Performance"
CONFIG_MBEDTLS_CMAC_C=y CONFIG_MBEDTLS_CMAC_C=y
CONFIG_MBEDTLS_CHACHA20_C=y CONFIG_MBEDTLS_CHACHA20_C=y

View File

@@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif #endif
@@ -120,13 +119,8 @@ void cbor_thread(void) {
DEBUG_DATA(res_APDU + 1, res_APDU_size); DEBUG_DATA(res_APDU + 1, res_APDU_size);
} }
else { else {
if (apdu.sw >= CTAP1_ERR_INVALID_CHANNEL) { res_APDU[0] = apdu.sw;
res_APDU[-1] = apdu.sw; //apdu.sw = 0;
apdu.sw = 0;
}
else {
res_APDU[0] = apdu.sw;
}
} }
finished_data_size = res_APDU_size + 1; finished_data_size = res_APDU_size + 1;
@@ -210,6 +204,9 @@ CborError COSE_key(mbedtls_ecp_keypair *key, CborEncoder *mapEncoderParent,
else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { else if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
alg = FIDO2_ALG_ECDH_ES_HKDF_256; alg = FIDO2_ALG_ECDH_ES_HKDF_256;
} }
else if (key->grp.id == MBEDTLS_ECP_DP_ED25519) {
alg = FIDO2_ALG_EDDSA;
}
return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder); return COSE_key_params(crv, alg, &key->grp, &key->Q, mapEncoderParent, mapEncoder);
} }
CborError COSE_key_shared(mbedtls_ecdh_context *key, CborError COSE_key_shared(mbedtls_ecdh_context *key,

View File

@@ -37,7 +37,6 @@
#include "crypto_utils.h" #include "crypto_utils.h"
#include "pico_keys.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "kek.h"
uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t usage_timer = 0, initial_usage_time_limit = 0;
uint32_t max_usage_time_period = 600 * 1000; uint32_t max_usage_time_period = 600 * 1000;
@@ -280,21 +279,6 @@ int pinUvAuthTokenUsageTimerObserver() {
return 0; return 0;
} }
int check_mkek_encrypted(const uint8_t *dhash) {
if (file_get_size(ef_mkek) == MKEK_IV_SIZE + MKEK_KEY_SIZE) {
hash_multi(dhash, 16, session_pin); // Only for storing MKEK
uint8_t mkek[MKEK_SIZE] = {0};
memcpy(mkek, file_get_data(ef_mkek), MKEK_IV_SIZE + MKEK_KEY_SIZE);
int ret = store_mkek(mkek);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
mbedtls_platform_zeroize(session_pin, sizeof(session_pin));
if (ret != PICOKEY_OK) {
return CTAP2_ERR_PIN_AUTH_INVALID;
}
}
return PICOKEY_OK;
}
uint8_t new_pin_mismatches = 0; uint8_t new_pin_mismatches = 0;
int cbor_client_pin(const uint8_t *data, size_t len) { int cbor_client_pin(const uint8_t *data, size_t len) {
@@ -431,20 +415,12 @@ 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[34], dhash[32]; 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, dhash); mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
double_hash_pin(dhash, 16, hsh + 2); file_put_data(ef_pin, hsh, 2 + 16);
file_put_data(ef_pin, hsh, 2 + 32);
low_flash_available(); low_flash_available();
ret = check_mkek_encrypted(dhash);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
goto err; //No return goto err; //No return
} }
else if (subcommand == 0x4) { //changePIN else if (subcommand == 0x4) { //changePIN
@@ -486,8 +462,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
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[34]; uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 34); memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
@@ -498,9 +474,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
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 dhash[32]; if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
double_hash_pin(paddedNewPin, 16, dhash);
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -514,7 +488,6 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
} }
hash_multi(paddedNewPin, 16, session_pin);
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
@@ -542,33 +515,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
uint8_t hsh[34]; 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, dhash); mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
double_hash_pin(dhash, 16, hsh + 2);
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 &&
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 32) == 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);
} }
file_put_data(ef_pin, hsh, 2 + 16);
uint8_t mkek[MKEK_SIZE] = {0};
ret = load_mkek(mkek);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
file_put_data(ef_pin, hsh, 2 + 32);
ret = check_mkek_encrypted(dhash);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
hash_multi(dhash, 16, session_pin);
ret = store_mkek(mkek);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
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 *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin)); uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin));
memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin)); memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin));
@@ -618,8 +570,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
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 pin_data[34]; uint8_t pin_data[18];
memcpy(pin_data, file_get_data(ef_pin), 34); memcpy(pin_data, file_get_data(ef_pin), 18);
pin_data[0] -= 1; pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
@@ -630,9 +582,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
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 dhash[32]; if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
double_hash_pin(paddedNewPin, 16, dhash);
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -646,19 +596,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
} }
} }
ret = check_mkek_encrypted(paddedNewPin);
if (ret != PICOKEY_OK) {
CBOR_ERROR(ret);
}
hash_multi(paddedNewPin, 16, session_pin);
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
new_pin_mismatches = 0; new_pin_mismatches = 0;
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
mbedtls_platform_zeroize(pin_data, sizeof(pin_data));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
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) {

View File

@@ -27,7 +27,6 @@
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/chachapoly.h" #include "mbedtls/chachapoly.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "file.h"
extern uint8_t keydev_dec[32]; extern uint8_t keydev_dec[32];
extern bool has_keydev_dec; extern bool has_keydev_dec;
@@ -36,7 +35,7 @@ int cbor_config(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0, vendorParam = 0; uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0;
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;
@@ -66,7 +65,7 @@ int cbor_config(const uint8_t *data, size_t len) {
raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1); raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1);
CBOR_PARSE_MAP_START(_f1, 2) CBOR_PARSE_MAP_START(_f1, 2)
{ {
if (subcommand == 0x7f) { // Config Aut if (subcommand == 0x7f) {
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
CBOR_FIELD_GET_UINT(vendorCommandId, 2); CBOR_FIELD_GET_UINT(vendorCommandId, 2);
@@ -75,7 +74,7 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_FIELD_GET_BYTES(vendorAutCt, 2); CBOR_FIELD_GET_BYTES(vendorAutCt, 2);
} }
} }
else if (subcommand == 0x03) { // Extensions else if (subcommand == 0x03) {
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
CBOR_FIELD_GET_UINT(newMinPinLength, 2); CBOR_FIELD_GET_UINT(newMinPinLength, 2);
@@ -95,15 +94,6 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_FIELD_GET_BOOL(forceChangePin, 2); CBOR_FIELD_GET_BOOL(forceChangePin, 2);
} }
} }
else if (subcommand == 0x1B) { // PHY
CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) {
CBOR_FIELD_GET_UINT(vendorCommandId, 2);
}
else if (subpara == 0x02) {
CBOR_FIELD_GET_UINT(vendorParam, 2);
}
}
} }
CBOR_PARSE_MAP_END(_f1, 2); CBOR_PARSE_MAP_END(_f1, 2);
raw_subpara_len = cbor_value_get_next_byte(&_f1) - raw_subpara; raw_subpara_len = cbor_value_get_next_byte(&_f1) - raw_subpara;
@@ -222,40 +212,6 @@ int cbor_config(const uint8_t *data, size_t len) {
set_opts(get_opts() | FIDO2_OPT_EA); set_opts(get_opts() | FIDO2_OPT_EA);
goto err; goto err;
} }
#ifndef ENABLE_EMULATION
else if (subcommand == 0x1B) {
if (vendorParam == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (vendorCommandId == CTAP_CONFIG_PHY_VIDPID) {
phy_data.vid = (vendorParam >> 16) & 0xFFFF;
phy_data.pid = vendorParam & 0xFFFF;
phy_data.vidpid_present = true;
}
else if (vendorCommandId == CTAP_CONFIG_PHY_LED_GPIO) {
phy_data.led_gpio = (uint8_t)vendorParam;
phy_data.led_gpio_present = true;
}
else if (vendorCommandId == CTAP_CONFIG_PHY_LED_BTNESS) {
phy_data.led_brightness = (uint8_t)vendorParam;
phy_data.led_brightness_present = true;
}
else if (vendorCommandId == CTAP_CONFIG_PHY_OPTS) {
phy_data.opts = (uint16_t)vendorParam;
}
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
uint8_t tmp[PHY_MAX_SIZE];
uint16_t tmp_len = 0;
memset(tmp, 0, sizeof(tmp));
if (phy_serialize_data(&phy_data, tmp, &tmp_len) != PICOKEY_OK) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
}
#endif
else { else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }

View File

@@ -519,7 +519,10 @@ 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 += put_uint32_t_be(ctr, pa); *pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
memcpy(pa, ext, ext_len); pa += ext_len; memcpy(pa, ext, ext_len); pa += ext_len;
if ((size_t)(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);
@@ -543,10 +546,21 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
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, aut_data, aut_data_len + clientDataHash.len, hash); else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL); if (md != NULL) {
mbedtls_ecdsa_free(&ekey); ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
}
else {
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
}
mbedtls_ecp_keypair_free(&ekey);
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
uint8_t lfields = 3; uint8_t lfields = 3;
if (selcred->opts.present == true && selcred->opts.rk == ptrue) { if (selcred->opts.present == true && selcred->opts.rk == ptrue) {

View File

@@ -90,11 +90,14 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_CRED_ID_LENGTH)); // MAX_CRED_ID_MAX_LENGTH
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0A));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 4));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder, &arrayEncoder, 5));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_EDDSA, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES384, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES512, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2)); CBOR_CHECK(COSE_public_key(FIDO2_ALG_ES256K, &arrayEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));

View File

@@ -129,7 +129,10 @@ 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;
put_uint32_t_le(offset, verify_data + 34); verify_data[34] = offset & 0xFF;
verify_data[35] = (offset >> 8) & 0xFF;
verify_data[36] = (offset >> 16) & 0xFF;
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((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) { if (verify((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);

View File

@@ -45,7 +45,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CredExtensions extensions = { 0 }; CredExtensions extensions = { 0 };
//options.present = true; //options.present = true;
//options.up = ptrue; //options.up = ptrue;
options.uv = pfalse; //options.uv = pfalse;
//options.rk = pfalse; //options.rk = pfalse;
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
@@ -221,6 +221,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (curve <= 0) { if (curve <= 0) {
curve = FIDO2_CURVE_P256K1; curve = FIDO2_CURVE_P256K1;
} }
}
else if (pubKeyCredParams[i].alg == FIDO2_ALG_EDDSA) {
if (curve <= 0) {
curve = FIDO2_CURVE_ED25519;
}
} }
else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) { else if (pubKeyCredParams[i].alg <= FIDO2_ALG_RS256 && pubKeyCredParams[i].alg >= FIDO2_ALG_RS512) {
// pass // pass
@@ -246,7 +251,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
//else if (options.up == NULL) //5.7 //else if (options.up == NULL) //5.7
//rup = ptrue; //rup = ptrue;
} }
if (pinUvAuthParam.present == false && options.uv == pfalse && file_has_data(ef_pin)) { //8.1 if (pinUvAuthParam.present == false && options.uv != ptrue && file_has_data(ef_pin)) { //8.1
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
} }
if (enterpriseAttestation > 0) { if (enterpriseAttestation > 0) {
@@ -286,7 +291,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) { if (strcmp(excludeList[e].type.data, (char *)"public-key") != 0) {
continue; continue;
} }
Credential ecred = {0}; Credential ecred;
if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash, if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash,
&ecred) == 0 && &ecred) == 0 &&
(ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED || (ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED ||
@@ -364,7 +369,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (extensions.credBlob.present == true) { if (extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, extensions.credBlob.len < MAX_CREDBLOB_LENGTH)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder,
extensions.credBlob.len < MAX_CREDBLOB_LENGTH));
} }
if (extensions.credProtect != 0) { if (extensions.credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect"));
@@ -385,16 +391,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
ext_len = cbor_encoder_get_buffer_size(&encoder, ext); ext_len = cbor_encoder_get_buffer_size(&encoder, ext);
flags |= FIDO2_AUT_FLAG_ED; flags |= FIDO2_AUT_FLAG_ED;
} }
mbedtls_ecdsa_context ekey; mbedtls_ecp_keypair ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
int ret = fido_load_key(curve, cred_id, &ekey); int ret = fido_load_key(curve, cred_id, &ekey);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id); const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(ekey.grp.id);
if (cinfo == NULL) { if (cinfo == NULL) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
size_t olen = 0; size_t olen = 0;
@@ -409,14 +415,18 @@ 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 += put_uint32_t_be(ctr, pa); *pa++ = (ctr >> 24) & 0xFF;
*pa++ = (ctr >> 16) & 0xFF;
*pa++ = (ctr >> 8) & 0xFF;
*pa++ = ctr & 0xFF;
memcpy(pa, aaguid, 16); pa += 16; memcpy(pa, aaguid, 16); pa += 16;
pa += put_uint16_t_be(cred_id_len, pa); *pa++ = ((uint16_t)cred_id_len >> 8) & 0xFF;
*pa++ = (uint16_t)cred_id_len & 0xFF;
memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len; memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len;
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs; memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len; memcpy(pa, ext, ext_len); pa += (uint16_t)ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) { if ((size_t)(pa - aut_data) != aut_data_len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
@@ -429,41 +439,30 @@ 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, aut_data, aut_data_len + clientDataHash.len, hash); else if (ekey.grp.id == MBEDTLS_ECP_DP_ED25519) {
md = NULL;
}
if (md != NULL) {
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
}
bool self_attestation = true; bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecp_keypair_free(&ekey);
mbedtls_ecdsa_init(&ekey); mbedtls_ecp_keypair_init(&ekey);
uint8_t key[32] = {0}; ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32);
if (load_keydev(key) != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER);
}
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, key, 32);
mbedtls_platform_zeroize(key, sizeof(key));
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, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL); if (md != NULL) {
mbedtls_ecdsa_free(&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);
}
if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) { else {
if (memcmp(user.parent.name.data, "+pico", 5) == 0) { ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
options.rk = pfalse; }
#ifndef ENABLE_EMULATION mbedtls_ecp_keypair_free(&ekey);
uint8_t *p = (uint8_t *)user.parent.name.data + 5; if (ret != 0) {
if (memcmp(p, "CommissionProfile", 17) == 0) { CBOR_ERROR(CTAP2_ERR_PROCESSING);
ret = phy_unserialize_data(user.id.data, user.id.len, &phy_data);
if (ret == PICOKEY_OK) {
file_put_data(ef_phy, user.id.data, user.id.len);
}
}
#endif
if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
low_flash_available();
}
} }
uint8_t largeBlobKey[32] = {0}; uint8_t largeBlobKey[32] = {0};

View File

@@ -24,14 +24,13 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#endif #endif
#include "fs/phy.h"
extern void scan_all(); extern void scan_all();
int cbor_reset() { int cbor_reset() {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1 #if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1
if (!(phy_data.opts & PHY_OPT_DISABLE_POWER_RESET) && board_millis() > 10000) { if (board_millis() > 10000) {
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
#endif #endif

View File

@@ -37,7 +37,14 @@ int mse_decrypt_ct(uint8_t *data, size_t len) {
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12); mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, len - 16, mse.key_enc, mse.Qpt, 65, data + len - 16, data, data); int ret = mbedtls_chachapoly_auth_decrypt(&chatx,
len - 16,
mse.key_enc,
mse.Qpt,
65,
data + len - 16,
data,
data);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
return ret; return ret;
} }
@@ -105,7 +112,8 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc), file_get_size(ef_keydev_enc))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc),
file_get_size(ef_keydev_enc)));
} }
else if (vendorCmd == 0x02) { else if (vendorCmd == 0x02) {
if (vendorParam.present == false) { if (vendorParam.present == false) {
@@ -132,7 +140,11 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdh_context hkey; mbedtls_ecdh_context hkey;
mbedtls_ecdh_init(&hkey); mbedtls_ecdh_init(&hkey);
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL); int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp,
&hkey.ctx.mbed_ecdh.d,
&hkey.ctx.mbed_ecdh.Q,
random_gen,
NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -148,19 +160,37 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buf[MBEDTLS_ECP_MAX_BYTES]; uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, mse.Qpt,sizeof(mse.Qpt)); ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp,
&hkey.ctx.mbed_ecdh.Qp,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&olen,
mse.Qpt,
sizeof(mse.Qpt));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL); ret = mbedtls_ecdh_calc_secret(&hkey,
&olen,
buf,
MBEDTLS_ECP_MAX_BYTES,
random_gen,
NULL);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
mbedtls_platform_zeroize(buf, sizeof(buf)); mbedtls_platform_zeroize(buf, sizeof(buf));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc)); ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
NULL,
0,
buf,
olen,
mse.Qpt,
sizeof(mse.Qpt),
mse.key_enc,
sizeof(mse.key_enc));
mbedtls_platform_zeroize(buf, sizeof(buf)); mbedtls_platform_zeroize(buf, sizeof(buf));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
@@ -218,7 +248,9 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
} }
mbedtls_x509write_csr ctx; mbedtls_x509write_csr ctx;
mbedtls_x509write_csr_init(&ctx); mbedtls_x509write_csr_init(&ctx);
snprintf((char *) buffer, sizeof(buffer), "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str); snprintf((char *) buffer,
sizeof(buffer),
"C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %s", pico_serial_str);
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);
@@ -226,7 +258,12 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
key.pk_ctx = &ekey; key.pk_ctx = &ekey;
mbedtls_x509write_csr_set_key(&ctx, &key); mbedtls_x509write_csr_set_key(&ctx, &key);
mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256); mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256);
mbedtls_x509write_csr_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", 0xB, 0, aaguid, sizeof(aaguid)); mbedtls_x509write_csr_set_extension(&ctx,
"\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04",
0xB,
0,
aaguid,
sizeof(aaguid));
ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_gen, NULL); ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_gen, NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
if (ret <= 0) { if (ret <= 0) {
@@ -249,41 +286,6 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
goto err; goto err;
} }
} }
#ifndef ENABLE_EMULATION
else if (cmd == CTAP_VENDOR_PHY_OPTS) {
if (vendorCmd == 0x01) {
uint16_t opts = 0;
if (file_has_data(ef_phy)) {
uint8_t *data = file_get_data(ef_phy);
opts = get_uint16_t_be(data + PHY_OPTS);
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, opts));
}
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
}
#endif
else if (cmd == CTAP_VENDOR_MEMORY) {
if (vendorCmd == 0x01) {
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 5));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_free_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_used_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_total_space()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_num_files()));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, flash_size()));
}
else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
}
else { else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }

View File

@@ -26,7 +26,7 @@
int cmd_authenticate() { int cmd_authenticate() {
CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data; CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data;
CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU; CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU;
//if (scan_files(true) != PICOKEY_OK) //if (scan_files(true) != CCID_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) { if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
@@ -55,7 +55,7 @@ int cmd_authenticate() {
} }
} }
free(tmp_kh); free(tmp_kh);
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -66,7 +66,10 @@ 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();
put_uint32_t_be(ctr, resp->ctr); resp->ctr[0] = (ctr >> 24) & 0xFF;
resp->ctr[1] = (ctr >> 16) & 0xFF;
resp->ctr[2] = (ctr >> 8) & 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));

View File

@@ -37,9 +37,9 @@ int u2f_select(app_t *a, uint8_t 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;
return PICOKEY_OK; return CCID_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
INITIALIZER ( u2f_ctor ) { INITIALIZER ( u2f_ctor ) {
@@ -47,7 +47,7 @@ INITIALIZER ( u2f_ctor ) {
} }
int u2f_unload() { int u2f_unload() {
return PICOKEY_OK; return CCID_OK;
} }
const uint8_t *bogus_firefox = (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint8_t *bogus_firefox = (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
@@ -59,7 +59,7 @@ int cmd_register() {
CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU; CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU;
resp->registerId = CTAP_REGISTER_ID; resp->registerId = CTAP_REGISTER_ID;
resp->keyHandleLen = KEY_HANDLE_LEN; resp->keyHandleLen = KEY_HANDLE_LEN;
//if (scan_files(true) != PICOKEY_OK) //if (scan_files(true) != CCID_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) { if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -77,7 +77,7 @@ int cmd_register() {
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key); int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key);
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -100,14 +100,8 @@ int cmd_register() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
uint8_t key_dev[32] = {0}; ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), 32);
ret = load_keydev(key_dev); if (ret != CCID_OK) {
if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR();
}
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, key_dev, 32);
mbedtls_platform_zeroize(key_dev, sizeof(key_dev));
if (ret != PICOKEY_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }

View File

@@ -147,10 +147,6 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
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);
if (!cred) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
}
memset(cred, 0, sizeof(Credential));
memcpy(copy_cred_id, cred_id, cred_id_len); memcpy(copy_cred_id, cred_id, cred_id_len);
ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash);
if (ret != 0) { // U2F? if (ret != 0) { // U2F?
@@ -240,19 +236,17 @@ err:
} }
void credential_free(Credential *cred) { void credential_free(Credential *cred) {
if (cred) { CBOR_FREE_BYTE_STRING(cred->rpId);
CBOR_FREE_BYTE_STRING(cred->rpId); CBOR_FREE_BYTE_STRING(cred->userId);
CBOR_FREE_BYTE_STRING(cred->userId); 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) {
if (cred->extensions.present) { CBOR_FREE_BYTE_STRING(cred->extensions.credBlob);
CBOR_FREE_BYTE_STRING(cred->extensions.credBlob);
}
cred->present = false;
cred->extensions.present = false;
cred->opts.present = false;
} }
cred->present = false;
cred->extensions.present = false;
cred->opts.present = false;
} }
int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) { int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) {

View File

@@ -114,10 +114,6 @@ typedef struct {
#define CTAP_CONFIG_AUT_ENABLE 0x03e43f56b34285e2 #define CTAP_CONFIG_AUT_ENABLE 0x03e43f56b34285e2
#define CTAP_CONFIG_AUT_DISABLE 0x1831a40f04a25ed9 #define CTAP_CONFIG_AUT_DISABLE 0x1831a40f04a25ed9
#define CTAP_CONFIG_PHY_VIDPID 0x6fcb19b0cbe3acfa
#define CTAP_CONFIG_PHY_LED_GPIO 0x7b392a394de9f948
#define CTAP_CONFIG_PHY_LED_BTNESS 0x76a85945985d02fd
#define CTAP_CONFIG_PHY_OPTS 0x969f3b09eceb805f
#define CTAP_VENDOR_CBOR (CTAPHID_VENDOR_FIRST + 1) #define CTAP_VENDOR_CBOR (CTAPHID_VENDOR_FIRST + 1)
@@ -125,8 +121,6 @@ typedef struct {
#define CTAP_VENDOR_MSE 0x02 #define CTAP_VENDOR_MSE 0x02
#define CTAP_VENDOR_UNLOCK 0x03 #define CTAP_VENDOR_UNLOCK 0x03
#define CTAP_VENDOR_EA 0x04 #define CTAP_VENDOR_EA 0x04
#define CTAP_VENDOR_PHY_OPTS 0x05
#define CTAP_VENDOR_MEMORY 0x06
#define CTAP_PERMISSION_MC 0x01 // MakeCredential #define CTAP_PERMISSION_MC 0x01 // MakeCredential
#define CTAP_PERMISSION_GA 0x02 // GetAssertion #define CTAP_PERMISSION_GA 0x02 // GetAssertion

View File

@@ -16,7 +16,6 @@
*/ */
#include "fido.h" #include "fido.h"
#include "kek.h"
#include "pico_keys.h" #include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "ctap.h" #include "ctap.h"
@@ -35,19 +34,14 @@
#include "management.h" #include "management.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "version.h" #include "version.h"
#include "crypto_utils.h"
#include "otp.h"
int fido_process_apdu(); int fido_process_apdu();
int fido_unload(); int fido_unload();
uint8_t PICO_PRODUCT = 2; // Pico FIDO
pinUvAuthToken_t paut = { 0 }; pinUvAuthToken_t paut = { 0 };
uint8_t keydev_dec[32]; uint8_t keydev_dec[32];
bool has_keydev_dec = false; bool has_keydev_dec = false;
uint8_t session_pin[32] = { 0 };
const uint8_t fido_aid[] = { const uint8_t fido_aid[] = {
8, 8,
@@ -72,9 +66,9 @@ int fido_select(app_t *a, uint8_t 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;
return PICOKEY_OK; return CCID_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
extern uint8_t (*get_version_major)(); extern uint8_t (*get_version_major)();
@@ -90,7 +84,7 @@ INITIALIZER ( fido_ctor ) {
} }
int fido_unload() { int fido_unload() {
return PICOKEY_OK; return CCID_OK;
} }
mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) { mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
@@ -112,6 +106,12 @@ mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
else if (curve == FIDO2_CURVE_X448) { else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448; return MBEDTLS_ECP_DP_CURVE448;
} }
else if (curve == FIDO2_CURVE_ED25519) {
return MBEDTLS_ECP_DP_ED25519;
}
else if (curve == FIDO2_CURVE_ED448) {
return MBEDTLS_ECP_DP_ED448;
}
return MBEDTLS_ECP_DP_NONE; return MBEDTLS_ECP_DP_NONE;
} }
int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) { int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
@@ -133,10 +133,16 @@ int mbedtls_curve_to_fido(mbedtls_ecp_group_id id) {
else if (id == MBEDTLS_ECP_DP_CURVE448) { else if (id == MBEDTLS_ECP_DP_CURVE448) {
return FIDO2_CURVE_X448; return FIDO2_CURVE_X448;
} }
else if (id == MBEDTLS_ECP_DP_ED25519) {
return FIDO2_CURVE_ED25519;
}
else if (id == MBEDTLS_ECP_DP_ED448) {
return FIDO2_CURVE_ED448;
}
return 0; return 0;
} }
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) { int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key) {
mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve); mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) { if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
return CTAP2_ERR_UNSUPPORTED_ALGORITHM; return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
@@ -182,27 +188,19 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
int load_keydev(uint8_t *key) { int load_keydev(uint8_t *key) {
if (has_keydev_dec == false && !file_has_data(ef_keydev)) { if (has_keydev_dec == false && !file_has_data(ef_keydev)) {
return PICOKEY_ERR_MEMORY_FATAL; return CCID_ERR_MEMORY_FATAL;
} }
if (has_keydev_dec == true) { if (has_keydev_dec == true) {
memcpy(key, keydev_dec, sizeof(keydev_dec)); memcpy(key, keydev_dec, sizeof(keydev_dec));
} }
else { else {
memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev)); memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev));
if (mkek_decrypt(key, 32) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
} }
//return mkek_decrypt(key, file_get_size(ef_keydev));
return PICOKEY_OK; return CCID_OK;
} }
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) { int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
for (int i = 0; i < KEY_PATH_ENTRIES; i++) { for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)]; uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) { if (!(k & 0x80000000)) {
@@ -235,12 +233,11 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
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, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) { int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecp_keypair *key) {
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length 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)) != PICOKEY_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);
@@ -280,6 +277,9 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (r != 0) { if (r != 0) {
return r; return r;
} }
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL); return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
} }
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
@@ -289,7 +289,6 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
int scan_files() { int scan_files() {
ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF); ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF); ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF);
ef_mkek = search_by_fid(EF_MKEK, NULL, SPECIFY_EF);
if (ef_keydev) { if (ef_keydev) {
if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) { if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) {
printf("KEY DEVICE is empty. Generating SECP256R1 curve..."); printf("KEY DEVICE is empty. Generating SECP256R1 curve...");
@@ -304,16 +303,13 @@ int scan_files() {
uint8_t kdata[64]; uint8_t kdata[64];
size_t key_size = 0; size_t key_size = 0;
ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, kdata, sizeof(kdata)); ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, kdata, sizeof(kdata));
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
return ret; return ret;
} }
if (otp_key_1) {
ret = aes_encrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, kdata, 32);
}
ret = file_put_data(ef_keydev, kdata, (uint16_t)key_size); 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 != PICOKEY_OK) { if (ret != CCID_OK) {
return ret; return ret;
} }
printf(" done!\n"); printf(" done!\n");
@@ -322,33 +318,13 @@ int scan_files() {
else { else {
printf("FATAL ERROR: KEY DEV not found in memory!\r\n"); printf("FATAL ERROR: KEY DEV not found in memory!\r\n");
} }
if (ef_mkek) { // No encrypted MKEK
if (!file_has_data(ef_mkek)) {
uint8_t mkek[MKEK_IV_SIZE + MKEK_KEY_SIZE];
random_gen(NULL, mkek, sizeof(mkek));
file_put_data(ef_mkek, mkek, sizeof(mkek));
int ret = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), file_get_data(ef_keydev), 32);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
if (ret != 0) {
printf("FATAL ERROR: MKEK encryption failed!\r\n");
}
}
}
else {
printf("FATAL ERROR: MKEK not found in memory!\r\n");
}
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[2048], outk[32]; uint8_t cert[2048];
memset(outk, 0, sizeof(outk));
int ret = 0;
if ((ret = load_keydev(outk)) != 0) {
return ret;
}
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, outk, sizeof(outk)); int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &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;
@@ -380,13 +356,6 @@ int scan_files() {
printf("FATAL ERROR: Global counter not found in memory!\r\n"); printf("FATAL ERROR: Global counter not found in memory!\r\n");
} }
ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF); ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
if (file_get_size(ef_pin) == 18) { // Upgrade PIN storage
uint8_t pin_data[34] = { 0 }, dhash[32];
memcpy(pin_data, file_get_data(ef_pin), 18);
double_hash_pin(pin_data + 2, 16, dhash);
memcpy(pin_data + 2, dhash, 32);
file_put_data(ef_pin, pin_data, 34);
}
ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF); ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
if (ef_authtoken) { if (ef_authtoken) {
if (!file_has_data(ef_authtoken)) { if (!file_has_data(ef_authtoken)) {
@@ -404,9 +373,8 @@ int scan_files() {
if (!file_has_data(ef_largeblob)) { if (!file_has_data(ef_largeblob)) {
file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17); 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);
} }
low_flash_available(); low_flash_available();
return PICOKEY_OK; return CCID_OK;
} }
void scan_all() { void scan_all() {
@@ -423,10 +391,12 @@ void init_fido() {
bool wait_button_pressed() { bool wait_button_pressed() {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
queue_try_add(&card_to_usb_q, &val); queue_try_add(&card_to_usb_q, &val);
do { do {
queue_remove_blocking(&usb_to_card_q, &val); queue_remove_blocking(&usb_to_card_q, &val);
} while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); } while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
#endif
#endif #endif
return val == EV_BUTTON_TIMEOUT; return val == EV_BUTTON_TIMEOUT;
} }
@@ -434,18 +404,21 @@ bool wait_button_pressed() {
uint32_t user_present_time_limit = 0; uint32_t user_present_time_limit = 0;
bool check_user_presence() { bool check_user_presence() {
if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) { #if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
if (user_present_time_limit == 0 ||
user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
if (wait_button_pressed() == true) { //timeout if (wait_button_pressed() == true) { //timeout
return false; return false;
} }
//user_present_time_limit = board_millis(); //user_present_time_limit = board_millis();
} }
#endif
return true; return true;
} }
uint32_t get_sign_counter() { uint32_t get_sign_counter() {
uint8_t *caddr = file_get_data(ef_counter); uint8_t *caddr = file_get_data(ef_counter);
return get_uint32_t_le(caddr); return (*caddr) | (*(caddr + 1) << 8) | (*(caddr + 2) << 16) | (*(caddr + 3) << 24);
} }
uint8_t get_opts() { uint8_t get_opts() {

View File

@@ -28,6 +28,7 @@
#endif #endif
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/eddsa.h"
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#else #else
@@ -45,13 +46,13 @@ extern int derive_key(const uint8_t *app_id,
bool new_key, bool new_key,
uint8_t *key_handle, uint8_t *key_handle,
int, int,
mbedtls_ecdsa_context *key); mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern bool wait_button_pressed(); extern bool wait_button_pressed();
extern void init_fido(); extern void init_fido();
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); 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_ecp_keypair *key);
extern int load_keydev(uint8_t *key); extern int load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out);
@@ -130,6 +131,4 @@ extern uint32_t user_present_time_limit;
extern pinUvAuthToken_t paut; extern pinUvAuthToken_t paut;
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign); extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
extern uint8_t session_pin[32];
#endif //_FIDO_H #endif //_FIDO_H

View File

@@ -18,20 +18,39 @@
#include "files.h" #include "files.h"
file_t file_entries[] = { file_t file_entries[] = {
{ .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = { 0 } }, // MF { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
{ .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key .ef_structure = 0, .acl = { 0 } }, // MF
{ .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc { .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{ .fid = EF_MKEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MKEK .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
{ .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device { .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,
{ .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{ .fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN { .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL,
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, { .fid = EF_COUNTER, .parent = 0, .name = NULL,
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = { 0 } } //end .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
.ef_structure = 0, .acl = { 0 } } //end
}; };
const file_t *MF = &file_entries[0]; const file_t *MF = &file_entries[0];
@@ -43,4 +62,3 @@ file_t *ef_pin = NULL;
file_t *ef_authtoken = NULL; file_t *ef_authtoken = NULL;
file_t *ef_keydev_enc = NULL; file_t *ef_keydev_enc = NULL;
file_t *ef_largeblob = NULL; file_t *ef_largeblob = NULL;
file_t *ef_mkek = NULL;

View File

@@ -22,7 +22,6 @@
#define EF_KEY_DEV 0xCC00 #define EF_KEY_DEV 0xCC00
#define EF_KEY_DEV_ENC 0xCC01 #define EF_KEY_DEV_ENC 0xCC01
#define EF_MKEK 0xCC0F
#define EF_EE_DEV 0xCE00 #define EF_EE_DEV 0xCE00
#define EF_EE_DEV_EA 0xCE01 #define EF_EE_DEV_EA 0xCE01
#define EF_COUNTER 0xC000 #define EF_COUNTER 0xC000
@@ -47,6 +46,5 @@ extern file_t *ef_pin;
extern file_t *ef_authtoken; extern file_t *ef_authtoken;
extern file_t *ef_keydev_enc; extern file_t *ef_keydev_enc;
extern file_t *ef_largeblob; extern file_t *ef_largeblob;
extern file_t *ef_mkek;
#endif //_FILES_H_ #endif //_FILES_H_

View File

@@ -1,137 +0,0 @@
/*
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fido.h"
#include "pico_keys.h"
#include "stdlib.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#endif
#include "kek.h"
#include "crypto_utils.h"
#include "random.h"
#include "mbedtls/md.h"
#include "mbedtls/cmac.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/chachapoly.h"
#include "files.h"
#include "otp.h"
extern uint8_t session_pin[32];
uint8_t mkek_mask[MKEK_KEY_SIZE];
bool has_mkek_mask = false;
#define POLY 0xedb88320
uint32_t crc32c(const uint8_t *buf, size_t len) {
uint32_t crc = 0xffffffff;
while (len--) {
crc ^= *buf++;
for (int k = 0; k < 8; k++) {
crc = (crc >> 1) ^ (POLY & (0 - (crc & 1)));
}
}
return ~crc;
}
void mkek_masked(uint8_t *mkek, const uint8_t *mask) {
if (mask) {
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
MKEK_KEY(mkek)[i] ^= mask[i];
}
}
}
int load_mkek(uint8_t *mkek) {
file_t *tf = search_file(EF_MKEK);
if (file_has_data(tf)) {
memcpy(mkek, file_get_data(tf), MKEK_SIZE);
}
if (has_mkek_mask) {
mkek_masked(mkek, mkek_mask);
}
if (file_get_size(tf) == MKEK_SIZE) {
int ret = aes_decrypt_cfb_256(session_pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
if (ret != 0) {
return PICOKEY_EXEC_ERROR;
}
if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != *(uint32_t *) MKEK_CHECKSUM(mkek)) {
return PICOKEY_WRONG_DKEK;
}
if (otp_key_1) {
mkek_masked(mkek, otp_key_1);
}
}
return PICOKEY_OK;
}
void release_mkek(uint8_t *mkek) {
mbedtls_platform_zeroize(mkek, MKEK_SIZE);
}
int store_mkek(const uint8_t *mkek) {
uint8_t tmp_mkek[MKEK_SIZE];
if (mkek == NULL) {
const uint8_t *rd = random_bytes_get(MKEK_IV_SIZE + MKEK_KEY_SIZE);
memcpy(tmp_mkek, rd, MKEK_IV_SIZE + MKEK_KEY_SIZE);
}
else {
memcpy(tmp_mkek, mkek, MKEK_SIZE);
}
if (otp_key_1) {
mkek_masked(tmp_mkek, otp_key_1);
}
*(uint32_t *) MKEK_CHECKSUM(tmp_mkek) = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE);
uint8_t tmp_mkek_pin[MKEK_SIZE];
memcpy(tmp_mkek_pin, tmp_mkek, MKEK_SIZE);
file_t *tf = search_file(EF_MKEK);
if (!tf) {
release_mkek(tmp_mkek);
release_mkek(tmp_mkek_pin);
return PICOKEY_ERR_FILE_NOT_FOUND;
}
aes_encrypt_cfb_256(session_pin, MKEK_IV(tmp_mkek_pin), MKEK_KEY(tmp_mkek_pin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
file_put_data(tf, tmp_mkek_pin, MKEK_SIZE);
release_mkek(tmp_mkek_pin);
low_flash_available();
release_mkek(tmp_mkek);
return PICOKEY_OK;
}
int mkek_encrypt(uint8_t *data, uint16_t len) {
int r;
uint8_t mkek[MKEK_SIZE + 4];
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
return r;
}
r = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
release_mkek(mkek);
return r;
}
int mkek_decrypt(uint8_t *data, uint16_t len) {
int r;
uint8_t mkek[MKEK_SIZE + 4];
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
return r;
}
r = aes_decrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
release_mkek(mkek);
return r;
}

View File

@@ -1,46 +0,0 @@
/*
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KEK_H_
#define _KEK_H_
#include "crypto_utils.h"
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#include <stdbool.h>
#endif
extern int load_mkek(uint8_t *);
extern int store_mkek(const uint8_t *);
extern void init_mkek();
extern void release_mkek(uint8_t *);
extern int mkek_encrypt(uint8_t *data, uint16_t len);
extern int mkek_decrypt(uint8_t *data, uint16_t len);
#define MKEK_IV_SIZE (IV_SIZE)
#define MKEK_KEY_SIZE (32)
#define MKEK_KEY_CS_SIZE (4)
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
#define MKEK_IV(p) (p)
#define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE)
#define MKEK_CHECKSUM(p) (MKEK_KEY(p) + MKEK_KEY_SIZE)
#define DKEK_KEY_SIZE (32)
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
extern bool has_mkek_mask;
#endif

View File

@@ -42,7 +42,7 @@ int man_select(app_t *a, uint8_t force) {
scan_all(); scan_all();
init_otp(); init_otp();
} }
return PICOKEY_OK; return CCID_OK;
} }
INITIALIZER ( man_ctor ) { INITIALIZER ( man_ctor ) {
@@ -50,7 +50,7 @@ INITIALIZER ( man_ctor ) {
} }
int man_unload() { int man_unload() {
return PICOKEY_OK; return CCID_OK;
} }
bool cap_supported(uint16_t cap) { bool cap_supported(uint16_t cap) {
@@ -65,7 +65,7 @@ bool cap_supported(uint16_t cap) {
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) {
ecaps = get_uint16_t_be(tag_data); ecaps = (tag_data[0] << 8) | tag_data[1];
} }
return ecaps & cap; return ecaps & cap;
} }
@@ -94,6 +94,9 @@ int man_get_config() {
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR; res_APDU[res_APDU_size++] = PICO_FIDO_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = TAG_NFC_SUPPORTED;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00;
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
res_APDU[res_APDU_size++] = TAG_USB_ENABLED; res_APDU[res_APDU_size++] = TAG_USB_ENABLED;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
@@ -105,6 +108,9 @@ int man_get_config() {
res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK; res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
res_APDU[res_APDU_size++] = TAG_NFC_ENABLED;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = 0x00;
} }
else { else {
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));
@@ -129,20 +135,12 @@ int cmd_write_config() {
return SW_OK(); return SW_OK();
} }
extern int cbor_reset();
int cmd_factory_reset() {
cbor_reset();
return SW_OK();
}
#define INS_READ_CONFIG 0x1D #define INS_READ_CONFIG 0x1D
#define INS_WRITE_CONFIG 0x1C #define INS_WRITE_CONFIG 0x1C
#define INS_RESET 0x1E // Reset device
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_READ_CONFIG, cmd_read_config }, { INS_READ_CONFIG, cmd_read_config },
{ INS_WRITE_CONFIG, cmd_write_config }, { INS_WRITE_CONFIG, cmd_write_config },
{ INS_RESET, cmd_factory_reset },
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };

View File

@@ -100,9 +100,9 @@ int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1; res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEY_OK; return CCID_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
INITIALIZER ( oath_ctor ) { INITIALIZER ( oath_ctor ) {
@@ -110,7 +110,7 @@ INITIALIZER ( oath_ctor ) {
} }
int oath_unload() { int oath_unload() {
return PICOKEY_OK; return CCID_OK;
} }
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) {
@@ -337,7 +337,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
int r = mbedtls_md_hmac(md_info, key + 2, key_len - 2, chal, chal_len, hmac); int r = mbedtls_md_hmac(md_info, key + 2, key_len - 2, chal, chal_len, hmac);
size_t hmac_size = mbedtls_md_get_size(md_info); size_t hmac_size = mbedtls_md_get_size(md_info);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
if (truncate == 0x01) { if (truncate == 0x01) {
res_APDU[res_APDU_size++] = 4 + 1; res_APDU[res_APDU_size++] = 4 + 1;
@@ -354,7 +354,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size; memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size;
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEY_OK; return CCID_OK;
} }
int cmd_calculate() { int cmd_calculate() {
@@ -391,11 +391,19 @@ int cmd_calculate() {
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.data, key.len, chal.data, chal.len); int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
uint64_t v = get_uint64_t_be(chal.data); uint64_t v =
((uint64_t) chal.data[0] << 56) |
((uint64_t) chal.data[1] << 48) |
((uint64_t) chal.data[2] << 40) |
((uint64_t) chal.data[3] << 32) |
((uint64_t) chal.data[4] << 24) |
((uint64_t) chal.data[5] << 16) |
((uint64_t) chal.data[6] << 8) |
(uint64_t) chal.data[7];
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);
@@ -403,7 +411,14 @@ int cmd_calculate() {
asn1_ctx_t ctxt; asn1_ctx_t ctxt;
asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt); asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
asn1_find_tag(&ctxt, TAG_IMF, &chal); asn1_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_t_be(v, chal.data); chal.data[0] = (v >> 56) & 0xFF;
chal.data[1] = (v >> 48) & 0xFF;
chal.data[2] = (v >> 40) & 0xFF;
chal.data[3] = (v >> 32) & 0xFF;
chal.data[4] = (v >> 24) & 0xFF;
chal.data[5] = (v >> 16) & 0xFF;
chal.data[6] = (v >> 8) & 0xFF;
chal.data[7] = v & 0xff;
file_put_data(ef, tmp, (uint16_t)ef_size); file_put_data(ef, tmp, (uint16_t)ef_size);
low_flash_available(); low_flash_available();
free(tmp); free(tmp);
@@ -451,7 +466,7 @@ int cmd_calculate_all() {
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.data, key.len, chal.data, chal.len); int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1]; res_APDU[res_APDU_size++] = key.data[1];
} }
@@ -562,14 +577,14 @@ int cmd_verify_hotp() {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) { if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_t_be(code.data); code_int = (code.data[0] << 24) | (code.data[1] << 16) | (code.data[2] << 8) | code.data[3];
} }
int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len); int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) { if (ret != CCID_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
uint32_t res_int = get_uint32_t_be(res_APDU + 2); uint32_t res_int = (res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5];
if (res_APDU[1] == 6) { if (res_APDU[1] == 6) {
res_int %= (uint32_t) 1e6; res_int %= (uint32_t) 1e6;
} }

View File

@@ -144,9 +144,9 @@ int otp_select(app_t *a, uint8_t force) {
memmove(res_APDU, res_APDU + 1, 6); memmove(res_APDU, res_APDU + 1, 6);
res_APDU_size = 6; res_APDU_size = 6;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEY_OK; return CCID_OK;
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
uint8_t modhex_tab[] = uint8_t modhex_tab[] =
@@ -169,11 +169,12 @@ void init_otp() {
otp_config_t *otp_config = (otp_config_t *) data; otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) && if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) &&
!(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) { !(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) {
uint16_t counter = get_uint16_t_be(data + otp_config_size); uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1];
if (++counter <= 0x7fff) { if (++counter <= 0x7fff) {
uint8_t new_data[otp_config_size + 8]; uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
put_uint16_t_be(counter, new_data + otp_config_size); new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
} }
} }
@@ -227,18 +228,25 @@ int otp_button_pressed(uint8_t slot) {
memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE); memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE);
uint64_t imf = 0; uint64_t imf = 0;
const uint8_t *p = data + otp_config_size; const uint8_t *p = data + otp_config_size;
imf = get_uint64_t_be(p); imf |= (uint64_t) *p++ << 56;
p += 8; imf |= (uint64_t) *p++ << 48;
imf |= (uint64_t) *p++ << 40;
imf |= (uint64_t) *p++ << 32;
imf |= *p++ << 24;
imf |= *p++ << 16;
imf |= *p++ << 8;
imf |= *p++;
if (imf == 0) { if (imf == 0) {
imf = get_uint16_t_be(otp_config->uid + 4); imf = ((otp_config->uid[4] << 8) | otp_config->uid[5]) << 4;
} }
uint8_t chal[8]; uint8_t chal[8] =
put_uint64_t_be(imf, chal); { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8, imf & 0xff };
res_APDU_size = 0; res_APDU_size = 0;
int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal)); int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal));
if (ret == PICOKEY_OK) { if (ret == CCID_OK) {
uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6; uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6;
uint32_t number = get_uint16_t_be(res_APDU + 2); uint32_t number =
(res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5];
number %= base; number %= base;
char number_str[9]; char number_str[9];
if (otp_config->cfg_flags & OATH_HOTP8) { if (otp_config->cfg_flags & OATH_HOTP8) {
@@ -250,8 +258,9 @@ int otp_button_pressed(uint8_t slot) {
add_keyboard_buffer((const uint8_t *) number_str, 6, true); add_keyboard_buffer((const uint8_t *) number_str, 6, true);
} }
imf++; imf++;
uint8_t new_chal[8]; uint8_t new_chal[8] =
put_uint64_t_be(imf, new_chal); { imf >> 56, imf >> 48, imf >> 40, imf >> 32, imf >> 24, imf >> 16, imf >> 8,
imf & 0xff };
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));
@@ -275,7 +284,7 @@ int otp_button_pressed(uint8_t slot) {
else { else {
uint8_t otpk[22], *po = otpk; uint8_t otpk[22], *po = otpk;
bool update_counter = false; bool update_counter = false;
uint16_t counter = get_uint16_t_be(data + otp_config_size), crc = 0; uint16_t counter = (data[otp_config_size] << 8) | data[otp_config_size + 1], crc = 0;
uint32_t ts = board_millis() / 1000; uint32_t ts = board_millis() / 1000;
if (counter == 0) { if (counter == 0) {
update_counter = true; update_counter = true;
@@ -285,8 +294,9 @@ int otp_button_pressed(uint8_t slot) {
po += 6; po += 6;
memcpy(po, otp_config->uid, UID_SIZE); memcpy(po, otp_config->uid, UID_SIZE);
po += UID_SIZE; po += UID_SIZE;
po += put_uint16_t_le(counter, po); *po++ = counter & 0xff;
ts >>= 1; *po++ = counter >> 8;
ts >>= 3;
*po++ = ts & 0xff; *po++ = ts & 0xff;
*po++ = ts >> 8; *po++ = ts >> 8;
*po++ = ts >> 16; *po++ = ts >> 16;
@@ -294,7 +304,8 @@ int otp_button_pressed(uint8_t slot) {
random_gen(NULL, po, 2); random_gen(NULL, po, 2);
po += 2; po += 2;
crc = calculate_crc(otpk + 6, 14); crc = calculate_crc(otpk + 6, 14);
po += put_uint16_t_le(~crc, po); *po++ = ~crc & 0xff;
*po++ = ~crc >> 8;
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);
@@ -315,7 +326,8 @@ int otp_button_pressed(uint8_t slot) {
if (update_counter == true) { if (update_counter == true) {
uint8_t new_data[otp_config_size + 8]; uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data)); memcpy(new_data, data, sizeof(new_data));
put_uint16_t_be(counter, new_data + otp_config_size); new_data[otp_config_size] = counter >> 8;
new_data[otp_config_size + 1] = counter & 0xff;
file_put_data(ef, new_data, sizeof(new_data)); file_put_data(ef, new_data, sizeof(new_data));
low_flash_available(); low_flash_available();
} }
@@ -336,7 +348,7 @@ INITIALIZER( otp_ctor ) {
} }
int otp_unload() { int otp_unload() {
return PICOKEY_OK; return CCID_OK;
} }
uint16_t otp_status() { uint16_t otp_status() {
@@ -520,7 +532,9 @@ extern uint16_t *get_send_buffer_size(uint8_t itf);
int otp_send_frame(uint8_t *frame, size_t frame_len) { int otp_send_frame(uint8_t *frame, size_t frame_len) {
uint16_t crc = calculate_crc(frame, frame_len); uint16_t crc = calculate_crc(frame, frame_len);
frame_len += put_uint16_t_le(~crc, frame + frame_len); frame[frame_len] = ~crc & 0xff;
frame[frame_len + 1] = ~crc >> 8;
frame_len += 2;
*get_send_buffer_size(ITF_KEYBOARD) = frame_len; *get_send_buffer_size(ITF_KEYBOARD) = frame_len;
otp_exp_seq = (frame_len / 7); otp_exp_seq = (frame_len / 7);
if (frame_len % 7) { if (frame_len % 7) {
@@ -553,7 +567,7 @@ int otp_hid_set_report_cb(uint8_t itf,
memcpy(otp_frame_rx + rseq * 7, buffer, 7); memcpy(otp_frame_rx + rseq * 7, buffer, 7);
if (rseq == 9) { if (rseq == 9) {
DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx)); DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65); 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]; uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) { if (residual_crc == rcrc) {
uint8_t hdr[5]; uint8_t hdr[5];

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_ #ifndef __VERSION_H_
#define __VERSION_H_ #define __VERSION_H_
#define PICO_FIDO_VERSION 0x0602 #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

@@ -19,7 +19,7 @@
from fido2.client import CtapError from fido2.client import CtapError
from fido2.cose import ES256, ES384, ES512 from fido2.cose import ES256, ES384, ES512, EdDSA
import fido2.features import fido2.features
fido2.features.webauthn_json_mapping.enabled = False fido2.features.webauthn_json_mapping.enabled = False
from utils import ES256K from utils import ES256K
@@ -124,7 +124,7 @@ def test_bad_type_pubKeyCredParams(device):
device.doMC(key_params=["wrong"]) device.doMC(key_params=["wrong"])
@pytest.mark.parametrize( @pytest.mark.parametrize(
"alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM] "alg", [ES256.ALGORITHM, ES384.ALGORITHM, ES512.ALGORITHM, ES256K.ALGORITHM, EdDSA.ALGORITHM]
) )
def test_algorithms(device, info, alg): def test_algorithms(device, info, alg):
if ({'alg': alg, 'type': 'public-key'} in info.algorithms): if ({'alg': alg, 'type': 'public-key'} in info.algorithms):

View File

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

View File

@@ -77,17 +77,11 @@ class VendorConfig(Config):
class PARAM(IntEnum): class PARAM(IntEnum):
VENDOR_COMMAND_ID = 0x01 VENDOR_COMMAND_ID = 0x01
VENDOR_AUT_CT = 0x02 VENDOR_AUT_CT = 0x02
VENDOR_PARAM = 0x02
class CMD(IntEnum): class CMD(IntEnum):
CONFIG_AUT_ENABLE = 0x03e43f56b34285e2 CONFIG_AUT_ENABLE = 0x03e43f56b34285e2
CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9 CONFIG_AUT_DISABLE = 0x1831a40f04a25ed9
CONFIG_VENDOR_PROTOTYPE = 0x7f CONFIG_VENDOR_PROTOTYPE = 0x7f
CONFIG_VENDOR_PHY = 0x1b
CONFIG_PHY_VIDPID = 0x6fcb19b0cbe3acfa
CONFIG_PHY_OPTS = 0x969f3b09eceb805f
CONFIG_PHY_LED_GPIO = 0x7b392a394de9f948
CONFIG_PHY_LED_BTNESS = 0x76a85945985d02fd
class RESP(IntEnum): class RESP(IntEnum):
KEY_AGREEMENT = 0x01 KEY_AGREEMENT = 0x01
@@ -112,42 +106,6 @@ class VendorConfig(Config):
}, },
) )
def vidpid(self, vid, pid):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PHY,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_VIDPID,
VendorConfig.PARAM.VENDOR_PARAM: (vid & 0xFFFF) << 16 | pid
},
)
def led_gpio(self, gpio):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PHY,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_LED_GPIO,
VendorConfig.PARAM.VENDOR_PARAM: gpio
},
)
def led_brightness(self, brightness):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PHY,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_LED_BTNESS,
VendorConfig.PARAM.VENDOR_PARAM: brightness
},
)
def phy_opts(self, opts):
self._call(
VendorConfig.CMD.CONFIG_VENDOR_PHY,
{
VendorConfig.PARAM.VENDOR_COMMAND_ID: VendorConfig.CMD.CONFIG_PHY_OPTS,
VendorConfig.PARAM.VENDOR_PARAM: opts
},
)
class Ctap2Vendor(Ctap2): class Ctap2Vendor(Ctap2):
def __init__(self, device: CtapDevice, strict_cbor: bool = True): def __init__(self, device: CtapDevice, strict_cbor: bool = True):
super().__init__(device=device, strict_cbor=strict_cbor) super().__init__(device=device, strict_cbor=strict_cbor)
@@ -232,8 +190,6 @@ class Vendor:
VENDOR_MSE = 0x02 VENDOR_MSE = 0x02
VENDOR_UNLOCK = 0x03 VENDOR_UNLOCK = 0x03
VENDOR_EA = 0x04 VENDOR_EA = 0x04
VENDOR_PHY = 0x05
VENDOR_MEMORY = 0x06
@unique @unique
class PARAM(IntEnum): class PARAM(IntEnum):
@@ -251,10 +207,6 @@ class Vendor:
PARAM = 0x01 PARAM = 0x01
COSE_KEY = 0x02 COSE_KEY = 0x02
class PHY_OPTS(IntEnum):
PHY_OPT_WCID = 0x1
PHY_OPT_DIMM = 0x2
def __init__( def __init__(
self, self,
ctap: Ctap2Vendor, ctap: Ctap2Vendor,
@@ -441,48 +393,6 @@ class Vendor:
} }
) )
def vidpid(self, vid, pid):
return self.vcfg.vidpid(vid, pid)
def led_gpio(self, gpio):
return self.vcfg.led_gpio(gpio)
def led_brightness(self, brightness):
if (brightness > 15):
print('ERROR: Brightness must be between 0 and 15')
return
return self.vcfg.led_brightness(brightness)
def led_dimmable(self, onoff):
opts = self.phy_opts()
if (onoff):
opts |= Vendor.PHY_OPTS.PHY_OPT_DIMM
else:
opts &= ~Vendor.PHY_OPTS.PHY_OPT_DIMM
print(f'opts: {opts}')
return self.vcfg.phy_opts(opts)
def wcid(self, onoff):
opts = self.phy_opts()
if (onoff):
opts |= Vendor.PHY_OPTS.PHY_OPT_WCID
else:
opts &= ~Vendor.PHY_OPTS.PHY_OPT_WCID
return self.vcfg.phy_opts(opts)
def phy_opts(self):
return self._call(
Vendor.CMD.VENDOR_PHY,
Vendor.SUBCMD.ENABLE,
)[Vendor.RESP.PARAM]
def memory(self):
resp = self._call(
Vendor.CMD.VENDOR_MEMORY,
Vendor.SUBCMD.ENABLE,
)
return { 'free': resp[1], 'used': resp[2], 'total': resp[3], 'files': resp[4], 'size': resp[5] }
def parse_args(): def parse_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparser = parser.add_subparsers(title="commands", dest="command") subparser = parser.add_subparsers(title="commands", dest="command")
@@ -498,21 +408,6 @@ def parse_args():
parser_attestation.add_argument('subcommand', choices=['csr']) parser_attestation.add_argument('subcommand', choices=['csr'])
parser_attestation.add_argument('--filename', help='Uploads the certificate filename to the device as enterprise attestation certificate. If not provided, it will generate an enterprise attestation certificate automatically.') parser_attestation.add_argument('--filename', help='Uploads the certificate filename to the device as enterprise attestation certificate. If not provided, it will generate an enterprise attestation certificate automatically.')
parser_phy = subparser.add_parser('phy', help='Set PHY options.')
subparser_phy = parser_phy.add_subparsers(title='commands', dest='subcommand', required=True)
parser_phy_vp = subparser_phy.add_parser('vidpid', help='Sets VID/PID. Use VID:PID format (e.g. 1234:5678)')
parser_phy_vp.add_argument('value', help='Value of the PHY option.', metavar='VAL', nargs='?')
parser_phy_ledn = subparser_phy.add_parser('led_gpio', help='Sets LED GPIO number.')
parser_phy_ledn.add_argument('value', help='Value of the PHY option.', metavar='VAL', nargs='?')
parser_phy_optwcid = subparser_phy.add_parser('wcid', help='Enable/Disable Web CCID interface.')
parser_phy_optwcid.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable Web CCID interface.', nargs='?')
parser_phy_ledbtness = subparser_phy.add_parser('led_brightness', help='Sets LED max. brightness.')
parser_phy_ledbtness.add_argument('value', help='Value of the max. brightness.', metavar='VAL', nargs='?')
parser_phy_optdimm = subparser_phy.add_parser('led_dimmable', help='Enable/Disable LED dimming.')
parser_phy_optdimm.add_argument('value', choices=['enable', 'disable'], help='Enable/Disable LED dimming.', nargs='?')
parser_mem = subparser.add_parser('memory', help='Get current memory usage.')
args = parser.parse_args() args = parser.parse_args()
return args return args
@@ -546,41 +441,8 @@ def attestation(vdr, args):
cert = x509.load_pem_x509_certificate(dataf) cert = x509.load_pem_x509_certificate(dataf)
vdr.upload_ea(cert.public_bytes(Encoding.DER)) vdr.upload_ea(cert.public_bytes(Encoding.DER))
def phy(vdr, args):
val = args.value if 'value' in args else None
if (val):
if (args.subcommand == 'vidpid'):
sp = val.split(':')
if (len(sp) != 2):
print('ERROR: VID/PID have wrong format. Use VID:PID format (e.g. 1234:5678)')
ret = vdr.vidpid(int(sp[0],16), int(sp[1],16))
elif (args.subcommand == 'led_gpio'):
val = int(val)
ret = vdr.led_gpio(val)
elif (args.subcommand == 'led_brightness'):
val = int(val)
ret = vdr.led_brightness(val)
elif (args.subcommand == 'led_dimmable'):
ret = vdr.led_dimmable(val == 'enable')
elif (args.subcommand == 'wcid'):
ret = vdr.wcid(val == 'enable')
if (ret):
print(f'Current value: {hexlify(ret)}')
else:
print('Command executed successfully. Please, restart your Pico Key.')
def memory(vdr, args):
mem = vdr.memory()
print(f'Memory usage:')
print(f'\tFree: {mem["free"]/1024:.2f} kilobytes ({mem["free"]*100/mem["total"]:.2f}%)')
print(f'\tUsed: {mem["used"]/1024:.2f} kilobytes ({mem["used"]*100/mem["total"]:.2f}%)')
print(f'\tTotal: {mem["total"]/1024:.2f} kilobytes')
print(f'\tFlash size: {mem["size"]/1024:.2f} kilobytes')
print(f'\tFiles: {mem["files"]}')
def main(args): def main(args):
print('Pico Fido Tool v1.10') print('Pico Fido Tool v1.6')
print('Author: Pol Henarejos') print('Author: Pol Henarejos')
print('Report bugs to https://github.com/polhenarejos/pico-fido/issues') print('Report bugs to https://github.com/polhenarejos/pico-fido/issues')
print('') print('')
@@ -598,10 +460,6 @@ def main(args):
backup(vdr, args) backup(vdr, args)
elif (args.command == 'attestation'): elif (args.command == 'attestation'):
attestation(vdr, args) attestation(vdr, args)
elif (args.command == 'phy'):
phy(vdr, args)
elif (args.command == 'memory'):
memory(vdr, args)
def run(): def run():
args = parse_args() args = parse_args()

View File

@@ -2,44 +2,12 @@
git submodule update --init --recursive git submodule update --init --recursive
sudo apt update sudo apt update
if [[ $1 == "pico" ]]; then
sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
git clone https://github.com/raspberrypi/pico-sdk git clone https://github.com/raspberrypi/pico-sdk
cd pico-sdk cd pico-sdk
git checkout tags/2.1.0
git submodule update --init git submodule update --init
cd .. cd ..
git clone https://github.com/raspberrypi/picotool
cd picotool
git submodule update --init
mkdir build mkdir build
cd build cd build
cmake -DPICO_SDK_PATH=../../pico-sdk ..
make -j`nproc`
sudo make install
cd ../..
mkdir build_pico
cd build_pico
cmake -DPICO_SDK_PATH=../pico-sdk .. cmake -DPICO_SDK_PATH=../pico-sdk ..
make make
cd ..
elif [[ $1 == "esp32" ]]; then
sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32s3
. ./export.sh
cd ..
idf.py set-target esp32s3
idf.py all
mkdir -p release
cd build
esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_fido_esp32-s3.bin @flash_args
cd ..
else
mkdir build
cd build
cmake -DENABLE_EMULATION=1 ..
make
fi