492 Commits

Author SHA1 Message Date
Pol Henarejos
113e720fca Merge remote-tracking branch 'origin/main' 2025-06-22 19:58:17 +02:00
Pol Henarejos
c45c97ee1f Fix Pico Keys SDK build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-06-22 19:57:15 +02:00
Pol Henarejos
d66d1c85b9 Add missing header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-06-22 19:52:36 +02:00
Pol Henarejos
f01aca5518 Flash size is obtained dynamically rather than in build time. It will allow to reduce dramatically the number of builds.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-05-30 12:06:26 +02:00
Pol Henarejos
da3a7f25d0 Fix bool build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-05-25 19:20:04 +02:00
Pol Henarejos
eb75ad4efa Add app_exists() to check if an AID is loaded. 2025-05-25 19:07:20 +02:00
Pol Henarejos
11d8a5343c Remove the tweak for packets multiple of 64 bytes. It was fixed in the USB stack handling (don't remember where).
Fixes #95.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-05-23 20:17:57 +02:00
Pol Henarejos
a324477a8a Fix interface descriptor when HID is disabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-05-02 18:28:38 +02:00
Pol Henarejos
580b0acffa Define MCU for emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-07 01:24:03 +02:00
Pol Henarejos
3990e7643a Fix EPNUM counting for ESP32. It fixes the problem of not sending KB.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-06 18:31:01 +02:00
Pol Henarejos
5718c83083 Upgrade TinyUSB for ESP32
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-04-06 18:26:34 +02:00
Pol Henarejos
a75fd6b815 CTAP_RESP should be 0ed before sending.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-30 18:12:06 +02:00
Pol Henarejos
499e8fafaa Upgrade to mbedtls v3.6.3 and fix git subscripts.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-24 23:58:53 +01:00
Pol Henarejos
5f79a8c8ed Fix ESP32 dynamic USB interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-24 09:22:25 +01:00
Pol Henarejos
a08abaed0f Enable each USB interface independently depending on PHY parameters.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-22 23:25:31 +01:00
Pol Henarejos
4ef641b8d3 Always build ccid if defined.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-22 23:25:04 +01:00
Pol Henarejos
c185b35ca3 Add enabled USB interfaces in PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-22 23:24:36 +01:00
Pol Henarejos
f1b1382300 USB descriptors are now created dynamically.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-21 15:30:50 +01:00
Pol Henarejos
f18f761234 Restore led mode when finishing button press.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 01:19:17 +01:00
Pol Henarejos
1a4ca13cc7 Add get led mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-19 01:18:57 +01:00
Pol Henarejos
ef9b66f990 Use TLV for PHY serialization/unserialization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-17 11:36:14 +01:00
Pol Henarejos
7191cda6d3 Add PHY option to enable specific curves. It's in the app side the management.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-11 18:43:08 +01:00
Pol Henarejos
2c3fe5bebf Only pin to core in ESP32-S3 since it is multicore.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-03-07 19:35:13 +01:00
Pol Henarejos
9e9632f297 Fix commissioned values for LED.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 00:49:45 +01:00
Pol Henarejos
259c4854df Fix LED for ESP32S3
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-23 00:49:12 +01:00
Pol Henarejos
0a4c7b0981 Fix autobuild.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:56:19 +01:00
Pol Henarejos
db338842b9 Add git pull when switch
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:12:19 +01:00
Pol Henarejos
71af710568 Add EDDSA support as a conditional build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 19:00:21 +01:00
Pol Henarejos
e18f192edf Fix ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 18:59:11 +01:00
Pol Henarejos
07415e6e8b Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 17:08:29 +01:00
Pol Henarejos
a9eff9fb17 Build cyw43 driver with RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-21 17:02:20 +01:00
Pol Henarejos
6e6b524878 Fix led driver build for Pimoroni.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 15:14:23 +01:00
Pol Henarejos
bfa085cae9 Take led_driver on build depending on defines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 14:32:58 +01:00
Pol Henarejos
94a842fa04 Add file & line to debug info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 11:43:47 +01:00
Pol Henarejos
90fb86be64 Add support for ESP32-S2 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-19 11:18:11 +01:00
Pol Henarejos
f06cb3a96d Fix multiple interfaces in older PCSC versions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-02-12 13:25:23 +01:00
Pol Henarejos
5985548c97 Merge pull request #7 from imkuang/limit-led-update-frequency
Limit the frequency of LED status updates
2025-02-09 19:16:29 +01:00
Pol Henarejos
3f5cbf6542 Merge pull request #8 from imkuang/update-led-ws2812-driver
Update ws2812 pio program and optimized the process of RGB color values
2025-02-09 19:12:39 +01:00
Ming Kuang
29c0d078c3 Update ws2812 pio program and optimized the process of RGB color values
1. Update ws2812 pio program to the latest version in pico-examples.
   References: https://github.com/raspberrypi/pico-examples/pull/486
2. Modify the rgbw type to false since we don't use the white channel.
3. Optimize the process of RGB color values to avoid a lot of shift
   operations and improve readability.
2025-02-09 16:51:22 +08:00
Ming Kuang
1723613b4e Limit the frequency of LED status updates
Unrestricted refreshing of the LED status may cause the WS2812
controller to not work properly.
Observed on my waveshare_rp2040_one board where the LED remains
either constantly on or off, even though the workflow should
dim or turn off/on the LED.
2025-02-09 15:35:42 +08:00
Pol Henarejos
44ca760e1c Added phy_save() and phy_load() to save and load PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 17:09:20 +01:00
Pol Henarejos
4992d8e273 Added phy_save() and phy_load() to save and load PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 17:06:55 +01:00
Pol Henarejos
80fa13a19c Do not init PHY on unserialize.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 16:57:53 +01:00
Pol Henarejos
b4c67d2fa5 Add PHY option to keep LED steady.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 16:27:26 +01:00
Pol Henarejos
18eb3e6ef2 Fixed stack overflow on serializing PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 15:16:13 +01:00
Pol Henarejos
350f0da763 Fix USB keyboard descriptor.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-29 13:21:17 +01:00
Pol Henarejos
a081a2bde6 LibCCID allows propietary class for CCID (ALLOW_PROPIETARY_CLASS in LibCCID). Then both interfaces are loaded but since both belong to same device, only the last is opened.
We change maxSlot value even it breaks the ICCD spec to cause a timeout in LibCCID and deactivate WebCCID interface.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-17 20:56:03 +01:00
Pol Henarejos
3d912878f1 Add OTP (dummy value) for emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-01-08 13:25:43 +01:00
Pol Henarejos
68a816895e Fix build for RP2040.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-30 21:37:38 +01:00
Pol Henarejos
1d89c14268 Compute flash memory bounds depending on the partition if available.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-30 21:27:46 +01:00
Pol Henarejos
5508c082e5 Add padding to align the struct in host build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-30 21:27:27 +01:00
Pol Henarejos
0bed03e522 Reduce data partition to 2K. It start always at half of flash.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-30 21:27:00 +01:00
Pol Henarejos
9e2b6ac4b6 Remove comment
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-24 02:05:50 +01:00
Pol Henarejos
046bac42e3 Update CCID descriptor to reflect max USB transport size.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-24 02:05:07 +01:00
Pol Henarejos
c59fb91540 Set stack size depending on the number of enabled interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-24 01:42:33 +01:00
Pol Henarejos
f8cb36c2cf Use uint16 funcs.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 21:23:13 +01:00
Pol Henarejos
d78e977926 Use BE/LE functions for packing uint16.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 21:00:43 +01:00
Pol Henarejos
8e68e6cae9 Use BE/LE functions for packing uint16.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 21:00:38 +01:00
Pol Henarejos
d530ea6979 Add BE/LE functions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 20:39:47 +01:00
Pol Henarejos
f509833a3c Pack file struct for.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 20:39:31 +01:00
Pol Henarejos
4f5f2a8854 Add functions to pack/unpack uint32_t and uint64_t.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 20:26:52 +01:00
Pol Henarejos
ffaf20da5d Add memory statistics.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-23 19:35:56 +01:00
Pol Henarejos
e627b3fc86 Fix with string termination.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-17 17:06:08 +01:00
Pol Henarejos
585a6d77e3 Use USB product field in the descriptor.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-17 16:27:11 +01:00
Pol Henarejos
7805131d92 Introduce USB product name as a dynamic field.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-17 16:25:47 +01:00
Pol Henarejos
86999d8cdd Do not debug after write the buffer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-16 18:42:42 +01:00
Pol Henarejos
6859cedcbf Use PHY value for LED GPIO number.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-16 13:10:51 +01:00
Pol Henarejos
1431f91281 In pure U2F mode, no keepalive is sent by authenticator. Instead, client sends commands to know the status.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-11 22:36:24 +01:00
Pol Henarejos
f58bcaecf1 In pure U2F mode, no keepalive is sent by authenticator. Instead, client sends commands to know the status.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-11 22:36:09 +01:00
Pol Henarejos
cb4e2ba0eb Fixes for ESP32-S3:
- It only supports 4 IN endpoints, so 1 EP must be removed (INT of CCID).
- It only supports 8 strings max.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-11 12:14:31 +01:00
Pol Henarejos
e9875b358c Fix cancel command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-03 08:35:20 +01:00
Pol Henarejos
fcae98eecc Add support for tinyusb 0.17 in ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-01 01:23:56 +01:00
Pol Henarejos
a61f7683b6 Add option to disable power cycle on reset via Commissioner.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-12-01 01:07:25 +01:00
Pol Henarejos
a271785814 Fix build for RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-25 23:45:54 +01:00
Pol Henarejos
49758c6ac7 Fix ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-25 22:59:01 +01:00
Pol Henarejos
9f79693025 Fix for Pico SDK 2.1.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-25 22:44:00 +01:00
Pol Henarejos
812f075ee4 Add UP button timeout to PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-25 12:57:17 +01:00
Pol Henarejos
6a18e3aa83 Add CCID SET_DATA_RATE_AND_CLOCK command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-25 12:54:57 +01:00
Pol Henarejos
8c25e9be87 Upgrade to v3.6.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-09 15:13:43 +01:00
Pol Henarejos
5a52afe826 Upgrade Pico Keys SDK to v7.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-09 14:56:50 +01:00
Pol Henarejos
5bce3e4c83 Remove Secure boot build flags, since are added to rescue.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-09 00:23:22 +01:00
Pol Henarejos
c877e51240 Add compile flags for optimization build in ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-09 00:20:16 +01:00
Pol Henarejos
9018ebb55d Fix secure otp build for non rp2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:45:50 +01:00
Pol Henarejos
621d5553e1 Fix PHY missing headers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:25:11 +01:00
Pol Henarejos
37e3058015 Add command to enable secure boot and secure lock via rescue.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:24:33 +01:00
Pol Henarejos
daddb7fa57 No options on secure boot and lock in PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:24:16 +01:00
Pol Henarejos
4da9b89d90 Add function to enable secure boot and secure lock.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:24:05 +01:00
Pol Henarejos
200413c317 Add macro to make checks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-08 19:23:45 +01:00
Pol Henarejos
758d7b88cd Add product and mcu to info in rescue mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-07 20:00:30 +01:00
Pol Henarejos
cf36c2988c Add DEV key to OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-07 00:15:58 +01:00
Pol Henarejos
f38e0619b8 Remove printf
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-06 23:42:55 +01:00
Pol Henarejos
5f27c0d75d Fix esp32 build with wcid.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-06 17:11:39 +01:00
Pol Henarejos
3dbf969e12 WCID interface is always enabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-06 17:02:38 +01:00
Pol Henarejos
e85d77c084 Fix version header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 18:36:59 +01:00
Pol Henarejos
6625678c30 Rename CCID_ codes to PICOKEY_
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 18:21:24 +01:00
Pol Henarejos
242e357a74 Add rescue app to communicate via webUSB.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 18:03:19 +01:00
Pol Henarejos
5399149b9d Increase number of hosted apps to 8.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 18:03:00 +01:00
Pol Henarejos
0edb1f370f Fix HID report descriptors.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 15:23:34 +01:00
Pol Henarejos
27a685b931 Fix usb initialization for emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 09:42:27 +01:00
Pol Henarejos
e4a3124876 Fix PHY for led neopixel.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 00:29:13 +01:00
Pol Henarejos
0638409ff8 Refactor PHY to support more flexible and scalable architecture.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-05 00:29:13 +01:00
Pol Henarejos
802df9e705 Add flags to enable secure boot and secure boot lock via firmware on boot.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-04 18:31:34 +01:00
Pol Henarejos
6f7d92a591 Add parse phy byte string.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-11-04 18:25:05 +01:00
Pol Henarejos
62c3d0c360 Add OTP read raw.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-10-28 00:15:13 +01:00
Pol Henarejos
6216cd24be Make public read/write RP2350 OTP functions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-10-13 20:22:16 +02:00
Pol Henarejos
32eed01508 Use non-guarded OTP reads to avoid bus faults.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-10-13 20:21:43 +02:00
Pol Henarejos
84c3efd782 Let detect macos target.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-10-01 13:29:09 +02:00
Pol Henarejos
cec3b4c7f6 Do not pack file_t to avoid misalignments.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-10-01 13:28:52 +02:00
Pol Henarejos
e2b3eacd89 Fix indent getting version
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-30 09:07:52 +02:00
Pol Henarejos
a816b6f747 Added PHY options to control the brigthness of the LED and its dimming.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-27 20:55:49 +02:00
Pol Henarejos
058473dce9 Add LED compatibility for other boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-27 19:57:58 +02:00
Pol Henarejos
037e760879 For compatibility with single led boards, mounted/not mounted led modes have to blink.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-27 19:38:40 +02:00
Pol Henarejos
50e54ed984 Fix float casting, otherwise it is always 0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-27 19:37:57 +02:00
Pol Henarejos
e32870bedb Merge pull request #5 from benallard/led
Add brightness to the LED mode.
2024-09-27 19:17:06 +02:00
Benoît Allard
c0012fe2a2 Use the correct shifting value 2024-09-26 19:21:21 +02:00
Benoît Allard
01d1856fcc Add brightness to the LED mode. 2024-09-25 23:20:48 +02:00
Benoît Allard
7a0b67f3cb led: Rename 'blink' to 'mode' 2024-09-25 21:46:33 +02:00
Pol Henarejos
fe396bc5b8 Fix ESP & emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-25 19:40:22 +02:00
Pol Henarejos
15d81be6de Specify led driver for each board.
Quina matada!

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-25 19:28:58 +02:00
Pol Henarejos
268ab824ce Add cmake scripts.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-25 19:28:27 +02:00
Pol Henarejos
86674fd6ca Fix build for WS2812 boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-25 12:00:50 +02:00
Pol Henarejos
30df1d9202 Fix build for boards with WS2812.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-25 11:33:14 +02:00
Pol Henarejos
839e8244d9 Fix header in Linux. Fixes #63
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-19 18:25:41 +02:00
Pol Henarejos
739e9f1b98 Added ESP32 OTP support.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-16 00:51:43 +02:00
Pol Henarejos
cafb6a4774 Not used
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-16 00:51:43 +02:00
Pol Henarejos
1bf323c367 Fix build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-13 08:47:32 +02:00
Pol Henarejos
3d52921ef5 Add sha256_alt to use sha256 hardware in RP2350.
Other boards and SHA224 use mbedtls implementation.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-13 00:26:44 +02:00
Pol Henarejos
f8a05f4832 Fix maxPower and dwProtocols (recover T=0).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-12 19:42:49 +02:00
Pol Henarejos
2011cfd35e In Windows, report ID shall start from 1.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-12 19:17:59 +02:00
Pol Henarejos
108cfec47c Enable OTP to store a permanent secret key.
It can be used by HSM or Fido to protect the keys and use it as MKEK.
2024-09-11 23:16:23 +02:00
Pol Henarejos
d3d2f021e7 Use debug header
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-11 23:15:29 +02:00
Pol Henarejos
e70552a298 Move debug to dedicated header
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-11 23:15:09 +02:00
Pol Henarejos
952e7791b0 Add json file to enable Secure Boot in RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-11 23:13:03 +02:00
Pol Henarejos
76ba851df1 Use internal TRNG of Pico.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-06 15:16:34 +02:00
Pol Henarejos
3cbbb6a16c Add signature and copy_to_ram if supports it
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-05 07:43:56 +02:00
Pol Henarejos
697e2fd263 Add macro to parse version file and set pico_binary_version accordingly.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-04 01:30:23 +02:00
Pol Henarejos
4711ae768a Move some functions to emulation header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-03 18:07:50 +02:00
Pol Henarejos
ea6303de81 Add new led module to use colors whenever is possible.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-03 18:07:37 +02:00
Pol Henarejos
460111d29e Upgrade to MbedTLS 3.6.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-03 10:29:02 +02:00
Pol Henarejos
70622a9a3b Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-03 10:28:50 +02:00
Pol Henarejos
bc34efed5c Fix LED blink when ON/OFF.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 18:20:52 +02:00
Pol Henarejos
20099b61e8 Fix ESP32 GPIO led no.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 17:28:18 +02:00
Pol Henarejos
9f65a2cfa0 Fix BOOT press with RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 09:48:04 +02:00
Pol Henarejos
294c1fdf41 Fix USB descriptor in case only HID is enabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 09:46:51 +02:00
Pol Henarejos
83c2eaa0b2 Remove printf.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 09:46:32 +02:00
Pol Henarejos
1c16bad83a Remove unusued var.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-09-02 09:46:12 +02:00
Pol Henarejos
3235cd8595 Use mutex/semaphores for emulation, like in Pico and ESP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 12:42:22 +02:00
Pol Henarejos
f8c4106367 Clear otp report before processing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 00:33:48 +02:00
Pol Henarejos
e8b060abb3 Call reset multicore before launching the thread.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-30 00:33:31 +02:00
Pol Henarejos
4cf8d77609 Fix partition 0 boot.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-29 16:29:11 +02:00
Pol Henarejos
2497b633ae Fix flash initialization for RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-28 18:47:31 +02:00
Pol Henarejos
0560e49b5c Add PICO_PLATFORM macro.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-28 18:47:07 +02:00
Pol Henarejos
af06fb367e Add partitions to RP2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-28 18:46:12 +02:00
Pol Henarejos
6f64a6b5ac Move ESP32 partitions file.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-28 18:44:00 +02:00
Pol Henarejos
2d6545f191 Add support to RP2350.
RP2350 does not support RTC, so we use AON timer instead.
2024-08-28 16:42:46 +02:00
Pol Henarejos
c2eda3ca53 Fix USB/CCID writes when APDU is longer than 64 bytes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-26 22:41:46 +02:00
Pol Henarejos
23dcc91add Fix vendord usb tx buffer size.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-26 22:40:44 +02:00
Pol Henarejos
e871c52f18 Fix long writes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-26 02:18:53 +02:00
Pol Henarejos
9ac4ebdaed Fix emulation write offset.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 20:57:22 +02:00
Pol Henarejos
85be276915 Fix ccid write with offset.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 20:57:00 +02:00
Pol Henarejos
956f476872 Fix emulation build without HID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 18:29:51 +02:00
Pol Henarejos
ac2a6c1052 Init low flash in core1 in emulation mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 00:11:10 +02:00
Pol Henarejos
e333383a22 Do not use mbedtls crt_dbrg as it it not reliable.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-25 00:10:53 +02:00
Pol Henarejos
7702401caa Do not use pthread_cancel. Instead use EV_EXIT.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-24 23:44:32 +02:00
Pol Henarejos
7a88a2b8e7 Improved multicore synchronization. Now they exchange signals and protect areas atomically.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 19:24:18 +02:00
Pol Henarejos
90842bb8f7 Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 14:24:17 +02:00
Pol Henarejos
65fea84df1 Fix warnings.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 13:17:10 +02:00
Pol Henarejos
b4487892a2 Fix windows build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 13:17:00 +02:00
Pol Henarejos
fa6292118d Major refactor of USB CCID and USB HID interfaces. All interfaces are rewritten.
With this new scheme we ensure that:
- memcpy's are reduced.
- no race conditions are performed.
- critical areas are protected.
- callbacks are executed immediately.
- write's are executed after the positive report is received.
- no usb middle interface anymore.
- CCID and HID are totally independent.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-23 10:02:19 +02:00
Pol Henarejos
0745838e3f Fix when receiving a packet in the middle of a transmission. RX shall be always processed.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 16:39:44 +02:00
Pol Henarejos
e1dd57067e Fix when a keepalive packet collides with an ongoing transmission.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 16:39:08 +02:00
Pol Henarejos
38f0e2cc3a select_app now invokes U2F or FIDO depending on the message.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 14:29:11 +02:00
Pol Henarejos
c1571c02f8 Increase vStack depending on the number of interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-20 12:43:01 +02:00
Pol Henarejos
d379a39bd6 keepalive should be sent without conditions and without reseting any buffer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 16:44:58 +02:00
Pol Henarejos
7c76a71f33 Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 13:18:03 +02:00
Pol Henarejos
93c491d72c Fix thread cancel in ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:07:19 +02:00
Pol Henarejos
e2bd7fc50f Add tinycbor to ESP32 build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:06:49 +02:00
Pol Henarejos
11447371fe Rewritten continuous flow for HID.
HID uses complete_cb to send the next packet and not the value returned by tud_write. Therefore, no other writes can happen in between of a writing packet if fails.

This ensures a proper interface multiplexing and continuous flow.

Also, the read pointer is used to multiplex usb packets.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:06:24 +02:00
Pol Henarejos
4e6ebc5c2a TinyUSB uses interface argument for that driver. Therefore, for vendord driver, interface starts at 0, even the HID interface is used.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:03:30 +02:00
Pol Henarejos
8fdd1a2305 Add usb.h declarations.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:02:32 +02:00
Pol Henarejos
0f24d17456 thread management is now in usb stuff. It ensures to launch an apdu/cbor thread depending on the processed packet.
It also includes a usb_rx_more to advance the rx pointer. It is useful to multiplex usb packets.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:02:15 +02:00
Pol Henarejos
c9df3c22a0 driver_exec_finished_cont_hid() now accepts an itf argument.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-19 00:00:46 +02:00
Pol Henarejos
b3dbee5cd6 Increase vStack of core0 of ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-18 23:43:54 +02:00
Pol Henarejos
aad1387052 Increase vStack in core1 of ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-08-18 23:43:32 +02:00
Pol Henarejos
f4ad8e1af2 Fix idVendor, idProduct allocation for Pico Patcher.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-15 14:41:08 +02:00
Pol Henarejos
7e8807e054 Fix potential infinite loop when bad ASN1 is processed.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-07-08 10:53:19 +02:00
Pol Henarejos
eca200d2f1 Fix EF.DIR selection.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-28 22:04:52 +02:00
Pol Henarejos
5c11db54ae BCD must be 2.0 for compatibility with windows.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-27 21:01:22 +02:00
Pol Henarejos
01d1de6074 Upgrade Pico Keys SDK to v6.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-22 20:56:03 +02:00
Pol Henarejos
447c68febd Fix potential overflow.
In practice, it never may happen.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-22 19:03:37 +02:00
Pol Henarejos
2700163e1f Better use phy opt mask.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-21 22:08:16 +02:00
Pol Henarejos
246ed5cf19 Fix when setting options and taking VIDPID values.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-21 22:07:28 +02:00
Pol Henarejos
f8480291fe Upgrade to Mbedtls 3.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-21 21:29:14 +02:00
Pol Henarejos
a3ff9ba697 Merge pull request #2 from al-heisner/main
Change total flash pages (needed for pico-hsm)
2024-06-21 18:57:51 +02:00
al heisner
e920bff3f4 Change total flash pages (needed for pico-hsm) 2024-06-21 11:41:02 -05:00
Pol Henarejos
218441a45a Added support for enable/disable Web CCID on the fly.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-19 23:28:55 +02:00
Pol Henarejos
a0e55ebfae Fix tusb initialization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-19 22:30:07 +02:00
Pol Henarejos
59597a0a68 Merge branch 'esp32' 2024-06-19 22:01:46 +02:00
Pol Henarejos
d458250887 Add PHY options and PHY_WCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-06-19 22:00:55 +02:00
Pol Henarejos
9a607707f0 Merge branch 'main' into esp32
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-05-31 17:12:12 +02:00
Pol Henarejos
e4e43dae04 Build x509 suite always if necessary.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-05-23 18:40:01 +02:00
Pol Henarejos
88071e1172 Some fixes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-05-05 00:56:51 +02:00
Pol Henarejos
af20b4f894 Merge branch 'main' into esp32
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-28 19:26:08 +02:00
Pol Henarejos
f0074e5367 CCID and WCID structs not used.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-22 23:35:19 +02:00
Pol Henarejos
0535138211 Only T=1 protocol is supported.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-21 22:52:16 +02:00
Pol Henarejos
a5f19a1356 Only T=1 protocol is supported.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-21 22:51:17 +02:00
Pol Henarejos
ef196bf10b Use new methods search_file() and file_put_data().
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 16:36:15 +02:00
Pol Henarejos
fc5f4299cc Fix emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 11:56:54 +02:00
Pol Henarejos
6f2721aba3 Use persistent memory for storing dynamic VID/PID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 11:42:57 +02:00
Pol Henarejos
cf1e076453 Introducing EF_PHY to store PHY (VIDPID and LED no.).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 11:40:01 +02:00
Pol Henarejos
22d4e62952 Add procedure to compute unique ID at startup.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 11:31:11 +02:00
Pol Henarejos
019c5929a2 Remove carriage return \r for better debug.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-17 11:21:10 +02:00
Pol Henarejos
ade730ffb5 Introducing EF_PHY to store PHY (VIDPID and LED no.).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-16 23:22:11 +02:00
Pol Henarejos
afc71f6942 Moving EF_VP to more generic EF_PHY, which stores PHY aspects from the chip.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-16 16:24:05 +02:00
Pol Henarejos
7b35000e11 Use persistent memory for storing dynamic VID/PID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-16 16:18:28 +02:00
Pol Henarejos
6f7ab69a9d Added support for dynamic USB_VID / USB_PID.
It can be changed on runtime without rebuilding or patching.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-16 00:04:23 +02:00
Pol Henarejos
b6b53010cc Fix build for emulated interface.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-16 00:03:43 +02:00
Pol Henarejos
8d86a8c56b Add procedure to compute unique ID at startup.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-15 23:44:51 +02:00
Pol Henarejos
a7be923783 ITF WCID can be compiled separately.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-15 23:44:12 +02:00
Pol Henarejos
10ab0d561c Upate build parameters.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-11 15:15:18 +02:00
Pol Henarejos
7def35f87c Remove carriage return \r for better debug.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-10 18:16:38 +02:00
Pol Henarejos
6adfe4344f When flash is written, map must be reopened.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-10 18:16:05 +02:00
Pol Henarejos
ab1b245f4f Fix write & read to flash partition.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-09 19:58:33 +02:00
Pol Henarejos
1ba109bd0a Fix TUSB definition.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-08 19:38:42 +02:00
Pol Henarejos
06fd241f49 Second round to make it work for ESP32S3.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-08 16:47:16 +02:00
Pol Henarejos
49f05e9e13 Now it builds the image.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-05 17:57:56 +02:00
Pol Henarejos
023039deb2 Attempting to add support to esp32s3.
Will it work? Who knows...

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-04-04 21:01:55 +02:00
Pol Henarejos
3d0a27c834 Add 3DES support.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-25 13:25:29 +01:00
Pol Henarejos
c0652ba1f7 Fix chained responses in other interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-21 22:02:01 +01:00
Pol Henarejos
b353beaaf8 Fixed chained response.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-20 00:07:00 +01:00
Pol Henarejos
b034a6c2d3 Added support for APDU chaining.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-19 18:55:09 +01:00
Pol Henarejos
151ae5fae4 Fix stupid bug initializing asn1 struct.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 21:20:57 +01:00
Pol Henarejos
e055d4cfc9 Added support for WebCCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 17:24:20 +01:00
Pol Henarejos
9fdae7ef31 Fix HID compilation with new sizes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 17:24:20 +01:00
Pol Henarejos
f88e786c04 Changed ASN1 calls for easier calls.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-03-13 17:16:35 +01:00
Pol Henarejos
caddf87c23 Fix Windows emulation build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-09 11:43:47 +01:00
Pol Henarejos
29837e5691 Fix Pico build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 20:43:15 +01:00
Pol Henarejos
63a2546166 Fix CodeQL build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 20:36:48 +01:00
Pol Henarejos
5ea372f01c Fix LE computation in a wrapped APDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 19:57:46 +01:00
Pol Henarejos
8476316e21 Fix wrapped RAPDU always returns 0x9000.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 19:57:22 +01:00
Pol Henarejos
bbc06efe67 Fix byte overwrite for long chained RAPDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 01:58:09 +01:00
Pol Henarejos
b4f71beaf0 Fix SM verification for long messages.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 01:57:55 +01:00
Pol Henarejos
a2bc4b6be9 Fix byte overwrite for long chained RAPDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 01:57:39 +01:00
Pol Henarejos
c9b830baa3 Fix chaining long APDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 01:27:30 +01:00
Pol Henarejos
22c9b7321b Fix SM wrap for large RAPDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-02 01:03:51 +01:00
Pol Henarejos
823c1d53ea Try to fix CodeQL build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-01 21:08:21 +01:00
Pol Henarejos
b663f5bebf Some fixes for emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-01 20:56:36 +01:00
Pol Henarejos
a9dc6fd7f8 Added support for building emulation in Windows.
It has not been tested but it should not break any linux build.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2024-01-01 01:54:49 +01:00
Pol Henarejos
adf53b4231 Fix ATR overwrite.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-12-29 19:07:02 +01:00
Pol Henarejos
4d77ca7b75 Add -DVIDPID=<VALUE> to build a project with a known VID/PID. Supported values: NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-12-11 18:12:38 +01:00
Pol Henarejos
30f86afe6d Fix build emulation in apple.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-11 21:18:53 +01:00
Pol Henarejos
f0687c1ef3 Upgrade to version 5.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 17:23:52 +01:00
Pol Henarejos
6069911be0 Fix cmac.c build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 16:55:20 +01:00
Pol Henarejos
0faa01acfe Upgrade to mbedtls 3.5.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 16:40:49 +01:00
Pol Henarejos
09276f7117 Rename files to new names.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 13:32:39 +01:00
Pol Henarejos
d0dc786f74 Rename project to Pico Keys SDK to avoid confusions with Pico Fido and Pico OpenPGP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 13:32:28 +01:00
Pol Henarejos
de3f5f0bce Update CMake file for standalone build.
It should build but not run.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 13:01:21 +01:00
Pol Henarejos
899a7ed609 Move some functions from HID to fido callbacks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 13:01:10 +01:00
Pol Henarejos
d253889747 Use get_version_major and get_version_minor as pointers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:57:09 +01:00
Pol Henarejos
c9cb330a07 Move some OTP functions from HID to OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-11-06 11:49:18 +01:00
Pol Henarejos
d580194030 Fix reading OTP packets from HID interface.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 17:34:09 +01:00
Pol Henarejos
0663c694ef Move timers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 17:33:47 +01:00
Pol Henarejos
81fcd2ced7 Go back 1 second wait
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 17:33:34 +01:00
Pol Henarejos
3182d1e2e6 Fixed potential crash.
board_button_read() disables interrupts and cannot be parallelized when flash is being used. It is imperative that core1 must not use flash during the board_button_read(). Since it is not feasible to put mutexes in *every* flash memory read/write in core1, it is preferable to wait until core1 finishes command execution.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-31 00:40:38 +01:00
Pol Henarejos
4f0925420b Fix HID version.
Select fido app when necessary.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:51:18 +02:00
Pol Henarejos
c896741114 Report descriptor shall contain FEATURE report too for Windows compatibility.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:32:31 +02:00
Pol Henarejos
f801f73f72 Report ID for keyboard shall be 0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-28 20:32:04 +02:00
Pol Henarejos
4b099c9d1e Call select AID if selected.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-12 17:40:49 +02:00
Pol Henarejos
1b5a7496e1 Only accept those applets that load successfully.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-11 21:04:45 +02:00
Pol Henarejos
eef2f190f2 New format for applet selection.
AID comparison is performed by the kernel. If it is the same as previously loaded, do nothing. If not found, do nothing. If found and is different, unload old and load the new one.

All other applets shall be migrated to new format.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-11 21:02:04 +02:00
Pol Henarejos
dbfb89f959 Add plaintext debug payload.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-10-11 12:12:41 +02:00
Pol Henarejos
42dcdd3372 Fix when chunking
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-24 10:31:35 +02:00
Pol Henarejos
a35ba063c4 Add cyw43 lib only for pico_w board.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 10:39:00 +02:00
Pol Henarejos
10a9511358 Added support for LED in Pico W.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-18 10:12:32 +02:00
Pol Henarejos
910b2fb75a Added NO_DELAY in emulation env.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-09-05 18:14:18 +02:00
Pol Henarejos
81a598f464 Revert "Fixed chained response."
This reverts commit e84258c434.
2023-08-22 17:18:36 +02:00
Pol Henarejos
a36a89cc95 If an applet is not selected, it returns NOT_FOUND on every command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-18 12:25:40 +02:00
Pol Henarejos
e84258c434 Fixed chained response.
Now it returns exactly 256 bytes (including SW).

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-08-16 19:19:50 +02:00
Pol Henarejos
4cfbc19aa7 Added support for Ripemd160.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-05-23 20:39:37 +02:00
Pol Henarejos
c7849e0bda Added support to Nitrokey's nitropy tool.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-05-16 09:22:52 +02:00
Pol Henarejos
579178ac56 Upgrade to mbedtls 3.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-05-10 00:17:19 +02:00
Pol Henarejos
38283f588d Fix particular case where an EF has masked types.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-04-27 11:43:20 +02:00
Pol Henarejos
46e7d3a181 Fix otp processing if other applications were processed before.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-31 00:41:12 +02:00
Pol Henarejos
f636085dbf Fix potential freeze.
For unknown reason, button cannot be checked if USB is active, as it is stalled.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-31 00:40:37 +02:00
Pol Henarejos
38fb8018e6 Add extern crc.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-30 23:44:21 +02:00
Pol Henarejos
3947b59881 Add fix for emulation conditional build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-30 01:04:11 +02:00
Pol Henarejos
94f9f2fdac Add bool header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-30 00:57:41 +02:00
Pol Henarejos
630da663c4 Added support for APPEND_CR.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-30 00:51:49 +02:00
Pol Henarejos
ef0fb29f29 Added encoding support for keyboard hid.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-30 00:37:07 +02:00
Pol Henarejos
c11d403f12 Added support for OTP interface.
This interface enables a HID Keyboard interface to send keystrokes to host. Also, it enables bidirectional flow through set/get report with 8-bytes chunked frames of 70 bytes.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-28 23:32:43 +02:00
Pol Henarejos
c6d08ae139 Fix conditional build for WS2812.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-26 20:15:38 +02:00
Pol Henarejos
b12e66a057 Added support for AES 512 bit keys (for XTS).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-19 20:00:59 +01:00
Pol Henarejos
ec9eb7c436 Fix race condition.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-14 09:57:50 +01:00
Pol Henarejos
be03298832 Fix potential crash on delete file.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-09 18:16:18 +01:00
Pol Henarejos
599e5edbd1 Fix conditional interface compilation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-04 14:16:45 +01:00
Pol Henarejos
15569ab419 Update code style.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-04 14:10:46 +01:00
Pol Henarejos
3b268a33eb Sending keepalive on cbor processing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-03 00:50:13 +01:00
Pol Henarejos
86613453ae Sending timeout command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-03 00:48:42 +01:00
Pol Henarejos
96f2dab74b Fix init_cmd channel.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-03 00:22:45 +01:00
Pol Henarejos
8f8134efbc Fix preparing rdata pointer with emulated HID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-03 00:05:05 +01:00
Pol Henarejos
b96e853e6d Added support for Fido emulation to automatize tests.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-02 22:05:04 +01:00
Pol Henarejos
455bc17a74 Added support for Waveshare RP2040 zero.
It uses the WS2812 led for blinking like normal Pico or Tiny2040.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-03-01 23:32:42 +01:00
Pol Henarejos
16b4fa6ca3 Emulation is now a higher define which also accepts interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-23 07:57:35 +01:00
Pol Henarejos
e5e5af634c Fix endianness of CCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-20 16:17:16 +01:00
Pol Henarejos
2471b3308b Adding support for CCID GET, SET and RESET PARAMS.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-20 13:16:46 +01:00
Pol Henarejos
e44fde509b Added support for Interrupt endpoint.
It is only used to inform the host changes on card status (insert or removal). Actually it only notifies the insertion of the virtual card on connect.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-17 19:43:26 +01:00
Pol Henarejos
fc40588547 Fixes for FIDO with Pico SDK 1.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-17 11:49:09 +01:00
Pol Henarejos
47fab18f96 Enabling entropy and ctr_drbg for emulation mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-16 23:41:43 +01:00
Pol Henarejos
1e1e49010a Upgrade to mbedtls v3.3.0 2023-02-16 23:33:13 +01:00
Pol Henarejos
2d486adadb mbed_config file is now specified via command line to avoid copying to includedir.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-16 23:26:21 +01:00
Pol Henarejos
1a3db6b667 Update mbedtls_config.h.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-16 23:25:37 +01:00
Pol Henarejos
e47c5412cf Fixes for Pico SDK 1.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-16 22:54:30 +01:00
Pol Henarejos
4708ae3d99 Add APPLE SDK search.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-16 13:51:22 +01:00
Pol Henarejos
31f899416c Using new style.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-15 00:14:10 +01:00
Pol Henarejos
43ef33d60b Switching to new style.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-15 00:10:00 +01:00
Pol Henarejos
12bdcbd1f9 Harmonizing coding style.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-14 23:23:57 +01:00
Pol Henarejos
31e66007d3 Fix embeding res_APDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-03 17:24:45 +01:00
Pol Henarejos
dcb18a3476 Fix when requesting more data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-02-02 22:28:42 +01:00
Pol Henarejos
07c15e0a3c Lets try
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-30 15:39:22 +01:00
Pol Henarejos
8f68e9f8a3 Some tricks
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-30 13:30:11 +01:00
Pol Henarejos
7e8021a3de Adding aesni in emulation env.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-30 13:04:21 +01:00
Pol Henarejos
a9eee861fe Adding support for chained apdu in emulation mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-17 00:06:17 +01:00
Pol Henarejos
00f9e9c408 Fix packed term.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-14 00:40:50 +01:00
Pol Henarejos
b4c1375961 Fix readin cached pages.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-14 00:40:39 +01:00
Pol Henarejos
4b420a7e8e Fix important crash.
When a file was cleared, file->data was not nulled and it was retained in subsequent calls, which derived onto a flash memory corruption.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-14 00:40:22 +01:00
Pol Henarejos
f59b7d92ef Delete meta file if becomes zero.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-14 00:39:06 +01:00
Pol Henarejos
7293683906 Using correct packed form.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-13 18:53:56 +01:00
Pol Henarejos
5d2dd5aa75 Compilation fixes
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-13 18:48:40 +01:00
Pol Henarejos
9bdde87b63 Fix reading memory when they are mapped.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-13 18:07:33 +01:00
Pol Henarejos
007782cd2b Moving debug data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-12 20:03:51 +01:00
Pol Henarejos
4d06c0fc3d Fix accessing to mapped memory.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-12 20:03:21 +01:00
Pol Henarejos
4c5ce3d257 Adding MAX macro.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-12 20:02:39 +01:00
Pol Henarejos
abb86dbf4b Fix missing vars in cmake.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-12 20:02:26 +01:00
Pol Henarejos
4919eb980f Added a major refactoring to include Emulated interface.
It works in combination with virtualsmarcard module (vpcd). It properly installed, it creates a virtual reader that can be interfaced via PCSC+vcpd. At user app level, it has no difference of having a physical smart card.

At this moment, it only works emulating a CCID interface.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-09 18:06:21 +01:00
Pol Henarejos
2d511df5d8 Fix alternating CCID and HID. (IT DOES NOT WORK)
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2023-01-08 23:56:48 +01:00
Pol Henarejos
bc107de1b9 Restyled messages.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-30 01:55:16 +01:00
Pol Henarejos
411755dee4 Adding a secondary HID interface that emulates a keyboard.
With it, an app can send a password directly to the host, like it is typed by user.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-30 01:41:49 +01:00
Pol Henarejos
20bd2c8b41 Fix writting read buffer for itf > 0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-30 01:40:22 +01:00
Pol Henarejos
70979da57a Remove debug line.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-28 17:05:19 +01:00
Pol Henarejos
9e92b9d4ed asn1_find_tag() may accept NULL tag_data and tag_len.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-26 21:37:42 +01:00
Pol Henarejos
026ce37c11 Fix returned type.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-24 01:40:53 +01:00
Pol Henarejos
36b2924036 If file functions are called with NULL arg silently return.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-24 01:39:26 +01:00
Pol Henarejos
a8fe504d14 No more discrimination related with core0/core1. using get_core_num() returns the core number.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-24 01:38:09 +01:00
Pol Henarejos
c0a540ae2b Fix processing APDU when no app is selected.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-24 01:37:04 +01:00
Pol Henarejos
7deaa990d3 An app can be selected even if there is another selected previously.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-24 00:49:25 +01:00
Pol Henarejos
88b2978ae5 Fix ATR response.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 22:50:37 +01:00
Pol Henarejos
b0bfc410a4 Thread on CORE1 is reset at every call.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 20:39:01 +01:00
Pol Henarejos
3310b911fc APDU header is defined at apdu_processing, depending on the interface.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 20:38:34 +01:00
Pol Henarejos
4682e5821f Selecting an app by AID requires the AID as argument.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 19:33:02 +01:00
Pol Henarejos
24522b9db8 Fix selecting FIDO AID when MSG.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 19:32:02 +01:00
Pol Henarejos
cd3ab0682c Fix initiating driver for CCID and buffers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-22 19:31:39 +01:00
Pol Henarejos
e99757ed52 Fix with size of descriptor in single interface mode.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-20 23:51:14 +01:00
Pol Henarejos
6faebdf309 TUD options are declared on compile time depending on enabled interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-20 23:50:51 +01:00
Pol Henarejos
e5825df5cb Added capability to add multiple interfaces: HID and CCID at compile time.
Depending on compiling flags, HID and/or CCID may be enabled independently and run simultaneously.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-12-20 23:41:24 +01:00
Pol Henarejos
fa54da973c Added first step to Enterprise Attestation.
Once enabled, it allows to generate a CSR in the device, which is sent to our PKI. If valid, it returns a signed certificate by an intermediate CA that will be used for attestation.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-30 23:41:05 +01:00
Pol Henarejos
0bc13df1a2 Queues are emptied at begining of card thread.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-28 18:54:01 +01:00
Pol Henarejos
a3f060a79d Setting own VID/PID (despite they are useless).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-28 17:36:40 +01:00
Pol Henarejos
c4178fda4b Fix when multiple shutdowns are sent
Thread queues are empty on every start to avoid ancient messages from previous sessions.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-24 20:21:06 +01:00
Pol Henarejos
3def9bff4f Added PKCS5 source for key derivation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-14 13:07:24 +01:00
Pol Henarejos
fccee34a1e In asn1_find_tag(), tag_data and tag_len are not modified if not found.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-11 14:30:34 +01:00
Pol Henarejos
28170100cc Adding support for Curve25519 and Curve448.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-11-09 16:49:45 +01:00
Pol Henarejos
74210d7af0 Fix chaining more than 2 chunks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-30 23:41:56 +01:00
Pol Henarejos
b2c2980d73 Fix secure channel with no payload.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-30 21:10:35 +01:00
Pol Henarejos
4a8a6728c7 Adding support for specific vendor HID command (0x41).
It is a self implementation, based on CBOR command.
data[0] conveys the command and the contents mapped in CBOR encoding.
The map uses the authConfig template, where the fist item in the map is the subcommand (enable/disable at this moment), the second is a map of the parameters, the third and fourth are the pinUvParam and pinUvProtocol.

With this format only a single vendor HID command is necessary (0x41), which will be used for all my own commands, by using the command id in data[0] like with CBOR.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-29 19:41:00 +02:00
Pol Henarejos
5bdc7ab202 Adding specific vendor command to unlock the device.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-17 17:38:58 +02:00
Pol Henarejos
1e66e51595 Adding ENABLE_DELAYED_BOOT flag for delayed boot compilation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-05 11:09:24 +02:00
Pol Henarejos
e5fe638c68 Fix related with reallocation under some optimization situations.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-10-05 09:33:18 +02:00
Pol Henarejos
8f14db677e Fix strange bug when usb cannot write.
In this case, the buffer is kept until the next success call.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-29 23:11:49 +02:00
Pol Henarejos
d0fe447416 Fix PING with no data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-29 16:59:30 +02:00
Pol Henarejos
27d897be6c Adding delete_file().
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-29 09:05:39 +02:00
Pol Henarejos
c5095dfec6 Only send response apdu if sw != 0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-27 22:10:47 +02:00
Pol Henarejos
2aff75a3ec Fix keepalive msg.
Only sent when CBOR is initiatied.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-27 22:09:16 +02:00
Pol Henarejos
286858c907 Compact debug.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-27 22:07:15 +02:00
Pol Henarejos
815e865ced Moving some defines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-27 12:23:43 +02:00
Pol Henarejos
3912775ccb Fix writting large packets.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-27 12:23:16 +02:00
Pol Henarejos
b70a7474f2 Possibly not necessary, as it returns 0 if there is no available.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 23:35:35 +02:00
Pol Henarejos
96641e79e5 Moving to MbedTLS 3.2.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 23:33:12 +02:00
Pol Henarejos
fa371643a1 Fix writing large usb buffers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 23:23:07 +02:00
Pol Henarejos
52a2ff8b34 Adding chacha sources, as it is enabled in config.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 20:34:51 +02:00
Pol Henarejos
55d4839e21 Adding missing function to ccid driver.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 20:34:18 +02:00
Pol Henarejos
657913d29a Upgrading version
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 18:14:18 +02:00
Pol Henarejos
18fa1d7f37 Reseting previous command if new arrives.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-25 18:09:37 +02:00
Pol Henarejos
f123108c3e Added variable to cancel button press.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-23 18:07:38 +02:00
Pol Henarejos
f8590ba8c7 Added CTAPHID_CANCEL support.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-23 18:07:27 +02:00
Pol Henarejos
4d7101b802 Fix send_keepalive with auxiliary buffer.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 23:53:55 +02:00
Pol Henarejos
7fded7234b Adding extra buffer to tx.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 22:52:56 +02:00
Pol Henarejos
988d4e23c2 Fix combining APDU MSG and keepalive.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 22:52:41 +02:00
Pol Henarejos
c23f17107a Random functions shall be called for each core, otherwise it will hung.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 20:18:05 +02:00
Pol Henarejos
91e2b7f643 Fix reading corrupted memory.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 19:24:17 +02:00
Pol Henarejos
3092da23ed card_init_core1() shall be called from every thread launched on core1.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 19:24:07 +02:00
Pol Henarejos
e29521fcf6 Multiple bug fixes to pass HID tests.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 19:23:39 +02:00
Pol Henarejos
d2e54b04db Adding variable button timeout.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 19:22:44 +02:00
Pol Henarejos
4ab68cc822 HID fixes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 14:05:39 +02:00
Pol Henarejos
e1914556ec Fix debug_data
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 09:59:02 +02:00
Pol Henarejos
287be74921 Adding macro for easy debug.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-22 09:29:43 +02:00
Pol Henarejos
5a4aff7008 Adding KEEP_ALIVE response.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-20 15:31:34 +02:00
Pol Henarejos
8b97791d8f Reorganizing core0/core1 split.
Now CBOR and APDU (i.e., intensive processing) areas are executed on core1, while core0 is dedicated for hardware tasks (usb, button, led, etc.).
2022-09-20 14:39:59 +02:00
Pol Henarejos
847005d94f Adding support for clientPIN.
It does not pass the tests yet.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-19 17:20:52 +02:00
Pol Henarejos
68f43f3cb2 Adding functions for calling random in core0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-16 00:49:10 +02:00
Pol Henarejos
4c49e59edc Major CTAP refactoring.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-15 14:16:40 +02:00
Pol Henarejos
633593aae3 Adding chacha sources.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-15 14:16:30 +02:00
Pol Henarejos
42f3c67c61 Adding Credentials structure.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-14 17:27:00 +02:00
Pol Henarejos
493a88538a Adding support for ChaCha20 with Poly1305.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-14 17:26:45 +02:00
Pol Henarejos
607f7c50d4 Adding some macros for CBOR parsing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-14 00:08:05 +02:00
Pol Henarejos
2cb59d57d2 Adding first attempt of adding make_credential.
It requires lot of efforts to parse CBOR incoming data.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-13 20:37:15 +02:00
Pol Henarejos
a8e1fe5842 Adding CBOR parser routines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-13 20:36:27 +02:00
Pol Henarejos
d1530733a2 Lots of fixes with CBOR encoding cbor_get_info().
- Numeric fields shall be encoded with uint and NOT with simple, despite are < 24.
- maxCredentialCountInList and maxCredentialIdLength only accept uint values.
- up shall not be present (assumed True always).
- Also added cbor_reset(). It does nothing but ok.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-12 00:50:38 +02:00
Pol Henarejos
4538d6ef14 Add TinyCBOR library compile.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-09 20:43:18 +02:00
Pol Henarejos
4a1bddb3d5 Adding cbor_get_info().
This is the first funciont that uses TinyCBOR to encode the cbor message.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-09 20:35:11 +02:00
Pol Henarejos
c6a129b6ad Add TinyCBOR for CBOR encoding/decoding.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-09 20:33:42 +02:00
Pol Henarejos
abd52c34ba Added CBOR processing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 20:37:21 +02:00
Pol Henarejos
7aeac46eef Adding CTAP2 commands.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 17:49:56 +02:00
Pol Henarejos
867d4637ee Moving from U2F to CTAP1.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 17:35:40 +02:00
Pol Henarejos
7491021102 Fix initializing variables.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 16:38:13 +02:00
Pol Henarejos
9b137f6f08 Moved to FIDO.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 13:50:28 +02:00
Pol Henarejos
3f492b9272 Upgrade version to v3.2.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 13:45:30 +02:00
Pol Henarejos
799733203b Added SYNC command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 13:24:03 +02:00
Pol Henarejos
0be497e713 Added LOCK command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 13:12:17 +02:00
Pol Henarejos
e23dead31d Add PING command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 12:56:32 +02:00
Pol Henarejos
4d9faccedb Added some sanity checks.
Also fix u2f_error report.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 12:13:34 +02:00
Pol Henarejos
f47df94dfb Added some string descriptors.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-08 10:45:25 +02:00
Pol Henarejos
c0123aa669 Adding blink in 1 second on WINK.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-06 16:09:02 +02:00
Pol Henarejos
43dfb0cde5 Fix APDU processing for small packets.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-05 17:30:05 +02:00
Pol Henarejos
f14e029094 Adding x509 routines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-05 17:05:51 +02:00
Pol Henarejos
f14cc8dba5 Clearing tx buffer for every transmission.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-05 16:47:07 +02:00
Pol Henarejos
16a1981dc3 When a packet > 57 bytes is sent, it must be chunked.
Once the packet is sent, a callback is triggered to send the next chunk.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-05 11:29:04 +02:00
Pol Henarejos
9ccd10fcea Adding x509 functions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-02 19:08:45 +02:00
Pol Henarejos
a6506e6c95 Adding missing headers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-09-02 19:08:33 +02:00
Pol Henarejos
3e73d6569b Disabling MbedTLS with FS. 2022-09-02 19:08:25 +02:00
Pol Henarejos
214ec2b9ae Adding support for U2F_MSG 2022-09-02 18:02:31 +02:00
Pol Henarejos
1d2a461086 Adding missing file. 2022-08-31 14:18:14 +02:00
Pol Henarejos
8075352fab Upgrading version to v3.0 2022-08-31 13:55:29 +02:00
Pol Henarejos
cd3812ecca Creating a cmake library to be added by other projects. 2022-08-31 13:55:14 +02:00
Pol Henarejos
2f565f23e0 Small debug fix 2022-08-30 17:48:25 +02:00
Pol Henarejos
93ac6c2128 Fix addressing apdu. 2022-08-30 16:57:37 +02:00
Pol Henarejos
13983bdd68 Fix compiling with disabled debug apdu. 2022-08-30 16:57:12 +02:00
Pol Henarejos
b42e2b5493 Fix processing apdu. 2022-08-30 16:57:01 +02:00
Pol Henarejos
b75e5a6619 Not used anymore.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-30 13:22:21 +02:00
Pol Henarejos
40288a85f1 It's a major reorganization.
In order to add FIDO2 support, we need to reorganize some USB/CCID calls to specific area (named driver).
Thus, pico-hsm-sdk has two drivers:
- CCID driver implements APDU over USB/CCID ISO-7816 standard procedures.
- HID driver implements APDU over HID.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-30 02:00:11 +02:00
Pol Henarejos
2236501d20 Upgrading pico-ccid to version 2.2 2022-08-29 11:31:48 +02:00
Pol Henarejos
61536fa41a Adding extern to random_gen()
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-25 13:37:34 +02:00
Pol Henarejos
8e5d33c4ba Removing trailing spaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-19 01:44:03 +02:00
Pol Henarejos
33b33fdbba neug_get() does not have any argument.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-18 23:54:10 +02:00
Pol Henarejos
7738c1902e Added permanent memory region to store data that remains persistent even after an initialization. To delete it, the device must be fully wiped.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-18 19:48:13 +02:00
Pol Henarejos
2df878232b File new should return file_t pointer if it exists in the file table.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-08-18 11:57:01 +02:00
Pol Henarejos
be86197b0b Added macro to disable APDU debug.
It will speed up the device notably.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-14 19:12:17 +02:00
Pol Henarejos
d1b52d9521 PUK AUT may return 0x9001.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-12 18:07:13 +02:00
Pol Henarejos
3397f25bf0 Simply generic_hash()
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-10 16:37:06 +02:00
Pol Henarejos
9ea71fb45b Fix DEBUG_PAYLOAD().
It might overlap variables.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-09 17:28:27 +02:00
Pol Henarejos
fe53f9a729 Another fix with RAPDU in C0.
A STATUS_SLOT may be sent in between of consecutive C0. Thus, RAPDU shall be reset on every answer, even if it is partial.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 02:18:32 +02:00
Pol Henarejos
f44658eb63 Fix preparing next RAPDU in C0 response. 2022-06-06 01:44:41 +02:00
Pol Henarejos
2b8c23f593 Upgrading to version 2.0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 00:11:24 +02:00
Pol Henarejos
9cfe762043 low_flash_available() should be called outside.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-03 20:11:14 +02:00
Pol Henarejos
07305e6fd7 Fix returning error message.
If return code is not 0x9000, RAPDU is cleared.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-03 16:04:31 +02:00
Pol Henarejos
8bdcfa1041 Replacing with asn1 tag len function.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-03 11:16:25 +02:00
Pol Henarejos
7249fb129b Using custom mbedtls configuration file.
We disable lots of unwanted algorithms and suites and we only keep those are used.
2022-06-01 12:57:24 +02:00
Pol Henarejos
199095c204 Moving some ASN1 procedures to a separate file. 2022-06-01 09:45:27 +02:00
Pol Henarejos
67efd73a96 Not used anymore.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-31 20:38:43 +02:00
Pol Henarejos
fa4ecf658f Implementing own functions for cvc manipulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-31 18:51:43 +02:00
Pol Henarejos
8d409023bf Fix Ne value for legacy apdu. 2022-05-31 00:04:46 +02:00
Pol Henarejos
950e276ee8 Adding asn1_find_tag() for searching for a tag in a asn1 string. 2022-05-30 23:31:17 +02:00
Pol Henarejos
ef52ae37d3 Reorganizing usb layer. 2022-05-30 12:20:42 +02:00
Pol Henarejos
58e9e67ee5 Fix with data and extended length. 2022-05-30 00:51:36 +02:00
Pol Henarejos
acde4c54d5 Fix timeout. 2022-05-30 00:14:44 +02:00
Pol Henarejos
46603fa390 If the he packet is multiple 64 bytes, we trunk it.
It is a weird bug that affects PHY of rp2040.
2022-05-29 03:34:22 +02:00
Pol Henarejos
8bb47e7979 Compilation fixes in debug mode 2022-05-29 03:33:40 +02:00
Pol Henarejos
e0bff38384 Moving again to TinyUSB 2022-05-29 01:52:44 +02:00
Pol Henarejos
152a2fa031 Fix warnings 2022-05-27 20:58:28 +02:00
Pol Henarejos
79878a76c2 More fixes 2022-05-27 09:04:08 +02:00
Pol Henarejos
da871e695e More and more fixes. 2022-05-27 00:36:44 +02:00
Pol Henarejos
d4b0978d50 More fixes 2022-05-26 14:15:16 +02:00
Pol Henarejos
77ce276b59 First attempt to run away from tinyUSB to our code.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-26 00:03:38 +02:00
Pol Henarejos
56453b60d6 Added fmd flag to wrap FCP to include later the FMD.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 23:30:01 +02:00
Pol Henarejos
bd178c86e4 Added check.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 20:52:31 +02:00
Pol Henarejos
cd6a2dd4b5 Fix for new meta data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 20:52:01 +02:00
Pol Henarejos
24502966ce Fix finding meta_data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 20:41:04 +02:00
Pol Henarejos
3431293d43 Optimized special case when new meta data length is the same.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 15:54:07 +02:00
Pol Henarejos
21f70601b4 Avoid unnecessary memcpy
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 15:20:59 +02:00
Pol Henarejos
c4e781103f Fix with write offsets.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 14:43:08 +02:00
Pol Henarejos
6c90ce3361 Add meta functions for manipulating meta data.
Added meta_add(), meta_delete() and meta_find().
It conveys this meta data throught tag A5 of FCP.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 14:42:54 +02:00
Pol Henarejos
1a58422cd8 flash_write_data_to_file() now accepts offset argument.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 14:28:30 +02:00
Pol Henarejos
5a30c7cbdc format_tlv_len() accepts NULL argument.
In that case, it returns the length of the length in bytes.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 14:27:49 +02:00
Pol Henarejos
5e2fc081f1 Added high level functions for reading file and returning file size.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 00:18:43 +02:00
Pol Henarejos
d19429cb84 Fix handling dynamic files.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-23 19:56:26 +02:00
Pol Henarejos
7ed4cb912e These fids are propertary.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-23 14:43:09 +02:00
Pol Henarejos
efb6c8d8cd Adding Life-cycle status to FCP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:49:30 +02:00
Pol Henarejos
f7d30d7f4d Adding FCP tag template. Some apps could require FMD tag.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:37:57 +02:00
Pol Henarejos
de39035d9f FCI name (tag 84) has 16 bytes max length.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:34:00 +02:00
Pol Henarejos
ae935d19f8 Fix sending FCI name tag.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:33:14 +02:00
Pol Henarejos
de04dd6121 Should be with this values.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-05 22:27:01 +02:00
Pol Henarejos
9c5250f6ca Adding timeout for press button of 15 secs.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-05 20:03:17 +02:00
Pol Henarejos
cddc3b2dec Adding name to FCP
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-20 14:13:43 +02:00
70 changed files with 11786 additions and 3096 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "mbedtls"]
path = mbedtls
url = https://github.com/ARMmbed/mbedtls
[submodule "tinycbor"]
path = tinycbor
url = https://github.com/intel/tinycbor.git

