229 Commits

Author SHA1 Message Date
Pol Henarejos
b3ce44f569 Rename asn1 -> tlv, as it reflects better the purpose.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-18 16:41:48 +02:00
Pol Henarejos
3ddb459e5c Add stop-n-wait mechanism to avoid sending too huge payloads.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-18 16:41:27 +02:00
Pol Henarejos
a9261e34ad Small tweaks
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-15 17:15:35 +02:00
Pol Henarejos
6e2a2aef71 Fix esp32 MLDSA build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-15 14:18:12 +02:00
Pol Henarejos
f4d0ca2933 Fix all_header location.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-15 12:21:14 +02:00
Pol Henarejos
e83f0b6b52 Added ML-DSA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-15 11:16:45 +02:00
Pol Henarejos
24dd4b2e69 Add PIN protection for TPM in windows and linux.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-15 10:30:46 +02:00
Pol Henarejos
6f9bc55004 Disable alignment warn
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-14 20:25:57 +02:00
Pol Henarejos
3d55f3a991 Fix warnings. Needs alignment
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-14 20:13:57 +02:00
Pol Henarejos
54317f8d43 Add otp for windows and linux.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-14 19:19:09 +02:00
Pol Henarejos
7f53d7f748 Fix warnings
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-14 19:18:39 +02:00
Pol Henarejos
08507069bd Derive secp256k1 from SE.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-14 00:36:40 +02:00
Pol Henarejos
d590a21738 Refactor OTP to add more platforms.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-13 20:16:49 +02:00
Pol Henarejos
141d62da01 Fix warnings
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-13 15:56:40 +02:00
Pol Henarejos
4507bb68a6 Fix conditional build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-13 00:37:06 +02:00
Pol Henarejos
d868a351da Add libcvc as a component.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-13 00:29:20 +02:00
Pol Henarejos
61457e1b8e Fix build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-13 00:25:26 +02:00
Pol Henarejos
15148acab5 Add fallback serials for emulation.
Let's see how it works.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-12 22:26:01 +02:00
Pol Henarejos
d3ce3c20dc Fix random serial DER encoding.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-12 19:48:30 +02:00
Pol Henarejos
a4a1651ed4 Fix race condition when generating key.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-12 19:04:01 +02:00
Pol Henarejos
b3c91f068d Add rest query get.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-12 18:28:17 +02:00
Pol Henarejos
45017a514e Add optional query parser.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-12 14:49:01 +02:00
Pol Henarejos
4a168ae6c0 Fix last_activity and last_seq checks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-09 00:58:35 +02:00
Pol Henarejos
525b87cd72 Zeroize critical buffers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-08 19:43:46 +02:00
Pol Henarejos
5838d6f443 Add libcvc dep
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-07 01:33:38 +02:00
Pol Henarejos
1be7acaedd Fix warnings
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-06 11:31:07 +02:00
Pol Henarejos
49564e2e5e Remove printf
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-05 20:24:32 +02:00
Pol Henarejos
084aa8c44b Fix when olen == 0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-05 01:55:22 +02:00
Pol Henarejos
e0a8380dcd Add b64decode len.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-04 21:10:18 +02:00
Pol Henarejos
f8db7613b6 Fix warnings
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-04 15:16:17 +02:00
Pol Henarejos
869ef09f34 Fix check supported content type.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-04 09:46:26 +02:00
Pol Henarejos
0cc24a9637 Allow non-json / x-pem requests and responses.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-04 01:01:30 +02:00
Pol Henarejos
c4bffd5433 Add stdio
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-02 11:38:59 +02:00
Pol Henarejos
d24cdd6c16 Fix build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 21:41:03 +02:00
Pol Henarejos
9cb83e3abc Use ecp keypair calc public instead.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 20:57:58 +02:00
Pol Henarejos
92b8c644d8 Fix conditional dep build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:44:06 +02:00
Pol Henarejos
810c1a88c3 Unregister submodules
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:37:15 +02:00
Pol Henarejos
dbc8ff4a4a Use dynamic dependence resolver.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:29:16 +02:00
Pol Henarejos
e7be1171da Fix include header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 18:30:05 +02:00
Pol Henarejos
b4813e9db2 Fix build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 12:59:36 +02:00
Pol Henarejos
ee13b6904a Intercept /cancel
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-30 15:55:46 +02:00
Pol Henarejos
3a03000df1 Add cancelable key generation
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-30 09:56:23 +02:00
Pol Henarejos
707cdf7bf4 Fix windows build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-29 15:36:53 +02:00
Pol Henarejos
0abea5b6b2 Add background jobs.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-28 00:40:05 +02:00
Pol Henarejos
3fa5204949 Fix request signature.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-28 00:19:50 +02:00
Pol Henarejos
3d3b46a5b5 Fix ESP build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 20:33:06 +02:00
Pol Henarejos
cbc48dd8d7 Fix memory non-freed
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 20:32:57 +02:00
Pol Henarejos
6069c3dc2e Fix rare race condition with hwrng.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 20:32:28 +02:00
Pol Henarejos
dcf747a766 Fix tcp writes in slow boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 12:15:50 +02:00
Pol Henarejos
3789ed3596 Fix interface launch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 10:58:08 +02:00
Pol Henarejos
7ed012c6f5 Add headers in response.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 09:46:01 +02:00
Pol Henarejos
b73a7e4a72 Rename delete_file.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-27 09:45:42 +02:00
Pol Henarejos
a7b143f0d8 Add param parser and role check.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-26 21:10:47 +02:00
Pol Henarejos
c8b5bf8f82 Accept multiple HTTP methods.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-26 18:00:29 +02:00
Pol Henarejos
a906628318 Added session key negotiation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 20:40:19 +02:00
Pol Henarejos
9ab9d96af5 Add base64url routines.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 17:09:51 +02:00
Pol Henarejos
11a8923148 Fix RX and parsing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 15:47:18 +02:00
Pol Henarejos
0eeac93416 Add support for verified sessions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 15:25:53 +02:00
Pol Henarejos
dfeb5b973b Include bsp headers for timers.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 12:03:01 +02:00
Pol Henarejos
cc78469c01 Add stdio header.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 00:13:37 +02:00
Pol Henarejos
e24eb9b150 More renames.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-21 00:06:28 +02:00
Pol Henarejos
0d3a1bdf51 Add support for LWIP esp32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 23:50:02 +02:00
Pol Henarejos
3836ee70e4 Do not enable INT CCID with LWIP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 23:49:42 +02:00
Pol Henarejos
50bb75bdd6 Fix interface iStrings.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 23:49:31 +02:00
Pol Henarejos
26de18608f A refactor.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 17:34:42 +02:00
Pol Henarejos
fa07b59cc7 Add REST session handling.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 13:01:23 +02:00
Pol Henarejos
7db11c21f6 Rename random functions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-20 13:01:14 +02:00
Pol Henarejos
2b28e19e61 Rename public methods.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-19 20:11:43 +02:00
Pol Henarejos
febae0e664 Add support for TLS.
Cert is self-signed and auto-generated on first boot.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-19 03:16:54 +02:00
Pol Henarejos
f8cbb145f4 Add multicore to LWIP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-18 16:37:30 +02:00
Pol Henarejos
9b4c2840c2 Add CJSON boolean macro.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-18 16:36:47 +02:00
Pol Henarejos
8099d699e4 Adde LWIP interface to Phy.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-18 16:36:37 +02:00
Pol Henarejos
b244d2a484 Add more support for rest emulation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-17 16:40:28 +02:00
Pol Henarejos
28aa1f2dcf Add support for emulation env.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-17 16:11:34 +02:00
Pol Henarejos
70b1daac82 Add CJSON macros.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-17 16:11:23 +02:00
Pol Henarejos
2fa03e1170 Add cjson
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-16 19:51:14 +02:00
Pol Henarejos
5705a3d026 Remove iperf references.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-16 19:50:08 +02:00
Pol Henarejos
32bbdc4684 Add set_atr for a rescue ATR.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-16 19:49:56 +02:00
Pol Henarejos
194b48773a Not used
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-16 19:49:22 +02:00
Pol Henarejos
8821728cc7 Moving third-party submodules to third-party folder. 2026-04-16 19:48:25 +02:00
Pol Henarejos
7b8d09550a Add method and route factory. 2026-04-12 12:09:44 +02:00
Pol Henarejos
f84b6bed93 Add a tiny REST server. 2026-04-10 20:40:05 +02:00
Pol Henarejos
89d44e8c32 Upgrade mbedtls baseline. 2026-04-10 15:31:17 +02:00
Pol Henarejos
bfc20f4c14 Fix build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-07 21:50:34 +02:00
Pol Henarejos
44ee025416 Upgrade Pico Keys SDK 8.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 20:04:21 +02:00
Pol Henarejos
45fc1700a3 Upgrade MbedTLS v3.6.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 20:04:10 +02:00
Pol Henarejos
f76bc631d2 Add macros for PIN KDF.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-01 16:20:22 +02:00
Pol Henarejos
189567eebe Add constness
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-01 16:20:12 +02:00
Pol Henarejos
8df41a6789 Fix build for cyw43 led.
Fixes #24.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-28 16:19:19 +01:00
Pol Henarejos
00c03fff25 Move antirollback to 4.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-28 16:19:03 +01:00
Pol Henarejos
9ca3647695 Do not include OTP FIDO in the CCID interface if not available.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-20 14:34:46 +01:00
Pol Henarejos
89a8042634 Added v2 for encryption utilities.
Version 1 derives an encryption key without dependence on OTP.
Version 2 derives an encryption key with dependence on OTP.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-19 18:11:53 +01:00
Pol Henarejos
a9ac2779b7 Clean SRAM on reset to BOOTSEL to avoid memory dumps.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 18:53:54 +01:00
Pol Henarejos
5e9ae65046 Remove session pin.
It is intended for bio features, not supported by Pico HSM.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 16:38:56 +01:00
Pol Henarejos
38cf771fc1 Some sanity clears in secure messaging.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 16:34:11 +01:00
Pol Henarejos
9c0575418e Check MAC length in secure messaging.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 16:24:44 +01:00
Pol Henarejos
0df1914cde Add macros for ACL.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 14:26:31 +01:00
Pol Henarejos
39c3339b38 Allow non-const ACL.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-18 13:18:54 +01:00
Pol Henarejos
8aad7bdef9 Fix build for openssl backend.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-09 11:02:31 +01:00
Pol Henarejos
94ab2ccef7 Mark submodules as system includes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-08 22:05:30 +01:00
Pol Henarejos
e5079e510f Remove redundant declaration.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-08 21:49:00 +01:00
Pol Henarejos
5302942ae3 Do not use FORTIFY as causes out of memory panics.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-08 20:25:09 +01:00
Pol Henarejos
8e6c6c1fcc Apply strict build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-08 19:27:23 +01:00
Pol Henarejos
802a706587 Fixed rare race condition.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-08 17:31:27 +01:00
Pol Henarejos
34633828d7 Fix MLKEM build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 17:41:32 +01:00
Pol Henarejos
ba1046c172 Small typos
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 17:18:58 +01:00
Pol Henarejos
4cd437ed35 Fix strict non-prototype declaration warn.
Fixes #22.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 17:12:40 +01:00
Pol Henarejos
4c88d712b4 Beautify cmake files.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 13:30:37 +01:00
Pol Henarejos
6c7b254183 Add openssl backend.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-25 23:30:54 +01:00
Pol Henarejos
1be3691a95 Increase buffer size for non-pico.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-25 19:33:28 +01:00
Pol Henarejos
6b483029a5 Introducing BULK commands to reduce bandwidth.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 18:29:37 +01:00
Pol Henarejos
57e88f85ee Set rollback globally to avoid incompatibilities.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:50:17 +01:00
Pol Henarejos
5dd2f7fa73 Optimitzations to reduce number of interruptions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:47:13 +01:00
Pol Henarejos
636f929f2d Add template for PR.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:55:44 +01:00
Pol Henarejos
7abedc5b0e Merge pull request #21 from ryulamp/main
Fix RP2350 secure boot key definition
2026-02-16 16:02:09 +01:00
ryulamp
a83742cc3f Refactor secure boot check in otp_is_secure_boot_enabled
Refactor otp_is_secure_boot_enabled to check secure boot status before defining BOOTKEY.
2026-02-12 14:54:16 +08:00
ryulamp
766879991e Fix RP2350 secure boot key definition 2026-02-11 22:42:55 +08:00
Pol Henarejos
b8aa0221db [BETA] Add support to Secure Boot in ESP32.
Needs deep testing.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-07 14:32:06 +01:00
Pol Henarejos
87e9f9e58b Add support for HIGH/LOW LED in ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-04 23:32:37 +01:00
Pol Henarejos
a4090e87f5 Add support for ESP32S2 product.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-04 23:32:17 +01:00
Pol Henarejos
6f996c67c2 Fix phy marker write.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-01 20:33:39 +01:00
Pol Henarejos
a51b17b54d Fix res_APDU size.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-30 23:07:19 +01:00
Pol Henarejos
d0faf6d6a3 Rename pico key sdk project to pico_rescue.
This is a minimal firmware for rescue.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 23:01:47 +01:00
Pol Henarejos
61d4515ecc Pico Keys SDK 8.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 16:11:19 +01:00
Pol Henarejos
2cd21f7dd2 Add weak init callback.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 16:11:12 +01:00
Pol Henarejos
081f473815 Add a PHY marker for RP2040 to preserve the serial number in BOOTSEL.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 16:03:09 +01:00
Pol Henarejos
56f4fca657 Move crc to crypto utils.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 16:02:44 +01:00
Pol Henarejos
2f77e1c3fa Add 8K flash area for binding.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 15:48:33 +01:00
Pol Henarejos
da94e24b45 Add rescue support for RP2040.
Note, however, that this is a best-effort approach since it does not have OTP. All security attempts are flawled and shall not be used to keep security information.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-28 18:52:12 +01:00
Pol Henarejos
8075611f15 Pico Keys SDK 8.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-28 00:53:50 +01:00
Pol Henarejos
474e8b8b46 Fix crash when only CCID is enabled
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-28 00:53:34 +01:00
Pol Henarejos
668b1ac1dd Fix emulation build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:27:07 +01:00
Pol Henarejos
20f2b3b74b Fix interface strings when are not all enabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:19:56 +01:00
Pol Henarejos
50488cc890 Add sanity check in case too large packets are sent.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-26 01:19:31 +01:00
Pol Henarejos
860f77a45b Move rtc
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-24 01:15:10 +01:00
Pol Henarejos
42267cb237 Use new descriptors allocated to picokeys.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:30:12 +01:00
Pol Henarejos
b5c2e55c71 Add missing files.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:09:27 +01:00
Pol Henarejos
68600291d0 Reorganize tree for ESP32
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 11:22:37 +01:00
Pol Henarejos
132ec29424 Fix SHA256 alt
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 11:22:37 +01:00
Pol Henarejos
1125b05f9c Add ML-KEM submodule
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 11:22:37 +01:00
Pol Henarejos
8412727e03 Rename methods for better description
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 11:22:37 +01:00
Pol Henarejos
8a0ef0b30c Add set/get RTC.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-19 16:36:21 +01:00
Pol Henarejos
f108eebb93 Fix LED default parameters in Pimoroni boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-15 01:17:13 +01:00
Pol Henarejos
263e554cc6 Upgrade to v8.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:50:58 +01:00
Pol Henarejos
7de98552d1 Fix button logic.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:39:35 +01:00
Pol Henarejos
08dc94a144 Disable button press by default since LED may not be properly configured until it is commissioned.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:37:18 +01:00
Pol Henarejos
7e6e3c8f3c Fix build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:36:09 +01:00
Pol Henarejos
6305ea11ab Blink led three times to acknowledge proper commissioning.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:15:45 +01:00
Pol Henarejos
4df616082e Fix led for pimoroni boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 22:03:35 +01:00
Pol Henarejos
3bf035d68a Zeroize pkey
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 22:02:58 +01:00
Pol Henarejos
7dc7be0909 Add device public key recovery and upload attestation certification.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-15 14:34:04 +01:00
Pol Henarejos
015fb61759 Add sign with keydev to rescue.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-15 01:17:26 +01:00
Pol Henarejos
1f4d638119 Build minimal picokey app.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-14 18:45:02 +01:00
Pol Henarejos
05fe0596ef Revert "Move EDDSA to another branch."
This reverts commit 09ec0767b6.
2025-12-11 15:42:30 +01:00
Pol Henarejos
d86371bb2c Revert "Move Secure Boot to another branch."
This reverts commit 8cb2484aa3.
2025-12-11 15:42:21 +01:00
Pol Henarejos
8cb2484aa3 Move Secure Boot to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 21:37:36 +01:00
Pol Henarejos
7583ecff18 Fix applet cmp
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 19:15:22 +01:00
Pol Henarejos
09ec0767b6 Move EDDSA to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 15:36:29 +01:00
Pol Henarejos
d0dea3d0c5 Fix MSOS/BOS descriptor.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-03 16:34:05 +01:00
Pol Henarejos
53d3a7ac91 Fix OTP button press in ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-02 14:38:07 +01:00
Pol Henarejos
2438356d83 Set anti-rollback version only when the binary is signed.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-02 09:39:17 +01:00
Pol Henarejos
79b69bfd7e Add WHOLE_ARCHIVE property.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-02 09:29:34 +01:00
Pol Henarejos
d189c2978c Add anti-rollback argument.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-01 23:41:29 +01:00
Pol Henarejos
c1cc33fd9d Upodate mbedtls only when necessary.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-01 17:02:47 +01:00
Pol Henarejos
2d72a157d5 Fix on AID selection. It should support shorter AID if matches.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-01 01:44:29 +01:00
Pol Henarejos
711a4df490 Upgrade to v8.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-30 18:30:24 +01:00
Pol Henarejos
66f31c15b6 Upgrade to mbedtls v3.6.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-30 18:28:13 +01:00
Pol Henarejos
fa119d0c6e Fix build for ESP32.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-28 00:12:26 +01:00
Pol Henarejos
b67e9ac143 Fix key generation for RP2040.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-28 00:12:18 +01:00
Pol Henarejos
5d3d10b62b Fix declaration.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-28 00:12:06 +01:00
Pol Henarejos
27938f0d9b Add reboot bootsel command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-28 00:11:54 +01:00
Pol Henarejos
20117d1609 Add read secure boot status.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:06:44 +01:00
Pol Henarejos
8f4f5373cf Do not use secboot in Phy.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:06:31 +01:00
Pol Henarejos
d4971bba19 Fix get secure boot status.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:06:20 +01:00
Pol Henarejos
2001006a16 Fix otp build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-17 12:23:16 +01:00
Pol Henarejos
7c5f729b69 Add is_secure_boot_enable and is_secure_lock_enabled to PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-17 12:20:44 +01:00
Pol Henarejos
07bbadf34c Add support for reading memory status.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-17 11:52:25 +01:00
Pol Henarejos
ed848d005f Fix curious bug when FIDO+OpenPGP+CCID connection is used in some circumstances.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 21:12:47 +01:00
Pol Henarejos
e6c0227996 Fix VIDPID PHY Read.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 21:11:57 +01:00
Pol Henarejos
84f7952817 Add support for PHY read.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 20:13:42 +01:00
Pol Henarejos
116aca7697 Fix #if/else logic.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 20:13:42 +01:00
Pol Henarejos
d410a4cfc2 Add support for RP2354.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-15 19:56:46 +01:00
Pol Henarejos
9b6d6f6736 Fix build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-28 09:36:41 +01:00
Pol Henarejos
8f907b25ba Relicense project under the GNU Affero General Public License v3 (AGPLv3)
and add the Enterprise / Commercial licensing option.

Main changes:
- Replace GPLv3 headers with AGPLv3 headers in source files.
- Update LICENSE file to the full AGPLv3 text.
- Add ENTERPRISE.md describing the dual-licensing model:
  * Community Edition: AGPLv3 (strong copyleft, including network use).
  * Enterprise / Commercial Edition: proprietary license for production /
    multi-user / OEM use without the obligation to disclose derivative code.
- Update README with a new "License and Commercial Use" section pointing to
  ENTERPRISE.md and clarifying how companies can obtain a commercial license.

Why this change:
- AGPLv3 ensures that modified versions offered as a service or deployed
  in production environments must provide corresponding source code.
- The Enterprise / Commercial edition provides organizations with an
  alternative proprietary license that allows internal, large-scale, or OEM
  use (bulk provisioning, policy enforcement, inventory / revocation,
  custom attestation, signed builds) without AGPL disclosure obligations.

This commit formally marks the first release that is dual-licensed:
AGPLv3 for the Community Edition and a proprietary commercial license
for Enterprise customers.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-26 20:06:16 +01:00
Pol Henarejos
233e6594c6 Add casts to fix warnings.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-12 18:52:07 +02:00
Pol Henarejos
eca6807f8e Fix win build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-12 18:51:46 +02:00
Pol Henarejos
14d5a75571 Add some win compatibility.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-12 18:51:29 +02:00
Pol Henarejos
e56624948b Expose gettimeofday.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-12 18:47:43 +02:00
Pol Henarejos
200d59f91b ADd strlcpy when necessary.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-12 18:47:34 +02:00
Pol Henarejos
c165ae4838 Add set of secure functions to derive keys based on OTP, if available, and pico_serial as a fallback. PIN is also an input vector, which defines a separated domain.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-08 00:30:41 +02:00
Pol Henarejos
0ddfdf8134 Add sanity check.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-07 21:11:28 +02:00
Pol Henarejos
031d76737b Add pico_serial_hash as a source of unique (almost) 32 bytes string.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-07 21:11:06 +02:00
Pol Henarejos
df94d10f8f Fix print macro.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-07 21:10:19 +02:00
Pol Henarejos
b3b2b67034 Add const to OTP functions.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
3eff2442c6 Fix is_empty_otp_buffer when a register is invalid.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
a7e1cf028b To prevent the PVC attack, MKEK and DEV keys are migrated to another OTP page.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
e14a12b002 Add OTP chaff to avoid passive voltage contrast (PVC) attacks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
d39732c613 Allow data partition write only with secure code (not in BL).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
56c2ef0cc1 Fix alignment when programming OTP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-10-06 14:21:41 +02:00
Pol Henarejos
9b294b9685 Fix build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-30 17:25:55 +02:00
Pol Henarejos
5048e07f81 Add hash functions using OTP as feed when available.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-28 20:28:28 +02:00
Pol Henarejos
d63ed56e0e Fix phy_data idVendor/idProduct when not set.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-28 20:28:28 +02:00
Pol Henarejos
afe2b28fab Merge remote-tracking branch 'origin/main' 2025-09-24 01:12:07 +02:00
Pol Henarejos
838f342877 Fix HID processing only for CTAP_HID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-24 01:11:45 +02:00
Pol Henarejos
1a1d03ab2f Add compatibility for non-pico boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-24 01:11:19 +02:00
Pol Henarejos
809dc3d16d Add missing files.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-23 17:03:38 +02:00
Pol Henarejos
70c0c1bf81 Fix conditional build for non-pico platforms.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-23 16:59:59 +02:00
Pol Henarejos
cff3f8f677 Fix interface conditional builds.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-23 16:56:34 +02:00
Pol Henarejos
6f6004c57b Fix build for non-pico boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-23 00:02:20 +02:00
Pol Henarejos
0b49fe4e1b Fix build for non-pico boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-22 23:52:47 +02:00
Pol Henarejos
4edc506759 Fix build for non-pico boards.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-22 23:35:46 +02:00
Pol Henarejos
e55014cfb3 Fix set version for non-pico platforms.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-22 17:31:48 +02:00
Pol Henarejos
2211fafe32 Fix non-pico build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-22 17:30:39 +02:00
Pol Henarejos
276f1b2ae8 Fix build for non-pico platforms.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-22 17:27:08 +02:00
Pol Henarejos
202d32d13d Fix descriptor description when there are disabled interfaces.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-02 01:20:07 +02:00
Pol Henarejos
95f02b6ea7 Add dummy led driver to avoid crashes in case a non-supported board is built.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-01 22:02:08 +02:00
Pol Henarejos
2e2b78445c Load led driver depending on PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-01 21:27:43 +02:00
Pol Henarejos
da44fd21d4 Add support for led driver in PHY.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-09-01 21:27:15 +02:00
Pol Henarejos
365567d12b Upgrade tinycbor to 0.6.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-29 01:20:09 +02:00
Pol Henarejos
a3406572cd Fix uint16 endianness that affected chained RAPDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-29 01:17:37 +02:00
Pol Henarejos
8321db1f67 Fix build for rp2350.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-25 01:39:06 +02:00
Pol Henarejos
5984d1f72d NK compatibility improvements.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-25 01:33:46 +02:00
Pol Henarejos
685e660ec0 Call pico_sdk_init in the cmake.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-25 01:33:23 +02:00
Pol Henarejos
3863842536 Fix crash in case response buffer is not 16bit aligned.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-08-24 01:22:59 +02:00
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
120 changed files with 14429 additions and 2698 deletions

50
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,50 @@
## Summary
Describe in plain language what this PR does and why.
- What problem does it solve?
- Is it a bug fix, a new feature, a cleanup/refactor…?
## Details / Impact
Please include any relevant details:
- Hardware / board(s) tested:
- Firmware / commit/base version:
- Security impact (if any):
- e.g. changes PIN handling, touches key storage, affects attestation, etc.
- Behavior changes:
- e.g. new command, new API surface, different defaults, etc.
## Testing
How did you test this change?
- Steps to reproduce / validate:
- Expected vs actual results:
- Any logs / traces (please remove secrets):
## Licensing confirmation (required)
By checking the box below, you confirm ALL of the following:
- You are the author of this contribution, or you have the right to contribute it.
- You have read `CONTRIBUTING.md`.
- You agree that this contribution may be merged, used, modified, and redistributed:
- under the AGPLv3 Community Edition, **and**
- under any proprietary / commercial / Enterprise editions of this project,
now or in the future.
- You understand that submitting this PR does not create any support obligation,
SLA, or guarantee of merge.
**I confirm the above licensing terms:**
- [ ] Yes, I agree
## Anything else?
Optional: mention known limitations, follow-ups, or if this is related to an existing Issue.

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.DS_Store*

6
.gitmodules vendored
View File

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

View File

@@ -1,82 +1,89 @@
# #
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). # This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
# Copyright (c) 2022 Pol Henarejos. # Copyright (c) 2022 Pol Henarejos.
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3. # the Free Software Foundation, version 3.
# #
# This program is distributed in the hope that it will be useful, but # This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of # WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
if(ESP_PLATFORM) if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src) set(EXTRA_COMPONENT_DIRS src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) 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() else()
if(NOT ENABLE_EMULATION)
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake)
endif()
if(ENABLE_EMULATION) project(pico_rescue C CXX ASM)
else()
include(pico_sdk_import.cmake)
endif()
project(pico_keys C CXX ASM) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11) if(NOT DEFINED __FOR_CI)
set(CMAKE_CXX_STANDARD 17) set(__FOR_CI 0)
endif()
if(__FOR_CI)
add_compile_definitions(__FOR_CI)
endif()
if(ENABLE_EMULATION) add_executable(pico_rescue)
else() endif()
pico_sdk_init()
endif()
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_CCID 1)
set(USB_ITF_HID 1) set(USB_ITF_WCID 1)
include(pico_keys_sdk_import.cmake) include(cmake/version.cmake)
include(cmake/options.cmake OPTIONAL)
add_executable(pico_keys_sdk_exe) include(picokeys_sdk_import.cmake)
if(NOT ESP_PLATFORM)
target_compile_options(pico_keys_sdk_exe PUBLIC set(SOURCES ${PICOKEYS_SOURCES})
-Wall endif()
-Werror list(APPEND SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
${CMAKE_CURRENT_LIST_DIR}/src/version.c
) )
if(ENABLE_EMULATION) SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/picokeys_version.h")
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) if(ESP_PLATFORM)
project(pico_rescue)
endif() endif()
if(NOT ESP_PLATFORM)
target_sources(pico_rescue PUBLIC ${SOURCES})
target_include_directories(pico_rescue PUBLIC ${INCLUDES})
target_compile_options(pico_rescue PRIVATE -Wall)
if(NOT MSVC)
target_compile_options(pico_rescue PRIVATE -Werror)
endif()
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(pico_rescue PRIVATE -fdata-sections -ffunction-sections)
endif()
if(APPLE)
target_link_options(pico_rescue PRIVATE -Wl,-dead_strip)
elseif(MSVC)
target_compile_options(pico_rescue PRIVATE -WX)
target_link_libraries(pico_rescue PRIVATE wsock32 ws2_32 Bcrypt Ncrypt)
else()
target_link_options(pico_rescue PRIVATE -Wl,--gc-sections)
endif()
target_link_libraries(pico_rescue PRIVATE pthread m)
else()
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif()
endif() endif()

141
LICENSE
View File