View File

@@ -1,70 +1,82 @@
#
# This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
#
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
# 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
#
# 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
# 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
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.16)
include(pico_sdk_import.cmake)
if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(USB_ITF_CCID 1)
#set(USB_ITF_HID 1)
include(pico_keys_sdk_import.cmake)
project(pico_keys_sdk)
else()
project(pico_ccid C CXX ASM)
if(ENABLE_EMULATION)
else()
include(pico_sdk_import.cmake)
endif()
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
project(pico_keys C CXX ASM)
pico_sdk_init()
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
add_executable(pico_ccid)
if(ENABLE_EMULATION)
else()
pico_sdk_init()
endif()
if (NOT DEFINED USB_VID)
set(USB_VID 0xFEFF)
if (NOT DEFINED __FOR_CI)
set(__FOR_CI 0)
endif()
if (__FOR_CI)
add_definitions(-D__FOR_CI)
endif()
set(USB_ITF_CCID 1)
set(USB_ITF_HID 1)
include(pico_keys_sdk_import.cmake)
add_executable(pico_keys_sdk_exe)
target_compile_options(pico_keys_sdk_exe PUBLIC
-Wall
-Werror
)
if(ENABLE_EMULATION)
target_compile_options(pico_keys_sdk_exe PUBLIC
-fdata-sections
-ffunction-sections
)
if(APPLE)
target_link_options(pico_keys_sdk_exe PUBLIC
-Wl,-dead_strip
)
else()
target_link_options(pico_keys_sdk_exe PUBLIC
-Wl,--gc-sections
)
endif (APPLE)
else()
pico_add_extra_outputs(pico_keys_sdk_exe)
target_link_libraries(pico_keys_sdk_exe PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
endif()
add_definitions(-DUSB_VID=${USB_VID})
if (NOT DEFINED USB_PID)
set(USB_PID 0xFCFD)
endif()
add_definitions(-DUSB_PID=${USB_PID})
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/ctx.c
PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\""
)
target_sources(pico_ccid PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/ccid/ccid2040.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/src/ccid/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/ccid/crypto_utils.c
)
target_include_directories(pico_ccid PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/ccid
${CMAKE_CURRENT_LIST_DIR}/src/rng
${CMAKE_CURRENT_LIST_DIR}/src/usb
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
)
pico_add_extra_outputs(pico_ccid)
#target_compile_definitions(pico_ccid PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
target_link_libraries(pico_ccid PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)

44
cmake/dict.cmake Normal file
View File

@@ -0,0 +1,44 @@
function(dict command dict )
if(command STREQUAL SET)
set(arg_key ${ARGV2})
set(arg_value ${ARGV3})
dict(_IDX ${dict} "${arg_key}" idx)
if(NOT idx STREQUAL -1)
list(REMOVE_AT ${dict} ${idx})
endif()
list(APPEND ${dict} "${arg_key}=${arg_value}")
set(${dict} "${${dict}}" PARENT_SCOPE)
elseif(command STREQUAL GET)
set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3})
dict(_IDX ${dict} "${arg_key}" idx)
if(idx STREQUAL -1)
message(FATAL_ERROR "No key \"${arg_key}\" in dictionary")
endif()
list(GET ${dict} ${idx} kv)
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
set(${arg_outvar} "${value}" PARENT_SCOPE)
elseif(command STREQUAL _IDX)
set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3})
set(idx 0)
foreach(kv IN LISTS ${dict})
string(REGEX REPLACE "^([^=]+)=.*" "\\1" key "${kv}")
if(arg_key STREQUAL key)
set(${arg_outvar} "${idx}" PARENT_SCOPE)
return()
endif()
math(EXPR idx ${idx}+1)
endforeach()
set(${arg_outvar} "-1" PARENT_SCOPE)
else()
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
endif()
endfunction()

49
cmake/version.cmake Normal file
View File

@@ -0,0 +1,49 @@
macro(HEXCHAR2DEC VAR VAL)
if(${VAL} MATCHES "[0-9]")
SET(${VAR} ${VAL})
elseif(${VAL} MATCHES "[aA]")
SET(${VAR} 10)
elseif(${VAL} MATCHES "[bB]")
SET(${VAR} 11)
elseif(${VAL} MATCHES "[cC]")
SET(${VAR} 12)
elseif(${VAL} MATCHES "[dD]")
SET(${VAR} 13)
elseif(${VAL} MATCHES "[eE]")
SET(${VAR} 14)
elseif(${VAL} MATCHES "[fF]")
SET(${VAR} 15)
else()
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
endif()
endmacro(HEXCHAR2DEC)
macro(HEX2DEC VAR VAL)
SET(CURINDEX 0)
STRING(LENGTH "${VAL}" CURLENGTH)
SET(${VAR} 0)
while(CURINDEX LESS CURLENGTH)
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
HEXCHAR2DEC(CHAR ${CHAR})
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
MATH(EXPR CURINDEX "${CURINDEX}+1")
endwhile()
endmacro(HEX2DEC)
macro(SET_VERSION MAJOR MINOR FILE)
file(READ ${FILE} ver)
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
string(CONCAT ver_minor ${CMAKE_MATCH_3}${CMAKE_MATCH_4})
HEX2DEC(ver_major ${ver_major})
HEX2DEC(ver_minor ${ver_minor})
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
if(NOT ENABLE_EMULATION AND NOT ESP_PLATFORM)
pico_set_binary_version(${CMAKE_PROJECT_NAME} MAJOR ${ver_major} MINOR ${ver_minor})
endif()
SET(${MAJOR} ${ver_major})
SET(${MINOR} ${ver_minor})
endmacro(SET_VERSION)

7
config/esp32/partitions.csv Executable file
View File

@@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M,
part0, 0x40, 0x1, 0x200000, 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000
4 phy_init, data, phy, 0xf000, 0x1000
5 factory, app, factory, 0x10000, 1M,
6 part0, 0x40, 0x1, 0x200000, 1M,

3590
config/mbedtls_config.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,288 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "common.h"
#include "mbedtls/sha256.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "pico/sha256.h"
#define SHA256_BLOCK_SIZE 64
static const uint32_t K[] = {
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
};
#define SHR(x, n) (((x) & 0xFFFFFFFF) >> (n))
#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define R(t) \
( \
local.W[t] = S1(local.W[(t) - 2]) + local.W[(t) - 7] + \
S0(local.W[(t) - 15]) + local.W[(t) - 16] \
)
#define P(a, b, c, d, e, f, g, h, x, K) \
do \
{ \
local.temp1 = (h) + S3(e) + F1((e), (f), (g)) + (K) + (x); \
local.temp2 = S2(a) + F0((a), (b), (c)); \
(d) += local.temp1; (h) = local.temp1 + local.temp2; \
} while (0)
void mbedtls_sha256_init(mbedtls_sha256_context *ctx) {
memset(ctx, 0, sizeof(mbedtls_sha256_context));
}
void mbedtls_sha256_free(mbedtls_sha256_context *ctx) {
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha256_context));
}
int mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224) {
ctx->is224 = is224;
if (is224 == 1) {
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
else {
return pico_sha256_start_blocking(&ctx->pico_state, SHA256_BIG_ENDIAN, true);
}
return 0;
}
static int mbedtls_internal_sha256_process_c(mbedtls_sha256_context *ctx, const unsigned char data[SHA256_BLOCK_SIZE]) {
struct {
uint32_t temp1, temp2, W[64];
uint32_t A[8];
} local;
unsigned int i;
for (i = 0; i < 8; i++) {
local.A[i] = ctx->state[i];
}
for (i = 0; i < 16; i++) {
local.W[i] = MBEDTLS_GET_UINT32_BE(data, 4 * i);
}
for (i = 0; i < 16; i += 8) {
P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0]);
P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1]);
P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2]);
P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3]);
P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4]);
P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5]);
P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6]);
P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
local.A[5], local.A[6], local.A[7], R(i+0), K[i+0]);
P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
local.A[4], local.A[5], local.A[6], R(i+1), K[i+1]);
P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
local.A[3], local.A[4], local.A[5], R(i+2), K[i+2]);
P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
local.A[2], local.A[3], local.A[4], R(i+3), K[i+3]);
P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
local.A[1], local.A[2], local.A[3], R(i+4), K[i+4]);
P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
local.A[0], local.A[1], local.A[2], R(i+5), K[i+5]);
P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
local.A[7], local.A[0], local.A[1], R(i+6), K[i+6]);
P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
local.A[6], local.A[7], local.A[0], R(i+7), K[i+7]);
}
for (i = 0; i < 8; i++) {
ctx->state[i] += local.A[i];
}
/* Zeroise buffers and variables to clear sensitive data from memory. */
mbedtls_platform_zeroize(&local, sizeof(local));
return 0;
}
static size_t mbedtls_internal_sha256_process_many_c(mbedtls_sha256_context *ctx, const uint8_t *data, size_t len) {
size_t processed = 0;
while (len >= SHA256_BLOCK_SIZE) {
if (mbedtls_internal_sha256_process_c(ctx, data) != 0) {
return 0;
}
data += SHA256_BLOCK_SIZE;
len -= SHA256_BLOCK_SIZE;
processed += SHA256_BLOCK_SIZE;
}
return processed;
}
int mbedtls_sha256_update(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) {
if (ctx->is224 == 1) {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
if (ilen == 0) {
return 0;
}
left = ctx->total[0] & 0x3F;
fill = SHA256_BLOCK_SIZE - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t) ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *) (ctx->buffer + left), input, fill);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
return ret;
}
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= SHA256_BLOCK_SIZE) {
size_t processed = mbedtls_internal_sha256_process_many_c(ctx, input, ilen);
if (processed < SHA256_BLOCK_SIZE) {
return MBEDTLS_ERR_ERROR_GENERIC_ERROR;
}
input += processed;
ilen -= processed;
}
if (ilen > 0) {
memcpy((void *) (ctx->buffer + left), input, ilen);
}
}
else {
pico_sha256_update_blocking(&ctx->pico_state, (const uint8_t *)input, ilen);
}
return 0;
}
int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
if (ctx->is224) {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if (used <= 56) {
memset(ctx->buffer + used, 0, 56 - used);
} else {
memset(ctx->buffer + used, 0, SHA256_BLOCK_SIZE - used);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
goto exit;
}
memset(ctx->buffer, 0, 56);
}
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
MBEDTLS_PUT_UINT32_BE(high, ctx->buffer, 56);
MBEDTLS_PUT_UINT32_BE(low, ctx->buffer, 60);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
goto exit;
}
MBEDTLS_PUT_UINT32_BE(ctx->state[0], output, 0);
MBEDTLS_PUT_UINT32_BE(ctx->state[1], output, 4);
MBEDTLS_PUT_UINT32_BE(ctx->state[2], output, 8);
MBEDTLS_PUT_UINT32_BE(ctx->state[3], output, 12);
MBEDTLS_PUT_UINT32_BE(ctx->state[4], output, 16);
MBEDTLS_PUT_UINT32_BE(ctx->state[5], output, 20);
MBEDTLS_PUT_UINT32_BE(ctx->state[6], output, 24);
ret = 0;
exit:
mbedtls_sha256_free(ctx);
return ret;
}
else {
sha256_result_t result;
pico_sha256_finish(&ctx->pico_state, &result);
memcpy(output, result.bytes, 32);
}
return 0;
}

View File

@@ -0,0 +1,36 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _SHA256_ALT_H_
#define _SHA256_ALT_H_
#include "pico_keys.h"
#include "pico/sha256.h"
typedef struct mbedtls_sha256_context {
pico_sha256_state_t MBEDTLS_PRIVATE(pico_state);
#if defined(MBEDTLS_SHA224_C)
unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< The data block being processed. */
uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< The number of Bytes processed. */
uint32_t MBEDTLS_PRIVATE(state)[8]; /*!< The intermediate digest state. */
int MBEDTLS_PRIVATE(is224); /*!< Determines which function to use:
0: Use SHA-256, or 1: Use SHA-224. */
#endif
}
mbedtls_sha256_context;
#endif /* _SHA256_ALT_H_ */

40
config/rp2350/pt.json Normal file
View File

@@ -0,0 +1,40 @@
{
"version": [1, 0],
"unpartitioned": {
"families": ["absolute"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
"partitions": [
{
"name": "Pico Keys Firmware",
"id": 0,
"start": 0,
"size": "1024K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
{
"name": "Pico Keys Data",
"id": 1,
"start": "2048K",
"size": "2048K",
"families": ["data"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
},
"link": ["owner", 0],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
}
]
}

View File

@@ -0,0 +1,42 @@
{
"boot_flags1": {
"key_valid": 1
},
"bootkey0": [
225,
209,
107,
167,
100,
171,
215,
18,
212,
239,
110,
62,
221,
116,
78,
213,
99,
140,
38,
11,
119,
28,
249,
129,
81,
17,
11,
175,
172,
155,
200,
113
],
"crit1": {
"secure_boot_enable": 1
}
}

Submodule mbedtls updated: d65aeb3734...107ea89daa

436
pico_keys_sdk_import.cmake Normal file
View File

@@ -0,0 +1,436 @@
#
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
# 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(pico-keys-sdk/cmake/version.cmake)
option(VIDPID "Set specific VID/PID from a known platform {NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG}" "None")
message(STATUS "VIDPID:\t\t\t '${VIDPID}'")
if(VIDPID STREQUAL "NitroHSM")
set(USB_VID 0x20A0)
set(USB_PID 0x4230)
elseif(VIDPID STREQUAL "NitroFIDO2")
set(USB_VID 0x20A0)
set(USB_PID 0x42B1)
elseif(VIDPID STREQUAL "NitroStart")
set(USB_VID 0x20A0)
set(USB_PID 0x4211)
elseif(VIDPID STREQUAL "NitroPro")
set(USB_VID 0x20A0)
set(USB_PID 0x4108)
elseif(VIDPID STREQUAL "Nitro3")
set(USB_VID 0x20A0)
set(USB_PID 0x42B2)
elseif(VIDPID STREQUAL "Yubikey5")
set(USB_VID 0x1050)
set(USB_PID 0x0407)
elseif(VIDPID STREQUAL "YubikeyNeo")
set(USB_VID 0x1050)
set(USB_PID 0x0116)
elseif(VIDPID STREQUAL "YubiHSM")
set(USB_VID 0x1050)
set(USB_PID 0x0030)
elseif(VIDPID STREQUAL "Gnuk")
set(USB_VID 0x234B)
set(USB_PID 0x0000)
elseif(VIDPID STREQUAL "GnuPG")
set(USB_VID 0x1209)
set(USB_PID 0x2440)
endif()
if(ESP_PLATFORM)
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_VID)
set(USB_VID CONFIG_TINYUSB_DESC_CUSTOM_VID)
endif()
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_PID)
set(USB_PID CONFIG_TINYUSB_DESC_CUSTOM_PID)
endif()
endif()
if(NOT DEFINED USB_VID)
set(USB_VID 0xFEFF)
endif()
add_definitions(-DUSB_VID=${USB_VID})
if(NOT DEFINED USB_PID)
set(USB_PID 0xFCFD)
endif()
add_definitions(-DUSB_PID=${USB_PID})
if(NOT DEFINED DEBUG_APDU)
set(DEBUG_APDU 0)
endif()
if(NOT DEFINED ENABLE_EMULATION)
set(ENABLE_EMULATION 0)
endif()
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
if(ENABLE_DELAYED_BOOT)
add_definitions(-DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
message(STATUS "Delayed boot:\t\t enabled")
else()
message(STATUS "Delayed boot:\t\t disabled")
endif(ENABLE_DELAYED_BOOT)
if(USB_ITF_HID)
add_definitions(-DUSB_ITF_HID=1)
message(STATUS "USB HID Interface:\t\t enabled")
endif(USB_ITF_HID)
if(USB_ITF_CCID)
add_definitions(-DUSB_ITF_CCID=1)
message(STATUS "USB CCID Interface:\t\t enabled")
if(USB_ITF_WCID)
add_definitions(-DUSB_ITF_WCID=1)
message(STATUS "USB WebCCID Interface:\t enabled")
endif(USB_ITF_WCID)
endif(USB_ITF_CCID)
add_definitions(-DDEBUG_APDU=${DEBUG_APDU})
if(NOT ESP_PLATFORM)
add_definitions(-DMBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
else()
add_definitions(-DCFG_TUSB_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/src/usb/tusb_config.h")
endif()
message(STATUS "USB VID/PID:\t\t\t ${USB_VID}:${USB_PID}")
if(NOT ESP_PLATFORM)
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
if(ENABLE_EDDSA)
message(STATUS "EdDSA support:\t\t enabled")
else()
message(STATUS "EdDSA support:\t\t disabled")
endif(ENABLE_EDDSA)
set(MBEDTLS_PATH "${CMAKE_SOURCE_DIR}/pico-keys-sdk/mbedtls")
if(ENABLE_EDDSA)
set(MBEDTLS_ORIGIN "https://github.com/polhenarejos/mbedtls.git")
set(MBEDTLS_REF "mbedtls-3.6-eddsa")
add_definitions(-DMBEDTLS_ECP_DP_ED25519_ENABLED=1 -DMBEDTLS_ECP_DP_ED448_ENABLED=1 -DMBEDTLS_EDDSA_C=1 -DMBEDTLS_SHA3_C=1)
else()
set(MBEDTLS_ORIGIN "https://github.com/Mbed-TLS/mbedtls.git")
set(MBEDTLS_REF "v3.6.3")
endif()
execute_process(
COMMAND git config --global --add safe.directory ${MBEDTLS_PATH}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} submodule update --init --recursive pico-keys-sdk
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} remote get-url origin
OUTPUT_VARIABLE CURRENT_ORIGIN
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT "${CURRENT_ORIGIN}" STREQUAL "${MBEDTLS_ORIGIN}")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} remote set-url origin ${MBEDTLS_ORIGIN}
OUTPUT_QUIET ERROR_QUIET
)
endif()
execute_process(
COMMAND git -C ${MBEDTLS_PATH} rev-parse --verify ${MBEDTLS_REF}
OUTPUT_VARIABLE CURRENT_REF
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE REF_EXISTS
)
if(NOT REF_EXISTS EQUAL 0 OR NOT CURRENT_REF STREQUAL "${MBEDTLS_REF}")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} fetch origin +refs/heads/*:refs/remotes/origin/* --tags --force
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND rm -rf ${MBEDTLS_PATH}/framework
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
if(ENABLE_EDDSA)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout -B ${MBEDTLS_REF} --track origin/${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
else()
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout ${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
endif()
endif()
endif(NOT ESP_PLATFORM)
set(MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum_core.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkcs5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
)
if (ENABLE_EDDSA)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/eddsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha3.c
)
endif()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/otp.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_cyw43.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pimoroni.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_ws2812.c
)
if(ESP_PLATFORM)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c)
endif()
## mbedTLS reports an stringop overflow for cmac.c
if(NOT ENABLE_EMULATION AND NOT APPLE)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
PROPERTIES
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
)
endif()
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/src/usb
${CMAKE_CURRENT_LIST_DIR}/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/rng
${CMAKE_CURRENT_LIST_DIR}/src/led
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
)
if(USB_ITF_HID)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
)
set(CBOR_SOURCES
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborencoder.c
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser.c
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser_dup_string.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src
)
endif()
set(LIBRARIES
pico_stdlib
pico_multicore
pico_rand
pico_aon_timer
hardware_flash
pico_unique_id
tinyusb_device
tinyusb_board
hardware_pio
)
set(IS_CYW43 0)
if (NOT ENABLE_EMULATION AND NOT ESP_PLATFORM)
file(READ ${PICO_SDK_PATH}/src/boards/include/boards/${PICO_BOARD}.h content)
string(REGEX MATCHALL "CYW43_WL_GPIO_LED_PIN" _ ${content})
if (CMAKE_MATCH_0)
message(STATUS "Found cyw43 LED:\t\t true")
set(LIBRARIES ${LIBRARIES} pico_cyw43_arch_none)
set(IS_CYW43 1)
endif()
endif()
function(add_impl_library target)
add_library(${target} INTERFACE)
string(TOUPPER ${target} TARGET_UPPER)
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
endfunction()
if(USB_ITF_HID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
)
endif()
if(USB_ITF_CCID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
)
endif()
add_definitions("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
if(ENABLE_EMULATION)
if(APPLE)
add_definitions("-Wno-deprecated-declarations")
elseif(MSVC)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
)
endif()
add_definitions(-DENABLE_EMULATION)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aesni.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
)
else()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
)
endif()
set(EXTERNAL_SOURCES ${CBOR_SOURCES})
if(NOT ESP_PLATFORM)
set(EXTERNAL_SOURCES ${EXTERNAL_SOURCES} ${MBEDTLS_SOURCES})
endif()
if(MSVC)
set(
CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -wd4820 -wd4255 -wd5045 -wd4706 -wd4061 -wd5105"
)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS
__STDC_WANT_SECURE_LIB__=0
_WIN32_WINNT_WIN10_TH2=0
_WIN32_WINNT_WIN10_RS1=0
_WIN32_WINNT_WIN10_RS2=0
_WIN32_WINNT_WIN10_RS3=0
_WIN32_WINNT_WIN10_RS4=0
_WIN32_WINNT_WIN10_RS5=0
_STRALIGN_USE_SECURE_CRT=0
NTDDI_WIN10_CU=0)
set_source_files_properties(
${EXTERNAL_SOURCES}
PROPERTIES
COMPILE_FLAGS " -W3 -wd4242 -wd4065"
)
endif()
if(PICO_RP2350)
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
if (NOT IS_CYW43)
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
endif()
if (SECURE_BOOT_PKEY)
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
pico_hash_binary(${CMAKE_PROJECT_NAME})
endif()
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
)
set(LIBRARIES ${LIBRARIES} pico_sha256)
endif()
set(INTERNAL_SOURCES ${PICO_KEYS_SOURCES})
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${EXTERNAL_SOURCES})
if(NOT TARGET pico_keys_sdk)
if(ENABLE_EMULATION OR ESP_PLATFORM)
add_impl_library(pico_keys_sdk)
else()
pico_add_library(pico_keys_sdk)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
endif()
target_sources(pico_keys_sdk INTERFACE ${PICO_KEYS_SOURCES})
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
endif()

14
sdkconfig.defaults Executable file
View File

@@ -0,0 +1,14 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="config/esp32/partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="config/esp32/partitions.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_MODE_PERF=y
COMPILER_OPTIMIZATION="Performance"

5
src/CMakeLists.txt Executable file
View File

@@ -0,0 +1,5 @@
idf_component_register(
SRCS ${PICO_KEYS_SOURCES}
INCLUDE_DIRS . fs rng usb led ../tinycbor/src
REQUIRES bootloader_support esp_partition esp_tinyusb efuse mbedtls
)

254
src/apdu.c Normal file
View File

@@ -0,0 +1,254 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "apdu.h"
#include "pico_keys.h"
#include "usb.h"
#include <stdio.h>
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#endif
#ifdef ENABLE_EMULATION
#include "emulation.h"
#endif
uint8_t *rdata_gr = NULL;
uint16_t rdata_bk = 0x0;
extern uint32_t timeout;
bool is_chaining = false;
uint8_t chain_buf[4096];
uint8_t *chain_ptr = NULL;
int process_apdu() {
led_set_mode(MODE_PROCESSING);
if (CLA(apdu) & 0x10) {
if (!is_chaining) {
chain_ptr = chain_buf;
}
if (chain_ptr - chain_buf + apdu.nc >= sizeof(chain_buf)) {
return SW_CLA_NOT_SUPPORTED();
}
memcpy(chain_ptr, apdu.data, apdu.nc);
chain_ptr += apdu.nc;
is_chaining = true;
return SW_OK();
}
else {
if (is_chaining) {
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
apdu.nc += (uint16_t)(chain_ptr - chain_buf);
is_chaining = false;
}
}
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
if (select_app(apdu.data, apdu.nc) == PICOKEY_OK) {
return SW_OK();
}
return SW_FILE_NOT_FOUND();
}
if (current_app && current_app->process_apdu) {
return current_app->process_apdu();
}
return SW_FILE_NOT_FOUND();
}
uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
apdu.header = (uint8_t *) buffer;
apdu.nc = apdu.ne = 0;
if (buffer_size == 4) {
apdu.nc = apdu.ne = 0;
if (apdu.ne == 0) {
apdu.ne = 256;
}
}
else if (buffer_size == 5) {
apdu.nc = 0;
apdu.ne = apdu.header[4];
if (apdu.ne == 0) {
apdu.ne = 256;
}
}
else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
if (buffer_size == 7) {
apdu.ne = get_uint16_t_be(apdu.header + 5);
if (apdu.ne == 0) {
apdu.ne = 65536;
}
}
else {
apdu.ne = 0;
apdu.nc = get_uint16_t_be(apdu.header + 5);
apdu.data = apdu.header + 7;
if (apdu.nc + 7 + 2 == buffer_size) {
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2);
if (apdu.ne == 0) {
apdu.ne = 65536;
}
}
}
}
else {
apdu.nc = apdu.header[4];
apdu.data = apdu.header + 5;
apdu.ne = 0;
if (apdu.nc + 5 + 1 == buffer_size) {
apdu.ne = apdu.header[buffer_size - 1];
if (apdu.ne == 0) {
apdu.ne = 256;
}
}
}
//printf("apdu.nc %ld, apdu.ne %ld\n",apdu.nc,apdu.ne);
if (apdu.header[1] == 0xc0) {
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk);
timeout_stop();
*(uint16_t *) rdata_gr = rdata_bk;
if (apdu.rlen <= apdu.ne) {
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
}
#endif
#else
driver_exec_finished_cont_emul(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
#endif
//Prepare next RAPDU
apdu.sw = 0;
apdu.rlen = 0;
rdata_gr = apdu.rdata;
}
else {
rdata_gr += apdu.ne;
rdata_bk = *(uint16_t *) rdata_gr;
rdata_gr[0] = 0x61;
if (apdu.rlen - apdu.ne >= 256) {
rdata_gr[1] = 0;
}
else {
rdata_gr[1] = (uint8_t)(apdu.rlen - apdu.ne);
}
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
}
#endif
#else
driver_exec_finished_cont_emul(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
#endif
apdu.rlen -= (uint16_t)apdu.ne;
}
}
else {
apdu.sw = 0;
apdu.rlen = 0;
rdata_gr = apdu.rdata;
return 1;
}
return 0;
}
uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
apdu.sw = make_uint16_t_be(sw1, sw2);
if (sw1 != 0x90) {
res_APDU_size = 0;
}
return make_uint16_t_be(sw1, sw2);
}
void apdu_thread(void) {
card_init_core1();
while (1) {
uint32_t m = 0;
queue_remove_blocking(&usb_to_card_q, &m);
uint32_t flag = m + 1;
queue_add_blocking(&card_to_usb_q, &flag);
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
set_res_sw(0x6f, 0x00);
goto done;
}
else if (m == EV_EXIT) {
break;
}
process_apdu();
done: ;
apdu_finish();
finished_data_size = apdu_next();
flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag);
#ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10));
#endif
}
//printf("EXIT !!!!!!\n");
if (current_app && current_app->unload) {
current_app->unload();
current_app = NULL;
}
#ifdef ESP_PLATFORM
vTaskDelete(NULL);
#endif
}
void apdu_finish() {
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen);
// timeout_stop();
#ifndef ENABLE_EMULATION
/* It was fixed in the USB handling. Keep it just in case */
//if ((apdu.rlen + 2 + 10) % 64 == 0) { // FIX for strange behaviour with PSCS and multiple of 64
// apdu.ne = apdu.rlen - 2;
//}
#endif
}
uint16_t apdu_next() {
if (apdu.sw != 0) {
if (apdu.rlen <= apdu.ne) {
return apdu.rlen + 2;
}
else {
rdata_gr = apdu.rdata + apdu.ne;
rdata_bk = *(uint16_t *) rdata_gr;
rdata_gr[0] = 0x61;
if (apdu.rlen - apdu.ne >= 256) {
rdata_gr[1] = 0;
}
else {
rdata_gr[1] = (uint8_t)(apdu.rlen - apdu.ne);
}
apdu.rlen -= (uint16_t)apdu.ne;
}
return (uint16_t)(apdu.ne + 2);
}
return 0;
}

78
src/apdu.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _APDU_H_
#define _APDU_H_
#include <stdlib.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#endif
#include "compat.h"
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
int (*select_aid)(struct app *, uint8_t);
int (*unload)();
} app_t;
extern bool app_exists(const uint8_t *aid, size_t aid_len);
extern int register_app(int (*)(app_t *, uint8_t), const uint8_t *);
extern int select_app(const uint8_t *aid, size_t aid_len);
typedef struct cmd {
uint8_t ins;
int (*cmd_handler)();
} cmd_t;
extern uint8_t num_apps;
extern app_t apps[8];
extern app_t *current_app;
PACK(struct apdu {
uint8_t *header;
uint32_t nc;
uint32_t ne;
uint8_t *data;
uint16_t sw;
uint8_t *rdata;
uint16_t rlen;
});
#define CLA(a) a.header[0]
#define INS(a) a.header[1]
#define P1(a) a.header[2]
#define P2(a) a.header[3]
#define res_APDU (apdu.rdata)
#define res_APDU_size (apdu.rlen)
extern struct apdu apdu;
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
extern int process_apdu();
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
extern void apdu_finish();
extern uint16_t apdu_next();
extern void apdu_thread();
#endif

140
src/asn1.c Normal file
View File

@@ -0,0 +1,140 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#include "asn1.h"
int asn1_ctx_init(uint8_t *data, uint16_t len, asn1_ctx_t *ctx) {
if (!ctx) {
return PICOKEY_ERR_NULL_PARAM;
}
ctx->data = data;
ctx->len = len;
return PICOKEY_OK;
}
int asn1_ctx_clear(asn1_ctx_t *ctx) {
ctx->data = NULL;
ctx->len = 0;
return PICOKEY_OK;
}
uint16_t asn1_len(asn1_ctx_t *ctx) {
if (ctx->data && ctx->len > 0) {
return ctx->len;
}
return 0;
}
uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
uint32_t d = ctx->data[0];
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
d <<= 8;
d |= ctx->data[lt];
}
return d;
}
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
if (tag > 0x00ff) {
return ret + 1;
}
return ret;
}
uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
if (len < 128) {
if (out) {
*out = (uint8_t)len;
}
return 1;
}
else if (len < 256) {
if (out) {
*out++ = 0x81;
*out++ = (uint8_t)len;
}
return 2;
}
if (out) {
*out++ = 0x82;
put_uint16_t_be(len, out);
}
return 3;
}
int walk_tlv(const asn1_ctx_t *ctxi,
uint8_t **p,
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data) {
if (!p) {
return 0;
}
if (!*p) {
*p = (uint8_t *) ctxi->data;
}
if (*p - ctxi->data >= ctxi->len) {
return 0;
}
uint16_t tg = 0x0;
uint16_t tgl = 0;
tg = *(*p)++;
if ((tg & 0x1f) == 0x1f) {
tg <<= 8;
tg |= *(*p)++;
}
tgl = *(*p)++;
if (tgl == 0x82) {
tgl = *(*p)++ << 8;
tgl |= *(*p)++;
}
else if (tgl == 0x81) {
tgl = *(*p)++;
}
if (tag) {
*tag = tg;
}
if (tag_len) {
*tag_len = tgl;
}
if (data) {
*data = *p;
}
*p = *p + tgl;
return 1;
}
bool asn1_find_tag(const asn1_ctx_t *ctxi,
uint16_t itag,
asn1_ctx_t *ctxo) {
uint16_t tag = 0x0;
uint8_t *p = NULL;
uint8_t *tdata = NULL;
uint16_t tlen = 0;
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
if (itag == tag) {
if (ctxo != NULL) {
ctxo->data = tdata;
ctxo->len = tlen;
}
return true;
}
}
return false;
}

50
src/asn1.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _ASN1_H_
#define _ASN1_H_
#include <stdlib.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#else
#include <stdint.h>
#include <stdbool.h>
#endif
typedef struct asn1_ctx {
uint8_t *data;
uint16_t len;
} asn1_ctx_t;
extern int asn1_ctx_init(uint8_t *, uint16_t, asn1_ctx_t *);
extern int asn1_ctx_clear(asn1_ctx_t *ctx);
extern uint16_t asn1_len(asn1_ctx_t *ctx);
extern uint32_t asn1_get_uint(asn1_ctx_t *ctx);
extern int walk_tlv(const asn1_ctx_t *ctxi,
uint8_t **p,
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data);
extern uint8_t format_tlv_len(uint16_t len, uint8_t *out);
extern bool asn1_find_tag(const asn1_ctx_t *ctxi,
uint16_t itag,
asn1_ctx_t *ctxo);
extern uint16_t asn1_len_tag(uint16_t tag, uint16_t len);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,255 +0,0 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
* 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 _CCID2040_H_
#define _CCID2040_H_
#include "ccid.h"
#include "tusb.h"
#include "file.h"
#include "pico/unique_id.h"
#include "pico/util/queue.h"
#define USB_REQ_CCID 0xA1
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
struct app* (*select_aid)();
int (*unload)();
} app_t;
extern int register_app(app_t * (*)());
extern const uint8_t historical_bytes[];
#define DEBUG_PAYLOAD(p,s) { \
printf("Payload %s (%d bytes):\r\n", #p,s);\
for (int i = 0; i < s; i += 16) {\
printf("%07Xh : ",i+p);\
for (int j = 0; j < 16; j++) {\
if (j < s-i) printf("%02X ",(p)[i+j]);\
else printf(" ");\
if (j == 7) printf(" ");\
} printf(": "); \
for (int j = 0; j < MIN(16,s-i); j++) {\
printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\
if (j == 7) printf(" ");\
}\
printf("\r\n");\
} printf("\r\n"); \
}
struct apdu {
uint8_t seq;
/* command APDU */
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
uint8_t *cmd_apdu_data;
size_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
size_t expected_res_size; /* Ne, calculated by Le field */
/* response APDU */
uint16_t sw;
uint16_t res_apdu_data_len;
uint8_t *res_apdu_data;
};
#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
#define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
#define CCID_MSG_HEADER_SIZE 10
#define USB_LL_BUF_SIZE 64
/* CCID thread */
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
#define EV_PRESS_BUTTON 32
/* SC HSM thread */
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_EXIT 8
#define EV_BUTTON_PRESSED 16
//Variables set by core1
extern queue_t *ccid_comm;
extern queue_t *card_comm;
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
#define CLA(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
#define P1(a) a.cmd_apdu_head[2]
#define P2(a) a.cmd_apdu_head[3]
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
extern struct apdu apdu;
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
static inline const uint16_t make_uint16_t(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline const uint16_t get_uint16_t(const uint8_t *b, uint16_t offset) {
return make_uint16_t(b[offset], b[offset+1]);
}
static inline const void put_uint16_t(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
}
extern const uint8_t *ccid_atr;
#ifdef DEBUG
void stdout_init (void);
#define DEBUG_MORE 1
/*
* Debug functions in debug.c
*/
void put_byte (uint8_t b);
void put_byte_with_no_nl (uint8_t b);
void put_short (uint16_t x);
void put_word (uint32_t x);
void put_int (uint32_t x);
void put_string (const char *s);
void put_binary (const char *s, int len);
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_WORD(w) put_word (w)
#define DEBUG_SHORT(h) put_short (h)
#define DEBUG_BYTE(b) put_byte (b)
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
#else
#define DEBUG_INFO(msg)
#define DEBUG_WORD(w)
#define DEBUG_SHORT(h)
#define DEBUG_BYTE(b)
#define DEBUG_BINARY(s,len)
#endif
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern pico_unique_board_id_t unique_id;
enum {
BLINK_NOT_MOUNTED = (250 << 16) | 250,
BLINK_MOUNTED = (250 << 16) | 250,
BLINK_SUSPENDED = (500 << 16) | 1000,
BLINK_PROCESSING = (50 << 16) | 50,
BLINK_ALWAYS_ON = UINT32_MAX,
BLINK_ALWAYS_OFF = 0
};
extern void led_set_blink(uint32_t mode);
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
#define SW_WARNING_CORRUPTED() set_res_sw (0x62, 0x81)
#define SW_WARNING_EOF() set_res_sw (0x62, 0x82)
#define SW_WARNING_EF_DEACTIVATED() set_res_sw (0x62, 0x83)
#define SW_WARNING_WRONG_FCI() set_res_sw (0x62, 0x84)
#define SW_WARNING_EF_TERMINATED() set_res_sw (0x62, 0x85)
#define SW_WARNING_NOINFO() set_res_sw (0x63, 0x00)
#define SW_WARNING_FILLUP() set_res_sw (0x63, 0x81)
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw (0x66, 0x00)
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define SW_WRONG_DATA() set_res_sw (0x67, 0x00)
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
#define SW_COMMAND_INCOMPATIBLE() set_res_sw (0x69, 0x81)
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83)
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw (0x69, 0x87)
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw (0x69, 0x88)
#define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99)
#define SW_INCORRECT_PARAMS() set_res_sw (0x6A, 0x80)
#define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81)
#define SW_FILE_NOT_FOUND() set_res_sw (0x6A, 0x82)
#define SW_RECORD_NOT_FOUND() set_res_sw (0x6A, 0x83)
#define SW_FILE_FULL() set_res_sw (0x6A, 0x84)
#define SW_WRONG_NE() set_res_sw (0x6A, 0x85)
#define SW_INCORRECT_P1P2() set_res_sw (0x6A, 0x86)
#define SW_WRONG_NC() set_res_sw (0x6A, 0x87)
#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88)
#define SW_FILE_EXISTS() set_res_sw (0x6A, 0x89)
#define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00)
#define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00)
#define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00)
#define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00)
#define SW_UNKNOWN() set_res_sw (0x6F, 0x00)
#define SW_OK() set_res_sw (0x90, 0x00)
#define CCID_OK 0
#define CCID_ERR_NO_MEMORY -1000
#define CCID_ERR_MEMORY_FATAL -1001
#define CCID_ERR_NULL_PARAM -1002
#define CCID_ERR_FILE_NOT_FOUND -1003
#define CCID_ERR_BLOCKED -1004
#define CCID_NO_LOGIN -1005
#define CCID_EXEC_ERROR -1006
#define CCID_WRONG_LENGTH -1007
#define CCID_WRONG_DATA -1008
#define CCID_WRONG_DKEK -1009
#define CCID_WRONG_SIGNATURE -1010
#define CCID_WRONG_PADDING -1011
#define CCID_VERIFICATION_FAILED -1012
extern int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint8_t *tag, size_t *tag_len, uint8_t **data);
extern int format_tlv_len(size_t len, uint8_t *out);
#endif

View File

@@ -1,146 +0,0 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
* 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 <pico/unique_id.h>
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "crypto_utils.h"
#include "ccid2040.h"
void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
uint8_t o1[32];
hash_multi(pin, len, o1);
for (int i = 0; i < sizeof(o1); i++)
o1[i] ^= pin[i%len];
hash_multi(o1, sizeof(o1), output);
}
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
int iters = 256;
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id));
while (iters > len)
{
mbedtls_sha256_update (&ctx, input, len);
iters -= len;
}
if (iters > 0) // remaining iterations
mbedtls_sha256_update (&ctx, input, iters);
mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_free (&ctx);
}
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update (&ctx, input, len);
mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_free (&ctx);
}
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
mbedtls_md_setup(&ctx, md_info, 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, input, len);
mbedtls_md_finish(&ctx, output);
mbedtls_md_free(&ctx);
}
int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv)
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0)
return CCID_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv)
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0)
return CCID_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
}
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
}
struct lv_data {
unsigned char *value;
uint8_t len;
};
struct ec_curve_mbed_id {
struct lv_data curve;
mbedtls_ecp_group_id id;
};
struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 },
{ { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 },
{ { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 },
{ { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 },
{ { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 },
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
};
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
return ec->id;
}
}
return MBEDTLS_ECP_DP_NONE;
}

View File

@@ -1,48 +0,0 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
* 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 _CRYPTO_UTILS_H_
#define _CRYPTO_UTILS_H_
#include "stdlib.h"
#include "pico/stdlib.h"
#include "mbedtls/ecp.h"
#include "mbedtls/md.h"
#define HSM_KEY_RSA 0x1
#define HSM_KEY_EC 0x10
#define HSM_KEY_AES 0x100
#define HSM_KEY_AES_128 0x300
#define HSM_KEY_AES_192 0x500
#define HSM_KEY_AES_256 0x900
#define HSM_AES_MODE_CBC 1
#define HSM_AES_MODE_CFB 2
#define IV_SIZE 16
extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]);
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output);
extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
#endif

View File

@@ -1,270 +0,0 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
* 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 "eac.h"
#include "crypto_utils.h"
#include "random.h"
#include "mbedtls/cmac.h"
static uint8_t nonce[8];
static uint8_t auth_token[8];
static uint8_t sm_kmac[16];
static uint8_t sm_kenc[16];
static MSE_protocol sm_protocol = MSE_NONE;
static mbedtls_mpi sm_mSSC;
static uint8_t sm_blocksize = 0;
static uint8_t sm_iv[16];
size_t sm_session_pin_len = 0;
uint8_t sm_session_pin[16];
bool is_secured_apdu() {
return (CLA(apdu) & 0xC);
}
void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) {
uint8_t *b = (uint8_t *)calloc(1, input_len+nonce_len+4);
if (input)
memcpy(b, input, input_len);
if (nonce)
memcpy(b+input_len, nonce, nonce_len);
b[input_len+nonce_len+3] = counter;
uint8_t digest[20];
generic_hash(MBEDTLS_MD_SHA1, b, input_len+nonce_len+4, digest);
memcpy(out, digest, 16);
free(b);
}
void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
memcpy(nonce, random_bytes_get(8), 8);
sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc);
sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac);
mbedtls_mpi_init(&sm_mSSC);
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
mbedtls_mpi_lset(&sm_mSSC, 0);
memset(sm_iv, 0, sizeof(sm_iv));
sm_session_pin_len = 0;
}
void sm_set_protocol(MSE_protocol proto) {
sm_protocol = proto;
if (proto == MSE_AES)
sm_blocksize = 16;
else if (proto == MSE_3DES)
sm_blocksize = 8;
}
MSE_protocol sm_get_protocol() {
return sm_protocol;
}
uint8_t *sm_get_nonce() {
return nonce;
}
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
}
int sm_unwrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0)
return CCID_OK;
int r = sm_verify();
if (r != CCID_OK)
return r;
int le = sm_get_le();
if (le >= 0)
apdu.expected_res_size = le;
uint8_t *body = NULL;
size_t body_size = 0;
bool is87 = false;
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
size_t tag_len = 0;
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x87 || tag == 0x85) {
body = tag_data;
body_size = tag_len;
if (tag == 0x87) {
is87 = true;
body_size--;
}
}
}
if (!body)
return CCID_WRONG_DATA;
if (is87 && *body++ != 0x1) {
return CCID_WRONG_PADDING;
}
sm_update_iv();
aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size);
memmove(apdu.cmd_apdu_data, body, body_size);
apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size);
DEBUG_PAYLOAD(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
return CCID_OK;
}
int sm_wrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0)
return CCID_OK;
uint8_t input[1024];
size_t input_len = 0;
memset(input, 0, sizeof(input));
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
mbedtls_mpi_copy(&sm_mSSC, &ssc);
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = 0x80;
memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize)));
res_APDU_size += (sm_blocksize - (res_APDU_size%sm_blocksize));
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
sm_update_iv();
aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, res_APDU, res_APDU_size);
memmove(res_APDU+1, res_APDU, res_APDU_size);
res_APDU[0] = 0x1;
res_APDU_size++;
if (res_APDU_size < 128) {
memmove(res_APDU+2, res_APDU, res_APDU_size);
res_APDU[1] = res_APDU_size;
res_APDU_size += 2;
}
else if (res_APDU_size < 256) {
memmove(res_APDU+3, res_APDU, res_APDU_size);
res_APDU[1] = 0x81;
res_APDU[2] = res_APDU_size;
res_APDU_size += 3;
}
else {
memmove(res_APDU+4, res_APDU, res_APDU_size);
res_APDU[1] = 0x82;
res_APDU[2] = res_APDU_size >> 8;
res_APDU[3] = res_APDU_size & 0xff;
res_APDU_size += 4;
}
res_APDU[0] = 0x87;
}
res_APDU[res_APDU_size++] = 0x99;
res_APDU[res_APDU_size++] = 2;
res_APDU[res_APDU_size++] = apdu.sw >> 8;
res_APDU[res_APDU_size++] = apdu.sw & 0xff;
memcpy(input+input_len, res_APDU, res_APDU_size);
input_len += res_APDU_size;
input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len%sm_blocksize));
r = sm_sign(input, input_len, res_APDU+res_APDU_size+2);
res_APDU[res_APDU_size++] = 0x8E;
res_APDU[res_APDU_size++] = 8;
res_APDU_size += 8;
if (apdu.expected_res_size > 0)
apdu.expected_res_size = res_APDU_size;
return CCID_OK;
}
int sm_get_le() {
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
size_t tag_len = 0;
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x97) {
uint32_t le = 0;
for (int t = 1; t <= tag_len; t++)
le |= (*tag_data++) << (tag_len-t);
return le;
}
}
return -1;
}
void sm_update_iv() {
uint8_t tmp_iv[16], sc_counter[16];
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
aes_encrypt(sm_kenc, tmp_iv, 128, HSM_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
}
int sm_verify() {
uint8_t input[1024];
memset(input, 0, sizeof(input));
int input_len = 0, r = 0;
bool add_header = (CLA(apdu) & 0xC) == 0xC;
int data_len = (int)(apdu.cmd_apdu_data_len/sm_blocksize)*sm_blocksize;
if (data_len % sm_blocksize)
data_len += sm_blocksize;
if (data_len+(add_header ? sm_blocksize : 0) > 1024)
return CCID_WRONG_LENGTH;
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
mbedtls_mpi_copy(&sm_mSSC, &ssc);
r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (r != 0)
return CCID_EXEC_ERROR;
if (add_header) {
input[input_len++] = CLA(apdu);
input[input_len++] = INS(apdu);
input[input_len++] = P1(apdu);
input[input_len++] = P2(apdu);
input[input_len++] = 0x80;
input_len += sm_blocksize-5;
}
bool some_added = false;
const uint8_t *mac = NULL;
size_t mac_len = 0;
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
size_t tag_len = 0;
while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) {
if (tag & 0x1) {
input[input_len++] = tag;
int tlen = format_tlv_len(tag_len, input+input_len);
input_len += tlen;
memcpy(input+input_len, tag_data, tag_len);
input_len += tag_len;
some_added = true;
}
if (tag == 0x8E) {
mac = tag_data;
mac_len = tag_len;
}
}
if (!mac)
return CCID_WRONG_DATA;
if (some_added) {
input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len%sm_blocksize));
}
uint8_t signature[16];
r = sm_sign(input, input_len, signature);
if (r != 0)
return CCID_EXEC_ERROR;
if (memcmp(signature, mac, mac_len) == 0)
return CCID_OK;
return CCID_VERIFICATION_FAILED;
}
int sm_remove_padding(const uint8_t *data, size_t data_len) {
int i = data_len-1;
for (; i >= 0 && data[i] == 0; i--);
if (i < 0 || data[i] != 0x80)
return -1;
return i;
}

50
src/compat.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _COMPAT_H_
#define _COMPAT_H_
#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
#else
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
#endif // _COMPAT_H

174
src/crypto_utils.c Normal file
View File

@@ -0,0 +1,174 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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/>.
*/
#if defined(ENABLE_EMULATION)
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#else
#include <pico/unique_id.h>
#endif
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "crypto_utils.h"
#include "pico_keys.h"
void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
uint8_t o1[32];
hash_multi(pin, len, o1);
for (int i = 0; i < sizeof(o1); i++) {
o1[i] ^= pin[i % len];
}
hash_multi(o1, sizeof(o1), output);
}
void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
uint16_t iters = 256;
mbedtls_sha256_starts(&ctx, 0);
#ifndef ENABLE_EMULATION
mbedtls_sha256_update(&ctx, pico_serial.id, sizeof(pico_serial.id));
#endif
while (iters > len) {
mbedtls_sha256_update(&ctx, input, len);
iters -= len;
}
if (iters > 0) { // remaining iterations
mbedtls_sha256_update(&ctx, input, iters);
}
mbedtls_sha256_finish(&ctx, output);
mbedtls_sha256_free(&ctx);
}
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0);
mbedtls_sha256_update(&ctx, input, len);
mbedtls_sha256_finish(&ctx, output);
mbedtls_sha256_free(&ctx);
}
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
mbedtls_md(mbedtls_md_info_from_type(md), input, len, output);
}
int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv) {
memcpy(tmp_iv, iv, IV_SIZE);
}
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
}
if (mode == PICO_KEYS_AES_MODE_CBC) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
}
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv) {
memcpy(tmp_iv, iv, IV_SIZE);
}
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
}
if (mode == PICO_KEYS_AES_MODE_CBC) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
}
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
return aes_encrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
}
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
return aes_decrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
}
struct lv_data {
unsigned char *value;
uint8_t len;
};
struct ec_curve_mbed_id {
struct lv_data curve;
mbedtls_ecp_group_id id;
};
struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
24 }, MBEDTLS_ECP_DP_SECP192R1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
32 }, MBEDTLS_ECP_DP_SECP256R1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
48 }, MBEDTLS_ECP_DP_SECP384R1 },
{ { (unsigned char *)
"\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
66 }, MBEDTLS_ECP_DP_SECP521R1 },
{ { (unsigned char *)
"\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77",
32 }, MBEDTLS_ECP_DP_BP256R1 },
{ { (unsigned char *)
"\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53",
48 }, MBEDTLS_ECP_DP_BP384R1 },
{ { (unsigned char *)
"\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3",
64 }, MBEDTLS_ECP_DP_BP512R1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37",
24 }, MBEDTLS_ECP_DP_SECP192K1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F",
32 }, MBEDTLS_ECP_DP_SECP256K1 },
{ { (unsigned char *)
"\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xed",
32 }, MBEDTLS_ECP_DP_CURVE25519 },
{ { (unsigned char *)
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
56 }, MBEDTLS_ECP_DP_CURVE448 },
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
};
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
return ec->id;
}
}
return MBEDTLS_ECP_DP_NONE;
}