@@ -1,5 +1,5 @@
GNU GENERAL PUBLIC LICENSE GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
@@ -7,17 +7,15 @@
Preamble Preamble
The GNU General Public License is a free, copyleft license for The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works. software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast, to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the software for all its users.
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you price. Our General Public Licenses are designed to make sure that you
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things. free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you Developers that use our General Public Licenses protect your rights
these rights or asking you to surrender the rights. Therefore, you have with two steps: (1) assert copyright on the software, and (2) offer
certain responsibilities if you distribute copies of the software, or if you this License which gives you legal permission to copy, distribute
you modify it: responsibilities to respect the freedom of others. and/or modify the software.
For example, if you distribute copies of such a program, whether A secondary benefit of defending all users' freedom is that
gratis or for a fee, you must pass on to the recipients the same improvements made in alternate versions of the program, if they
freedoms that you received. You must make sure that they, too, receive receive widespread use, become available for other developers to
or can get the source code. And you must show them these terms so they incorporate. Many developers of free software are heartened and
know their rights. encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
Developers that use the GNU GPL protect your rights with two steps: The GNU Affero General Public License is designed specifically to
(1) assert copyright on the software, and (2) offer you this License ensure that, in such cases, the modified source code becomes available
giving you legal permission to copy, distribute and/or modify it. to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
For the developers' and authors' protection, the GPL clearly explains An older license, called the Affero General Public License and
that there is no warranty for this free software. For both users' and published by Affero, was designed to accomplish similar goals. This is
authors' sake, the GPL requires that modified versions be marked as a different license, not a version of the Affero GPL, but Affero has
changed, so that their problems will not be attributed erroneously to released a new version of the Affero GPL which permits relicensing under
authors of previous versions. this license.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
@@ -72,7 +60,7 @@ modification follow.
0. Definitions. 0. Definitions.
"This License" refers to version 3 of the GNU General Public License. "This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks. works, such as semiconductor masks.
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program. License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License. 13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work, License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License, but the work with which it is combined will remain governed by version
section 13, concerning interaction through a network will apply to the 3 of the GNU General Public License.
combination as such.
14. Revised Versions of this License. 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will the GNU Affero General Public License from time to time. Such new versions
be similar in spirit to the present version, but may differ in detail to will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns. address new problems or concerns.
Each version is given a distinguishing version number. If the Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation. by the Free Software Foundation.
If the Program specifies that a proxy can decide which future If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you public statement of acceptance of a version permanently authorizes you
to choose that version for the Program. to choose that version for the Program.
@@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C) <year> <name of author> Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Affero 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 Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short If your software can interact with users remotely through a computer
notice like this when it starts in an interactive mode: network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
<program> Copyright (C) <year> <name of author> interface could display a "Source" link that leads users to an archive
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. of the code. There are many ways you could offer source, and different
This is free software, and you are welcome to redistribute it solutions will be better for different programs; see section 13 for the
under certain conditions; type `show c' for details. specific requirements.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school, You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

189
cmake/build_helpers.cmake Normal file
View File

@@ -0,0 +1,189 @@
#
# Pico Keys SDK build helper functions
#
function(picokeys_apply_strict_flags)
set(options)
set(oneValueArgs FILTER_REGEX)
set(multiValueArgs SOURCES)
cmake_parse_arguments(PKAS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT PKAS_SOURCES)
return()
endif()
if (MSVC)
set(PICOKEYS_STRICT_FLAGS
-Wall
-Zc:strictStrings
-WX
)
else ()
set(PICOKEYS_STRICT_FLAGS
-pipe
-funsigned-char
-fstrict-aliasing
-fdiagnostics-color=auto
-Wextra
-Wchar-subscripts
-Wundef
-Wshadow
-Wcast-align
-Wwrite-strings
-Wunused
-Wuninitialized
-Wpointer-arith
-Wredundant-decls
-Winline
-Wformat
-Wformat-security
-Wswitch-enum
-Winit-self
-Wmissing-include-dirs
-Wempty-body
-Wmissing-prototypes
-Wstrict-prototypes
-Wold-style-definition
-Wbad-function-cast
-Wnested-externs
-Wmissing-declarations
-Werror
)
endif()
foreach(src IN LISTS PKAS_SOURCES)
if(PKAS_FILTER_REGEX)
if(NOT src MATCHES "${PKAS_FILTER_REGEX}")
continue()
endif()
endif()
set_property(SOURCE "${src}" APPEND PROPERTY COMPILE_OPTIONS ${PICOKEYS_STRICT_FLAGS})
endforeach()
endfunction()
function(picokeys_configure_host_target)
set(options)
set(oneValueArgs TARGET STRICT_FILTER_REGEX MACOS_APP_BUNDLE_ID MACOS_APP_DEVELOPMENT_TEAM)
set(multiValueArgs SOURCES INCLUDES)
cmake_parse_arguments(PKCHT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT PKCHT_TARGET OR ESP_PLATFORM)
return()
endif()
target_sources(${PKCHT_TARGET} PUBLIC ${PKCHT_SOURCES})
target_include_directories(${PKCHT_TARGET} PUBLIC ${PKCHT_INCLUDES})
target_compile_options(${PKCHT_TARGET} PRIVATE -Wall)
picokeys_apply_strict_flags(
SOURCES ${PKCHT_SOURCES}
FILTER_REGEX "${PKCHT_STRICT_FILTER_REGEX}"
)
if(NOT MSVC)
target_compile_options(${PKCHT_TARGET} PRIVATE -Werror)
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
if(${COMPILER_COLON} GREATER_EQUAL 0)
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-error=use-after-free)
endif()
endif()
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(${PKCHT_TARGET} PRIVATE -fdata-sections -ffunction-sections)
endif()
if(APPLE)
target_link_options(${PKCHT_TARGET} PRIVATE -Wl,-dead_strip)
if(MACOS_APP)
target_link_libraries(${PKCHT_TARGET} PRIVATE
"-framework Security"
"-framework CoreFoundation"
)
if(CMAKE_GENERATOR STREQUAL "Xcode")
if("${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}" STREQUAL "")
message(FATAL_ERROR "MACOS_APP=1 with Xcode requires MACOS_APP_DEVELOPMENT_TEAM")
endif()
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-missing-include-dirs)
set_target_properties(${PKCHT_TARGET} PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_GUI_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
MACOSX_BUNDLE_BUNDLE_NAME "${PKCHT_TARGET}"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic"
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/pico_novus.entitlements"
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES"
)
endif()
endif()
if(DEBUG_APDU)
target_compile_options(${PKCHT_TARGET} PRIVATE
-fsanitize=address
-g
-O1
-fno-omit-frame-pointer
)
target_link_options(${PKCHT_TARGET} PRIVATE
-fsanitize=address
-g
-O1
-fno-omit-frame-pointer
)
endif()
endif()
endif()
endfunction()
function(picokeys_add_macos_app_xcode_driver)
set(options)
set(oneValueArgs TARGET BUNDLE_ID SIGN_IDENTITY DEVELOPMENT_TEAM)
cmake_parse_arguments(PKMXD "${options}" "${oneValueArgs}" "" ${ARGN})
if(NOT PKMXD_TARGET)
return()
endif()
if(NOT (APPLE AND ENABLE_EMULATION AND MACOS_APP AND NOT CMAKE_GENERATOR STREQUAL "Xcode" AND NOT MACOS_APP_XCODE_DRIVER))
return()
endif()
if("${PKMXD_DEVELOPMENT_TEAM}" STREQUAL "")
message(FATAL_ERROR "MACOS_APP=1 requires MACOS_APP_DEVELOPMENT_TEAM")
endif()
set(MACOS_APP_XCODE_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-macos-app-xcode")
set(MACOS_APP_XCODE_FORWARD_ARGS)
get_cmake_property(_cache_vars CACHE_VARIABLES)
foreach(_cv ${_cache_vars})
if(_cv MATCHES "^(ENABLE_|DEBUG_APDU$|VIDPID$|USB_VID$|USB_PID$|USE_OPENSSL$|CMAKE_BUILD_TYPE$)")
get_property(_cv_type CACHE ${_cv} PROPERTY TYPE)
if(NOT _cv_type STREQUAL "INTERNAL")
set(_cv_val "${${_cv}}")
string(REPLACE ";" "\\;" _cv_val "${_cv_val}")
list(APPEND MACOS_APP_XCODE_FORWARD_ARGS "-D${_cv}:${_cv_type}=${_cv_val}")
endif()
endif()
endforeach()
add_custom_target(${PKMXD_TARGET}_xcode ALL
COMMAND cmake -S "${CMAKE_CURRENT_SOURCE_DIR}" -B "${MACOS_APP_XCODE_BUILD_DIR}" -G Xcode
-DENABLE_EMULATION=1
-DMACOS_APP=1
-DMACOS_APP_XCODE_DRIVER=1
-DMACOS_APP_BUNDLE_ID="${PKMXD_BUNDLE_ID}"
-DMACOS_APP_SIGN_IDENTITY="${PKMXD_SIGN_IDENTITY}"
-DMACOS_APP_DEVELOPMENT_TEAM="${PKMXD_DEVELOPMENT_TEAM}"
${MACOS_APP_XCODE_FORWARD_ARGS}
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/Debug/include"
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources-normal/arm64"
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources/arm64"
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources"
COMMAND xcodebuild -allowProvisioningUpdates -project "${MACOS_APP_XCODE_BUILD_DIR}/${PKMXD_TARGET}.xcodeproj" -scheme "${PKMXD_TARGET}" -configuration Debug build
COMMENT "Building signed ${PKMXD_TARGET}.app via Xcode"
VERBATIM
)
endfunction()

131
cmake/deps.cmake Normal file
View File

@@ -0,0 +1,131 @@
include(FetchContent)
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
configure_bool_option(
ENABLE_EDDSA
""
"EdDSA support:\t\t enabled"
"EdDSA support:\t\t disabled"
)
set(MBEDTLS_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mbedtls")
set(TINYCBOR_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/tinycbor")
set(CJSON_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/cjson")
set(MLKEM_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mlkem")
set(MLDSA_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mldsa")
set(LIBCVC_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/libcvc")
set(PICOKEYS_MBEDTLS_STD_REPO "https://github.com/Mbed-TLS/mbedtls.git")
set(PICOKEYS_MBEDTLS_STD_REF "v3.6.6")
set(PICOKEYS_MBEDTLS_EDDSA_REPO "https://github.com/polhenarejos/mbedtls.git")
set(PICOKEYS_MBEDTLS_EDDSA_REF "mbedtls-3.6-eddsa")
set(PICOKEYS_TINYCBOR_REPO "https://github.com/intel/tinycbor.git")
set(PICOKEYS_TINYCBOR_REF "v0.6.1")
set(PICOKEYS_CJSON_REPO "https://github.com/DaveGamble/cJSON.git")
set(PICOKEYS_CJSON_REF "v1.7.19")
set(PICOKEYS_MLKEM_REPO "https://github.com/pq-code-package/mlkem-native.git")
set(PICOKEYS_MLKEM_REF "v1.1.0")
set(PICOKEYS_MLDSA_REPO "https://github.com/pq-code-package/mldsa-native.git")
set(PICOKEYS_MLDSA_REF "v1.0.0-beta")
set(PICOKEYS_LIBCVC_REPO "https://github.com/polhenarejos/libcvc.git")
set(PICOKEYS_LIBCVC_REF "main")
set(PICOKEYS_FETCH_DEPS_ON_DEMAND ON CACHE BOOL "Fetch third-party deps into pico-keys-sdk/third-party when missing")
function(picokeys_sync_dep name repo ref dest)
set(_marker "${dest}/.picokeys_dep_source")
set(_need_fetch OFF)
if(NOT EXISTS "${dest}")
if(NOT PICOKEYS_FETCH_DEPS_ON_DEMAND)
message(FATAL_ERROR "${name} source code not found at ${dest}. Enable PICOKEYS_FETCH_DEPS_ON_DEMAND or provide the source tree manually.")
endif()
set(_need_fetch ON)
else()
set(_repo_ok OFF)
set(_ref_ok OFF)
if(EXISTS "${_marker}")
file(STRINGS "${_marker}" _meta_lines)
foreach(_line IN LISTS _meta_lines)
if(_line STREQUAL "REPO=${repo}")
set(_repo_ok ON)
endif()
if(_line STREQUAL "REF=${ref}")
set(_ref_ok ON)
endif()
endforeach()
endif()
if(NOT _repo_ok OR NOT _ref_ok)
set(_need_fetch ON)
endif()
endif()
if(_need_fetch)
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=updating (this may take a few seconds)")
if(EXISTS "${dest}")
file(REMOVE_RECURSE "${dest}")
endif()
execute_process(
COMMAND git clone ${repo} ${dest}
RESULT_VARIABLE _clone_rc
OUTPUT_VARIABLE _clone_out
ERROR_VARIABLE _clone_err
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT _clone_rc EQUAL 0)
message(FATAL_ERROR "Failed to clone ${name} from ${repo}\nstdout: ${_clone_out}\nstderr: ${_clone_err}")
endif()
execute_process(
COMMAND git -C ${dest} checkout ${ref}
RESULT_VARIABLE _checkout_rc
OUTPUT_VARIABLE _checkout_out
ERROR_VARIABLE _checkout_err
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT _checkout_rc EQUAL 0)
message(FATAL_ERROR "Failed to checkout ${name} ref ${ref}\nstdout: ${_checkout_out}\nstderr: ${_checkout_err}")
endif()
if(NOT EXISTS "${dest}")
message(FATAL_ERROR "Failed to fetch ${name} into ${dest}")
endif()
file(WRITE "${_marker}" "REPO=${repo}\nREF=${ref}\n")
else()
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=cached")
endif()
endfunction()
if(NOT ESP_PLATFORM)
if(ENABLE_EDDSA)
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_EDDSA_REPO}")
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_EDDSA_REF}")
add_compile_definitions(
MBEDTLS_ECP_DP_ED25519_ENABLED=1
MBEDTLS_ECP_DP_ED448_ENABLED=1
MBEDTLS_EDDSA_C=1
MBEDTLS_SHA3_C=1
)
else()
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_STD_REPO}")
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_STD_REF}")
endif()
picokeys_sync_dep(mbedtls_dep "${MBEDTLS_ORIGIN}" "${MBEDTLS_REF}" "${MBEDTLS_PATH}")
endif()
if(USB_ITF_HID)
picokeys_sync_dep(tinycbor_dep "${PICOKEYS_TINYCBOR_REPO}" "${PICOKEYS_TINYCBOR_REF}" "${TINYCBOR_PATH}")
endif()
if(USB_ITF_LWIP)
picokeys_sync_dep(cjson_dep "${PICOKEYS_CJSON_REPO}" "${PICOKEYS_CJSON_REF}" "${CJSON_PATH}")
endif()
if(ENABLE_PQC)
picokeys_sync_dep(mlkem_dep "${PICOKEYS_MLKEM_REPO}" "${PICOKEYS_MLKEM_REF}" "${MLKEM_PATH}")
picokeys_sync_dep(mldsa_dep "${PICOKEYS_MLDSA_REPO}" "${PICOKEYS_MLDSA_REF}" "${MLDSA_PATH}")
endif()
if(ENABLE_LIBCVC)
picokeys_sync_dep(libcvc_dep "${PICOKEYS_LIBCVC_REPO}" "${PICOKEYS_LIBCVC_REF}" "${LIBCVC_PATH}")
endif()

View File

@@ -1,4 +1,4 @@
function(dict command dict ) function(dict command dict)
if(command STREQUAL SET) if(command STREQUAL SET)
set(arg_key ${ARGV2}) set(arg_key ${ARGV2})
set(arg_value ${ARGV3}) set(arg_value ${ARGV3})
@@ -10,7 +10,6 @@ function(dict command dict )
list(APPEND ${dict} "${arg_key}=${arg_value}") list(APPEND ${dict} "${arg_key}=${arg_value}")
set(${dict} "${${dict}}" PARENT_SCOPE) set(${dict} "${${dict}}" PARENT_SCOPE)
elseif(command STREQUAL GET) elseif(command STREQUAL GET)
set(arg_key ${ARGV2}) set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3}) set(arg_outvar ${ARGV3})
@@ -23,7 +22,6 @@ function(dict command dict )
list(GET ${dict} ${idx} kv) list(GET ${dict} ${idx} kv)
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}") string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
set(${arg_outvar} "${value}" PARENT_SCOPE) set(${arg_outvar} "${value}" PARENT_SCOPE)
elseif(command STREQUAL _IDX) elseif(command STREQUAL _IDX)
set(arg_key ${ARGV2}) set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3}) set(arg_outvar ${ARGV3})
@@ -34,10 +32,9 @@ function(dict command dict )
set(${arg_outvar} "${idx}" PARENT_SCOPE) set(${arg_outvar} "${idx}" PARENT_SCOPE)
return() return()
endif() endif()
math(EXPR idx ${idx}+1) math(EXPR idx ${idx} + 1)
endforeach() endforeach()
set(${arg_outvar} "-1" PARENT_SCOPE) set(${arg_outvar} "-1" PARENT_SCOPE)
else() else()
message(FATAL_ERROR "dict does not recognize sub-command ${command}") message(FATAL_ERROR "dict does not recognize sub-command ${command}")
endif() endif()

144
cmake/openssl.cmake Normal file
View File

@@ -0,0 +1,144 @@
#
# OpenSSL wrapper configuration for Pico Keys SDK.
# Keeps OpenSSL-specific build logic out of picokeys_sdk_import.cmake.
#
if(NOT DEFINED USE_OPENSSL)
set(USE_OPENSSL 0)
endif()
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 0)
set(USE_OPENSSL_EMULATION_WRAPPER 0)
if(ENABLE_EMULATION AND USE_OPENSSL)
find_package(OpenSSL QUIET)
if(OpenSSL_FOUND)
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 1)
set(USE_OPENSSL_EMULATION_WRAPPER 1)
message(STATUS "OpenSSL backend:\t\t enabled")
else()
message(STATUS "OpenSSL backend:\t\t disabled (OpenSSL not found)")
endif()
elseif(ENABLE_EMULATION)
message(STATUS "OpenSSL backend:\t\t disabled")
endif()
if(USE_OPENSSL_EMULATION_WRAPPER)
add_definitions(
-Dmbedtls_platform_zeroize=openssl_mbedtls_platform_zeroize
-Dmbedtls_sha256=openssl_mbedtls_sha256
-Dmbedtls_sha256_init=openssl_mbedtls_sha256_init
-Dmbedtls_sha256_free=openssl_mbedtls_sha256_free
-Dmbedtls_sha256_starts=openssl_mbedtls_sha256_starts
-Dmbedtls_sha256_update=openssl_mbedtls_sha256_update
-Dmbedtls_sha256_finish=openssl_mbedtls_sha256_finish
-Dmbedtls_md_info_from_type=openssl_mbedtls_md_info_from_type
-Dmbedtls_md_get_size=openssl_mbedtls_md_get_size
-Dmbedtls_md=openssl_mbedtls_md
-Dmbedtls_md_hmac=openssl_mbedtls_md_hmac
-Dmbedtls_md_init=openssl_mbedtls_md_init
-Dmbedtls_md_free=openssl_mbedtls_md_free
-Dmbedtls_md_setup=openssl_mbedtls_md_setup
-Dmbedtls_md_starts=openssl_mbedtls_md_starts
-Dmbedtls_md_update=openssl_mbedtls_md_update
-Dmbedtls_md_finish=openssl_mbedtls_md_finish
-Dmbedtls_hkdf=openssl_mbedtls_hkdf
-Dmbedtls_aes_init=openssl_mbedtls_aes_init
-Dmbedtls_aes_free=openssl_mbedtls_aes_free
-Dmbedtls_aes_setkey_enc=openssl_mbedtls_aes_setkey_enc
-Dmbedtls_aes_setkey_dec=openssl_mbedtls_aes_setkey_dec
-Dmbedtls_aes_crypt_ecb=openssl_mbedtls_aes_crypt_ecb
-Dmbedtls_aes_crypt_cbc=openssl_mbedtls_aes_crypt_cbc
-Dmbedtls_aes_crypt_cfb128=openssl_mbedtls_aes_crypt_cfb128
-Dmbedtls_aes_crypt_ofb=openssl_mbedtls_aes_crypt_ofb
-Dmbedtls_aes_crypt_ctr=openssl_mbedtls_aes_crypt_ctr
-Dmbedtls_aes_xts_init=openssl_mbedtls_aes_xts_init
-Dmbedtls_aes_xts_free=openssl_mbedtls_aes_xts_free
-Dmbedtls_aes_xts_setkey_enc=openssl_mbedtls_aes_xts_setkey_enc
-Dmbedtls_aes_xts_setkey_dec=openssl_mbedtls_aes_xts_setkey_dec
-Dmbedtls_aes_crypt_xts=openssl_mbedtls_aes_crypt_xts
-Dmbedtls_gcm_init=openssl_mbedtls_gcm_init
-Dmbedtls_gcm_free=openssl_mbedtls_gcm_free
-Dmbedtls_gcm_setkey=openssl_mbedtls_gcm_setkey
-Dmbedtls_gcm_crypt_and_tag=openssl_mbedtls_gcm_crypt_and_tag
-Dmbedtls_gcm_auth_decrypt=openssl_mbedtls_gcm_auth_decrypt
-Dmbedtls_ccm_init=openssl_mbedtls_ccm_init
-Dmbedtls_ccm_free=openssl_mbedtls_ccm_free
-Dmbedtls_ccm_setkey=openssl_mbedtls_ccm_setkey
-Dmbedtls_ccm_encrypt_and_tag=openssl_mbedtls_ccm_encrypt_and_tag
-Dmbedtls_ccm_auth_decrypt=openssl_mbedtls_ccm_auth_decrypt
-Dmbedtls_chachapoly_init=openssl_mbedtls_chachapoly_init
-Dmbedtls_chachapoly_free=openssl_mbedtls_chachapoly_free
-Dmbedtls_chachapoly_setkey=openssl_mbedtls_chachapoly_setkey
-Dmbedtls_chachapoly_encrypt_and_tag=openssl_mbedtls_chachapoly_encrypt_and_tag
-Dmbedtls_chachapoly_auth_decrypt=openssl_mbedtls_chachapoly_auth_decrypt
-Dmbedtls_cipher_info_from_type=openssl_mbedtls_cipher_info_from_type
-Dmbedtls_cipher_cmac=openssl_mbedtls_cipher_cmac
-Dmbedtls_mpi_init=openssl_mbedtls_mpi_init
-Dmbedtls_mpi_free=openssl_mbedtls_mpi_free
-Dmbedtls_mpi_grow=openssl_mbedtls_mpi_grow
-Dmbedtls_mpi_lset=openssl_mbedtls_mpi_lset
-Dmbedtls_mpi_size=openssl_mbedtls_mpi_size
-Dmbedtls_mpi_read_binary=openssl_mbedtls_mpi_read_binary
-Dmbedtls_mpi_read_binary_le=openssl_mbedtls_mpi_read_binary_le
-Dmbedtls_mpi_write_binary=openssl_mbedtls_mpi_write_binary
-Dmbedtls_mpi_write_binary_le=openssl_mbedtls_mpi_write_binary_le
-Dmbedtls_mpi_copy=openssl_mbedtls_mpi_copy
-Dmbedtls_mpi_cmp_mpi=openssl_mbedtls_mpi_cmp_mpi
-Dmbedtls_mpi_cmp_int=openssl_mbedtls_mpi_cmp_int
-Dmbedtls_mpi_add_mpi=openssl_mbedtls_mpi_add_mpi
-Dmbedtls_mpi_add_int=openssl_mbedtls_mpi_add_int
-Dmbedtls_mpi_sub_abs=openssl_mbedtls_mpi_sub_abs
-Dmbedtls_mpi_mod_mpi=openssl_mbedtls_mpi_mod_mpi
-Dmbedtls_asn1_get_tag=openssl_mbedtls_asn1_get_tag
-Dmbedtls_asn1_get_int=openssl_mbedtls_asn1_get_int
-Dmbedtls_asn1_get_alg_null=openssl_mbedtls_asn1_get_alg_null
-Dmbedtls_oid_get_md_hmac=openssl_mbedtls_oid_get_md_hmac
-Dmbedtls_pkcs5_pbkdf2_hmac_ext=openssl_mbedtls_pkcs5_pbkdf2_hmac_ext
-Dmbedtls_pkcs5_pbes2_ext=openssl_mbedtls_pkcs5_pbes2_ext
-Dmbedtls_rsa_gen_key=openssl_mbedtls_rsa_gen_key
-Dmbedtls_rsa_init=openssl_mbedtls_rsa_init
-Dmbedtls_rsa_free=openssl_mbedtls_rsa_free
-Dmbedtls_rsa_set_padding=openssl_mbedtls_rsa_set_padding
-Dmbedtls_rsa_get_len=openssl_mbedtls_rsa_get_len
-Dmbedtls_rsa_import=openssl_mbedtls_rsa_import
-Dmbedtls_rsa_complete=openssl_mbedtls_rsa_complete
-Dmbedtls_rsa_check_pubkey=openssl_mbedtls_rsa_check_pubkey
-Dmbedtls_rsa_check_privkey=openssl_mbedtls_rsa_check_privkey
-Dmbedtls_ecp_curve_info_from_grp_id=openssl_mbedtls_ecp_curve_info_from_grp_id
-Dmbedtls_ecp_get_type=openssl_mbedtls_ecp_get_type
-Dmbedtls_ecp_group_init=openssl_mbedtls_ecp_group_init
-Dmbedtls_ecp_group_free=openssl_mbedtls_ecp_group_free
-Dmbedtls_ecp_group_load=openssl_mbedtls_ecp_group_load
-Dmbedtls_ecp_keypair_init=openssl_mbedtls_ecp_keypair_init
-Dmbedtls_ecp_keypair_free=openssl_mbedtls_ecp_keypair_free
-Dmbedtls_ecp_gen_key=openssl_mbedtls_ecp_gen_key
-Dmbedtls_ecp_mul=openssl_mbedtls_ecp_mul
-Dmbedtls_ecp_read_key=openssl_mbedtls_ecp_read_key
-Dmbedtls_ecp_write_key_ext=openssl_mbedtls_ecp_write_key_ext
-Dmbedtls_ecp_point_read_binary=openssl_mbedtls_ecp_point_read_binary
-Dmbedtls_ecp_point_write_binary=openssl_mbedtls_ecp_point_write_binary
-Dmbedtls_ecp_point_edwards=openssl_mbedtls_ecp_point_edwards
-Dmbedtls_ecp_check_pubkey=openssl_mbedtls_ecp_check_pubkey
-Dmbedtls_ecp_check_pub_priv=openssl_mbedtls_ecp_check_pub_priv
-Dmbedtls_ecdsa_init=openssl_mbedtls_ecdsa_init
-Dmbedtls_ecdsa_free=openssl_mbedtls_ecdsa_free
-Dmbedtls_ecdsa_genkey=openssl_mbedtls_ecdsa_genkey
-Dmbedtls_rsa_private=openssl_mbedtls_rsa_private
-Dmbedtls_rsa_pkcs1_sign=openssl_mbedtls_rsa_pkcs1_sign
-Dmbedtls_rsa_rsassa_pkcs1_v15_sign=openssl_mbedtls_rsa_rsassa_pkcs1_v15_sign
-Dmbedtls_rsa_pkcs1_verify=openssl_mbedtls_rsa_pkcs1_verify
-Dmbedtls_rsa_pkcs1_decrypt=openssl_mbedtls_rsa_pkcs1_decrypt
-Dmbedtls_ecdh_init=openssl_mbedtls_ecdh_init
-Dmbedtls_ecdh_free=openssl_mbedtls_ecdh_free
-Dmbedtls_ecdh_setup=openssl_mbedtls_ecdh_setup
-Dmbedtls_ecdh_gen_public=openssl_mbedtls_ecdh_gen_public
-Dmbedtls_ecdh_read_public=openssl_mbedtls_ecdh_read_public
-Dmbedtls_ecdh_calc_secret=openssl_mbedtls_ecdh_calc_secret
-Dmbedtls_ecdsa_sign=openssl_mbedtls_ecdsa_sign
-Dmbedtls_ecdsa_verify=openssl_mbedtls_ecdsa_verify
-Dmbedtls_ecdsa_write_signature=openssl_mbedtls_ecdsa_write_signature
-Dmbedtls_eddsa_sign=openssl_mbedtls_eddsa_sign
-Dmbedtls_eddsa_write_signature=openssl_mbedtls_eddsa_write_signature
)
endif()

14
cmake/options.cmake Normal file
View File

@@ -0,0 +1,14 @@
macro(configure_bool_option option_name define_name enabled_msg disabled_msg)
if(${option_name})
if(NOT "${define_name}" STREQUAL "")
add_compile_definitions(${define_name}=1)
endif()
message(STATUS "${enabled_msg}")
else()
if(NOT "${define_name}" STREQUAL "")
add_compile_definitions(${define_name}=0)
endif()
message(STATUS "${disabled_msg}")
endif()
endmacro()

View File

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

View File

@@ -0,0 +1,8 @@
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
idf_component_register(
SRCS ${CJSON_SOURCES}
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/cjson
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -0,0 +1,9 @@
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
idf_component_register(
SRCS ${LIBCVC_SOURCES}
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/libcvc/src ${PICOKEYS_SDK_DIR}/third-party/libcvc/include
REQUIRES mbedtls
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -0,0 +1,24 @@
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
file(GLOB_RECURSE MLDSA_SOURCES
${MLDSA_DIR}/src/*.c
)
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLDSA_SOURCES}
INCLUDE_DIRS ${MLDSA_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLD_CONFIG_PARAMETER_SET=44
MLD_CONFIG_MULTILEVEL_WITH_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,24 @@
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
file(GLOB_RECURSE MLDSA_SOURCES
${MLDSA_DIR}/src/*.c
)
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLDSA_SOURCES}
INCLUDE_DIRS ${MLDSA_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLD_CONFIG_PARAMETER_SET=65
MLD_CONFIG_MULTILEVEL_NO_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,24 @@
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
file(GLOB_RECURSE MLDSA_SOURCES
${MLDSA_DIR}/src/*.c
)
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLDSA_SOURCES}
INCLUDE_DIRS ${MLDSA_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLD_CONFIG_PARAMETER_SET=87
MLD_CONFIG_MULTILEVEL_NO_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,24 @@
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
file(GLOB_RECURSE MLKEM_SOURCES
${MLKEM_DIR}/src/*.c
)
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLKEM_SOURCES}
INCLUDE_DIRS ${MLKEM_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLK_CONFIG_PARAMETER_SET=1024
MLK_CONFIG_MULTILEVEL_NO_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,24 @@
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
file(GLOB_RECURSE MLKEM_SOURCES
${MLKEM_DIR}/src/*.c
)
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLKEM_SOURCES}
INCLUDE_DIRS ${MLKEM_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLK_CONFIG_PARAMETER_SET=512
MLK_CONFIG_MULTILEVEL_WITH_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,24 @@
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
file(GLOB_RECURSE MLKEM_SOURCES
${MLKEM_DIR}/src/*.c
)
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
idf_component_register(
SRCS ${MLKEM_SOURCES}
INCLUDE_DIRS ${MLKEM_DIR}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
MLK_CONFIG_PARAMETER_SET=768
MLK_CONFIG_MULTILEVEL_NO_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
target_compile_options(${COMPONENT_LIB} PRIVATE
-O2
-fno-builtin
-fno-strict-aliasing
)

View File

@@ -0,0 +1,46 @@
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
set(PICOKEYS_INCLUDE_DIRS
${PICOKEYS_SDK_DIR}/src
${PICOKEYS_SDK_DIR}/src/fs
${PICOKEYS_SDK_DIR}/src/otp
${PICOKEYS_SDK_DIR}/src/rng
${PICOKEYS_SDK_DIR}/src/usb
${PICOKEYS_SDK_DIR}/src/led
)
set(PICOKEYS_REQUIRES
bootloader_support
esp_partition
esp_tinyusb
efuse
mbedtls
tinycbor
lwip
cjson
)
if(ENABLE_PQC)
list(APPEND PICOKEYS_INCLUDE_DIRS
${PICOKEYS_SDK_DIR}/third-party/mlkem/mlkem
${PICOKEYS_SDK_DIR}/config/mlkem
${PICOKEYS_SDK_DIR}/third-party/mldsa/mldsa
${PICOKEYS_SDK_DIR}/config/mldsa
)
list(APPEND PICOKEYS_REQUIRES
mlkem512
mlkem768
mlkem1024
mldsa44
mldsa65
mldsa87
)
endif()
idf_component_register(
SRCS ${PICOKEYS_SOURCES}
INCLUDE_DIRS ${PICOKEYS_INCLUDE_DIRS}
REQUIRES ${PICOKEYS_REQUIRES}
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

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

View File

@@ -0,0 +1,8 @@
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
idf_component_register(
SRCS ${CBOR_SOURCES}
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/tinycbor/src
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

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

View File

@@ -330,7 +330,7 @@
//#define MBEDTLS_RSA_ALT //#define MBEDTLS_RSA_ALT
//#define MBEDTLS_SHA1_ALT //#define MBEDTLS_SHA1_ALT
#ifdef PICO_RP2350 #ifdef PICO_RP2350
#define MBEDTLS_SHA256_ALT //#define MBEDTLS_SHA256_ALT
#endif #endif
//#define MBEDTLS_SHA512_ALT //#define MBEDTLS_SHA512_ALT

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_ALL_H
#define MLD_ALL_H
/* API for MLDSA-44 */
#define MLD_CONFIG_PARAMETER_SET 44
#include "mldsa_native.h"
#undef MLD_CONFIG_PARAMETER_SET
#undef MLD_H
/* API for MLDSA-65 */
#define MLD_CONFIG_PARAMETER_SET 65
#include "mldsa_native.h"
#undef MLD_CONFIG_PARAMETER_SET
#undef MLD_H
/* API for MLDSA-87 */
#define MLD_CONFIG_PARAMETER_SET 87
#include "mldsa_native.h"
#undef MLD_CONFIG_PARAMETER_SET
#undef MLD_H
#endif /* !MLD_ALL_H */

View File

@@ -0,0 +1,10 @@
#pragma once
/* Disable all native/asm backends */
// #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH
/* No SuperCop */
#define MLD_CONFIG_NO_SUPERCOP
/* No verification API */
#define MLD_CONFIG_NO_VERIFY_API

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#if !defined(MLK_ALL_H)
#define MLK_ALL_H
/* API for MLKEM-512 */
#define MLK_CONFIG_PARAMETER_SET 512
#include "mlkem_native.h"
#undef MLK_CONFIG_PARAMETER_SET
#undef MLK_H
/* API for MLKEM-768 */
#define MLK_CONFIG_PARAMETER_SET 768
#include "mlkem_native.h"
#undef MLK_CONFIG_PARAMETER_SET
#undef MLK_H
/* API for MLKEM-1024 */
#define MLK_CONFIG_PARAMETER_SET 1024
#include "mlkem_native.h"
#undef MLK_CONFIG_PARAMETER_SET
#undef MLK_H
#endif /* !MLK_ALL_H */

View File

@@ -0,0 +1,13 @@
#pragma once
/* Disable all native/asm backends */
#define MLK_NO_NATIVE_BACKENDS 1
/* No CBMC */
#undef CBMC
/* Platform characteristics */
#define MLK_LITTLE_ENDIAN 1
/* Memory model */
#define MLK_NO_MALLOC 1

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful,
* WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* General Public License for more details. * GNU Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "common.h" #include "common.h"
@@ -286,3 +286,9 @@ int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
} }
return 0; return 0;
} }
void mbedtls_sha256_clone(mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src)
{
*dst = *src;
}

View File

@@ -3,22 +3,21 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful,
* WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* General Public License for more details. * GNU Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _SHA256_ALT_H_ #ifndef _SHA256_ALT_H_
#define _SHA256_ALT_H_ #define _SHA256_ALT_H_
#include "pico_keys.h"
#include "pico/sha256.h" #include "pico/sha256.h"
typedef struct mbedtls_sha256_context { typedef struct mbedtls_sha256_context {

View File

@@ -10,7 +10,7 @@
}, },
"partitions": [ "partitions": [
{ {
"name": "Pico Keys Firmware", "name": "PicoKeys Firmware",
"id": 0, "id": 0,
"start": 0, "start": 0,
"size": "1024K", "size": "1024K",
@@ -22,15 +22,30 @@
} }
}, },
{ {
"name": "Pico Keys Data", "name": "PicoKeys Data",
"id": 1, "id": 1,
"start": "2048K", "start": "1032K",
"size": "2048K", "size": "3064K",
"families": ["data"], "families": ["data"],
"permissions": { "permissions": {
"secure": "rw", "secure": "rw",
"nonsecure": "rw", "nonsecure": "",
"bootloader": "rw" "bootloader": "r"
},
"link": ["owner", 0],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
},
{
"name": "PicoKeys Binding",
"id": 2,
"start": "1024K",
"size": "8K",
"families": ["data"],
"permissions": {
"secure": "r",
"nonsecure": "",
"bootloader": "w"
}, },
"link": ["owner", 0], "link": ["owner", 0],
"ignored_during_arm_boot": true, "ignored_during_arm_boot": true,

Submodule mbedtls deleted from 107ea89daa

View File

@@ -1,436 +0,0 @@
#
# 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(SOURCES ${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(SOURCES ${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(SOURCES ${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(SOURCES ${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(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
)
endif()
add_definitions(-DENABLE_EMULATION)
set(SOURCES ${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(SOURCES ${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(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
)
set(LIBRARIES ${LIBRARIES} pico_sha256)
endif()
set(INTERNAL_SOURCES ${SOURCES})
set(SOURCES ${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 ${SOURCES})
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
endif()

671
picokeys_sdk_import.cmake Normal file
View File

@@ -0,0 +1,671 @@
#
# 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 OPTIONAL)
include(pico-keys-sdk/cmake/options.cmake OPTIONAL)
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 0x2E8A)
endif()
add_compile_definitions(USB_VID=${USB_VID})
if(NOT DEFINED USB_PID)
set(USB_PID 0x10FD)
endif()
add_compile_definitions(USB_PID=${USB_PID})
if(NOT DEFINED DEBUG_APDU)
set(DEBUG_APDU 0)
endif()
if(NOT DEFINED ENABLE_EMULATION)
set(ENABLE_EMULATION 0)
endif()
include(${CMAKE_CURRENT_LIST_DIR}/cmake/openssl.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/build_helpers.cmake)
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
configure_bool_option(
ENABLE_DELAYED_BOOT
""
"Delayed boot:\t\t enabled"
"Delayed boot:\t\t disabled"
)
if(ENABLE_DELAYED_BOOT)
add_compile_definitions(PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
endif()
if(USB_ITF_HID)
add_compile_definitions(USB_ITF_HID=1)
message(STATUS "USB HID Interface:\t\t enabled")
endif()
if(USB_ITF_CCID)
add_compile_definitions(USB_ITF_CCID=1)
message(STATUS "USB CCID Interface:\t\t enabled")
if(USB_ITF_WCID)
add_compile_definitions(USB_ITF_WCID=1)
message(STATUS "USB WebCCID Interface:\t enabled")
endif()
endif()
if(USB_ITF_LWIP)
add_compile_definitions(USB_ITF_LWIP=1)
message(STATUS "USB LWIP Interface:\t\t enabled")
endif()
add_compile_definitions(DEBUG_APDU=${DEBUG_APDU})
if(NOT ESP_PLATFORM)
add_compile_definitions(MBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
else()
add_compile_definitions(CFG_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}")
include(${CMAKE_CURRENT_LIST_DIR}/cmake/deps.cmake)
option(ENABLE_PQC "Enable/disable PQC support" OFF)
configure_bool_option(
ENABLE_PQC
""
"PQC support:\t\t\t enabled"
"PQC support:\t\t\t disabled"
)
if(ENABLE_PQC)
add_compile_definitions(ENABLE_PQC)
endif()
set(MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/bignum_core.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ccm.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/gcm.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkcs5.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha512.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/chachapoly.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/chacha20.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/poly1305.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/des.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/base64.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pem.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkwrite.c
)
if(ENABLE_EDDSA)
list(APPEND MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/eddsa.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha3.c
)
endif()
if(ENABLE_PQC)
if(NOT ESP_PLATFORM)
file(GLOB_RECURSE MLKEM_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src/*.c
)
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
add_library(mlkem512 STATIC ${MLKEM_SOURCES})
target_include_directories(mlkem512 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
)
target_compile_definitions(mlkem512 PRIVATE
MLK_CONFIG_PARAMETER_SET=512
MLK_CONFIG_MULTILEVEL_WITH_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
add_library(mlkem768 STATIC ${MLKEM_SOURCES})
target_include_directories(mlkem768 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
)
target_compile_definitions(mlkem768 PRIVATE
MLK_CONFIG_PARAMETER_SET=768
MLK_CONFIG_MULTILEVEL_NO_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
add_library(mlkem1024 STATIC ${MLKEM_SOURCES})
target_include_directories(mlkem1024 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
)
target_compile_definitions(mlkem1024 PRIVATE
MLK_CONFIG_PARAMETER_SET=1024
MLK_CONFIG_MULTILEVEL_NO_SHARED
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
)
file(GLOB_RECURSE MLDSA_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src/*.c
)
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
add_library(mldsa44 STATIC ${MLDSA_SOURCES})
target_include_directories(mldsa44 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
)
target_compile_definitions(mldsa44 PRIVATE
MLD_CONFIG_PARAMETER_SET=44
MLD_CONFIG_MULTILEVEL_WITH_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
add_library(mldsa65 STATIC ${MLDSA_SOURCES})
target_include_directories(mldsa65 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
)
target_compile_definitions(mldsa65 PRIVATE
MLD_CONFIG_PARAMETER_SET=65
MLD_CONFIG_MULTILEVEL_NO_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
add_library(mldsa87 STATIC ${MLDSA_SOURCES})
target_include_directories(mldsa87 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
)
target_compile_definitions(mldsa87 PRIVATE
MLD_CONFIG_PARAMETER_SET=87
MLD_CONFIG_MULTILEVEL_NO_SHARED
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
)
endif()
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
)
list(APPEND SYSTEM_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
)
add_compile_definitions(
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
MLK_CONFIG_MULTILEVEL_BUILD=1
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
MLD_CONFIG_MULTILEVEL_BUILD=1
)
endif()
if(ESP_PLATFORM)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_esp32.c
)
elseif(ENABLE_EMULATION)
if(MSVC)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_windows.c
)
elseif(APPLE)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_macos.c
)
elseif(UNIX AND NOT APPLE)
add_compile_definitions(OTP_LINUX_USE_TSS=1)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_linux.c
)
else()
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_emulation.c
)
endif()
elseif(PICO_RP2350)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_rp2350.c
)
elseif(PICO_RP2040)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_rp2040.c
)
endif()
list(APPEND PICOKEYS_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/phy.c
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp.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/tlv.c
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
${CMAKE_CURRENT_LIST_DIR}/src/serial.c
${CMAKE_CURRENT_LIST_DIR}/src/pico_time.c
${CMAKE_CURRENT_LIST_DIR}/src/button.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
)
if(ESP_PLATFORM)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
)
else()
if(NOT ENABLE_EMULATION)
list(APPEND PICOKEYS_SOURCES
${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
)
endif()
endif()
## mbedTLS reports an stringop overflow for cmac.c
if(NOT ENABLE_EMULATION AND NOT APPLE)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cmac.c
PROPERTIES
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
)
endif()
list(APPEND 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}/src/otp
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
)
set(SYSTEM_INCLUDES
${SYSTEM_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
)
if(USB_ITF_HID)
list(APPEND SYSTEM_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src
)
endif()
if(USB_ITF_LWIP)
list(APPEND SYSTEM_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/third-party/cjson
)
endif()
if(USB_ITF_LWIP)
if (NOT ESP_PLATFORM)
add_compile_definitions(
MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
MBEDTLS_SSL_PROTO_TLS1_2
MBEDTLS_SSL_SRV_C
MBEDTLS_SSL_TLS_C
)
endif()
list(APPEND MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkparse.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_ecc.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkcs12.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_ciphersuites.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_msg.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_tls.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_tls12_server.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_crt.c
)
endif()
if(USB_ITF_HID)
list(APPEND MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkwrite.c
)
endif()
set(CBOR_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborencoder.c
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborparser.c
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborparser_dup_string.c
)
set(CJSON_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/cjson/cJSON.c
)
set(LIBCVC_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_build.c
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_parse.c
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_sign.c
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_tlv.c
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_write.c
)
set(LIBRARIES)
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
list(APPEND LIBRARIES mbedtls)
endif()
if(USE_OPENSSL_EMULATION_WRAPPER)
list(APPEND LIBRARIES OpenSSL::Crypto)
endif()
if(UNIX AND NOT APPLE AND ENABLE_EMULATION)
find_library(TSS2_ESYS_LIB NAMES tss2-esys)
find_library(TSS2_TCTILDR_LIB NAMES tss2-tctildr)
if(TSS2_ESYS_LIB AND TSS2_TCTILDR_LIB)
list(APPEND LIBRARIES ${TSS2_ESYS_LIB} ${TSS2_TCTILDR_LIB})
else()
message(WARNING "Linux OTP TPM backend enabled but tpm2-tss libraries not found (need tss2-esys and tss2-tctildr)")
endif()
endif()
if(NOT ESP_PLATFORM)
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
add_library(mbedtls STATIC ${MBEDTLS_SOURCES})
target_include_directories(mbedtls SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include)
endif()
if(ENABLE_LIBCVC)
add_library(libcvc STATIC ${LIBCVC_SOURCES})
target_include_directories(libcvc SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src ${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/include)
target_link_libraries(libcvc PRIVATE mbedtls)
list(APPEND LIBRARIES libcvc)
endif()
if(USB_ITF_HID)
add_library(tinycbor STATIC ${CBOR_SOURCES})
target_include_directories(tinycbor SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src)
list(APPEND LIBRARIES tinycbor)
endif()
if(USB_ITF_LWIP)
add_library(cjson STATIC ${CJSON_SOURCES})
target_include_directories(cjson SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/cjson)
list(APPEND LIBRARIES cjson)
endif()
endif()
if(PICO_PLATFORM)
list(APPEND LIBRARIES
pico_stdlib
pico_multicore
pico_rand
pico_aon_timer
hardware_flash
pico_unique_id
tinyusb_device
tinyusb_board
hardware_pio
)
if(USB_ITF_LWIP)
list(APPEND LIBRARIES
pico_lwip
pico_lwip_nosys
)
endif()
endif()
if(ENABLE_PQC)
list(APPEND LIBRARIES
mlkem768
mlkem1024
mlkem512
mldsa44
mldsa65
mldsa87
)
endif()
set(IS_CYW43 0)
if(PICO_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")
list(APPEND 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)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
)
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
)
endif()
if(USB_ITF_CCID)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
)
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
)
endif()
if(NOT MSVC)
add_compile_options("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
else()
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
)
endif()
if(ENABLE_EMULATION)
if(APPLE)
add_definitions("-Wno-deprecated-declarations")
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
"-framework IOKit"
"-framework CoreFoundation"
)
elseif(MSVC)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Ncrypt)
elseif(UNIX AND NOT APPLE AND TSS2_ESYS_LIB AND TSS2_TCTILDR_LIB)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${TSS2_ESYS_LIB} ${TSS2_TCTILDR_LIB})
endif()
add_compile_definitions(ENABLE_EMULATION)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
)
if(USE_OPENSSL_EMULATION_WRAPPER)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/openssl.c
)
endif()
list(APPEND MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/aesni.c
)
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
)
else()
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
)
endif()
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd5045 -wd4820 -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_WIN11_DT=0
)
endif()
if(PICO_PLATFORM)
pico_sdk_init()
endif()
if(USB_ITF_LWIP)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest_server.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest_server_tls.c
)
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip
)
if(NOT ENABLE_EMULATION)
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/lwip.c
)
if ((NOT ESP_PLATFORM) AND (NOT IDF_TARGET))
list(APPEND PICOKEYS_SOURCES
${PICO_TINYUSB_PATH}/lib/networking/dhserver.c
${PICO_TINYUSB_PATH}/lib/networking/dnserver.c
)
list(APPEND INCLUDES
${PICO_TINYUSB_PATH}/lib/networking
${PICO_LWIP_PATH}/src/include/lwip/apps
)
message(STATUS "TINYUSB_PATH:\t\t ${PICO_TINYUSB_PATH}")
message(STATUS "LWIP_PATH:\t\t ${PICO_LWIP_PATH}")
endif()
endif()
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)
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
)
if(TARGET mbedtls)
target_include_directories(mbedtls PRIVATE
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
)
target_link_libraries(mbedtls PRIVATE pico_sha256)
endif()
list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
)
add_compile_definitions(MBEDTLS_SHA256_ALT=1)
list(APPEND LIBRARIES pico_sha256)
endif()
set(INTERNAL_SOURCES ${PICOKEYS_SOURCES})
if(NOT TARGET picokeys_sdk)
if(PICO_PLATFORM)
pico_add_library(picokeys_sdk)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
else()
add_impl_library(picokeys_sdk)
endif()
target_sources(picokeys_sdk INTERFACE ${PICOKEYS_SOURCES})
target_include_directories(picokeys_sdk INTERFACE ${INCLUDES})
target_include_directories(picokeys_sdk SYSTEM INTERFACE ${SYSTEM_INCLUDES})
target_link_libraries(picokeys_sdk INTERFACE ${LIBRARIES})
endif()

View File

@@ -12,3 +12,4 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_WL_SECTOR_SIZE_512=y CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_MODE_PERF=y CONFIG_WL_SECTOR_MODE_PERF=y
COMPILER_OPTIMIZATION="Performance" COMPILER_OPTIMIZATION="Performance"
CONFIG_MBEDTLS_HKDF_C=y

View File

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

View File

@@ -3,24 +3,25 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include "apdu.h" #include "apdu.h"
#include "pico_keys.h" #include "led/led.h"
#include "usb.h" #include "usb.h"
#include <stdio.h> #include <stdio.h>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "compat/esp_compat.h"
#endif #endif
#ifdef ENABLE_EMULATION #ifdef ENABLE_EMULATION
#include "emulation.h" #include "emulation.h"
@@ -30,16 +31,23 @@ uint8_t *rdata_gr = NULL;
uint16_t rdata_bk = 0x0; uint16_t rdata_bk = 0x0;
extern uint32_t timeout; extern uint32_t timeout;
bool is_chaining = false; bool is_chaining = false;
uint8_t chain_buf[4096]; uint8_t chain_buf[2038];
uint8_t *chain_ptr = NULL; uint8_t *chain_ptr = NULL;
int process_apdu() { struct apdu apdu;
int process_apdu(void) {
led_set_mode(MODE_PROCESSING); led_set_mode(MODE_PROCESSING);
if (CLA(apdu) & 0x10) { if (CLA(apdu) & 0x10) {
size_t chain_used = 0;
if (!is_chaining) { if (!is_chaining) {
chain_ptr = chain_buf; chain_ptr = chain_buf;
} }
if (chain_ptr - chain_buf + apdu.nc >= sizeof(chain_buf)) { chain_used = (size_t)(chain_ptr - chain_buf);
if (chain_used + apdu.nc >= sizeof(chain_buf)) {
memset(chain_buf, 0, sizeof(chain_buf));
chain_ptr = NULL;
is_chaining = false;
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }
memcpy(chain_ptr, apdu.data, apdu.nc); memcpy(chain_ptr, apdu.data, apdu.nc);
@@ -52,11 +60,13 @@ int process_apdu() {
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc); memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf); memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
apdu.nc += (uint16_t)(chain_ptr - chain_buf); apdu.nc += (uint16_t)(chain_ptr - chain_buf);
memset(chain_buf, 0, sizeof(chain_buf));
chain_ptr = NULL;
is_chaining = false; is_chaining = false;
} }
} }
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID 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) { if (select_app(apdu.data, apdu.nc) == PICOKEYS_OK) {
return SW_OK(); return SW_OK();
} }
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
@@ -85,17 +95,17 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
} }
else if (apdu.header[4] == 0x0 && buffer_size >= 7) { else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
if (buffer_size == 7) { if (buffer_size == 7) {
apdu.ne = get_uint16_t_be(apdu.header + 5); apdu.ne = get_uint16_be(apdu.header + 5);
if (apdu.ne == 0) { if (apdu.ne == 0) {
apdu.ne = 65536; apdu.ne = 65536;
} }
} }
else { else {
apdu.ne = 0; apdu.ne = 0;
apdu.nc = get_uint16_t_be(apdu.header + 5); apdu.nc = get_uint16_be(apdu.header + 5);
apdu.data = apdu.header + 7; apdu.data = apdu.header + 7;
if (apdu.nc + 7 + 2 == buffer_size) { if (apdu.nc + 7 + 2 == buffer_size) {
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2); apdu.ne = get_uint16_be(apdu.header + buffer_size - 2);
if (apdu.ne == 0) { if (apdu.ne == 0) {
apdu.ne = 65536; apdu.ne = 65536;
} }
@@ -113,21 +123,22 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
} }
} }
} }
//printf("apdu.nc %ld, apdu.ne %ld\n",apdu.nc,apdu.ne); //printf("apdu.nc %u, apdu.ne %u\n",apdu.nc,apdu.ne);
if (apdu.header[1] == 0xc0) { if (apdu.header[1] == 0xc0) {
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk); //printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk);
timeout_stop(); timeout_stop();
*(uint16_t *) rdata_gr = rdata_bk; rdata_gr[0] = rdata_bk >> 8;
rdata_gr[1] = rdata_bk & 0xff;
if (apdu.rlen <= apdu.ne) { if (apdu.rlen <= apdu.ne) {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID #ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) { if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata); driver_exec_finished_cont_hid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
} }
#endif #endif
#ifdef USB_ITF_CCID #ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) { if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata); driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
} }
#endif #endif
#else #else
@@ -140,7 +151,7 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
} }
else { else {
rdata_gr += apdu.ne; rdata_gr += apdu.ne;
rdata_bk = *(uint16_t *) rdata_gr; rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1];
rdata_gr[0] = 0x61; rdata_gr[0] = 0x61;
if (apdu.rlen - apdu.ne >= 256) { if (apdu.rlen - apdu.ne >= 256) {
rdata_gr[1] = 0; rdata_gr[1] = 0;
@@ -151,12 +162,12 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID #ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) { if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata); driver_exec_finished_cont_hid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
} }
#endif #endif
#ifdef USB_ITF_CCID #ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) { if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata); driver_exec_finished_cont_ccid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
} }
#endif #endif
#else #else
@@ -175,20 +186,23 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
} }
uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) { uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
apdu.sw = make_uint16_t_be(sw1, sw2); apdu.sw = make_uint16_be(sw1, sw2);
if (sw1 != 0x90) { if (sw1 != 0x90) {
res_APDU_size = 0; res_APDU_size = 0;
} }
return make_uint16_t_be(sw1, sw2); return make_uint16_be(sw1, sw2);
} }
void apdu_thread(void) { void *apdu_thread(void *arg) {
(void)arg;
card_init_core1(); card_init_core1();
while (1) { while (1) {
uint32_t m = 0; uint32_t m = 0;
queue_remove_blocking(&usb_to_card_q, &m); queue_remove_blocking(&usb_to_card_q, &m);
uint32_t flag = m + 1; uint32_t flag = m + 1;
queue_add_blocking(&card_to_usb_q, &flag); if (m != EV_CMD_AVAILABLE) {
queue_add_blocking(&card_to_usb_q, &flag);
}
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) { if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
set_res_sw(0x6f, 0x00); set_res_sw(0x6f, 0x00);
@@ -215,13 +229,11 @@ done: ;
current_app->unload(); current_app->unload();
current_app = NULL; current_app = NULL;
} }
#ifdef ESP_PLATFORM return NULL;
vTaskDelete(NULL);
#endif
} }
void apdu_finish() { void apdu_finish(void) {
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen); put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
// timeout_stop(); // timeout_stop();
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
/* It was fixed in the USB handling. Keep it just in case */ /* It was fixed in the USB handling. Keep it just in case */
@@ -231,14 +243,14 @@ void apdu_finish() {
#endif #endif
} }
uint16_t apdu_next() { uint16_t apdu_next(void) {
if (apdu.sw != 0) { if (apdu.sw != 0) {
if (apdu.rlen <= apdu.ne) { if (apdu.rlen <= apdu.ne) {
return apdu.rlen + 2; return apdu.rlen + 2;
} }
else { else {
rdata_gr = apdu.rdata + apdu.ne; rdata_gr = apdu.rdata + apdu.ne;
rdata_bk = *(uint16_t *) rdata_gr; rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1];
rdata_gr[0] = 0x61; rdata_gr[0] = 0x61;
if (apdu.rlen - apdu.ne >= 256) { if (apdu.rlen - apdu.ne >= 256) {
rdata_gr[1] = 0; rdata_gr[1] = 0;
@@ -252,3 +264,30 @@ uint16_t apdu_next() {
} }
return 0; return 0;
} }
int bulk_cmd(int (*cmd)(void)) {
uint8_t *p = apdu.data;
uint8_t *rapdu = apdu.rdata;
uint16_t rapdu_size = 0;
uint8_t *top = apdu.data + apdu.nc;
while (p < top) {
P1(apdu) = p[0];
P2(apdu) = p[1];
apdu.nc = p[2];
apdu.data = p + 3;
*apdu.rdata++ = p[0];
*apdu.rdata++ = p[1];
*apdu.rdata++ = 0;
*apdu.rdata++ = 0;
apdu.rlen = 0;
cmd();
put_uint16_be(apdu.rlen, apdu.rdata - 2);
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
rapdu_size += 4 + apdu.rlen + 2;
apdu.rdata += apdu.rlen + 2;
p += 3 + apdu.nc;
}
apdu.rlen = rapdu_size;
apdu.rdata = rapdu;
return SW_OK();
}

View File

@@ -3,34 +3,31 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _APDU_H_ #ifndef _APDU_H_
#define _APDU_H_ #define _APDU_H_
#include <stdlib.h> #include <stddef.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) #include <stdint.h>
#include "pico/stdlib.h" #include <stdbool.h>
#endif #include "compat/compat.h"
#include "compat.h"
#include <stdio.h>
#include <inttypes.h>
typedef struct app { typedef struct app {
const uint8_t *aid; const uint8_t *aid;
int (*process_apdu)(); int (*process_apdu)(void);
int (*select_aid)(struct app *, uint8_t); int (*select_aid)(struct app *, uint8_t);
int (*unload)(); int (*unload)(void);
} app_t; } app_t;
extern bool app_exists(const uint8_t *aid, size_t aid_len); extern bool app_exists(const uint8_t *aid, size_t aid_len);
@@ -39,11 +36,11 @@ extern int select_app(const uint8_t *aid, size_t aid_len);
typedef struct cmd { typedef struct cmd {
uint8_t ins; uint8_t ins;
int (*cmd_handler)(); int (*cmd_handler)(void);
} cmd_t; } cmd_t;
extern uint8_t num_apps; extern uint8_t num_apps;
extern app_t apps[8]; extern app_t apps[16];
extern app_t *current_app; extern app_t *current_app;
PACK(struct apdu { PACK(struct apdu {
@@ -68,10 +65,69 @@ PACK(struct apdu {
extern struct apdu apdu; extern struct apdu apdu;
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2); extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
extern int process_apdu(); extern int process_apdu(void);
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size); extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
extern void apdu_finish(); extern void apdu_finish(void);
extern uint16_t apdu_next(); extern uint16_t apdu_next(void);
extern void apdu_thread(); extern void *apdu_thread(void *);
extern int bulk_cmd(int (*cmd)(void));
#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)
#endif #endif

View File

@@ -1,50 +0,0 @@
/*
* 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

159
src/button.c Normal file
View File

@@ -0,0 +1,159 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "button.h"
#include "led/led.h"
#include "pico_time.h"
#if defined(PICO_PLATFORM)
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/gpio.h"
#elif defined(ESP_PLATFORM)
#include "driver/gpio.h"
#endif
#include "usb.h"
extern void execute_tasks(void);
int (*button_pressed_cb)(uint8_t) = NULL;
static bool req_button_pending = false;
bool is_req_button_pending(void) {
return req_button_pending;
}
bool cancel_button = false;
#if !defined(ENABLE_EMULATION)
#ifdef ESP_PLATFORM
static bool picok_board_button_read(void) {
int boot_state = gpio_get_level(BOOT_PIN);
return boot_state == 0;
}
#elif defined(PICO_PLATFORM)
static bool __no_inline_not_in_flash_func(picok_get_bootsel_button)(void) {
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.
#ifdef 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;
}
static bool picok_board_button_read(void) {
return picok_get_bootsel_button();
}
#else
static bool picok_board_button_read(void) {
return true; // always unpressed
}
#endif
static bool button_pressed_state = false;
static uint32_t button_pressed_time = 0;
static uint8_t button_press = 0;
bool button_wait(void) {
/* Disabled by default. As LED may not be properly configured,
it will not be possible to indicate button press unless it
is commissioned. */
uint32_t button_timeout = 0;
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
void button_task(void) {
#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
}

31
src/button.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BUTTON_H
#define BUTTON_H
#include <stdint.h>
#include <stdbool.h>
#if defined(ESP_PLATFORM)
#define BOOT_PIN GPIO_NUM_0
#endif
extern bool button_wait(void);
extern void button_task(void);
#endif // BUTTON_H

37
src/compat/board.h 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#include <stdint.h>
#ifdef _MSC_VER
#include <windows.h>
struct timezone;
extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
#else
#include <sys/time.h>
#endif
static inline uint32_t board_millis(void) {
struct timeval start;
gettimeofday(&start, NULL);
uint64_t ms = (uint64_t)start.tv_sec * 1000ULL + (uint64_t)start.tv_usec / 1000ULL;
return (uint32_t)ms;
}
#endif // _BOARD_H_

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _COMPAT_H_ #ifndef _COMPAT_H_
@@ -47,4 +47,23 @@
static void f(void) static void f(void)
#endif #endif
#include <string.h>
#ifdef _MSC_VER
#ifndef HAVE_STRLCPY
static inline size_t strlcpy(char *dst, const char *src, size_t size)
{
size_t srclen = strlen(src);
if (size != 0) {
size_t copylen = (srclen >= size) ? size - 1 : srclen;
memcpy(dst, src, copylen);
dst[copylen] = '\0';
}
return srclen;
}
#endif
#endif
#endif // _COMPAT_H #endif // _COMPAT_H

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __ESP_COMPAT_H_ #ifndef __ESP_COMPAT_H_
@@ -37,7 +37,12 @@ extern TaskHandle_t hcore0, hcore1;
#define ESP32_CORE0 tskNO_AFFINITY #define ESP32_CORE0 tskNO_AFFINITY
#define ESP32_CORE1 tskNO_AFFINITY #define ESP32_CORE1 tskNO_AFFINITY
#endif #endif
#define multicore_launch_core1(a) xTaskCreatePinnedToCore((void(*)(void *))a, "core1", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, ESP32_CORE1) static inline void task_wrapper(void *arg) {
void* (*func)(void*) = (void* (*)(void*))arg;
func(NULL);
vTaskDelete(NULL);
}
#define multicore_launch_func_core1(func) xTaskCreatePinnedToCore(task_wrapper, "core1", 4096*ITF_TOTAL*2, (void *)func, 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 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) #define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
static inline uint32_t board_millis(void) { static inline uint32_t board_millis(void) {

119
src/compat/pthread_win32.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef _MSC_VER
#ifndef _PTHREAD_H_
#define _PTHREAD_H_
#include <windows.h>
#include <stdint.h>
#include <stdlib.h>
typedef HANDLE pthread_t;
typedef CRITICAL_SECTION pthread_mutex_t;
typedef struct {
CONDITION_VARIABLE cond;
} pthread_cond_t;
// Mutex
static inline int pthread_mutex_init(pthread_mutex_t *m, void *a) {
(void)a;
InitializeCriticalSection(m);
return 0;
}
static inline int pthread_mutex_lock(pthread_mutex_t *m) {
EnterCriticalSection(m);
return 0;
}
static inline int pthread_mutex_unlock(pthread_mutex_t *m) {
LeaveCriticalSection(m);
return 0;
}
static inline int pthread_mutex_destroy(pthread_mutex_t *m) {
DeleteCriticalSection(m);
return 0;
}
static inline int pthread_detach(pthread_t t) {
CloseHandle(t);
return 0;
}
// Thread
static DWORD WINAPI thread_entry(LPVOID param) {
void **args = (void **)param;
void *(*fn)(void *) = (void *(*)(void *))(uintptr_t)args[0];
void *arg = args[1];
fn(arg);
free(param);
return 0;
}
static inline int pthread_create(pthread_t *t, void *a, void *(*fn)(void *), void *arg) {
(void)a;
void **params = malloc(2 * sizeof(void *));
if (!params) return -1;
params[0] = (void *)(uintptr_t)fn;
params[1] = arg;
*t = CreateThread(NULL, 0, thread_entry, params, 0, NULL);
return *t ? 0 : -1;
}
static inline int pthread_join(pthread_t t, void **ret) {
WaitForSingleObject(t, INFINITE);
CloseHandle(t);
if (ret) *ret = NULL;
return 0;
}
// Condition variable
static inline int pthread_cond_init(pthread_cond_t *c, void *a) {
(void)a;
InitializeConditionVariable(&c->cond);
return 0;
}
static inline int pthread_cond_destroy(pthread_cond_t *c) {
(void)c;
return 0;
}
static inline int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) {
SleepConditionVariableCS(&c->cond, m, INFINITE);
return 0;
}
static inline int pthread_cond_signal(pthread_cond_t *c) {
WakeConditionVariable(&c->cond);
return 0;
}
static inline int pthread_cond_broadcast(pthread_cond_t *c) {
WakeAllConditionVariable(&c->cond);
return 0;
}
static inline int pthread_mutex_trylock(pthread_mutex_t *m){
return TryEnterCriticalSection(m) ? 0 : EBUSY;
}
#endif // _PTHREAD_H_
#endif // _MSC_VER

135
src/compat/queue.h Normal file
View File

@@ -0,0 +1,135 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef QUEUE_H
#define QUEUE_H
#ifdef _MSC_VER
#include "compat/pthread_win32.h"
#include "compat/semaphore_win32.h"
#else
#include <pthread.h>
#include <semaphore.h>
#endif
#include <stdbool.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;
#ifdef _MSC_VER
char padding[sizeof(void *) - sizeof(bool)];
#endif
} 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_func_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 // QUEUE_H

View File

@@ -0,0 +1,47 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef _MSC_VER
#ifndef _SEMAPHORE_H_
#define _SEMAPHORE_H_
#include <windows.h>
typedef struct {
HANDLE handle;
} sem_t;
static inline int sem_init(sem_t *sem, int pshared, unsigned int value) {
(void)pshared;
sem->handle = CreateSemaphore(NULL, value, 0x7FFFFFFF, NULL);
return sem->handle ? 0 : -1;
}
static inline int sem_wait(sem_t *sem) {
return WaitForSingleObject(sem->handle, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
}
static inline int sem_post(sem_t *sem) {
return ReleaseSemaphore(sem->handle, 1, NULL) ? 0 : -1;
}
static inline int sem_destroy(sem_t *sem) {
return CloseHandle(sem->handle) ? 0 : -1;
}
#endif // _SEMAPHORE_H_
#endif // _MSC_VER

View File

@@ -3,34 +3,151 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#if defined(ENABLE_EMULATION) #include "picokeys.h"
#elif defined(ESP_PLATFORM) #include "serial.h"
#include "esp_compat.h"
#else
#include <pico/unique_id.h>
#endif
#include "mbedtls/md.h" #include "mbedtls/md.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/gcm.h"
#include "mbedtls/base64.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "pico_keys.h" #include "otp.h"
#include "random.h"
static const mbedtls_md_info_t *SHA256(void) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
}
void derive_kbase(uint8_t kbase[32]) {
const uint8_t nootp_salt[] = "NO-OTP";
if (otp_key_1) {
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), otp_key_1, 32, (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
}
else {
mbedtls_hkdf(SHA256(), nootp_salt, sizeof(nootp_salt)-1, pico_serial_hash, sizeof(pico_serial_hash), (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
}
}
void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]) {
uint8_t kbase[32];
derive_kbase(kbase);
mbedtls_md_hmac(SHA256(), kbase, 32, pin, pin_len, kver);
mbedtls_platform_zeroize(kbase, sizeof(kbase));
}
void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]) {
uint8_t kver[32];
derive_kver(pin, pin_len, kver);
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/VERIFY", 10, verifier, 32);
mbedtls_platform_zeroize(kver, sizeof(kver));
}
void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]) {
uint8_t kver[32];
derive_kver(pin, pin_len, kver);
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/TOKEN", 9, pin_token, 32);
mbedtls_platform_zeroize(kver, sizeof(kver));
}
void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]) {
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), pin_token, 32, (const uint8_t *)"PIN/ENC", 7, kenc, 32);
}
void pin_derive_kenc2(const uint8_t pin_token[32], uint8_t kenc[32]) {
uint8_t kbase[64];
derive_kbase(kbase);
memcpy(kbase + 32, pin_token, 32);
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kbase, 64, (const uint8_t *)"PIN/ENC2", 8, kenc, 32);
mbedtls_platform_zeroize(kbase, sizeof(kbase));
}
// ------------------------------------------------------------------
// Encrypt 32-byte device key using AES-256-GCM
// Output: [nonce|ciphertext|tag] = 12 + in_len + 16 = 60 bytes
// ------------------------------------------------------------------
int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf) {
uint8_t *nonce = out_buf;
uint8_t *ct = out_buf + 12;
uint8_t *tag = out_buf + 12 + in_len;
random_fill_buffer(nonce, 12);
mbedtls_gcm_context gcm;
mbedtls_gcm_init(&gcm);
uint8_t kenc[32];
if (version == PIN_KDF_V2) {
pin_derive_kenc2(key, kenc);
}
else if (version == PIN_KDF_V1) {
pin_derive_kenc(key, kenc);
}
else {
mbedtls_gcm_free(&gcm);
return PICOKEYS_WRONG_DATA;
}
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
mbedtls_platform_zeroize(kenc, sizeof(kenc));
if (rc != 0) {
return rc;
}
rc = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, in_len, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), in_buf, ct, 16, tag);
mbedtls_gcm_free(&gcm);
return rc;
}
// ------------------------------------------------------------------
// Decrypt & verify 32-byte device key using AES-256-GCM
// Input: [nonce|ciphertext|tag] = in_len bytes
// Output: decrypted = in_len - 12 - 16 bytes
// ------------------------------------------------------------------
int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf) {
const uint8_t *nonce = in_buf;
const uint8_t *ct = in_buf + 12;
const uint8_t *tag = in_buf + in_len - 16;
mbedtls_gcm_context gcm;
uint8_t kenc[32];
if (version == PIN_KDF_V2) {
pin_derive_kenc2(key, kenc);
}
else if (version == PIN_KDF_V1) {
pin_derive_kenc(key, kenc);
}
else {
return PICOKEYS_WRONG_DATA;
}
mbedtls_gcm_init(&gcm);
int ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
mbedtls_platform_zeroize(kenc, sizeof(kenc));
if (ret != 0) {
return ret;
}
MBEDTLS_MPI_CHK(mbedtls_gcm_auth_decrypt(&gcm, in_len - 16 - 12, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), tag, 16, ct, out_buf));
cleanup:
mbedtls_gcm_free(&gcm);
return ret;
}
// Old functions, kept for compatibility. NOT SECURE, use the new ones above.
void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) { void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
uint8_t o1[32]; uint8_t o1[32];
hash_multi(pin, len, o1); hash_multi(pin, len, o1);
for (int i = 0; i < sizeof(o1); i++) { for (size_t i = 0; i < sizeof(o1); i++) {
o1[i] ^= pin[i % len]; o1[i] ^= pin[i % len];
} }
hash_multi(o1, sizeof(o1), output); hash_multi(o1, sizeof(o1), output);
@@ -82,12 +199,20 @@ int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
} }
int r = mbedtls_aes_setkey_enc(&aes, key, key_size); int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; mbedtls_aes_free(&aes);
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
return PICOKEYS_EXEC_ERROR;
} }
if (mode == PICO_KEYS_AES_MODE_CBC) { int rc = 0;
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data); if (mode == PICOKEYS_AES_MODE_CBC) {
rc = 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); else {
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
}
mbedtls_aes_free(&aes);
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
return rc;
} }
int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) { int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) {
@@ -101,31 +226,44 @@ int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
} }
int r = mbedtls_aes_setkey_dec(&aes, key, key_size); int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; mbedtls_aes_free(&aes);
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
return PICOKEYS_EXEC_ERROR;
} }
if (mode == PICO_KEYS_AES_MODE_CBC) { int rc = 0;
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data); if (mode == PICOKEYS_AES_MODE_CBC) {
rc = 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 else {
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data); r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
if (r != 0) {
mbedtls_aes_free(&aes);
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
return PICOKEYS_EXEC_ERROR;
}
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
}
mbedtls_aes_free(&aes);
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
return rc;
} }
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) { 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); return aes_encrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
} }
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t 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); return aes_decrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
} }
struct lv_data { PACK(struct lv_data {
unsigned char *value; unsigned char *value;
uint8_t len; uint8_t len;
}; });
struct ec_curve_mbed_id { PACK(struct ec_curve_mbed_id {
struct lv_data curve; struct lv_data curve;
mbedtls_ecp_group_id id; mbedtls_ecp_group_id id;
}; });
struct ec_curve_mbed_id ec_curves_mbed[] = { struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *) { { (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", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
@@ -172,3 +310,84 @@ mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_
} }
return MBEDTLS_ECP_DP_NONE; return MBEDTLS_ECP_DP_NONE;
} }
#define POLY 0xedb88320
uint32_t crc32c(const uint8_t *buf, size_t len) {
uint32_t crc = 0xffffffff;
while (len--) {
crc ^= *buf++;
for (int k = 0; k < 8; k++) {
crc = (crc >> 1) ^ (POLY & (0 - (crc & 1)));
}
}
return ~crc;
}
int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
int rc = mbedtls_base64_encode(dst, dlen, olen, src, slen);
if (rc != 0) {
return rc;
}
for (size_t i = 0; i < *olen; i++) {
if (dst[i] == '+') {
dst[i] = '-';
}
else if (dst[i] == '/') {
dst[i] = '_';
}
}
if (*olen == 0) {
return 0;
}
uint8_t *p = dst + *olen - 1;
while (*p == '=') {
*p-- = '\0';
(*olen)--;
}
return 0;
}
int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
// First convert from base64url to standard base64
if ((slen % 4) == 1) return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
size_t padding = (4 - (slen % 4)) % 4;
unsigned char *b64_src = malloc(slen + padding);
if (b64_src == NULL) {
return PICOKEYS_ERR_MEMORY_FATAL;
}
for (size_t i = 0; i < slen; i++) {
if (src[i] == '-') {
b64_src[i] = '+';
}
else if (src[i] == '_') {
b64_src[i] = '/';
}
else {
b64_src[i] = src[i];
}
}
for (size_t i = 0; i < padding; i++) {
b64_src[slen + i] = '=';
}
size_t b64_len = slen + padding;
int rc = mbedtls_base64_decode(dst, dlen, olen, b64_src, b64_len);
free(b64_src);
return rc;
}
int b64url_decoded_len(size_t n, size_t *out_len) {
if (out_len == NULL) return -1;
if ((n % 4) == 1) return -2; // longitud base64url invàlida
size_t pad = (4 - (n % 4)) % 4; // 0,1,2
size_t total = n + pad;
size_t out = (total / 4) * 3;
if (pad == 1) out -= 1;
else if (pad == 2) out -= 2;
*out_len = out;
return 0;
}

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _CRYPTO_UTILS_H_ #ifndef _CRYPTO_UTILS_H_
@@ -21,23 +21,40 @@
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/md.h" #include "mbedtls/md.h"
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask #define PICOKEYS_KEY_RSA 0x000f // It is a mask
#define PICO_KEYS_KEY_RSA_1K 0x0001 #define PICOKEYS_KEY_RSA_1K 0x0001
#define PICO_KEYS_KEY_RSA_2K 0x0002 #define PICOKEYS_KEY_RSA_2K 0x0002
#define PICO_KEYS_KEY_RSA_3K 0x0004 #define PICOKEYS_KEY_RSA_3K 0x0004
#define PICO_KEYS_KEY_RSA_4k 0x0008 #define PICOKEYS_KEY_RSA_4k 0x0008
#define PICO_KEYS_KEY_EC 0x0010 #define PICOKEYS_KEY_EC 0x0010
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask #define PICOKEYS_KEY_AES 0x0f00 // It is a mask
#define PICO_KEYS_KEY_AES_128 0x0100 #define PICOKEYS_KEY_AES_128 0x0100
#define PICO_KEYS_KEY_AES_192 0x0200 #define PICOKEYS_KEY_AES_192 0x0200
#define PICO_KEYS_KEY_AES_256 0x0400 #define PICOKEYS_KEY_AES_256 0x0400
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */ #define PICOKEYS_KEY_AES_512 0x0800 /* For AES XTS */
#define PICO_KEYS_AES_MODE_CBC 1 #define PICOKEYS_AES_MODE_CBC 1
#define PICO_KEYS_AES_MODE_CFB 2 #define PICOKEYS_AES_MODE_CFB 2
#define IV_SIZE 16 #define IV_SIZE 16
typedef enum {
PIN_KDF_V1 = 1,
PIN_KDF_V2 = 2,
PIN_KDF_UNKNOWN = 0xff
} pin_kdf_version_t;
#define PIN_KDF_DEFAULT_VERSION PIN_KDF_V2
// Newer and safe functions
extern void derive_kbase(uint8_t kbase[32]);
extern void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]);
extern void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]);
extern void pin_derive_kenc2(const uint8_t pin_token[32], uint8_t kenc[32]);
extern void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]);
extern void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]);
extern int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
extern void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]); 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 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 hash256(const uint8_t *input, size_t len, uint8_t output[32]);
@@ -47,5 +64,11 @@ extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size,
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, 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 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); extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
extern uint32_t crc32c(const uint8_t *buf, size_t len);
extern int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
extern int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
extern int b64url_decoded_len(size_t n, size_t *out_len);
#define PIN_KDF_SIZE(x) (12 + (x) + 16)
#endif #endif

View File

@@ -3,48 +3,69 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _DEBUG_H_ #ifndef _DEBUG_H_
#define _DEBUG_H_ #define _DEBUG_H_
#if defined(DEBUG_APDU) && DEBUG_APDU == 1 #if defined(DEBUG_APDU) && DEBUG_APDU == 1
#define DEBUG_PAYLOAD(_p, _s) { \ #include <inttypes.h>
printf("Payload %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \ #include <stddef.h>
for (int _i = 0; _i < _s; _i += 16) { \ #include <stdint.h>
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \ #include <stdio.h>
for (int _j = 0; _j < 16; _j++) { \
if (_j < _s - _i) printf("%02X ", (_p)[_i + _j]); \ static inline void debug_payload_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
else printf(" "); \ printf("Payload %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
if (_j == 7) printf(" "); \ for (size_t i = 0; i < s; i += 16) {
} printf(": "); \ printf("%" PRIxPTR "h : ", (uintptr_t)(p + i));
for (int _j = 0; _j < 16; _j++) { \ for (size_t 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]); \ if (j < s - i) {
else printf(" "); \ printf("%02X ", p[i + j]);
if (_j == 7) printf(" "); \ }
} \ else {
printf("\n"); \ printf(" ");
} printf("\n"); \ }
} if (j == 7) {
#define DEBUG_DATA(_p, _s) { \ printf(" ");
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++) { \ printf(": ");
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \ for (size_t j = 0; j < 16; j++) {
} \ if (j < s - i && p[i + j] > 32 && p[i + j] != 127 && p[i + j] < 176) {
printf("%s\n", _tmp); \ printf("%c", p[i + j]);
free(_tmp); \ }
else {
printf(" ");
}
if (j == 7) {
printf(" ");
}
}
printf("\n");
} }
printf("\n");
}
static inline void debug_data_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
printf("Data %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
for (size_t i = 0; i < s; i++) {
printf("%02X", p[i]);
}
printf("\n");
}
#define DEBUG_PAYLOAD(_p, _s) debug_payload_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
#define DEBUG_DATA(_p, _s) debug_data_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
#else #else
#define DEBUG_PAYLOAD(_p, _s) #define DEBUG_PAYLOAD(_p, _s)

135
src/eac.c
View File

@@ -3,24 +3,30 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include "eac.h" #include "eac.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "random.h" #include "random.h"
#include "mbedtls/cmac.h" #include "mbedtls/cmac.h"
#include "asn1.h" #include "tlv.h"
#include "apdu.h" #include "apdu.h"
#ifdef ENABLE_EMULATION
#include "usb/emulation/emulation.h"
#else
#include "usb/usb.h"
#endif
static uint8_t sm_nonce[8]; static uint8_t sm_nonce[8];
static uint8_t sm_kmac[16]; static uint8_t sm_kmac[16];
@@ -29,19 +35,13 @@ static MSE_protocol sm_protocol = MSE_NONE;
static mbedtls_mpi sm_mSSC; static mbedtls_mpi sm_mSSC;
static uint8_t sm_blocksize = 0; static uint8_t sm_blocksize = 0;
static uint8_t sm_iv[16]; static uint8_t sm_iv[16];
uint16_t sm_session_pin_len = 0; static bool sm_active = false;
uint8_t sm_session_pin[16];
bool is_secured_apdu() { bool is_secured_apdu(void) {
return CLA(apdu) & 0xC; return CLA(apdu) & 0xC;
} }
void sm_derive_key(const uint8_t *input, static 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) {
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); uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
if (input) { if (input) {
memcpy(b, input, input_len); memcpy(b, input, input_len);
@@ -60,11 +60,12 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
memcpy(sm_nonce, random_bytes_get(8), 8); 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, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac); sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
mbedtls_mpi_free(&sm_mSSC);
mbedtls_mpi_init(&sm_mSSC); mbedtls_mpi_init(&sm_mSSC);
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize); mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
mbedtls_mpi_lset(&sm_mSSC, 0); mbedtls_mpi_lset(&sm_mSSC, 0);
memset(sm_iv, 0, sizeof(sm_iv)); memset(sm_iv, 0, sizeof(sm_iv));
sm_session_pin_len = 0; sm_active = true;
} }
void sm_set_protocol(MSE_protocol proto) { void sm_set_protocol(MSE_protocol proto) {
@@ -75,32 +76,38 @@ void sm_set_protocol(MSE_protocol proto) {
else if (proto == MSE_3DES) { else if (proto == MSE_3DES) {
sm_blocksize = 8; sm_blocksize = 8;
} }
else {
sm_blocksize = 0;
}
memset(sm_kenc, 0, sizeof(sm_kenc));
memset(sm_kmac, 0, sizeof(sm_kmac));
memset(sm_nonce, 0, sizeof(sm_nonce));
memset(sm_iv, 0, sizeof(sm_iv));
sm_active = false;
} }
MSE_protocol sm_get_protocol() { MSE_protocol sm_get_protocol(void) {
return sm_protocol; return sm_protocol;
} }
uint8_t *sm_get_nonce() { uint8_t *sm_get_nonce(void) {
return sm_nonce; return sm_nonce;
} }
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]) {
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
sm_kmac,
128,
in,
in_len,
out);
} }
int sm_unwrap() { int sm_unwrap(void) {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) { if (sm_indicator == 0) {
return PICOKEY_OK; return PICOKEYS_OK;
}
if (!sm_active || sm_blocksize == 0) {
return PICOKEYS_EXEC_ERROR;
} }
int r = sm_verify(); int r = sm_verify();
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
apdu.ne = sm_get_le(); apdu.ne = sm_get_le();
@@ -111,10 +118,9 @@ int sm_unwrap() {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
{
if (tag == 0x87 || tag == 0x85) { if (tag == 0x87 || tag == 0x85) {
body = tag_data; body = tag_data;
body_size = tag_len; body_size = tag_len;
@@ -126,25 +132,28 @@ int sm_unwrap() {
} }
if (!body) { if (!body) {
apdu.nc = 0; apdu.nc = 0;
return PICOKEY_OK; return PICOKEYS_OK;
} }
if (is87 && *body++ != 0x1) { if (is87 && *body++ != 0x1) {
return PICOKEY_WRONG_PADDING; return PICOKEYS_WRONG_PADDING;
} }
sm_update_iv(); sm_update_iv();
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size); aes_decrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, body, body_size);
memmove(apdu.data, body, body_size); memmove(apdu.data, body, body_size);
apdu.nc = sm_remove_padding(apdu.data, body_size); apdu.nc = sm_remove_padding(apdu.data, body_size);
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc); DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
return PICOKEY_OK; return PICOKEYS_OK;
} }
int sm_wrap() { int sm_wrap(void) {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) { if (sm_indicator == 0) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
uint8_t input[2048]; if (!sm_active || sm_blocksize == 0) {
return PICOKEYS_EXEC_ERROR;
}
uint8_t input[USB_BUFFER_SIZE];
size_t input_len = 0; size_t input_len = 0;
memset(input, 0, sizeof(input)); memset(input, 0, sizeof(input));
mbedtls_mpi ssc; mbedtls_mpi ssc;
@@ -153,7 +162,7 @@ int sm_wrap() {
mbedtls_mpi_copy(&sm_mSSC, &ssc); mbedtls_mpi_copy(&sm_mSSC, &ssc);
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
input_len += sm_blocksize; input_len += sm_blocksize;
mbedtls_mpi_free(&ssc); mbedtls_mpi_free(&ssc);
@@ -163,7 +172,7 @@ int sm_wrap() {
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize)); res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
DEBUG_PAYLOAD(res_APDU, res_APDU_size); DEBUG_PAYLOAD(res_APDU, res_APDU_size);
sm_update_iv(); sm_update_iv();
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size); aes_encrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
memmove(res_APDU + 1, res_APDU, res_APDU_size); memmove(res_APDU + 1, res_APDU, res_APDU_size);
res_APDU[0] = 0x1; res_APDU[0] = 0x1;
res_APDU_size++; res_APDU_size++;
@@ -181,14 +190,14 @@ int sm_wrap() {
else { else {
memmove(res_APDU + 4, res_APDU, res_APDU_size); memmove(res_APDU + 4, res_APDU, res_APDU_size);
res_APDU[1] = 0x82; res_APDU[1] = 0x82;
put_uint16_t_be(res_APDU_size, res_APDU + 2); put_uint16_be(res_APDU_size, res_APDU + 2);
res_APDU_size += 4; res_APDU_size += 4;
} }
res_APDU[0] = 0x87; res_APDU[0] = 0x87;
} }
res_APDU[res_APDU_size++] = 0x99; res_APDU[res_APDU_size++] = 0x99;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size); put_uint16_be(apdu.sw, res_APDU + res_APDU_size);
res_APDU_size += 2; res_APDU_size += 2;
memcpy(input + input_len, res_APDU, res_APDU_size); memcpy(input + input_len, res_APDU, res_APDU_size);
input_len += res_APDU_size; input_len += res_APDU_size;
@@ -202,16 +211,16 @@ int sm_wrap() {
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
} }
set_res_sw(0x90, 0x00); set_res_sw(0x90, 0x00);
return PICOKEY_OK; return PICOKEYS_OK;
} }
uint16_t sm_get_le() { uint16_t sm_get_le(void) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x97) { if (tag == 0x97) {
uint16_t le = 0; uint16_t le = 0;
for (uint16_t t = 1; t <= tag_len; t++) { for (uint16_t t = 1; t <= tag_len; t++) {
@@ -223,26 +232,26 @@ uint16_t sm_get_le() {
return 0; return 0;
} }
void sm_update_iv() { void sm_update_iv(void) {
uint8_t tmp_iv[16], sc_counter[16]; 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 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)); 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)); aes_encrypt(sm_kenc, tmp_iv, 128, PICOKEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
memcpy(sm_iv, sc_counter, sizeof(sc_counter)); memcpy(sm_iv, sc_counter, sizeof(sc_counter));
} }
int sm_verify() { int sm_verify(void) {
uint8_t input[2048]; uint8_t input[USB_BUFFER_SIZE];
memset(input, 0, sizeof(input)); memset(input, 0, sizeof(input));
uint16_t input_len = 0; uint16_t input_len = 0;
int r = 0; int r = 0;
bool add_header = (CLA(apdu) & 0xC) == 0xC; bool add_header = (CLA(apdu) & 0xC) == 0xC;
int data_len = (int) (apdu.nc / sm_blocksize) * sm_blocksize; size_t data_len = (size_t)(apdu.nc / sm_blocksize) * sm_blocksize;
if (data_len % sm_blocksize) { if (data_len % sm_blocksize) {
data_len += sm_blocksize; data_len += sm_blocksize;
} }
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) { if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
return PICOKEY_WRONG_LENGTH; return PICOKEYS_WRONG_LENGTH;
} }
mbedtls_mpi ssc; mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc); mbedtls_mpi_init(&ssc);
@@ -252,7 +261,7 @@ int sm_verify() {
input_len += sm_blocksize; input_len += sm_blocksize;
mbedtls_mpi_free(&ssc); mbedtls_mpi_free(&ssc);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (add_header) { if (add_header) {
input[input_len++] = CLA(apdu); input[input_len++] = CLA(apdu);
@@ -268,12 +277,12 @@ int sm_verify() {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag & 0x1) { if (tag & 0x1) {
input[input_len++] = (uint8_t)tag; input[input_len++] = (uint8_t)tag;
uint8_t tlen = format_tlv_len(tag_len, input + input_len); uint8_t tlen = tlv_format_len(tag_len, input + input_len);
input_len += tlen; input_len += tlen;
memcpy(input + input_len, tag_data, tag_len); memcpy(input + input_len, tag_data, tag_len);
input_len += tag_len; input_len += tag_len;
@@ -284,8 +293,8 @@ int sm_verify() {
mac_len = tag_len; mac_len = tag_len;
} }
} }
if (!mac) { if (!mac || mac_len != 8) {
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (some_added) { if (some_added) {
input[input_len++] = 0x80; input[input_len++] = 0x80;
@@ -294,12 +303,12 @@ int sm_verify() {
uint8_t signature[16]; uint8_t signature[16];
r = sm_sign(input, input_len, signature); r = sm_sign(input, input_len, signature);
if (r != 0) { if (r != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (memcmp(signature, mac, mac_len) == 0) { if (memcmp(signature, mac, mac_len) == 0) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
return PICOKEY_VERIFICATION_FAILED; return PICOKEYS_VERIFICATION_FAILED;
} }
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) { uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) {

View File

@@ -3,22 +3,24 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _EAC_H_ #ifndef _EAC_H_
#define _EAC_H_ #define _EAC_H_
#include "pico_keys.h" #include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef enum MSE_protocol { typedef enum MSE_protocol {
MSE_AES = 0, MSE_AES = 0,
@@ -28,17 +30,15 @@ typedef enum MSE_protocol {
extern void sm_derive_all_keys(const uint8_t *input, size_t input_len); extern void sm_derive_all_keys(const uint8_t *input, size_t input_len);
extern void sm_set_protocol(MSE_protocol proto); extern void sm_set_protocol(MSE_protocol proto);
extern MSE_protocol sm_get_protocol(); extern MSE_protocol sm_get_protocol(void);
extern uint8_t *sm_get_nonce(); extern uint8_t *sm_get_nonce(void);
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); extern int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]);
int sm_verify(); int sm_verify(void);
void sm_update_iv(); void sm_update_iv(void);
uint16_t sm_get_le(); uint16_t sm_get_le(void);
extern int sm_unwrap(); extern int sm_unwrap(void);
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len); uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
extern int sm_wrap(); extern int sm_wrap(void);
extern bool is_secured_apdu(); extern bool is_secured_apdu(void);
extern uint8_t sm_session_pin[16];
extern uint16_t sm_session_pin_len;
#endif #endif

View File

@@ -3,45 +3,39 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include "file.h" #include "file.h"
#include "pico_keys.h" #include "tlv.h"
#include <string.h>
#include <stdio.h>
#include "asn1.h"
#include "apdu.h" #include "apdu.h"
#include <stdio.h>
#define MAX_DEPTH 4
#define MAX_DYNAMIC_FILES 256
extern const uintptr_t end_data_pool; extern const uintptr_t end_data_pool;
extern const uintptr_t start_data_pool; extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool; extern const uintptr_t end_rom_pool;
extern const uintptr_t start_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_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 #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 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; file_t *ef_phy = &sef_phy;
#endif #endif
//puts FCI in the RAPDU //puts FCI in the RAPDU
void process_fci(const file_t *pe, int fmd) { void file_process_fci(const file_t *pe, int fmd) {
res_APDU_size = 0; res_APDU_size = 0;
if (fmd) { if (fmd) {
res_APDU[res_APDU_size++] = 0x6f; res_APDU[res_APDU_size++] = 0x6f;
@@ -55,12 +49,13 @@ void process_fci(const file_t *pe, int fmd) {
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
if (pe->data) { if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0); int (*data_fn)(const file_t *, int) = (int (*)(const file_t *, int))(uintptr_t)pe->data;
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size); uint16_t len = (uint16_t)data_fn(pe, 0);
res_APDU_size += put_uint16_be(len, res_APDU + res_APDU_size);
} }
else { else {
uint16_t v = file_get_size(pe); uint16_t v = file_get_size(pe);
res_APDU_size += put_uint16_t_be(v, res_APDU + res_APDU_size); res_APDU_size += put_uint16_be(v, res_APDU + res_APDU_size);
} }
} }
else { else {
@@ -86,7 +81,7 @@ void process_fci(const file_t *pe, int fmd) {
res_APDU[res_APDU_size++] = 0x83; res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size); res_APDU_size += put_uint16_be(pe->fid, res_APDU + res_APDU_size);
if (pe->name) { if (pe->name) {
res_APDU[res_APDU_size++] = 0x84; res_APDU[res_APDU_size++] = 0x84;
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16); res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
@@ -115,7 +110,7 @@ file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false; bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) { static bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent) { if (child == parent) {
return true; return true;
} }
@@ -129,7 +124,7 @@ file_t *get_parent(file_t *f) {
return &file_entries[f->parent]; return &file_entries[f->parent];
} }
file_t *search_by_name(uint8_t *name, uint16_t namelen) { file_t *file_search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) { for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) { if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
return p; return p;
@@ -138,7 +133,7 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
return NULL; return NULL;
} }
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) { file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
if (fid == EF_PHY) { if (fid == EF_PHY) {
return ef_phy; return ef_phy;
@@ -158,28 +153,37 @@ file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp
return NULL; return NULL;
} }
file_t *search_file(const uint16_t fid) { static file_t *search_dynamic_file(uint16_t fid) {
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF); for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid) {
return &dynamic_file[i];
}
}
return NULL;
}
file_t *file_search(const uint16_t fid) {
file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
if (ef) { if (ef) {
return ef; return ef;
} }
return search_dynamic_file(fid); return search_dynamic_file(fid);
} }
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) { static 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; return 0;
} }
if (pe == top) { //MF or relative DF if (pe == top) { //MF or relative DF
return 0; return 0;
} }
put_uint16_t_be(pe->fid, buf); put_uint16_be(pe->fid, buf);
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2; 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) { static uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH * 2], *p = path; uint8_t buf[MAX_DEPTH * 2], *p = path;
put_uint16_t_be(pe->fid, buf); put_uint16_be(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2; 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) { for (int d = depth - 2; d >= 0; d -= 2) {
memcpy(p, buf + d, 2); memcpy(p, buf + d, 2);
@@ -188,7 +192,7 @@ uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
return depth; return depth;
} }
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) { file_t *file_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)) { if (pathlen > sizeof(path)) {
return NULL; return NULL;
@@ -207,7 +211,7 @@ file_t *currentDF = NULL;
const file_t *selected_applet = NULL; const file_t *selected_applet = NULL;
bool isUserAuthenticated = false; bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) { bool file_authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op]; uint8_t acl = ef->acl[op];
if (acl == 0x0) { if (acl == 0x0) {
return true; return true;
@@ -227,11 +231,11 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
return false; return false;
} }
void initialize_flash(bool hard) { void file_initialize_flash(bool hard) {
if (hard) { if (hard) {
const uint8_t empty[8] = { 0 }; const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty)); flash_program_block(end_data_pool, empty, sizeof(empty));
low_flash_available(); flash_commit();
} }
for (file_t *f = file_entries; f != file_last; f++) { 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) {
@@ -243,8 +247,7 @@ void initialize_flash(bool hard) {
extern uintptr_t last_base; extern uintptr_t last_base;
extern uint32_t num_files; extern uint32_t num_files;
void scan_region(bool persistent) static void scan_region(bool persistent) {
{
uintptr_t endp = end_data_pool, startp = start_data_pool; uintptr_t endp = end_data_pool, startp = start_data_pool;
if (persistent) { if (persistent) {
endp = end_rom_pool; endp = end_rom_pool;
@@ -261,7 +264,7 @@ void scan_region(bool persistent)
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_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))); 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); file_t *file = (file_t *) file_search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) { if (!file) {
file = file_new(fid); file = file_new(fid);
} }
@@ -279,18 +282,17 @@ void scan_region(bool persistent)
} }
} }
} }
void wait_flash_finish(); void file_scan_flash(void) {
void scan_flash() { file_initialize_flash(false); //soft initialization
initialize_flash(false); //soft initialization uint32_t r1 = (uint32_t)flash_read_uintptr(end_rom_pool);
uint32_t r1 = *(uintptr_t *) flash_read(end_rom_pool), r2 = *(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t)); uint32_t r2 = (uint32_t)flash_read_uintptr(end_rom_pool + sizeof(uintptr_t));
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) { if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
printf("First initialization (or corrupted!)\n"); printf("First initialization (or corrupted!)\n");
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)]; uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
memset(empty, 0, sizeof(empty)); memset(empty, 0, sizeof(empty));
flash_program_block(end_data_pool, empty, sizeof(empty)); flash_program_block(end_data_pool, empty, sizeof(empty));
flash_program_block(end_rom_pool, empty, sizeof(empty)); flash_program_block(end_rom_pool, empty, sizeof(empty));
//low_flash_available(); //flash_commit();
//wait_flash_finish();
} }
printf("SCAN\n"); printf("SCAN\n");
scan_region(true); scan_region(true);
@@ -328,18 +330,9 @@ int file_put_data(file_t *file, const uint8_t *data, uint16_t len) {
return flash_write_data_to_file(file, data, len); return flash_write_data_to_file(file, data, len);
} }
file_t *search_dynamic_file(uint16_t fid) { static int delete_dynamic_file(file_t *f) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid) {
return &dynamic_file[i];
}
}
return NULL;
}
int delete_dynamic_file(file_t *f) {
if (f == NULL) { if (f == NULL) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
for (int i = 0; i < dynamic_files; i++) { for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) { if (dynamic_file[i].fid == f->fid) {
@@ -347,15 +340,15 @@ int delete_dynamic_file(file_t *f) {
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t)); memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
} }
dynamic_files--; dynamic_files--;
return PICOKEY_OK; return PICOKEYS_OK;
} }
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
file_t *file_new(uint16_t fid) { file_t *file_new(uint16_t fid) {
file_t *f; file_t *f;
if ((f = search_file(fid))) { if ((f = file_search(fid))) {
return f; return f;
} }
if (dynamic_files == MAX_DYNAMIC_FILES) { if (dynamic_files == MAX_DYNAMIC_FILES) {
@@ -377,20 +370,20 @@ file_t *file_new(uint16_t fid) {
return f; return f;
} }
uint16_t meta_find(uint16_t fid, uint8_t **out) { uint16_t meta_find(uint16_t fid, uint8_t **out) {
file_t *ef = search_file(EF_META); file_t *ef = file_search(EF_META);
if (!ef) { if (!ef) {
return 0; return 0;
} }
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) { if (tag_len < 2) {
continue; continue;
} }
uint16_t cfid = get_uint16_t_be(tag_data); uint16_t cfid = get_uint16_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
if (out) { if (out) {
*out = tag_data + 2; *out = tag_data + 2;
@@ -401,24 +394,24 @@ uint16_t meta_find(uint16_t fid, uint8_t **out) {
return 0; return 0;
} }
int meta_delete(uint16_t fid) { int meta_delete(uint16_t fid) {
file_t *ef = search_file(EF_META); file_t *ef = file_search(EF_META);
if (!ef) { if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
uint8_t *fdata = NULL; uint8_t *fdata = NULL;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1; uint8_t *tpos = p - tag_len - tlv_format_len(tag_len, NULL) - 1;
if (tag_len < 2) { if (tag_len < 2) {
continue; continue;
} }
uint16_t cfid = get_uint16_t_be(tag_data); uint16_t cfid = get_uint16_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
uint16_t new_len = ctxi.len - 1 - tag_len - format_tlv_len(tag_len, NULL); uint16_t new_len = ctxi.len - 1 - tag_len - tlv_format_len(tag_len, NULL);
if (new_len == 0) { if (new_len == 0) {
flash_clear_file(ef); flash_clear_file(ef);
} }
@@ -432,21 +425,21 @@ int meta_delete(uint16_t fid) {
} }
int r = file_put_data(ef, fdata, new_len); int r = file_put_data(ef, fdata, new_len);
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
} }
low_flash_available(); flash_commit();
break; break;
} }
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) { int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
int r; int r;
file_t *ef = search_file(EF_META); file_t *ef = file_search(EF_META);
if (!ef) { if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint16_t ef_size = file_get_size(ef); uint16_t ef_size = file_get_size(ef);
uint8_t *fdata = (uint8_t *) calloc(1, ef_size); uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
@@ -454,25 +447,25 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(fdata, ef_size, &ctxi); tlv_ctx_init(fdata, ef_size, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) { if (tag_len < 2) {
continue; continue;
} }
uint16_t cfid = get_uint16_t_be(tag_data); uint16_t cfid = get_uint16_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
if (tag_len - 2 == len) { //an update if (tag_len - 2 == len) { //an update
memcpy(p - tag_len + 2, data, len); memcpy(p - tag_len + 2, data, len);
r = file_put_data(ef, fdata, ef_size); r = file_put_data(ef, fdata, ef_size);
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
else { //needs reallocation else { //needs reallocation
uint8_t *tpos = p - asn1_len_tag(tag, tag_len); uint8_t *tpos = p - tlv_len_tag(tag, tag_len);
memmove(tpos, p, fdata + ef_size - p); memmove(tpos, p, fdata + ef_size - p);
tpos += fdata + ef_size - p; tpos += fdata + ef_size - p;
volatile uintptr_t meta_offset = tpos - fdata; volatile uintptr_t meta_offset = tpos - fdata;
@@ -484,52 +477,73 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
} }
else { else {
free(fdata); free(fdata);
return PICOKEY_ERR_MEMORY_FATAL; return PICOKEYS_ERR_MEMORY_FATAL;
} }
} }
uint8_t *f = fdata + meta_offset; uint8_t *f = fdata + meta_offset;
*f++ = fid & 0xff; *f++ = fid & 0xff;
f += format_tlv_len(len + 2, f); f += tlv_format_len(len + 2, f);
f += put_uint16_t_be(fid, f); f += put_uint16_be(fid, f);
memcpy(f, data, len); memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size); r = file_put_data(ef, fdata, ef_size);
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
} }
} }
fdata = (uint8_t *) realloc(fdata, ef_size + asn1_len_tag(fid & 0x1f, len + 2)); fdata = (uint8_t *) realloc(fdata, ef_size + tlv_len_tag(fid & 0x1f, len + 2));
uint8_t *f = fdata + ef_size; uint8_t *f = fdata + ef_size;
*f++ = fid & 0x1f; *f++ = fid & 0x1f;
f += format_tlv_len(len + 2, f); f += tlv_format_len(len + 2, f);
f += put_uint16_t_be(fid, f); f += put_uint16_be(fid, f);
memcpy(f, data, len); memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2)); r = file_put_data(ef, fdata, ef_size + (uint16_t)tlv_len_tag(fid & 0x1f, len + 2));
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
bool file_has_data(file_t *f) { bool file_has_data(const file_t *f) {
return f != NULL && f->data != NULL && file_get_size(f) > 0; return f != NULL && f->data != NULL && file_get_size(f) > 0;
} }
int delete_file(file_t *ef) { int file_delete(file_t *ef) {
if (ef == NULL) { if (ef == NULL) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
meta_delete(ef->fid); meta_delete(ef->fid);
if (flash_clear_file(ef) != PICOKEY_OK) { if (flash_clear_file(ef) != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (delete_dynamic_file(ef) != PICOKEY_OK) { if (delete_dynamic_file(ef) != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
}
int flash_clear_file(file_t *file) {
if (file == NULL || file->data == NULL) {
return PICOKEYS_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 %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);
}
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 PICOKEYS_OK;
} }

View File

@@ -3,29 +3,25 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
#include <stdlib.h> #include <stddef.h>
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#include "pico/stdlib.h"
#else
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#endif #include <stdbool.h>
#include "compat.h" #include "compat/compat.h"
#include "phy.h" #include "phy.h"
#define FILE_TYPE_NOT_KNOWN 0x00 #define FILE_TYPE_NOT_KNOWN 0x00
@@ -55,36 +51,40 @@
#define ACL_OP_UPDATE_ERASE 0x05 #define ACL_OP_UPDATE_ERASE 0x05
#define ACL_OP_READ_SEARCH 0x06 #define ACL_OP_READ_SEARCH 0x06
#define ACL_NONE { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
#define ACL_ALL { 0 }
#define ACL_RO { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
#define ACL_RW { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
#define ACL_R_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0x00 }
#define ACL_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0xff }
#define SPECIFY_EF 0x1 #define SPECIFY_EF 0x1
#define SPECIFY_DF 0x2 #define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3 #define SPECIFY_ANY 0x3
#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_META 0xE010 #define EF_META 0xE010
#define MAX_DEPTH 4 #ifdef _MSC_VER
__pragma( pack(push, 1) )
#define MAX_DYNAMIC_FILES 256 #endif
typedef struct file { typedef struct file {
const uint8_t *name; const uint8_t *name;
uint8_t *data; //should include 2 bytes len at begining uint8_t *data; //should include 2 bytes len at begining
const uint16_t fid; const uint16_t fid;
const uint8_t acl[7]; uint8_t acl[7];
const uint8_t parent; //entry number in the whole table!! const uint8_t parent; //entry number in the whole table!!
const uint8_t type; const uint8_t type;
const uint8_t ef_structure; const uint8_t ef_structure;
#ifdef ENABLE_EMULATION #ifdef ENABLE_EMULATION
uint32_t _padding; uint32_t _padding;
#endif #endif
} __attribute__ ((packed)) file_t; }
#ifdef _MSC_VER
extern bool file_has_data(file_t *); __pragma( pack(pop) )
#else
__attribute__ ((packed))
#endif
file_t;
extern file_t *currentEF; extern file_t *currentEF;
extern file_t *currentDF; extern file_t *currentDF;
@@ -92,22 +92,16 @@ extern const file_t *selected_applet;
extern const file_t *MF; extern const file_t *MF;
extern const file_t *file_last; extern const file_t *file_last;
extern const file_t *file_openpgp;
extern const file_t *file_sc_hsm;
extern bool card_terminated; extern bool card_terminated;
extern file_t *file_pin1;
extern file_t *file_retries_pin1;
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 *file_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 *file_search(const uint16_t fid);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen); extern file_t *file_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 file_t *file_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 bool file_authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe, int fmd); extern void file_process_fci(const file_t *pe, int fmd);
extern void scan_flash(); extern void file_scan_flash(void);
extern void initialize_flash(bool); extern void file_initialize_flash(bool);
extern file_t file_entries[]; extern file_t file_entries[];
@@ -115,29 +109,20 @@ extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr); extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const file_t *ef); 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_read_uint8_offset(const file_t *ef, const uint16_t offset);
extern bool file_has_data(const file_t *);
extern uint8_t *file_get_data(const file_t *tf); extern uint8_t *file_get_data(const file_t *tf);
extern uint16_t file_get_size(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 int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
extern file_t *file_new(uint16_t); extern file_t *file_new(uint16_t);
extern int flash_clear_file(file_t *file);
extern int file_delete(file_t *ef);
file_t *get_parent(file_t *f); file_t *get_parent(file_t *f);
extern uint16_t dynamic_files;
extern file_t dynamic_file[];
extern file_t *search_dynamic_file(uint16_t);
extern int delete_dynamic_file(file_t *f);
extern bool isUserAuthenticated; extern bool isUserAuthenticated;
extern uint16_t meta_find(uint16_t, uint8_t **out); extern uint16_t meta_find(uint16_t, uint8_t **out);
extern int meta_delete(uint16_t fid); extern int meta_delete(uint16_t fid);
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len); 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 #ifndef ENABLE_EMULATION
extern file_t *ef_phy; extern file_t *ef_phy;

28
src/fs/files.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "file.h"
file_t file_entries[] = {
/* 0 */ { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
.ef_structure = 0, .acl = { 0 } }, // MF
/* 1 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
.ef_structure = 0, .acl = { 0 } } //end
};
const file_t *MF = &file_entries[0];
const file_t *file_last = &file_entries[sizeof(file_entries) / sizeof(file_t) - 1];

View File

@@ -3,37 +3,40 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include <stdint.h> #if !defined(PICO_PLATFORM)
#include <string.h>
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
#define XIP_BASE 0 #define XIP_BASE 0
#define FLASH_SECTOR_SIZE 4096 #ifdef ENABLE_EMULATION
#ifdef ESP_PLATFORM #define FLASH_SECTOR_SIZE 0x4000
uint32_t PICO_FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#else #else
#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024) #define FLASH_SECTOR_SIZE 0x1000
#endif
#ifdef ESP_PLATFORM
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif #endif
#else #else
#include "pico/stdlib.h" uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
#include "hardware/flash.h" #include "hardware/flash.h"
#endif #endif
#include "pico_keys.h"
#include "file.h" #include "file.h"
#include <stdio.h>
extern void low_flash_task(void);
extern void low_flash_commit(void);
/* /*
* ------------------------------------------------------ * ------------------------------------------------------
@@ -49,15 +52,6 @@ uint32_t PICO_FLASH_SIZE_BYTES = (1 * 1024 * 1024);
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region //To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
uintptr_t end_flash, end_rom_pool, start_rom_pool, end_data_pool, 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_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 last_base; uintptr_t last_base;
uint32_t num_files = 0; uint32_t num_files = 0;
@@ -71,7 +65,7 @@ void flash_set_bounds(uintptr_t start, uintptr_t end) {
last_base = end_data_pool; last_base = end_data_pool;
} }
uintptr_t allocate_free_addr(uint16_t size, bool persistent) { static uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
if (size > FLASH_SECTOR_SIZE) { if (size > FLASH_SECTOR_SIZE) {
return 0x0; //ERROR return 0x0; //ERROR
} }
@@ -118,35 +112,14 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
return 0x0; //probably never reached return 0x0; //probably never reached
} }
int flash_clear_file(file_t *file) { static int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
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 %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);
}
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) { if (!file) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0; uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
uint8_t *old_data = NULL; uint8_t *old_data = NULL;
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) { if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
return PICOKEY_ERR_NO_MEMORY; return PICOKEYS_ERR_NO_MEMORY;
} }
if (file->data) { //already in flash if (file->data) { //already in flash
if (offset + len <= size_file_flash) { //it fits, no need to move it if (offset + len <= size_file_flash) { //it fits, no need to move it
@@ -154,7 +127,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
if (data) { if (data) {
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len); flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
else { //we clear the old file else { //we clear the old file
flash_clear_file(file); flash_clear_file(file);
@@ -171,7 +144,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT); uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
//printf("na %x\n",new_addr); //printf("na %x\n",new_addr);
if (new_addr == 0x0) { if (new_addr == 0x0) {
return PICOKEY_ERR_NO_MEMORY; return PICOKEYS_ERR_NO_MEMORY;
} }
if (new_addr < last_base) { if (new_addr < last_base) {
last_base = new_addr; last_base = new_addr;
@@ -186,29 +159,37 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
free(old_data); free(old_data);
} }
num_files++; num_files++;
return PICOKEY_OK; return PICOKEYS_OK;
} }
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) { int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
return flash_write_data_to_file_offset(file, data, len, 0); return flash_write_data_to_file_offset(file, data, len, 0);
} }
uint32_t flash_free_space() { uint32_t flash_free_space(void) {
return last_base - start_data_pool; return (uint32_t)(last_base - start_data_pool);
} }
uint32_t flash_used_space() { uint32_t flash_used_space(void) {
return end_data_pool - last_base; return (uint32_t)(end_data_pool - last_base);
} }
uint32_t flash_total_space() { uint32_t flash_total_space(void) {
return end_data_pool - start_data_pool; return (uint32_t)(end_data_pool - start_data_pool);
} }
uint32_t flash_num_files() { uint32_t flash_num_files(void) {
return num_files; return num_files;
} }
uint32_t flash_size() { uint32_t flash_size(void) {
return PICO_FLASH_SIZE_BYTES; return FLASH_SIZE_BYTES;
}
void flash_task(void) {
low_flash_task();
}
void flash_commit(void) {
low_flash_commit();
} }

46
src/fs/flash.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _FLASH_H
#define _FLASH_H
#include <stdint.h>
#include <stdbool.h>
extern uint32_t flash_free_space(void);
extern uint32_t flash_used_space(void);
extern uint32_t flash_total_space(void);
extern uint32_t flash_num_files(void);
extern uint32_t flash_size(void);
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
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_word(uintptr_t addr, uint32_t data);
extern int flash_program_uintptr(uintptr_t addr, uintptr_t data);
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_erase_page(uintptr_t addr, size_t page_size);
extern bool flash_check_blank(const uint8_t *p_start, size_t size);
extern void flash_task(void);
extern void low_flash_init(void);
extern void flash_commit(void);
#endif // _FLASH_H

View File

@@ -3,27 +3,23 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include <stdint.h> #include "serial.h"
#include <stdlib.h> #include "crypto_utils.h"
#include <stdio.h> #include <stdio.h>
#include "pico_keys.h"
#include <string.h>
#ifdef PICO_PLATFORM #ifdef PICO_PLATFORM
#include "pico/stdlib.h"
#include "hardware/flash.h" #include "hardware/flash.h"
#include "hardware/sync.h" #include "hardware/sync.h"
#include "pico/mutex.h" #include "pico/mutex.h"
@@ -32,62 +28,64 @@
#include "pico/bootrom.h" #include "pico/bootrom.h"
#include "boot/picobin.h" #include "boot/picobin.h"
#else #else
#ifdef _MSC_VER #ifdef ESP_PLATFORM
#include <windows.h> #include "compat/esp_compat.h"
#include <io.h> #include "esp_partition.h"
#define O_RDWR _O_RDWR const esp_partition_t *part0;
#define O_CREAT _O_CREAT #define save_and_disable_interrupts() 1
#define open _open #define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
#define write _write #define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
#define mode_t unsigned short #define restore_interrupts(a) (void)a
#define lseek _lseek
#include "mman.h"
#else #else
#ifdef ESP_PLATFORM #ifdef _MSC_VER
#include "esp_compat.h" #include <windows.h>
#include "esp_partition.h" #include <io.h>
const esp_partition_t *part0; #define O_RDWR _O_RDWR
#define save_and_disable_interrupts() 1 #define O_CREAT _O_CREAT
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b) #define open _open
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c); #define write _write
#define restore_interrupts(a) (void)a #define mode_t unsigned short
#define lseek _lseek
#include "mman.h"
#else #else
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "emulation.h"
#endif #endif
#include "compat/queue.h"
#endif #endif
#define FLASH_SECTOR_SIZE 4096 #ifdef ENABLE_EMULATION
#ifdef ESP_PLATFORM #define FLASH_SECTOR_SIZE 0x4000
extern uint32_t PICO_FLASH_SIZE_BYTES;
#else #else
#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024) #define FLASH_SECTOR_SIZE 0x1000
#endif #endif
#define XIP_BASE 0 #define XIP_BASE 0
int fd_map = 0; int fd_map = 0;
uint8_t *map = NULL; uint8_t *map = NULL;
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
extern uint32_t FLASH_SIZE_BYTES;
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif
#define TOTAL_FLASH_PAGES 6 #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 start_data_pool;
extern const uintptr_t end_rom_pool; extern const uintptr_t end_rom_pool;
PACK(
typedef struct page_flash { typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE]; uint8_t page[FLASH_SECTOR_SIZE];
uintptr_t address; uintptr_t address;
bool ready; bool ready;
bool erase; bool erase;
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
} page_flash_t; }) page_flash_t;
static page_flash_t flash_pages[TOTAL_FLASH_PAGES]; static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash; static mutex_t mtx_flash;
static semaphore_t sem_flash;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
static bool locked_out = false; static bool locked_out = false;
@@ -101,25 +99,34 @@ bool flash_available = false;
//this function has to be called from the core 0 //this function has to be called from the core 0
void do_flash() { void low_flash_task(void);
void low_flash_commit(void);
void low_flash_task(void){
if (mutex_try_enter(&mtx_flash, NULL) == true) { if (mutex_try_enter(&mtx_flash, NULL) == true) {
if (locked_out == true && flash_available == true && ready_pages > 0) { if (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\n"); //printf(" DO_FLASH AVAILABLE\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) { if (flash_pages[r].ready == true) {
#ifndef ENABLE_EMULATION #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
mutex_exit(&mtx_flash);
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE); //printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false) { if (multicore_lockout_start_timeout_us(1000) == false) {
; printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
mutex_enter_blocking(&mtx_flash);
continue;
} }
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE); //printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts(); uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE); 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); flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts(ints); restore_interrupts(ints);
while (multicore_lockout_end_timeout_us(1000) == false) { if (multicore_lockout_end_timeout_us(1000) == false) {
; printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
mutex_enter_blocking(&mtx_flash);
continue;
} }
mutex_enter_blocking(&mtx_flash);
//printf("WRITEN %X !\n",flash_pages[r].address); //printf("WRITEN %X !\n",flash_pages[r].address);
#else #else
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE); memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
@@ -128,15 +135,23 @@ void do_flash() {
ready_pages--; ready_pages--;
} }
else if (flash_pages[r].erase == true) { else if (flash_pages[r].erase == true) {
#ifndef ENABLE_EMULATION #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
while (multicore_lockout_start_timeout_us(1000) == false) { mutex_exit(&mtx_flash);
; if (multicore_lockout_start_timeout_us(1000) == false) {
printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
mutex_enter_blocking(&mtx_flash);
continue;
} }
//printf("WRITTING\n"); //printf("WRITTING\n");
uint32_t ints = save_and_disable_interrupts();
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); 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) { restore_interrupts(ints);
; if (multicore_lockout_end_timeout_us(1000) == false) {
printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
mutex_enter_blocking(&mtx_flash);
continue;
} }
mutex_enter_blocking(&mtx_flash);
#else #else
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE); memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
#endif #endif
@@ -144,96 +159,104 @@ void do_flash() {
ready_pages--; ready_pages--;
} }
} }
#ifdef ENABLE_EMULATION #if !defined(PICO_PLATFORM) && !defined(ESP_PLATFORM)
msync(map, PICO_FLASH_SIZE_BYTES, MS_SYNC); msync(map, FLASH_SIZE_BYTES, MS_SYNC);
#endif #endif
if (ready_pages != 0) { if (ready_pages != 0) {
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n"); printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
} }
} }
flash_available = false; if (ready_pages == 0) {
flash_available = false;
}
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
esp_partition_munmap(fd_map); 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); esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
#endif #endif
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
} }
sem_release(&sem_flash);
} }
#ifdef PICO_RP2040
void phymarker_write(void);
#endif
//this function has to be called from the core 0 //this function has to be called from the core 0
void low_flash_init() { void low_flash_init(void) {
#ifdef PICO_RP2040
phymarker_write();
#endif
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES); memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
mutex_init(&mtx_flash); mutex_init(&mtx_flash);
sem_init(&sem_flash, 0, 1);
uint32_t data_start_addr; uint32_t data_start_addr;
uint32_t data_end_addr; uint32_t data_end_addr;
#if defined(ENABLE_EMULATION) #if defined(ESP_PLATFORM)
fd_map = open("memory.flash", O_RDWR | O_CREAT, (mode_t) 0600);
lseek(fd_map, PICO_FLASH_SIZE_BYTES - 1, SEEK_SET);
write(fd_map, "", 1);
map = mmap(0, PICO_FLASH_SIZE_BYTES, PROT_READ | PROT_WRITE, MAP_SHARED, fd_map, 0);
data_start_addr = 0;
data_end_addr = PICO_FLASH_SIZE_BYTES;
#elif defined(ESP_PLATFORM)
part0 = esp_partition_find_first(0x40, 0x1, "part0"); 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); 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_start_addr = 0;
data_end_addr = part0->size; data_end_addr = part0->size;
PICO_FLASH_SIZE_BYTES = part0->size; FLASH_SIZE_BYTES = part0->size;
#elif defined(PICO_PLATFORM) #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 #ifdef PICO_RP2350
__attribute__((aligned(4))) uint8_t workarea[4 * 1024]; __attribute__((aligned(4))) uint32_t workarea[1024];
int rc = rom_load_partition_table(workarea, sizeof(workarea), false); int rc = rom_load_partition_table((uint8_t *)workarea, sizeof(workarea), false);
if (rc) { if (rc) {
reset_usb_boot(0, 0); reset_usb_boot(0, 0);
} }
uint8_t boot_partition = 1; 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)); rc = rom_get_partition_table_info(workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
if (rc != 3) { if (rc != 3) {
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1); data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = PICO_FLASH_SIZE_BYTES; data_end_addr = FLASH_SIZE_BYTES;
} else { } else {
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB; uint16_t first_sector_number = (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; uint16_t last_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
data_start_addr = first_sector_number * FLASH_SECTOR_SIZE; data_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE; data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
if (data_end_addr > FLASH_SIZE_BYTES) {
data_end_addr = FLASH_SIZE_BYTES;
}
} }
data_end_addr -= 2 * FLASH_SECTOR_SIZE; data_end_addr -= 2 * FLASH_SECTOR_SIZE;
#else #else
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1); data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = PICO_FLASH_SIZE_BYTES; data_end_addr = FLASH_SIZE_BYTES;
#endif #endif
data_start_addr += XIP_BASE; data_start_addr += XIP_BASE;
data_end_addr += XIP_BASE; data_end_addr += XIP_BASE;
#else
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;
#endif #endif
flash_set_bounds(data_start_addr, data_end_addr); flash_set_bounds(data_start_addr, data_end_addr);
} }
void low_flash_init_core1() { void low_flash_init_core1(void) {
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
multicore_lockout_victim_init(); multicore_lockout_victim_init();
locked_out = true; locked_out = true;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
} }
void wait_flash_finish() { void low_flash_commit(void) {
sem_acquire_blocking(&sem_flash); //blocks until released
//wake up
sem_acquire_blocking(&sem_flash); //decrease permits
}
void low_flash_available() {
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
flash_available = true; flash_available = true;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
} }
page_flash_t *find_free_page(uintptr_t addr) { static page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL; page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
@@ -260,24 +283,24 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
page_flash_t *p = NULL; page_flash_t *p = NULL;
if (!data || len == 0) { if (!data || len == 0) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) { if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n"); printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY; return PICOKEYS_ERR_NO_MEMORY;
} }
if (!(p = find_free_page(addr))) { if (!(p = find_free_page(addr))) {
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n"); printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
return PICOKEY_ERR_MEMORY_FATAL; return PICOKEYS_ERR_MEMORY_FATAL;
} }
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len); 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)); //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); mutex_exit(&mtx_flash);
return PICOKEY_OK; return PICOKEYS_OK;
} }
int flash_program_halfword(uintptr_t addr, uint16_t data) { int flash_program_halfword(uintptr_t addr, uint16_t data) {
@@ -306,7 +329,7 @@ uint8_t *flash_read(uintptr_t addr) {
} }
uint8_t *v = (uint8_t *) addr; uint8_t *v = (uint8_t *) addr;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM) #if !defined(PICO_PLATFORM)
if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) { if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) {
v += (uintptr_t) map; v += (uintptr_t) map;
} }
@@ -317,7 +340,7 @@ uint8_t *flash_read(uintptr_t addr) {
uintptr_t flash_read_uintptr(uintptr_t addr) { uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr); uint8_t *p = flash_read(addr);
uintptr_t v = 0x0; uintptr_t v = 0x0;
for (int i = 0; i < sizeof(uintptr_t); i++) { for (size_t i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t) p[i] << (8 * i); v |= (uintptr_t) p[i] << (8 * i);
} }
return v; return v;
@@ -325,7 +348,7 @@ uintptr_t flash_read_uintptr(uintptr_t addr) {
uint16_t flash_read_uint16(uintptr_t addr) { uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr); uint8_t *p = flash_read(addr);
uint16_t v = 0x0; uint16_t v = 0x0;
for (int i = 0; i < sizeof(uint16_t); i++) { for (size_t i = 0; i < sizeof(uint16_t); i++) {
v |= p[i] << (8 * i); v |= p[i] << (8 * i);
} }
return v; return v;
@@ -341,19 +364,19 @@ int flash_erase_page(uintptr_t addr, size_t page_size) {
if (ready_pages == TOTAL_FLASH_PAGES) { if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n"); printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY; return PICOKEYS_ERR_NO_MEMORY;
} }
if (!(p = find_free_page(addr))) { if (!(p = find_free_page(addr))) {
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n"); printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
return PICOKEY_ERR_MEMORY_FATAL; return PICOKEYS_ERR_MEMORY_FATAL;
} }
p->erase = true; p->erase = true;
p->ready = false; p->ready = false;
p->page_size = page_size; p->page_size = page_size;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
return PICOKEY_OK; return PICOKEYS_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) {
@@ -366,3 +389,42 @@ bool flash_check_blank(const uint8_t *p_start, size_t size) {
} }
return true; return true;
} }
#ifdef PICO_RP2040
typedef struct {
uint64_t magic;
uint16_t version;
uint16_t flags;
uint8_t uid[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
uint32_t crc32;
} __attribute__ ((packed)) phymarker_t;
uintptr_t __phymarker_start = (uintptr_t)0x10100000;
const uint64_t PHYSICAL_MARKER_MAGIC = 0x5049434F4B455953ULL; // "PICOKEYS"
void phymarker_write(void) {
const uint64_t magic = *(uint64_t *)__phymarker_start;
if (magic == PHYSICAL_MARKER_MAGIC) {
return;
}
phymarker_t pm = {
.magic = PHYSICAL_MARKER_MAGIC, // "PICOKEYS"
.version = 0x0001,
.flags = 0x0000,
.crc32 = 0x00000000
};
memcpy(pm.uid, pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
pm.crc32 = crc32c((const uint8_t *)&pm, sizeof(phymarker_t) - sizeof(uint32_t));
uint8_t buf[FLASH_PAGE_SIZE] = {0};
memcpy(buf, &pm, sizeof(phymarker_t));
uint32_t ints = save_and_disable_interrupts();
flash_range_erase((uint32_t)__phymarker_start - XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program((uint32_t)__phymarker_start - XIP_BASE, (const uint8_t *)buf, sizeof(buf));
restore_interrupts(ints);
}
#endif

View File

@@ -1,3 +1,20 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <windows.h> #include <windows.h>
#include <errno.h> #include <errno.h>

View File

@@ -1,8 +1,21 @@
/* /*
* sys/mman.h * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* mman-win32 * Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _SYS_MMAN_H_ #ifndef _SYS_MMAN_H_
#define _SYS_MMAN_H_ #define _SYS_MMAN_H_

View File

@@ -1,241 +0,0 @@
/*
* 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
}

View File

@@ -1,51 +0,0 @@
/*
* 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_

View File

@@ -3,20 +3,20 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "file.h" #include "otp.h"
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
@@ -24,7 +24,7 @@ phy_data_t phy_data;
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) { int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (!phy || !data || !len) { if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
uint8_t *p = data; uint8_t *p = data;
if (phy->vidpid_present) { if (phy->vidpid_present) {
@@ -47,7 +47,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
} }
*p++ = PHY_OPTS; *p++ = PHY_OPTS;
*p++ = 2; *p++ = 2;
p += put_uint16_t_be(phy->opts, p); p += put_uint16_be(phy->opts, p);
if (phy->up_btn_present) { if (phy->up_btn_present) {
*p++ = PHY_UP_BTN; *p++ = PHY_UP_BTN;
*p++ = 1; *p++ = 1;
@@ -55,7 +55,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
} }
if (phy->usb_product_present) { if (phy->usb_product_present) {
*p++ = PHY_USB_PRODUCT; *p++ = PHY_USB_PRODUCT;
*p++ = strlen(phy->usb_product) + 1; *p++ = (uint8_t)strlen(phy->usb_product) + 1;
strcpy((char *)p, phy->usb_product); strcpy((char *)p, phy->usb_product);
p += strlen(phy->usb_product); p += strlen(phy->usb_product);
*p++ = '\0'; *p++ = '\0';
@@ -63,21 +63,26 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (phy->enabled_curves_present) { if (phy->enabled_curves_present) {
*p++ = PHY_ENABLED_CURVES; *p++ = PHY_ENABLED_CURVES;
*p++ = 4; *p++ = 4;
p += put_uint32_t_be(phy->enabled_curves, p); p += put_uint32_be(phy->enabled_curves, p);
} }
if (phy->enabled_usb_itf_present) { if (phy->enabled_usb_itf_present) {
*p++ = PHY_ENABLED_USB_ITF; *p++ = PHY_ENABLED_USB_ITF;
*p++ = 1; *p++ = 1;
*p++ = phy->enabled_usb_itf; *p++ = phy->enabled_usb_itf;
} }
if (phy->led_driver_present) {
*p++ = PHY_LED_DRIVER;
*p++ = 1;
*p++ = phy->led_driver;
}
*len = p - data; *len = (uint8_t)(p - data);
return PICOKEY_OK; return PICOKEYS_OK;
} }
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) { int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
if (!phy || !data || !len) { if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
const uint8_t *p = data; const uint8_t *p = data;
uint8_t tag, tlen; uint8_t tag, tlen;
@@ -109,7 +114,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
break; break;
case PHY_OPTS: case PHY_OPTS:
if (tlen == 2) { if (tlen == 2) {
phy->opts = get_uint16_t_be(p); phy->opts = get_uint16_be(p);
p += 2; p += 2;
} }
break; break;
@@ -129,7 +134,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
break; break;
case PHY_ENABLED_CURVES: case PHY_ENABLED_CURVES:
if (tlen == 4) { if (tlen == 4) {
phy->enabled_curves = get_uint32_t_be(p); phy->enabled_curves = get_uint32_be(p);
p += 4; p += 4;
phy->enabled_curves_present = true; phy->enabled_curves_present = true;
} }
@@ -141,39 +146,45 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
phy->enabled_usb_itf_present = true; phy->enabled_usb_itf_present = true;
} }
break; break;
case PHY_LED_DRIVER:
if (tlen == 1) {
phy->led_driver = *p++;
phy->led_driver_present = true;
}
break;
default: default:
p += tlen; p += tlen;
break; break;
} }
} }
if (!phy_data.enabled_usb_itf_present) { 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 = PHY_USB_ITF_ALL;
phy_data.enabled_usb_itf_present = true; phy_data.enabled_usb_itf_present = true;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int phy_init() { int phy_init(void) {
memset(&phy_data, 0, sizeof(phy_data_t)); memset(&phy_data, 0, sizeof(phy_data_t));
return phy_load(); return phy_load();
} }
int phy_save() { int phy_save(void) {
uint8_t tmp[PHY_MAX_SIZE] = {0}; uint8_t tmp[PHY_MAX_SIZE] = {0};
uint16_t tmp_len = 0; uint16_t tmp_len = 0;
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len); int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
if (ret != PICOKEY_OK) { if (ret != PICOKEYS_OK) {
return ret; return ret;
} }
file_put_data(ef_phy, tmp, tmp_len); file_put_data(ef_phy, tmp, tmp_len);
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int phy_load() { int phy_load(void) {
if (file_has_data(ef_phy)) { if (file_has_data(ef_phy)) {
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data); return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
#endif #endif

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _PHY_H_ #ifndef _PHY_H_
@@ -28,6 +28,7 @@
#define PHY_USB_PRODUCT 0x9 #define PHY_USB_PRODUCT 0x9
#define PHY_ENABLED_CURVES 0xA #define PHY_ENABLED_CURVES 0xA
#define PHY_ENABLED_USB_ITF 0xB #define PHY_ENABLED_USB_ITF 0xB
#define PHY_LED_DRIVER 0xC
#define PHY_OPT_WCID 0x1 #define PHY_OPT_WCID 0x1
#define PHY_OPT_DIMM 0x2 #define PHY_OPT_DIMM 0x2
@@ -50,10 +51,25 @@
#define PHY_USB_ITF_WCID 0x2 #define PHY_USB_ITF_WCID 0x2
#define PHY_USB_ITF_HID 0x4 #define PHY_USB_ITF_HID 0x4
#define PHY_USB_ITF_KB 0x8 #define PHY_USB_ITF_KB 0x8
#define PHY_USB_ITF_LWIP 0x10
#define PHY_USB_ITF_ALL (PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB | PHY_USB_ITF_LWIP)
#define PHY_LED_DRIVER_PICO 0x1
#define PHY_LED_DRIVER_PIMORONI 0x2
#define PHY_LED_DRIVER_WS2812 0x3
#ifdef CYW43_WL_GPIO_LED_PIN
#define PHY_LED_DRIVER_CYW43 0x4
#endif
#ifdef ESP_PLATFORM
#define PHY_LED_DRIVER_NEOPIXEL 0x5
#endif
#define PHY_LED_DRIVER_NONE 0xFF
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
PACK(
typedef struct phy_data { typedef struct phy_data {
union { union {
struct { struct {
@@ -73,6 +89,7 @@ typedef struct phy_data {
uint8_t led_brightness; uint8_t led_brightness;
uint8_t up_btn; uint8_t up_btn;
uint8_t enabled_usb_itf; uint8_t enabled_usb_itf;
uint8_t led_driver;
bool vidpid_present; bool vidpid_present;
bool led_gpio_present; bool led_gpio_present;
@@ -81,17 +98,18 @@ typedef struct phy_data {
bool usb_product_present; bool usb_product_present;
bool enabled_curves_present; bool enabled_curves_present;
bool enabled_usb_itf_present; bool enabled_usb_itf_present;
bool led_driver_present;
} phy_data_t; }) phy_data_t;
#define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1)) #define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1)+(2+1))
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len); 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_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
extern int phy_init(); extern int phy_init(void);
extern int phy_save(); extern int phy_save(void);
extern int phy_load(); extern int phy_load(void);
extern phy_data_t phy_data; extern phy_data_t phy_data;
#endif #endif

42
src/json.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _JSON_H_
#define _JSON_H_
#include "cJSON.h"
#define CJSON_ADD_GENERIC(hdl, ptr, item, value) do { \
if (hdl(ptr, item, value) == NULL) { \
response->status_code = 500; \
return 1; \
} \
} while(0)
#define CJSON_ADD_GENERIC_ITEM(hdl, ptr, item, value) do { \
if (hdl(ptr, item, value) == false) { \
response->status_code = 500; \
return 1; \
} \
} while(0)
#define CJSON_ADD_STRING(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddStringToObject, (ptr)->json, item, value)
#define CJSON_ADD_NUMBER(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddNumberToObject, (ptr)->json, item, value)
#define CJSON_ADD_BOOL(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddBoolToObject, (ptr)->json, item, value)
#define CJSON_ADD_ITEM(ptr, item, value) CJSON_ADD_GENERIC_ITEM(cJSON_AddItemToObject, (ptr)->json, item, value)
#endif // _JSON_H_

View File

@@ -1,33 +1,30 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include "picokeys.h"
#include <stdlib.h> #include "led/led.h"
#include "pico_keys.h" #include "pico_time.h"
#ifdef PICO_PLATFORM #if defined(ESP_PLATFORM)
#include "bsp/board.h" #include "driver/gpio.h"
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(ENABLE_EMULATION) #elif defined(ENABLE_EMULATION)
#include "emulation.h" #include "emulation.h"
#endif #endif
extern void led_driver_init(); led_driver_t *led_driver = NULL;
extern void led_driver_color(uint8_t, uint32_t, float);
static uint32_t led_mode = MODE_NOT_MOUNTED; static uint32_t led_mode = MODE_NOT_MOUNTED;
@@ -35,12 +32,12 @@ void led_set_mode(uint32_t mode) {
led_mode = mode; led_mode = mode;
} }
uint32_t led_get_mode() { uint32_t led_get_mode(void) {
return led_mode; return led_mode;
} }
void led_blinking_task() { void led_blinking_task(void) {
#ifndef ENABLE_EMULATION #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
static uint32_t start_ms = 0; static uint32_t start_ms = 0;
static uint32_t stop_ms = 0; static uint32_t stop_ms = 0;
static uint32_t last_led_update_ms = 0; static uint32_t last_led_update_ms = 0;
@@ -69,7 +66,7 @@ void led_blinking_task() {
// limit the frequency of LED status updates // limit the frequency of LED status updates
if (board_millis() - last_led_update_ms > 2) { if (board_millis() - last_led_update_ms > 2) {
led_driver_color(led_color, led_brightness, progress); led_driver->set_color(led_color, led_brightness, progress);
last_led_update_ms = board_millis(); last_led_update_ms = board_millis();
} }
@@ -81,15 +78,97 @@ void led_blinking_task() {
#endif #endif
} }
void led_off_all() { void led_off_all(void) {
#ifndef ENABLE_EMULATION #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
led_driver_color(LED_COLOR_OFF, 0, 0); led_driver->set_color(LED_COLOR_OFF, 0, 0);
#endif #endif
} }
void led_init() { extern led_driver_t led_driver_pico;
#ifndef ENABLE_EMULATION extern led_driver_t led_driver_cyw43;
led_driver_init(); extern led_driver_t led_driver_ws2812;
extern led_driver_t led_driver_neopixel;
extern led_driver_t led_driver_pimoroni;
static void led_driver_init_dummy(void) {
// Do nothing
}
static void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
(void)color;
(void)led_brightness;
(void)progress;
// Do nothing
}
led_driver_t led_driver_dummy = {
.init = led_driver_init_dummy,
.set_color = led_driver_color_dummy,
};
void led_init(void) {
led_driver = &led_driver_dummy;
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
// Guess default driver
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350)
led_driver = &led_driver_pimoroni;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PIMORONI;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_LED_PIN;
#elif defined(CYW43_WL_GPIO_LED_PIN)
led_driver = &led_driver_cyw43;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_CYW43;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : CYW43_WL_GPIO_LED_PIN;
#elif defined(PICO_DEFAULT_WS2812_PIN)
led_driver = &led_driver_ws2812;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_WS2812;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_WS2812_PIN;
#elif defined(ESP_PLATFORM)
#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
led_driver = &led_driver_neopixel;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_NEOPIXEL;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : NEOPIXEL_PIN;
#elif defined(PICO_DEFAULT_LED_PIN)
led_driver = &led_driver_pico;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PICO;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_LED_PIN;
#endif
if (phy_data.led_driver_present) {
switch (phy_data.led_driver) {
case PHY_LED_DRIVER_PICO:
led_driver = &led_driver_pico;
break;
#ifdef ESP_PLATFORM
case PHY_LED_DRIVER_NEOPIXEL:
led_driver = &led_driver_neopixel;
break;
#else
#ifdef CYW43_WL_GPIO_LED_PIN
case PHY_LED_DRIVER_CYW43:
led_driver = &led_driver_cyw43;
break;
#endif
case PHY_LED_DRIVER_WS2812:
led_driver = &led_driver_ws2812;
break;
case PHY_LED_DRIVER_PIMORONI:
led_driver = &led_driver_pimoroni;
break;
#endif
default:
break;
}
}
phy_data.led_driver_present = true;
phy_data.led_gpio_present = true;
led_driver->init();
led_set_mode(MODE_NOT_MOUNTED); led_set_mode(MODE_NOT_MOUNTED);
#endif #endif
} }

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _LED_H_ #ifndef _LED_H_
@@ -62,9 +62,16 @@ enum {
}; };
extern void led_set_mode(uint32_t mode); extern void led_set_mode(uint32_t mode);
extern uint32_t led_get_mode(); extern uint32_t led_get_mode(void);
extern void led_blinking_task(); extern void led_blinking_task(void);
extern void led_off_all(); extern void led_off_all(void);
extern void led_init(); extern void led_init(void);
typedef struct {
void (*init)(void);
void (*set_color)(uint8_t color, uint32_t led_brightness, float progress);
} led_driver_t;
extern led_driver_t *led_driver;
#endif // _LED_H_ #endif // _LED_H_

View File

@@ -3,30 +3,38 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "led/led.h"
#ifdef PICO_PLATFORM
#include "hardware/gpio.h"
#endif
#ifdef CYW43_WL_GPIO_LED_PIN #ifdef CYW43_WL_GPIO_LED_PIN
#include "pico/cyw43_arch.h" #include "pico/cyw43_arch.h"
void led_driver_init() { void led_driver_init_cyw43(void);
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress);
void led_driver_init_cyw43(void) {
cyw43_arch_init(); cyw43_arch_init();
} }
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) { void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness; (void)led_brightness;
(void)color;
uint8_t gpio = CYW43_WL_GPIO_LED_PIN; uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
if (phy_data.led_gpio_present) { if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio; gpio = phy_data.led_gpio;
@@ -34,4 +42,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
cyw43_arch_gpio_put(gpio, progress >= 0.5); cyw43_arch_gpio_put(gpio, progress >= 0.5);
} }
led_driver_t led_driver_cyw43 = {
.init = led_driver_init_cyw43,
.set_color = led_driver_color_cyw43,
};
#endif #endif

View File

@@ -3,19 +3,23 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "led/led.h"
#ifdef PICO_PLATFORM
#include "hardware/gpio.h"
#endif
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
@@ -45,7 +49,7 @@ tNeopixel pixel[] = {
#define NEOPIXEL_PIN GPIO_NUM_27 #define NEOPIXEL_PIN GPIO_NUM_27
#endif #endif
void led_driver_init() { void led_driver_init_neopixel(void) {
uint8_t gpio = NEOPIXEL_PIN; uint8_t gpio = NEOPIXEL_PIN;
if (phy_data.led_gpio_present) { if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio; gpio = phy_data.led_gpio;
@@ -53,7 +57,7 @@ void led_driver_init() {
neopixel = neopixel_Init(1, gpio); neopixel = neopixel_Init(1, gpio);
} }
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) { void led_driver_color_neopixel(uint8_t color, uint32_t led_brightness, float progress) {
static tNeopixel spx = {.index = 0, .rgb = 0}; static tNeopixel spx = {.index = 0, .rgb = 0};
if (!(phy_data.opts & PHY_OPT_DIMM)) { if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0; progress = progress >= 0.5 ? 1 : 0;
@@ -72,4 +76,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
neopixel_SetPixel(neopixel, &spx, 1); neopixel_SetPixel(neopixel, &spx, 1);
} }
led_driver_t led_driver_neopixel = {
.init = led_driver_init_neopixel,
.set_color = led_driver_color_neopixel,
};
#endif #endif

View File

@@ -3,25 +3,40 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "led/led.h"
#if defined(PICO_DEFAULT_LED_PIN) && !defined(PICO_DEFAULT_WS2812_PIN) && !defined(PIMORONI_TINY2040) && !defined(PIMORONI_TINY2350) #ifdef PICO_PLATFORM
#include "hardware/gpio.h"
#endif
#ifdef PICO_DEFAULT_LED_PIN
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
#else
static uint8_t gpio = 0;
#endif
uint8_t gpio = PICO_DEFAULT_LED_PIN; #ifdef ESP_PLATFORM
#include "driver/gpio.h"
#define gpio_init gpio_reset_pin
#define gpio_set_dir gpio_set_direction
#define gpio_put gpio_set_level
#define GPIO_OUT GPIO_MODE_OUTPUT
#endif
void led_driver_init() { #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
static void led_driver_init_pico(void) {
if (phy_data.led_gpio_present) { if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio; gpio = phy_data.led_gpio;
} }
@@ -29,9 +44,15 @@ void led_driver_init() {
gpio_set_dir(gpio, GPIO_OUT); gpio_set_dir(gpio, GPIO_OUT);
} }
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) { static void led_driver_color_pico(uint8_t color, uint32_t led_brightness, float progress) {
(void)color;
(void)led_brightness; (void)led_brightness;
gpio_put(gpio, progress >= 0.5); gpio_put(gpio, progress >= 0.5);
} }
led_driver_t led_driver_pico = {
.init = led_driver_init_pico,
.set_color = led_driver_color_pico,
};
#endif #endif

View File

@@ -3,30 +3,27 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "led/led.h"
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350) #ifdef PICO_PLATFORM
#include "hardware/gpio.h"
#ifdef PIMORONI_TINY2040 #ifdef PICO_DEFAULT_LED_PIN
#define LED_R_PIN TINY2040_LED_R_PIN static uint8_t gpio = PICO_DEFAULT_LED_PIN;
#define LED_G_PIN TINY2040_LED_G_PIN #else
#define LED_B_PIN TINY2040_LED_B_PIN static uint8_t gpio = 0;
#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 #endif
uint8_t pixel[][3] = { uint8_t pixel[][3] = {
@@ -40,22 +37,31 @@ uint8_t pixel[][3] = {
{0, 0, 0} // 7: white {0, 0, 0} // 7: white
}; };
void led_driver_init() { static void led_driver_init_pimoroni(void) {
gpio_init(LED_R_PIN); if (phy_data.led_gpio_present) {
gpio_set_dir(LED_R_PIN, GPIO_OUT); gpio = phy_data.led_gpio;
gpio_init(LED_G_PIN); }
gpio_set_dir(LED_G_PIN, GPIO_OUT); gpio_init(gpio-1);
gpio_init(LED_B_PIN); gpio_set_dir(gpio-1, GPIO_OUT);
gpio_set_dir(LED_B_PIN, GPIO_OUT); gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
gpio_init(gpio+1);
gpio_set_dir(gpio+1, GPIO_OUT);
} }
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) { static void led_driver_color_pimoroni(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
if (progress < 0.5) { if (progress < 0.5) {
color = LED_COLOR_OFF; color = LED_COLOR_OFF;
} }
gpio_put(LED_R_PIN, pixel[color][0]); gpio_put(gpio-1, pixel[color][0]);
gpio_put(LED_G_PIN, pixel[color][1]); gpio_put(gpio, pixel[color][1]);
gpio_put(LED_B_PIN, pixel[color][2]); gpio_put(gpio+1, pixel[color][2]);
} }
led_driver_t led_driver_pimoroni = {
.init = led_driver_init_pimoroni,
.set_color = led_driver_color_pimoroni,
};
#endif #endif

View File

@@ -3,22 +3,22 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "led/led.h"
#ifdef PICO_DEFAULT_WS2812_PIN
#ifdef PICO_PLATFORM
#include "hardware/pio.h" #include "hardware/pio.h"
#include "hardware/clocks.h" #include "hardware/clocks.h"
@@ -70,11 +70,14 @@ static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
pio_sm_set_enabled(pio, sm, true); pio_sm_set_enabled(pio, sm, true);
} }
void led_driver_init() { static void led_driver_init_ws2812(void) {
PIO pio = pio0; PIO pio = pio0;
int sm = 0; int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program); uint offset = pio_add_program(pio, &ws2812_program);
uint8_t gpio = PICO_DEFAULT_WS2812_PIN; uint8_t gpio = 0;
#ifdef PICO_DEFAULT_WS2812_PIN
gpio = PICO_DEFAULT_WS2812_PIN;
#endif
if (phy_data.led_gpio_present) { if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio; gpio = phy_data.led_gpio;
} }
@@ -113,7 +116,7 @@ static inline void ws2812_put_pixel(uint32_t u32_pixel) {
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u); pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
} }
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) { static void led_driver_color_ws2812(uint8_t color, uint32_t led_brightness, float progress) {
if (!(phy_data.opts & PHY_OPT_DIMM)) { if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0; progress = progress >= 0.5 ? 1 : 0;
} }
@@ -128,4 +131,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
ws2812_put_pixel(urgb_u32(pixel_color.r, pixel_color.g, pixel_color.b)); ws2812_put_pixel(urgb_u32(pixel_color.r, pixel_color.g, pixel_color.b));
} }
led_driver_t led_driver_ws2812 = {
.init = led_driver_init_ws2812,
.set_color = led_driver_color_ws2812,
};
#endif #endif

View File

@@ -3,51 +3,47 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include "picokeys.h"
#include <stdlib.h> #include "button.h"
#if !defined(ENABLE_EMULATION)
// Pico #include "tusb.h"
#endif
#if defined(ENABLE_EMULATION) #if defined(ENABLE_EMULATION)
#include "emulation.h" #include "emulation.h"
#elif defined(ESP_PLATFORM) #elif defined(ESP_PLATFORM)
#include "tusb.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "rom/gpio.h" #include "rom/gpio.h"
#include "tinyusb.h" #include "tinyusb.h"
#include "esp_efuse.h" #elif defined(PICO_PLATFORM)
#define BOOT_PIN GPIO_NUM_0
#else
#include "pico/stdlib.h"
#include "bsp/board.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/ioqspi.h"
#include "hardware/structs/sio.h" #include "pico/stdio.h"
#endif #endif
#include "random.h" #include "random.h"
#include "pico_keys.h" #include "hwrng.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
extern void do_flash(); #include "flash.h"
extern void low_flash_init(); #include "otp.h"
extern void init_otp_files(); #include "led/led.h"
#include "pico_time.h"
#include "serial.h"
#include "mbedtls/sha256.h"
app_t apps[8]; app_t apps[16];
uint8_t num_apps = 0; uint8_t num_apps = 0;
app_t *current_app = NULL; app_t *current_app = NULL;
@@ -55,11 +51,8 @@ app_t *current_app = NULL;
const uint8_t *ccid_atr = NULL; const uint8_t *ccid_atr = NULL;
bool app_exists(const uint8_t *aid, size_t aid_len) { 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++) { for (int a = 0; a < num_apps; a++) {
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) { if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
return true; return true;
} }
} }
@@ -80,233 +73,82 @@ int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
} }
int select_app(const uint8_t *aid, size_t aid_len) { 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))) { if (current_app && current_app->aid && (current_app->aid + 1 == aid || (aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])))) {
current_app->select_aid(current_app, 0); current_app->select_aid(current_app, 0);
return PICOKEY_OK; return PICOKEYS_OK;
} }
for (int a = 0; a < num_apps; a++) { for (int a = 0; a < num_apps; a++) {
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) { if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
if (current_app) { if (current_app) {
if (current_app->aid && !memcmp(current_app->aid + 1, aid, aid_len)) { if (current_app->aid && aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])) {
current_app->select_aid(current_app, 1); current_app->select_aid(current_app, 1);
return PICOKEY_OK; return PICOKEYS_OK;
} }
if (current_app->unload) { if (current_app->unload) {
current_app->unload(); current_app->unload();
} }
} }
current_app = &apps[a]; current_app = &apps[a];
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) { if (current_app->select_aid(current_app, 1) == PICOKEYS_OK) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
} }
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
int (*button_pressed_cb)(uint8_t) = NULL;
void execute_tasks(); WEAK int picokey_init(void) {
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; 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 void execute_tasks(void);
// are about to temporarily disable flash access! void execute_tasks(void) {
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) #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
tud_task(); // tinyusb device task tud_task(); // tinyusb device task
#endif
#ifdef USB_ITF_LWIP
#if !defined(ENABLE_EMULATION)
service_traffic();
#endif
rest_task();
#endif #endif
usb_task(); usb_task();
led_blinking_task(); led_blinking_task();
} }
void core0_loop() { static void core0_loop(void *arg) {
(void)arg;
#if defined(ESP_PLATFORM) && defined(USB_ITF_LWIP)
if (ITF_LWIP_TOTAL > 0) {
lwip_itf_init();
}
#endif
while (1) { while (1) {
execute_tasks(); execute_tasks();
neug_task(); hwrng_task();
do_flash(); flash_task();
#ifndef ENABLE_EMULATION button_task();
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 #ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
#endif #endif
} }
} }
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
pico_unique_board_id_t pico_serial;
#ifdef ESP_PLATFORM #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 tinyusb_config_t tusb_cfg;
extern const uint8_t desc_config[]; extern const uint8_t desc_config[];
extern char *string_desc_arr[];
extern char *string_desc_itf[];
TaskHandle_t hcore0 = NULL, hcore1 = NULL; TaskHandle_t hcore0 = NULL, hcore1 = NULL;
int app_main() { int app_main(void) {
#else #else
#ifdef ENABLE_EMULATION
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
#endif
int main(void) { int main(void) {
#endif #endif
pico_get_unique_board_id(&pico_serial); serial_init();
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 ENABLE_EMULATION
#ifndef ESP_PLATFORM #ifdef PICO_PLATFORM
board_init(); board_init();
stdio_init_all(); stdio_init_all();
#endif #endif
@@ -317,11 +159,11 @@ int main(void) {
random_init(); random_init();
init_otp_files(); otp_init();
low_flash_init(); low_flash_init();
scan_flash(); file_scan_flash();
init_rtc(); init_rtc();
@@ -343,13 +185,16 @@ int main(void) {
if (phy_data.usb_product_present) { if (phy_data.usb_product_present) {
tusb_cfg.string_descriptor[2] = phy_data.usb_product; tusb_cfg.string_descriptor[2] = phy_data.usb_product;
} }
static char tmps[4][32]; static char tmps[5][32];
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) { const int max_desc_slots = 8 - 6;
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0])); const int itf_desc_count = ITF_TOTAL < max_desc_slots ? ITF_TOTAL : max_desc_slots;
strlcat(tmps[i-4], " ", sizeof(tmps[0])); for (int i = 0; i < itf_desc_count; i++) {
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0])); strlcpy(tmps[i], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
tusb_cfg.string_descriptor[i] = tmps[i-4]; strlcat(tmps[i], " ", sizeof(tmps[0]));
strlcat(tmps[i], string_desc_itf[i], sizeof(tmps[0]));
tusb_cfg.string_descriptor[i+6] = tmps[i];
} }
tusb_cfg.string_descriptor_count = 6 + itf_desc_count;
tusb_cfg.configuration_descriptor = desc_config; tusb_cfg.configuration_descriptor = desc_config;
tinyusb_driver_install(&tusb_cfg); tinyusb_driver_install(&tusb_cfg);
@@ -358,10 +203,14 @@ int main(void) {
#endif #endif
#endif #endif
#ifndef ENABLE_EMULATION
picokey_init();
#endif
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0); xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
#else #else
core0_loop(); core0_loop(NULL);
#endif #endif
return 0; return 0;

39
src/otp/otp.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "otp.h"
#include "otp_platform.h"
#include <stdlib.h>
const uint8_t *otp_key_1 = NULL;
const uint8_t *otp_key_2 = NULL;
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
return otp_platform_enable_secure_boot(bootkey, secure_lock);
}
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
return otp_platform_is_secure_boot_enabled(bootkey);
}
bool otp_is_secure_boot_locked(void) {
return otp_platform_is_secure_boot_locked();
}
void otp_init(void) {
otp_platform_init(&otp_key_1, &otp_key_2);
}

33
src/otp/otp.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _OTP_H_
#define _OTP_H_
#include <stdint.h>
#include <stdbool.h>
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
extern void otp_init(void);
extern bool otp_is_secure_boot_enabled(uint8_t *bootkey);
extern bool otp_is_secure_boot_locked(void);
extern const uint8_t *otp_key_1;
extern const uint8_t *otp_key_2;
#endif // _OTP_H_

47
src/otp/otp_emulation.c Normal file
View File

@@ -0,0 +1,47 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "picokeys.h"
#include "otp_platform.h"
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
(void)bootkey;
(void)secure_lock;
return PICOKEYS_OK;
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
(void)bootkey;
return false;
}
bool otp_platform_is_secure_boot_locked(void) {
return false;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
static uint8_t _otp1[32] = {0};
static uint8_t _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
*otp_key_1_out = _otp1;
*otp_key_2_out = _otp2;
}

341
src/otp/otp_esp32.c Normal file
View File

@@ -0,0 +1,341 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "picokeys.h"
#include "otp.h"
#include "otp_platform.h"
#include "random.h"
#include "mbedtls/ecdsa.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#define OTP_KEY_1 EFUSE_BLK_KEY3
#define OTP_KEY_2 EFUSE_BLK_KEY4
uint8_t _otp_key_1[32] = {0};
uint8_t _otp_key_2[32] = {0};
static const uint8_t esp_secure_boot_digest[32] = {
0x0c, 0x1e, 0xce, 0xf3, 0xb4, 0x8f, 0x4a, 0x81,
0x45, 0x6c, 0x85, 0x39, 0x15, 0xcc, 0x05, 0x36,
0xbe, 0x23, 0x24, 0xee, 0xac, 0x8e, 0x3b, 0xb5,
0x77, 0x6f, 0x2d, 0xb9, 0x62, 0x38, 0x75, 0x6a
};
#ifndef SECURE_BOOT_BOOTKEY_INDEX
#define SECURE_BOOT_BOOTKEY_INDEX 0
#endif
#ifndef PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK
#define PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK 1
#endif
static esp_efuse_purpose_t esp_secure_boot_purpose(uint8_t digest_idx) {
switch (digest_idx) {
case 0: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0;
case 1: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1;
case 2: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2;
default: return ESP_EFUSE_KEY_PURPOSE_MAX;
}
}
static bool esp_find_secure_boot_block(uint8_t digest_idx, esp_efuse_block_t *out_block) {
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
return false;
}
for (esp_efuse_block_t blk = EFUSE_BLK_KEY0; blk < EFUSE_BLK_KEY_MAX; blk++) {
if (esp_efuse_get_key_purpose(blk) == purpose) {
if (out_block) {
*out_block = blk;
}
return true;
}
}
return false;
}
static esp_err_t esp_provision_secure_boot_digest(uint8_t digest_idx, esp_efuse_block_t *out_block) {
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
return ESP_ERR_INVALID_ARG;
}
esp_efuse_block_t block = EFUSE_BLK_KEY_MAX;
if (esp_find_secure_boot_block(digest_idx, &block)) {
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
if (!key_desc) {
return ESP_FAIL;
}
uint8_t existing[32] = {0};
esp_err_t err = esp_efuse_read_field_blob(key_desc, existing, sizeof(existing) * 8);
if (err != ESP_OK) {
return err;
}
if (memcmp(existing, esp_secure_boot_digest, sizeof(existing)) != 0) {
return ESP_ERR_INVALID_STATE;
}
if (out_block) {
*out_block = block;
}
return ESP_OK;
}
block = esp_efuse_find_unused_key_block();
if (block == EFUSE_BLK_KEY_MAX) {
return ESP_ERR_NOT_FOUND;
}
esp_err_t err = esp_efuse_batch_write_begin();
if (err != ESP_OK) {
return err;
}
err = esp_efuse_set_key_purpose(block, purpose);
if (err == ESP_OK) {
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
if (!key_desc) {
err = ESP_FAIL;
} else {
err = esp_efuse_write_field_blob(key_desc, esp_secure_boot_digest, sizeof(esp_secure_boot_digest) * 8);
}
}
if (err == ESP_OK) {
err = esp_efuse_batch_write_commit();
} else {
esp_efuse_batch_write_cancel();
}
if (err == ESP_OK && out_block) {
*out_block = block;
}
return err;
}
static esp_err_t esp_disable_debug_interfaces(void) {
esp_err_t err = ESP_OK;
#ifdef ESP_EFUSE_SOFT_DIS_JTAG
err = esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
if (err != ESP_OK) {
return err;
}
#endif
#ifdef ESP_EFUSE_HARD_DIS_JTAG
err = esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
if (err != ESP_OK) {
return err;
}
#endif
#ifdef ESP_EFUSE_DIS_USB_JTAG
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
if (err != ESP_OK) {
return err;
}
#endif
#ifdef ESP_EFUSE_DIS_USB_SERIAL_JTAG
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_SERIAL_JTAG);
if (err != ESP_OK) {
return err;
}
#endif
#ifdef ESP_EFUSE_DIS_PAD_JTAG
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
if (err != ESP_OK) {
return err;
}
#endif
return err;
}
static 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);
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
return false;
}
uint8_t preferred = SECURE_BOOT_BOOTKEY_INDEX;
if (preferred <= 2 && esp_find_secure_boot_block(preferred, NULL)
&& !esp_efuse_get_digest_revoke(preferred)) {
if (bootkey) {
*bootkey = preferred;
}
return true;
}
for (uint8_t idx = 0; idx <= 2; idx++) {
if (esp_find_secure_boot_block(idx, NULL) && !esp_efuse_get_digest_revoke(idx)) {
if (bootkey) {
*bootkey = idx;
}
return true;
}
}
return false;
}
bool otp_platform_is_secure_boot_locked(void) {
uint8_t bootkey_idx = 0xFF;
if (!otp_platform_is_secure_boot_enabled(&bootkey_idx)) {
return false;
}
for (uint8_t idx = 0; idx <= 2; idx++) {
if (idx == bootkey_idx) {
continue;
}
if (!esp_efuse_get_digest_revoke(idx)) {
return false;
}
}
return true;
}
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
if (bootkey > 2) {
return ESP_ERR_INVALID_ARG;
}
if (secure_lock && PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK && !esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
printf("Secure lock requires SECURE_BOOT_EN already set. Enable secure boot first.\n");
return ESP_ERR_INVALID_STATE;
}
esp_efuse_block_t key_block = EFUSE_BLK_KEY_MAX;
esp_err_t err = esp_provision_secure_boot_digest(bootkey, &key_block);
if (err != ESP_OK) {
printf("Error provisioning secure boot digest %u [%d]\n", bootkey, err);
return err;
}
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
err = esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
if (err != ESP_OK) {
printf("Error enabling secure boot [%d]\n", err);
return err;
}
}
if (secure_lock) {
for (uint8_t idx = 0; idx <= 2; idx++) {
if (idx == bootkey) {
continue;
}
err = esp_efuse_set_digest_revoke(idx);
if (err != ESP_OK) {
printf("Error revoking secure boot digest %u [%d]\n", idx, err);
return err;
}
}
err = esp_efuse_set_key_dis_write(key_block);
if (err != ESP_OK) {
printf("Error setting secure boot key block read only [%d]\n", err);
return err;
}
err = esp_efuse_set_keypurpose_dis_write(key_block);
if (err != ESP_OK) {
printf("Error setting secure boot key purpose read only [%d]\n", err);
return err;
}
/* // Not sure if it allows future upgrades if ROM download mode is disabled, so leaving it enabled for now
err = esp_efuse_disable_rom_download_mode();
if (err != ESP_OK) {
printf("Error disabling ROM download mode [%d]\n", err);
return err;
}
*/
err = esp_disable_debug_interfaces();
if (err != ESP_OK) {
printf("Error disabling JTAG interfaces [%d]\n", err);
return err;
}
}
return PICOKEYS_OK;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
esp_err_t ret = 0;
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
if (esp_efuse_key_block_unused(OTP_KEY_1)) {
uint8_t mkek[32] = {0};
random_fill_buffer(mkek, sizeof(mkek));
ret = esp_efuse_write_key(OTP_KEY_1, ESP_EFUSE_KEY_PURPOSE_USER, mkek, sizeof(mkek));
if (ret != 0) {
printf("Error writing OTP key 1 [%d]\n", ret);
}
mbedtls_platform_zeroize(mkek, sizeof(mkek));
write_otp[0] = OTP_KEY_1;
}
ret = read_key_from_efuse(OTP_KEY_1, _otp_key_1, sizeof(_otp_key_1));
if (ret != ESP_OK) {
printf("Error reading OTP key 1 [%d]\n", ret);
}
*otp_key_1_out = _otp_key_1;
if (esp_efuse_key_block_unused(OTP_KEY_2)) {
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_fill_iterator, NULL);
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
mbedtls_ecdsa_free(&ecdsa);
}
ret = esp_efuse_write_key(OTP_KEY_2, ESP_EFUSE_KEY_PURPOSE_USER, pkey, olen);
if (ret != 0) {
printf("Error writing OTP key 2 [%d]\n", ret);
}
mbedtls_platform_zeroize(pkey, sizeof(pkey));
write_otp[1] = OTP_KEY_2;
}
ret = read_key_from_efuse(OTP_KEY_2, _otp_key_2, sizeof(_otp_key_2));
if (ret != ESP_OK) {
printf("Error reading OTP key 2 [%d]\n", ret);
}
*otp_key_2_out = _otp_key_2;
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); i++) {
if (write_otp[i] != 0xFFFF) {
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);
}
}
}
}

623
src/otp/otp_linux.c Normal file
View File

@@ -0,0 +1,623 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <termios.h>
#include "picokeys.h"
#include "otp_platform.h"
#include "random.h"
#include "mbedtls/bignum.h"
#include "mbedtls/ecp.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/sha256.h"
#include <tss2/tss2_esys.h>
#include <tss2/tss2_tctildr.h>
#define OTP_LINUX_DEFAULT_TPM_HANDLE "0x81010001"
#define OTP_LINUX_DEFAULT_PEER_KEY_FILE ".config/pico-novus/otp_peer_p256.bin"
static int read_tpm_pin_prompt(const char *prompt, char *pin_out, size_t pin_out_size) {
const char *pin_env = getenv("PICO_NOVUS_TPM_PIN");
if (!pin_out || pin_out_size < 2) {
return -1;
}
if (pin_env && pin_env[0] != '\0') {
size_t n = strlen(pin_env);
if (n >= pin_out_size) {
return -1;
}
memcpy(pin_out, pin_env, n + 1);
return 0;
}
if (!isatty(STDIN_FILENO)) {
fprintf(stderr, "[otp-linux] No TTY for PIN prompt; set PICO_NOVUS_TPM_PIN\n");
return -1;
}
struct termios oldt;
struct termios newt;
if (tcgetattr(STDIN_FILENO, &oldt) != 0) {
return -1;
}
newt = oldt;
newt.c_lflag &= ~(ECHO);
fprintf(stderr, "%s", prompt ? prompt : "Enter TPM key PIN: ");
fflush(stderr);
if (tcsetattr(STDIN_FILENO, TCSANOW, &newt) != 0) {
return -1;
}
if (!fgets(pin_out, (int)pin_out_size, stdin)) {
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fprintf(stderr, "\n");
return -1;
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fprintf(stderr, "\n");
{
size_t n = strlen(pin_out);
if (n > 0 && pin_out[n - 1] == '\n') {
pin_out[n - 1] = '\0';
}
}
return (pin_out[0] != '\0') ? 0 : -1;
}
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
int rc = -1;
uint8_t digest[32];
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
mbedtls_ecp_group grp;
mbedtls_mpi x, n_minus_1;
if (!secret || secret_len == 0 || !out_key32) {
return -1;
}
mbedtls_sha256_context sha;
mbedtls_sha256_init(&sha);
mbedtls_sha256_starts(&sha, 0);
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
mbedtls_sha256_update(&sha, secret, secret_len);
mbedtls_sha256_finish(&sha, digest);
mbedtls_sha256_free(&sha);
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&x);
mbedtls_mpi_init(&n_minus_1);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
goto cleanup;
}
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
goto cleanup;
}
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
goto cleanup;
}
rc = 0;
cleanup:
mbedtls_mpi_free(&n_minus_1);
mbedtls_mpi_free(&x);
mbedtls_ecp_group_free(&grp);
return rc;
}
static int ensure_parent_dir(const char *path) {
char tmp[512];
char *slash;
if (!path || strlen(path) >= sizeof(tmp)) {
return -1;
}
strncpy(tmp, path, sizeof(tmp) - 1);
tmp[sizeof(tmp) - 1] = '\0';
slash = strrchr(tmp, '/');
if (!slash) {
return 0;
}
*slash = '\0';
if (tmp[0] == '\0') {
return 0;
}
if (mkdir(tmp, 0700) == 0 || errno == EEXIST) {
return 0;
}
return -1;
}
static int random_fill_buffer_rng(void *ctx, unsigned char *output, size_t output_len) {
(void)ctx;
random_fill_buffer(output, output_len);
return 0;
}
static int is_valid_p256_privkey(const uint8_t priv32[32]) {
int ok = 0;
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&d);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_read_binary(&d, priv32, 32) != 0) {
goto cleanup;
}
if (mbedtls_mpi_cmp_int(&d, 1) < 0 || mbedtls_mpi_cmp_mpi(&d, &grp.N) >= 0) {
goto cleanup;
}
ok = 1;
cleanup:
mbedtls_mpi_free(&d);
mbedtls_ecp_group_free(&grp);
return ok;
}
static int generate_valid_p256_privkey(uint8_t out_priv32[32]) {
int rc = -1;
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&d);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
goto cleanup;
}
if (mbedtls_ecp_gen_privkey(&grp, &d, random_fill_buffer_rng, NULL) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&d, out_priv32, 32) != 0) {
goto cleanup;
}
rc = 0;
cleanup:
mbedtls_mpi_free(&d);
mbedtls_ecp_group_free(&grp);
return rc;
}
static int load_or_create_peer_p256_privkey(uint8_t out_priv32[32]) {
int rc = -1;
FILE *fp = NULL;
const char *custom = getenv("PICO_NOVUS_PEER_KEY_FILE");
const char *home = getenv("HOME");
char path[512];
if (custom && custom[0] != '\0') {
strncpy(path, custom, sizeof(path) - 1);
path[sizeof(path) - 1] = '\0';
}
else if (home && home[0] != '\0') {
if (snprintf(path, sizeof(path), "%s/%s", home, OTP_LINUX_DEFAULT_PEER_KEY_FILE) >= (int)sizeof(path)) {
return -1;
}
}
else {
if (snprintf(path, sizeof(path), "%s", OTP_LINUX_DEFAULT_PEER_KEY_FILE) >= (int)sizeof(path)) {
return -1;
}
}
fp = fopen(path, "rb");
if (fp) {
size_t n = fread(out_priv32, 1, 32, fp);
fclose(fp);
if (n == 32 && is_valid_p256_privkey(out_priv32)) {
return 0;
}
}
if (generate_valid_p256_privkey(out_priv32) != 0) {
return -1;
}
if (ensure_parent_dir(path) != 0) {
return -1;
}
fp = fopen(path, "wb");
if (!fp) {
return -1;
}
if (fwrite(out_priv32, 1, 32, fp) != 32) {
fclose(fp);
return -1;
}
fclose(fp);
chmod(path, 0600);
rc = 0;
return rc;
}
static int peer_priv_to_pub_point(const uint8_t priv32[32], TPM2B_ECC_POINT *pub_out) {
int rc = -1;
mbedtls_ecp_group grp;
mbedtls_mpi d;
mbedtls_ecp_point q;
uint8_t x[32] = {0};
uint8_t y[32] = {0};
if (!priv32 || !pub_out) {
return -1;
}
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&d);
mbedtls_ecp_point_init(&q);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_read_binary(&d, priv32, 32) != 0) {
goto cleanup;
}
if (!is_valid_p256_privkey(priv32)) {
goto cleanup;
}
if (mbedtls_ecp_mul(&grp, &q, &d, &grp.G, random_fill_buffer_rng, NULL) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&q.X, x, sizeof(x)) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&q.Y, y, sizeof(y)) != 0) {
goto cleanup;
}
memset(pub_out, 0, sizeof(*pub_out));
pub_out->point.x.size = sizeof(x);
memcpy(pub_out->point.x.buffer, x, sizeof(x));
pub_out->point.y.size = sizeof(y);
memcpy(pub_out->point.y.buffer, y, sizeof(y));
rc = 0;
cleanup:
mbedtls_ecp_point_free(&q);
mbedtls_mpi_free(&d);
mbedtls_ecp_group_free(&grp);
return rc;
}
static int load_or_create_tpm_p256_key(ESYS_CONTEXT *esys, TPM2_HANDLE handle, const char *pin, ESYS_TR *key_out, int *created_out) {
TSS2_RC rc;
ESYS_TR key = ESYS_TR_NONE;
ESYS_TR transient = ESYS_TR_NONE;
ESYS_TR persisted = ESYS_TR_NONE;
TPM2B_PUBLIC in_public = {0};
TPM2B_SENSITIVE_CREATE in_sensitive = {0};
TPM2B_DATA outside_info = {0};
TPML_PCR_SELECTION creation_pcr = {0};
TPM2B_PUBLIC *out_public = NULL;
TPM2B_CREATION_DATA *creation_data = NULL;
TPM2B_DIGEST *creation_hash = NULL;
TPMT_TK_CREATION *creation_ticket = NULL;
TPMS_CAPABILITY_DATA *cap_data = NULL;
TPMI_YES_NO more_data = TPM2_NO;
TPM2B_AUTH auth = {0};
if (!esys || !key_out) {
return -1;
}
*key_out = ESYS_TR_NONE;
if (created_out) {
*created_out = 0;
}
if (pin && pin[0] != '\0') {
size_t pin_len = strlen(pin);
if (pin_len > sizeof(auth.buffer)) {
return -1;
}
auth.size = (UINT16)pin_len;
memcpy(auth.buffer, pin, pin_len);
}
rc = Esys_GetCapability(esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_HANDLES, handle, 1, &more_data, &cap_data);
if (rc != TSS2_RC_SUCCESS) {
fprintf(stderr, "[otp-linux] Esys_GetCapability failed while checking key handle: 0x%x\n", rc);
goto cleanup;
}
if (cap_data && cap_data->data.handles.count > 0 && cap_data->data.handles.handle[0] == handle) {
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &key);
if (rc != TSS2_RC_SUCCESS) {
fprintf(stderr, "[otp-linux] Esys_TR_FromTPMPublic failed for existing key: 0x%x\n", rc);
goto cleanup;
}
if (auth.size > 0) {
rc = Esys_TR_SetAuth(esys, key, &auth);
if (rc != TSS2_RC_SUCCESS) {
Esys_TR_Close(esys, &key);
key = ESYS_TR_NONE;
goto cleanup;
}
}
*key_out = key;
key = ESYS_TR_NONE;
goto cleanup;
}
in_public.publicArea.type = TPM2_ALG_ECC;
in_public.publicArea.nameAlg = TPM2_ALG_SHA256;
in_public.publicArea.objectAttributes = TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN;
in_public.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG_NULL;
in_public.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG_NULL;
in_public.publicArea.parameters.eccDetail.curveID = TPM2_ECC_NIST_P256;
in_public.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
if (auth.size > 0) {
in_sensitive.sensitive.userAuth = auth;
}
rc = Esys_CreatePrimary(esys, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, &in_public, &outside_info, &creation_pcr, &transient, &out_public, &creation_data, &creation_hash, &creation_ticket);
if (rc != TSS2_RC_SUCCESS || transient == ESYS_TR_NONE) {
fprintf(stderr, "[otp-linux] Esys_CreatePrimary failed while provisioning TPM key: 0x%x\n", rc);
goto cleanup;
}
rc = Esys_EvictControl(esys, ESYS_TR_RH_OWNER, transient, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, handle, &persisted);
if (rc != TSS2_RC_SUCCESS) {
/* If another process persisted it first, try to load the handle again. */
ESYS_TR retry = ESYS_TR_NONE;
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &retry);
if (rc == TSS2_RC_SUCCESS) {
*key_out = retry;
goto cleanup;
}
fprintf(stderr, "[otp-linux] Esys_EvictControl failed while provisioning TPM key: 0x%x\n", rc);
goto cleanup;
}
if (persisted != ESYS_TR_NONE) {
Esys_TR_Close(esys, &persisted);
persisted = ESYS_TR_NONE;
}
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, key_out);
if (rc != TSS2_RC_SUCCESS) {
fprintf(stderr, "[otp-linux] Persisted key created but reload failed: 0x%x\n", rc);
*key_out = ESYS_TR_NONE;
goto cleanup;
}
if (auth.size > 0) {
rc = Esys_TR_SetAuth(esys, *key_out, &auth);
if (rc != TSS2_RC_SUCCESS) {
Esys_TR_Close(esys, key_out);
*key_out = ESYS_TR_NONE;
goto cleanup;
}
}
if (created_out) {
*created_out = 1;
}
cleanup:
if (cap_data) {
Esys_Free(cap_data);
}
if (creation_ticket) {
Esys_Free(creation_ticket);
}
if (creation_hash) {
Esys_Free(creation_hash);
}
if (creation_data) {
Esys_Free(creation_data);
}
if (out_public) {
Esys_Free(out_public);
}
if (persisted != ESYS_TR_NONE) {
Esys_TR_Close(esys, &persisted);
}
if (transient != ESYS_TR_NONE) {
Esys_TR_Close(esys, &transient);
}
return (*key_out != ESYS_TR_NONE) ? 0 : -1;
}
static int linux_tpm_vault_load_or_create_key(uint8_t out_key32[32]) {
TSS2_TCTI_CONTEXT *tcti = NULL;
ESYS_CONTEXT *esys = NULL;
ESYS_TR tpm_key = ESYS_TR_NONE;
TPM2B_ECC_POINT peer_pub = {0};
TPM2B_ECC_POINT *z_point = NULL;
TPM2B_PUBLIC *tpm_pub = NULL;
uint8_t peer_priv[32] = {0};
uint8_t ecdh_secret[132] = {0};
size_t ecdh_secret_len = 0;
char pin[128] = {0};
int created_now = 0;
int rc_out = -1;
TSS2_RC rc;
const char *tcti_name = getenv("PICO_NOVUS_TCTI");
const char *handle_hex = getenv("PICO_NOVUS_TPM_HANDLE");
if (!tcti_name || tcti_name[0] == '\0') {
tcti_name = getenv("TPM2TOOLS_TCTI");
}
if (!handle_hex || handle_hex[0] == '\0') {
handle_hex = OTP_LINUX_DEFAULT_TPM_HANDLE;
}
if (tcti_name && tcti_name[0] != '\0') {
rc = Tss2_TctiLdr_Initialize(tcti_name, &tcti);
}
else {
rc = Tss2_TctiLdr_Initialize(NULL, &tcti);
if (rc != TSS2_RC_SUCCESS) {
rc = Tss2_TctiLdr_Initialize("swtpm:host=127.0.0.1,port=2321", &tcti);
if (rc != TSS2_RC_SUCCESS) {
rc = Tss2_TctiLdr_Initialize("mssim:host=127.0.0.1,port=2321", &tcti);
}
}
}
if (rc != TSS2_RC_SUCCESS) {
fprintf(stderr, "[otp-linux] Tss2_TctiLdr_Initialize failed: 0x%x\n", rc);
goto cleanup;
}
rc = Esys_Initialize(&esys, tcti, NULL);
if (rc != TSS2_RC_SUCCESS) {
fprintf(stderr, "[otp-linux] Esys_Initialize failed: 0x%x\n", rc);
goto cleanup;
}
unsigned long handle_num = strtoul(handle_hex, NULL, 0);
if (read_tpm_pin_prompt("Enter or set TPM key PIN: ", pin, sizeof(pin)) != 0) {
fprintf(stderr, "[otp-linux] PIN is required to unlock/provision TPM key\n");
goto cleanup;
}
if (load_or_create_tpm_p256_key(esys, (TPM2_HANDLE)handle_num, pin, &tpm_key, &created_now) != 0) {
fprintf(stderr, "[otp-linux] Cannot load/create persistent TPM key at handle: %s\n", handle_hex);
goto cleanup;
}
if (created_now && !getenv("PICO_NOVUS_TPM_PIN") && isatty(STDIN_FILENO)) {
char confirm[128] = {0};
if (read_tpm_pin_prompt("Confirm TPM key PIN: ", confirm, sizeof(confirm)) != 0 || strcmp(pin, confirm) != 0) {
fprintf(stderr, "[otp-linux] PIN confirmation mismatch\n");
memset(confirm, 0, sizeof(confirm));
goto cleanup;
}
memset(confirm, 0, sizeof(confirm));
}
rc = Esys_ReadPublic(esys, tpm_key, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &tpm_pub, NULL, NULL);
if (rc != TSS2_RC_SUCCESS || !tpm_pub) {
fprintf(stderr, "[otp-linux] Esys_ReadPublic failed: 0x%x\n", rc);
goto cleanup;
}
if (tpm_pub->publicArea.type != TPM2_ALG_ECC || tpm_pub->publicArea.parameters.eccDetail.curveID != TPM2_ECC_NIST_P256) {
fprintf(stderr, "[otp-linux] TPM key must be ECC P-256\n");
goto cleanup;
}
if (load_or_create_peer_p256_privkey(peer_priv) != 0) {
fprintf(stderr, "[otp-linux] Cannot load/create software peer key\n");
goto cleanup;
}
if (peer_priv_to_pub_point(peer_priv, &peer_pub) != 0) {
fprintf(stderr, "[otp-linux] Cannot derive software peer public key\n");
goto cleanup;
}
rc = Esys_ECDH_ZGen(esys, tpm_key, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &peer_pub, &z_point);
if (rc != TSS2_RC_SUCCESS || !z_point) {
if (rc == TPM2_RC_AUTH_FAIL || rc == TPM2_RC_BAD_AUTH) {
fprintf(stderr, "[otp-linux] TPM key auth failed (wrong PIN?)\n");
}
fprintf(stderr, "[otp-linux] Esys_ECDH_ZGen failed: 0x%x\n", rc);
goto cleanup;
}
if (z_point->point.x.size > 66 || z_point->point.y.size > 66) {
fprintf(stderr, "[otp-linux] Unexpected ECDH point size\n");
goto cleanup;
}
memcpy(ecdh_secret + ecdh_secret_len, z_point->point.x.buffer, z_point->point.x.size);
ecdh_secret_len += z_point->point.x.size;
memcpy(ecdh_secret + ecdh_secret_len, z_point->point.y.buffer, z_point->point.y.size);
ecdh_secret_len += z_point->point.y.size;
if (derive_secp256k1_privkey_from_secret(ecdh_secret, ecdh_secret_len, out_key32) != 0) {
fprintf(stderr, "[otp-linux] Failed deriving secp256k1 key\n");
goto cleanup;
}
rc_out = 0;
cleanup:
memset(pin, 0, sizeof(pin));
if (z_point) {
Esys_Free(z_point);
}
if (tpm_pub) {
Esys_Free(tpm_pub);
}
if (esys) {
if (tpm_key != ESYS_TR_NONE) {
Esys_TR_Close(esys, &tpm_key);
}
Esys_Finalize(&esys);
}
if (tcti) {
Tss2_TctiLdr_Finalize(&tcti);
}
return rc_out;
}
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
(void)bootkey;
(void)secure_lock;
return PICOKEYS_OK;
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
(void)bootkey;
return false;
}
bool otp_platform_is_secure_boot_locked(void) {
return false;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
static uint8_t _otp1[32] = {0};
static uint8_t _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
if (linux_tpm_vault_load_or_create_key(_otp2) != 0) {
printf("[otp-linux] Warning: TPM path unavailable, using emulated otp_key_2\n");
}
*otp_key_1_out = _otp1;
*otp_key_2_out = _otp2;
}

273
src/otp/otp_macos.c Normal file
View File

@@ -0,0 +1,273 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "otp_platform.h"
#if defined(MACOS_APP) && MACOS_APP
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <stdio.h>
#include <string.h>
#include "mbedtls/bignum.h"
#include "mbedtls/ecp.h"
#include "mbedtls/sha256.h"
#define CF_SAFE_RELEASE(x) do { if ((x) != NULL) CFRelease(x); } while (0)
#define SE_KEY_TAG "com.picokeys.novus.se.key"
#define LOCAL_KEY_TAG "com.picokeys.novus.local.ecdh.key"
static int sec_err(const char *ctx, OSStatus st) {
fprintf(stderr, "[macos-se] %s failed: OSStatus=%d\n", ctx, (int)st);
return -1;
}
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
int rc = -1;
uint8_t digest[32];
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
mbedtls_ecp_group grp;
mbedtls_mpi x, n_minus_1;
if (!secret || secret_len == 0 || !out_key32) {
return -1;
}
mbedtls_sha256_context sha;
mbedtls_sha256_init(&sha);
mbedtls_sha256_starts(&sha, 0);
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
mbedtls_sha256_update(&sha, secret, secret_len);
mbedtls_sha256_finish(&sha, digest);
mbedtls_sha256_free(&sha);
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&x);
mbedtls_mpi_init(&n_minus_1);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
goto cleanup;
}
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
goto cleanup;
}
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
goto cleanup;
}
rc = 0;
cleanup:
mbedtls_mpi_free(&n_minus_1);
mbedtls_mpi_free(&x);
mbedtls_ecp_group_free(&grp);
return rc;
}
static int load_or_create_p256_key(const char *tag_str, bool in_secure_enclave, SecKeyRef *out_private_key) {
SecKeyRef private_key = NULL;
CFDataRef tag = NULL;
CFDictionaryRef find_query = NULL;
CFDictionaryRef priv_attrs = NULL;
CFNumberRef key_size_num = NULL;
CFDictionaryRef attrs = NULL;
CFErrorRef err = NULL;
OSStatus st;
int rc = -1;
if (!tag_str || !out_private_key) {
return -1;
}
*out_private_key = NULL;
tag = CFDataCreate(NULL, (const UInt8 *)tag_str, (CFIndex)strlen(tag_str));
if (!tag) {
fprintf(stderr, "[macos-se] CFDataCreate(tag) failed\n");
goto cleanup;
}
const void *find_keys[] = { kSecClass, kSecAttrApplicationTag, kSecAttrKeyType, kSecReturnRef };
const void *find_vals[] = { kSecClassKey, tag, kSecAttrKeyTypeECSECPrimeRandom, kCFBooleanTrue };
find_query = CFDictionaryCreate(NULL, find_keys, find_vals, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (!find_query) {
fprintf(stderr, "[macos-se] CFDictionaryCreate(find_query) failed\n");
goto cleanup;
}
st = SecItemCopyMatching(find_query, (CFTypeRef *)&private_key);
if (st == errSecItemNotFound) {
const void *priv_keys[] = { kSecAttrIsPermanent, kSecAttrApplicationTag };
const void *priv_vals[] = { kCFBooleanTrue, tag };
priv_attrs = CFDictionaryCreate(NULL, priv_keys, priv_vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (!priv_attrs) {
fprintf(stderr, "[macos-se] CFDictionaryCreate(priv_attrs) failed\n");
goto cleanup;
}
int key_size = 256;
key_size_num = CFNumberCreate(NULL, kCFNumberIntType, &key_size);
if (!key_size_num) {
fprintf(stderr, "[macos-se] CFNumberCreate(key_size) failed\n");
goto cleanup;
}
if (in_secure_enclave) {
const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrTokenID, kSecPrivateKeyAttrs };
const void *vals[] = { kSecAttrKeyTypeECSECPrimeRandom, key_size_num, kSecAttrTokenIDSecureEnclave, priv_attrs };
attrs = CFDictionaryCreate(NULL, keys, vals, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
} else {
const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits, kSecPrivateKeyAttrs };
const void *vals[] = { kSecAttrKeyTypeECSECPrimeRandom, key_size_num, priv_attrs };
attrs = CFDictionaryCreate(NULL, keys, vals, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
if (!attrs) {
fprintf(stderr, "[macos-se] CFDictionaryCreate(attrs) failed\n");
goto cleanup;
}
private_key = SecKeyCreateRandomKey(attrs, &err);
if (!private_key) {
fprintf(stderr, "[macos-se] SecKeyCreateRandomKey failed\n");
if (err) {
CFShow(err);
}
goto cleanup;
}
printf("[macos-se] Created key '%s'%s\n", tag_str, in_secure_enclave ? " in Secure Enclave" : "");
} else if (st != errSecSuccess) {
sec_err("SecItemCopyMatching", st);
goto cleanup;
} else {
printf("[macos-se] Using existing key '%s'\n", tag_str);
}
*out_private_key = private_key;
private_key = NULL;
rc = 0;
cleanup:
if (err) {
CFRelease(err);
}
CF_SAFE_RELEASE(attrs);
CF_SAFE_RELEASE(key_size_num);
CF_SAFE_RELEASE(priv_attrs);
CF_SAFE_RELEASE(find_query);
CF_SAFE_RELEASE(tag);
CF_SAFE_RELEASE(private_key);
return rc;
}
static int macos_se_vault_load_or_create_key(uint8_t out_key32[32]) {
int rc = -1;
SecKeyRef se_private_key = NULL;
SecKeyRef local_private_key = NULL;
SecKeyRef local_public_key = NULL;
CFDataRef shared_secret = NULL;
CFDictionaryRef ecdh_params = NULL;
CFErrorRef err = NULL;
if (load_or_create_p256_key(SE_KEY_TAG, true, &se_private_key) != 0) {
goto cleanup;
}
if (load_or_create_p256_key(LOCAL_KEY_TAG, false, &local_private_key) != 0) {
goto cleanup;
}
local_public_key = SecKeyCopyPublicKey(local_private_key);
if (!local_public_key) {
fprintf(stderr, "[macos-se] SecKeyCopyPublicKey(local_private_key) failed\n");
goto cleanup;
}
ecdh_params = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (!ecdh_params) {
fprintf(stderr, "[macos-se] CFDictionaryCreate(ecdh_params) failed\n");
goto cleanup;
}
shared_secret = SecKeyCopyKeyExchangeResult(se_private_key, kSecKeyAlgorithmECDHKeyExchangeStandard, local_public_key, ecdh_params, &err);
if (!shared_secret) {
fprintf(stderr, "[macos-se] SecKeyCopyKeyExchangeResult failed\n");
if (err) {
CFShow(err);
}
goto cleanup;
}
if (derive_secp256k1_privkey_from_secret(CFDataGetBytePtr(shared_secret), (size_t)CFDataGetLength(shared_secret), out_key32) != 0) {
fprintf(stderr, "[macos-se] failed deriving secp256k1 private key from ECDH secret\n");
goto cleanup;
}
rc = 0;
cleanup:
if (err) {
CFRelease(err);
}
CF_SAFE_RELEASE(ecdh_params);
CF_SAFE_RELEASE(shared_secret);
CF_SAFE_RELEASE(local_public_key);
CF_SAFE_RELEASE(local_private_key);
CF_SAFE_RELEASE(se_private_key);
return rc;
}
#endif
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
(void)bootkey;
(void)secure_lock;
return PICOKEYS_OK;
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
(void)bootkey;
return true;
}
bool otp_platform_is_secure_boot_locked(void) {
return false;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
static uint8_t _otp1[32] = {0};
static uint8_t _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
#if defined(MACOS_APP) && MACOS_APP
if (macos_se_vault_load_or_create_key(_otp2) != 0) {
printf("Warning: failed to load MACOS_APP Secure Enclave key; using dummy otp_key_2\n");
}
#endif
*otp_key_1_out = _otp1;
*otp_key_2_out = _otp2;
}

29
src/otp/otp_platform.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _OTP_PLATFORM_H_
#define _OTP_PLATFORM_H_
#include <stdint.h>
#include <stdbool.h>
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock);
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey);
bool otp_platform_is_secure_boot_locked(void);
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out);
#endif

47
src/otp/otp_rp2040.c Normal file
View File

@@ -0,0 +1,47 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "picokeys.h"
#include "otp_platform.h"
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
(void)bootkey;
(void)secure_lock;
return PICOKEYS_WRONG_DATA;
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
(void)bootkey;
return false;
}
bool otp_platform_is_secure_boot_locked(void) {
return false;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
static uint8_t _otp1[32] = {0};
static uint8_t _otp2[32] = {0};
memset(_otp1, 0xDF, sizeof(_otp1));
memset(_otp2, 0x93, sizeof(_otp2));
*otp_key_1_out = _otp1;
*otp_key_2_out = _otp2;
}

294
src/otp/otp_rp2350.c Normal file
View File

@@ -0,0 +1,294 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdalign.h>
#include "picokeys.h"
#include "otp.h"
#include "otp_platform.h"
#include "pico/bootrom.h"
#include "hardware/structs/otp.h"
#include "hardware/regs/otp_data.h"
#include "random.h"
#include "mbedtls/ecdsa.h"
#define OTP_OLD_MKEK_ROW 0xEF0
#define OTP_OLD_DEVK_ROW 0xED0
#define OTP_MKEK_ROW 0xE90
#define OTP_DEVK_ROW 0xE80
#define OTP_KEY_1 OTP_MKEK_ROW
#define OTP_KEY_2 OTP_DEVK_ROW
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, const 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((uint8_t *)data, len, cmd);
if (ret) {
printf("OTP Write failed with error: %ld\n", ret);
}
return ret;
}
static int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, true);
}
static int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, false);
}
static const uint8_t* otp_buffer(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + (row*2)));
return (const uint8_t *)p;
}
static const uint8_t* otp_buffer_raw(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_RAW_BASE + (row*4)));
return (const uint8_t *)p;
}
static bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
return is_empty_buffer(otp_buffer_raw(row), len * 2);
}
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)) {
alignas(4) 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;
}
static void otp_invalidate_key(uint16_t row, uint16_t len) {
if (!is_empty_otp_buffer(row, len)) {
uint8_t *inval = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
if (inval) {
memset(inval, 0xFF, len * 2);
otp_write_data_raw(row, inval, len * 2);
mbedtls_platform_zeroize(inval, len * 2);
free(inval);
}
}
}
static int otp_chaff(uint16_t row, uint16_t len) {
const uint8_t *raw = otp_buffer_raw(row);
uint8_t *chaff = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
if (chaff) {
memcpy(chaff, raw, len * 2);
for (int i = 0; i < len * 2; i++) {
chaff[i] ^= 0xFF;
}
int ret = otp_write_data_raw(row + 32, chaff, len * 2);
mbedtls_platform_zeroize(chaff, len * 2);
free(chaff);
return ret;
}
return BOOTROM_ERROR_INVALID_STATE;
}
static int otp_migrate_key(uint16_t new_row, uint16_t old_row, uint16_t len) {
if (is_empty_otp_buffer(new_row, len) && !is_empty_otp_buffer(old_row, len)) {
const uint8_t *key = otp_buffer(old_row);
uint8_t *new_key = (uint8_t *)calloc(len, sizeof(uint8_t));
if (new_key) {
memcpy(new_key, key, len);
int ret = otp_write_data(new_row, new_key, len);
if (ret == BOOTROM_OK) {
otp_chaff(new_row, len);
otp_invalidate_key(old_row, 32);
}
mbedtls_platform_zeroize(new_key, len);
free(new_key);
return ret;
}
}
return BOOTROM_ERROR_INVALID_STATE;
}
static void otp_migrate_chaff(void) {
otp_migrate_key(OTP_MKEK_ROW, OTP_OLD_MKEK_ROW, 32);
otp_migrate_key(OTP_DEVK_ROW, OTP_OLD_DEVK_ROW, 32);
otp_lock_page(OTP_MKEK_ROW >> 6);
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
const uint8_t *crit1 = otp_buffer(OTP_DATA_CRIT1_ROW);
if ((crit1[0] & (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB)) == 0) {
return false;
}
alignas(2) uint8_t BOOTKEY[32] = {
0xE1, 0xD1, 0x6B, 0xA7, 0x64, 0xAB, 0xD7, 0x12,
0xD4, 0xEF, 0x6E, 0x3E, 0xDD, 0x74, 0x4E, 0xD5,
0x63, 0x8C, 0x26, 0x0B, 0x77, 0x1C, 0xF9, 0x81,
0x51, 0x11, 0x0B, 0xAF, 0xAC, 0x9B, 0xC8, 0x71
};
uint8_t bootkey_idx = 0;
for (; bootkey_idx < 6; bootkey_idx++) {
const uint8_t *bootkey_row = otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10 * bootkey_idx);
if (memcmp(bootkey_row, BOOTKEY, sizeof(BOOTKEY)) == 0) {
break;
}
}
if (bootkey_idx == 6) {
return false;
}
const uint8_t *boot_flags1 = otp_buffer(OTP_DATA_BOOT_FLAGS1_ROW);
if ((boot_flags1[0] & (1 << (bootkey_idx + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB))) == 0) {
return false;
}
if (bootkey) {
*bootkey = bootkey_idx;
}
return true;
}
bool otp_platform_is_secure_boot_locked(void) {
uint8_t bootkey_idx = 0xFF;
if (otp_platform_is_secure_boot_enabled(&bootkey_idx) == false) {
return false;
}
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
if ((boot_flags1[1] & ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) !=
((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) {
return false;
}
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
if ((crit1[0] & (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB)) == 0
|| (crit1[0] & (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB)) == 0
|| ((crit1[0] & (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB)) != (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB))) {
return false;
}
return bootkey_idx != 0xFF;
}
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
int ret = 0;
alignas(2) 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)) {
PICOKEYS_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
}
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
alignas(4) 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)));
}
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R2_ROW, flagsb1, sizeof(flagsb1)));
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
alignas(4) 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);
}
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R2_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R3_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R4_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R5_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R6_ROW, flagsc1, sizeof(flagsc1)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R7_ROW, flagsc1, sizeof(flagsc1)));
if (secure_lock) {
const 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);
alignas(4) uint8_t flagsp1[] = { page1v, page1v, page1v, 0x00 };
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
const 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);
alignas(4) uint8_t flagsp2[] = { page2v, page2v, page2v, 0x00 };
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
}
goto err;
err:
if (ret != PICOKEYS_OK) {
return ret;
}
return PICOKEYS_OK;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
otp_migrate_chaff();
int ret = 0;
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
if (is_empty_otp_buffer(OTP_KEY_1, 32)) {
uint8_t mkek[32] = {0};
random_fill_buffer(mkek, sizeof(mkek));
ret = otp_write_data(OTP_KEY_1, mkek, sizeof(mkek));
if (ret != 0) {
printf("Error writing OTP key 1 [%d]\n", ret);
}
otp_chaff(OTP_KEY_1, 32);
mbedtls_platform_zeroize(mkek, sizeof(mkek));
write_otp[0] = OTP_KEY_1;
}
*otp_key_1_out = otp_buffer(OTP_KEY_1);
if (is_empty_otp_buffer(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_fill_iterator, NULL);
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
mbedtls_ecdsa_free(&ecdsa);
}
ret = otp_write_data(OTP_KEY_2, pkey, olen);
if (ret != 0) {
printf("Error writing OTP key 2 [%d]\n", ret);
}
mbedtls_platform_zeroize(pkey, sizeof(pkey));
otp_chaff(OTP_KEY_2, 32);
write_otp[1] = OTP_KEY_2;
}
*otp_key_2_out = otp_buffer(OTP_KEY_2);
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); i++) {
if (write_otp[i] != 0xFFFF) {
otp_lock_page(write_otp[i] >> 6);
}
}
}

577
src/otp/otp_windows.c Normal file
View File

@@ -0,0 +1,577 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "otp_platform.h"
#if defined(_MSC_VER)
#include <windows.h>
#include <ncrypt.h>
#include <bcrypt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include "mbedtls/bignum.h"
#include "mbedtls/ecp.h"
#include "mbedtls/sha256.h"
#ifndef BCRYPT_KDF_RAW_SECRET
#define BCRYPT_KDF_RAW_SECRET L"RAW_SECRET"
#endif
#define TPM_KEY_NAME L"pico_novus_tpm_ecdh"
#define SW_PEER_NAME L"pico_novus_sw_peer_ecdh"
#define SW_LOCAL_NAME L"pico_novus_sw_local_ecdh"
#ifndef OTP_WINDOWS_TPM_STRICT
#define OTP_WINDOWS_TPM_STRICT 1
#endif
static int win_err(const char *ctx, SECURITY_STATUS st) {
fprintf(stderr, "[win-tpm] %s failed: 0x%08lx\n", ctx, (unsigned long)st);
return -1;
}
static const char *ncrypt_status_hint(SECURITY_STATUS st) {
switch (st) {
case NTE_DEVICE_NOT_READY:
return "TPM is not ready (disabled, uninitialized, or inaccessible)";
case NTE_NOT_SUPPORTED:
return "operation/algorithm not supported by this provider";
case NTE_BAD_KEYSET:
return "keyset not found";
case NTE_PERM:
return "permission denied";
default:
return "unmapped status";
}
}
static int read_tpm_pin_prompt(const char *prompt, char *pin_out, size_t pin_out_size) {
const char *pin_env = getenv("PICO_NOVUS_TPM_PIN");
if (!pin_out || pin_out_size < 2) {
return -1;
}
if (pin_env && pin_env[0] != '\0') {
size_t n = strlen(pin_env);
if (n >= pin_out_size) {
return -1;
}
memcpy(pin_out, pin_env, n + 1);
return 0;
}
if (!_isatty(_fileno(stdin))) {
fprintf(stderr, "[win-tpm] No TTY for PIN prompt; set PICO_NOVUS_TPM_PIN\n");
return -1;
}
HANDLE h_in = GetStdHandle(STD_INPUT_HANDLE);
DWORD old_mode = 0;
DWORD new_mode = 0;
if (h_in == INVALID_HANDLE_VALUE || !GetConsoleMode(h_in, &old_mode)) {
return -1;
}
new_mode = old_mode & (~ENABLE_ECHO_INPUT);
fprintf(stderr, "%s", prompt ? prompt : "Enter TPM key PIN: ");
fflush(stderr);
if (!SetConsoleMode(h_in, new_mode)) {
return -1;
}
if (!fgets(pin_out, (int)pin_out_size, stdin)) {
SetConsoleMode(h_in, old_mode);
fprintf(stderr, "\n");
return -1;
}
SetConsoleMode(h_in, old_mode);
fprintf(stderr, "\n");
size_t n = strlen(pin_out);
if (n > 0 && pin_out[n - 1] == '\n') {
pin_out[n - 1] = '\0';
}
if (n > 1 && pin_out[n - 2] == '\r') {
pin_out[n - 2] = '\0';
}
return (pin_out[0] != '\0') ? 0 : -1;
}
static int key_exists_by_name(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name, int *exists_out) {
SECURITY_STATUS st;
NCRYPT_KEY_HANDLE key = 0;
if (!exists_out) {
return -1;
}
*exists_out = 0;
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
if (st == ERROR_SUCCESS) {
*exists_out = 1;
NCryptFreeObject(key);
return 0;
}
if (st == NTE_BAD_KEYSET) {
return 0;
}
return win_err("NCryptOpenKey(exists)", st);
}
static int delete_persisted_key_if_exists(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name) {
SECURITY_STATUS st;
NCRYPT_KEY_HANDLE key = 0;
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
if (st == NTE_BAD_KEYSET) {
return 0;
}
if (st != ERROR_SUCCESS) {
return win_err("NCryptOpenKey(delete)", st);
}
st = NCryptDeleteKey(key, 0);
if (st != ERROR_SUCCESS) {
NCryptFreeObject(key);
return win_err("NCryptDeleteKey", st);
}
printf("[win-tpm] Deleted key '%ls'\n", key_name);
return 0;
}
static int set_tpm_usage_pin(NCRYPT_KEY_HANDLE key, const char *pin, const char *ctx) {
SECURITY_STATUS st;
int wlen;
wchar_t wpin[128];
if (!pin || pin[0] == '\0') {
return 0;
}
memset(wpin, 0, sizeof(wpin));
wlen = MultiByteToWideChar(CP_UTF8, 0, pin, -1, wpin, (int)(sizeof(wpin) / sizeof(wpin[0])));
if (wlen <= 1) {
fprintf(stderr, "[win-tpm] invalid PIN encoding\n");
return -1;
}
/* PCP usage auth is expected as WCHAR string (including terminator). */
st = NCryptSetProperty(
key,
NCRYPT_PCP_USAGEAUTH_PROPERTY,
(PBYTE)wpin,
(DWORD)(wlen * sizeof(wchar_t)),
0
);
SecureZeroMemory(wpin, sizeof(wpin));
if (st != ERROR_SUCCESS) {
if (st == NTE_NOT_SUPPORTED) {
fprintf(stderr, "[win-tpm] TPM provider does not support PIN auth property on this machine\n");
return 1;
}
return win_err(ctx, st);
}
return 0;
}
static int probe_tpm_native_pin_support(NCRYPT_PROV_HANDLE prov) {
SECURITY_STATUS st;
NCRYPT_KEY_HANDLE probe_key = 0;
const wchar_t probe_name[] = L"pico_novus_pin_probe_tmp";
const wchar_t probe_pin[] = L"0";
st = NCryptCreatePersistedKey(prov, &probe_key, NCRYPT_ECDH_P256_ALGORITHM, probe_name, 0, NCRYPT_OVERWRITE_KEY_FLAG);
if (st != ERROR_SUCCESS) {
return -1;
}
st = NCryptSetProperty(
probe_key,
NCRYPT_PCP_USAGEAUTH_PROPERTY,
(PBYTE)probe_pin,
(DWORD)(sizeof(probe_pin)),
0
);
if (st == NTE_NOT_SUPPORTED) {
NCryptDeleteKey(probe_key, 0);
return 0;
}
if (st != ERROR_SUCCESS) {
NCryptDeleteKey(probe_key, 0);
return -1;
}
st = NCryptDeleteKey(probe_key, 0);
if (st != ERROR_SUCCESS) {
return -1;
}
return 1;
}
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
int rc = -1;
uint8_t digest[32];
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
mbedtls_ecp_group grp;
mbedtls_mpi x, n_minus_1;
if (!secret || secret_len == 0 || !out_key32) {
return -1;
}
mbedtls_sha256_context sha;
mbedtls_sha256_init(&sha);
mbedtls_sha256_starts(&sha, 0);
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
mbedtls_sha256_update(&sha, secret, secret_len);
mbedtls_sha256_finish(&sha, digest);
mbedtls_sha256_free(&sha);
mbedtls_ecp_group_init(&grp);
mbedtls_mpi_init(&x);
mbedtls_mpi_init(&n_minus_1);
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
goto cleanup;
}
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
goto cleanup;
}
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
goto cleanup;
}
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
goto cleanup;
}
rc = 0;
cleanup:
mbedtls_mpi_free(&n_minus_1);
mbedtls_mpi_free(&x);
mbedtls_ecp_group_free(&grp);
return rc;
}
static int open_or_create_persisted_ecdh_p256_key(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name, const char *pin, NCRYPT_KEY_HANDLE *out_key, int *created_out) {
SECURITY_STATUS st;
NCRYPT_KEY_HANDLE key = 0;
DWORD pin_len = 0;
int pin_rc = 0;
if (!out_key) {
return -1;
}
*out_key = 0;
if (created_out) {
*created_out = 0;
}
if (pin && pin[0] != '\0') {
pin_len = (DWORD)strlen(pin);
}
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
if (st == NTE_BAD_KEYSET) {
st = NCryptCreatePersistedKey(prov, &key, NCRYPT_ECDH_P256_ALGORITHM, key_name, 0, 0);
if (st != ERROR_SUCCESS) {
return win_err("NCryptCreatePersistedKey", st);
}
if (pin_len > 0) {
pin_rc = set_tpm_usage_pin(key, pin, "NCryptSetProperty(NCRYPT_PCP_USAGEAUTH_PROPERTY/create)");
if (pin_rc == 1) {
fprintf(stderr, "[win-tpm] PIN protection unsupported by TPM provider; continuing without TPM-native PIN\n");
}
else if (pin_rc != 0) {
NCryptFreeObject(key);
return -1;
}
}
st = NCryptFinalizeKey(key, 0);
if (st != ERROR_SUCCESS) {
NCryptFreeObject(key);
return win_err("NCryptFinalizeKey", st);
}
printf("[win-tpm] Created key '%ls'\n", key_name);
if (created_out) {
*created_out = 1;
}
}
else if (st != ERROR_SUCCESS) {
return win_err("NCryptOpenKey", st);
}
else {
printf("[win-tpm] Using existing key '%ls'\n", key_name);
}
if (pin_len > 0) {
pin_rc = set_tpm_usage_pin(key, pin, "NCryptSetProperty(NCRYPT_PCP_USAGEAUTH_PROPERTY/open)");
if (pin_rc == 1) {
fprintf(stderr, "[win-tpm] PIN protection unsupported by TPM provider; continuing without TPM-native PIN\n");
}
else if (pin_rc != 0) {
NCryptFreeObject(key);
return -1;
}
}
*out_key = key;
return 0;
}
static int windows_tpm_vault_load_or_create_key(uint8_t out_key32[32]) {
int rc = -1;
SECURITY_STATUS st;
NCRYPT_PROV_HANDLE tpm_prov = 0;
NCRYPT_PROV_HANDLE sw_prov = 0;
NCRYPT_KEY_HANDLE tpm_key = 0;
NCRYPT_KEY_HANDLE sw_peer_key = 0;
NCRYPT_KEY_HANDLE imported_peer_pub = 0;
NCRYPT_SECRET_HANDLE secret = 0;
PBYTE raw_secret = NULL;
DWORD raw_secret_len = 0;
PBYTE peer_pub_blob = NULL;
DWORD peer_pub_blob_len = 0;
char pin[128] = {0};
int key_exists = 0;
int pin_supported = 0;
st = NCryptOpenStorageProvider(&tpm_prov, MS_PLATFORM_CRYPTO_PROVIDER, 0);
if (st != ERROR_SUCCESS) {
fprintf(stderr, "[win-tpm] MS_PLATFORM_CRYPTO_PROVIDER unavailable: 0x%08lx (%s)\n", (unsigned long)st, ncrypt_status_hint(st));
#if OTP_WINDOWS_TPM_STRICT
return -1;
#else
st = NCryptOpenStorageProvider(&sw_prov, MS_KEY_STORAGE_PROVIDER, 0);
if (st != ERROR_SUCCESS) {
return win_err("NCryptOpenStorageProvider(MS_KEY_STORAGE_PROVIDER)", st);
}
printf("[win-tpm] Falling back to software KSP (MS_KEY_STORAGE_PROVIDER)\n");
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_LOCAL_NAME, NULL, &tpm_key, NULL) != 0) {
goto cleanup;
}
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_PEER_NAME, NULL, &sw_peer_key, NULL) != 0) {
goto cleanup;
}
st = NCryptSecretAgreement(tpm_key, sw_peer_key, &secret, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptSecretAgreement(fallback)", st);
goto cleanup;
}
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &raw_secret_len, 0);
if (st != ERROR_SUCCESS || raw_secret_len == 0) {
win_err("NCryptDeriveKey(size/fallback)", st);
goto cleanup;
}
raw_secret = (PBYTE)malloc(raw_secret_len);
if (!raw_secret) {
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)raw_secret_len);
goto cleanup;
}
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, raw_secret, raw_secret_len, &raw_secret_len, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptDeriveKey(data/fallback)", st);
goto cleanup;
}
if (derive_secp256k1_privkey_from_secret(raw_secret, (size_t)raw_secret_len, out_key32) != 0) {
fprintf(stderr, "[win-tpm] failed deriving secp256k1 private key in software fallback\n");
goto cleanup;
}
rc = 0;
goto cleanup;
#endif
}
else {
printf("[win-tpm] Using TPM platform provider\n");
}
st = NCryptOpenStorageProvider(&sw_prov, MS_KEY_STORAGE_PROVIDER, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptOpenStorageProvider(MS_KEY_STORAGE_PROVIDER)", st);
goto cleanup;
}
pin_supported = probe_tpm_native_pin_support(tpm_prov);
if (pin_supported < 0) {
fprintf(stderr, "[win-tpm] Cannot determine TPM-native PIN support; continuing without PIN\n");
pin_supported = 0;
}
else if (pin_supported == 0) {
fprintf(stderr, "[win-tpm] TPM provider does not support native PIN auth; continuing without PIN\n");
}
if (key_exists_by_name(tpm_prov, TPM_KEY_NAME, &key_exists) != 0) {
goto cleanup;
}
if (pin_supported) {
if (!key_exists) {
if (read_tpm_pin_prompt("Set TPM key PIN: ", pin, sizeof(pin)) != 0) {
fprintf(stderr, "[win-tpm] PIN is required to provision TPM key\n");
goto cleanup;
}
if (!getenv("PICO_NOVUS_TPM_PIN") && _isatty(_fileno(stdin))) {
char confirm[128] = {0};
if (read_tpm_pin_prompt("Confirm TPM key PIN: ", confirm, sizeof(confirm)) != 0 || strcmp(pin, confirm) != 0) {
fprintf(stderr, "[win-tpm] PIN confirmation mismatch\n");
SecureZeroMemory(confirm, sizeof(confirm));
goto cleanup;
}
SecureZeroMemory(confirm, sizeof(confirm));
}
}
else {
if (read_tpm_pin_prompt("Enter TPM key PIN: ", pin, sizeof(pin)) != 0) {
fprintf(stderr, "[win-tpm] PIN is required to unlock TPM key\n");
goto cleanup;
}
}
}
if (open_or_create_persisted_ecdh_p256_key(tpm_prov, TPM_KEY_NAME, pin_supported ? pin : NULL, &tpm_key, NULL) != 0) {
goto cleanup;
}
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_PEER_NAME, NULL, &sw_peer_key, NULL) != 0) {
goto cleanup;
}
st = NCryptExportKey(sw_peer_key, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, NULL, 0, &peer_pub_blob_len, 0);
if (st != ERROR_SUCCESS || peer_pub_blob_len == 0) {
win_err("NCryptExportKey(size)", st);
goto cleanup;
}
peer_pub_blob = (PBYTE)malloc(peer_pub_blob_len);
if (!peer_pub_blob) {
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)peer_pub_blob_len);
goto cleanup;
}
st = NCryptExportKey(sw_peer_key, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, peer_pub_blob, peer_pub_blob_len, &peer_pub_blob_len, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptExportKey(data)", st);
goto cleanup;
}
st = NCryptImportKey(tpm_prov, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, &imported_peer_pub, peer_pub_blob, peer_pub_blob_len, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptImportKey(BCRYPT_ECCPUBLIC_BLOB)", st);
goto cleanup;
}
st = NCryptSecretAgreement(tpm_key, imported_peer_pub, &secret, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptSecretAgreement", st);
goto cleanup;
}
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &raw_secret_len, 0);
if (st != ERROR_SUCCESS || raw_secret_len == 0) {
win_err("NCryptDeriveKey(size)", st);
goto cleanup;
}
raw_secret = (PBYTE)malloc(raw_secret_len);
if (!raw_secret) {
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)raw_secret_len);
goto cleanup;
}
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, raw_secret, raw_secret_len, &raw_secret_len, 0);
if (st != ERROR_SUCCESS) {
win_err("NCryptDeriveKey(data)", st);
goto cleanup;
}
if (derive_secp256k1_privkey_from_secret(raw_secret, (size_t)raw_secret_len, out_key32) != 0) {
fprintf(stderr, "[win-tpm] failed deriving secp256k1 private key from ECDH secret\n");
goto cleanup;
}
rc = 0;
cleanup:
SecureZeroMemory(pin, sizeof(pin));
if (peer_pub_blob) {
SecureZeroMemory(peer_pub_blob, peer_pub_blob_len);
free(peer_pub_blob);
}
if (raw_secret) {
SecureZeroMemory(raw_secret, raw_secret_len);
free(raw_secret);
}
if (secret) {
NCryptFreeObject(secret);
}
if (imported_peer_pub) {
NCryptFreeObject(imported_peer_pub);
}
if (sw_peer_key) {
NCryptFreeObject(sw_peer_key);
}
if (tpm_key) {
NCryptFreeObject(tpm_key);
}
if (sw_prov) {
NCryptFreeObject(sw_prov);
}
if (tpm_prov) {
NCryptFreeObject(tpm_prov);
}
return rc;
}
#endif
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
(void)bootkey;
(void)secure_lock;
return PICOKEYS_OK;
}
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
(void)bootkey;
return true;
}
bool otp_platform_is_secure_boot_locked(void) {
return false;
}
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
static uint8_t _otp1[32] = {0};
static uint8_t _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
#if defined(_MSC_VER)
if (windows_tpm_vault_load_or_create_key(_otp2) != 0) {
printf("Warning: failed to load Windows TPM key; using dummy otp_key_2\n");
}
#endif
*otp_key_1_out = _otp1;
*otp_key_2_out = _otp2;
}

View File

@@ -1,240 +0,0 @@
/*
* 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

117
src/pico_time.c Normal file
View File

@@ -0,0 +1,117 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "pico_time.h"
#ifdef ESP_PLATFORM
#include <sys/time.h>
#endif
#ifdef _MSC_VER
#include <windows.h>
PACK(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;
}
int settimeofday(const struct timeval* tp, const struct timezone* tzp) {
(void)tzp;
SYSTEMTIME st;
FILETIME ft;
uint64_t time;
time = ((uint64_t)tp->tv_sec * 10000000L) + ((uint64_t)tp->tv_usec * 10) + ((uint64_t)116444736000000000ULL);
ft.dwLowDateTime = (uint32_t)(time & 0xFFFFFFFF);
ft.dwHighDateTime = (uint32_t)(time >> 32);
FileTimeToSystemTime(&ft, &st);
return SetSystemTime(&st);
}
#endif
struct tm *gmtime_utc(const time_t *timep, struct tm *result) {
#ifdef _WIN32
struct tm *tmp = gmtime(timep);
if (tmp == NULL) {
return NULL;
}
*result = *tmp;
return result;
#else
return gmtime_r(timep, result);
#endif
}
#ifdef ENABLE_EMULATION
bool set_rtc = true;
#else
bool set_rtc = false;
#endif
bool has_set_rtc(void) {
return set_rtc;
}
void set_rtc_time(time_t t) {
#ifdef PICO_PLATFORM
struct timespec tv = {.tv_sec = t, .tv_nsec = 0};
aon_timer_set_time(&tv);
#else
struct timeval tv = {.tv_sec = (long)t, .tv_usec = 0};
settimeofday(&tv, NULL);
#endif
set_rtc = true;
}
time_t get_rtc_time(void) {
#ifdef PICO_PLATFORM
struct timespec tv;
aon_timer_get_time(&tv);
return tv.tv_sec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec;
#endif
}
void init_rtc(void) {
#ifdef PICO_PLATFORM
struct timespec tv = {0};
tv.tv_sec = 1577836800; // 2020-01-01
aon_timer_start(&tv);
#endif
}

41
src/pico_time.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TIME_H
#define TIME_H
#if defined(PICO_PLATFORM)
#include "pico/aon_timer.h"
#include "bsp/board.h"
#elif defined(ESP_PLATFORM)
#include "compat/esp_compat.h"
#include <time.h>
#else
#ifndef _MSC_VER
#include <sys/time.h>
#endif
#include <time.h>
#include "compat/board.h"
#endif
extern struct tm *gmtime_utc(const time_t *timep, struct tm *result);
extern bool has_set_rtc(void);
extern time_t get_rtc_time(void);
extern void set_rtc_time(time_t tv_sec);
extern void init_rtc(void);
#endif // TIME_H

175
src/picokeys.h Normal file
View File

@@ -0,0 +1,175 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _PICOKEYS_H_
#define _PICOKEYS_H_
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#if defined(PICO_RP2040) || defined(PICO_RP2350)
#define PICO_PLATFORM
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "file.h"
#include "flash.h"
#include "debug.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
#ifdef _MSC_VER
#define WEAK
#else
#define WEAK __attribute__((weak))
#endif
extern int picokey_init(void);
extern void low_flash_init_core1(void);
static inline uint16_t make_uint16_be(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline uint16_t make_uint16_le(uint8_t b1, uint8_t b2) {
return (b2 << 8) | b1;
}
static inline uint16_t get_uint16_be(const uint8_t *b) {
return make_uint16_be(b[0], b[1]);
}
static inline uint16_t get_uint16_le(const uint8_t *b) {
return make_uint16_le(b[0], b[1]);
}
static inline uint8_t put_uint16_be(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 2;
}
static inline uint8_t put_uint16_le(uint16_t n, uint8_t *b) {
*b++ = n & 0xff;
*b = (n >> 8) & 0xff;
return 2;
}
static inline uint32_t make_uint32_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_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_be(const uint8_t *b) {
return make_uint32_be(b[0], b[1], b[2], b[3]);
}
static inline uint32_t get_uint32_le(const uint8_t *b) {
return make_uint32_le(b[0], b[1], b[2], b[3]);
}
static inline uint8_t put_uint32_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 uint8_t put_uint32_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_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_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_be(const uint8_t *b) {
return make_uint64_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint64_t get_uint64_le(const uint8_t *b) {
return make_uint64_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint32_t put_uint64_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_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 int (*button_pressed_cb)(uint8_t);
extern bool is_req_button_pending(void);
#define PICOKEYS_OK 0
#define PICOKEYS_ERR_NO_MEMORY -1000
#define PICOKEYS_ERR_MEMORY_FATAL -1001
#define PICOKEYS_ERR_NULL_PARAM -1002
#define PICOKEYS_ERR_FILE_NOT_FOUND -1003
#define PICOKEYS_ERR_BLOCKED -1004
#define PICOKEYS_NO_LOGIN -1005
#define PICOKEYS_EXEC_ERROR -1006
#define PICOKEYS_WRONG_LENGTH -1007
#define PICOKEYS_WRONG_DATA -1008
#define PICOKEYS_WRONG_DKEK -1009
#define PICOKEYS_WRONG_SIGNATURE -1010
#define PICOKEYS_WRONG_PADDING -1011
#define PICOKEYS_VERIFICATION_FAILED -1012
#define PICOKEYS_CHECK(x) do { ret = (x); if (ret != PICOKEYS_OK) goto err; } while (0)
extern int set_atr(void);
#endif

View File

@@ -3,24 +3,24 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __VERSION_H_ #ifndef __VERSION_H_
#define __VERSION_H_ #define __VERSION_H_
#define PICO_KEYS_SDK_VERSION 0x0700 #define PICOKEYS_SDK_VERSION 0x0806
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff) #define PICOKEYS_SDK_VERSION_MAJOR ((PICOKEYS_SDK_VERSION >> 8) & 0xff)
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff) #define PICOKEYS_SDK_VERSION_MINOR (PICOKEYS_SDK_VERSION & 0xff)
#endif #endif

View File

@@ -3,25 +3,43 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "serial.h"
#include "led/led.h"
#include <time.h>
#include "pico_time.h"
#ifdef PICO_PLATFORM
#include "hardware/watchdog.h"
#endif
#include "apdu.h" #include "apdu.h"
#include "pico_keys_version.h" #include "picokeys_version.h"
#include "otp.h" #include "otp.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include "random.h"
#include "crypto_utils.h"
#include "usb.h"
int rescue_process_apdu();
int rescue_unload(); #ifdef PICO_PLATFORM
extern char __flash_binary_start;
extern char __flash_binary_end;
#endif
static int rescue_process_apdu(void);
static int rescue_unload(void);
const uint8_t rescue_aid[] = { const uint8_t rescue_aid[] = {
8, 8,
@@ -29,60 +47,316 @@ const uint8_t rescue_aid[] = {
}; };
#ifdef PICO_RP2350 #ifdef PICO_RP2350
#define PICO_MCU 1 const uint8_t PICO_MCU = 1;
#elif defined(ESP_PLATFORM) #elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define PICO_MCU 2 const uint8_t PICO_MCU = 2;
#elif defined(ENABLE_EMULATION) #elif defined(ENABLE_EMULATION)
#define PICO_MCU 3 const uint8_t PICO_MCU = 3;
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
const uint8_t PICO_MCU = 4;
#else #else
#define PICO_MCU 0 const uint8_t PICO_MCU = 0;
#endif #endif
extern uint8_t PICO_PRODUCT; #define EF_DEVCERT_KEY 0xE0C1
int rescue_select(app_t *a, uint8_t force) { extern uint8_t PICO_PRODUCT;
extern uint8_t PICO_VERSION_MAJOR;
extern uint8_t PICO_VERSION_MINOR;
static int rescue_select(app_t *a, uint8_t force) {
a->process_apdu = rescue_process_apdu; a->process_apdu = rescue_process_apdu;
a->unload = rescue_unload; a->unload = rescue_unload;
res_APDU_size = 0; res_APDU_size = 0;
res_APDU[res_APDU_size++] = PICO_MCU; res_APDU[res_APDU_size++] = PICO_MCU;
res_APDU[res_APDU_size++] = PICO_PRODUCT; res_APDU[res_APDU_size++] = PICO_PRODUCT;
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MAJOR; res_APDU[res_APDU_size++] = PICO_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MINOR; res_APDU[res_APDU_size++] = PICO_VERSION_MINOR;
memcpy(res_APDU + res_APDU_size, pico_serial.id, sizeof(pico_serial.id));
res_APDU_size += sizeof(pico_serial.id);
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
if (force) { if (force) {
scan_flash(); file_scan_flash();
} }
return PICOKEY_OK; return PICOKEYS_OK;
}
const uint8_t atr_rescue[] = {
24,
0x3B, 0xFE, 0x18, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x45, 0x80, 0x31, 0x81, 0x54, 0x48, 0x53, 0x4D,
0x31, 0x73, 0x80, 0x21, 0x40, 0x81, 0x07, 0xFA
};
extern const uint8_t *ccid_atr;
WEAK int set_atr(void) {
ccid_atr = atr_rescue;
return 0;
} }
INITIALIZER ( rescue_ctor ) { INITIALIZER ( rescue_ctor ) {
register_app(rescue_select, rescue_aid); register_app(rescue_select, rescue_aid);
} }
int rescue_unload() { static int rescue_unload(void) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
int cmd_write() { static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id ec_id) {
file_t *ef_devcert_key = file_new(EF_DEVCERT_KEY);
if (!ef_devcert_key) {
return SW_FILE_NOT_FOUND();
}
uint8_t kbase[32] = {0};
derive_kbase(kbase);
if (file_has_data(ef_devcert_key)) {
uint8_t pkey[32] = {0};
memcpy(pkey, file_get_data(ef_devcert_key), 32);
aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, pkey, 32);
int ret = mbedtls_ecp_read_key(ec_id, ecp, pkey, 32);
mbedtls_platform_zeroize(pkey, sizeof(pkey));
if (ret != 0) {
return SW_EXEC_ERROR();
}
}
else {
// Generate new key
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES] = {0};
size_t olen = 0;
mbedtls_ecp_gen_key(ec_id, ecp, random_fill_iterator, NULL);
mbedtls_ecp_write_key_ext(ecp, &olen, pkey, sizeof(pkey));
aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, pkey, 32);
file_put_data(ef_devcert_key, pkey, (uint16_t)olen);
mbedtls_platform_zeroize(pkey, sizeof(pkey));
flash_commit();
}
return PICOKEYS_OK;
}
static int cmd_keydev_sign(void) {
uint8_t p1 = P1(apdu);
if (p1 == 0x01) {
if (apdu.nc != 32) {
return SW_WRONG_LENGTH();
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
if (!otp_key_2) {
int ret = load_internal_keydev(&ecp, ec_id);
if (ret != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ecp);
return ret;
}
}
else {
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
}
uint16_t key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(ec_id)->bit_size + 7) / 8);
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
int ret = mbedtls_ecdsa_sign(&ecp.MBEDTLS_PRIVATE(grp), &r, &s, &ecp.MBEDTLS_PRIVATE(d), apdu.data, apdu.nc, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
return SW_EXEC_ERROR();
}
mbedtls_mpi_write_binary(&r, res_APDU, key_size / 2); res_APDU_size = key_size / 2;
mbedtls_mpi_write_binary(&s, res_APDU + res_APDU_size, key_size / 2); res_APDU_size += key_size / 2;
mbedtls_ecp_keypair_free(&ecp);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
}
else if (p1 == 0x02) {
// Return public key
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
if (!otp_key_2) {
int ret = load_internal_keydev(&ecp, ec_id);
if (ret != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ecp);
return ret;
}
}
else {
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
}
int ret = mbedtls_ecp_keypair_calc_public(&ecp, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 2038);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
res_APDU_size = (uint16_t)olen;
mbedtls_ecp_keypair_free(&ecp);
}
else if (p1 == 0x03) {
// Upload device attestation certificate
if (apdu.nc == 0) {
return SW_WRONG_LENGTH();
}
file_t *ef_devcert = file_new(0x2F02); // EF_DEVCERT
if (!ef_devcert) {
return SW_FILE_NOT_FOUND();
}
file_put_data(ef_devcert, apdu.data, (uint16_t)apdu.nc);
res_APDU_size = 0;
flash_commit();
}
else {
return SW_INCORRECT_P1P2();
}
return SW_OK();
}
// Blocking CORE1
static void led_3_blinks(void) {
#ifndef ENABLE_EMULATION
uint32_t mode = led_get_mode();
led_set_mode(MODE_PROCESSING);
sleep_ms(500);
led_set_mode(mode);
#endif
}
static int cmd_write(void) {
if (apdu.nc < 2) { if (apdu.nc < 2) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
if (P1(apdu) == 0x1) { // PHY uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p1 == 0x1) { // PHY
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
int ret = phy_unserialize_data(apdu.data, apdu.nc, &phy_data); int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
if (ret == PICOKEY_OK) { if (ret == PICOKEYS_OK) {
if (phy_save() != PICOKEY_OK) { if (phy_save() != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
#endif #endif
} }
else if (p1 == 0x2) { // SET TIME
time_t tv_sec = 0;
if (p2 != 0x1 && p2 != 0x2) {
return SW_INCORRECT_P1P2();
}
if (p2 == 0x1) {
if (apdu.nc != 8) {
return SW_WRONG_LENGTH();
}
struct tm tm;
tm.tm_year = get_uint16_be(apdu.data) - 1900;
tm.tm_mon = apdu.data[2];
tm.tm_mday = apdu.data[3];
tm.tm_wday = apdu.data[4];
tm.tm_hour = apdu.data[5];
tm.tm_min = apdu.data[6];
tm.tm_sec = apdu.data[7];
tv_sec = mktime(&tm);
}
else if (p2 == 0x2) {
if (apdu.nc != 4) {
return SW_WRONG_LENGTH();
}
uint32_t t = (apdu.data[0] << 24) | (apdu.data[1] << 16) | (apdu.data[2] << 8) | apdu.data[3];
tv_sec = (time_t)t;
}
set_rtc_time(tv_sec);
}
led_3_blinks();
return SW_OK();
}
static int cmd_read(void) {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p1 == 0x1) { // PHY
#ifndef ENABLE_EMULATION
uint16_t len = 0;
int ret = phy_serialize_data(&phy_data, apdu.rdata, &len);
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
res_APDU_size = len;
#endif
}
else if (p1 == 0x2) { // FLASH INFO
res_APDU_size = 0;
uint32_t free = flash_free_space(), total = flash_total_space(), used = flash_used_space(), nfiles = flash_num_files(), size = flash_size();
res_APDU_size += put_uint32_be(free, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_be(used, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_be(total, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_be(nfiles, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_be(size, res_APDU + res_APDU_size);
#ifdef PICO_PLATFORM
uintptr_t start = (uintptr_t) &__flash_binary_start;
uintptr_t end = (uintptr_t) &__flash_binary_end;
uint32_t fw_size = (uint32_t)(end - start);
res_APDU_size += put_uint32_be(fw_size, res_APDU + res_APDU_size);
#endif
}
else if (p1 == 0x3) { // OTP SECURE BOOT STATUS
res_APDU_size = 0;
uint8_t bootkey = 0xFF;
bool enabled = otp_is_secure_boot_enabled(&bootkey);
bool locked = otp_is_secure_boot_locked();
res_APDU[res_APDU_size++] = enabled ? 0x1 : 0x0;
res_APDU[res_APDU_size++] = locked ? 0x1 : 0x0;
res_APDU[res_APDU_size++] = bootkey;
}
else if (p1 == 0x4) { // GET TIME
if (p2 != 0x1 && p2 != 0x2) {
return SW_INCORRECT_P1P2();
}
if (!has_set_rtc()) {
return SW_CONDITIONS_NOT_SATISFIED();
}
res_APDU_size = 0;
time_t tv_sec = get_rtc_time();
if (p2 == 0x1) {
struct tm *tm = localtime(&tv_sec);
res_APDU_size += put_uint16_be((uint16_t)(tm->tm_year + 1900), res_APDU);
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_mon;
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_mday;
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_wday;
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_hour;
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_min;
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_sec;
}
else if (p2 == 0x2) {
res_APDU_size += put_uint32_be((uint32_t)tv_sec, res_APDU);
}
}
return SW_OK(); return SW_OK();
} }
#if defined(PICO_RP2350) || defined(ESP_PLATFORM) #if defined(PICO_RP2350) || defined(ESP_PLATFORM)
int cmd_secure() { static int cmd_secure(void) {
if (apdu.nc != 0) { if (apdu.nc != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
@@ -91,25 +365,57 @@ int cmd_secure() {
bool secure_lock = P2(apdu) == 0x1; bool secure_lock = P2(apdu) == 0x1;
int ret = otp_enable_secure_boot(bootkey, secure_lock); int ret = otp_enable_secure_boot(bootkey, secure_lock);
if (ret != 0) { if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
led_3_blinks();
return SW_OK(); return SW_OK();
} }
#endif #endif
#ifdef PICO_PLATFORM
static int cmd_reboot_bootsel(void) {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) {
// Reboot to BOOTSEL
uint32_t val = EV_RESET;
queue_try_add(&card_to_usb_q, &val);
}
else if (P1(apdu) == 0x0) {
// Reboot to normal mode
watchdog_reboot(0, 0, 100);
}
else {
return SW_INCORRECT_P1P2();
}
return SW_OK();
}
#endif
#define INS_KEYDEV_SIGN 0x10
#define INS_WRITE 0x1C #define INS_WRITE 0x1C
#define INS_SECURE 0x1D #define INS_SECURE 0x1D
#define INS_READ 0x1E
#define INS_REBOOT_BOOTSEL 0x1F
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_KEYDEV_SIGN, cmd_keydev_sign },
{ INS_WRITE, cmd_write }, { INS_WRITE, cmd_write },
#if defined(PICO_RP2350) || defined(ESP_PLATFORM) #if defined(PICO_RP2350) || defined(ESP_PLATFORM)
{ INS_SECURE, cmd_secure }, { INS_SECURE, cmd_secure },
#endif
{ INS_READ, cmd_read },
#ifdef PICO_PLATFORM
{ INS_REBOOT_BOOTSEL, cmd_reboot_bootsel },
#endif #endif
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int rescue_process_apdu() { static int rescue_process_apdu(void) {
if (CLA(apdu) != 0x80) { if (CLA(apdu) != 0x80) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -3,87 +3,100 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include "picokeys.h"
#include <string.h> #include "hwrng.h"
#include <stdio.h> #include "pico_time.h"
#if defined(ENABLE_EMULATION)
#include <stdbool.h> #if defined(PICO_PLATFORM)
#include <stdlib.h> #include "pico/rand.h"
#include <time.h> #include "pico/mutex.h"
#include "emulation.h" #elif defined(ESP_PLATFORM)
#elif (ESP_PLATFORM)
#include "bootloader_random.h" #include "bootloader_random.h"
#include "esp_random.h" #include "esp_random.h"
#include "esp_compat.h" #include "compat/esp_compat.h"
#else #else
#include "pico/stdlib.h" #include "compat/queue.h"
#include "hwrng.h"
#include "bsp/board.h"
#include "pico/rand.h"
#endif #endif
void hwrng_start() { static void hwrng_start(void) {
#if defined(ENABLE_EMULATION) #if defined(ENABLE_EMULATION)
srand(time(0)); srand((unsigned int)time(NULL));
#elif defined(ESP_PLATFORM) #elif defined(ESP_PLATFORM)
bootloader_random_enable(); bootloader_random_enable();
#endif #endif
} }
static uint64_t random_word = 0xcbf29ce484222325; static uint64_t random_word = 0xcbf29ce484222325;
static uint8_t ep_round = 0; static uint8_t hwrng_mix_round = 0;
static void ep_init() { static void hwrng_mix_init(void) {
random_word = 0xcbf29ce484222325; random_word = 0xcbf29ce484222325;
ep_round = 0; hwrng_mix_round = 0;
} }
/* Here, we assume a little endian architecture. */ /* Here, we assume a little endian architecture. */
static int ep_process() { static int hwrng_mix_process(void) {
if (ep_round == 0) { if (hwrng_mix_round == 0) {
ep_init(); hwrng_mix_init();
} }
uint64_t word = 0x0; uint64_t word = 0x0;
#if defined(ENABLE_EMULATION) #if defined(PICO_PLATFORM)
word = rand(); word = get_rand_64();
word <<= 32;
word |= rand();
#elif defined(ESP_PLATFORM) #elif defined(ESP_PLATFORM)
esp_fill_random((uint8_t *)&word, sizeof(word)); esp_fill_random((uint8_t *)&word, sizeof(word));
#else #else
word = get_rand_64(); word = rand();
word <<= 32;
word |= rand();
#endif #endif
random_word ^= word ^ board_millis(); random_word ^= word ^ board_millis();
random_word *= 0x00000100000001B3; random_word *= 0x00000100000001B3;
if (++ep_round == 8) { if (++hwrng_mix_round == 8) {
ep_round = 0; hwrng_mix_round = 0;
return 2; //2 words return sizeof(uint64_t) / sizeof(uint32_t); //2 words
} }
return 0; return 0;
} }
struct rng_rb { PACK(
typedef struct hwrng_buf {
uint32_t *buf; uint32_t *buf;
uint8_t head, tail; uint8_t head;
uint8_t tail;
uint8_t size; uint8_t size;
unsigned int full : 1; unsigned int full : 1;
unsigned int empty : 1; unsigned int empty : 1;
}; }) hwrng_buf_t;
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) { static mutex_t hwrng_mutex;
static bool hwrng_mutex_initialized = false;
static inline void hwrng_lock(void) {
if (hwrng_mutex_initialized) {
mutex_enter_blocking(&hwrng_mutex);
}
}
static inline void hwrng_unlock(void) {
if (hwrng_mutex_initialized) {
mutex_exit(&hwrng_mutex);
}
}
static void hwrng_buf_init(struct hwrng_buf *rb, uint32_t *p, uint8_t size) {
rb->buf = p; rb->buf = p;
rb->size = size; rb->size = size;
rb->head = rb->tail = 0; rb->head = rb->tail = 0;
@@ -91,23 +104,35 @@ static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
rb->empty = 1; rb->empty = 1;
} }
static void rb_add(struct rng_rb *rb, uint32_t v) { static void hwrng_buf_add(struct hwrng_buf *rb, uint32_t v) {
rb->buf[rb->tail++] = v; if (rb->full) {
if (rb->tail == rb->size) { return;
rb->tail = 0;
} }
if (rb->tail == rb->head) {
rb->full = 1; uint8_t tail = rb->tail;
rb->buf[tail] = v;
tail++;
if (tail >= rb->size) {
tail = 0;
} }
rb->tail = tail;
rb->full = (rb->tail == rb->head);
rb->empty = 0; rb->empty = 0;
} }
static uint32_t rb_del(struct rng_rb *rb) { static uint32_t hwrng_buf_del(struct hwrng_buf *rb) {
uint32_t v = rb->buf[rb->head++]; uint32_t v = 0;
if (rb->empty) {
if (rb->head == rb->size) { return v;
rb->head = 0;
} }
uint8_t head = rb->head;
v = rb->buf[head];
head++;
if (head >= rb->size) {
head = 0;
}
rb->head = head;
if (rb->head == rb->tail) { if (rb->head == rb->tail) {
rb->empty = 1; rb->empty = 1;
} }
@@ -116,73 +141,86 @@ static uint32_t rb_del(struct rng_rb *rb) {
return v; return v;
} }
static struct rng_rb the_ring_buffer; static struct hwrng_buf ring_buffer;
void *neug_task() { void *hwrng_task(void) {
struct rng_rb *rb = &the_ring_buffer; struct hwrng_buf *rb = &ring_buffer;
int n; int n;
if ((n = ep_process())) { hwrng_lock();
int i; if ((n = hwrng_mix_process())) {
const uint32_t *vp = (const uint32_t *) &random_word; const uint32_t *vp = (const uint32_t *) &random_word;
for (i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
rb_add(rb, *vp++); hwrng_buf_add(rb, *vp++);
if (rb->full) { if (rb->full) {
break; break;
} }
} }
} }
hwrng_unlock();
return NULL; return NULL;
} }
void neug_init(uint32_t *buf, uint8_t size) { void hwrng_init(uint32_t *buf, uint8_t size) {
struct rng_rb *rb = &the_ring_buffer; struct hwrng_buf *rb = &ring_buffer;
rb_init(rb, buf, size); mutex_init(&hwrng_mutex);
hwrng_mutex_initialized = true;
hwrng_buf_init(rb, buf, size);
hwrng_start(); hwrng_start();
ep_init(); hwrng_mix_init();
} }
void neug_flush(void) { void hwrng_flush(void) {
struct rng_rb *rb = &the_ring_buffer; struct hwrng_buf *rb = &ring_buffer;
hwrng_lock();
while (!rb->empty) { while (!rb->empty) {
rb_del(rb); hwrng_buf_del(rb);
} }
hwrng_unlock();
} }
uint32_t neug_get() { uint32_t hwrng_get(void) {
struct rng_rb *rb = &the_ring_buffer; struct hwrng_buf *rb = &ring_buffer;
uint32_t v; uint32_t v;
while (rb->empty) { while (true) {
neug_task(); hwrng_lock();
if (!rb->empty) {
v = hwrng_buf_del(rb);
hwrng_unlock();
break;
}
hwrng_unlock();
hwrng_task();
} }
v = rb_del(rb);
return v; return v;
} }
void neug_wait_full() { void hwrng_wait_full(void) {
struct rng_rb *rb = &the_ring_buffer; struct hwrng_buf *rb = &ring_buffer;
#ifndef ENABLE_EMULATION
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0; uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
#else #elif defined(PICO_PLATFORM)
uint core = get_core_num(); uint core = get_core_num();
#endif #endif
#endif while (true) {
while (!rb->full) { hwrng_lock();
#ifndef ENABLE_EMULATION hwrng_unlock();
if (rb->full) {
break;
}
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
if (core == 1) { if (core == 1) {
sleep_ms(1); sleep_ms(1);
} }
else else
#endif #endif
neug_task(); hwrng_task();
} }
} }

View File

@@ -3,31 +3,26 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _NEUG_H_ #ifndef _NEUG_H_
#define _NEUG_H_ #define _NEUG_H_
#include <stdint.h>
#define NEUG_PRE_LOOP 32 void hwrng_init(uint32_t *buf, uint8_t size);
uint32_t hwrng_get(void);
#include <stdlib.h> void hwrng_flush(void);
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) void hwrng_wait_full(void);
#include "pico/stdlib.h" void *hwrng_task(void);
#endif
void neug_init(uint32_t *buf, uint8_t size);
uint32_t neug_get();
void neug_flush(void);
void neug_wait_full();
#endif #endif

View File

@@ -3,75 +3,96 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#define HWRNG_PRE_LOOP 32
#include <stdint.h> #include "picokeys.h"
#include <string.h>
#include "hwrng.h" #include "hwrng.h"
#include "random.h"
#if defined(PICO_PLATFORM)
#include "pico/mutex.h"
#elif defined(ESP_PLATFORM)
#include "compat/esp_compat.h"
#else
#include "compat/queue.h"
#endif
#define RANDOM_BYTES_LENGTH 32 #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)];
static mutex_t random_mutex;
static bool random_mutex_initialized = false;
void random_init(void) { void random_init(void) {
int i; mutex_init(&random_mutex);
random_mutex_initialized = true;
hwrng_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
neug_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t)); for (int i = 0; i < HWRNG_PRE_LOOP; i++) {
hwrng_get();
for (i = 0; i < NEUG_PRE_LOOP; i++) {
neug_get();
} }
} }
/*
* Free pointer to random 32-byte
*/
static void random_bytes_free(const uint8_t *p) {
(void) p;
memset(random_word, 0, RANDOM_BYTES_LENGTH);
hwrng_flush();
}
/* /*
* Return pointer to random 32-byte * Return pointer to random 32-byte
*/ */
void random_bytes_free(const uint8_t *p);
#define MAX_RANDOM_BUFFER 1024 #define MAX_RANDOM_BUFFER 1024
const uint8_t *random_bytes_get(size_t len) { const uint8_t *random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER) { if (len > MAX_RANDOM_BUFFER) {
return NULL; return NULL;
} }
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)]; static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
if (random_mutex_initialized) {
mutex_enter_blocking(&random_mutex);
}
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) { for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full(); hwrng_wait_full();
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH); memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *) random_word); random_bytes_free((const uint8_t *) random_word);
} }
if (random_mutex_initialized) {
mutex_exit(&random_mutex);
}
return (const uint8_t *) return_word; return (const uint8_t *) return_word;
} }
/*
* Free pointer to random 32-byte
*/
void random_bytes_free(const uint8_t *p) {
(void) p;
memset(random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush();
}
/* /*
* Random byte iterator * Random byte iterator
*/ */
int random_gen(void *arg, unsigned char *out, size_t out_len) { int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
uint8_t *index_p = (uint8_t *) arg; random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
uint8_t index = index_p ? *index_p : 0; uint8_t index = ctx ? ctx->index : 0;
uint8_t n; uint8_t n;
int ret = 0;
if (random_mutex_initialized) {
mutex_enter_blocking(&random_mutex);
}
while (out_len) { while (out_len) {
neug_wait_full(); if (ctx && ctx->cancel) {
ret = -1;
break;
}
hwrng_wait_full();
n = RANDOM_BYTES_LENGTH - index; n = RANDOM_BYTES_LENGTH - index;
if (n > out_len) { if (n > out_len) {
@@ -85,13 +106,20 @@ int random_gen(void *arg, unsigned char *out, size_t out_len) {
if (index >= RANDOM_BYTES_LENGTH) { if (index >= RANDOM_BYTES_LENGTH) {
index = 0; index = 0;
neug_flush(); hwrng_flush();
} }
} }
if (index_p) { if (ctx) {
*index_p = index; ctx->index = index;
}
if (random_mutex_initialized) {
mutex_exit(&random_mutex);
} }
return 0; return ret;
}
int random_fill_buffer(uint8_t *buf, size_t n) {
return random_fill_iterator(NULL, buf, n);
} }

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@@ -21,14 +21,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
void random_init(void); typedef struct {
uint8_t index;
volatile bool cancel;
} random_fill_iterator_ctx_t;
/* 32-byte random bytes */ extern void
const uint8_t *random_bytes_get(size_t); random_init(void);
void random_bytes_free(const uint8_t *p);
/* iterator returning a byta at a time */ extern const uint8_t *random_bytes_get(size_t);
extern int random_gen(void *arg, unsigned char *output, size_t output_len); extern int random_fill_iterator(void *arg, unsigned char *output, size_t output_len);
extern int random_fill_buffer(uint8_t *buf, size_t n);
#endif #endif

247
src/serial.c Normal file
View File

@@ -0,0 +1,247 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "serial.h"
#include "mbedtls/sha256.h"
#if defined(ESP_PLATFORM)
#include "esp_efuse.h"
#endif
#include <stdio.h>
#include <string.h>
#ifndef ESP_PLATFORM
#include <time.h>
#endif
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
static int get_macos_serial(uint8_t *out) {
io_service_t platformExpert;
CFTypeRef serialNumberAsCFString;
char serial[32] = {0};
if (!out) {
return -1;
}
out[0] = '\0';
platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
if (!platformExpert) {
return -2;
}
serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
IOObjectRelease(platformExpert);
if (!serialNumberAsCFString) {
return -3;
}
Boolean ok = CFStringGetCString(serialNumberAsCFString, serial, sizeof(serial), kCFStringEncodingUTF8);
CFRelease(serialNumberAsCFString);
if (ok) {
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
}
return ok ? 0 : -4;
}
#elif defined(_MSC_VER)
#include <windows.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
static int get_system_uuid(char *out) {
char serial[64] = {0};
HRESULT hr;
IWbemLocator *locator = NULL;
IWbemServices *svc = NULL;
IEnumWbemClassObject *enumerator = NULL;
IWbemClassObject *obj = NULL;
ULONG returned = 0;
VARIANT vtProp;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
return -1;
hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hr) && hr != RPC_E_TOO_LATE) {
CoUninitialize();
return -2;
}
hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *)&locator);
if (FAILED(hr)) {
CoUninitialize();
return -3;
}
hr = locator->lpVtbl->ConnectServer(locator, L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &svc);
if (FAILED(hr)) {
locator->lpVtbl->Release(locator);
CoUninitialize();
return -4;
}
hr = CoSetProxyBlanket((IUnknown *)svc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hr)) {
svc->lpVtbl->Release(svc);
locator->lpVtbl->Release(locator);
CoUninitialize();
return -5;
}
hr = svc->lpVtbl->ExecQuery(svc, L"WQL", L"SELECT UUID FROM Win32_ComputerSystemProduct", WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator);
if (FAILED(hr) || !enumerator) {
svc->lpVtbl->Release(svc);
locator->lpVtbl->Release(locator);
CoUninitialize();
return -6;
}
hr = enumerator->lpVtbl->Next( enumerator, WBEM_INFINITE, 1, &obj, &returned);
if (returned == 0 || !obj) {
enumerator->lpVtbl->Release(enumerator);
svc->lpVtbl->Release(svc);
locator->lpVtbl->Release(locator);
CoUninitialize();
return -7;
}
VariantInit(&vtProp);
hr = obj->lpVtbl->Get(obj, L"UUID", 0, &vtProp, NULL, NULL);
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR && vtProp.bstrVal) {
WideCharToMultiByte(CP_UTF8, 0, vtProp.bstrVal, -1, serial, (int)sizeof(serial), NULL, NULL);
}
VariantClear(&vtProp);
obj->lpVtbl->Release(obj);
enumerator->lpVtbl->Release(enumerator);
svc->lpVtbl->Release(svc);
locator->lpVtbl->Release(locator);
CoUninitialize();
if (serial[0]) {
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
}
return serial[0] ? 0 : -8;
}
#elif defined(__linux__)
#include <string.h>
#include <ctype.h>
static int read_first_line(const char *path, char *out, size_t out_len) {
FILE *f;
if (!out || out_len == 0) {
return -1;
}
out[0] = '\0';
f = fopen(path, "r");
if (!f) {
return -2;
}
if (!fgets(out, out_len, f)) {
fclose(f);
return -3;
}
fclose(f);
out[strcspn(out, "\r\n")] = '\0';
return out[0] ? 0 : -4;
}
static int is_bad_value(const char *s) {
if (!s || !s[0])
return 1;
if (strcasecmp(s, "None") == 0)
return 1;
if (strcasecmp(s, "Unknown") == 0)
return 1;
if (strcasecmp(s, "Default string") == 0)
return 1;
if (strcasecmp(s, "To be filled by O.E.M.") == 0)
return 1;
if (strcmp(s, "00000000-0000-0000-0000-000000000000") == 0)
return 1;
if (strcmp(s, "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") == 0)
return 1;
return 0;
}
static int append_field(char *out, size_t out_len, const char *prefix,const char *path) {
char value[256];
if (read_first_line(path, value, sizeof(value)) != 0) {
return -1;
}
if (is_bad_value(value)) {
return -2;
}
strncat(out, prefix, out_len - strlen(out) - 1);
strncat(out, value, out_len - strlen(out) - 1);
strncat(out, ";", out_len - strlen(out) - 1);
return 0;
}
static int get_linux_hardware_id(char *out) {
if (!out) {
return -1;
}
char serial[256] = {0};
append_field(serial, sizeof(serial), "UUID=", "/sys/class/dmi/id/product_uuid");
append_field(serial, sizeof(serial), "BOARD=", "/sys/class/dmi/id/board_serial");
append_field(serial, sizeof(serial), "PRODUCT=", "/sys/class/dmi/id/product_serial");
append_field(serial, sizeof(serial), "CHASSIS=", "/sys/class/dmi/id/chassis_serial");
append_field(serial, sizeof(serial), "MACHINE=", "/etc/machine-id");
if (serial[0]) {
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
}
return serial[0] ? 0 : -2;
}
#endif
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
uint8_t pico_serial_hash[32];
picokey_serial_t pico_serial;
static int serial_id_is_zero(const uint8_t *id, size_t len) {
for (size_t i = 0; i < len; i++) {
if (id[i] != 0) {
return 0;
}
}
return 1;
}
#if defined(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)
#elif defined(__APPLE__)
#define pico_get_unique_board_id(a) get_macos_serial((uint8_t *)(a))
#elif defined(_MSC_VER)
#define pico_get_unique_board_id(a) get_system_uuid((char *)(a))
#elif defined(__linux__)
#define pico_get_unique_board_id(a) get_linux_hardware_id((char *)(a))
#endif
void serial_init(void) {
int serial_rc = 0;
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
serial_rc = pico_get_unique_board_id(&pico_serial);
#else
pico_get_unique_board_id(&pico_serial);
#endif
if (serial_rc != 0 || serial_id_is_zero(pico_serial.id, sizeof(pico_serial.id))) {
printf("serial init: failed to read stable hardware id (rc=%d); using fallback id\n", serial_rc);
memset(pico_serial.id, 0, sizeof(pico_serial.id));
}
memset(pico_serial_str, 0, sizeof(pico_serial_str));
for (size_t i = 0; i < sizeof(pico_serial); i++) {
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
}
mbedtls_sha256(pico_serial.id, sizeof(pico_serial.id), pico_serial_hash, false);
}

40
src/serial.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SERIAL_H_
#define _SERIAL_H_
#include <stdint.h>
#if !defined (PICO_PLATFORM)
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 16
#else
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
#endif
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } picokey_serial_t;
#else
#include "pico/unique_id.h"
typedef pico_unique_board_id_t picokey_serial_t;
#endif
extern picokey_serial_t pico_serial;
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
extern uint8_t pico_serial_hash[32];
extern void serial_init(void);
#endif //_SERIAL_H_

View File

@@ -3,44 +3,44 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include "picokeys.h"
#include "asn1.h" #include "tlv.h"
int asn1_ctx_init(uint8_t *data, uint16_t len, asn1_ctx_t *ctx) { int tlv_ctx_init(uint8_t *data, uint16_t len, tlv_ctx_t *ctx) {
if (!ctx) { if (!ctx) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
ctx->data = data; ctx->data = data;
ctx->len = len; ctx->len = len;
return PICOKEY_OK; return PICOKEYS_OK;
} }
int asn1_ctx_clear(asn1_ctx_t *ctx) { int tlv_ctx_clear(tlv_ctx_t *ctx) {
ctx->data = NULL; ctx->data = NULL;
ctx->len = 0; ctx->len = 0;
return PICOKEY_OK; return PICOKEYS_OK;
} }
uint16_t asn1_len(asn1_ctx_t *ctx) { uint16_t tlv_len(tlv_ctx_t *ctx) {
if (ctx->data && ctx->len > 0) { if (ctx->data && ctx->len > 0) {
return ctx->len; return ctx->len;
} }
return 0; return 0;
} }
uint32_t asn1_get_uint(asn1_ctx_t *ctx) { uint32_t tlv_get_uint(tlv_ctx_t *ctx) {
uint32_t d = ctx->data[0]; uint32_t d = ctx->data[0];
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) { for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
d <<= 8; d <<= 8;
@@ -49,15 +49,15 @@ uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
return d; return d;
} }
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) { uint16_t tlv_len_tag(uint16_t tag, uint16_t len) {
uint16_t ret = 1 + format_tlv_len(len, NULL) + len; uint16_t ret = 1 + tlv_format_len(len, NULL) + len;
if (tag > 0x00ff) { if (tag > 0x00ff) {
return ret + 1; return ret + 1;
} }
return ret; return ret;
} }
uint8_t format_tlv_len(uint16_t len, uint8_t *out) { uint8_t tlv_format_len(uint16_t len, uint8_t *out) {
if (len < 128) { if (len < 128) {
if (out) { if (out) {
*out = (uint8_t)len; *out = (uint8_t)len;
@@ -73,16 +73,12 @@ uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
} }
if (out) { if (out) {
*out++ = 0x82; *out++ = 0x82;
put_uint16_t_be(len, out); put_uint16_be(len, out);
} }
return 3; return 3;
} }
int walk_tlv(const asn1_ctx_t *ctxi, int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data) {
uint8_t **p,
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data) {
if (!p) { if (!p) {
return 0; return 0;
} }
@@ -92,8 +88,7 @@ int walk_tlv(const asn1_ctx_t *ctxi,
if (*p - ctxi->data >= ctxi->len) { if (*p - ctxi->data >= ctxi->len) {
return 0; return 0;
} }
uint16_t tg = 0x0; uint16_t tg = 0x0, tgl = 0;
uint16_t tgl = 0;
tg = *(*p)++; tg = *(*p)++;
if ((tg & 0x1f) == 0x1f) { if ((tg & 0x1f) == 0x1f) {
tg <<= 8; tg <<= 8;
@@ -120,14 +115,10 @@ int walk_tlv(const asn1_ctx_t *ctxi,
return 1; return 1;
} }
bool asn1_find_tag(const asn1_ctx_t *ctxi, bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo) {
uint16_t itag, uint16_t tag = 0x0, tlen = 0;
asn1_ctx_t *ctxo) { uint8_t *p = NULL, *tdata = NULL;
uint16_t tag = 0x0; while (tlv_walk(ctxi, &p, &tag, &tlen, &tdata)) {
uint8_t *p = NULL;
uint8_t *tdata = NULL;
uint16_t tlen = 0;
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
if (itag == tag) { if (itag == tag) {
if (ctxo != NULL) { if (ctxo != NULL) {
ctxo->data = tdata; ctxo->data = tdata;

41
src/tlv.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* 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 Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _TLV_H_
#define _TLV_H_
#include <stdint.h>
#include <stdbool.h>
#include "compat/compat.h"
PACK(
typedef struct tlv_ctx {
uint8_t *data;
uint16_t len;
}) tlv_ctx_t;
extern int tlv_ctx_init(uint8_t *, uint16_t, tlv_ctx_t *);
extern int tlv_ctx_clear(tlv_ctx_t *ctx);
extern uint16_t tlv_len(tlv_ctx_t *ctx);
extern uint32_t tlv_get_uint(tlv_ctx_t *ctx);
extern int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data);
extern uint8_t tlv_format_len(uint16_t len, uint8_t *out);
extern bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo);
extern uint16_t tlv_len_tag(uint16_t tag, uint16_t len);
#endif

View File

@@ -3,20 +3,21 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "picokeys.h"
#include "led/led.h"
#include "random.h" #include "random.h"
#include "pico_keys.h"
#ifdef PICO_PLATFORM #ifdef PICO_PLATFORM
#include "bsp/board.h" #include "bsp/board.h"
#endif #endif
@@ -27,7 +28,6 @@
#include "emulation.h" #include "emulation.h"
#endif #endif
#include "ccid.h" #include "ccid.h"
#include "usb_descriptors.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
@@ -97,21 +97,22 @@ static uint8_t itf_num;
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL; static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read); int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
void ccid_init(void);
void ccid_task(void);
#ifdef ENABLE_EMULATION
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize);
#endif
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) { static void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
ccid_tx[itf].w_ptr += size + offset; ccid_tx[itf].w_ptr += size + offset;
ccid_tx[itf].r_ptr += 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_response = NULL;
ccid_header_t **ccid_resp_fast = NULL; ccid_header_t **ccid_resp_fast = NULL;
ccid_header_t **ccid_header = NULL; ccid_header_t **ccid_header = NULL;
uint8_t sc_itf_to_usb_itf(uint8_t itf) { static uint8_t sc_itf_to_usb_itf(uint8_t itf) {
if (itf == ITF_SC_CCID) { if (itf == ITF_SC_CCID) {
return ITF_CCID; return ITF_CCID;
} }
@@ -121,7 +122,7 @@ uint8_t sc_itf_to_usb_itf(uint8_t itf) {
return itf; return itf;
} }
void ccid_init_buffers() { static void ccid_init_buffers(void) {
if (ITF_SC_TOTAL == 0) { if (ITF_SC_TOTAL == 0) {
return; return;
} }
@@ -142,7 +143,7 @@ void ccid_init_buffers() {
} }
} }
int driver_init_ccid(uint8_t itf) { static int driver_init_ccid(uint8_t itf) {
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr); 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); ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
// apdu.header = &ccid_header->apdu; // apdu.header = &ccid_header->apdu;
@@ -153,10 +154,12 @@ int driver_init_ccid(uint8_t itf) {
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0; //ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
return PICOKEY_OK; return PICOKEYS_OK;
} }
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) { void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
(void)buffer;
(void)bufsize;
uint32_t len = tud_vendor_n_available(itf); uint32_t len = tud_vendor_n_available(itf);
do { do {
uint16_t tlen = 0; uint16_t tlen = 0;
@@ -173,27 +176,27 @@ void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
} while (len > 0); } while (len > 0);
} }
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) { static int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
if (*tx_buffer != 0x81) { if (*tx_buffer != 0x81) {
DEBUG_PAYLOAD(tx_buffer, buffer_size); DEBUG_PAYLOAD(tx_buffer, buffer_size);
} }
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size); uint32_t written = tud_vendor_n_write(itf, tx_buffer, buffer_size);
if (r > 0) { if (written > 0) {
tud_vendor_n_flush(itf); tud_vendor_n_write_flush(itf);
ccid_tx[itf].r_ptr += (uint16_t)buffer_size; ccid_tx[itf].r_ptr += (uint16_t)written;
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) { if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0; ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
} }
} }
#ifdef ENABLE_EMULATION #ifdef ENABLE_EMULATION
tud_vendor_tx_cb(itf, r); tud_vendor_tx_cb(itf, written);
#endif #endif
return r; return (int)written;
} }
int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) { static int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
return driver_write_ccid(itf, buffer, buffer_size); return driver_write_ccid(itf, buffer, buffer_size);
} }
@@ -201,6 +204,20 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
(void) rx_read; (void) rx_read;
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) { if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
driver_init_ccid(itf); driver_init_ccid(itf);
if (ccid_header[itf]->dwLength > USB_BUFFER_SIZE - 10) {
//Invalid length
ccid_rx[itf].r_ptr = ccid_rx[itf].w_ptr = 0;
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = 2;
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;
memcpy(&ccid_resp_fast[itf]->apdu, "\x6F\x00", 2);
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 12);
return 0;
}
//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); //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)){ 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); ccid_rx[itf].r_ptr += (uint16_t)(ccid_header[itf]->dwLength + 10);
@@ -302,7 +319,7 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
return 0; return 0;
} }
void driver_exec_timeout_ccid(uint8_t itf) { static void driver_exec_timeout_ccid(uint8_t itf) {
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET; ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
ccid_resp_fast[itf]->dwLength = 0; ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0; ccid_resp_fast[itf]->bSlot = 0;
@@ -327,13 +344,13 @@ void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t of
ccid_write_offset(itf, size_next+10, offset); ccid_write_offset(itf, size_next+10, offset);
} }
void ccid_task() { void ccid_task(void) {
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) { for (uint8_t itf = 0; itf < ITF_SC_TOTAL; itf++) {
int status = card_status(sc_itf_to_usb_itf(itf)); int status = card_status(sc_itf_to_usb_itf(itf));
if (status == PICOKEY_OK) { if (status == PICOKEYS_OK) {
driver_exec_finished_ccid(itf, finished_data_size); driver_exec_finished_ccid(itf, finished_data_size);
} }
else if (status == PICOKEY_ERR_BLOCKED) { else if (status == PICOKEYS_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf); driver_exec_timeout_ccid(itf);
} }
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) { if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
@@ -344,17 +361,17 @@ void ccid_task() {
} }
} }
void ccid_init() { void ccid_init(void) {
ccid_init_buffers(); ccid_init_buffers();
} }
#ifndef ENABLE_EMULATION
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) { void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
(void) sent_bytes; (void) sent_bytes;
tud_vendor_n_write_flush(itf); tud_vendor_n_write_flush(itf);
} }
#ifndef ENABLE_EMULATION
static void ccid_init_cb(void) { static void ccid_init_cb(void) {
vendord_init(); vendord_init();
} }
@@ -378,7 +395,11 @@ static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)((uint8_t *)itf_desc + drv_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); TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
uint8_t msg[] = { 0x50, 0x03 }; uint8_t msg[] = { 0x50, 0x03 };
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg)); usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg));
#else
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg), sizeof(msg));
#endif
#else #else
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len); vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
#endif #endif

View File

@@ -3,16 +3,16 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _CCID_H_ #ifndef _CCID_H_
@@ -40,4 +40,30 @@ enum ccid_state {
extern const uint8_t *ccid_atr; extern const uint8_t *ccid_atr;
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 //_CCID_H_ #endif //_CCID_H_

View File

@@ -3,18 +3,25 @@
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * Affero 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifdef _MSC_VER
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#endif
#include "emulation.h" #include "emulation.h"
#include <stdio.h> #include <stdio.h>
#ifndef _MSC_VER #ifndef _MSC_VER
@@ -29,7 +36,6 @@ typedef int socket_t;
#define INVALID_SOCKET (-1) #define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1) #define SOCKET_ERROR (-1)
#else #else
#include <ws2tcpip.h>
#define O_NONBLOCK _O_NONBLOCK #define O_NONBLOCK _O_NONBLOCK
#define close closesocket #define close closesocket
typedef SOCKET socket_t; typedef SOCKET socket_t;
@@ -41,7 +47,6 @@ typedef int socklen_t;
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include "pico_keys.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
#include "ccid/ccid.h" #include "ccid/ccid.h"
@@ -59,8 +64,18 @@ uint16_t emul_rx_size = 0, emul_tx_size = 0;
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len); extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
pthread_t hcore0, hcore1; pthread_t hcore0, hcore1;
#ifdef _MSC_VER
static void log_sock_error(const char *ctx) {
fprintf(stderr, "%s failed (WSAGetLastError=%d)\n", ctx, WSAGetLastError());
}
#else
static void log_sock_error(const char *ctx) {
fprintf(stderr, "%s failed (errno=%d)\n", ctx, errno);
}
#endif
#ifndef _MSC_VER #ifndef _MSC_VER
int msleep(long msec) { static int msleep(long msec) {
struct timespec ts; struct timespec ts;
int res; int res;
@@ -80,7 +95,7 @@ int msleep(long msec) {
} }
#endif #endif
int emul_init(char *host, uint16_t port) { int emul_init(const char *host, uint16_t port) {
struct sockaddr_in serv_addr; struct sockaddr_in serv_addr;
fprintf(stderr, "\n Starting emulation envionrment\n"); fprintf(stderr, "\n Starting emulation envionrment\n");
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -90,7 +105,7 @@ int emul_init(char *host, uint16_t port) {
} }
#endif #endif
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket"); log_sock_error("socket(ccid)");
return -1; return -1;
} }
@@ -100,13 +115,13 @@ int emul_init(char *host, uint16_t port) {
// Convert IPv4 and IPv6 addresses from text to binary // Convert IPv4 and IPv6 addresses from text to binary
// form // form
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) { if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
perror("inet_pton"); log_sock_error("inet_pton(ccid)");
close(ccid_sock); close(ccid_sock);
return -1; return -1;
} }
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect"); log_sock_error("connect(ccid)");
close(ccid_sock); close(ccid_sock);
return -1; return -1;
} }
@@ -129,12 +144,12 @@ int emul_init(char *host, uint16_t port) {
struct sockaddr_in server_sockaddr; struct sockaddr_in server_sockaddr;
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket"); log_sock_error("socket(hid_server)");
return -1; return -1;
} }
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) { if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
perror("setsockopt"); log_sock_error("setsockopt(SO_REUSEADDR)");
close(hid_server_sock); close(hid_server_sock);
return 1; return 1;
} }
@@ -154,20 +169,21 @@ int emul_init(char *host, uint16_t port) {
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr, if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
sizeof server_sockaddr) != 0) { sizeof server_sockaddr) != 0) {
perror("bind"); log_sock_error("bind(hid_server)");
close(hid_server_sock); close(hid_server_sock);
return 1; return 1;
} }
if (listen(hid_server_sock, 0) != 0) { if (listen(hid_server_sock, SOMAXCONN) != 0) {
perror("listen"); log_sock_error("listen(hid_server)");
close(hid_server_sock); close(hid_server_sock);
return 1; return 1;
} }
fprintf(stderr, "HID server listening on 0.0.0.0:%u\n", hid_port);
return 0; return 0;
} }
socket_t get_sock_itf(uint8_t itf) { static socket_t get_sock_itf(uint8_t itf) {
#ifdef USB_ITF_CCID #ifdef USB_ITF_CCID
if (itf == ITF_CCID) { if (itf == ITF_CCID) {
return ccid_sock; return ccid_sock;
@@ -200,7 +216,11 @@ uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_s
uint16_t size = htons(buffer_size); uint16_t size = htons(buffer_size);
socket_t sock = get_sock_itf(itf); socket_t sock = get_sock_itf(itf);
// DEBUG_PAYLOAD(buffer,buffer_size); // DEBUG_PAYLOAD(buffer,buffer_size);
#ifdef _WIN32
int ret = 0; int ret = 0;
#else
ssize_t ret = 0;
#endif
do { do {
ret = send(sock, (const char *)&size, sizeof(size), 0); ret = send(sock, (const char *)&size, sizeof(size), 0);
if (ret == SOCKET_ERROR) { if (ret == SOCKET_ERROR) {
@@ -279,7 +299,11 @@ uint16_t emul_read(uint8_t itf) {
__pragma(warning(pop)) __pragma(warning(pop))
#endif #endif
struct timeval timeout; struct timeval timeout;
#ifdef _WIN32
int valread = 0; int valread = 0;
#else
ssize_t valread = 0;
#endif
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 0 * 1000; timeout.tv_usec = 0 * 1000;
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout); int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
@@ -320,7 +344,7 @@ uint16_t emul_read(uint8_t itf) {
} }
#endif #endif
else { else {
emul_rx_size += valread; emul_rx_size += (uint16_t)valread;
} }
return (uint16_t)emul_rx_size; return (uint16_t)emul_rx_size;
} }
@@ -333,7 +357,7 @@ uint16_t emul_read(uint8_t itf) {
return emul_rx_size; return emul_rx_size;
} }
void emul_task() { void emul_task(void) {
#ifdef USB_ITF_CCID #ifdef USB_ITF_CCID
emul_read(ITF_CCID); emul_read(ITF_CCID);
#endif #endif

Some files were not shown because too many files have changed in this diff Show More