51
src/crypto_utils.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _CRYPTO_UTILS_H_
#define _CRYPTO_UTILS_H_
#include "mbedtls/ecp.h"
#include "mbedtls/md.h"
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask
#define PICO_KEYS_KEY_RSA_1K 0x0001
#define PICO_KEYS_KEY_RSA_2K 0x0002
#define PICO_KEYS_KEY_RSA_3K 0x0004
#define PICO_KEYS_KEY_RSA_4k 0x0008
#define PICO_KEYS_KEY_EC 0x0010
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
#define PICO_KEYS_KEY_AES_128 0x0100
#define PICO_KEYS_KEY_AES_192 0x0200
#define PICO_KEYS_KEY_AES_256 0x0400
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
#define PICO_KEYS_AES_MODE_CBC 1
#define PICO_KEYS_AES_MODE_CFB 2
#define IV_SIZE 16
extern void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]);
extern void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]);
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output);
extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len);
extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len);
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
#endif

54
src/debug.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _DEBUG_H_
#define _DEBUG_H_
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
#define DEBUG_PAYLOAD(_p, _s) { \
printf("Payload %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \
for (int _i = 0; _i < _s; _i += 16) { \
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
for (int _j = 0; _j < 16; _j++) { \
if (_j < _s - _i) printf("%02X ", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} printf(": "); \
for (int _j = 0; _j < 16; _j++) { \
if (_j < _s - _i && (_p)[_i + _j] > 32 && (_p)[_i + _j] != 127 && (_p)[_i + _j] < 176) printf("%c", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} \
printf("\n"); \
} printf("\n"); \
}
#define DEBUG_DATA(_p, _s) { \
printf("Data %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \
char *_tmp = (char *) calloc(1, 2 * _s + 1); \
for (int _i = 0; _i < _s; _i++) { \
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
} \
printf("%s\n", _tmp); \
free(_tmp); \
}
#else
#define DEBUG_PAYLOAD(_p, _s)
#define DEBUG_DATA(_p, _s)
#endif
#endif // _DEBUG_H_

314
src/eac.c Normal file
View File

@@ -0,0 +1,314 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "eac.h"
#include "crypto_utils.h"
#include "random.h"
#include "mbedtls/cmac.h"
#include "asn1.h"
#include "apdu.h"
static uint8_t sm_nonce[8];
static uint8_t sm_kmac[16];
static uint8_t sm_kenc[16];
static MSE_protocol sm_protocol = MSE_NONE;
static mbedtls_mpi sm_mSSC;
static uint8_t sm_blocksize = 0;
static uint8_t sm_iv[16];
uint16_t sm_session_pin_len = 0;
uint8_t sm_session_pin[16];
bool is_secured_apdu() {
return CLA(apdu) & 0xC;
}
void sm_derive_key(const uint8_t *input,
size_t input_len,
uint8_t counter,
const uint8_t *nonce,
size_t nonce_len,
uint8_t *out) {
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
if (input) {
memcpy(b, input, input_len);
}
if (nonce) {
memcpy(b + input_len, nonce, nonce_len);
}
b[input_len + nonce_len + 3] = counter;
uint8_t digest[20];
generic_hash(MBEDTLS_MD_SHA1, b, input_len + nonce_len + 4, digest);
memcpy(out, digest, 16);
free(b);
}
void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
memcpy(sm_nonce, random_bytes_get(8), 8);
sm_derive_key(derived, derived_len, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
mbedtls_mpi_init(&sm_mSSC);
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
mbedtls_mpi_lset(&sm_mSSC, 0);
memset(sm_iv, 0, sizeof(sm_iv));
sm_session_pin_len = 0;
}
void sm_set_protocol(MSE_protocol proto) {
sm_protocol = proto;
if (proto == MSE_AES) {
sm_blocksize = 16;
}
else if (proto == MSE_3DES) {
sm_blocksize = 8;
}
}
MSE_protocol sm_get_protocol() {
return sm_protocol;
}
uint8_t *sm_get_nonce() {
return sm_nonce;
}
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
sm_kmac,
128,
in,
in_len,
out);
}
int sm_unwrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) {
return PICOKEY_OK;
}
int r = sm_verify();
if (r != PICOKEY_OK) {
return r;
}
apdu.ne = sm_get_le();
uint8_t *body = NULL;
uint16_t body_size = 0;
bool is87 = false;
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
{
if (tag == 0x87 || tag == 0x85) {
body = tag_data;
body_size = tag_len;
if (tag == 0x87) {
is87 = true;
body_size--;
}
}
}
if (!body) {
apdu.nc = 0;
return PICOKEY_OK;
}
if (is87 && *body++ != 0x1) {
return PICOKEY_WRONG_PADDING;
}
sm_update_iv();
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size);
memmove(apdu.data, body, body_size);
apdu.nc = sm_remove_padding(apdu.data, body_size);
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
return PICOKEY_OK;
}
int sm_wrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) {
return PICOKEY_OK;
}
uint8_t input[2048];
size_t input_len = 0;
memset(input, 0, sizeof(input));
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
mbedtls_mpi_copy(&sm_mSSC, &ssc);
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
}
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = 0x80;
memset(res_APDU + res_APDU_size, 0, (sm_blocksize - (res_APDU_size % sm_blocksize)));
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
sm_update_iv();
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
memmove(res_APDU + 1, res_APDU, res_APDU_size);
res_APDU[0] = 0x1;
res_APDU_size++;
if (res_APDU_size < 128) {
memmove(res_APDU + 2, res_APDU, res_APDU_size);
res_APDU[1] = (uint8_t)res_APDU_size;
res_APDU_size += 2;
}
else if (res_APDU_size < 256) {
memmove(res_APDU + 3, res_APDU, res_APDU_size);
res_APDU[1] = 0x81;
res_APDU[2] = (uint8_t)res_APDU_size;
res_APDU_size += 3;
}
else {
memmove(res_APDU + 4, res_APDU, res_APDU_size);
res_APDU[1] = 0x82;
put_uint16_t_be(res_APDU_size, res_APDU + 2);
res_APDU_size += 4;
}
res_APDU[0] = 0x87;
}
res_APDU[res_APDU_size++] = 0x99;
res_APDU[res_APDU_size++] = 2;
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size);
res_APDU_size += 2;
memcpy(input + input_len, res_APDU, res_APDU_size);
input_len += res_APDU_size;
input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len % sm_blocksize));
r = sm_sign(input, input_len, res_APDU + res_APDU_size + 2);
res_APDU[res_APDU_size++] = 0x8E;
res_APDU[res_APDU_size++] = 8;
res_APDU_size += 8;
if (apdu.ne > 0) {
apdu.ne = res_APDU_size;
}
set_res_sw(0x90, 0x00);
return PICOKEY_OK;
}
uint16_t sm_get_le() {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x97) {
uint16_t le = 0;
for (uint16_t t = 1; t <= tag_len; t++) {
le |= (*tag_data++) << (tag_len - t) * 8;
}
return le;
}
}
return 0;
}
void sm_update_iv() {
uint8_t tmp_iv[16], sc_counter[16];
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
}
int sm_verify() {
uint8_t input[2048];
memset(input, 0, sizeof(input));
uint16_t input_len = 0;
int r = 0;
bool add_header = (CLA(apdu) & 0xC) == 0xC;
int data_len = (int) (apdu.nc / sm_blocksize) * sm_blocksize;
if (data_len % sm_blocksize) {
data_len += sm_blocksize;
}
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
return PICOKEY_WRONG_LENGTH;
}
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
mbedtls_mpi_copy(&sm_mSSC, &ssc);
r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
}
if (add_header) {
input[input_len++] = CLA(apdu);
input[input_len++] = INS(apdu);
input[input_len++] = P1(apdu);
input[input_len++] = P2(apdu);
input[input_len++] = 0x80;
input_len += sm_blocksize - 5;
}
bool some_added = false;
const uint8_t *mac = NULL;
uint16_t mac_len = 0;
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag & 0x1) {
input[input_len++] = (uint8_t)tag;
uint8_t tlen = format_tlv_len(tag_len, input + input_len);
input_len += tlen;
memcpy(input + input_len, tag_data, tag_len);
input_len += tag_len;
some_added = true;
}
if (tag == 0x8E) {
mac = tag_data;
mac_len = tag_len;
}
}
if (!mac) {
return PICOKEY_WRONG_DATA;
}
if (some_added) {
input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len % sm_blocksize));
}
uint8_t signature[16];
r = sm_sign(input, input_len, signature);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
}
if (memcmp(signature, mac, mac_len) == 0) {
return PICOKEY_OK;
}
return PICOKEY_VERIFICATION_FAILED;
}
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) {
int32_t i = data_len - 1;
for (; i >= 0 && data[i] == 0; i--) {
;
}
if (i < 0 || data[i] != 0x80) {
return 0;
}
return (uint16_t)i;
}

View File

@@ -1,32 +1,30 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 _EAC_H_
#define _EAC_H_
#include <stdlib.h>
#include "pico/stdlib.h"
#include "ccid2040.h"
#include "pico_keys.h"
typedef enum MSE_protocol {
MSE_AES = 0,
MSE_3DES,
MSE_NONE
}MSE_protocol;
} MSE_protocol;
extern void sm_derive_all_keys(const uint8_t *input, size_t input_len);
extern void sm_set_protocol(MSE_protocol proto);
@@ -35,12 +33,12 @@ extern uint8_t *sm_get_nonce();
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
int sm_verify();
void sm_update_iv();
int sm_get_le();
uint16_t sm_get_le();
extern int sm_unwrap();
int sm_remove_padding(const uint8_t *data, size_t data_len);
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
extern int sm_wrap();
extern bool is_secured_apdu();
extern uint8_t sm_session_pin[16];
extern size_t sm_session_pin_len;
extern uint16_t sm_session_pin_len;
#endif

61
src/esp_compat.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 __ESP_COMPAT_H_
#define __ESP_COMPAT_H_
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
typedef QueueHandle_t queue_t;
#define queue_init(a,b,c) do { *(a) = xQueueCreate(c, b); } while(0)
#define queue_add_blocking(a,b) xQueueSend(*(a), b, portMAX_DELAY)
#define queue_remove_blocking(a,b) xQueueReceive(*(a), b, portMAX_DELAY)
#define queue_try_add(a,b) xQueueSend(*(a), b, 0)
#define queue_is_empty(a) (uxQueueMessagesWaiting(*(a)) == 0)
#define queue_try_remove(a,b) xQueueReceive(*(a), b, 0)
extern TaskHandle_t hcore0, hcore1;
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define ESP32_CORE0 0
#define ESP32_CORE1 1
#else
#define ESP32_CORE0 tskNO_AFFINITY
#define ESP32_CORE1 tskNO_AFFINITY
#endif
#define multicore_launch_core1(a) xTaskCreatePinnedToCore((void(*)(void *))a, "core1", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, ESP32_CORE1)
#define multicore_reset_core1() do { if (hcore1) { eTaskState e = eTaskGetState(hcore1); if (e <= eSuspended) { vTaskDelete(hcore1); }} }while(0)
#define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
static inline uint32_t board_millis(void) {
return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ );
}
typedef SemaphoreHandle_t mutex_t;
typedef SemaphoreHandle_t semaphore_t;
#define mutex_init(a) do { *(a) = xSemaphoreCreateMutex();} while(0)
#define mutex_try_enter(a,b) xSemaphoreTake(*(a), 0)
#define mutex_enter_blocking(a) xSemaphoreTake(*(a), portMAX_DELAY)
#define mutex_exit(a) xSemaphoreGive(*(a))
#define sem_init(a,b,c) do { *(a) = xSemaphoreCreateCounting(c, b); } while(0)
#define sem_release(a) xSemaphoreGive(*(a))
#define sem_acquire_blocking(a) xSemaphoreTake(*(a), portMAX_DELAY)
#define multicore_lockout_victim_init() (void)0
static inline bool multicore_lockout_start_timeout_us(int a) { if (hcore1) { vTaskSuspend(hcore1); } return true; }
static inline bool multicore_lockout_end_timeout_us(int a) { if (hcore1) { vTaskResume(hcore1); } return true; }
#endif
#endif

View File

@@ -1,92 +1,127 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 "file.h"
#include "tusb.h"
#include "ccid2040.h"
#include "pico_keys.h"
#include <string.h>
#include <stdio.h>
#include "asn1.h"
#include "apdu.h"
extern const uintptr_t end_data_pool;
extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool;
extern const uintptr_t start_rom_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_word (uintptr_t addr, uint32_t data);
extern int flash_program_uintptr (uintptr_t addr, uintptr_t data);
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t flash_read_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern int flash_clear_file(file_t *ef);
extern void low_flash_available();
#ifndef ENABLE_EMULATION
file_t sef_phy = {.fid = EF_PHY, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}};
file_t *ef_phy = &sef_phy;
#endif
//puts FCI in the RAPDU
void process_fci(const file_t *pe) {
uint8_t *p = res_APDU;
uint8_t buf[64];
void process_fci(const file_t *pe, int fmd) {
res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0x6f;
if (fmd) {
res_APDU[res_APDU_size++] = 0x6f;
res_APDU[res_APDU_size++] = 0x00; //computed later
}
res_APDU[res_APDU_size++] = 0x62;
res_APDU[res_APDU_size++] = 0x00; //computed later
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 2;
if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
res_APDU[res_APDU_size++] = len & 0xff;
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size);
}
else {
res_APDU[res_APDU_size++] = pe->data[1];
res_APDU[res_APDU_size++] = pe->data[0];
uint16_t v = file_get_size(pe);
res_APDU_size += put_uint16_t_be(v, res_APDU + res_APDU_size);
}
}
else {
memset(res_APDU+res_APDU_size, 0, 2);
memset(res_APDU + res_APDU_size, 0, 2);
res_APDU_size += 2;
}
res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size] = 0;
if (pe->type == FILE_TYPE_INTERNAL_EF)
if (pe->type & FILE_TYPE_INTERNAL_EF) {
res_APDU[res_APDU_size++] |= 0x08;
else if (pe->type == FILE_TYPE_WORKING_EF)
}
else if (pe->type & FILE_TYPE_WORKING_EF) {
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
else if (pe->type == FILE_TYPE_DF)
}
else if (pe->type & FILE_TYPE_DF) {
res_APDU[res_APDU_size++] |= 0x38;
}
else {
res_APDU_size++;
}
res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2;
put_uint16_t(pe->fid, res_APDU+res_APDU_size);
res_APDU_size += 2;
res_APDU[1] = res_APDU_size-2;
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size);
if (pe->name) {
res_APDU[res_APDU_size++] = 0x84;
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
memcpy(res_APDU + res_APDU_size, pe->name + 2, MIN(pe->name[0], 16));
res_APDU_size += MIN(pe->name[0], 16);
}
memcpy(res_APDU + res_APDU_size, "\x8A\x01\x05", 3); //life-cycle (5 -> activated)
res_APDU_size += 3;
uint8_t *meta_data = NULL;
uint16_t meta_size = meta_find(pe->fid, &meta_data);
if (meta_size > 0 && meta_data != NULL) {
res_APDU[res_APDU_size++] = 0xA5;
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = (uint8_t )meta_size;
memcpy(res_APDU + res_APDU_size, meta_data, meta_size);
res_APDU_size += meta_size;
}
res_APDU[1] = (uint8_t)res_APDU_size - 2;
if (fmd) {
res_APDU[3] = (uint8_t )res_APDU_size - 4;
}
}
#define MAX_DYNAMIC_FILES 64
uint16_t dynamic_files = 0;
file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent)
if (child == parent) {
return true;
if (child == MF)
}
if (child == MF) {
return false;
}
return is_parent(&file_entries[child->parent], parent);
}
@@ -96,7 +131,7 @@ file_t *get_parent(file_t *f) {
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
return p;
}
}
@@ -104,47 +139,65 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
}
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
#ifndef ENABLE_EMULATION
if (fid == EF_PHY) {
return ef_phy;
}
#endif
for (file_t *p = file_entries; p != file_last; p++) {
if (p->fid != 0x0000 && p->fid == fid) {
if (!parent || (parent && is_parent(p, parent))) {
if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
if (!sp || sp == SPECIFY_ANY ||
(((sp & SPECIFY_EF) && (p->type & (FILE_TYPE_INTERNAL_EF|FILE_TYPE_WORKING_EF))) ||
((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF))) {
return p;
}
}
}
}
return NULL;
}
file_t *search_file(const uint16_t fid) {
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
if (ef) {
return ef;
}
return search_dynamic_file(fid);
}
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
if (!buflen)
if (!buflen) {
return 0;
if (pe == top) //MF or relative DF
}
if (pe == top) { //MF or relative DF
return 0;
put_uint16_t(pe->fid, buf);
return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
}
put_uint16_t_be(pe->fid, buf);
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2;
}
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH*2], *p = path;
put_uint16_t(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2;
for (int d = depth-2; d >= 0; d -= 2) {
memcpy(p, buf+d, 2);
uint8_t buf[MAX_DEPTH * 2], *p = path;
put_uint16_t_be(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2;
for (int d = depth - 2; d >= 0; d -= 2) {
memcpy(p, buf + d, 2);
p += 2;
}
return depth;
}
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
uint8_t path[MAX_DEPTH*2];
uint8_t path[MAX_DEPTH * 2];
if (pathlen > sizeof(path)) {
return NULL;
}
for (file_t *p = file_entries; p != file_last; p++) {
uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
if (pathlen == depth && memcmp(path, pe_path, depth) == 0) {
return p;
}
}
return NULL;
}
@@ -156,15 +209,17 @@ bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op];
if (acl == 0x0)
if (acl == 0x0) {
return true;
else if (acl == 0xff)
}
else if (acl == 0xff) {
return false;
else if (acl == 0x90 || acl & 0x9F == 0x10) {
// PIN required.
if(isUserAuthenticated) {
}
else if (acl == 0x90 || (acl & 0x9F) == 0x10) {
// PIN required.
if (isUserAuthenticated) {
return true;
}
}
else {
return false;
}
@@ -172,15 +227,6 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
return false;
}
void initialize_chain(file_chain_t **chain) {
file_chain_t *next;
for (file_chain_t *f = *chain; f; f = next) {
next = f->next;
free(f);
}
*chain = NULL;
}
void initialize_flash(bool hard) {
if (hard) {
const uint8_t empty[8] = { 0 };
@@ -188,76 +234,133 @@ void initialize_flash(bool hard) {
low_flash_available();
}
for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
f->data = NULL;
}
}
dynamic_files = 0;
}
void scan_flash() {
initialize_flash(false); //soft initialization
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
{
printf("First initialization (or corrupted!)\r\n");
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
extern uintptr_t last_base;
extern uint32_t num_files;
void scan_region(bool persistent)
{
uintptr_t endp = end_data_pool, startp = start_data_pool;
if (persistent) {
endp = end_rom_pool;
startp = start_rom_pool;
}
printf("SCAN\r\n");
uintptr_t base = flash_read_uintptr(end_data_pool);
for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) {
if (base == 0x0) //all is empty
else {
last_base = endp;
num_files = 0;
}
for (uintptr_t base = flash_read_uintptr(endp); base >= startp; base = flash_read_uintptr(base)) {
if (base == 0x0) { //all is empty
break;
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
printf("[%x] scan fid %x, len %d\r\n",base,fid,flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t)));
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (file)
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
}
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t));
printf("[%x] scan fid %x, len %d\n", (unsigned int) base, fid, flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)));
file_t *file = (file_t *) search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) {
file = file_new(fid);
}
if (file) {
file->data = (uint8_t *) (base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t));
}
if (!persistent) {
num_files++;
}
if (flash_read_uintptr(base) == 0x0) {
if (base < last_base) {
last_base = base;
}
break;
}
}
}
void wait_flash_finish();
void scan_flash() {
initialize_flash(false); //soft initialization
uint32_t r1 = *(uintptr_t *) flash_read(end_rom_pool), r2 = *(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t));
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
printf("First initialization (or corrupted!)\n");
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
memset(empty, 0, sizeof(empty));
flash_program_block(end_data_pool, empty, sizeof(empty));
flash_program_block(end_rom_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
}
printf("SCAN\n");
scan_region(true);
scan_region(false);
}
uint8_t *file_read(const uint8_t *addr) {
return flash_read((uintptr_t)addr);
return flash_read((uintptr_t) addr);
}
uint16_t file_read_uint16(const uint8_t *addr) {
return flash_read_uint16((uintptr_t)addr);
return flash_read_uint16((uintptr_t) addr);
}
uint8_t file_read_uint8(const uint8_t *addr) {
return flash_read_uint8((uintptr_t)addr);
uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset) {
return flash_read_uint8((uintptr_t) (file_get_data(ef) + offset));
}
uint8_t file_read_uint8(const file_t *ef) {
return file_read_uint8_offset(ef, 0);
}
uint8_t *file_get_data(const file_t *tf) {
if (!tf || !tf->data) {
return NULL;
}
return file_read(tf->data + sizeof(uint16_t));
}
uint16_t file_get_size(const file_t *tf) {
if (!tf || !tf->data) {
return 0;
}
return file_read_uint16(tf->data);
}
int file_put_data(file_t *file, const uint8_t *data, uint16_t len) {
return flash_write_data_to_file(file, data, len);
}
file_t *search_dynamic_file(uint16_t fid) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid)
if (dynamic_file[i].fid == fid) {
return &dynamic_file[i];
}
}
return NULL;
}
int delete_dynamic_file(file_t *f) {
if (f == NULL) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) {
for (int j = i+1; j < dynamic_files; j++)
memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
for (int j = i + 1; j < dynamic_files; j++) {
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
}
dynamic_files--;
return CCID_OK;
return PICOKEY_OK;
}
}
return CCID_ERR_FILE_NOT_FOUND;
return PICOKEY_ERR_FILE_NOT_FOUND;
}
file_t *file_new(uint16_t fid) {
file_t *f;
if ((f = search_dynamic_file(fid)))
if ((f = search_file(fid))) {
return f;
if (dynamic_files == MAX_DYNAMIC_FILES)
}
if (dynamic_files == MAX_DYNAMIC_FILES) {
return NULL;
}
f = &dynamic_file[dynamic_files];
dynamic_files++;
file_t file = {
@@ -267,28 +370,166 @@ file_t *file_new(uint16_t fid) {
.type = FILE_TYPE_WORKING_EF,
.ef_structure = FILE_EF_TRANSPARENT,
.data = NULL,
.acl = {0}
.acl = { 0 }
};
memcpy(f, &file, sizeof(file_t));
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
return f;
}
file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) {
if (search_file_chain(file->fid, *chain))
return NULL;
file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t));
fc->file = file;
fc->next = *chain;
*chain = fc;
return fc;
}
file_t *search_file_chain(uint16_t fid, file_chain_t *chain) {
for (file_chain_t *fc = chain; fc; fc = fc->next) {
if (fid == fc->file->fid) {
return fc->file;
uint16_t meta_find(uint16_t fid, uint8_t **out) {
file_t *ef = search_file(EF_META);
if (!ef) {
return 0;
}
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) {
if (out) {
*out = tag_data + 2;
}
return tag_len - 2;
}
}
return NULL;
}
return 0;
}
int meta_delete(uint16_t fid) {
file_t *ef = search_file(EF_META);
if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
uint8_t *fdata = NULL;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) {
uint16_t new_len = ctxi.len - 1 - tag_len - format_tlv_len(tag_len, NULL);
if (new_len == 0) {
flash_clear_file(ef);
}
else {
fdata = (uint8_t *) calloc(1, new_len);
if (tpos > ctxi.data) {
memcpy(fdata, ctxi.data, tpos - ctxi.data);
}
if (ctxi.data + ctxi.len > p) {
memcpy(fdata + (tpos - ctxi.data), p, ctxi.data + ctxi.len - p);
}
int r = file_put_data(ef, fdata, new_len);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
}
low_flash_available();
break;
}
}
return PICOKEY_OK;
}
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
int r;
file_t *ef = search_file(EF_META);
if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
uint16_t ef_size = file_get_size(ef);
uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
memcpy(fdata, file_get_data(ef), ef_size);
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(fdata, ef_size, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) {
if (tag_len - 2 == len) { //an update
memcpy(p - tag_len + 2, data, len);
r = file_put_data(ef, fdata, ef_size);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
return PICOKEY_OK;
}
else { //needs reallocation
uint8_t *tpos = p - asn1_len_tag(tag, tag_len);
memmove(tpos, p, fdata + ef_size - p);
tpos += fdata + ef_size - p;
volatile uintptr_t meta_offset = tpos - fdata;
ef_size += len - (tag_len - 2);
if (len > tag_len - 2) {
uint8_t *fdata_new = (uint8_t *) realloc(fdata, ef_size);
if (fdata_new != NULL) {
fdata = fdata_new;
}
else {
free(fdata);
return PICOKEY_ERR_MEMORY_FATAL;
}
}
uint8_t *f = fdata + meta_offset;
*f++ = fid & 0xff;
f += format_tlv_len(len + 2, f);
f += put_uint16_t_be(fid, f);
memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
return PICOKEY_OK;
}
}
}
fdata = (uint8_t *) realloc(fdata, ef_size + asn1_len_tag(fid & 0x1f, len + 2));
uint8_t *f = fdata + ef_size;
*f++ = fid & 0x1f;
f += format_tlv_len(len + 2, f);
f += put_uint16_t_be(fid, f);
memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2));
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
return PICOKEY_OK;
}
bool file_has_data(file_t *f) {
return f != NULL && f->data != NULL && file_get_size(f) > 0;
}
int delete_file(file_t *ef) {
if (ef == NULL) {
return PICOKEY_OK;
}
meta_delete(ef->fid);
if (flash_clear_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
if (delete_dynamic_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
low_flash_available();
return PICOKEY_OK;
}

View File

@@ -1,30 +1,36 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 _FILE_H_
#define _FILE_H_
#include <stdlib.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#else
#include <stdbool.h>
#include <stdint.h>
#endif
#include "compat.h"
#include "phy.h"
#define FILE_TYPE_UNKNOWN 0x00
#define FILE_TYPE_NOT_KNOWN 0x00
#define FILE_TYPE_DF 0x04
#define FILE_TYPE_INTERNAL_EF 0x03
#define FILE_TYPE_INTERNAL_EF 0x02
#define FILE_TYPE_WORKING_EF 0x01
#define FILE_TYPE_BSO 0x10
#define FILE_PERSISTENT 0x20
@@ -53,33 +59,32 @@
#define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3
#define EF_DKEK 0x108F
#define EF_PRKDFS 0x6040
#define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
#define EF_META 0xE010
#define MAX_DEPTH 4
typedef struct file
{
const uint16_t fid;
const uint8_t parent; //entry number in the whole table!!
#define MAX_DYNAMIC_FILES 256
typedef struct file {
const uint8_t *name;
uint8_t *data; //should include 2 bytes len at begining
const uint16_t fid;
const uint8_t acl[7];
const uint8_t parent; //entry number in the whole table!!
const uint8_t type;
const uint8_t ef_structure;
uint8_t *data; //should include 2 bytes len at begining
const uint8_t acl[7];
} __attribute__((packed)) file_t;
#ifdef ENABLE_EMULATION
uint32_t _padding;
#endif
} __attribute__ ((packed)) file_t;
typedef struct file_chain
{
file_t *file;
struct file_chain *next;
} file_chain_t;
extern bool file_has_data(file_t *);
extern file_t *currentEF;
extern file_t *currentDF;
@@ -96,10 +101,11 @@ extern file_t *file_sopin;
extern file_t *file_retries_sopin;
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
extern file_t *search_file(const uint16_t fid);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe);
extern void process_fci(const file_t *pe, int fmd);
extern void scan_flash();
extern void initialize_flash(bool);
@@ -107,7 +113,11 @@ extern file_t file_entries[];
extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const uint8_t *addr);
extern uint8_t file_read_uint8(const file_t *ef);
extern uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset);
extern uint8_t *file_get_data(const file_t *tf);
extern uint16_t file_get_size(const file_t *tf);
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
extern file_t *file_new(uint16_t);
file_t *get_parent(file_t *f);
@@ -116,9 +126,21 @@ extern file_t dynamic_file[];
extern file_t *search_dynamic_file(uint16_t);
extern int delete_dynamic_file(file_t *f);
extern file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain);
extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain);
extern bool isUserAuthenticated;
extern uint16_t meta_find(uint16_t, uint8_t **out);
extern int meta_delete(uint16_t fid);
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
extern int delete_file(file_t *ef);
extern uint32_t flash_free_space();
extern uint32_t flash_used_space();
extern uint32_t flash_total_space();
extern uint32_t flash_num_files();
extern uint32_t flash_size();
#ifndef ENABLE_EMULATION
extern file_t *ef_phy;
#endif
#endif // _FILE_H_

View File

@@ -1,17 +1,17 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -19,11 +19,22 @@
#include <stdint.h>
#include <string.h>
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#define XIP_BASE 0
#define FLASH_SECTOR_SIZE 4096
#ifdef ESP_PLATFORM
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif
#else
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "ccid2040.h"
#include "tusb.h"
#endif
#include "pico_keys.h"
#include "file.h"
#include <stdio.h>
/*
* ------------------------------------------------------
@@ -32,57 +43,75 @@
* | |
* ------------------------------------------------------
*/
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
#define FLASH_PERMANENT_REGION (4*FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t) + sizeof(uint32_t))
#define FLASH_PERMANENT_REGION (4 * FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-FLASH_PERMANENT_REGION; //This is a fixed value. DO NOT CHANGE
#define FLASH_ADDR_DATA_STORAGE_START start_data_pool
uintptr_t end_flash, end_rom_pool, start_rom_pool, end_data_pool, start_data_pool;
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_halfword(uintptr_t addr, uint16_t data);
extern int flash_program_uintptr(uintptr_t, uintptr_t);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern void low_flash_available();
uintptr_t allocate_free_addr(uint16_t size) {
if (size > FLASH_SECTOR_SIZE)
uintptr_t last_base;
uint32_t num_files = 0;
void flash_set_bounds(uintptr_t start, uintptr_t end) {
end_flash = end;
end_rom_pool = end_flash - FLASH_DATA_HEADER_SIZE - 4;
start_rom_pool = end_rom_pool - FLASH_PERMANENT_REGION;
end_data_pool = start_rom_pool - FLASH_DATA_HEADER_SIZE;
start_data_pool = start;
last_base = end_data_pool;
}
uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
if (size > FLASH_SECTOR_SIZE) {
return 0x0; //ERROR
size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size
uintptr_t next_base = 0x0;
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
}
size_t real_size = size + sizeof(uint16_t) + sizeof(uintptr_t) + sizeof(uint16_t) + sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size
uintptr_t next_base = 0x0, endp = end_data_pool, startp = start_data_pool;
if (persistent) {
endp = end_rom_pool;
startp = start_rom_pool;
}
for (uintptr_t base = endp; base >= startp; base = next_base) {
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
uintptr_t potential_addr = base-real_size;
uintptr_t potential_addr = base - real_size;
next_base = flash_read_uintptr(base);
//printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
//printf("nb %x %x %x %x\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
if (next_base == 0x0) { //we are at the end
//now we check if we fit in the current sector
if (addr_alg <= potential_addr) //it fits in the current sector
{
if (addr_alg <= potential_addr) { //it fits in the current sector
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg-real_size;
else if (addr_alg - FLASH_SECTOR_SIZE >= startp) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg - real_size;
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
return 0x0;
}
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked)
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
else if (addr_alg <= potential_addr
&& base - (next_base + flash_read_uint16(next_base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)) + 2 * sizeof(uint16_t) + 2 * sizeof(uintptr_t)) > base - potential_addr
&& (flash_read_uint16(next_base + 2 * sizeof(uintptr_t)) & 0x1000) != 0x1000) {
flash_program_uintptr(potential_addr, next_base);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(next_base + sizeof(uintptr_t), potential_addr);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
@@ -91,43 +120,96 @@ uintptr_t allocate_free_addr(uint16_t size) {
}
int flash_clear_file(file_t *file) {
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t));
if (file == NULL || file->data == NULL) {
return PICOKEY_OK;
}
uintptr_t base_addr = (uintptr_t)(file->data - sizeof(uintptr_t) - sizeof(uint16_t) - sizeof(uintptr_t));
uintptr_t prev_addr = flash_read_uintptr(base_addr + sizeof(uintptr_t));
uintptr_t next_addr = flash_read_uintptr(base_addr);
//printf("nc %x->%x %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
flash_program_uintptr(prev_addr, next_addr);
flash_program_halfword((uintptr_t)file->data, 0);
if (next_addr > 0)
flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
//printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
return CCID_OK;
flash_program_halfword((uintptr_t) file->data, 0);
if (next_addr > 0) {
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr);
}
flash_program_uintptr(base_addr, 0);
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
file->data = NULL;
num_files--;
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
return PICOKEY_OK;
}
int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
if (!file) {
return PICOKEY_ERR_NULL_PARAM;
}
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
uint8_t *old_data = NULL;
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
return PICOKEY_ERR_NO_MEMORY;
}
if (file->data) { //already in flash
if (offset + len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t) file->data, offset + len);
if (data) {
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
}
return PICOKEY_OK;
}
else { //we clear the old file
flash_clear_file(file);
if (offset > 0) {
old_data = (uint8_t *) calloc(1, offset + len);
memcpy(old_data, flash_read((uintptr_t) (file->data + sizeof(uint16_t))), offset);
memcpy(old_data + offset, data, len);
len = offset + len;
data = old_data;
}
}
}
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
//printf("na %x\n",new_addr);
if (new_addr == 0x0) {
return PICOKEY_ERR_NO_MEMORY;
}
if (new_addr < last_base) {
last_base = new_addr;
}
file->data = (uint8_t *) new_addr + sizeof(uintptr_t) + sizeof(uint16_t) + sizeof(uintptr_t); //next addr+fid+prev addr
flash_program_halfword(new_addr + sizeof(uintptr_t) + sizeof(uintptr_t), file->fid);
flash_program_halfword((uintptr_t) file->data, len);
if (data) {
flash_program_block((uintptr_t) file->data + sizeof(uint16_t), data, len);
}
if (old_data) {
free(old_data);
}
num_files++;
return PICOKEY_OK;
}
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
if (!file)
return CCID_ERR_NULL_PARAM;
if (len > FLASH_SECTOR_SIZE)
return CCID_ERR_NO_MEMORY;
if (file->data) { //already in flash
uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data);
if (len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return CCID_OK;
}
else { //we clear the old file
flash_clear_file(file);
}
}
uintptr_t new_addr = allocate_free_addr(len);
//printf("na %x\r\n",new_addr);
if (new_addr == 0x0)
return CCID_ERR_NO_MEMORY;
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return CCID_OK;
return flash_write_data_to_file_offset(file, data, len, 0);
}
uint32_t flash_free_space() {
return last_base - start_data_pool;
}
uint32_t flash_used_space() {
return end_data_pool - last_base;
}
uint32_t flash_total_space() {
return end_data_pool - start_data_pool;
}
uint32_t flash_num_files() {
return num_files;
}
uint32_t flash_size() {
return FLASH_SIZE_BYTES;
}

View File

@@ -1,17 +1,17 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -20,16 +20,61 @@
#include <stdlib.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "pico/multicore.h"
#include "ccid2040.h"
#include "pico_keys.h"
#include <string.h>
#ifdef PICO_PLATFORM
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "pico/multicore.h"
#include "pico/bootrom.h"
#include "boot/picobin.h"
#else
#ifdef _MSC_VER
#include <windows.h>
#include <io.h>
#define O_RDWR _O_RDWR
#define O_CREAT _O_CREAT
#define open _open
#define write _write
#define mode_t unsigned short
#define lseek _lseek
#include "mman.h"
#else
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#include "esp_partition.h"
const esp_partition_t *part0;
#define save_and_disable_interrupts() 1
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
#define restore_interrupts(a) (void)a
#else
#include <unistd.h>
#include <sys/mman.h>
#include "emulation.h"
#endif
#endif
#define FLASH_SECTOR_SIZE 4096
#define XIP_BASE 0
int fd_map = 0;
uint8_t *map = NULL;
#include <fcntl.h>
#endif
#ifndef ENABLE_EMULATION
extern uint32_t FLASH_SIZE_BYTES;
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif
#define TOTAL_FLASH_PAGES 4
#define TOTAL_FLASH_PAGES 6
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool;
typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE];
@@ -42,59 +87,136 @@ typedef struct page_flash {
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash;
static semaphore_t sem_wait;
static semaphore_t sem_flash;
#ifndef ENABLE_EMULATION
static bool locked_out = false;
#else
static bool locked_out = true;
#endif
static uint8_t ready_pages = 0;
bool flash_available = false;
static bool locked_out = false;
//this function has to be called from the core 0
void do_flash()
{
void do_flash() {
if (mutex_try_enter(&mtx_flash, NULL) == true) {
if (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\r\n");
//printf(" DO_FLASH AVAILABLE\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) {
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
#ifndef ENABLE_EMULATION
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false) {
;
}
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts (ints);
while (multicore_lockout_end_timeout_us(1000) == false);
//printf("WRITEN %X !\r\n",flash_pages[r].address);
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts(ints);
while (multicore_lockout_end_timeout_us(1000) == false) {
;
}
//printf("WRITEN %X !\n",flash_pages[r].address);
#else
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
#endif
flash_pages[r].ready = false;
ready_pages--;
}
else if (flash_pages[r].erase == true) {
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING\r\n");
flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
while (multicore_lockout_end_timeout_us(1000) == false);
#ifndef ENABLE_EMULATION
while (multicore_lockout_start_timeout_us(1000) == false) {
;
}
//printf("WRITTING\n");
flash_range_erase(flash_pages[r].address - XIP_BASE, flash_pages[r].page_size ? ((int) (flash_pages[r].page_size / FLASH_SECTOR_SIZE)) * FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
while (multicore_lockout_end_timeout_us(1000) == false) {
;
}
#else
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
#endif
flash_pages[r].erase = false;
ready_pages--;
}
}
flash_available = false;
#ifdef ENABLE_EMULATION
msync(map, FLASH_SIZE_BYTES, MS_SYNC);
#endif
if (ready_pages != 0) {
DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES");
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
}
}
flash_available = false;
#ifdef ESP_PLATFORM
esp_partition_munmap(fd_map);
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
#endif
mutex_exit(&mtx_flash);
}
sem_release(&sem_wait);
sem_release(&sem_flash);
}
//this function has to be called from the core 0
void low_flash_init() {
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
mutex_init(&mtx_flash);
sem_init(&sem_wait, 0, 1);
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
sem_init(&sem_flash, 0, 1);
uint32_t data_start_addr;
uint32_t data_end_addr;
#if defined(ENABLE_EMULATION)
fd_map = open("memory.flash", O_RDWR | O_CREAT, (mode_t) 0600);
lseek(fd_map, FLASH_SIZE_BYTES - 1, SEEK_SET);
write(fd_map, "", 1);
map = mmap(0, FLASH_SIZE_BYTES, PROT_READ | PROT_WRITE, MAP_SHARED, fd_map, 0);
data_start_addr = 0;
data_end_addr = FLASH_SIZE_BYTES;
#elif defined(ESP_PLATFORM)
part0 = esp_partition_find_first(0x40, 0x1, "part0");
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
data_start_addr = 0;
data_end_addr = part0->size;
FLASH_SIZE_BYTES = part0->size;
#elif defined(PICO_PLATFORM)
uint8_t txbuf[6] = {0x9f};
uint8_t rxbuf[6] = {0};
flash_do_cmd(txbuf, rxbuf, 4);
FLASH_SIZE_BYTES = (1 << rxbuf[3]);
#ifdef PICO_RP2350
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
if (rc) {
reset_usb_boot(0, 0);
}
uint8_t boot_partition = 1;
rc = rom_get_partition_table_info((uint32_t*)workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
if (rc != 3) {
data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = FLASH_SIZE_BYTES;
} else {
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
uint16_t last_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
data_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
}
data_end_addr -= 2 * FLASH_SECTOR_SIZE;
#else
data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = FLASH_SIZE_BYTES;
#endif
data_start_addr += XIP_BASE;
data_end_addr += XIP_BASE;
#endif
flash_set_bounds(data_start_addr, data_end_addr);
}
void low_flash_init_core1() {
@@ -105,9 +227,9 @@ void low_flash_init_core1() {
}
void wait_flash_finish() {
sem_acquire_blocking(&sem_wait); //blocks until released
sem_acquire_blocking(&sem_flash); //blocks until released
//wake up
sem_acquire_blocking(&sem_wait); //decrease permits
sem_acquire_blocking(&sem_flash); //decrease permits
}
void low_flash_available() {
@@ -119,14 +241,16 @@ void low_flash_available() {
page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
{
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if ((!flash_pages[r].ready && !flash_pages[r].erase) ||
flash_pages[r].address == addr_alg) { //first available
p = &flash_pages[r];
if (!flash_pages[r].ready && !flash_pages[r].erase)
{
memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
if (!flash_pages[r].ready && !flash_pages[r].erase) {
#ifdef PICO_PLATFORM
memcpy(p->page, (uint8_t *) addr_alg, FLASH_SECTOR_SIZE);
#else
memcpy(p->page, (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) ? (uint8_t *) (map + addr_alg) : (uint8_t *) addr_alg, FLASH_SECTOR_SIZE);
#endif
ready_pages++;
p->address = addr_alg;
p->ready = true;
@@ -138,57 +262,60 @@ page_flash_t *find_free_page(uintptr_t addr) {
}
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
if (!data || len == 0)
return CCID_ERR_NULL_PARAM;
if (!data || len == 0) {
return PICOKEY_ERR_NULL_PARAM;
}
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return CCID_ERR_NO_MEMORY;
printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr)))
{
if (!(p = find_free_page(addr))) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
return CCID_ERR_MEMORY_FATAL;
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
return PICOKEY_ERR_MEMORY_FATAL;
}
memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
//printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr);
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len);
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
mutex_exit(&mtx_flash);
return CCID_OK;
return PICOKEY_OK;
}
int flash_program_halfword (uintptr_t addr, uint16_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
int flash_program_halfword(uintptr_t addr, uint16_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uint16_t));
}
int flash_program_word (uintptr_t addr, uint32_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
int flash_program_word(uintptr_t addr, uint32_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uint32_t));
}
int flash_program_uintptr (uintptr_t addr, uintptr_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
int flash_program_uintptr(uintptr_t addr, uintptr_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uintptr_t));
}
uint8_t *flash_read(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
mutex_enter_blocking(&mtx_flash);
if (ready_pages > 0) {
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
uint8_t *v = &flash_pages[r].page[addr & (FLASH_SECTOR_SIZE - 1)];
mutex_exit(&mtx_flash);
return v;
}
}
}
uint8_t *v = (uint8_t *)addr;
uint8_t *v = (uint8_t *) addr;
mutex_exit(&mtx_flash);
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) {
v += (uintptr_t) map;
}
#endif
return v;
}
@@ -196,7 +323,7 @@ uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uintptr_t v = 0x0;
for (int i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t)p[i]<<(8*i);
v |= (uintptr_t) p[i] << (8 * i);
}
return v;
}
@@ -204,7 +331,7 @@ uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uint16_t v = 0x0;
for (int i = 0; i < sizeof(uint16_t); i++) {
v |= p[i]<<(8*i);
v |= p[i] << (8 * i);
}
return v;
}
@@ -212,36 +339,35 @@ uint8_t flash_read_uint8(uintptr_t addr) {
return *flash_read(addr);
}
int flash_erase_page (uintptr_t addr, size_t page_size) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
int flash_erase_page(uintptr_t addr, size_t page_size) {
page_flash_t *p = NULL;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return CCID_ERR_NO_MEMORY;
printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr))) {
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
mutex_exit(&mtx_flash);
return CCID_ERR_MEMORY_FATAL;
return PICOKEY_ERR_MEMORY_FATAL;
}
p->erase = true;
p->ready = false;
p->page_size = page_size;
mutex_exit(&mtx_flash);
return CCID_OK;
return PICOKEY_OK;
}
bool flash_check_blank(const uint8_t *p_start, size_t size)
{
bool flash_check_blank(const uint8_t *p_start, size_t size) {
const uint8_t *p;
for (p = p_start; p < p_start + size; p++) {
if (*p != 0xff)
if (*p != 0xff) {
return false;
}
}
return true;
}

184
src/fs/mman.c Normal file
View File

@@ -0,0 +1,184 @@
#include <windows.h>
#include <errno.h>
#include <io.h>
#include "mman.h"
#ifndef FILE_MAP_EXECUTE
#define FILE_MAP_EXECUTE 0x0020
#endif /* FILE_MAP_EXECUTE */
static int __map_mman_error(const DWORD err, const int deferr)
{
(void)deferr;
if (err == 0)
return 0;
//TODO: implement
return err;
}
static DWORD __map_mmap_prot_page(const int prot)
{
DWORD protect = 0;
if (prot == PROT_NONE)
return protect;
if ((prot & PROT_EXEC) != 0)
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
else
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_READWRITE : PAGE_READONLY;
}
return protect;
}
static DWORD __map_mmap_prot_file(const int prot)
{
DWORD desiredAccess = 0;
if (prot == PROT_NONE)
return desiredAccess;
if ((prot & PROT_READ) != 0)
desiredAccess |= FILE_MAP_READ;
if ((prot & PROT_WRITE) != 0)
desiredAccess |= FILE_MAP_WRITE;
if ((prot & PROT_EXEC) != 0)
desiredAccess |= FILE_MAP_EXECUTE;
return desiredAccess;
}
void* mmap(void* addr, size_t len, int prot, int flags, int fildes, off_t off)
{
(void)addr;
HANDLE fm, h;
void* map = MAP_FAILED;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4293)
#endif
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
const DWORD protect = __map_mmap_prot_page(prot);
const DWORD desiredAccess = __map_mmap_prot_file(prot);
const off_t maxSize = off + (off_t)len;
const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
errno = 0;
if (len == 0
/* Unsupported flag combinations */
|| (flags & MAP_FIXED) != 0
/* Usupported protection combinations */
|| prot == PROT_EXEC)
{
errno = EINVAL;
return MAP_FAILED;
}
h = ((flags & MAP_ANONYMOUS) == 0) ?
(HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return MAP_FAILED;
}
fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
if (fm == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
CloseHandle(fm);
if (map == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
return map;
}
int munmap(void* addr, size_t len)
{
(void)len;
if (UnmapViewOfFile(addr))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int mprotect(void* addr, size_t len, int prot)
{
DWORD newProtect = __map_mmap_prot_page(prot);
DWORD oldProtect = 0;
if (VirtualProtect(addr, len, newProtect, &oldProtect))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int msync(void* addr, size_t len, int flags)
{
(void)flags;
if (FlushViewOfFile(addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int mlock(const void* addr, size_t len)
{
if (VirtualLock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int munlock(const void* addr, size_t len)
{
if (VirtualUnlock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}

55
src/fs/mman.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* sys/mman.h
* mman-win32
*/
#ifndef _SYS_MMAN_H_
#define _SYS_MMAN_H_
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
/* All the headers include this file. */
#ifndef _MSC_VER
#include <_mingw.h>
#endif
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xf
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
/* Flags for msync. */
#define MS_ASYNC 1
#define MS_SYNC 2
#define MS_INVALIDATE 4
void* mmap(void* addr, size_t len, int prot, int flags, int fildes, off_t off);
int munmap(void* addr, size_t len);
int mprotect(void* addr, size_t len, int prot);
int msync(void* addr, size_t len, int flags);
int mlock(const void* addr, size_t len);
int munlock(const void* addr, size_t len);
#ifdef __cplusplus
};
#endif
#endif /* _SYS_MMAN_H_ */

241
src/fs/otp.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "file.h"
#include "pico_keys.h"
#include <stdio.h>
#include "otp.h"
#ifdef PICO_RP2350
#include "pico/bootrom.h"
#include "hardware/structs/otp.h"
#include "hardware/regs/otp_data.h"
#endif
#include "random.h"
#include "mbedtls/ecdsa.h"
#ifdef PICO_RP2350
static bool is_empty_buffer(const uint8_t *buffer, uint16_t buffer_len) {
for (int i = 0; i < buffer_len; i++) {
if (buffer[i] != 0x00) {
return false;
}
}
return true;
}
static int otp_write_data_mode(uint16_t row, uint8_t *data, uint16_t len, bool is_ecc) {
otp_cmd_t cmd = { .flags = row | (is_ecc ? OTP_CMD_ECC_BITS : 0) | OTP_CMD_WRITE_BITS };
uint32_t ret = rom_func_otp_access(data, len, cmd);
if (ret) {
printf("OTP Write failed with error: %ld\n", ret);
}
return ret;
}
int otp_write_data(uint16_t row, uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, true);
}
int otp_write_data_raw(uint16_t row, uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, false);
}
uint8_t* otp_buffer(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + (row*2)));
return (uint8_t *)p;
}
uint8_t* otp_buffer_raw(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_RAW_BASE + (row*4)));
return (uint8_t *)p;
}
bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
return is_empty_buffer(otp_buffer(row), len);
}
static bool is_otp_locked_page(uint8_t page) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + ((OTP_DATA_PAGE0_LOCK0_ROW + page*2)*2)));
return ((p[0] & 0xFFFF0000) == 0x3C3C0000 && (p[1] & 0xFF) == 0x3C);
}
static void otp_lock_page(uint8_t page) {
if (!is_otp_locked_page(page)) {
uint32_t value = 0x3c3c3c;
otp_write_data_raw(OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, (uint8_t *)&value, sizeof(value));
}
otp_hw->sw_lock[page] = 0b1100;
}
#endif
#ifdef ESP_PLATFORM
uint8_t _otp_key_1[32] = {0};
uint8_t _otp_key_2[32] = {0};
esp_err_t read_key_from_efuse(esp_efuse_block_t block, uint8_t *key, size_t key_len) {
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
if (!key_desc) {
return ESP_FAIL;
}
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
}
#endif
const uint8_t *otp_key_1 = NULL;
const uint8_t *otp_key_2 = NULL;
#ifdef PICO_RP2350
typedef int otp_ret_t;
#define OTP_WRITE(ROW, DATA, LEN) otp_write_data(ROW, DATA, LEN)
#define OTP_READ(ROW, PTR) do { PTR = otp_buffer(ROW); } while(0)
#define OTP_EMTPY(ROW, LEN) is_empty_otp_buffer(ROW, LEN)
#elif defined(ESP_PLATFORM)
typedef esp_err_t otp_ret_t;
#define OTP_WRITE(ROW, DATA, LEN) esp_efuse_write_key(ROW, ESP_EFUSE_KEY_PURPOSE_USER, DATA, LEN);
#define OTP_READ(ROW, PTR) do { \
esp_err_t ret = read_key_from_efuse(ROW, _##PTR, sizeof(_##PTR)); \
if (ret != ESP_OK) { printf("Error reading OTP key 1 [%d]\n", ret); } \
PTR = _##PTR; } while(0)
#define OTP_EMTPY(ROW, LEN) esp_efuse_key_block_unused(ROW)
#endif
#ifndef SECURE_BOOT_BOOTKEY_INDEX
#define SECURE_BOOT_BOOTKEY_INDEX 0
#endif
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
int ret = 0;
#ifdef PICO_RP2350
uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
if (is_empty_otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, 32)) {
PICOKEY_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
}
uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
uint8_t flagsb1[] = { boot_flags1[0] | (1 << (bootkey + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB)), boot_flags1[1], boot_flags1[2], 0x00 };
if (secure_lock) {
flagsb1[1] |= ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey)));
}
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R2_ROW, flagsb1, sizeof(flagsb1)));
uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
uint8_t flagsc1[] = { crit1[0] | (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB), crit1[1], crit1[2], 0x00 };
if (secure_lock) {
flagsc1[0] |= (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB);
flagsc1[0] |= (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB);
flagsc1[0] |= (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB);
}
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R2_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R3_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R4_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R5_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R6_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R7_ROW, flagsc1, sizeof(flagsc1)));
if (secure_lock) {
uint8_t *page1 = otp_buffer_raw(OTP_DATA_PAGE1_LOCK1_ROW);
uint8_t page1v = page1[0] | (OTP_DATA_PAGE1_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE1_LOCK1_LOCK_BL_LSB);
uint8_t flagsp1[] = { page1v, page1v, page1v, 0x00 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
uint8_t *page2 = otp_buffer_raw(OTP_DATA_PAGE2_LOCK1_ROW);
uint8_t page2v = page2[0] | (OTP_DATA_PAGE2_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE2_LOCK1_LOCK_BL_LSB);
uint8_t flagsp2[] = { page2v, page2v, page2v, 0x00 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
}
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot for ESP32-S3
#endif // PICO_RP2350
goto err;
err:
if (ret != PICOKEY_OK) {
return ret;
}
return PICOKEY_OK;
}
void init_otp_files() {
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
otp_ret_t ret = 0;
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
if (OTP_EMTPY(OTP_KEY_1, 32)) {
uint8_t mkek[32] = {0};
random_gen(NULL, mkek, sizeof(mkek));
ret = OTP_WRITE(OTP_KEY_1, mkek, sizeof(mkek));
if (ret != 0) {
printf("Error writing OTP key 1 [%d]\n", ret);
}
write_otp[0] = OTP_KEY_1;
}
OTP_READ(OTP_KEY_1, otp_key_1);
if (OTP_EMTPY(OTP_KEY_2, 32)) {
mbedtls_ecdsa_context ecdsa;
size_t olen = 0;
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES];
while (olen != 32) {
mbedtls_ecdsa_init(&ecdsa);
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
mbedtls_ecdsa_genkey(&ecdsa, ec_id, random_gen, NULL);
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
mbedtls_ecdsa_free(&ecdsa);
}
ret = OTP_WRITE(OTP_KEY_2, pkey, olen);
if (ret != 0) {
printf("Error writing OTP key 2 [%d]\n", ret);
}
write_otp[1] = OTP_KEY_2;
}
OTP_READ(OTP_KEY_2, otp_key_2);
for (int i = 0; i < sizeof(write_otp)/sizeof(uint16_t); i++) {
if (write_otp[i] != 0xFFFF) {
#if defined(PICO_RP2350)
otp_lock_page(write_otp[i] >> 6);
#elif defined(ESP_PLATFORM)
ret = esp_efuse_set_key_dis_write(write_otp[i]);
if (ret != ESP_OK) {
printf("Error setting OTP key %d to read only [%d]\n", i, ret);
}
ret = esp_efuse_set_keypurpose_dis_write(write_otp[i]);
if (ret != ESP_OK) {
printf("Error setting OTP key %d purpose to read only [%d]\n", i, ret);
}
#endif
}
}
#endif // PICO_RP2350 || ESP_PLATFORM
#ifdef ENABLE_EMULATION
static uint8_t _otp1[32] = {0}, _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
otp_key_1 = _otp1;
otp_key_2 = _otp2;
#endif
}

51
src/fs/otp.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _OTP_H_
#define _OTP_H_
#ifdef PICO_RP2350
#define OTP_MKEK_ROW 0xEF0
#define OTP_DEVK_ROW 0xED0
#define OTP_KEY_1 OTP_MKEK_ROW
#define OTP_KEY_2 OTP_DEVK_ROW
extern uint8_t* otp_buffer(uint16_t row);
extern uint8_t* otp_buffer_raw(uint16_t row);
extern bool is_empty_otp_buffer(uint16_t row, uint16_t len);
extern int otp_write_data(uint16_t row, uint8_t *data, uint16_t len);
extern int otp_write_data_raw(uint16_t row, uint8_t *data, uint16_t len);
#elif defined(ESP_PLATFORM)
#include "esp_efuse.h"
#define OTP_KEY_1 EFUSE_BLK_KEY3
#define OTP_KEY_2 EFUSE_BLK_KEY4
#endif
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
extern void init_otp_files();
extern const uint8_t *otp_key_1;
extern const uint8_t *otp_key_2;
#endif // _OTP_H_

179
src/fs/phy.c Normal file
View File

@@ -0,0 +1,179 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#include "file.h"
#ifndef ENABLE_EMULATION
phy_data_t phy_data;
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
}
uint8_t *p = data;
if (phy->vidpid_present) {
*p++ = PHY_VIDPID;
*p++ = 4;
*p++ = phy->vidpid[1];
*p++ = phy->vidpid[0];
*p++ = phy->vidpid[3];
*p++ = phy->vidpid[2];
}
if (phy->led_gpio_present) {
*p++ = PHY_LED_GPIO;
*p++ = 1;
*p++ = phy->led_gpio;
}
if (phy->led_brightness_present) {
*p++ = PHY_LED_BTNESS;
*p++ = 1;
*p++ = phy->led_brightness;
}
*p++ = PHY_OPTS;
*p++ = 2;
p += put_uint16_t_be(phy->opts, p);
if (phy->up_btn_present) {
*p++ = PHY_UP_BTN;
*p++ = 1;
*p++ = phy->up_btn;
}
if (phy->usb_product_present) {
*p++ = PHY_USB_PRODUCT;
*p++ = strlen(phy->usb_product) + 1;
strcpy((char *)p, phy->usb_product);
p += strlen(phy->usb_product);
*p++ = '\0';
}
if (phy->enabled_curves_present) {
*p++ = PHY_ENABLED_CURVES;
*p++ = 4;
p += put_uint32_t_be(phy->enabled_curves, p);
}
if (phy->enabled_usb_itf_present) {
*p++ = PHY_ENABLED_USB_ITF;
*p++ = 1;
*p++ = phy->enabled_usb_itf;
}
*len = p - data;
return PICOKEY_OK;
}
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
}
const uint8_t *p = data;
uint8_t tag, tlen;
while (p < data + len) {
tag = *p++;
tlen = *p++;
switch (tag) {
case PHY_VIDPID:
if (tlen == 4) {
memcpy(phy->vidpid, p, 4);
phy->vidpid[1] = *p++;
phy->vidpid[0] = *p++;
phy->vidpid[3] = *p++;
phy->vidpid[2] = *p++;
phy->vidpid_present = true;
}
break;
case PHY_LED_GPIO:
if (tlen == 1) {
phy->led_gpio = *p++;
phy->led_gpio_present = true;
}
break;
case PHY_LED_BTNESS:
if (tlen == 1) {
phy->led_brightness = *p++;
phy->led_brightness_present = true;
}
break;
case PHY_OPTS:
if (tlen == 2) {
phy->opts = get_uint16_t_be(p);
p += 2;
}
break;
case PHY_UP_BTN:
if (tlen == 1) {
phy->up_btn = *p++;
phy->up_btn_present = true;
}
break;
case PHY_USB_PRODUCT:
if (tlen > 0 && tlen <= sizeof(phy->usb_product)) {
memset(phy->usb_product, 0, sizeof(phy->usb_product));
strlcpy(phy->usb_product, (const char *)p, sizeof(phy->usb_product));
phy->usb_product_present = true;
p += strlen(phy->usb_product) + 1;
}
break;
case PHY_ENABLED_CURVES:
if (tlen == 4) {
phy->enabled_curves = get_uint32_t_be(p);
p += 4;
phy->enabled_curves_present = true;
}
break;
case PHY_ENABLED_USB_ITF:
if (tlen == 1) {
phy->enabled_usb_itf = *p++;
phy->enabled_usb_itf_present = true;
}
break;
default:
p += tlen;
break;
}
}
if (!phy_data.enabled_usb_itf_present) {
phy_data.enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
phy_data.enabled_usb_itf_present = true;
}
return PICOKEY_OK;
}
int phy_init() {
memset(&phy_data, 0, sizeof(phy_data_t));
return phy_load();
}
int phy_save() {
uint8_t tmp[PHY_MAX_SIZE] = {0};
uint16_t tmp_len = 0;
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
if (ret != PICOKEY_OK) {
return ret;
}
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
return PICOKEY_OK;
}
int phy_load() {
if (file_has_data(ef_phy)) {
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
}
return PICOKEY_OK;
}
#endif

98
src/fs/phy.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _PHY_H_
#define _PHY_H_
#define EF_PHY 0xE020
#define PHY_VIDPID 0x0
#define PHY_LED_GPIO 0x4
#define PHY_LED_BTNESS 0x5
#define PHY_OPTS 0x6
#define PHY_UP_BTN 0x8
#define PHY_USB_PRODUCT 0x9
#define PHY_ENABLED_CURVES 0xA
#define PHY_ENABLED_USB_ITF 0xB
#define PHY_OPT_WCID 0x1
#define PHY_OPT_DIMM 0x2
#define PHY_OPT_DISABLE_POWER_RESET 0x4
#define PHY_OPT_LED_STEADY 0x8
#define PHY_CURVE_SECP256R1 0x1
#define PHY_CURVE_SECP384R1 0x2
#define PHY_CURVE_SECP521R1 0x4
#define PHY_CURVE_SECP256K1 0x8
#define PHY_CURVE_BP256R1 0x10
#define PHY_CURVE_BP384R1 0x20
#define PHY_CURVE_BP512R1 0x40
#define PHY_CURVE_ED25519 0x80
#define PHY_CURVE_ED448 0x100
#define PHY_CURVE_CURVE25519 0x200
#define PHY_CURVE_CURVE448 0x400
#define PHY_USB_ITF_CCID 0x1
#define PHY_USB_ITF_WCID 0x2
#define PHY_USB_ITF_HID 0x4
#define PHY_USB_ITF_KB 0x8
#include <stdint.h>
#include <stdbool.h>
typedef struct phy_data {
union {
struct {
uint16_t vid;
uint16_t pid;
};
uint8_t vidpid[4];
};
uint32_t enabled_curves;
char usb_product[32];
uint16_t opts;
uint8_t led_gpio;
uint8_t led_brightness;
uint8_t up_btn;
uint8_t enabled_usb_itf;
bool vidpid_present;
bool led_gpio_present;
bool led_brightness_present;
bool up_btn_present;
bool usb_product_present;
bool enabled_curves_present;
bool enabled_usb_itf_present;
} phy_data_t;
#define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1))
#ifndef ENABLE_EMULATION
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
extern int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
extern int phy_init();
extern int phy_save();
extern int phy_load();
extern phy_data_t phy_data;
#endif
#endif // _PHY_H_

5
src/idf_component.yml Executable file
View File

@@ -0,0 +1,5 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_tinyusb: "^1.7.2"
#espressif/tinyusb: "^0.15.0"
zorxx/neopixel: "^1.0.4"

95
src/led/led.c Normal file
View File

@@ -0,0 +1,95 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 <stdio.h>
#include <stdlib.h>
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "bsp/board.h"
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(ENABLE_EMULATION)
#include "emulation.h"
#endif
extern void led_driver_init();
extern void led_driver_color(uint8_t, uint32_t, float);
static uint32_t led_mode = MODE_NOT_MOUNTED;
void led_set_mode(uint32_t mode) {
led_mode = mode;
}
uint32_t led_get_mode() {
return led_mode;
}
void led_blinking_task() {
#ifndef ENABLE_EMULATION
static uint32_t start_ms = 0;
static uint32_t stop_ms = 0;
static uint32_t last_led_update_ms = 0;
static uint8_t led_state = false;
uint8_t state = led_state;
#ifdef PICO_DEFAULT_LED_PIN_INVERTED
state = !state;
#endif
uint32_t led_brightness = (led_mode & LED_BTNESS_MASK) >> LED_BTNESS_SHIFT;
uint32_t led_color = (led_mode & LED_COLOR_MASK) >> LED_COLOR_SHIFT;
uint32_t led_off = (led_mode & LED_OFF_MASK) >> LED_OFF_SHIFT;
uint32_t led_on = (led_mode & LED_ON_MASK) >> LED_ON_SHIFT;
float progress = 0;
if (stop_ms > start_ms) {
progress = (float)(board_millis() - start_ms) / (stop_ms - start_ms);
}
if (!state) {
progress = 1. - progress;
}
if (phy_data.opts & PHY_OPT_LED_STEADY) {
progress = 1;
}
// limit the frequency of LED status updates
if (board_millis() - last_led_update_ms > 2) {
led_driver_color(led_color, led_brightness, progress);
last_led_update_ms = board_millis();
}
if (board_millis() >= stop_ms){
start_ms = stop_ms;
led_state ^= 1; // toggle
stop_ms = start_ms + (led_state ? led_on : led_off);
}
#endif
}
void led_off_all() {
#ifndef ENABLE_EMULATION
led_driver_color(LED_COLOR_OFF, 0, 0);
#endif
}
void led_init() {
#ifndef ENABLE_EMULATION
led_driver_init();
led_set_mode(MODE_NOT_MOUNTED);
#endif
}

70
src/led/led.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _LED_H_
#define _LED_H_
#include <stdint.h>
enum {
LED_COLOR_OFF = 0,
LED_COLOR_RED,
LED_COLOR_GREEN,
LED_COLOR_BLUE,
LED_COLOR_YELLOW,
LED_COLOR_MAGENTA,
LED_COLOR_CYAN,
LED_COLOR_WHITE
};
#define LED_OFF_BITS 12
#define LED_OFF_SHIFT 0
#define LED_OFF_MASK (((1 << LED_OFF_BITS) - 1) << LED_OFF_SHIFT)
#define LED_ON_BITS 12
#define LED_ON_SHIFT LED_OFF_BITS
#define LED_ON_MASK (((1 << LED_ON_BITS) - 1) << LED_ON_SHIFT)
#define LED_COLOR_BITS 3
#define LED_COLOR_SHIFT (LED_ON_BITS + LED_OFF_BITS)
#define LED_COLOR_MASK (((1 << LED_COLOR_BITS) - 1) << LED_COLOR_SHIFT)
#define LED_BTNESS_BITS 4
#define LED_BTNESS_SHIFT (LED_ON_BITS + LED_OFF_BITS + LED_COLOR_BITS)
#define LED_BTNESS_MASK (((1 << LED_BTNESS_BITS) - 1 ) << LED_BTNESS_SHIFT)
#define MAX_BTNESS ((1 << LED_BTNESS_BITS) - 1)
#define HALF_BTNESS ((1 << (LED_BTNESS_BITS - 1)) - 1)
// steady on
#define LED_ON_NO_BLINK ((1000 << LED_ON_SHIFT) | (0 << LED_OFF_SHIFT))
enum {
MODE_NOT_MOUNTED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_RED << LED_COLOR_SHIFT) | (500 << LED_ON_SHIFT) | (500 << LED_OFF_SHIFT),
MODE_MOUNTED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_GREEN << LED_COLOR_SHIFT) | (500 << LED_ON_SHIFT) | (500 << LED_OFF_SHIFT),
MODE_SUSPENDED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_BLUE << LED_COLOR_SHIFT) | (1000 << LED_ON_SHIFT) | (2000 << LED_OFF_SHIFT),
MODE_PROCESSING = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_GREEN << LED_COLOR_SHIFT) | (50 << LED_ON_SHIFT) | (50 << LED_OFF_SHIFT),
MODE_BUTTON = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_YELLOW << LED_COLOR_SHIFT) | (1000 << LED_ON_SHIFT) | (100 << LED_OFF_SHIFT),
MODE_ALWAYS_ON = UINT32_MAX,
MODE_ALWAYS_OFF = 0
};
extern void led_set_mode(uint32_t mode);
extern uint32_t led_get_mode();
extern void led_blinking_task();
extern void led_off_all();
extern void led_init();
#endif // _LED_H_

37
src/led/led_cyw43.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#ifdef CYW43_WL_GPIO_LED_PIN
#include "pico/cyw43_arch.h"
void led_driver_init() {
cyw43_arch_init();
}
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
cyw43_arch_gpio_put(gpio, progress >= 0.5);
}
#endif

75
src/led/led_neopixel.c Normal file
View File

@@ -0,0 +1,75 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#ifdef ESP_PLATFORM
#include "driver/gpio.h"
#include "neopixel.h"
tNeopixelContext neopixel = NULL;
tNeopixel pixel[] = {
{ 0, NP_RGB(0, 0, 0) }, /* off */
{ 0, NP_RGB(255, 0, 0) }, /* red */
{ 0, NP_RGB(0, 255, 0) }, /* green */
{ 0, NP_RGB(0, 0, 255) }, /* blue */
{ 0, NP_RGB(255, 255, 0) }, /* yellow */
{ 0, NP_RGB(255, 0, 255) }, /* magenta */
{ 0, NP_RGB(0, 255, 255) }, /* cyan */
{ 0, NP_RGB(255, 255, 255) }, /* white */
};
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#define NEOPIXEL_PIN GPIO_NUM_48
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define NEOPIXEL_PIN GPIO_NUM_15
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define NEOPIXEL_PIN GPIO_NUM_8
#else
#define NEOPIXEL_PIN GPIO_NUM_27
#endif
void led_driver_init() {
uint8_t gpio = NEOPIXEL_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
neopixel = neopixel_Init(1, gpio);
}
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
static tNeopixel spx = {.index = 0, .rgb = 0};
if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0;
}
uint32_t led_phy_btness = phy_data.led_brightness_present ? phy_data.led_brightness : MAX_BTNESS;
float brightness = ((float)led_brightness / MAX_BTNESS) * ((float)led_phy_btness / MAX_BTNESS) * progress;
uint32_t pixel_color = pixel[color].rgb;
uint8_t r = (pixel_color >> 16) & 0xFF;
uint8_t g = (pixel_color >> 8) & 0xFF;
uint8_t b = (pixel_color) & 0xFF;
r = (uint8_t)(r * brightness);
g = (uint8_t)(g * brightness);
b = (uint8_t)(b * brightness);
spx.rgb = NP_RGB(r, g, b);
neopixel_SetPixel(neopixel, &spx, 1);
}
#endif

37
src/led/led_pico.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#if defined(PICO_DEFAULT_LED_PIN) && !defined(PICO_DEFAULT_WS2812_PIN) && !defined(PIMORONI_TINY2040) && !defined(PIMORONI_TINY2350)
uint8_t gpio = PICO_DEFAULT_LED_PIN;
void led_driver_init() {
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
}
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
gpio_put(gpio, progress >= 0.5);
}
#endif

61
src/led/led_pimoroni.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350)
#ifdef PIMORONI_TINY2040
#define LED_R_PIN TINY2040_LED_R_PIN
#define LED_G_PIN TINY2040_LED_G_PIN
#define LED_B_PIN TINY2040_LED_B_PIN
#elif defined(PIMORONI_TINY2350)
#define LED_R_PIN TINY2350_LED_R_PIN
#define LED_G_PIN TINY2350_LED_G_PIN
#define LED_B_PIN TINY2350_LED_B_PIN
#endif
uint8_t pixel[][3] = {
{1, 1, 1}, // 0: off
{0, 1, 1}, // 1: red
{1, 0, 1}, // 2: green
{1, 1, 0}, // 3: blue
{0, 0, 1}, // 4: yellow
{0, 1, 0}, // 5: magenta
{1, 0, 0}, // 6: cyan
{0, 0, 0} // 7: white
};
void led_driver_init() {
gpio_init(LED_R_PIN);
gpio_set_dir(LED_R_PIN, GPIO_OUT);
gpio_init(LED_G_PIN);
gpio_set_dir(LED_G_PIN, GPIO_OUT);
gpio_init(LED_B_PIN);
gpio_set_dir(LED_B_PIN, GPIO_OUT);
}
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
if (progress < 0.5) {
color = LED_COLOR_OFF;
}
gpio_put(LED_R_PIN, pixel[color][0]);
gpio_put(LED_G_PIN, pixel[color][1]);
gpio_put(LED_B_PIN, pixel[color][2]);
}
#endif

131
src/led/led_ws2812.c Normal file
View File

@@ -0,0 +1,131 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#ifdef PICO_DEFAULT_WS2812_PIN
#include "hardware/pio.h"
#include "hardware/clocks.h"
#define ws2812_wrap_target 0
#define ws2812_wrap 3
#define ws2812_pio_version 0
#define ws2812_T1 3
#define ws2812_T2 3
#define ws2812_T3 4
static const uint16_t ws2812_program_instructions[] = {
// .wrap_target
0x6321, // 0: out x, 1 side 0 [3]
0x1223, // 1: jmp !x, 3 side 1 [2]
0x1200, // 2: jmp 0 side 1 [2]
0xa242, // 3: nop side 0 [2]
// .wrap
};
static const struct pio_program ws2812_program = {
.instructions = ws2812_program_instructions,
.length = 4,
.origin = -1,
.pio_version = ws2812_pio_version,
#if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0
#endif
};
static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_config c = ws2812_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, pin);
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
void led_driver_init() {
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
uint8_t gpio = PICO_DEFAULT_WS2812_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
ws2812_program_init(pio, sm, offset, gpio, 800000, false);
}
struct urgb_color {
uint8_t r;
uint8_t g;
uint8_t b;
};
static struct urgb_color urgb_color_table[] = {
{0x00, 0x00, 0x00}, // 0: off LED_COLOR_OFF
{0xff, 0x00, 0x00}, // 1: red LED_COLOR_RED
{0x00, 0xff, 0x00}, // 2: green LED_COLOR_GREEN
{0x00, 0x00, 0xff}, // 3: blue LED_COLOR_BLUE
{0xff, 0xff, 0x00}, // 4: yellow LED_COLOR_YELLOW
{0xff, 0x00, 0xff}, // 5: magenta LED_COLOR_MAGENTA
{0x00, 0xff, 0xff}, // 6: cyan LED_COLOR_CYAN
{0xff, 0xff, 0xff} // 7: white LED_COLOR_WHITE
};
static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
return ((uint32_t) (r) << 8) | // For GRB data ordering WS2812
((uint32_t) (g) << 16) |
(uint32_t) (b);
#if 0 // TODO: How to adapt WS2812 with different data ordering ?
return ((uint32_t)(r) << 16) | // For RGB data ordering WS2812
((uint32_t)(g) << 8) |
(uint32_t)(b);
#endif
}
static inline void ws2812_put_pixel(uint32_t u32_pixel) {
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
}
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0;
}
uint32_t led_phy_btness = phy_data.led_brightness_present ? phy_data.led_brightness : MAX_BTNESS;
float brightness = ((float)led_brightness / MAX_BTNESS) * ((float)led_phy_btness / MAX_BTNESS) * progress;
struct urgb_color pixel_color = urgb_color_table[color];
pixel_color.r = (uint8_t)(pixel_color.r * brightness);
pixel_color.g = (uint8_t)(pixel_color.g * brightness);
pixel_color.b = (uint8_t)(pixel_color.b * brightness);
ws2812_put_pixel(urgb_u32(pixel_color.r, pixel_color.g, pixel_color.b));
}
#endif

368
src/main.c Normal file
View File

@@ -0,0 +1,368 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 <stdio.h>
#include <stdlib.h>
// Pico
#if defined(ENABLE_EMULATION)
#include "emulation.h"
#elif defined(ESP_PLATFORM)
#include "tusb.h"
#include "driver/gpio.h"
#include "rom/gpio.h"
#include "tinyusb.h"
#include "esp_efuse.h"
#define BOOT_PIN GPIO_NUM_0
#else
#include "pico/stdlib.h"
#include "bsp/board.h"
#include "pico/aon_timer.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/sio.h"
#endif
#include "random.h"
#include "pico_keys.h"
#include "apdu.h"
#include "usb.h"
extern void do_flash();
extern void low_flash_init();
extern void init_otp_files();
app_t apps[8];
uint8_t num_apps = 0;
app_t *current_app = NULL;
const uint8_t *ccid_atr = NULL;
bool app_exists(const uint8_t *aid, size_t aid_len) {
if (current_app && current_app->aid && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, aid_len))) {
return true;
}
for (int a = 0; a < num_apps; a++) {
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) {
return true;
}
}
return false;
}
int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
if (app_exists(aid + 1, aid[0])) {
return 1;
}
if (num_apps < sizeof(apps) / sizeof(app_t)) {
apps[num_apps].select_aid = select_aid;
apps[num_apps].aid = aid;
num_apps++;
return 1;
}
return 0;
}
int select_app(const uint8_t *aid, size_t aid_len) {
if (current_app && current_app->aid && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, aid_len))) {
current_app->select_aid(current_app, 0);
return PICOKEY_OK;
}
for (int a = 0; a < num_apps; a++) {
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) {
if (current_app) {
if (current_app->aid && !memcmp(current_app->aid + 1, aid, aid_len)) {
current_app->select_aid(current_app, 1);
return PICOKEY_OK;
}
if (current_app->unload) {
current_app->unload();
}
}
current_app = &apps[a];
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
return PICOKEY_OK;
}
}
}
return PICOKEY_ERR_FILE_NOT_FOUND;
}
int (*button_pressed_cb)(uint8_t) = NULL;
void execute_tasks();
static bool req_button_pending = false;
bool is_req_button_pending() {
return req_button_pending;
}
bool cancel_button = false;
#ifdef ENABLE_EMULATION
#ifdef _MSC_VER
#include <windows.h>
struct timezone
{
__int32 tz_minuteswest; /* minutes W of Greenwich */
bool tz_dsttime; /* type of dst correction */
};
int gettimeofday(struct timeval* tp, struct timezone* tzp)
{
(void)tzp;
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
// until 00:00:00 January 1, 1970
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}
#endif
#else
#ifdef ESP_PLATFORM
bool picok_board_button_read() {
int boot_state = gpio_get_level(BOOT_PIN);
return boot_state == 0;
}
#else
bool __no_inline_not_in_flash_func(picok_get_bootsel_button)() {
const uint CS_PIN_INDEX = 1;
// Must disable interrupts, as interrupt handlers may be in flash, and we
// are about to temporarily disable flash access!
uint32_t flags = save_and_disable_interrupts();
// Set chip select to Hi-Z
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
// Note we can't call into any sleep functions in flash right now
for (volatile int i = 0; i < 1000; ++i);
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
// Note the button pulls the pin *low* when pressed.
#if PICO_RP2040
#define CS_BIT (1u << 1)
#else
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
#endif
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
// Need to restore the state of chip select, else we are going to have a
// bad time when we return to code in flash!
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
restore_interrupts(flags);
return button_state;
}
uint32_t picok_board_button_read(void)
{
return picok_get_bootsel_button();
}
#endif
bool button_pressed_state = false;
uint32_t button_pressed_time = 0;
uint8_t button_press = 0;
bool wait_button() {
uint32_t button_timeout = 15000;
if (phy_data.up_btn_present) {
button_timeout = phy_data.up_btn * 1000;
if (button_timeout == 0) {
return false;
}
}
uint32_t start_button = board_millis();
bool timeout = false;
cancel_button = false;
uint32_t led_mode = led_get_mode();
led_set_mode(MODE_BUTTON);
req_button_pending = true;
while (picok_board_button_read() == false && cancel_button == false) {
execute_tasks();
//sleep_ms(10);
if (start_button + button_timeout < board_millis()) { /* timeout */
timeout = true;
break;
}
}
if (!timeout) {
while (picok_board_button_read() == true && cancel_button == false) {
execute_tasks();
//sleep_ms(10);
if (start_button + 15000 < board_millis()) { /* timeout */
timeout = true;
break;
}
}
}
led_set_mode(led_mode);
req_button_pending = false;
return timeout || cancel_button;
}
#endif
struct apdu apdu;
void init_rtc() {
#ifdef PICO_PLATFORM
struct timespec tv = {0};
tv.tv_sec = 1577836800; // 2020-01-01
aon_timer_start(&tv);
#endif
}
extern void neug_task();
extern void usb_task();
void execute_tasks()
{
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
tud_task(); // tinyusb device task
#endif
usb_task();
led_blinking_task();
}
void core0_loop() {
while (1) {
execute_tasks();
neug_task();
do_flash();
#ifndef ENABLE_EMULATION
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
bool current_button_state = picok_board_button_read();
if (current_button_state != button_pressed_state) {
if (current_button_state == false) { // unpressed
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
button_press++;
}
button_pressed_time = board_millis();
}
button_pressed_state = current_button_state;
}
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
if (button_pressed_cb != NULL) {
(*button_pressed_cb)(button_press);
}
button_pressed_time = button_press = 0;
}
}
#endif
#ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10));
#endif
}
}
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
pico_unique_board_id_t pico_serial;
#ifdef ESP_PLATFORM
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
extern tinyusb_config_t tusb_cfg;
extern const uint8_t desc_config[];
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
int app_main() {
#else
#ifdef ENABLE_EMULATION
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
#endif
int main(void) {
#endif
pico_get_unique_board_id(&pico_serial);
memset(pico_serial_str, 0, sizeof(pico_serial_str));
for (int i = 0; i < sizeof(pico_serial); i++) {
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
}
#ifndef ENABLE_EMULATION
#ifndef ESP_PLATFORM
board_init();
stdio_init_all();
#endif
#else
emul_init("127.0.0.1", 35963);
#endif
random_init();
init_otp_files();
low_flash_init();
scan_flash();
init_rtc();
#ifndef ENABLE_EMULATION
phy_init();
#endif
led_init();
usb_init();
#ifndef ENABLE_EMULATION
#ifdef ESP_PLATFORM
gpio_pad_select_gpio(BOOT_PIN);
gpio_set_direction(BOOT_PIN, GPIO_MODE_INPUT);
gpio_pulldown_dis(BOOT_PIN);
tusb_cfg.string_descriptor[3] = pico_serial_str;
if (phy_data.usb_product_present) {
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
}
static char tmps[4][32];
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
tusb_cfg.string_descriptor[i] = tmps[i-4];
}
tusb_cfg.configuration_descriptor = desc_config;
tinyusb_driver_install(&tusb_cfg);
#else
tusb_init();
#endif
#endif
#ifdef ESP_PLATFORM
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
#else
core0_loop();
#endif
return 0;
}

240
src/pico_keys.h Normal file
View File

@@ -0,0 +1,240 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _PICO_KEYS_H_
#define _PICO_KEYS_H_
#if defined(PICO_RP2040) || defined(PICO_RP2350)
#define PICO_PLATFORM
#endif
#include "file.h"
#include "led/led.h"
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#include <stdint.h>
#if !defined(MIN)
#if defined(_MSC_VER)
#define MIN(a,b) (((a)<(b))?(a):(b))
#else
#define MIN(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif
#endif
#if !defined(MAX)
#if defined(_MSC_VER)
#define MAX(a,b) (((a)>(b))?(a):(b))
#else
#define MAX(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#endif
#else
#include "pico/unique_id.h"
#endif
#include <string.h>
#include "debug.h"
#if defined(ENABLE_EMULATION)
#include <stdbool.h>
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#else
#include "pico/util/queue.h"
#endif
extern bool wait_button();
extern void low_flash_init_core1();
static inline uint16_t make_uint16_t_be(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline uint16_t make_uint16_t_le(uint8_t b1, uint8_t b2) {
return (b2 << 8) | b1;
}
static inline uint16_t get_uint16_t_be(const uint8_t *b) {
return make_uint16_t_be(b[0], b[1]);
}
static inline uint16_t get_uint16_t_le(const uint8_t *b) {
return make_uint16_t_le(b[0], b[1]);
}
static inline uint32_t put_uint16_t_be(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 2;
}
static inline uint32_t put_uint16_t_le(uint16_t n, uint8_t *b) {
*b++ = n & 0xff;
*b = (n >> 8) & 0xff;
return 2;
}
static inline uint32_t make_uint32_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
}
static inline uint32_t make_uint32_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}
static inline uint32_t get_uint32_t_be(const uint8_t *b) {
return make_uint32_t_be(b[0], b[1], b[2], b[3]);
}
static inline uint32_t get_uint32_t_le(const uint8_t *b) {
return make_uint32_t_le(b[0], b[1], b[2], b[3]);
}
static inline uint32_t put_uint32_t_be(uint32_t n, uint8_t *b) {
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 4;
}
static inline uint32_t put_uint32_t_le(uint32_t n, uint8_t *b) {
*b++ = n & 0xff;
*b++ = (n >> 8) & 0xff;
*b++ = (n >> 16) & 0xff;
*b = (n >> 24) & 0xff;
return 4;
}
static inline uint64_t make_uint64_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
return ((uint64_t) b1 << 56) | ((uint64_t) b2 << 48) | ((uint64_t) b3 << 40) | ((uint64_t) b4 << 32) | ((uint64_t) b5 << 24) | ((uint64_t) b6 << 16) | ((uint64_t) b7 << 8) | b8;
}
static inline uint64_t make_uint64_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
return ((uint64_t) b8 << 56) | ((uint64_t) b7 << 48) | ((uint64_t) b6 << 40) | ((uint64_t) b5 << 32) | ((uint64_t) b4 << 24) | ((uint64_t) b3 << 16) | ((uint64_t) b2 << 8) | b1;
}
static inline uint64_t get_uint64_t_be(const uint8_t *b) {
return make_uint64_t_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint64_t get_uint64_t_le(const uint8_t *b) {
return make_uint64_t_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint32_t put_uint64_t_be(uint64_t n, uint8_t *b) {
*b++ = (n >> 56) & 0xff;
*b++ = (n >> 48) & 0xff;
*b++ = (n >> 40) & 0xff;
*b++ = (n >> 32) & 0xff;
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 8;
}
static inline uint32_t put_uint64_t_le(uint64_t n, uint8_t *b) {
*b++ = n & 0xff;
*b++ = (n >> 8) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 32) & 0xff;
*b++ = (n >> 40) & 0xff;
*b++ = (n >> 48) & 0xff;
*b = (n >> 56) & 0xff;
return 8;
}
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern int (*button_pressed_cb)(uint8_t);
extern bool is_req_button_pending();
extern uint32_t button_timeout;
#define SW_BYTES_REMAINING_00() set_res_sw(0x61, 0x00)
#define SW_WARNING_STATE_UNCHANGED() set_res_sw(0x62, 0x00)
#define SW_WARNING_CORRUPTED() set_res_sw(0x62, 0x81)
#define SW_WARNING_EOF() set_res_sw(0x62, 0x82)
#define SW_WARNING_EF_DEACTIVATED() set_res_sw(0x62, 0x83)
#define SW_WARNING_WRONG_FCI() set_res_sw(0x62, 0x84)
#define SW_WARNING_EF_TERMINATED() set_res_sw(0x62, 0x85)
#define SW_WARNING_NOINFO() set_res_sw(0x63, 0x00)
#define SW_WARNING_FILLUP() set_res_sw(0x63, 0x81)
#define SW_EXEC_ERROR() set_res_sw(0x64, 0x00)
#define SW_MEMORY_FAILURE() set_res_sw(0x65, 0x81)
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw(0x66, 0x00)
#define SW_WRONG_LENGTH() set_res_sw(0x67, 0x00)
#define SW_WRONG_DATA() set_res_sw(0x67, 0x00)
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw(0x68, 0x81)
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw(0x68, 0x82)
#define SW_COMMAND_INCOMPATIBLE() set_res_sw(0x69, 0x81)
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw(0x69, 0x82)
#define SW_PIN_BLOCKED() set_res_sw(0x69, 0x83)
#define SW_DATA_INVALID() set_res_sw(0x69, 0x84)
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw(0x69, 0x85)
#define SW_COMMAND_NOT_ALLOWED() set_res_sw(0x69, 0x86)
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw(0x69, 0x87)
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw(0x69, 0x88)
#define SW_APPLET_SELECT_FAILED() set_res_sw(0x69, 0x99)
#define SW_INCORRECT_PARAMS() set_res_sw(0x6A, 0x80)
#define SW_FUNC_NOT_SUPPORTED() set_res_sw(0x6A, 0x81)
#define SW_FILE_NOT_FOUND() set_res_sw(0x6A, 0x82)
#define SW_RECORD_NOT_FOUND() set_res_sw(0x6A, 0x83)
#define SW_FILE_FULL() set_res_sw(0x6A, 0x84)
#define SW_WRONG_NE() set_res_sw(0x6A, 0x85)
#define SW_INCORRECT_P1P2() set_res_sw(0x6A, 0x86)
#define SW_WRONG_NC() set_res_sw(0x6A, 0x87)
#define SW_REFERENCE_NOT_FOUND() set_res_sw(0x6A, 0x88)
#define SW_FILE_EXISTS() set_res_sw(0x6A, 0x89)
#define SW_WRONG_P1P2() set_res_sw(0x6B, 0x00)
#define SW_CORRECT_LENGTH_00() set_res_sw(0x6C, 0x00)
#define SW_INS_NOT_SUPPORTED() set_res_sw(0x6D, 0x00)
#define SW_CLA_NOT_SUPPORTED() set_res_sw(0x6E, 0x00)
#define SW_UNKNOWN() set_res_sw(0x6F, 0x00)
#define SW_OK() set_res_sw(0x90, 0x00)
#define PICOKEY_OK 0
#define PICOKEY_ERR_NO_MEMORY -1000
#define PICOKEY_ERR_MEMORY_FATAL -1001
#define PICOKEY_ERR_NULL_PARAM -1002
#define PICOKEY_ERR_FILE_NOT_FOUND -1003
#define PICOKEY_ERR_BLOCKED -1004
#define PICOKEY_NO_LOGIN -1005
#define PICOKEY_EXEC_ERROR -1006
#define PICOKEY_WRONG_LENGTH -1007
#define PICOKEY_WRONG_DATA -1008
#define PICOKEY_WRONG_DKEK -1009
#define PICOKEY_WRONG_SIGNATURE -1010
#define PICOKEY_WRONG_PADDING -1011
#define PICOKEY_VERIFICATION_FAILED -1012
#define PICOKEY_CHECK(x) do { ret = (x); if (ret != PICOKEY_OK) goto err; } while (0)
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } pico_unique_board_id_t;
#endif
extern pico_unique_board_id_t pico_serial;
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
#endif

View File

@@ -1,27 +1,26 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 __VERSION_H_
#define __VERSION_H_
#define CCID_VERSION 0x0101
#define PICO_KEYS_SDK_VERSION 0x0700
#define CCID_VERSION_MAJOR ((CCID_VERSION >> 8) & 0xff)
#define CCID_VERSION_MINOR (CCID_VERSION & 0xff)
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
#endif

123
src/rescue.c Normal file
View File

@@ -0,0 +1,123 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "pico_keys.h"
#include "apdu.h"
#include "pico_keys_version.h"
#include "otp.h"
int rescue_process_apdu();
int rescue_unload();
const uint8_t rescue_aid[] = {
8,
0xA0, 0x58, 0x3F, 0xC1, 0x9B, 0x7E, 0x4F, 0x21
};
#ifdef PICO_RP2350
#define PICO_MCU 1
#elif defined(ESP_PLATFORM)
#define PICO_MCU 2
#elif defined(ENABLE_EMULATION)
#define PICO_MCU 3
#else
#define PICO_MCU 0
#endif
extern uint8_t PICO_PRODUCT;
int rescue_select(app_t *a, uint8_t force) {
a->process_apdu = rescue_process_apdu;
a->unload = rescue_unload;
res_APDU_size = 0;
res_APDU[res_APDU_size++] = PICO_MCU;
res_APDU[res_APDU_size++] = PICO_PRODUCT;
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MINOR;
apdu.ne = res_APDU_size;
if (force) {
scan_flash();
}
return PICOKEY_OK;
}
INITIALIZER ( rescue_ctor ) {
register_app(rescue_select, rescue_aid);
}
int rescue_unload() {
return PICOKEY_OK;
}
int cmd_write() {
if (apdu.nc < 2) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) { // PHY
#ifndef ENABLE_EMULATION
int ret = phy_unserialize_data(apdu.data, apdu.nc, &phy_data);
if (ret == PICOKEY_OK) {
if (phy_save() != PICOKEY_OK) {
return SW_EXEC_ERROR();
}
}
#endif
}
return SW_OK();
}
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
int cmd_secure() {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
uint8_t bootkey = P1(apdu);
bool secure_lock = P2(apdu) == 0x1;
int ret = otp_enable_secure_boot(bootkey, secure_lock);
if (ret != 0) {
return SW_EXEC_ERROR();
}
return SW_OK();
}
#endif
#define INS_WRITE 0x1C
#define INS_SECURE 0x1D
static const cmd_t cmds[] = {
{ INS_WRITE, cmd_write },
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
{ INS_SECURE, cmd_secure },
#endif
{ 0x00, 0x0 }
};
int rescue_process_apdu() {
if (CLA(apdu) != 0x80) {
return SW_CLA_NOT_SUPPORTED();
}
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) {
int r = cmd->cmd_handler();
return r;
}
}
return SW_INS_NOT_SUPPORTED();
}

View File

@@ -1,42 +1,45 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Part of the code is taken from GnuK (GPLv3)
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#if defined(ENABLE_EMULATION)
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include "emulation.h"
#elif (ESP_PLATFORM)
#include "bootloader_random.h"
#include "esp_random.h"
#include "esp_compat.h"
#else
#include "pico/stdlib.h"
#include "neug.h"
#include "hardware/structs/rosc.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "hwrng.h"
#include "bsp/board.h"
#include "pico/unique_id.h"
#include "pico/rand.h"
#endif
void adc_start() {
adc_init();
adc_gpio_init(27);
adc_select_input(1);
}
void adc_stop() {
void hwrng_start() {
#if defined(ENABLE_EMULATION)
srand(time(0));
#elif defined(ESP_PLATFORM)
bootloader_random_enable();
#endif
}
static uint64_t random_word = 0xcbf29ce484222325;
@@ -48,40 +51,36 @@ static void ep_init() {
}
/* Here, we assume a little endian architecture. */
static int ep_process () {
static int ep_process() {
if (ep_round == 0) {
ep_init();
}
uint64_t word = 0x0;
for (int n = 0; n < 64; n++) {
uint8_t bit1, bit2;
do
{
bit1 = rosc_hw->randombit&0xff;
//sleep_ms(1);
bit2 = rosc_hw->randombit&0xff;
} while(bit1 == bit2);
word = (word << 1) | bit1;
}
random_word ^= word^board_millis()^adc_read();
#if defined(ENABLE_EMULATION)
word = rand();
word <<= 32;
word |= rand();
#elif defined(ESP_PLATFORM)
esp_fill_random((uint8_t *)&word, sizeof(word));
#else
word = get_rand_64();
#endif
random_word ^= word ^ board_millis();
random_word *= 0x00000100000001B3;
if (++ep_round == 8) {
ep_round = 0;
return 2; //2 words
return 2; //2 words
}
return 0;
}
static const uint32_t *ep_output() {
return (uint32_t *)&random_word;
}
struct rng_rb {
uint32_t *buf;
uint8_t head, tail;
uint8_t size;
unsigned int full :1;
unsigned int empty :1;
unsigned int full : 1;
unsigned int empty : 1;
};
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
@@ -94,20 +93,24 @@ static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
static void rb_add(struct rng_rb *rb, uint32_t v) {
rb->buf[rb->tail++] = v;
if (rb->tail == rb->size)
if (rb->tail == rb->size) {
rb->tail = 0;
if (rb->tail == rb->head)
}
if (rb->tail == rb->head) {
rb->full = 1;
}
rb->empty = 0;
}
static uint32_t rb_del(struct rng_rb *rb) {
uint32_t v = rb->buf[rb->head++];
if (rb->head == rb->size)
if (rb->head == rb->size) {
rb->head = 0;
if (rb->head == rb->tail)
}
if (rb->head == rb->tail) {
rb->empty = 1;
}
rb->full = 0;
return v;
@@ -117,66 +120,69 @@ static struct rng_rb the_ring_buffer;
void *neug_task() {
struct rng_rb *rb = &the_ring_buffer;
int n;
if ((n = ep_process())) {
int i;
const uint32_t *vp;
vp = ep_output();
for (i = 0; i < n; i++) {
rb_add (rb, *vp++);
if (rb->full)
break;
}
}
int i;
const uint32_t *vp = (const uint32_t *) &random_word;
for (i = 0; i < n; i++) {
rb_add(rb, *vp++);
if (rb->full) {
break;
}
}
}
return NULL;
}
void neug_init(uint32_t *buf, uint8_t size) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
const uint32_t *u = (const uint32_t *)unique_id.id;
struct rng_rb *rb = &the_ring_buffer;
int i;
rb_init(rb, buf, size);
adc_start();
hwrng_start();
ep_init();
}
void neug_flush(void) {
struct rng_rb *rb = &the_ring_buffer;
while (!rb->empty)
rb_del (rb);
while (!rb->empty) {
rb_del(rb);
}
}
uint32_t neug_get(int kick) {
uint32_t neug_get() {
struct rng_rb *rb = &the_ring_buffer;
uint32_t v;
while (rb->empty)
while (rb->empty) {
neug_task();
}
v = rb_del(rb);
return v;
}
void neug_wait_full(void) { //should be called only on core1
void neug_wait_full() {
struct rng_rb *rb = &the_ring_buffer;
#ifndef ENABLE_EMULATION
#ifdef ESP_PLATFORM
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
#else
uint core = get_core_num();
#endif
#endif
while (!rb->full) {
sleep_ms(1);
#ifndef ENABLE_EMULATION
if (core == 1) {
sleep_ms(1);
}
else
#endif
neug_task();
}
}
void neug_fini(void) {
neug_get(1);
}

View File

@@ -1,17 +1,17 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -20,10 +20,14 @@
#define NEUG_PRE_LOOP 32
#include <stdlib.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#endif
void neug_init(uint32_t *buf, uint8_t size);
uint32_t neug_get();
void neug_flush(void);
void neug_wait_full(void);
void neug_fini(void);
void neug_wait_full();
#endif
#endif

View File

@@ -1,17 +1,17 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -19,91 +19,79 @@
#include <stdint.h>
#include <string.h>
#include "neug.h"
#include "hwrng.h"
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
void random_init(void) {
int i;
neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
neug_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++)
for (i = 0; i < NEUG_PRE_LOOP; i++) {
neug_get();
}
void random_fini(void) {
neug_fini ();
}
}
/*
* Return pointer to random 32-byte
*/
void random_bytes_free (const uint8_t *p);
void random_bytes_free(const uint8_t *p);
#define MAX_RANDOM_BUFFER 1024
const uint8_t * random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER)
const uint8_t *random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER) {
return NULL;
static uint32_t return_word[MAX_RANDOM_BUFFER/sizeof(uint32_t)];
for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full();
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *)random_word);
}
return (const uint8_t *)return_word;
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full();
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *) random_word);
}
return (const uint8_t *) return_word;
}
/*
* Free pointer to random 32-byte
*/
void random_bytes_free(const uint8_t *p) {
(void)p;
(void) p;
memset(random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush();
}
/*
* Return 4-byte salt
*/
void random_get_salt(uint8_t *p) {
uint32_t rnd;
rnd = neug_get();
memcpy(p, &rnd, sizeof (uint32_t));
rnd = neug_get();
memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
}
/*
* Random byte iterator
*/
int random_gen(void *arg, unsigned char *out, size_t out_len) {
uint8_t *index_p = (uint8_t *)arg;
uint8_t *index_p = (uint8_t *) arg;
uint8_t index = index_p ? *index_p : 0;
size_t n;
uint8_t n;
while (out_len) {
neug_wait_full();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len)
n = out_len;
if (n > out_len) {
n = (uint8_t)out_len;
}
memcpy(out, ((unsigned char *)random_word) + index, n);
memcpy(out, ((unsigned char *) random_word) + index, n);
out += n;
out_len -= n;
index += n;
if (index >= RANDOM_BYTES_LENGTH) {
index = 0;
neug_flush();
}
index = 0;
neug_flush();
}
}
if (index_p)
if (index_p) {
*index_p = index;
}
return 0;
}

View File

@@ -1,17 +1,17 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -19,20 +19,16 @@
#ifndef _RANDOM_H_
#define _RANDOM_H_
#include "stdlib.h"
#include "pico/stdlib.h"
#include <stdlib.h>
#include <stdint.h>
void random_init (void);
void random_fini (void);
void random_init(void);
/* 32-byte random bytes */
const uint8_t *random_bytes_get (size_t);
void random_bytes_free (const uint8_t *p);
/* 8-byte salt */
void random_get_salt (uint8_t *p);
const uint8_t *random_bytes_get(size_t);
void random_bytes_free(const uint8_t *p);
/* iterator returning a byta at a time */
int random_gen (void *arg, unsigned char *output, size_t output_len);
extern int random_gen(void *arg, unsigned char *output, size_t output_len);
#endif
#endif

View File

@@ -1,73 +0,0 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
* 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 _CCID_H_
#define _CCID_H_
struct ccid_class_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockSupport;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bclassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
} __attribute__ ((__packed__));
static const struct ccid_class_descriptor desc_ccid = {
.bLength = sizeof(struct ccid_class_descriptor),
.bDescriptorType = 0x21,
.bcdCCID = (0x0110),
.bMaxSlotIndex = 0,
.bVoltageSupport = 0x01, // 5.0V
.dwProtocols = (
0x01| // T=0
0x02), // T=1
.dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC),
.bNumClockSupport = 0,
.dwDataRate = (0x2580),
.dwMaxDataRate = (0x2580),
.bNumDataRatesSupported = 0,
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
.dwSynchProtocols = (0),
.dwMechanical = (0),
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
.dwMaxCCIDMessageLength = 65544+10,
.bClassGetResponse = 0xFF,
.bclassEnvelope = 0xFF,
.wLcdLayout = 0x0,
.bPINSupport = 0x0,
.bMaxCCIDBusySlots = 0x01,
};
#endif

464
src/usb/ccid/ccid.c Normal file
View File

@@ -0,0 +1,464 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "random.h"
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "bsp/board.h"
#endif
#ifndef ENABLE_EMULATION
#include "tusb.h"
#include "device/usbd_pvt.h"
#else
#include "emulation.h"
#endif
#include "ccid.h"
#include "usb_descriptors.h"
#include "apdu.h"
#include "usb.h"
#if MAX_RES_APDU_DATA_SIZE > MAX_CMD_APDU_DATA_SIZE
#define USB_BUF_SIZE (MAX_RES_APDU_DATA_SIZE + 20 + 9)
#else
#define USB_BUF_SIZE (MAX_CMD_APDU_DATA_SIZE + 20 + 9)
#endif
#define CCID_SET_PARAMS 0x61 /* non-ICCD command */
#define CCID_POWER_ON 0x62
#define CCID_POWER_OFF 0x63
#define CCID_SLOT_STATUS 0x65 /* non-ICCD command */
#define CCID_SECURE 0x69 /* non-ICCD command */
#define CCID_GET_PARAMS 0x6C /* non-ICCD command */
#define CCID_RESET_PARAMS 0x6D /* non-ICCD command */
#define CCID_XFR_BLOCK 0x6F
#define CCID_DATA_BLOCK_RET 0x80
#define CCID_SLOT_STATUS_RET 0x81 /* non-ICCD result */
#define CCID_PARAMS_RET 0x82 /* non-ICCD result */
#define CCID_SETDATARATEANDCLOCKFREQUENCY 0x73
#define CCID_SETDATARATEANDCLOCKFREQUENCY_RET 0x84
#define CCID_MSG_SEQ_OFFSET 6
#define CCID_MSG_STATUS_OFFSET 7
#define CCID_MSG_ERROR_OFFSET 8
#define CCID_MSG_CHAIN_OFFSET 9
#define CCID_MSG_DATA_OFFSET 10 /* == CCID_MSG_HEADER_SIZE */
#define CCID_MAX_MSG_DATA_SIZE USB_BUF_SIZE
#define CCID_STATUS_RUN 0x00
#define CCID_STATUS_PRESENT 0x01
#define CCID_STATUS_NOTPRESENT 0x02
#define CCID_CMD_STATUS_OK 0x00
#define CCID_CMD_STATUS_ERROR 0x40
#define CCID_CMD_STATUS_TIMEEXT 0x80
#define CCID_ERROR_XFR_OVERRUN 0xFC
/*
* Since command-byte is at offset 0,
* error with offset 0 means "command not supported".
*/
#define CCID_OFFSET_CMD_NOT_SUPPORTED 0
#define CCID_OFFSET_DATA_LEN 1
#define CCID_OFFSET_PARAM 8
#define CCID_THREAD_TERMINATED 0xffff
#define CCID_ACK_TIMEOUT 0x6600
PACK(
typedef struct {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t abRFU0;
uint16_t abRFU1;
uint8_t apdu; //Actually it is an array
}) ccid_header_t;
uint8_t ccid_status = 1;
#ifndef ENABLE_EMULATION
static uint8_t itf_num;
#endif
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
ccid_tx[itf].w_ptr += size + offset;
ccid_tx[itf].r_ptr += offset;
}
void ccid_write(uint8_t itf, uint16_t size) {
ccid_write_offset(itf, size, 0);
}
ccid_header_t **ccid_response = NULL;
ccid_header_t **ccid_resp_fast = NULL;
ccid_header_t **ccid_header = NULL;
uint8_t sc_itf_to_usb_itf(uint8_t itf) {
if (itf == ITF_SC_CCID) {
return ITF_CCID;
}
else if (itf == ITF_SC_WCID) {
return ITF_WCID;
}
return itf;
}
void ccid_init_buffers() {
if (ITF_SC_TOTAL == 0) {
return;
}
if (ccid_rx == NULL) {
ccid_rx = (usb_buffer_t *)calloc(ITF_SC_TOTAL, sizeof(usb_buffer_t));
}
if (ccid_tx == NULL) {
ccid_tx = (usb_buffer_t *)calloc(ITF_SC_TOTAL, sizeof(usb_buffer_t));
}
if (ccid_header == NULL) {
ccid_header = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
if (ccid_response == NULL) {
ccid_response = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
if (ccid_resp_fast == NULL) {
ccid_resp_fast = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
}
int driver_init_ccid(uint8_t itf) {
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr);
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
// apdu.header = &ccid_header->apdu;
ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr);
usb_set_timeout_counter(sc_itf_to_usb_itf(itf), 1500);
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
return PICOKEY_OK;
}
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
uint32_t len = tud_vendor_n_available(itf);
do {
uint16_t tlen = 0;
if (len > 0xFFFF) {
tlen = 0xFFFF;
}
else {
tlen = (uint16_t)len;
}
tlen = (uint16_t)tud_vendor_n_read(itf, ccid_rx[itf].buffer + ccid_rx[itf].w_ptr, tlen);
ccid_rx[itf].w_ptr += tlen;
driver_process_usb_packet_ccid(itf, tlen);
len -= tlen;
} while (len > 0);
}
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
if (*tx_buffer != 0x81) {
DEBUG_PAYLOAD(tx_buffer, buffer_size);
}
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
if (r > 0) {
tud_vendor_n_flush(itf);
ccid_tx[itf].r_ptr += (uint16_t)buffer_size;
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
}
}
#ifdef ENABLE_EMULATION
tud_vendor_tx_cb(itf, r);
#endif
return r;
}
int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
return driver_write_ccid(itf, buffer, buffer_size);
}
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
(void) rx_read;
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
driver_init_ccid(itf);
//printf("ccid_process %ld %d %x %x %d\n",ccid_header[itf]->dwLength,rx_read-10,ccid_header[itf]->bMessageType,ccid_header[itf]->bSeq,ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10);
if (ccid_header[itf]->dwLength <= (uint32_t)(ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10)){
ccid_rx[itf].r_ptr += (uint16_t)(ccid_header[itf]->dwLength + 10);
if (ccid_rx[itf].r_ptr >= ccid_rx[itf].w_ptr) {
ccid_rx[itf].r_ptr = ccid_rx[itf].w_ptr = 0;
}
size_t apdu_sent = 0;
if (ccid_header[itf]->bMessageType != CCID_SLOT_STATUS) {
DEBUG_PAYLOAD((uint8_t *)ccid_header[itf], ccid_header[itf]->dwLength + 10);
}
if (ccid_header[itf]->bMessageType == CCID_SLOT_STATUS) {
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
else if (ccid_header[itf]->bMessageType == CCID_POWER_ON) {
size_t size_atr = (ccid_atr ? ccid_atr[0] : 0);
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = (uint32_t)size_atr;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = 0;
ccid_resp_fast[itf]->abRFU1 = 0;
//printf("1 %x %x %x || %x %x %x\n",ccid_resp_fast->apdu,apdu.rdata,ccid_resp_fast,ccid_header,ccid_header->apdu,apdu.data);
memcpy(&ccid_resp_fast[itf]->apdu, ccid_atr + 1, size_atr);
if (ccid_status == 1) {
//card_start(apdu_thread);
}
ccid_status = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], (uint16_t)(size_atr + 10));
led_set_mode(MODE_MOUNTED);
}
else if (ccid_header[itf]->bMessageType == CCID_POWER_OFF) {
if (ccid_status == 0) {
//card_exit(0);
}
ccid_status = 1;
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
led_set_mode(MODE_SUSPENDED);
}
else if (ccid_header[itf]->bMessageType == CCID_SET_PARAMS ||
ccid_header[itf]->bMessageType == CCID_GET_PARAMS ||
ccid_header[itf]->bMessageType == CCID_RESET_PARAMS) {
/* Values from gnuk. Not specified in ICCD spec. */
const uint8_t params[] = {
0x11, /* bmFindexDindex */
0x10, /* bmTCCKST1 */
0xFE, /* bGuardTimeT1 */
0x55, /* bmWaitingIntegersT1 */
0x03, /* bClockStop */
0xFE, /* bIFSC */
0 /* bNadValue */
};
ccid_resp_fast[itf]->bMessageType = CCID_PARAMS_RET;
ccid_resp_fast[itf]->dwLength = sizeof(params);
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0x0100;
memcpy(&ccid_resp_fast[itf]->apdu, params, sizeof(params));
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], sizeof(params) + 10);
}
else if (ccid_header[itf]->bMessageType == CCID_SETDATARATEANDCLOCKFREQUENCY) {
ccid_resp_fast[itf]->bMessageType = CCID_SETDATARATEANDCLOCKFREQUENCY_RET;
ccid_resp_fast[itf]->dwLength = 8;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
memset(&ccid_resp_fast[itf]->apdu, 0, 8);
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 18);
}
else if (ccid_header[itf]->bMessageType == CCID_XFR_BLOCK) {
apdu.rdata = &ccid_response[itf]->apdu;
apdu_sent = apdu_process(itf, &ccid_header[itf]->apdu, (uint16_t)ccid_header[itf]->dwLength);
#ifndef ENABLE_EMULATION
if (apdu_sent > 0) {
card_start(sc_itf_to_usb_itf(itf), apdu_thread);
usb_send_event(EV_CMD_AVAILABLE);
}
#endif
}
return (uint16_t)apdu_sent;
}
}
return 0;
}
void driver_exec_timeout_ccid(uint8_t itf) {
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = CCID_CMD_STATUS_TIMEEXT;
ccid_resp_fast[itf]->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next) {
driver_exec_finished_cont_ccid(itf, size_next, 0);
}
void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset) {
ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr + offset);
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->dwLength = size_next;
ccid_response[itf]->bSlot = 0;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_response[itf]->abRFU0 = ccid_status;
ccid_response[itf]->abRFU1 = 0;
ccid_write_offset(itf, size_next+10, offset);
}
void ccid_task() {
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
int status = card_status(sc_itf_to_usb_itf(itf));
if (status == PICOKEY_OK) {
driver_exec_finished_ccid(itf, finished_data_size);
}
else if (status == PICOKEY_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf);
}
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
if (driver_write_ccid(itf, ccid_tx[itf].buffer + ccid_tx[itf].r_ptr, ccid_tx[itf].w_ptr - ccid_tx[itf].r_ptr) > 0) {
}
}
}
}
void ccid_init() {
ccid_init_buffers();
}
#ifndef ENABLE_EMULATION
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
(void) sent_bytes;
tud_vendor_n_write_flush(itf);
}
static void ccid_init_cb(void) {
vendord_init();
}
static void ccid_reset_cb(uint8_t rhport) {
itf_num = 0;
vendord_reset(rhport);
}
static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
uint8_t *itf_vendor = (uint8_t *) malloc(sizeof(uint8_t) * max_len);
TU_VERIFY( itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0);
//vendord_open expects a CLASS_VENDOR interface class
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + TUSB_SMARTCARD_CCID_EPS * sizeof(tusb_desc_endpoint_t);
memcpy(itf_vendor, itf_desc, sizeof(uint8_t) * max_len);
((tusb_desc_interface_t *) itf_vendor)->bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC;
#if TUSB_SMARTCARD_CCID_EPS == 3
((tusb_desc_interface_t *) itf_vendor)->bNumEndpoints -= 1;
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len - sizeof(tusb_desc_endpoint_t));
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)((uint8_t *)itf_desc + drv_len - sizeof(tusb_desc_endpoint_t));
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
uint8_t msg[] = { 0x50, 0x03 };
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg));
#else
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
#endif
free(itf_vendor);
TU_VERIFY(max_len >= drv_len, 0);
itf_num = itf_desc->bInterfaceNumber;
return drv_len;
}
// Support for parameterized reset via vendor interface control request
static bool ccid_control_xfer_cb(uint8_t __unused rhport,
uint8_t stage,
tusb_control_request_t const *request) {
// nothing to do with DATA & ACK stage
TU_LOG2("-------- CCID CTRL XFER\n");
if (stage != CONTROL_STAGE_SETUP) {
return true;
}
if (request->wIndex == itf_num) {
TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\n",
request->bmRequestType,
request->bRequest,
request->wValue,
request->wLength);
/*
#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL
if (request->bRequest == RESET_REQUEST_BOOTSEL) {
#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED
uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED;
#else
uint gpio_mask = 0u;
#endif
#if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED
if (request->wValue & 0x100) {
gpio_mask = 1u << (request->wValue >> 9u);
}
#endif
reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK);
// does not return, otherwise we'd return true
}
#endif
#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT
if (request->bRequest == RESET_REQUEST_FLASH) {
watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS);
return true;
}
#endif
*/
return true;
}
return false;
}
static bool ccid_xfer_cb(uint8_t rhport,
uint8_t ep_addr,
xfer_result_t result,
uint32_t xferred_bytes) {
//printf("------ CALLED XFER_CB\n");
return vendord_xfer_cb(rhport, ep_addr, result, xferred_bytes);
//return true;
}
static const usbd_class_driver_t ccid_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "CCID",
#endif
.init = ccid_init_cb,
.reset = ccid_reset_cb,
.open = ccid_open,
.control_xfer_cb = ccid_control_xfer_cb,
.xfer_cb = ccid_xfer_cb,
.sof = NULL
};
// Implement callback to add our custom driver
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
*driver_count = 1;
return &ccid_driver;
}
#endif

43
src/usb/ccid/ccid.h Normal file
View File

@@ -0,0 +1,43 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _CCID_H_
#define _CCID_H_
extern const uint8_t historical_bytes[];
#define MAX_CMD_APDU_DATA_SIZE (24 + 4 + 512 * 4)
#define MAX_RES_APDU_DATA_SIZE (5 + 9 + 512 * 4)
#define CCID_MSG_HEADER_SIZE 10
#define USB_LL_BUF_SIZE 64
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
extern const uint8_t *ccid_atr;
#endif //_CCID_H_

View File

@@ -0,0 +1,324 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _USB_COMMON_H
#define _USB_COMMON_H
#include "pico/types.h"
#include "hardware/structs/usb.h"
// bmRequestType bit definitions
#define USB_REQ_TYPE_STANDARD 0x00u
#define USB_REQ_TYPE_TYPE_MASK 0x60u
#define USB_REQ_TYPE_TYPE_CLASS 0x20u
#define USB_REQ_TYPE_TYPE_VENDOR 0x40u
#define USB_REQ_TYPE_RECIPIENT_MASK 0x1fu
#define USB_REQ_TYPE_RECIPIENT_DEVICE 0x00u
#define USB_REQ_TYPE_RECIPIENT_INTERFACE 0x01u
#define USB_REQ_TYPE_RECIPIENT_ENDPOINT 0x02u
#define USB_DIR_OUT 0x00u
#define USB_DIR_IN 0x80u
#define USB_TRANSFER_TYPE_CONTROL 0x0
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x1
#define USB_TRANSFER_TYPE_BULK 0x2
#define USB_TRANSFER_TYPE_INTERRUPT 0x3
#define USB_TRANSFER_TYPE_BITS 0x3
// Descriptor types
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_REQUEST_GET_STATUS 0x0
#define USB_REQUEST_CLEAR_FEATURE 0x01
#define USB_REQUEST_SET_FEATURE 0x03
#define USB_REQUEST_SET_ADDRESS 0x05
#define USB_REQUEST_GET_DESCRIPTOR 0x06
#define USB_REQUEST_SET_DESCRIPTOR 0x07
#define USB_REQUEST_GET_CONFIGURATION 0x08
#define USB_REQUEST_SET_CONFIGURATION 0x09
#define USB_REQUEST_GET_INTERFACE 0x0a
#define USB_REQUEST_SET_INTERFACE 0x0b
#define USB_REQUEST_SYNC_FRAME 0x0c
#define USB_REQUEST_MSC_GET_MAX_LUN 0xfe
#define USB_REQUEST_MSC_RESET 0xff
#define USB_FEAT_ENDPOINT_HALT 0x00
#define USB_FEAT_DEVICE_REMOTE_WAKEUP 0x01
#define USB_FEAT_TEST_MODE 0x02
#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
struct usb_setup_packet {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __packed;
struct usb_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
};
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __packed;
struct usb_configuration_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} __packed;
struct usb_interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} __packed;
struct usb_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} __packed;
struct usb_endpoint_descriptor_long {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bRefresh;
uint8_t bSyncAddr;
} __attribute__((packed));
struct ccid_class_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockSupport;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bclassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
} __attribute__((__packed__));
static const struct ccid_class_descriptor ccid_desc = {
.bLength = sizeof(struct ccid_class_descriptor),
.bDescriptorType = 0x21,
.bcdCCID = (0x0110),
.bMaxSlotIndex = 0,
.bVoltageSupport = 0x01, // 5.0V
.dwProtocols = (
0x01 | // T=0
0x02), // T=1
.dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC),
.bNumClockSupport = 0,
.dwDataRate = (0x2580),
.dwMaxDataRate = (0x2580),
.bNumDataRatesSupported = 0,
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
.dwSynchProtocols = (0),
.dwMechanical = (0),
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
.dwMaxCCIDMessageLength = 65544 + 10,
.bClassGetResponse = 0xFF,
.bclassEnvelope = 0xFF,
.wLcdLayout = 0x0,
.bPINSupport = 0x0,
.bMaxCCIDBusySlots = 0x01,
};
// Struct in which we keep the endpoint configuration
typedef void (*usb_ep_handler)(uint8_t *buf, uint16_t len);
struct usb_endpoint_configuration {
const struct usb_endpoint_descriptor *descriptor;
usb_ep_handler handler;
// Pointers to endpoint + buffer control registers
// in the USB controller DPSRAM
volatile uint32_t *endpoint_control;
volatile uint32_t *buffer_control;
volatile uint8_t *data_buffer;
// Toggle after each packet (unless replying to a SETUP)
uint8_t next_pid;
};
// Struct in which we keep the device configuration
struct usb_device_configuration {
const struct usb_device_descriptor *device_descriptor;
const struct usb_interface_descriptor *interface_descriptor;
const struct usb_configuration_descriptor *config_descriptor;
const struct ccid_class_descriptor *ccid_descriptor;
const unsigned char *lang_descriptor;
const unsigned char **descriptor_strings;
// USB num endpoints is 16
struct usb_endpoint_configuration endpoints[USB_NUM_ENDPOINTS];
};
#define EP0_IN_ADDR (USB_DIR_IN | 0)
#define EP0_OUT_ADDR (USB_DIR_OUT | 0)
#define EP1_OUT_ADDR (USB_DIR_OUT | 1)
#define EP2_IN_ADDR (USB_DIR_IN | 2)
// EP0 IN and OUT
static const struct usb_endpoint_descriptor ep0_out = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP0_OUT_ADDR, // EP number 0, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_CONTROL,
.wMaxPacketSize = 64,
.bInterval = 0
};
static const struct usb_endpoint_descriptor ep0_in = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP0_IN_ADDR, // EP number 0, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_CONTROL,
.wMaxPacketSize = 64,
.bInterval = 0
};
// Descriptors
static const struct usb_device_descriptor device_descriptor = {
.bLength = sizeof(struct usb_device_descriptor),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200, // USB 1.1 device
.bDeviceClass = 0, // Specified in interface descriptor
.bDeviceSubClass = 0, // No subclass
.bDeviceProtocol = 0, // No protocol
.bMaxPacketSize0 = 64, // Max packet size for ep0
.idVendor = 0x20a0, // Your vendor id
.idProduct = 0x4230, // Your product ID
.bcdDevice = 0x0101, // No device revision number
.iManufacturer = 1, // Manufacturer string index
.iProduct = 2, // Product string index
.iSerialNumber = 3, // No serial number
.bNumConfigurations = 1 // One configuration
};
static const struct usb_interface_descriptor interface_descriptor = {
.bLength = sizeof(struct usb_interface_descriptor),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2, // Interface has 2 endpoints
.bInterfaceClass = 0x0b, // Vendor specific endpoint
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 5
};
static const struct usb_endpoint_descriptor ep1_out = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP1_OUT_ADDR, // EP number 1, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 64,
.bInterval = 0
};
static const struct usb_endpoint_descriptor ep2_in = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP2_IN_ADDR, // EP number 2, IN from host (tx from device)
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 64,
.bInterval = 0
};
static const struct usb_configuration_descriptor config_descriptor = {
.bLength = sizeof(struct usb_configuration_descriptor),
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength = (sizeof(config_descriptor) +
sizeof(interface_descriptor) +
sizeof(ccid_desc) +
sizeof(ep1_out) +
sizeof(ep2_in)),
.bNumInterfaces = 1,
.bConfigurationValue = 1, // Configuration 1
.iConfiguration = 4, // No string
.bmAttributes = 0xa0, // attributes: self powered, no remote wakeup
.bMaxPower = 0x32 // 100ma
};
static const unsigned char lang_descriptor[] = {
4, // bLength
0x03, // bDescriptorType == String Descriptor
0x09, 0x04 // language id = us english
};
#define USB_REQ_CCID 0xA1
extern uint16_t usb_read(uint8_t *buffer, size_t buffer_size);
extern uint16_t usb_read_available();
extern uint32_t usb_write_offset(uint16_t size, uint16_t offset);
extern uint32_t usb_write(uint16_t size);
extern bool usb_is_configured();
extern void usb_init();
extern uint8_t *usb_get_rx();
extern uint32_t usb_send_tx_buffer();
extern uint8_t *usb_get_tx();
extern void usb_clear_rx();
extern bool usb_write_available();
extern uint32_t usb_write_flush();
#endif

View File

@@ -0,0 +1,343 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 "emulation.h"
#include <stdio.h>
#ifndef _MSC_VER
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <netinet/tcp.h>
typedef int socket_t;
#include <fcntl.h>
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
#else
#include <ws2tcpip.h>
#define O_NONBLOCK _O_NONBLOCK
#define close closesocket
typedef SOCKET socket_t;
typedef int socklen_t;
#define msleep Sleep
#pragma comment(lib, "Ws2_32.lib")
#endif
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "pico_keys.h"
#include "apdu.h"
#include "usb.h"
#include "ccid/ccid.h"
#include "hid/ctap_hid.h"
socket_t ccid_sock = 0;
socket_t hid_server_sock = 0;
socket_t hid_client_sock = INVALID_SOCKET;
extern uint8_t thread_type;
extern const uint8_t *cbor_data;
extern size_t cbor_len;
extern uint8_t cmd;
uint8_t emul_rx[USB_BUFFER_SIZE], emul_tx[USB_BUFFER_SIZE];
uint16_t emul_rx_size = 0, emul_tx_size = 0;
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
pthread_t hcore0, hcore1;
#ifndef _MSC_VER
int msleep(long msec) {
struct timespec ts;
int res;
if (msec < 0) {
errno = EINVAL;
return -1;
}
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
return res;
}
#endif
int emul_init(char *host, uint16_t port) {
struct sockaddr_in serv_addr;
fprintf(stderr, "\n Starting emulation envionrment\n");
#ifdef _MSC_VER
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("winsock initialization failure\n");
}
#endif
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
perror("inet_pton");
close(ccid_sock);
return -1;
}
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect");
close(ccid_sock);
return -1;
}
#ifdef _MSC_VER
unsigned long on = 1;
if (0 != ioctlsocket(ccid_sock, FIONBIO, &on)) {
perror("ioctlsocket FIONBIO");
}
#else
int x = fcntl(ccid_sock, F_GETFL, 0);
fcntl(ccid_sock, F_SETFL, x | O_NONBLOCK);
int flag = 1;
setsockopt(ccid_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
#endif
// HID server
socklen_t yes = 1;
uint16_t hid_port = port - 1;
struct sockaddr_in server_sockaddr;
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
return -1;
}
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
perror("setsockopt");
close(hid_server_sock);
return 1;
}
#if defined(HAVE_DECL_SO_NOSIGPIPE)
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_NOSIGPIPE, (void *) &yes, sizeof yes) != 0) {
perror("setsockopt");
close(hid_server_sock);
return 1;
}
#endif
memset(&server_sockaddr, 0, sizeof server_sockaddr);
server_sockaddr.sin_family = PF_INET;
server_sockaddr.sin_port = htons(hid_port);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
sizeof server_sockaddr) != 0) {
perror("bind");
close(hid_server_sock);
return 1;
}
if (listen(hid_server_sock, 0) != 0) {
perror("listen");
close(hid_server_sock);
return 1;
}
return 0;
}
socket_t get_sock_itf(uint8_t itf) {
#ifdef USB_ITF_CCID
if (itf == ITF_CCID) {
return ccid_sock;
}
#endif
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
return hid_client_sock;
}
#endif
return INVALID_SOCKET;
}
uint32_t tud_vendor_n_write(uint8_t itf, const uint8_t *buffer, uint32_t n) {
uint16_t ret = driver_write_emul(ITF_CCID, buffer, (uint16_t)n);
tud_vendor_tx_cb(itf, ret);
return ret;
}
#ifdef USB_ITF_HID
bool tud_hid_n_report(uint8_t itf, uint8_t report_id, const uint8_t *buffer, uint32_t n) {
(void) itf;
(void) report_id;
uint16_t ret = driver_write_emul(ITF_HID, buffer, (uint16_t)n);
return ret > 0;
}
#endif
uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
uint16_t size = htons(buffer_size);
socket_t sock = get_sock_itf(itf);
// DEBUG_PAYLOAD(buffer,buffer_size);
int ret = 0;
do {
ret = send(sock, (const char *)&size, sizeof(size), 0);
if (ret == SOCKET_ERROR) {
msleep(10);
}
} while (ret <= 0);
do {
ret = send(sock, (const char *)buffer, buffer_size, 0);
if (ret == SOCKET_ERROR) {
msleep(10);
}
} while (ret <= 0);
emul_tx_size = buffer_size;
return buffer_size;
}
void driver_exec_finished_cont_emul(uint8_t itf, uint16_t size_next, uint16_t offset) {
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_finished_cont_hid(itf, size_next, offset);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID) {
driver_write_emul(itf, emul_tx + offset, size_next);
}
#endif
}
uint16_t emul_read(uint8_t itf) {
/* First we look for a client */
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
struct sockaddr_in client_sockaddr;
socklen_t client_socklen = sizeof client_sockaddr;
int timeout;
struct pollfd pfd;
pfd.fd = hid_server_sock;
pfd.events = POLLIN;
pfd.revents = 0;
timeout = (0 * 1000 + 1000 / 1000);
if (poll(&pfd, 1, timeout) == -1) {
return 0;
}
if (pfd.revents & POLLIN) {
if (hid_client_sock > 0) {
close(hid_client_sock);
}
hid_client_sock = accept(hid_server_sock, (struct sockaddr *) &client_sockaddr, &client_socklen);
if (hid_client_sock != INVALID_SOCKET) {
printf("hid_client connected! %d\n", hid_client_sock);
}
}
/*if (send_buffer_size > 0) {
last_write_result[itf] = WRITE_PENDING;
tud_hid_report_complete_cb(ITF_HID, complete_report, complete_len);
}*/
}
#endif
socket_t sock = get_sock_itf(itf);
//printf("get_sockt itf %d - %d\n", itf, sock);
uint16_t len = 0;
fd_set input;
FD_ZERO(&input);
#ifdef _WIN32
__pragma(warning(push))
__pragma(warning(disable:4548))
#endif
FD_SET(sock, &input);
#ifdef _WIN32
__pragma(warning(pop))
#endif
struct timeval timeout;
int valread = 0;
timeout.tv_sec = 0;
timeout.tv_usec = 0 * 1000;
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
if (n == -1) {
//printf("read wrong [itf:%d]\n", itf);
//something wrong
}
else if (n == 0) {
//printf("read timeout [itf:%d]\n", itf);
}
if (FD_ISSET(sock, &input)) {
valread = recv(sock, (char *)&len, sizeof(len), 0);
len = ntohs(len);
if (len > 0) {
while (true) {
valread = recv(sock, (char *)emul_rx + emul_rx_size, len, 0);
if (valread > 0) {
if (len == 1) {
uint8_t c = emul_rx[0];
if (c == 4) {
driver_write_emul(itf, ccid_atr ? ccid_atr + 1 : NULL, ccid_atr ? ccid_atr[0] : 0);
}
}
#ifdef USB_ITF_CCID
else if (itf == ITF_CCID) {
uint16_t sent = 0;
DEBUG_PAYLOAD(emul_rx, len);
apdu.rdata = emul_tx;
if ((sent = apdu_process(itf, emul_rx, len)) > 0) {
process_apdu();
apdu_finish();
}
if (sent > 0) {
uint16_t ret = apdu_next();
DEBUG_PAYLOAD(apdu.rdata, ret);
driver_write_emul(itf, apdu.rdata, ret);
}
}
#endif
else {
emul_rx_size += valread;
}
return (uint16_t)emul_rx_size;
}
msleep(10);
}
}
}
//else
// printf("no input for sock %d - %d\n", itf, sock);
return emul_rx_size;
}
void emul_task() {
#ifdef USB_ITF_CCID
emul_read(ITF_CCID);
#endif
#ifdef USB_ITF_HID
emul_read(ITF_HID);
#endif
}

View File

@@ -0,0 +1,179 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _EMULATION_H_
#define _EMULATION_H_
#include <stdint.h>
#include <string.h>
#ifdef _MSC_VER
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <stdbool.h>
#define USB_BUFFER_SIZE 2048
extern int emul_init(char *host, uint16_t port);
extern uint8_t emul_rx[USB_BUFFER_SIZE];
extern uint16_t emul_rx_size, emul_tx_size;
extern uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
extern uint16_t emul_read(uint8_t itf);
static inline uint32_t board_millis() {
struct timeval start;
gettimeofday(&start, NULL);
return start.tv_sec * 1000 + start.tv_usec / 1000;
}
#ifdef USB_ITF_HID
typedef uint8_t hid_report_type_t;
#endif
#ifdef USB_ITF_CCID
static inline uint32_t tud_vendor_n_available(uint8_t itf) {
(void) itf;
return emul_rx_size;
}
static inline uint32_t tud_vendor_n_read(uint8_t itf, uint8_t *buffer, uint32_t n) {
(void) itf;
if (n > emul_rx_size) {
n = emul_rx_size;
}
memcpy(buffer, emul_rx, n);
emul_rx_size = 0;
return n;
}
extern void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
extern uint32_t tud_vendor_n_write(uint8_t itf, const uint8_t *buffer, uint32_t n);
static inline uint32_t tud_vendor_n_flush(uint8_t itf) {
(void) itf;
return emul_tx_size;
}
#endif
#ifdef USB_ITF_HID
extern void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len);
extern bool tud_hid_n_report(uint8_t itf, uint8_t report_id, const uint8_t *buffer, uint32_t n);
#endif
#include <pthread.h>
#include <semaphore.h>
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cnd;
size_t size_elem;
size_t num_elem;
size_t max_elem;
uint8_t buf[1024];
bool is_init;
} queue_t;
static inline void queue_free(queue_t *a) {
pthread_mutex_destroy(&a->mtx);
pthread_cond_destroy(&a->cnd);
a->is_init = false;
}
static inline void queue_init(queue_t *a, size_t size_elem, size_t max_elem) {
if (a->is_init) {
queue_free(a);
}
pthread_mutex_init(&a->mtx, NULL);
pthread_cond_init(&a->cnd, NULL);
a->size_elem = size_elem;
a->max_elem = max_elem;
a->num_elem = 0;
a->is_init = true;
}
static inline void queue_add_blocking(queue_t *a, const void *b) {
pthread_mutex_lock(&a->mtx);
while (a->num_elem == a->max_elem) {
pthread_cond_wait(&a->cnd, &a->mtx);
}
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
a->num_elem++;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
}
static inline void queue_remove_blocking(queue_t *a, void *b) {
pthread_mutex_lock(&a->mtx);
while (a->num_elem == 0) {
pthread_cond_wait(&a->cnd, &a->mtx);
}
memcpy(b, a->buf, a->size_elem);
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
a->num_elem--;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
}
static inline int queue_try_add(queue_t *a, const void *b) {
pthread_mutex_lock(&a->mtx);
if (a->num_elem == a->max_elem) {
pthread_mutex_unlock(&a->mtx);
return 0;
}
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
a->num_elem++;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
return 1;
}
static inline int queue_try_remove(queue_t *a, void *b) {
pthread_mutex_lock(&a->mtx);
if (a->num_elem == 0) {
pthread_mutex_unlock(&a->mtx);
return 0;
}
memcpy(b, a->buf, a->size_elem);
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
a->num_elem--;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
return 1;
}
static inline int queue_is_empty(queue_t *a) {
pthread_mutex_lock(&a->mtx);
bool ret = a->num_elem == 0;
pthread_mutex_unlock(&a->mtx);
return ret;
}
static inline int queue_is_full(queue_t *a) {
pthread_mutex_lock(&a->mtx);
bool ret = a->num_elem == a->max_elem;
pthread_mutex_unlock(&a->mtx);
return ret;
}
static inline void queue_clear(queue_t *a) {
pthread_mutex_lock(&a->mtx);
a->num_elem = 0;
pthread_mutex_unlock(&a->mtx);
}
extern pthread_t hcore0, hcore1;
#define multicore_launch_core1(a) pthread_create(&hcore1, NULL, (void *(*) (void *))a, NULL)
#define multicore_reset_core1()
typedef pthread_mutex_t mutex_t;
typedef sem_t semaphore_t;
#define mutex_init(a) pthread_mutex_init(a, NULL)
#define mutex_try_enter(a,b) (pthread_mutex_trylock(a) == 0)
#define mutex_enter_blocking(a) pthread_mutex_lock(a)
#define mutex_exit(a) pthread_mutex_unlock(a)
#define sem_release(a) sem_post(a)
#define sem_acquire_blocking(a) sem_wait(a)
#define multicore_lockout_victim_init() (void)0
#endif // _EMULATION_H_

168
src/usb/hid/ctap_hid.h Normal file
View File

@@ -0,0 +1,168 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _CTAP_HID_H_
#define _CTAP_HID_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "usb.h"
// Size of HID reports
#define HID_RPT_SIZE 64 // Default size of raw HID report
// Frame layout - command- and continuation frames
#define CID_BROADCAST 0xffffffff // Broadcast channel id
#define TYPE_MASK 0x80 // Frame type mask
#define TYPE_INIT 0x80 // Initial frame identifier
#define TYPE_CONT 0x00 // Continuation frame identifier
PACK(
typedef struct {
uint32_t cid; // Channel identifier
union {
uint8_t type; // Frame type - b7 defines type
struct {
uint8_t cmd; // Command - b7 set
uint8_t bcnth; // Message byte count - high part
uint8_t bcntl; // Message byte count - low part
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
} init;
struct {
uint8_t seq; // Sequence number - b7 cleared
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
} cont;
};
}) CTAPHID_FRAME;
extern CTAPHID_FRAME *ctap_req, *ctap_resp;
#define FRAME_TYPE(f) ((f)->type & TYPE_MASK)
#define FRAME_CMD(f) ((f)->init.cmd & ~TYPE_MASK)
#define MSG_LEN(f) ((f)->init.bcnth * 256 + (f)->init.bcntl)
#define FRAME_SEQ(f) ((f)->cont.seq & ~TYPE_MASK)
// HID usage- and usage-page definitions
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
#define FIDO_USAGE_CTAPHID 0x01 // CTAPHID usage for top-level collection
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
// General constants
#define CTAPHID_IF_VERSION 2 // Current interface implementation version
#define CTAPHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
// CTAPHID native commands
#define CTAPHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
#define CTAPHID_MSG (TYPE_INIT | 0x03) // Send CTAP message frame
#define CTAPHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
#define CTAPHID_INIT (TYPE_INIT | 0x06) // Channel initialization
#define CTAPHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
#define CTAPHID_CBOR (TYPE_INIT | 0x10) // CBOR
#define CTAPHID_CANCEL (TYPE_INIT | 0x11) // Cancel any request
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3B) // Keepalive command
#define CTAPHID_SYNC (TYPE_INIT | 0x3C) // Protocol resync command
#define CTAPHID_ERROR (TYPE_INIT | 0x3F) // Error response
#define CTAPHID_UPDATE (TYPE_INIT | 0x51)
#define CTAPHID_REBOOT (TYPE_INIT | 0x53)
#define CTAPHID_RNG (TYPE_INIT | 0x60)
#define CTAPHID_VERSION (TYPE_INIT | 0x61)
#define CTAPHID_UUID (TYPE_INIT | 0x62)
#define CTAPHID_LOCKED (TYPE_INIT | 0x63)
#define CTAPHID_OTP (TYPE_INIT | 0x70)
#define CTAPHID_PROVISIONER (TYPE_INIT | 0x71)
#define CTAPHID_ADMIN (TYPE_INIT | 0x72)
#define CTAPHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
#define CTAPHID_VENDOR_LAST (TYPE_INIT | 0x7F) // Last vendor defined command
// CTAP_KEEPALIVE command defines
#define KEEPALIVE_STATUS_PROCESSING 0x1
#define KEEPALIVE_STATUS_UPNEEDED 0x2
// CTAPHID_INIT command defines
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
#define CAPFLAG_WINK 0x01 // Device supports WINK command
#define CAPFLAG_CBOR 0x04 // Device supports CBOR command
PACK(
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
}) CTAPHID_INIT_REQ;
PACK(
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
uint32_t cid; // Channel identifier
uint8_t versionInterface; // Interface version
uint8_t versionMajor; // Major version number
uint8_t versionMinor; // Minor version number
uint8_t versionBuild; // Build version number
uint8_t capFlags; // Capabilities flags
}) CTAPHID_INIT_RESP;
// CTAPHID_SYNC command defines
typedef struct {
uint8_t nonce; // Client application nonce
} CTAPHID_SYNC_REQ;
typedef struct {
uint8_t nonce; // Client application nonce
} CTAPHID_SYNC_RESP;
// Low-level error codes. Return as negatives.
#define CTAP_MAX_PACKET_SIZE (64 - 7 + 128 * (64 - 5))
#define CTAP_MAX_CBOR_PAYLOAD (USB_BUFFER_SIZE - 64 - 7 - 1)
#define CTAP1_ERR_NONE 0x00 // No error
#define CTAP1_ERR_INVALID_CMD 0x01 // Invalid command
#define CTAP1_ERR_INVALID_PARAMETER 0x02 // Invalid parameter
#define CTAP1_ERR_INVALID_LEN 0x03 // Invalid message length
#define CTAP1_ERR_INVALID_SEQ 0x04 // Invalid message sequencing
#define CTAP1_ERR_MSG_TIMEOUT 0x05 // Message has timed out
#define CTAP1_ERR_CHANNEL_BUSY 0x06 // Channel busy
#define CTAP1_ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
#define CTAP1_ERR_INVALID_CHANNEL 0x0b // CID not valid
#define CTAP1_ERR_OTHER 0x7f // Other unspecified error
extern void add_keyboard_buffer(const uint8_t *, size_t, bool);
extern void append_keyboard_buffer(const uint8_t *data, size_t data_len);
extern bool is_nitrokey;
#ifdef __cplusplus
}
#endif
#endif // _CTAP_HID_H_

652
src/usb/hid/hid.c Normal file
View File

@@ -0,0 +1,652 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 ENABLE_EMULATION
#include "tusb.h"
#ifndef ESP_PLATFORM
#include "bsp/board.h"
#else
static portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED;
#endif
#else
#include "emulation.h"
#endif
#include "ctap_hid.h"
#include "pico_keys.h"
#include "pico_keys_version.h"
#include "apdu.h"
#include "usb.h"
static bool mounted = false;
extern void init_fido();
bool is_nitrokey = false;
uint8_t (*get_version_major)() = NULL;
uint8_t (*get_version_minor)() = NULL;
static usb_buffer_t *hid_rx = NULL, *hid_tx = NULL;
PACK(
typedef struct msg_packet {
uint16_t len;
uint16_t current_len;
uint8_t data[CTAP_MAX_PACKET_SIZE];
}) msg_packet_t;
msg_packet_t msg_packet = { 0 };
void tud_mount_cb() {
mounted = true;
}
bool driver_mounted_hid() {
return mounted;
}
static uint16_t *send_buffer_size = NULL;
static write_status_t *last_write_result = NULL;
CTAPHID_FRAME *ctap_req = NULL, *ctap_resp = NULL;
void send_keepalive();
int driver_process_usb_packet_hid(uint16_t read);
int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
int driver_process_usb_nopacket_hid();
void hid_init() {
if (ITF_HID_TOTAL == 0) {
return;
}
if (send_buffer_size == NULL) {
send_buffer_size = (uint16_t *)calloc(ITF_HID_TOTAL, sizeof(uint16_t));
}
if (last_write_result == NULL) {
last_write_result = (write_status_t *)calloc(ITF_HID_TOTAL, sizeof(write_status_t));
}
if (hid_rx == NULL) {
hid_rx = (usb_buffer_t *)calloc(ITF_HID_TOTAL, sizeof(usb_buffer_t));
}
if (hid_tx == NULL) {
hid_tx = (usb_buffer_t *)calloc(ITF_HID_TOTAL, sizeof(usb_buffer_t));
}
}
int driver_init_hid() {
#ifndef ENABLE_EMULATION
static bool _init = false;
if (_init == false) {
tud_init(BOARD_TUD_RHPORT);
_init = true;
}
#endif
ctap_req = (CTAPHID_FRAME *) (hid_rx[ITF_HID_CTAP].buffer + hid_rx[ITF_HID_CTAP].r_ptr);
apdu.header = ctap_req->init.data;
ctap_resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer);
apdu.rdata = ctap_resp->init.data;
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
usb_set_timeout_counter(ITF_HID, 200);
is_nitrokey = false;
hid_tx[ITF_HID_CTAP].w_ptr = hid_tx[ITF_HID_CTAP].r_ptr = 0;
send_buffer_size[ITF_HID_CTAP] = 0;
return 0;
}
uint16_t *get_send_buffer_size(uint8_t itf) {
return &send_buffer_size[itf];
}
//--------------------------------------------------------------------+
// USB HID
//--------------------------------------------------------------------+
uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t) = NULL;
// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
printf("get_report %d %d %d\n", itf, report_id, report_type);
memset(buffer, 0, reqlen);
DEBUG_PAYLOAD(buffer, reqlen);
if (hid_get_report_cb) {
hid_get_report_cb(itf, report_id, report_type, buffer, reqlen);
}
return reqlen;
}
uint32_t hid_write_offset(uint16_t size, uint16_t offset) {
if (hid_tx[ITF_HID_CTAP].buffer[offset] != 0x81) {
DEBUG_PAYLOAD(&hid_tx[ITF_HID_CTAP].buffer[offset], size);
}
hid_tx[ITF_HID_CTAP].w_ptr += size + offset;
hid_tx[ITF_HID_CTAP].r_ptr += offset;
return size;
}
uint32_t hid_write(uint16_t size) {
return hid_write_offset(size, 0);
}
#ifndef ENABLE_EMULATION
static uint8_t keyboard_buffer[256];
static uint8_t keyboard_buffer_len = 0;
static const uint8_t conv_table[128][2] = { HID_ASCII_TO_KEYCODE };
static uint8_t keyboard_w = 0;
static bool sent_key = false;
static bool keyboard_encode = false;
void add_keyboard_buffer(const uint8_t *data, size_t data_len, bool encode) {
keyboard_buffer_len = MIN(sizeof(keyboard_buffer), data_len);
memcpy(keyboard_buffer, data, keyboard_buffer_len);
keyboard_encode = encode;
}
void append_keyboard_buffer(const uint8_t *data, size_t data_len) {
if (keyboard_buffer_len + data_len < sizeof(keyboard_buffer)) {
memcpy(keyboard_buffer + keyboard_buffer_len, data, MIN(sizeof(keyboard_buffer) - keyboard_buffer_len, data_len));
keyboard_buffer_len += MIN(sizeof(keyboard_buffer) - keyboard_buffer_len, data_len);
}
}
static void send_hid_report(uint8_t report_id) {
if (!tud_hid_ready()) {
return;
}
switch (report_id) {
case REPORT_ID_KEYBOARD: {
if (keyboard_w < keyboard_buffer_len) {
if (sent_key == false) {
uint8_t keycode[6] = { 0 };
uint8_t modifier = 0;
uint8_t chr = keyboard_buffer[keyboard_w];
if (keyboard_encode) {
if (conv_table[chr][0]) {
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
}
keycode[0] = conv_table[chr][1];
}
else {
if (chr & 0x80) {
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
}
keycode[0] = chr & 0x7f;
}
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, modifier, keycode) == true) {
sent_key = true;
}
}
else {
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, 0, NULL) == true) {
keyboard_w++;
sent_key = false;
}
}
}
else if (keyboard_w == keyboard_buffer_len && keyboard_buffer_len > 0) {
keyboard_w = keyboard_buffer_len = 0;
}
}
break;
default: break;
}
}
#endif
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) {
//printf("report_complete %d %d %d\n", instance, len, send_buffer_size[instance]);
if (instance == ITF_HID_CTAP && len > 0) {
#ifdef ESP_PLATFORM
taskENTER_CRITICAL(&mutex);
#endif
CTAPHID_FRAME *req = (CTAPHID_FRAME *) report;
if (last_write_result[instance] == WRITE_PENDING) {
last_write_result[instance] = WRITE_SUCCESS;
if (FRAME_TYPE(req) == TYPE_INIT) {
if (req->init.cmd != CTAPHID_KEEPALIVE) {
send_buffer_size[instance] -= MIN(64 - 7, send_buffer_size[instance]);
}
}
else {
send_buffer_size[instance] -= MIN(64 - 5, send_buffer_size[instance]);
}
}
if (last_write_result[instance] == WRITE_SUCCESS) {
if (FRAME_TYPE(req) != TYPE_INIT || req->init.cmd != CTAPHID_KEEPALIVE) {
if (send_buffer_size[instance] > 0) {
ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
uint8_t seq = FRAME_TYPE(req) == TYPE_INIT ? 0 : FRAME_SEQ(req) + 1;
ctap_resp->cid = req->cid;
ctap_resp->cont.seq = seq;
hid_tx[ITF_HID_CTAP].r_ptr += 64 - 5;
}
else {
hid_tx[ITF_HID_CTAP].r_ptr += 64;
}
}
}
if (hid_tx[ITF_HID_CTAP].r_ptr >= hid_tx[ITF_HID_CTAP].w_ptr) {
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
}
#ifdef ESP_PLATFORM
taskEXIT_CRITICAL(&mutex);
#endif
}
}
int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
if (last_write_result[itf] == WRITE_PENDING) {
return 0;
}
bool r = tud_hid_n_report(itf, 0, buffer, buffer_size);
last_write_result[itf] = r ? WRITE_PENDING : WRITE_FAILED;
if (last_write_result[itf] == WRITE_FAILED) {
return 0;
}
#ifdef ENABLE_EMULATION
tud_hid_report_complete_cb(ITF_HID_CTAP, buffer, buffer_size);
#endif
return MIN(64, buffer_size);
}
int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t) = NULL;
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
// This example doesn't use multiple report and report ID
(void) itf;
(void) report_id;
(void) report_type;
printf("set_report %d %d %d\n", itf, report_id, report_type);
if (!hid_set_report_cb || hid_set_report_cb(itf, report_id, report_type, buffer, bufsize) == 0) {
//usb_rx(itf, buffer, bufsize);
memcpy(hid_rx[itf].buffer + hid_rx[itf].w_ptr, buffer, bufsize);
hid_rx[itf].w_ptr += bufsize;
int proc_pkt = driver_process_usb_packet_hid(64);
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
}
}
uint32_t last_cmd_time = 0, last_packet_time = 0;
int ctap_error(uint8_t error) {
memset((uint8_t *)ctap_resp, 0, sizeof(CTAPHID_FRAME));
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = CTAPHID_ERROR;
ctap_resp->init.bcntl = 1;
ctap_resp->init.data[0] = error;
hid_write(64);
last_packet_time = 0;
return 0;
}
uint8_t last_cmd = 0;
uint8_t last_seq = 0;
CTAPHID_FRAME last_req = { 0 };
uint32_t lock = 0;
uint8_t thread_type = 0; //1 is APDU, 2 is CBOR
extern bool cancel_button;
extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len);
int driver_process_usb_nopacket_hid() {
if (last_packet_time > 0 && last_packet_time + 500 < board_millis()) {
ctap_error(CTAP1_ERR_MSG_TIMEOUT);
last_packet_time = 0;
msg_packet.len = msg_packet.current_len = 0;
}
return 0;
}
extern const uint8_t fido_aid[], u2f_aid[];
extern void apdu_thread(void), cbor_thread(void);
int driver_process_usb_packet_hid(uint16_t read) {
int apdu_sent = 0;
if (read >= 5) {
driver_init_hid();
hid_rx[ITF_HID_CTAP].r_ptr += 64;
if (hid_rx[ITF_HID_CTAP].r_ptr >= hid_rx[ITF_HID_CTAP].w_ptr) {
hid_rx[ITF_HID_CTAP].r_ptr = hid_rx[ITF_HID_CTAP].w_ptr = 0;
}
last_packet_time = board_millis();
DEBUG_PAYLOAD((uint8_t *)ctap_req, 64);
if (ctap_req->cid == 0x0 ||
(ctap_req->cid == CID_BROADCAST && (FRAME_TYPE(ctap_req) != TYPE_INIT || ctap_req->init.cmd != CTAPHID_INIT))) {
return ctap_error(CTAP1_ERR_INVALID_CHANNEL);
}
if (board_millis() < lock && ctap_req->cid != last_req.cid &&
last_cmd_time + 100 > board_millis()) {
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
if (FRAME_TYPE(ctap_req) == TYPE_INIT) {
if (MSG_LEN(ctap_req) > CTAP_MAX_PACKET_SIZE) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
if (msg_packet.len > 0 && last_cmd_time + 100 > board_millis() &&
ctap_req->init.cmd != CTAPHID_INIT) {
if (last_req.cid != ctap_req->cid) { //We are in a transaction
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
else {
return ctap_error(CTAP1_ERR_INVALID_SEQ);
}
}
printf("command %x\n", FRAME_CMD(ctap_req));
printf("len %d\n", MSG_LEN(ctap_req));
msg_packet.len = msg_packet.current_len = 0;
if (MSG_LEN(ctap_req) > 64 - 7) {
msg_packet.len = MSG_LEN(ctap_req);
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->init.data, 64 - 7);
msg_packet.current_len += 64 - 7;
}
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
last_cmd = ctap_req->init.cmd;
last_seq = 0;
last_cmd_time = board_millis();
}
else {
if (msg_packet.len == 0) { //Received a cont with a prior init pkt
return 0;
}
if (last_seq != ctap_req->cont.seq) {
return ctap_error(CTAP1_ERR_INVALID_SEQ);
}
if (last_req.cid == ctap_req->cid) {
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->cont.data,
MIN(64 - 5, msg_packet.len - msg_packet.current_len));
msg_packet.current_len += MIN(64 - 5, msg_packet.len - msg_packet.current_len);
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
last_seq++;
}
else if (last_cmd_time + 100 > board_millis()) {
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
}
if (ctap_req->init.cmd == CTAPHID_INIT) {
card_exit();
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
init_fido();
CTAPHID_INIT_REQ *req = (CTAPHID_INIT_REQ *) ctap_req->init.data;
CTAPHID_INIT_RESP *resp = (CTAPHID_INIT_RESP *) ctap_resp->init.data;
memcpy(resp->nonce, req->nonce, sizeof(resp->nonce));
resp->cid = 0x01000000;
resp->versionInterface = CTAPHID_IF_VERSION;
resp->versionMajor = get_version_major ? get_version_major() : PICO_KEYS_SDK_VERSION_MAJOR;
resp->versionMinor = get_version_minor ? get_version_minor() : PICO_KEYS_SDK_VERSION_MINOR;
resp->capFlags = CAPFLAG_WINK | CAPFLAG_CBOR;
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = CTAPHID_INIT;
ctap_resp->init.bcntl = 17;
ctap_resp->init.bcnth = 0;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_WINK) {
if (MSG_LEN(ctap_req) != 0) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
last_packet_time = 0;
memcpy(ctap_resp, ctap_req, sizeof(CTAPHID_FRAME));
#ifndef ENABLE_EMULATION
sleep_ms(1000); //For blinking the device during 1 seg
#endif
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
}
else if ((last_cmd == CTAPHID_PING || last_cmd == CTAPHID_SYNC) &&
(msg_packet.len == 0 ||
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
memcpy(ctap_resp->init.data, msg_packet.data, msg_packet.len);
driver_exec_finished_hid(msg_packet.len);
}
else {
memcpy(ctap_resp->init.data, ctap_req->init.data, MSG_LEN(ctap_req));
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = last_cmd;
ctap_resp->init.bcnth = MSG_LEN(ctap_req) >> 8;
ctap_resp->init.bcntl = MSG_LEN(ctap_req) & 0xff;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_LOCK) {
if (MSG_LEN(ctap_req) != 1) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
if (ctap_req->init.data[0] > 10) {
return ctap_error(CTAP1_ERR_INVALID_PARAMETER);
}
lock = board_millis() + ctap_req->init.data[0] * 1000;
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_UUID) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
memcpy(ctap_resp->init.data, pico_serial.id, sizeof(pico_serial.id));
ctap_resp->init.bcntl = 16;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_VERSION) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
ctap_resp->init.data[0] = PICO_KEYS_SDK_VERSION_MAJOR;
ctap_resp->init.data[1] = PICO_KEYS_SDK_VERSION_MINOR;
ctap_resp->init.bcntl = 4;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_ADMIN) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
if (ctap_req->init.data[0] == 0x80) { // Status
memcpy(ctap_resp->init.data, "\x00\xff\xff\xff\x00", 5);
ctap_resp->init.bcntl = 5;
}
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if ((last_cmd == CTAPHID_MSG || last_cmd == CTAPHID_OTP) &&
(msg_packet.len == 0 ||
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
if (last_cmd == CTAPHID_OTP) {
is_nitrokey = true;
select_app(fido_aid + 1, fido_aid[0]);
}
else {
select_app(u2f_aid + 1, u2f_aid[0]);
}
thread_type = 1;
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = apdu_process(ITF_HID_CTAP, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = apdu_process(ITF_HID_CTAP, ctap_req->init.data, MSG_LEN(ctap_req));
}
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if ((last_cmd == CTAPHID_CBOR || last_cmd >= CTAPHID_VENDOR_FIRST) &&
(msg_packet.len == 0 || (msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
thread_type = 2;
select_app(fido_aid + 1, fido_aid[0]);
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = cbor_process(last_cmd, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = cbor_process(last_cmd, ctap_req->init.data, MSG_LEN(ctap_req));
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
if (apdu_sent < 0) {
return ctap_error((uint8_t)(-apdu_sent));
}
send_keepalive();
}
else if (ctap_req->init.cmd == CTAPHID_CANCEL) {
ctap_error(0x2D);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
cancel_button = true;
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
}
else {
if (msg_packet.len == 0) {
return ctap_error(CTAP1_ERR_INVALID_CMD);
}
}
// echo back anything we received from host
//tud_hid_report(0, buffer, bufsize);
//printf("END\n");
if (apdu_sent > 0) {
if (apdu_sent == 1) {
card_start(ITF_HID, apdu_thread);
}
else if (apdu_sent == 2) {
card_start(ITF_HID, cbor_thread);
}
usb_send_event(EV_CMD_AVAILABLE);
}
}
return apdu_sent;
}
void send_keepalive() {
if (thread_type == 1) {
return;
}
CTAPHID_FRAME *resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer + sizeof(hid_tx[ITF_HID_CTAP].buffer) - 64);
//memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
resp->cid = ctap_req->cid;
resp->init.cmd = CTAPHID_KEEPALIVE;
resp->init.bcntl = 1;
resp->init.data[0] = is_req_button_pending() ? 2 : 1;
//send_buffer_size[ITF_HID_CTAP] = 0;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)resp, 64);
}
void driver_exec_finished_hid(uint16_t size_next) {
if (size_next > 0) {
if (thread_type == 2 && apdu.sw != 0) {
ctap_error(apdu.sw & 0xff);
}
else {
if (is_nitrokey) {
memmove(apdu.rdata + 2, apdu.rdata, size_next - 2);
put_uint16_t_be(apdu.sw, apdu.rdata);
}
driver_exec_finished_cont_hid(ITF_HID_CTAP, size_next, 7);
}
}
apdu.sw = 0;
}
void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset) {
offset -= 7;
ctap_resp = (CTAPHID_FRAME *) (hid_tx[itf].buffer + offset);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.bcnth = size_next >> 8;
ctap_resp->init.bcntl = size_next & 0xff;
send_buffer_size[itf] = size_next;
ctap_resp->init.cmd = last_cmd;
if (hid_write_offset(size_next+7, offset) > 0) {
//ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
//send_buffer_size[ITF_HID_CTAP] -= MIN(64 - 7, send_buffer_size[ITF_HID_CTAP]);
}
}
void hid_task() {
#ifdef ENABLE_EMULATION
uint16_t rx_len = emul_read(ITF_HID);
if (rx_len) {
uint16_t rptr = 0;
while (rx_len > 0) {
tud_hid_set_report_cb(ITF_HID, 0, 0, emul_rx + rptr, 64);
rx_len -= 64;
rptr += 64;
}
emul_rx_size = 0;
}
#endif
int proc_pkt = 0;
if (hid_rx[ITF_HID_CTAP].w_ptr - hid_rx[ITF_HID_CTAP].r_ptr >= 64) {
//proc_pkt = driver_process_usb_packet_hid(64);
}
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
int status = card_status(ITF_HID);
if (status == PICOKEY_OK) {
driver_exec_finished_hid(finished_data_size);
}
else if (status == PICOKEY_ERR_BLOCKED) {
send_keepalive();
}
if (hid_tx[ITF_HID_CTAP].w_ptr > hid_tx[ITF_HID_CTAP].r_ptr && last_write_result[ITF_HID_CTAP] != WRITE_PENDING) {
if (driver_write_hid(ITF_HID_CTAP, hid_tx[ITF_HID_CTAP].buffer + hid_tx[ITF_HID_CTAP].r_ptr, 64) > 0) {
}
}
#ifndef ENABLE_EMULATION
/* Keyboard ITF */
// Poll every 10ms
const uint32_t interval_ms = 10;
static uint32_t start_ms = 0;
if (board_millis() - start_ms < interval_ms) {
return;
}
start_ms += interval_ms;
// Remote wakeup
if (tud_suspended() && keyboard_buffer_len > 0) {
tud_remote_wakeup();
}
else {
send_hid_report(REPORT_ID_KEYBOARD);
}
#endif
}

View File

@@ -27,49 +27,53 @@
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#ifndef BOARD_TUD_RHPORT
#define BOARD_TUD_RHPORT 0
#endif
// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#ifndef BOARD_TUD_MAX_SPEED
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
//--------------------------------------------------------------------
// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_PICO
#if CFG_TUSB_MCU == OPT_MCU_RP2040
#define CFG_TUSB_OS OPT_OS_PICO
#elif CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
#define CFG_TUSB_OS OPT_OS_FREERTOS
#endif
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
#ifndef CFG_TUSB_RHPORT0_MODE
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED)
#endif
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
@@ -83,7 +87,7 @@
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
#endif
//--------------------------------------------------------------------
@@ -94,26 +98,35 @@
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_TX_BUFSIZE 2048
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0
#ifdef USB_ITF_HID
#define CFG_TUD_HID 2
#else
#define CFG_TUD_HID 0
#endif
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 1
#ifdef USB_ITF_CCID
#define CFG_TUD_VENDOR 2
#else
#define CFG_TUD_VENDOR 0
#endif
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 16
#define CFG_TUD_HID_EP_BUFSIZE 64
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#include "pico/types.h"
static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); }
static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); }
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#ifdef __cplusplus
}
}
#endif
#endif /* _TUSB_CONFIG_H_ */

268
src/usb/usb.c Normal file
View File

@@ -0,0 +1,268 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 <stdio.h>
// Pico
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "bsp/board.h"
#endif
#include "pico_keys.h"
#include "usb.h"
#include "apdu.h"
#ifndef ENABLE_EMULATION
#include "tusb.h"
#else
#include "emulation.h"
#endif
// For memcpy
#include <string.h>
#include <stdlib.h>
// Device specific functions
static uint32_t *timeout_counter = NULL;
static uint8_t card_locked_itf = 0; // no locked
static void (*card_locked_func)(void) = NULL;
#ifndef ENABLE_EMULATION
static mutex_t mutex;
extern void usb_desc_setup();
#endif
#ifdef USB_ITF_HID
uint8_t ITF_HID_CTAP = ITF_INVALID, ITF_HID_KB = ITF_INVALID;
uint8_t ITF_HID = ITF_INVALID, ITF_KEYBOARD = ITF_INVALID;
uint8_t ITF_HID_TOTAL = 0;
extern void hid_init();
#endif
#ifdef USB_ITF_CCID
uint8_t ITF_SC_CCID = ITF_INVALID, ITF_SC_WCID = ITF_INVALID;
uint8_t ITF_CCID = ITF_INVALID, ITF_WCID = ITF_INVALID;
uint8_t ITF_SC_TOTAL = 0;
extern void ccid_init();
#endif
uint8_t ITF_TOTAL = 0;
void usb_set_timeout_counter(uint8_t itf, uint32_t v) {
timeout_counter[itf] = v;
}
queue_t usb_to_card_q = {0};
queue_t card_to_usb_q = {0};
#ifndef ENABLE_EMULATION
extern tusb_desc_device_t desc_device;
#endif
void usb_init() {
#ifndef ENABLE_EMULATION
if (phy_data.vidpid_present) {
desc_device.idVendor = phy_data.vid;
desc_device.idProduct = phy_data.pid;
}
mutex_init(&mutex);
#endif
queue_init(&card_to_usb_q, sizeof(uint32_t), 64);
queue_init(&usb_to_card_q, sizeof(uint32_t), 64);
uint8_t enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
#ifndef ENABLE_EMULATION
if (phy_data.enabled_usb_itf_present) {
enabled_usb_itf = phy_data.enabled_usb_itf;
}
#endif
#ifdef USB_ITF_HID
ITF_HID_TOTAL = 0;
#endif
#ifdef USB_ITF_CCID
ITF_SC_TOTAL = 0;
#endif
ITF_TOTAL = 0;
#ifdef USB_ITF_HID
if (enabled_usb_itf & PHY_USB_ITF_HID) {
ITF_HID_CTAP = ITF_HID_TOTAL++;
ITF_HID = ITF_TOTAL++;
}
if (enabled_usb_itf & PHY_USB_ITF_KB) {
ITF_HID_KB = ITF_HID_TOTAL++;
ITF_KEYBOARD = ITF_TOTAL++;
}
#endif
#ifdef USB_ITF_CCID
if (enabled_usb_itf & PHY_USB_ITF_CCID) {
ITF_SC_CCID = ITF_SC_TOTAL++;
ITF_CCID = ITF_TOTAL++;
}
if (enabled_usb_itf & PHY_USB_ITF_WCID) {
ITF_SC_WCID = ITF_SC_TOTAL++;
ITF_WCID = ITF_TOTAL++;
}
#endif
card_locked_itf = ITF_TOTAL;
if (timeout_counter == NULL) {
timeout_counter = (uint32_t *)calloc(ITF_TOTAL, sizeof(uint32_t));
}
#ifdef USB_ITF_HID
if (ITF_HID_TOTAL > 0) {
hid_init();
}
#endif
#ifdef USB_ITF_CCID
if (ITF_SC_TOTAL > 0) {
ccid_init();
}
#endif
#ifdef ESP_PLATFORM
usb_desc_setup();
#endif
}
uint32_t timeout = 0;
void timeout_stop() {
timeout = 0;
}
void timeout_start() {
timeout = board_millis();
}
bool is_busy() {
return timeout > 0;
}
void usb_send_event(uint32_t flag) {
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
queue_add_blocking(&usb_to_card_q, &flag);
if (flag == EV_CMD_AVAILABLE) {
timeout_start();
}
uint32_t m;
queue_remove_blocking(&card_to_usb_q , &m);
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
}
extern void low_flash_init();
void card_init_core1() {
low_flash_init_core1();
}
uint16_t finished_data_size = 0;
void card_start(uint8_t itf, void (*func)(void)) {
timeout_start();
if (card_locked_itf != itf || card_locked_func != func) {
if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) {
card_exit();
}
if (func) {
multicore_reset_core1();
multicore_launch_core1(func);
}
led_set_mode(MODE_MOUNTED);
card_locked_itf = itf;
card_locked_func = func;
}
}
void card_exit() {
if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) {
usb_send_event(EV_EXIT);
uint32_t m;
while (queue_is_empty(&usb_to_card_q) == false) {
if (queue_try_remove(&usb_to_card_q, &m) == false) {
break;
}
}
while (queue_is_empty(&card_to_usb_q) == false) {
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
if (queue_try_remove(&card_to_usb_q, &m) == false) {
break;
}
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
}
led_set_mode(MODE_SUSPENDED);
#ifdef ESP_PLATFORM
hcore1 = NULL;
#endif
}
card_locked_itf = ITF_TOTAL;
card_locked_func = NULL;
}
extern void hid_task();
extern void ccid_task();
extern void emul_task();
void usb_task() {
#ifdef USB_ITF_HID
hid_task();
#endif
#ifdef ENABLE_EMULATION
emul_task();
#else
#ifdef USB_ITF_CCID
ccid_task();
#endif
#endif
}
int card_status(uint8_t itf) {
if (card_locked_itf == itf) {
uint32_t m = 0x0;
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
bool has_m = queue_try_remove(&card_to_usb_q, &m);
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
//if (m != 0)
// printf("\n ------ M = %lu\n",m);
if (has_m) {
if (m == EV_EXEC_FINISHED) {
timeout_stop();
led_set_mode(MODE_MOUNTED);
return PICOKEY_OK;
}
#ifndef ENABLE_EMULATION
else if (m == EV_PRESS_BUTTON) {
uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED;
queue_try_add(&usb_to_card_q, &flag);
}
#endif
return PICOKEY_ERR_FILE_NOT_FOUND;
}
else {
if (timeout > 0) {
if (timeout + timeout_counter[itf] < board_millis()) {
timeout = board_millis();
return PICOKEY_ERR_BLOCKED;
}
}
}
}
return PICOKEY_ERR_FILE_NOT_FOUND;
}

122
src/usb/usb.h Normal file
View File

@@ -0,0 +1,122 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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 _USB_H_
#define _USB_H_
#if defined(ENABLE_EMULATION)
#include "emulation.h"
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#else
#include "pico/util/queue.h"
#endif
#include "compat.h"
/* USB thread */
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2
#define EV_EXEC_ACK_REQUIRED 4
#define EV_EXEC_FINISHED 8
#define EV_RX_DATA_READY 16
#define EV_PRESS_BUTTON 32
/* Card thread */
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_EXIT 8
#define EV_BUTTON_TIMEOUT 16
#define EV_BUTTON_PRESSED 32
static const uint8_t ITF_INVALID = 0xFF;
#ifdef USB_ITF_HID
extern uint8_t ITF_HID_CTAP, ITF_HID_KB;
extern uint8_t ITF_HID, ITF_KEYBOARD;
extern uint8_t ITF_HID_TOTAL;
#endif
#ifdef USB_ITF_CCID
extern uint8_t ITF_SC_CCID, ITF_SC_WCID;
extern uint8_t ITF_CCID, ITF_WCID;
extern uint8_t ITF_SC_TOTAL;
#endif
extern uint8_t ITF_TOTAL;
enum {
REPORT_ID_KEYBOARD = 0,
REPORT_ID_COUNT
};
#if defined(ESP_PLATFORM) && defined(USB_ITF_HID) && defined(USB_ITF_CCID)
#define TUSB_SMARTCARD_CCID_EPS 2
#else
#define TUSB_SMARTCARD_CCID_EPS 3
#endif
extern void usb_task();
extern queue_t usb_to_card_q;
extern queue_t card_to_usb_q;
extern void card_start(uint8_t, void (*func)(void));
extern void card_exit();
extern int card_status(uint8_t itf);
extern void usb_init();
extern uint16_t finished_data_size;
extern void usb_set_timeout_counter(uint8_t itf, uint32_t v);
extern void card_init_core1();
extern void usb_send_event(uint32_t flag);
extern void timeout_stop();
extern void timeout_start();
extern bool is_busy();
#ifdef USB_ITF_HID
extern void driver_exec_finished_hid(uint16_t size_next);
extern void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#ifdef USB_ITF_CCID
extern void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#ifdef ENABLE_EMULATION
extern void driver_exec_finished_emul(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_emul(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#define USB_BUFFER_SIZE 2048
PACK(
typedef struct {
uint8_t buffer[USB_BUFFER_SIZE];
uint16_t r_ptr;
uint16_t w_ptr;
}) usb_buffer_t;
typedef enum {
WRITE_UNKNOWN = 0,
WRITE_PENDING,
WRITE_FAILED,
WRITE_SUCCESS,
} write_status_t;
#endif

View File

@@ -1,26 +1,31 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 "tusb.h"
#include "usb_descriptors.h"
#include "ccid.h"
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/unique_id.h"
#include "ccid_version.h"
#endif
#ifdef ESP_PLATFORM
#include "tinyusb.h"
#endif
#include "pico_keys_version.h"
#include "usb.h"
#include "pico_keys.h"
#ifndef USB_VID
#define USB_VID 0xFEFF
@@ -33,14 +38,12 @@
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#define MAX_USB_POWER 1
#define MAX_USB_POWER 2
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
tusb_desc_device_t desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = (USB_BCD),
@@ -52,7 +55,7 @@ tusb_desc_device_t const desc_device =
.idVendor = (USB_VID),
.idProduct = (USB_PID),
.bcdDevice = CCID_VERSION,
.bcdDevice = PICO_KEYS_SDK_VERSION,
.iManufacturer = 1,
.iProduct = 2,
@@ -61,92 +64,241 @@ tusb_desc_device_t const desc_device =
.bNumConfigurations = 1
};
uint8_t const * tud_descriptor_device_cb(void)
{
#ifndef ESP_PLATFORM
uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
tusb_desc_interface_t const desc_interface =
{
.bLength = sizeof(tusb_desc_interface_t),
.bDescriptorType = TUSB_DESC_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = TUSB_CLASS_SMART_CARD,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 5,
};
#endif
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
tusb_desc_configuration_t const desc_config =
{
.bLength = sizeof(tusb_desc_configuration_t),
.bDescriptorType = TUSB_DESC_CONFIGURATION,
.wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 4,
.bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1),
#define TUD_INTERFACE_DESC_LEN 9
#define TUD_ENDPOINT_DESC_LEN 7
#define TUSB_SMARTCARD_LEN 54
#define TUSB_WSMARTCARD_LEN 53
#define TUSB_SMARTCARD_CCID_DESC_LEN (TUD_INTERFACE_DESC_LEN + TUSB_SMARTCARD_LEN + TUSB_SMARTCARD_CCID_EPS * TUD_ENDPOINT_DESC_LEN)
#define TUSB_SMARTCARD_WCID_DESC_LEN (TUD_INTERFACE_DESC_LEN + TUSB_WSMARTCARD_LEN + 2 * TUD_ENDPOINT_DESC_LEN)
uint16_t TUSB_DESC_TOTAL_LEN = TUD_CONFIG_DESC_LEN;
enum {
MAX_TUSB_DESC_TOTAL_LEN = (TUD_CONFIG_DESC_LEN
#ifdef USB_ITF_HID
+ TUD_HID_INOUT_DESC_LEN + TUD_HID_DESC_LEN
#endif
#ifdef USB_ITF_CCID
+ TUSB_SMARTCARD_CCID_DESC_LEN + TUSB_SMARTCARD_WCID_DESC_LEN
#endif
)
};
tusb_desc_endpoint_t const desc_ep1 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = TUSB_DIR_IN_MASK | 1,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
#ifdef USB_ITF_HID
uint8_t const desc_hid_report[] = {
TUD_HID_REPORT_DESC_FIDO_U2F(CFG_TUD_HID_EP_BUFSIZE)
};
uint8_t const desc_hid_report_kb[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_USAGE_PAGE(HID_USAGE_DESKTOP_KEYBOARD), HID_USAGE_MIN(0), HID_USAGE_MAX_N(255,2), HID_LOGICAL_MIN(0), HID_LOGICAL_MAX_N(255, 2), HID_REPORT_COUNT(8), HID_REPORT_SIZE(8), HID_FEATURE( HID_DATA | HID_VARIABLE | HID_ABSOLUTE),)
};
#endif
enum {
#ifdef USB_ITF_CCID
EPNUM_CCID = 1,
#if TUSB_SMARTCARD_CCID_EPS == 3
EPNUM_CCID_INT,
#endif
EPNUM_WCID,
#endif
#ifdef USB_ITF_HID
EPNUM_HID,
EPNUM_HID_KB,
#endif
EPNUM_TOTAL
};
tusb_desc_endpoint_t const desc_ep2 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = 2,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
#ifdef USB_ITF_CCID
#define TUD_SMARTCARD_DESCRIPTOR_WEB(_itf, _strix, _epout, _epin, _epsize) \
9, TUSB_DESC_INTERFACE, _itf, 0, 2, 0xFF, 0, 0, _strix, \
TUSB_WSMARTCARD_LEN, 0x21, U16_TO_U8S_LE(0x0110), 0, 0x1, U32_TO_U8S_LE(0x01|0x2), U32_TO_U8S_LE(0xDFC), U32_TO_U8S_LE(0xDFC), 0, U32_TO_U8S_LE(0x2580), U32_TO_U8S_LE(0x2580), 0, U32_TO_U8S_LE(0xFE), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0x40840), U32_TO_U8S_LE(USB_BUFFER_SIZE), 0xFF, 0xFF, U16_TO_U8S_LE(0x0), 0, \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
#define TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize) \
9, TUSB_DESC_INTERFACE, _itf, 0, TUSB_SMARTCARD_CCID_EPS, TUSB_CLASS_SMART_CARD, 0, 0, _strix, \
TUSB_SMARTCARD_LEN, 0x21, U16_TO_U8S_LE(0x0110), 0, 0x1, U32_TO_U8S_LE(0x01|0x2), U32_TO_U8S_LE(0xDFC), U32_TO_U8S_LE(0xDFC), 0, U32_TO_U8S_LE(0x2580), U32_TO_U8S_LE(0x2580), 0, U32_TO_U8S_LE(0xFE), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0x40840), U32_TO_U8S_LE(USB_BUFFER_SIZE), 0xFF, 0xFF, U16_TO_U8S_LE(0x0), 0, 0x1, \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
#if TUSB_SMARTCARD_CCID_EPS == 3
#define TUD_SMARTCARD_DESCRIPTOR(_itf, _strix, _epout, _epin, _epint, _epsize) \
TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize), \
7, TUSB_DESC_ENDPOINT, _epint, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), 0
#else
#define TUD_SMARTCARD_DESCRIPTOR(_itf, _strix, _epout, _epin, _epint, _epsize) \
TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize)
#endif
#endif
uint8_t desc_config[MAX_TUSB_DESC_TOTAL_LEN] = {
TUD_CONFIG_DESCRIPTOR(1, 0, 4, 0, USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, MAX_USB_POWER)
};
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)];
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
static uint8_t initd = 0;
if (initd == 0)
{
uint8_t *p = desc_config_extended;
memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t);
memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t);
memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor);
memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
initd = 1;
#ifdef USB_ITF_HID
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
printf("report_cb %d\n", itf);
if (itf == ITF_HID_CTAP) {
return desc_hid_report;
}
return (const uint8_t *)desc_config_extended;
else if (itf == ITF_HID_KB) {
return desc_hid_report_kb;
}
return NULL;
}
#endif
void usb_desc_setup() {
desc_config[4] = ITF_TOTAL;
TUSB_DESC_TOTAL_LEN = TUD_CONFIG_DESC_LEN;
uint8_t *p = desc_config + TUD_CONFIG_DESC_LEN;
#ifdef USB_ITF_HID
if (ITF_HID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUD_HID_INOUT_DESC_LEN;
const uint8_t desc[] = { TUD_HID_INOUT_DESCRIPTOR(ITF_HID, ITF_HID + 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, TUSB_DIR_IN_MASK | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) };
memcpy(p, desc, sizeof(desc));
p += sizeof(desc);
}
if (ITF_KEYBOARD != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUD_HID_DESC_LEN;
const uint8_t desc_kb[] = { TUD_HID_DESCRIPTOR(ITF_KEYBOARD, ITF_KEYBOARD + 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report_kb), TUSB_DIR_IN_MASK | EPNUM_HID_KB, 16, 5) };
memcpy(p, desc_kb, sizeof(desc_kb));
p += sizeof(desc_kb);
}
#endif
#ifdef USB_ITF_CCID
if (ITF_CCID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUSB_SMARTCARD_CCID_DESC_LEN;
const uint8_t desc_ccid[] = { TUD_SMARTCARD_DESCRIPTOR(ITF_CCID, ITF_CCID + 5, EPNUM_CCID, TUSB_DIR_IN_MASK | EPNUM_CCID, TUSB_DIR_IN_MASK | EPNUM_CCID_INT, 64) };
memcpy(p, desc_ccid, sizeof(desc_ccid));
p += sizeof(desc_ccid);
}
if (ITF_WCID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUSB_SMARTCARD_WCID_DESC_LEN;
const uint8_t desc_wcid[] = { TUD_SMARTCARD_DESCRIPTOR_WEB(ITF_WCID, ITF_WCID + 5, EPNUM_WCID, TUSB_DIR_IN_MASK | EPNUM_WCID, 64) };
memcpy(p, desc_wcid, sizeof(desc_wcid));
p += sizeof(desc_wcid);
}
#endif
desc_config[2] = TUSB_DESC_TOTAL_LEN & 0xFF;
desc_config[3] = TUSB_DESC_TOTAL_LEN >> 8;
}
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN)
#ifndef ESP_PLATFORM
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
usb_desc_setup();
return desc_config;
}
#endif
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
uint8_t const desc_bos[] =
enum
{
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
#define URL "www.picokeys.com"
static bool web_serial_connected = false;
const tusb_desc_webusb_url_t desc_url =
{
.bLength = 3 + sizeof(URL) - 1,
.bDescriptorType = 3, // WEBUSB URL type
.bScheme = 1, // 0: http, 1: https
.url = URL
};
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
uint8_t desc_ms_os_20[] = {
// Set header: length, type, windows version, total length
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
// Configuration subset header: length, type, configuration index, reserved, configuration total length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
// Function Subset header: length, type, first interface, reserved, subset length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0/*ITF_WCID*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
// MS OS 2.0 Registry property descriptor: length, type
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
};
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case VENDOR_REQUEST_WEBUSB:
return tud_control_xfer(rhport, request, (void*)(uintptr_t) &desc_url, desc_url.bLength);
case VENDOR_REQUEST_MICROSOFT:
if (request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
desc_ms_os_20[22] = ITF_WCID;
memcpy(&total_len, desc_ms_os_20+8, 2);
return tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_ms_os_20, total_len);
}
else {
return false;
}
default:
break;
}
break;
case TUSB_REQ_TYPE_CLASS:
if (request->bRequest == 0x22) {
web_serial_connected = (request->wValue != 0);
if (web_serial_connected) {
printf("\nWebUSB interface connected\n");
}
return tud_control_status(rhport, request);
}
break;
default:
break;
}
// stall unknown request
return false;
}
uint8_t const desc_bos[] = {
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2)
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
// Vendor Code, iLandingPage
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
};
uint8_t const * tud_descriptor_bos_cb(void)
{
uint8_t const *tud_descriptor_bos_cb(void) {
return desc_bos;
}
@@ -155,55 +307,80 @@ uint8_t const * tud_descriptor_bos_cb(void)
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
char const *string_desc_arr [] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Pol Henarejos", // 1: Manufacturer
"Pico HSM", // 2: Product
"Pico Key", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Pico HSM Config", // 4: Vendor Interface
"Pico HSM Interface"
"Config" // 4: Vendor Interface
#ifdef USB_ITF_HID
, "HID Interface"
, "HID Keyboard Interface"
#endif
#ifdef USB_ITF_CCID
, "CCID OTP FIDO Interface"
, "WebCCID Interface"
#endif
};
#ifdef ESP_PLATFORM
tinyusb_config_t tusb_cfg = {
.device_descriptor = &desc_device,
.string_descriptor = string_desc_arr,
.string_descriptor_count = (sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) > 8 ? 8 : (sizeof(string_desc_arr) / sizeof(string_desc_arr[0])),
.external_phy = false,
.configuration_descriptor = desc_config,
};
#else
static uint16_t _desc_str[32];
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
uint8_t chr_count;
uint8_t chr_count = 0;
if (index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}
else {
else {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) {
return NULL;
const char* str = string_desc_arr[index];
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
if (index == 3) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
str = unique_id_str;
}
chr_count = strlen(str);
if ( chr_count > 31 )
chr_count = 31;
const char *str = string_desc_arr[index];
if (index == 3) {
str = pico_serial_str;
}
else if (index == 2) {
if (phy_data.usb_product_present) {
str = phy_data.usb_product;
}
}
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++) {
_desc_str[1+i] = str[i];
uint8_t buff_avail = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1;
if (index >= 4) {
const char *product = phy_data.usb_product_present ? phy_data.usb_product : string_desc_arr[2];
uint8_t len = MIN(strlen(product), buff_avail);
for (int ix = 0; ix < len; chr_count++, ix++) {
_desc_str[1 + chr_count] = product[ix];
}
buff_avail -= len;
if (buff_avail > 0) {
_desc_str[1 + chr_count++] = ' ';
buff_avail--;
}
}
for (int ix = 0; ix < MIN(strlen(str), buff_avail); chr_count++, ix++) {
_desc_str[1 + chr_count] = str[ix];
}
}
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
return _desc_str;
}
#endif

View File

@@ -1,29 +1,49 @@
/*
* This file is part of the Pico CCID distribution (https://github.com/polhenarejos/pico-ccid).
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* 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
*
* 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
* 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
* 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 USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_
enum
{
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
#include "compat.h"
extern uint8_t const desc_ms_os_20[];
PACK(
struct ccid_class_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockSupport;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bclassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
});
#endif /* USB_DESCRIPTORS_H_ */

1
tinycbor Submodule

Submodule tinycbor added at e27261ed5e