179 Commits
v8.0 ... main

Author SHA1 Message Date
Pol Henarejos
d7fb22d39a Added trusted region.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-08 16:40:58 +02:00
Pol Henarejos
8a87b0d2de Fix options macro in case an arg is disabled.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-08 12:08:33 +02:00
Pol Henarejos
5fd26200ea Refactor HWRNG to be less blocking.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-08 12:08:28 +02:00
Pol Henarejos
0245933224 Emit completed if timeout is 0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 19:33:19 +02:00
Pol Henarejos
13d2e84595 Harden cross-core shared completion state 2026-06-01 13:36:59 +02:00
Pol Henarejos
f8338f0d01 Reduce BOOTSEL polling frequency in wait loop
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 13:36:52 +02:00
Pol Henarejos
018d4e6ff1 Rate-limit core0 card_status polling loops 2026-06-01 13:35:35 +02:00
Pol Henarejos
b13e2ebe15 Avoid blocking under mutex in usb_send_event 2026-06-01 13:35:25 +02:00
Pol Henarejos
2ed315cd81 Replace startup busy-spins with bounded retries 2026-06-01 13:35:15 +02:00
Pol Henarejos
9611a81898 Add core0 loop yield hint 2026-06-01 13:34:57 +02:00
Pol Henarejos
49edef1d3f Add cancel button event.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 01:40:31 +02:00
Pol Henarejos
eb26a96d3b Add button signals.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-31 20:09:28 +02:00
Pol Henarejos
d711f33721 Add signals
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-31 18:54:22 +02:00
Pol Henarejos
1a289db1cd Fix otp first build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-29 11:36:40 +02:00
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
120 changed files with 13590 additions and 2215 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).
# 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/>.
#
#
# 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/>.
#
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.16)
if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(USB_ITF_CCID 1)
#set(USB_ITF_HID 1)
include(pico_keys_sdk_import.cmake)
project(pico_keys_sdk)
set(EXTRA_COMPONENT_DIRS src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
if(NOT ENABLE_EMULATION)
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake)
endif()
if(ENABLE_EMULATION)
else()
include(pico_sdk_import.cmake)
endif()
project(pico_rescue C CXX ASM)
project(pico_keys C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if(NOT DEFINED __FOR_CI)
set(__FOR_CI 0)
endif()
if(__FOR_CI)
add_compile_definitions(__FOR_CI)
endif()
if(ENABLE_EMULATION)
else()
pico_sdk_init()
endif()
if (NOT DEFINED __FOR_CI)
set(__FOR_CI 0)
endif()
if (__FOR_CI)
add_definitions(-D__FOR_CI)
endif()
add_executable(pico_rescue)
endif()
set(USB_ITF_CCID 1)
set(USB_ITF_HID 1)
include(pico_keys_sdk_import.cmake)
add_executable(pico_keys_sdk_exe)
target_compile_options(pico_keys_sdk_exe PUBLIC
-Wall
-Werror
set(USB_ITF_WCID 1)
include(cmake/version.cmake)
include(cmake/options.cmake OPTIONAL)
include(picokeys_sdk_import.cmake)
if(NOT ESP_PLATFORM)
set(SOURCES ${PICOKEYS_SOURCES})
endif()
list(APPEND SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
${CMAKE_CURRENT_LIST_DIR}/src/version.c
)
if(ENABLE_EMULATION)
target_compile_options(pico_keys_sdk_exe PUBLIC
-fdata-sections
-ffunction-sections
)
if(APPLE)
target_link_options(pico_keys_sdk_exe PUBLIC
-Wl,-dead_strip
)
else()
target_link_options(pico_keys_sdk_exe PUBLIC
-Wl,--gc-sections
)
endif (APPLE)
else()
pico_add_extra_outputs(pico_keys_sdk_exe)
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/picokeys_version.h")
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()
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()

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

10
cmake/options.cmake Normal file
View File

@@ -0,0 +1,10 @@
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()
message(STATUS "${disabled_msg}")
endif()
endmacro()

View File

@@ -1,39 +1,39 @@
macro(HEXCHAR2DEC VAR VAL)
if(${VAL} MATCHES "[0-9]")
SET(${VAR} ${VAL})
set(${VAR} ${VAL})
elseif(${VAL} MATCHES "[aA]")
SET(${VAR} 10)
set(${VAR} 10)
elseif(${VAL} MATCHES "[bB]")
SET(${VAR} 11)
set(${VAR} 11)
elseif(${VAL} MATCHES "[cC]")
SET(${VAR} 12)
set(${VAR} 12)
elseif(${VAL} MATCHES "[dD]")
SET(${VAR} 13)
set(${VAR} 13)
elseif(${VAL} MATCHES "[eE]")
SET(${VAR} 14)
set(${VAR} 14)
elseif(${VAL} MATCHES "[fF]")
SET(${VAR} 15)
set(${VAR} 15)
else()
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
message(FATAL_ERROR "Invalid format for hexidecimal character")
endif()
endmacro(HEXCHAR2DEC)
endmacro()
macro(HEX2DEC VAR VAL)
SET(CURINDEX 0)
STRING(LENGTH "${VAL}" CURLENGTH)
SET(${VAR} 0)
set(CURINDEX 0)
string(LENGTH "${VAL}" CURLENGTH)
set(${VAR} 0)
while(CURINDEX LESS CURLENGTH)
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
string(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
HEXCHAR2DEC(CHAR ${CHAR})
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
MATH(EXPR CURINDEX "${CURINDEX}+1")
math(EXPR POWAH "(1 << ((${CURLENGTH} - ${CURINDEX} - 1) * 4))")
math(EXPR CHAR "(${CHAR} * ${POWAH})")
math(EXPR ${VAR} "${${VAR}} + ${CHAR}")
math(EXPR CURINDEX "${CURINDEX} + 1")
endwhile()
endmacro(HEX2DEC)
endmacro()
macro(SET_VERSION MAJOR MINOR FILE)
set(ROLLBACK 4)
file(READ ${FILE} ver)
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
@@ -42,8 +42,22 @@ macro(SET_VERSION MAJOR MINOR FILE)
HEX2DEC(ver_minor ${ver_minor})
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
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()
SET(${MAJOR} ${ver_major})
SET(${MINOR} ${ver_minor})
endmacro(SET_VERSION)
set(${MAJOR} ${ver_major})
set(${MINOR} ${ver_minor})
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
dependencies:
espressif/esp_tinyusb: "^1.7.2"
espressif/esp_tinyusb: "^1.7.6"
#espressif/tinyusb: "^0.15.0"
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
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M,
nvs, data, nvs, 0x11000, 0x6000
phy_init, data, phy, 0x17000, 0x1000
factory, app, factory, 0x20000, 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_SHA1_ALT
#ifdef PICO_RP2350
#define MBEDTLS_SHA256_ALT
//#define MBEDTLS_SHA256_ALT
#endif
//#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

@@ -286,3 +286,9 @@ int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
}
return 0;
}
void mbedtls_sha256_clone(mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src)
{
*dst = *src;
}

View File

@@ -18,7 +18,6 @@
#ifndef _SHA256_ALT_H_
#define _SHA256_ALT_H_
#include "pico_keys.h"
#include "pico/sha256.h"
typedef struct mbedtls_sha256_context {

View File

@@ -10,7 +10,7 @@
},
"partitions": [
{
"name": "Pico Keys Firmware",
"name": "PicoKeys Firmware",
"id": 0,
"start": 0,
"size": "1024K",
@@ -22,10 +22,10 @@
}
},
{
"name": "Pico Keys Data",
"name": "PicoKeys Data",
"id": 1,
"start": "1024K",
"size": "3072K",
"start": "1032K",
"size": "3064K",
"families": ["data"],
"permissions": {
"secure": "rw",
@@ -35,6 +35,21 @@
"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],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
}
]
}

Submodule mbedtls deleted from 107ea89daa

View File

@@ -1,449 +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.5")
endif()
execute_process(
COMMAND git config --global --add safe.directory ${MBEDTLS_PATH}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} submodule update --init --recursive pico-keys-sdk
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} remote get-url origin
OUTPUT_VARIABLE CURRENT_ORIGIN
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT "${CURRENT_ORIGIN}" STREQUAL "${MBEDTLS_ORIGIN}")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} remote set-url origin ${MBEDTLS_ORIGIN}
OUTPUT_QUIET ERROR_QUIET
)
endif()
execute_process(
COMMAND git -C ${MBEDTLS_PATH} rev-parse --verify ${MBEDTLS_REF}
OUTPUT_VARIABLE CURRENT_REF
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE REF_EXISTS
)
if(NOT REF_EXISTS EQUAL 0 OR NOT CURRENT_REF STREQUAL "${MBEDTLS_REF}")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} fetch origin +refs/heads/*:refs/remotes/origin/* --tags --force
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND rm -rf ${MBEDTLS_PATH}/framework
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
if(ENABLE_EDDSA)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout -B ${MBEDTLS_REF} --track origin/${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
else()
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout ${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
endif()
endif()
endif(NOT ESP_PLATFORM)
set(MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum_core.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkcs5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
)
if (ENABLE_EDDSA)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/eddsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha3.c
)
endif()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/otp.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
)
if(ESP_PLATFORM)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c)
else()
if (NOT ENABLE_EMULATION)
set(PICO_KEYS_SOURCES ${PICO_KEYS_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}/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 (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")
set(LIBRARIES ${LIBRARIES} pico_cyw43_arch_none)
set(IS_CYW43 1)
endif()
endif()
function(add_impl_library target)
add_library(${target} INTERFACE)
string(TOUPPER ${target} TARGET_UPPER)
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
endfunction()
if(USB_ITF_HID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
)
endif()
if(USB_ITF_CCID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
)
endif()
if(NOT MSVC)
add_definitions("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
endif()
if(MSVC)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
)
endif()
if(ENABLE_EMULATION)
if(APPLE)
add_definitions("-Wno-deprecated-declarations")
endif()
add_definitions(-DENABLE_EMULATION)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aesni.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
)
else()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
)
endif()
set(EXTERNAL_SOURCES ${CBOR_SOURCES})
if(NOT ESP_PLATFORM)
set(EXTERNAL_SOURCES ${EXTERNAL_SOURCES} ${MBEDTLS_SOURCES})
endif()
if(MSVC)
set(
CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -wd4820 -wd4255 -wd5045 -wd4706 -wd4061 -wd5105 -wd4141 -wd4200"
)
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)
set_source_files_properties(
${EXTERNAL_SOURCES}
PROPERTIES
COMPILE_FLAGS " -W3 -wd4242 -wd4065"
)
endif()
if(PICO_PLATFORM)
pico_sdk_init()
endif()
if(PICO_RP2350)
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
if (NOT IS_CYW43)
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
endif()
if (SECURE_BOOT_PKEY)
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
pico_hash_binary(${CMAKE_PROJECT_NAME})
endif()
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
)
set(LIBRARIES ${LIBRARIES} pico_sha256)
endif()
set(INTERNAL_SOURCES ${PICO_KEYS_SOURCES})
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${EXTERNAL_SOURCES})
if(NOT TARGET pico_keys_sdk)
if(PICO_PLATFORM)
pico_add_library(pico_keys_sdk)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
else()
add_impl_library(pico_keys_sdk)
endif()
target_sources(pico_keys_sdk INTERFACE ${PICO_KEYS_SOURCES})
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
endif()

796
picokeys_sdk_import.cmake Normal file
View File

@@ -0,0 +1,796 @@
#
# 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
${CMAKE_CURRENT_LIST_DIR}/src/signal.c
${CMAKE_CURRENT_LIST_DIR}/src/trusted.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)
if(ESP_PLATFORM OR ENABLE_EMULATION OR NOT PICO_PLATFORM)
list(APPEND LIBRARIES mbedtls)
endif()
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)
if(PICO_PLATFORM AND NOT ENABLE_EMULATION)
set(TRUSTED_MBEDTLS_ARCHIVE ${CMAKE_CURRENT_BINARY_DIR}/libtrusted_mbedtls.a)
add_custom_command(
OUTPUT ${TRUSTED_MBEDTLS_ARCHIVE}
COMMAND ${CMAKE_COMMAND} -E rm -f ${TRUSTED_MBEDTLS_ARCHIVE}
COMMAND ${CMAKE_OBJCOPY} --prefix-alloc-sections=.trusted $<TARGET_FILE:mbedtls> ${TRUSTED_MBEDTLS_ARCHIVE}
DEPENDS mbedtls
VERBATIM
)
add_custom_target(trusted_mbedtls_archive DEPENDS ${TRUSTED_MBEDTLS_ARCHIVE})
add_library(trusted_mbedtls STATIC IMPORTED GLOBAL)
add_dependencies(trusted_mbedtls trusted_mbedtls_archive)
set_target_properties(trusted_mbedtls PROPERTIES
IMPORTED_LOCATION ${TRUSTED_MBEDTLS_ARCHIVE}
)
add_compile_definitions(PICOKEYS_HAS_TRUSTED_REGION=1)
elseif(ENABLE_EMULATION AND NOT MSVC)
set(TRUSTED_REGION_EMBED_INPUT
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}mbedtls${CMAKE_STATIC_LIBRARY_SUFFIX}
)
if(APPLE)
set(PICOKEYS_TRUSTED_SECTION_DIRECTIVE ".section __DATA,__trusted_region,regular,no_dead_strip")
set(PICOKEYS_TRUSTED_START_SYM "___trusted_start")
set(PICOKEYS_TRUSTED_END_SYM "___trusted_end")
set(PICOKEYS_TRUSTED_LOAD_START_SYM "___trusted_load_start")
set(PICOKEYS_TRUSTED_LOAD_END_SYM "___trusted_load_end")
else()
set(PICOKEYS_TRUSTED_SECTION_DIRECTIVE ".section .trusted_region,\"a\",@progbits")
set(PICOKEYS_TRUSTED_START_SYM "__trusted_start")
set(PICOKEYS_TRUSTED_END_SYM "__trusted_end")
set(PICOKEYS_TRUSTED_LOAD_START_SYM "__trusted_load_start")
set(PICOKEYS_TRUSTED_LOAD_END_SYM "__trusted_load_end")
endif()
set(TRUSTED_REGION_EMBED_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/trusted_region_embed.S)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/src/trusted_region_embed.in.S
${TRUSTED_REGION_EMBED_SOURCE}
@ONLY
)
add_compile_definitions(PICOKEYS_HAS_TRUSTED_REGION=1)
endif()
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(ESP_PLATFORM AND NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
add_library(trusted_mbedtls_payload STATIC ${MBEDTLS_SOURCES})
target_include_directories(trusted_mbedtls_payload
SYSTEM PRIVATE
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
)
set(TRUSTED_REGION_EMBED_INPUT
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}trusted_mbedtls_payload${CMAKE_STATIC_LIBRARY_SUFFIX}
)
set(PICOKEYS_TRUSTED_SECTION_DIRECTIVE ".section .rodata.trusted_region,\"a\",@progbits")
set(PICOKEYS_TRUSTED_START_SYM "__trusted_start")
set(PICOKEYS_TRUSTED_END_SYM "__trusted_end")
set(PICOKEYS_TRUSTED_LOAD_START_SYM "__trusted_load_start")
set(PICOKEYS_TRUSTED_LOAD_END_SYM "__trusted_load_end")
set(TRUSTED_REGION_EMBED_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/trusted_region_embed.S)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/src/trusted_region_embed.in.S
${TRUSTED_REGION_EMBED_SOURCE}
@ONLY
)
add_compile_definitions(PICOKEYS_HAS_TRUSTED_REGION=1)
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(DEFINED TRUSTED_REGION_EMBED_SOURCE)
set_source_files_properties(${TRUSTED_REGION_EMBED_SOURCE} PROPERTIES
OBJECT_DEPENDS "${TRUSTED_REGION_EMBED_INPUT}"
)
list(APPEND PICOKEYS_SOURCES
${TRUSTED_REGION_EMBED_SOURCE}
)
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(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()
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_headers)
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)
if(TARGET trusted_mbedtls)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,--whole-archive"
trusted_mbedtls
"-Wl,--no-whole-archive"
)
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"LINKER:-T,${CMAKE_CURRENT_LIST_DIR}/../trusted_region.ld"
)
set_property(TARGET ${CMAKE_PROJECT_NAME} APPEND PROPERTY LINK_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/../trusted_region.ld
)
endif()
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_MODE_PERF=y
COMPILER_OPTIMIZATION="Performance"
CONFIG_MBEDTLS_HKDF_C=y

View File

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

View File

@@ -15,12 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "apdu.h"
#include "pico_keys.h"
#include "led/led.h"
#include "usb.h"
#include <stdio.h>
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#include "compat/esp_compat.h"
#endif
#ifdef ENABLE_EMULATION
#include "emulation.h"
@@ -30,16 +31,23 @@ uint8_t *rdata_gr = NULL;
uint16_t rdata_bk = 0x0;
extern uint32_t timeout;
bool is_chaining = false;
uint8_t chain_buf[4096];
uint8_t chain_buf[2038];
uint8_t *chain_ptr = NULL;
int process_apdu() {
struct apdu apdu;
int process_apdu(void) {
led_set_mode(MODE_PROCESSING);
if (CLA(apdu) & 0x10) {
size_t chain_used = 0;
if (!is_chaining) {
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();
}
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);
memcpy(apdu.data, chain_buf, 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;
}
}
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_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) {
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) {
apdu.ne = 65536;
}
}
else {
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;
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) {
apdu.ne = 65536;
}
@@ -176,11 +186,11 @@ 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) {
apdu.sw = make_uint16_t_be(sw1, sw2);
apdu.sw = make_uint16_be(sw1, sw2);
if (sw1 != 0x90) {
res_APDU_size = 0;
}
return make_uint16_t_be(sw1, sw2);
return make_uint16_be(sw1, sw2);
}
void *apdu_thread(void *arg) {
@@ -190,7 +200,9 @@ void *apdu_thread(void *arg) {
uint32_t m = 0;
queue_remove_blocking(&usb_to_card_q, &m);
uint32_t flag = m + 1;
queue_add_blocking(&card_to_usb_q, &flag);
if (m != EV_CMD_AVAILABLE) {
queue_add_blocking(&card_to_usb_q, &flag);
}
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
set_res_sw(0x6f, 0x00);
@@ -220,8 +232,8 @@ done: ;
return NULL;
}
void apdu_finish() {
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen);
void apdu_finish(void) {
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
// timeout_stop();
#ifndef ENABLE_EMULATION
/* It was fixed in the USB handling. Keep it just in case */
@@ -231,7 +243,7 @@ void apdu_finish() {
#endif
}
uint16_t apdu_next() {
uint16_t apdu_next(void) {
if (apdu.sw != 0) {
if (apdu.rlen <= apdu.ne) {
return apdu.rlen + 2;
@@ -252,3 +264,30 @@ uint16_t apdu_next() {
}
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

@@ -18,20 +18,16 @@
#ifndef _APDU_H_
#define _APDU_H_
#include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#endif
#include "compat.h"
#include <stdio.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "compat/compat.h"
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
int (*process_apdu)(void);
int (*select_aid)(struct app *, uint8_t);
int (*unload)();
int (*unload)(void);
} app_t;
extern bool app_exists(const uint8_t *aid, size_t aid_len);
@@ -40,7 +36,7 @@ extern int select_app(const uint8_t *aid, size_t aid_len);
typedef struct cmd {
uint8_t ins;
int (*cmd_handler)();
int (*cmd_handler)(void);
} cmd_t;
extern uint8_t num_apps;
@@ -69,10 +65,69 @@ PACK(struct apdu {
extern struct apdu apdu;
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 void apdu_finish();
extern uint16_t apdu_next();
extern void apdu_finish(void);
extern uint16_t apdu_next(void);
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

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 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 _ASN1_H_
#define _ASN1_H_
#include <stdlib.h>
#if defined(PICO_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

187
src/button.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* 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"
#include "signal.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;
bool touch_accept_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;
int 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) {
signal_emit(SIGNAL_USER_PRESENCE_COMPLETED);
return 0;
}
signal_user_presence_request_data_t data = {
.timeout = button_timeout / 1000,
};
signal_emit_param(SIGNAL_USER_PRESENCE_REQUEST, &data);
uint32_t start_button = board_millis();
const uint32_t button_poll_interval_ms = 2;
uint32_t next_button_poll_ms = start_button;
bool button_pressed = picok_board_button_read();
bool timeout = false;
cancel_button = false;
uint32_t led_mode = led_get_mode();
led_set_mode(MODE_BUTTON);
req_button_pending = true;
while (button_pressed == false && cancel_button == false) {
execute_tasks();
uint32_t now = board_millis();
if (now >= next_button_poll_ms) {
button_pressed = picok_board_button_read();
next_button_poll_ms = now + button_poll_interval_ms;
}
//sleep_ms(10);
if (start_button + button_timeout < now) { /* timeout */
timeout = true;
break;
}
}
if (!timeout) {
while (button_pressed == true && cancel_button == false) {
execute_tasks();
uint32_t now = board_millis();
if (now >= next_button_poll_ms) {
button_pressed = picok_board_button_read();
next_button_poll_ms = now + button_poll_interval_ms;
}
//sleep_ms(10);
if (start_button + 15000 < now) { /* timeout */
timeout = true;
break;
}
}
}
led_set_mode(led_mode);
req_button_pending = false;
if (timeout) {
signal_emit(SIGNAL_USER_PRESENCE_TIMEOUT);
return 1;
}
else if (cancel_button) {
signal_emit(SIGNAL_USER_PRESENCE_CANCELLED);
return 2;
}
signal_emit(SIGNAL_USER_PRESENCE_COMPLETED);
return 0;
}
#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
}

33
src/button.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 BUTTON_H
#define BUTTON_H
#include <stdint.h>
#include <stdbool.h>
#if defined(ESP_PLATFORM)
#define BOOT_PIN GPIO_NUM_0
#endif
extern int button_wait(void);
extern void button_task(void);
extern bool cancel_button;
extern bool touch_accept_button;
#endif // BUTTON_H

View File

@@ -18,6 +18,7 @@
#ifndef _BOARD_H_
#define _BOARD_H_
#include <stdint.h>
#ifdef _MSC_VER
#include <windows.h>
struct timezone;
@@ -26,10 +27,11 @@ extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
#include <sys/time.h>
#endif
static inline uint32_t board_millis() {
static inline uint32_t board_millis(void) {
struct timeval start;
gettimeofday(&start, NULL);
return start.tv_sec * 1000 + start.tv_usec / 1000;
uint64_t ms = (uint64_t)start.tv_sec * 1000ULL + (uint64_t)start.tv_usec / 1000ULL;
return (uint32_t)ms;
}
#endif // _BOARD_H_

View File

@@ -21,6 +21,7 @@
#define _PTHREAD_H_
#include <windows.h>
#include <stdint.h>
#include <stdlib.h>
typedef HANDLE pthread_t;
typedef CRITICAL_SECTION pthread_mutex_t;
@@ -51,6 +52,11 @@ static inline int pthread_mutex_destroy(pthread_mutex_t *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;

View File

@@ -19,8 +19,8 @@
#define QUEUE_H
#ifdef _MSC_VER
#include "pthread_win32.h"
#include "semaphore_win32.h"
#include "compat/pthread_win32.h"
#include "compat/semaphore_win32.h"
#else
#include <pthread.h>
#include <semaphore.h>
@@ -34,6 +34,9 @@ typedef struct {
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) {

View File

@@ -15,31 +15,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(PICO_PLATFORM)
#include <pico/unique_id.h>
#endif
#include "picokeys.h"
#include "serial.h"
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/gcm.h"
#include "mbedtls/base64.h"
#include "crypto_utils.h"
#include "pico_keys.h"
#include "otp.h"
#include "random.h"
#include <stdio.h>
int ct_memcmp(const void *a, const void *b, size_t n) {
const volatile uint8_t *x = (const volatile uint8_t *)a;
const volatile uint8_t *y = (const volatile uint8_t *)b;
uint8_t r = 0;
for (size_t i = 0; i < n; ++i) {
r |= x[i] ^ y[i];
}
return r;
}
static const mbedtls_md_info_t *SHA256(void) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
@@ -80,21 +66,38 @@ 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, uint8_t *out_buf) {
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_gen(NULL, nonce, 12);
random_fill_buffer(nonce, 12);
mbedtls_gcm_context gcm;
mbedtls_gcm_init(&gcm);
uint8_t kenc[32];
pin_derive_kenc(key, kenc);
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) {
@@ -111,24 +114,33 @@ int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len
// 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, uint8_t *out_buf) {
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;
mbedtls_gcm_init(&gcm);
uint8_t kenc[32];
pin_derive_kenc(key, kenc);
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
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 (rc != 0) {
return rc;
if (ret != 0) {
return ret;
}
rc = mbedtls_gcm_auth_decrypt(&gcm, in_len - 16 - 12, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), tag, 16, ct, out_buf);
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 rc;
return ret;
}
// Old functions, kept for compatibility. NOT SECURE, use the new ones above.
@@ -141,7 +153,6 @@ void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
hash_multi(o1, sizeof(o1), output);
}
void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
@@ -188,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);
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) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
int rc = 0;
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) {
@@ -207,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);
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) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
int rc = 0;
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
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
else {
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) {
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) {
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;
uint8_t len;
};
});
struct ec_curve_mbed_id {
PACK(struct ec_curve_mbed_id {
struct lv_data curve;
mbedtls_ecp_group_id id;
};
});
struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
@@ -278,3 +310,84 @@ mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_
}
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

@@ -21,32 +21,40 @@
#include "mbedtls/ecp.h"
#include "mbedtls/md.h"
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask
#define PICO_KEYS_KEY_RSA_1K 0x0001
#define PICO_KEYS_KEY_RSA_2K 0x0002
#define PICO_KEYS_KEY_RSA_3K 0x0004
#define PICO_KEYS_KEY_RSA_4k 0x0008
#define PICO_KEYS_KEY_EC 0x0010
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
#define PICO_KEYS_KEY_AES_128 0x0100
#define PICO_KEYS_KEY_AES_192 0x0200
#define PICO_KEYS_KEY_AES_256 0x0400
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
#define PICOKEYS_KEY_RSA 0x000f // It is a mask
#define PICOKEYS_KEY_RSA_1K 0x0001
#define PICOKEYS_KEY_RSA_2K 0x0002
#define PICOKEYS_KEY_RSA_3K 0x0004
#define PICOKEYS_KEY_RSA_4k 0x0008
#define PICOKEYS_KEY_EC 0x0010
#define PICOKEYS_KEY_AES 0x0f00 // It is a mask
#define PICOKEYS_KEY_AES_128 0x0100
#define PICOKEYS_KEY_AES_192 0x0200
#define PICOKEYS_KEY_AES_256 0x0400
#define PICOKEYS_KEY_AES_512 0x0800 /* For AES XTS */
#define PICO_KEYS_AES_MODE_CBC 1
#define PICO_KEYS_AES_MODE_CFB 2
#define PICOKEYS_AES_MODE_CBC 1
#define PICOKEYS_AES_MODE_CFB 2
#define IV_SIZE 16
extern int ct_memcmp(const void *a, const void *b, size_t n);
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, uint8_t *out_buf);
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf);
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 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]);
@@ -56,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_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 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

View File

@@ -19,32 +19,53 @@
#define _DEBUG_H_
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
#define DEBUG_PAYLOAD(_p, _s) { \
printf("Payload %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
for (size_t _i = 0; _i < (size_t)(_s); _i += 16) { \
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
for (size_t _j = 0; _j < 16; _j++) { \
if (_j < (size_t)(_s) - _i) printf("%02X ", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} printf(": "); \
for (size_t _j = 0; _j < 16; _j++) { \
if (_j < (size_t)(_s) - _i && (_p)[_i + _j] > 32 && (_p)[_i + _j] != 127 && (_p)[_i + _j] < 176) printf("%c", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} \
printf("\n"); \
} printf("\n"); \
}
#define DEBUG_DATA(_p, _s) { \
printf("Data %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
char *_tmp = (char *) calloc(2 * (_s) + 1, sizeof(char)); \
for (size_t _i = 0; _i < (size_t)(_s); _i++) { \
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
} \
printf("%s\n", _tmp); \
free(_tmp); \
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
static inline void debug_payload_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
printf("Payload %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
for (size_t i = 0; i < s; i += 16) {
printf("%" PRIxPTR "h : ", (uintptr_t)(p + i));
for (size_t j = 0; j < 16; j++) {
if (j < s - i) {
printf("%02X ", p[i + j]);
}
else {
printf(" ");
}
if (j == 7) {
printf(" ");
}
}
printf(": ");
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]);
}
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
#define DEBUG_PAYLOAD(_p, _s)

125
src/eac.c
View File

@@ -15,12 +15,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "eac.h"
#include "crypto_utils.h"
#include "random.h"
#include "mbedtls/cmac.h"
#include "asn1.h"
#include "tlv.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_kmac[16];
@@ -29,19 +35,13 @@ static MSE_protocol sm_protocol = MSE_NONE;
static mbedtls_mpi sm_mSSC;
static uint8_t sm_blocksize = 0;
static uint8_t sm_iv[16];
uint16_t sm_session_pin_len = 0;
uint8_t sm_session_pin[16];
static bool sm_active = false;
bool is_secured_apdu() {
bool is_secured_apdu(void) {
return CLA(apdu) & 0xC;
}
void sm_derive_key(const uint8_t *input,
size_t input_len,
uint8_t counter,
const uint8_t *nonce,
size_t nonce_len,
uint8_t *out) {
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) {
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
if (input) {
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);
sm_derive_key(derived, derived_len, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
mbedtls_mpi_free(&sm_mSSC);
mbedtls_mpi_init(&sm_mSSC);
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
mbedtls_mpi_lset(&sm_mSSC, 0);
memset(sm_iv, 0, sizeof(sm_iv));
sm_session_pin_len = 0;
sm_active = true;
}
void sm_set_protocol(MSE_protocol proto) {
@@ -75,32 +76,38 @@ void sm_set_protocol(MSE_protocol proto) {
else if (proto == MSE_3DES) {
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;
}
uint8_t *sm_get_nonce() {
uint8_t *sm_get_nonce(void) {
return sm_nonce;
}
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
sm_kmac,
128,
in,
in_len,
out);
int sm_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), sm_kmac, 128, in, in_len, out);
}
int sm_unwrap() {
int sm_unwrap(void) {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
if (!sm_active || sm_blocksize == 0) {
return PICOKEYS_EXEC_ERROR;
}
int r = sm_verify();
if (r != PICOKEY_OK) {
if (r != PICOKEYS_OK) {
return r;
}
apdu.ne = sm_get_le();
@@ -111,10 +118,9 @@ int sm_unwrap() {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
{
tlv_ctx_t ctxi;
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x87 || tag == 0x85) {
body = tag_data;
body_size = tag_len;
@@ -126,25 +132,28 @@ int sm_unwrap() {
}
if (!body) {
apdu.nc = 0;
return PICOKEY_OK;
return PICOKEYS_OK;
}
if (is87 && *body++ != 0x1) {
return PICOKEY_WRONG_PADDING;
return PICOKEYS_WRONG_PADDING;
}
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);
apdu.nc = sm_remove_padding(apdu.data, body_size);
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;
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;
memset(input, 0, sizeof(input));
mbedtls_mpi ssc;
@@ -153,7 +162,7 @@ int sm_wrap() {
mbedtls_mpi_copy(&sm_mSSC, &ssc);
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
@@ -163,7 +172,7 @@ int sm_wrap() {
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
sm_update_iv();
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
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);
res_APDU[0] = 0x1;
res_APDU_size++;
@@ -181,14 +190,14 @@ int sm_wrap() {
else {
memmove(res_APDU + 4, res_APDU, res_APDU_size);
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[0] = 0x87;
}
res_APDU[res_APDU_size++] = 0x99;
res_APDU[res_APDU_size++] = 2;
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size);
put_uint16_be(apdu.sw, res_APDU + res_APDU_size);
res_APDU_size += 2;
memcpy(input + input_len, res_APDU, res_APDU_size);
input_len += res_APDU_size;
@@ -202,16 +211,16 @@ int sm_wrap() {
apdu.ne = res_APDU_size;
}
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;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
tlv_ctx_t ctxi;
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x97) {
uint16_t le = 0;
for (uint16_t t = 1; t <= tag_len; t++) {
@@ -223,16 +232,16 @@ uint16_t sm_get_le() {
return 0;
}
void sm_update_iv() {
void sm_update_iv(void) {
uint8_t tmp_iv[16], sc_counter[16];
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
aes_encrypt(sm_kenc, tmp_iv, 128, PICOKEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
}
int sm_verify() {
uint8_t input[2048];
int sm_verify(void) {
uint8_t input[USB_BUFFER_SIZE];
memset(input, 0, sizeof(input));
uint16_t input_len = 0;
int r = 0;
@@ -242,7 +251,7 @@ int sm_verify() {
data_len += sm_blocksize;
}
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
return PICOKEY_WRONG_LENGTH;
return PICOKEYS_WRONG_LENGTH;
}
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
@@ -252,7 +261,7 @@ int sm_verify() {
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
if (add_header) {
input[input_len++] = CLA(apdu);
@@ -268,12 +277,12 @@ int sm_verify() {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
tlv_ctx_t ctxi;
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag & 0x1) {
input[input_len++] = (uint8_t)tag;
uint8_t tlen = format_tlv_len(tag_len, input + input_len);
uint8_t tlen = tlv_format_len(tag_len, input + input_len);
input_len += tlen;
memcpy(input + input_len, tag_data, tag_len);
input_len += tag_len;
@@ -284,8 +293,8 @@ int sm_verify() {
mac_len = tag_len;
}
}
if (!mac) {
return PICOKEY_WRONG_DATA;
if (!mac || mac_len != 8) {
return PICOKEYS_WRONG_DATA;
}
if (some_added) {
input[input_len++] = 0x80;
@@ -294,12 +303,12 @@ int sm_verify() {
uint8_t signature[16];
r = sm_sign(input, input_len, signature);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
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) {

View File

@@ -18,7 +18,9 @@
#ifndef _EAC_H_
#define _EAC_H_
#include "pico_keys.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef enum MSE_protocol {
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_set_protocol(MSE_protocol proto);
extern MSE_protocol sm_get_protocol();
extern uint8_t *sm_get_nonce();
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
int sm_verify();
void sm_update_iv();
uint16_t sm_get_le();
extern int sm_unwrap();
extern MSE_protocol sm_get_protocol(void);
extern uint8_t *sm_get_nonce(void);
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]);
int sm_verify(void);
void sm_update_iv(void);
uint16_t sm_get_le(void);
extern int sm_unwrap(void);
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
extern int sm_wrap();
extern bool is_secured_apdu();
extern uint8_t sm_session_pin[16];
extern uint16_t sm_session_pin_len;
extern int sm_wrap(void);
extern bool is_secured_apdu(void);
#endif

View File

@@ -15,33 +15,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "file.h"
#include "pico_keys.h"
#include <string.h>
#include <stdio.h>
#include "asn1.h"
#include "tlv.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 start_data_pool;
extern const uintptr_t end_rom_pool;
extern const uintptr_t start_rom_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t flash_read_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern int flash_clear_file(file_t *ef);
extern void low_flash_available();
#ifndef ENABLE_EMULATION
file_t sef_phy = {.fid = EF_PHY, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}};
file_t *ef_phy = &sef_phy;
#endif
//puts FCI in the RAPDU
void process_fci(const file_t *pe, int fmd) {
void file_process_fci(const file_t *pe, int fmd) {
res_APDU_size = 0;
if (fmd) {
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;
if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size);
int (*data_fn)(const file_t *, int) = (int (*)(const file_t *, int))(uintptr_t)pe->data;
uint16_t len = (uint16_t)data_fn(pe, 0);
res_APDU_size += put_uint16_be(len, res_APDU + res_APDU_size);
}
else {
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 {
@@ -86,7 +81,7 @@ void process_fci(const file_t *pe, int fmd) {
res_APDU[res_APDU_size++] = 0x83;
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) {
res_APDU[res_APDU_size++] = 0x84;
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 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) {
return true;
}
@@ -129,7 +124,7 @@ file_t *get_parent(file_t *f) {
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++) {
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
return p;
@@ -138,7 +133,7 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
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
if (fid == 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;
}
file_t *search_file(const uint16_t fid) {
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
static file_t *search_dynamic_file(uint16_t fid) {
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) {
return ef;
}
return search_dynamic_file(fid);
}
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
static uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
if (!buflen) {
return 0;
}
if (pe == top) { //MF or relative DF
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;
}
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;
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;
for (int d = depth - 2; d >= 0; 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;
}
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];
if (pathlen > sizeof(path)) {
return NULL;
@@ -207,7 +211,7 @@ file_t *currentDF = NULL;
const file_t *selected_applet = NULL;
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];
if (acl == 0x0) {
return true;
@@ -227,11 +231,11 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
return false;
}
void initialize_flash(bool hard) {
void file_initialize_flash(bool hard) {
if (hard) {
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
low_flash_available();
flash_commit();
}
for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
@@ -243,8 +247,7 @@ void initialize_flash(bool hard) {
extern uintptr_t last_base;
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;
if (persistent) {
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));
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) {
file = file_new(fid);
}
@@ -279,18 +282,17 @@ void scan_region(bool persistent)
}
}
}
void wait_flash_finish();
void scan_flash() {
initialize_flash(false); //soft initialization
uint32_t r1 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool)), r2 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t)));
void file_scan_flash(void) {
file_initialize_flash(false); //soft initialization
uint32_t r1 = (uint32_t)flash_read_uintptr(end_rom_pool);
uint32_t r2 = (uint32_t)flash_read_uintptr(end_rom_pool + sizeof(uintptr_t));
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
printf("First initialization (or corrupted!)\n");
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
memset(empty, 0, sizeof(empty));
flash_program_block(end_data_pool, empty, sizeof(empty));
flash_program_block(end_rom_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
//flash_commit();
}
printf("SCAN\n");
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);
}
file_t *search_dynamic_file(uint16_t fid) {
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) {
static int delete_dynamic_file(file_t *f) {
if (f == NULL) {
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
for (int i = 0; i < dynamic_files; i++) {
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));
}
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 *f;
if ((f = search_file(fid))) {
if ((f = file_search(fid))) {
return f;
}
if (dynamic_files == MAX_DYNAMIC_FILES) {
@@ -377,20 +370,20 @@ file_t *file_new(uint16_t fid) {
return f;
}
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) {
return 0;
}
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
tlv_ctx_t ctxi;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
uint16_t cfid = get_uint16_be(tag_data);
if (cfid == fid) {
if (out) {
*out = tag_data + 2;
@@ -401,24 +394,24 @@ uint16_t meta_find(uint16_t fid, uint8_t **out) {
return 0;
}
int meta_delete(uint16_t fid) {
file_t *ef = search_file(EF_META);
file_t *ef = file_search(EF_META);
if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
uint8_t *fdata = NULL;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
tlv_ctx_t ctxi;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
uint8_t *tpos = p - tag_len - tlv_format_len(tag_len, NULL) - 1;
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
uint16_t cfid = get_uint16_be(tag_data);
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) {
flash_clear_file(ef);
}
@@ -432,21 +425,21 @@ int meta_delete(uint16_t fid) {
}
int r = file_put_data(ef, fdata, new_len);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (r != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
}
low_flash_available();
flash_commit();
break;
}
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
int r;
file_t *ef = search_file(EF_META);
file_t *ef = file_search(EF_META);
if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
uint16_t ef_size = file_get_size(ef);
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;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(fdata, ef_size, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
tlv_ctx_t ctxi;
tlv_ctx_init(fdata, ef_size, &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue;
}
uint16_t cfid = get_uint16_t_be(tag_data);
uint16_t cfid = get_uint16_be(tag_data);
if (cfid == fid) {
if (tag_len - 2 == len) { //an update
memcpy(p - tag_len + 2, data, len);
r = file_put_data(ef, fdata, ef_size);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (r != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
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);
tpos += fdata + ef_size - p;
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 {
free(fdata);
return PICOKEY_ERR_MEMORY_FATAL;
return PICOKEYS_ERR_MEMORY_FATAL;
}
}
uint8_t *f = fdata + meta_offset;
*f++ = fid & 0xff;
f += format_tlv_len(len + 2, f);
f += put_uint16_t_be(fid, f);
f += tlv_format_len(len + 2, f);
f += put_uint16_be(fid, f);
memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (r != PICOKEYS_OK) {
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;
*f++ = fid & 0x1f;
f += format_tlv_len(len + 2, f);
f += put_uint16_t_be(fid, f);
f += tlv_format_len(len + 2, f);
f += put_uint16_be(fid, f);
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);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (r != PICOKEYS_OK) {
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;
}
int delete_file(file_t *ef) {
int file_delete(file_t *ef) {
if (ef == NULL) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
meta_delete(ef->fid);
if (flash_clear_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (flash_clear_file(ef) != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
if (delete_dynamic_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (delete_dynamic_file(ef) != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
low_flash_available();
return PICOKEY_OK;
flash_commit();
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

@@ -18,14 +18,10 @@
#ifndef _FILE_H_
#define _FILE_H_
#include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#else
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#endif
#include "compat.h"
#include <stdbool.h>
#include "compat/compat.h"
#include "phy.h"
#define FILE_TYPE_NOT_KNOWN 0x00
@@ -55,22 +51,19 @@
#define ACL_OP_UPDATE_ERASE 0x05
#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_DF 0x2
#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 MAX_DEPTH 4
#define MAX_DYNAMIC_FILES 256
#ifdef _MSC_VER
__pragma( pack(push, 1) )
#endif
@@ -78,7 +71,7 @@ typedef struct file {
const uint8_t *name;
uint8_t *data; //should include 2 bytes len at begining
const uint16_t fid;
const uint8_t acl[7];
uint8_t acl[7];
const uint8_t parent; //entry number in the whole table!!
const uint8_t type;
const uint8_t ef_structure;
@@ -93,30 +86,22 @@ __attribute__ ((packed))
#endif
file_t;
extern bool file_has_data(file_t *);
extern file_t *currentEF;
extern file_t *currentDF;
extern const file_t *selected_applet;
extern const file_t *MF;
extern const file_t *file_last;
extern const file_t *file_openpgp;
extern const file_t *file_sc_hsm;
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 *search_file(const uint16_t fid);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe, int fmd);
extern void scan_flash();
extern void initialize_flash(bool);
extern file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
extern file_t *file_search(const uint16_t fid);
extern file_t *file_search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool file_authenticate_action(const file_t *ef, uint8_t op);
extern void file_process_fci(const file_t *pe, int fmd);
extern void file_scan_flash(void);
extern void file_initialize_flash(bool);
extern file_t file_entries[];
@@ -124,29 +109,20 @@ extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const file_t *ef);
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 uint16_t file_get_size(const file_t *tf);
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
extern file_t *file_new(uint16_t);
extern int flash_clear_file(file_t *file);
extern int file_delete(file_t *ef);
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 uint16_t meta_find(uint16_t, uint8_t **out);
extern int meta_delete(uint16_t fid);
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
extern int delete_file(file_t *ef);
extern uint32_t flash_free_space();
extern uint32_t flash_used_space();
extern uint32_t flash_total_space();
extern uint32_t flash_num_files();
extern uint32_t flash_size();
#ifndef ENABLE_EMULATION
extern file_t *ef_phy;

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

@@ -15,14 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include "pico_keys.h"
#include "picokeys.h"
#if !defined(PICO_PLATFORM)
#define XIP_BASE 0
#define FLASH_SECTOR_SIZE 4096
#ifdef ENABLE_EMULATION
#define FLASH_SECTOR_SIZE 0x4000
#else
#define FLASH_SECTOR_SIZE 0x1000
#endif
#ifdef ESP_PLATFORM
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#else
@@ -30,11 +31,12 @@ uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#endif
#else
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
#include "pico/stdlib.h"
#include "hardware/flash.h"
#endif
#include "file.h"
#include <stdio.h>
extern void low_flash_task(void);
extern void low_flash_commit(void);
/*
* ------------------------------------------------------
@@ -50,15 +52,6 @@ uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
//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;
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;
uint32_t num_files = 0;
@@ -72,7 +65,7 @@ void flash_set_bounds(uintptr_t start, uintptr_t end) {
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) {
return 0x0; //ERROR
}
@@ -119,35 +112,14 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
return 0x0; //probably never reached
}
int flash_clear_file(file_t *file) {
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) {
static int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
if (!file) {
return PICOKEY_ERR_NULL_PARAM;
return PICOKEYS_ERR_NULL_PARAM;
}
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
uint8_t *old_data = NULL;
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
return PICOKEY_ERR_NO_MEMORY;
return PICOKEYS_ERR_NO_MEMORY;
}
if (file->data) { //already in flash
if (offset + len <= size_file_flash) { //it fits, no need to move it
@@ -155,7 +127,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
if (data) {
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
flash_clear_file(file);
@@ -172,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);
//printf("na %x\n",new_addr);
if (new_addr == 0x0) {
return PICOKEY_ERR_NO_MEMORY;
return PICOKEYS_ERR_NO_MEMORY;
}
if (new_addr < last_base) {
last_base = new_addr;
@@ -187,29 +159,37 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
free(old_data);
}
num_files++;
return PICOKEY_OK;
return PICOKEYS_OK;
}
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);
}
uint32_t flash_free_space() {
uint32_t flash_free_space(void) {
return (uint32_t)(last_base - start_data_pool);
}
uint32_t flash_used_space() {
uint32_t flash_used_space(void) {
return (uint32_t)(end_data_pool - last_base);
}
uint32_t flash_total_space() {
uint32_t flash_total_space(void) {
return (uint32_t)(end_data_pool - start_data_pool);
}
uint32_t flash_num_files() {
uint32_t flash_num_files(void) {
return num_files;
}
uint32_t flash_size() {
uint32_t flash_size(void) {
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

@@ -15,15 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include "picokeys.h"
#include "serial.h"
#include "crypto_utils.h"
#include <stdio.h>
#include "pico_keys.h"
#include <string.h>
#ifdef PICO_PLATFORM
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
@@ -33,7 +29,7 @@
#include "boot/picobin.h"
#else
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#include "compat/esp_compat.h"
#include "esp_partition.h"
const esp_partition_t *part0;
#define save_and_disable_interrupts() 1
@@ -55,9 +51,13 @@
#include <unistd.h>
#include <sys/mman.h>
#endif
#include "queue.h"
#include "compat/queue.h"
#endif
#ifdef ENABLE_EMULATION
#define FLASH_SECTOR_SIZE 0x4000
#else
#define FLASH_SECTOR_SIZE 0x1000
#endif
#define FLASH_SECTOR_SIZE 4096
#define XIP_BASE 0
int fd_map = 0;
uint8_t *map = NULL;
@@ -70,25 +70,22 @@ extern uint32_t FLASH_SIZE_BYTES;
#endif
#define TOTAL_FLASH_PAGES 6
#define FLASH_LOCKOUT_RETRIES 5
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool;
PACK(
typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE];
uintptr_t address;
bool ready;
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
} page_flash_t;
}) page_flash_t;
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash;
static semaphore_t sem_flash;
#ifndef ENABLE_EMULATION
static bool locked_out = false;
@@ -102,23 +99,34 @@ bool flash_available = false;
//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 (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
mutex_exit(&mtx_flash);
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) {
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);
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts(ints);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) {
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);
#else
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
@@ -128,12 +136,22 @@ void do_flash() {
}
else if (flash_pages[r].erase == true) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) {
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");
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);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) {
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
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
#endif
@@ -148,21 +166,27 @@ void do_flash() {
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
}
}
flash_available = false;
if (ready_pages == 0) {
flash_available = false;
}
#ifdef ESP_PLATFORM
esp_partition_munmap(fd_map);
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
#endif
mutex_exit(&mtx_flash);
}
sem_release(&sem_flash);
}
#ifdef PICO_RP2040
void phymarker_write(void);
#endif
//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);
mutex_init(&mtx_flash);
sem_init(&sem_flash, 0, 1);
uint32_t data_start_addr;
uint32_t data_end_addr;
@@ -179,21 +203,21 @@ void low_flash_init() {
FLASH_SIZE_BYTES = (1 << rxbuf[3]);
#ifdef PICO_RP2350
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
__attribute__((aligned(4))) uint32_t workarea[1024];
int rc = rom_load_partition_table((uint8_t *)workarea, sizeof(workarea), false);
if (rc) {
reset_usb_boot(0, 0);
}
uint8_t boot_partition = 1;
rc = rom_get_partition_table_info((uint32_t*)workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
rc = rom_get_partition_table_info(workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
if (rc != 3) {
data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = FLASH_SIZE_BYTES;
} else {
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
uint16_t last_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
uint16_t first_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_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_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
if (data_end_addr > FLASH_SIZE_BYTES) {
@@ -219,26 +243,20 @@ void low_flash_init() {
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);
multicore_lockout_victim_init();
locked_out = true;
mutex_exit(&mtx_flash);
}
void wait_flash_finish() {
sem_acquire_blocking(&sem_flash); //blocks until released
//wake up
sem_acquire_blocking(&sem_flash); //decrease permits
}
void low_flash_available() {
void low_flash_commit(void) {
mutex_enter_blocking(&mtx_flash);
flash_available = true;
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;
page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
@@ -265,24 +283,24 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
page_flash_t *p = NULL;
if (!data || len == 0) {
return PICOKEY_ERR_NULL_PARAM;
return PICOKEYS_ERR_NULL_PARAM;
}
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY;
return PICOKEYS_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr))) {
mutex_exit(&mtx_flash);
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);
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
mutex_exit(&mtx_flash);
return PICOKEY_OK;
return PICOKEYS_OK;
}
int flash_program_halfword(uintptr_t addr, uint16_t data) {
@@ -346,19 +364,19 @@ int flash_erase_page(uintptr_t addr, size_t page_size) {
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n");
return PICOKEY_ERR_NO_MEMORY;
return PICOKEYS_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr))) {
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
mutex_exit(&mtx_flash);
return PICOKEY_ERR_MEMORY_FATAL;
return PICOKEYS_ERR_MEMORY_FATAL;
}
p->erase = true;
p->ready = false;
p->page_size = page_size;
mutex_exit(&mtx_flash);
return PICOKEY_OK;
return PICOKEYS_OK;
}
bool flash_check_blank(const uint8_t *p_start, size_t size) {
@@ -371,3 +389,42 @@ bool flash_check_blank(const uint8_t *p_start, size_t size) {
}
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

@@ -15,8 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "file.h"
#include "picokeys.h"
#include "otp.h"
#ifndef ENABLE_EMULATION
@@ -25,7 +24,7 @@ phy_data_t phy_data;
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
return PICOKEYS_ERR_NULL_PARAM;
}
uint8_t *p = data;
if (phy->vidpid_present) {
@@ -48,7 +47,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
}
*p++ = PHY_OPTS;
*p++ = 2;
p += put_uint16_t_be(phy->opts, p);
p += put_uint16_be(phy->opts, p);
if (phy->up_btn_present) {
*p++ = PHY_UP_BTN;
*p++ = 1;
@@ -64,7 +63,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (phy->enabled_curves_present) {
*p++ = PHY_ENABLED_CURVES;
*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) {
*p++ = PHY_ENABLED_USB_ITF;
@@ -78,12 +77,12 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
}
*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) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
return PICOKEYS_ERR_NULL_PARAM;
}
const uint8_t *p = data;
uint8_t tag, tlen;
@@ -115,7 +114,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
break;
case PHY_OPTS:
if (tlen == 2) {
phy->opts = get_uint16_t_be(p);
phy->opts = get_uint16_be(p);
p += 2;
}
break;
@@ -135,7 +134,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
break;
case PHY_ENABLED_CURVES:
if (tlen == 4) {
phy->enabled_curves = get_uint32_t_be(p);
phy->enabled_curves = get_uint32_be(p);
p += 4;
phy->enabled_curves_present = true;
}
@@ -159,33 +158,33 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
}
}
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;
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
int phy_init() {
int phy_init(void) {
memset(&phy_data, 0, sizeof(phy_data_t));
return phy_load();
}
int phy_save() {
int phy_save(void) {
uint8_t tmp[PHY_MAX_SIZE] = {0};
uint16_t tmp_len = 0;
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return ret;
}
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
return PICOKEY_OK;
flash_commit();
return PICOKEYS_OK;
}
int phy_load() {
int phy_load(void) {
if (file_has_data(ef_phy)) {
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
#endif

View File

@@ -51,6 +51,8 @@
#define PHY_USB_ITF_WCID 0x2
#define PHY_USB_ITF_HID 0x4
#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
@@ -67,6 +69,7 @@
#include <stdint.h>
#include <stdbool.h>
PACK(
typedef struct phy_data {
union {
struct {
@@ -97,16 +100,16 @@ typedef struct phy_data {
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)+(2+1))
#ifndef ENABLE_EMULATION
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
extern int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
extern int phy_init();
extern int phy_save();
extern int phy_load();
extern int phy_init(void);
extern int phy_save(void);
extern int phy_load(void);
extern phy_data_t phy_data;
#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

@@ -15,14 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "bsp/board.h"
#elif defined(ESP_PLATFORM)
#include "picokeys.h"
#include "led/led.h"
#include "pico_time.h"
#if defined(ESP_PLATFORM)
#include "driver/gpio.h"
#include "esp_compat.h"
#elif defined(ENABLE_EMULATION)
#include "emulation.h"
#endif
@@ -35,11 +32,11 @@ void led_set_mode(uint32_t mode) {
led_mode = mode;
}
uint32_t led_get_mode() {
uint32_t led_get_mode(void) {
return led_mode;
}
void led_blinking_task() {
void led_blinking_task(void) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
static uint32_t start_ms = 0;
static uint32_t stop_ms = 0;
@@ -81,7 +78,7 @@ void led_blinking_task() {
#endif
}
void led_off_all() {
void led_off_all(void) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
led_driver->set_color(LED_COLOR_OFF, 0, 0);
#endif
@@ -93,11 +90,11 @@ extern led_driver_t led_driver_ws2812;
extern led_driver_t led_driver_neopixel;
extern led_driver_t led_driver_pimoroni;
void led_driver_init_dummy() {
static void led_driver_init_dummy(void) {
// Do nothing
}
void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
static void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
(void)color;
(void)led_brightness;
(void)progress;
@@ -109,13 +106,14 @@ led_driver_t led_driver_dummy = {
.set_color = led_driver_color_dummy,
};
void led_init() {
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;
@@ -144,14 +142,14 @@ void led_init() {
#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
case PHY_LED_DRIVER_PICO:
led_driver = &led_driver_pico;
break;
#ifdef CYW43_WL_GPIO_LED_PIN
case PHY_LED_DRIVER_CYW43:
led_driver = &led_driver_cyw43;

View File

@@ -62,13 +62,13 @@ enum {
};
extern void led_set_mode(uint32_t mode);
extern uint32_t led_get_mode();
extern void led_blinking_task();
extern void led_off_all();
extern void led_init();
extern uint32_t led_get_mode(void);
extern void led_blinking_task(void);
extern void led_off_all(void);
extern void led_init(void);
typedef struct {
void (*init)();
void (*init)(void);
void (*set_color)(uint8_t color, uint32_t led_brightness, float progress);
} led_driver_t;

View File

@@ -15,18 +15,26 @@
* 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
#include "pico/cyw43_arch.h"
void led_driver_init_cyw43() {
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();
}
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
(void)color;
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;

View File

@@ -15,7 +15,11 @@
* 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
@@ -45,7 +49,7 @@ tNeopixel pixel[] = {
#define NEOPIXEL_PIN GPIO_NUM_27
#endif
void led_driver_init_neopixel() {
void led_driver_init_neopixel(void) {
uint8_t gpio = NEOPIXEL_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;

View File

@@ -15,16 +15,28 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef PICO_DEFAULT_LED_PIN
uint8_t gpio = PICO_DEFAULT_LED_PIN;
#else
uint8_t gpio = 0;
#endif
#include "picokeys.h"
#include "led/led.h"
#ifdef PICO_PLATFORM
void led_driver_init_pico() {
#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
#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
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
static void led_driver_init_pico(void) {
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
@@ -32,7 +44,8 @@ void led_driver_init_pico() {
gpio_set_dir(gpio, GPIO_OUT);
}
void led_driver_color_pico(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;
gpio_put(gpio, progress >= 0.5);
}

View File

@@ -15,21 +15,15 @@
* 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
#ifdef PIMORONI_TINY2040
#define LED_R_PIN TINY2040_LED_R_PIN
#define LED_G_PIN TINY2040_LED_G_PIN
#define LED_B_PIN TINY2040_LED_B_PIN
#elif defined(PIMORONI_TINY2350)
#define LED_R_PIN TINY2350_LED_R_PIN
#define LED_G_PIN TINY2350_LED_G_PIN
#define LED_B_PIN TINY2350_LED_B_PIN
#include "hardware/gpio.h"
#ifdef PICO_DEFAULT_LED_PIN
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
#else
#define LED_R_PIN 0
#define LED_G_PIN 0
#define LED_B_PIN 0
static uint8_t gpio = 0;
#endif
uint8_t pixel[][3] = {
@@ -43,22 +37,26 @@ uint8_t pixel[][3] = {
{0, 0, 0} // 7: white
};
void led_driver_init_pimoroni() {
gpio_init(LED_R_PIN);
gpio_set_dir(LED_R_PIN, GPIO_OUT);
gpio_init(LED_G_PIN);
gpio_set_dir(LED_G_PIN, GPIO_OUT);
gpio_init(LED_B_PIN);
gpio_set_dir(LED_B_PIN, GPIO_OUT);
static void led_driver_init_pimoroni(void) {
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
gpio_init(gpio-1);
gpio_set_dir(gpio-1, 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_pimoroni(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) {
color = LED_COLOR_OFF;
}
gpio_put(LED_R_PIN, pixel[color][0]);
gpio_put(LED_G_PIN, pixel[color][1]);
gpio_put(LED_B_PIN, pixel[color][2]);
gpio_put(gpio-1, pixel[color][0]);
gpio_put(gpio, pixel[color][1]);
gpio_put(gpio+1, pixel[color][2]);
}
led_driver_t led_driver_pimoroni = {

View File

@@ -15,7 +15,8 @@
* 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/pio.h"
@@ -69,7 +70,7 @@ static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
pio_sm_set_enabled(pio, sm, true);
}
void led_driver_init_ws2812() {
static void led_driver_init_ws2812(void) {
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
@@ -115,7 +116,7 @@ static inline void ws2812_put_pixel(uint32_t u32_pixel) {
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
}
void led_driver_color_ws2812(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)) {
progress = progress >= 0.5 ? 1 : 0;
}

View File

@@ -15,10 +15,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico_keys.h"
#include "picokeys.h"
#include "button.h"
#if !defined(ENABLE_EMULATION)
#include "tusb.h"
#endif
@@ -28,27 +26,23 @@
#include "driver/gpio.h"
#include "rom/gpio.h"
#include "tinyusb.h"
#include "esp_efuse.h"
#define BOOT_PIN GPIO_NUM_0
#elif defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#include "bsp/board.h"
#include "pico/aon_timer.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/sio.h"
#include "pico/stdio.h"
#endif
#include "random.h"
#include "hwrng.h"
#include "apdu.h"
#include "usb.h"
#include "flash.h"
#include "otp.h"
#include "led/led.h"
#include "pico_time.h"
#include "serial.h"
#include "mbedtls/sha256.h"
extern void do_flash();
extern void low_flash_init();
extern void init_otp_files();
app_t apps[16];
uint8_t num_apps = 0;
@@ -58,7 +52,7 @@ const uint8_t *ccid_atr = NULL;
bool app_exists(const uint8_t *aid, size_t aid_len) {
for (int a = 0; a < num_apps; a++) {
if (apps[a].aid[0] == aid_len && !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;
}
}
@@ -79,234 +73,86 @@ 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) {
if (current_app && current_app->aid && current_app->aid[0] == aid_len && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, MIN(current_app->aid[0], 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);
return PICOKEY_OK;
return PICOKEYS_OK;
}
for (int a = 0; a < num_apps; a++) {
if (apps[a].aid[0] == aid_len && !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->aid && !memcmp(current_app->aid + 1, aid, MIN(current_app->aid[0], 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);
return PICOKEY_OK;
return PICOKEYS_OK;
}
if (current_app->unload) {
current_app->unload();
}
}
current_app = &apps[a];
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
return PICOKEY_OK;
if (current_app->select_aid(current_app, 1) == PICOKEYS_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();
static bool req_button_pending = false;
bool is_req_button_pending() {
return req_button_pending;
}
bool cancel_button = false;
#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);
WEAK int picokey_init(void) {
return 0;
}
#endif
#if !defined(ENABLE_EMULATION)
#ifdef ESP_PLATFORM
bool picok_board_button_read() {
int boot_state = gpio_get_level(BOOT_PIN);
return boot_state == 0;
}
#elif defined(PICO_PLATFORM)
bool __no_inline_not_in_flash_func(picok_get_bootsel_button)() {
const uint CS_PIN_INDEX = 1;
// Must disable interrupts, as interrupt handlers may be in flash, and we
// are about to temporarily disable flash access!
uint32_t flags = save_and_disable_interrupts();
// Set chip select to Hi-Z
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
// Note we can't call into any sleep functions in flash right now
for (volatile int i = 0; i < 1000; ++i);
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
// Note the button pulls the pin *low* when pressed.
#if PICO_RP2040
#define CS_BIT (1u << 1)
#else
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
#endif
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
// Need to restore the state of chip select, else we are going to have a
// bad time when we return to code in flash!
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
restore_interrupts(flags);
return button_state;
}
bool picok_board_button_read(void) {
return picok_get_bootsel_button();
}
#else
bool picok_board_button_read(void) {
return true; // always unpressed
}
#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()
{
void execute_tasks(void);
void execute_tasks(void) {
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
tud_task(); // tinyusb device task
#endif
#ifdef USB_ITF_LWIP
#if !defined(ENABLE_EMULATION)
service_traffic();
#endif
rest_task();
#endif
usb_task();
led_blinking_task();
#ifdef ENABLE_LVGL_UI
platform_ui_task();
#endif
}
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) {
execute_tasks();
neug_task();
do_flash();
#ifndef ENABLE_EMULATION
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
bool current_button_state = picok_board_button_read();
if (current_button_state != button_pressed_state) {
if (current_button_state == false) { // unpressed
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
button_press++;
}
button_pressed_time = board_millis();
}
button_pressed_state = current_button_state;
}
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
if (button_pressed_cb != NULL) {
(*button_pressed_cb)(button_press);
}
button_pressed_time = button_press = 0;
}
}
hwrng_task();
flash_task();
button_task();
#ifdef PICO_PLATFORM
// Avoid a pure busy loop on core0; gives the system a scheduling hint.
tight_loop_contents();
#endif
#ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10));
vTaskDelay(pdMS_TO_TICKS(10));
#endif
}
}
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
uint8_t pico_serial_hash[32];
pico_unique_board_id_t pico_serial;
#ifdef ESP_PLATFORM
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
extern tinyusb_config_t tusb_cfg;
extern const uint8_t desc_config[];
extern char *string_desc_arr[];
extern char *string_desc_itf[];
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
int app_main() {
int app_main(void) {
#else
#ifndef PICO_PLATFORM
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
#endif
int main(void) {
#endif
pico_get_unique_board_id(&pico_serial);
memset(pico_serial_str, 0, sizeof(pico_serial_str));
for (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);
serial_init();
#ifndef ENABLE_EMULATION
#ifdef PICO_PLATFORM
@@ -320,11 +166,11 @@ int main(void) {
random_init();
init_otp_files();
otp_init();
low_flash_init();
scan_flash();
file_scan_flash();
init_rtc();
@@ -346,13 +192,16 @@ int main(void) {
if (phy_data.usb_product_present) {
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
}
static char tmps[4][32];
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
tusb_cfg.string_descriptor[i] = tmps[i-4];
static char tmps[5][32];
const int max_desc_slots = 8 - 6;
const int itf_desc_count = ITF_TOTAL < max_desc_slots ? ITF_TOTAL : max_desc_slots;
for (int i = 0; i < itf_desc_count; i++) {
strlcpy(tmps[i], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
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;
tinyusb_driver_install(&tusb_cfg);
@@ -361,10 +210,14 @@ int main(void) {
#endif
#endif
#ifndef ENABLE_EMULATION
picokey_init();
#endif
#ifdef ESP_PLATFORM
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
#else
core0_loop();
core0_loop(NULL);
#endif
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);
}

View File

@@ -15,42 +15,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _OTP_H_
#define _OTP_H_
#ifdef PICO_RP2350
#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
extern const uint8_t* otp_buffer(uint16_t row);
extern const 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, const uint8_t *data, uint16_t len);
extern int otp_write_data_raw(uint16_t row, const 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
#include <stdint.h>
#include <stdbool.h>
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
extern void init_otp_files();
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;
extern bool otp_is_secure_boot_enabled(uint8_t *bootkey);
extern bool otp_is_secure_boot_locked();
#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;
}

View File

@@ -15,21 +15,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "file.h"
#include "pico_keys.h"
#include <stdio.h>
#include <stdalign.h>
#include "picokeys.h"
#include "otp.h"
#include "otp_platform.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"
#include <stdalign.h>
#ifdef PICO_RP2350
#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++) {
@@ -49,25 +55,25 @@ static int otp_write_data_mode(uint16_t row, const uint8_t *data, uint16_t len,
return ret;
}
int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
static int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, true);
}
int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len) {
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);
}
const uint8_t* otp_buffer(uint16_t row) {
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;
}
const uint8_t* otp_buffer_raw(uint16_t row) {
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;
}
bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
static bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
return is_empty_buffer(otp_buffer_raw(row), len * 2);
}
@@ -84,54 +90,71 @@ static void otp_lock_page(uint8_t page) {
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;
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);
}
}
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
}
#endif
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;
}
const uint8_t *otp_key_1 = NULL;
const uint8_t *otp_key_2 = NULL;
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;
}
#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
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);
}
#ifndef SECURE_BOOT_BOOTKEY_INDEX
#define SECURE_BOOT_BOOTKEY_INDEX 0
#endif
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
#ifdef PICO_RP2350
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[] = "\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";
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);
@@ -150,20 +173,16 @@ bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
*bootkey = bootkey_idx;
}
return true;
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot check for ESP32-S3
#endif
return false;
}
bool otp_is_secure_boot_locked() {
bool otp_platform_is_secure_boot_locked(void) {
uint8_t bootkey_idx = 0xFF;
if (otp_is_secure_boot_enabled(&bootkey_idx) == false) {
if (otp_platform_is_secure_boot_enabled(&bootkey_idx) == false) {
return false;
}
#ifdef PICO_RP2350
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)))) {
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);
@@ -173,18 +192,14 @@ bool otp_is_secure_boot_locked() {
return false;
}
return bootkey_idx != 0xFF;
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot lock check for ESP32-S3
#endif
return false;
}
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
int ret = 0;
#ifdef PICO_RP2350
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)) {
PICOKEY_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
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);
@@ -193,9 +208,9 @@ int otp_enable_secure_boot(uint8_t bootkey, bool 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)));
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 };
@@ -204,157 +219,76 @@ int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
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)));
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 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
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 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
}
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot for ESP32-S3
#else
(void)bootkey;
(void)secure_lock;
#endif // PICO_RP2350
goto err;
err:
if (ret != PICOKEY_OK) {
err:
if (ret != PICOKEYS_OK) {
return ret;
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
#ifdef PICO_RP2350
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);
free(inval);
}
}
}
static otp_ret_t 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;
}
otp_ret_t ret = otp_write_data_raw(row + 32, chaff, len * 2);
free(chaff);
return ret;
}
return BOOTROM_ERROR_INVALID_STATE;
}
static otp_ret_t 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);
otp_ret_t ret = otp_write_data(new_row, new_key, len);
if (ret == BOOTROM_OK) {
otp_chaff(new_row, len);
otp_invalidate_key(old_row, 32);
}
free(new_key);
return ret;
}
}
return BOOTROM_ERROR_INVALID_STATE;
}
void otp_migrate_chaff() {
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);
}
#endif
void init_otp_files() {
#ifdef PICO_RP2350
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
otp_migrate_chaff();
#endif
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
otp_ret_t ret = 0;
int ret = 0;
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
if (OTP_EMTPY(OTP_KEY_1, 32)) {
if (is_empty_otp_buffer(OTP_KEY_1, 32)) {
uint8_t mkek[32] = {0};
random_gen(NULL, mkek, sizeof(mkek));
ret = OTP_WRITE(OTP_KEY_1, mkek, sizeof(mkek));
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);
}
#ifdef PICO_RP2350
otp_chaff(OTP_KEY_1, 32);
#endif
mbedtls_platform_zeroize(mkek, sizeof(mkek));
write_otp[0] = OTP_KEY_1;
}
OTP_READ(OTP_KEY_1, otp_key_1);
*otp_key_1_out = otp_buffer(OTP_KEY_1);
if (OTP_EMTPY(OTP_KEY_2, 32)) {
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_gen, NULL);
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(OTP_KEY_2, pkey, olen);
ret = otp_write_data(OTP_KEY_2, pkey, olen);
if (ret != 0) {
printf("Error writing OTP key 2 [%d]\n", ret);
}
#ifdef PICO_RP2350
mbedtls_platform_zeroize(pkey, sizeof(pkey));
otp_chaff(OTP_KEY_2, 32);
#endif
write_otp[1] = OTP_KEY_2;
}
OTP_READ(OTP_KEY_2, otp_key_2);
*otp_key_2_out = otp_buffer(OTP_KEY_2);
for (int i = 0; i < sizeof(write_otp)/sizeof(uint16_t); i++) {
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); 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
}
}
#elif defined(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
}

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,243 +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 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 _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"
#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
#if defined(PICO_PLATFORM)
#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"
#elif defined(PICO_PLATFORM)
#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 uint8_t put_uint16_t_be(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 2;
}
static inline uint8_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();
#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 (PICO_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];
extern uint8_t pico_serial_hash[32];
#if defined(PICO_PLATFORM)
#define multicore_launch_func_core1(a) multicore_launch_core1((void (*) (void))a)
#endif
#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

@@ -18,9 +18,9 @@
#ifndef __VERSION_H_
#define __VERSION_H_
#define PICO_KEYS_SDK_VERSION 0x0800
#define PICOKEYS_SDK_VERSION 0x0806
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
#define PICOKEYS_SDK_VERSION_MAJOR ((PICOKEYS_SDK_VERSION >> 8) & 0xff)
#define PICOKEYS_SDK_VERSION_MINOR (PICOKEYS_SDK_VERSION & 0xff)
#endif

View File

@@ -15,17 +15,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "apdu.h"
#include "pico_keys_version.h"
#include "otp.h"
#include "picokeys.h"
#include "serial.h"
#include "led/led.h"
#include <time.h>
#include "pico_time.h"
#ifdef PICO_PLATFORM
#include "pico/bootrom.h"
#include "hardware/watchdog.h"
#endif
#include "apdu.h"
#include "picokeys_version.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[] = {
8,
@@ -33,20 +47,24 @@ const uint8_t rescue_aid[] = {
};
#ifdef PICO_RP2350
#define PICO_MCU 1
#elif defined(ESP_PLATFORM)
#define PICO_MCU 2
const uint8_t PICO_MCU = 1;
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
const uint8_t PICO_MCU = 2;
#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
#define PICO_MCU 0
const uint8_t PICO_MCU = 0;
#endif
#define EF_DEVCERT_KEY 0xE0C1
extern uint8_t PICO_PRODUCT;
extern uint8_t PICO_VERSION_MAJOR;
extern uint8_t PICO_VERSION_MINOR;
int rescue_select(app_t *a, uint8_t force) {
static int rescue_select(app_t *a, uint8_t force) {
a->process_apdu = rescue_process_apdu;
a->unload = rescue_unload;
res_APDU_size = 0;
@@ -54,50 +72,234 @@ int rescue_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = PICO_PRODUCT;
res_APDU[res_APDU_size++] = PICO_VERSION_MAJOR;
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;
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 ) {
register_app(rescue_select, rescue_aid);
}
int rescue_unload() {
return PICOKEY_OK;
static int rescue_unload(void) {
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) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) { // PHY
uint8_t p1 = P1(apdu), p2 = P2(apdu);
if (p1 == 0x1) { // PHY
#ifndef ENABLE_EMULATION
int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
if (ret == PICOKEY_OK) {
if (phy_save() != PICOKEY_OK) {
if (ret == PICOKEYS_OK) {
if (phy_save() != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
}
#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();
}
int cmd_read() {
static int cmd_read(void) {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
uint8_t p1 = P1(apdu);
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 != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
res_APDU_size = len;
@@ -106,11 +308,17 @@ int cmd_read() {
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_t_be(free, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(used, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(total, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(nfiles, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(size, res_APDU + res_APDU_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;
@@ -121,11 +329,34 @@ int cmd_read() {
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();
}
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
int cmd_secure() {
static int cmd_secure(void) {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
@@ -134,22 +365,24 @@ int cmd_secure() {
bool secure_lock = P2(apdu) == 0x1;
int ret = otp_enable_secure_boot(bootkey, secure_lock);
if (ret != 0) {
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
led_3_blinks();
return SW_OK();
}
#endif
#ifdef PICO_PLATFORM
int cmd_reboot_bootsel() {
static int cmd_reboot_bootsel(void) {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) {
// Reboot to BOOTSEL
reset_usb_boot(0, 0);
uint32_t val = EV_RESET;
queue_try_add(&card_to_usb_q, &val);
}
else if (P1(apdu) == 0x0) {
// Reboot to normal mode
@@ -163,12 +396,14 @@ int cmd_reboot_bootsel() {
}
#endif
#define INS_KEYDEV_SIGN 0x10
#define INS_WRITE 0x1C
#define INS_SECURE 0x1D
#define INS_READ 0x1E
#define INS_REBOOT_BOOTSEL 0x1F
static const cmd_t cmds[] = {
{ INS_KEYDEV_SIGN, cmd_keydev_sign },
{ INS_WRITE, cmd_write },
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
{ INS_SECURE, cmd_secure },
@@ -180,7 +415,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 }
};
int rescue_process_apdu() {
static int rescue_process_apdu(void) {
if (CLA(apdu) != 0x80) {
return SW_CLA_NOT_SUPPORTED();
}

View File

@@ -15,46 +15,41 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "picokeys.h"
#include "hwrng.h"
#include "pico_time.h"
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#include "hwrng.h"
#include "bsp/board.h"
#include "pico/rand.h"
#include "pico/mutex.h"
#elif defined(ESP_PLATFORM)
#include "bootloader_random.h"
#include "esp_random.h"
#include "esp_compat.h"
#include "compat/esp_compat.h"
#else
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include "board.h"
#include "compat/queue.h"
#endif
void hwrng_start() {
static void hwrng_start(void) {
#if defined(ENABLE_EMULATION)
srand(time(0));
srand((unsigned int)time(NULL));
#elif defined(ESP_PLATFORM)
bootloader_random_enable();
#endif
}
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;
ep_round = 0;
hwrng_mix_round = 0;
}
/* Here, we assume a little endian architecture. */
static int ep_process() {
if (ep_round == 0) {
ep_init();
static int hwrng_mix_process(void) {
if (hwrng_mix_round == 0) {
hwrng_mix_init();
}
uint64_t word = 0x0;
@@ -69,119 +64,182 @@ static int ep_process() {
#endif
random_word ^= word ^ board_millis();
random_word *= 0x00000100000001B3;
if (++ep_round == 8) {
ep_round = 0;
return 2; //2 words
if (++hwrng_mix_round == 8) {
hwrng_mix_round = 0;
return sizeof(uint64_t) / sizeof(uint32_t); //2 words
}
return 0;
}
struct rng_rb {
uint32_t *buf;
uint8_t head, tail;
uint8_t size;
unsigned int full : 1;
unsigned int empty : 1;
};
typedef struct hwrng_buf {
uint8_t *buf;
size_t head;
size_t tail;
size_t size;
size_t count;
} 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, uint8_t *p, size_t size) {
rb->buf = p;
rb->size = size;
rb->head = rb->tail = 0;
rb->full = 0;
rb->empty = 1;
rb->count = 0;
}
static void rb_add(struct rng_rb *rb, uint32_t v) {
rb->buf[rb->tail++] = v;
if (rb->tail == rb->size) {
rb->tail = 0;
static size_t hwrng_buf_add(struct hwrng_buf *rb, const uint8_t *data, size_t len) {
size_t room = rb->size - rb->count;
size_t n = len < room ? len : room;
size_t tail = rb->tail;
size_t first = n;
if (first > rb->size - tail) {
first = rb->size - tail;
}
if (rb->tail == rb->head) {
rb->full = 1;
}
rb->empty = 0;
}
static uint32_t rb_del(struct rng_rb *rb) {
uint32_t v = rb->buf[rb->head++];
if (rb->head == rb->size) {
rb->head = 0;
}
if (rb->head == rb->tail) {
rb->empty = 1;
}
rb->full = 0;
return v;
}
static struct rng_rb the_ring_buffer;
void *neug_task() {
struct rng_rb *rb = &the_ring_buffer;
int n;
if ((n = ep_process())) {
int i;
const uint32_t *vp = (const uint32_t *) &random_word;
for (i = 0; i < n; i++) {
rb_add(rb, *vp++);
if (rb->full) {
break;
}
if (first) {
memcpy(rb->buf + tail, data, first);
tail += first;
if (tail >= rb->size) {
tail = 0;
}
}
if (n > first) {
size_t second = n - first;
memcpy(rb->buf + tail, data + first, second);
tail += second;
}
rb->tail = tail;
rb->count += n;
return n;
}
static size_t hwrng_buf_del(struct hwrng_buf *rb, uint8_t *data, size_t len) {
size_t n = len < rb->count ? len : rb->count;
size_t head = rb->head;
size_t first = n;
if (first > rb->size - head) {
first = rb->size - head;
}
if (first) {
memcpy(data, rb->buf + head, first);
head += first;
if (head >= rb->size) {
head = 0;
}
}
if (n > first) {
size_t second = n - first;
memcpy(data + first, rb->buf + head, second);
head += second;
}
rb->head = head;
rb->count -= n;
return n;
}
static inline size_t hwrng_buf_space(const struct hwrng_buf *rb) {
return rb->size - rb->count;
}
static inline bool hwrng_buf_full(const struct hwrng_buf *rb) {
return rb->count == rb->size;
}
static struct hwrng_buf ring_buffer;
void *hwrng_task(void) {
struct hwrng_buf *rb = &ring_buffer;
hwrng_lock();
if (hwrng_buf_space(rb) >= sizeof(random_word) && hwrng_mix_process()) {
hwrng_buf_add(rb, (const uint8_t *)&random_word, sizeof(random_word));
}
hwrng_unlock();
return NULL;
}
void neug_init(uint32_t *buf, uint8_t size) {
struct rng_rb *rb = &the_ring_buffer;
void hwrng_init(uint8_t *buf, size_t size) {
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();
ep_init();
hwrng_mix_init();
}
void neug_flush(void) {
struct rng_rb *rb = &the_ring_buffer;
size_t hwrng_read(uint8_t *buf, size_t len) {
struct hwrng_buf *rb = &ring_buffer;
size_t n;
while (!rb->empty) {
rb_del(rb);
}
hwrng_lock();
n = hwrng_buf_del(rb, buf, len);
hwrng_unlock();
return n;
}
uint32_t neug_get() {
struct rng_rb *rb = &the_ring_buffer;
uint32_t v;
void hwrng_flush(void) {
struct hwrng_buf *rb = &ring_buffer;
hwrng_lock();
rb->head = 0;
rb->tail = 0;
rb->count = 0;
hwrng_unlock();
}
while (rb->empty) {
neug_task();
uint32_t hwrng_get(void) {
uint32_t v = 0;
size_t offset = 0;
while (offset < sizeof(v)) {
size_t n = hwrng_read(((uint8_t *)&v) + offset, sizeof(v) - offset);
if (n == 0) {
hwrng_task();
continue;
}
offset += n;
}
v = rb_del(rb);
return v;
}
void neug_wait_full() {
struct rng_rb *rb = &the_ring_buffer;
void hwrng_wait_full(void) {
struct hwrng_buf *rb = &ring_buffer;
#ifdef ESP_PLATFORM
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
#elif defined(PICO_PLATFORM)
uint core = get_core_num();
#endif
while (!rb->full) {
while (true) {
hwrng_lock();
bool full = hwrng_buf_full(rb);
hwrng_unlock();
if (full) {
break;
}
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
if (core == 1) {
sleep_ms(1);
}
else
#endif
neug_task();
hwrng_task();
}
}

View File

@@ -17,17 +17,14 @@
#ifndef _NEUG_H_
#define _NEUG_H_
#include <stdint.h>
#include <stddef.h>
#define NEUG_PRE_LOOP 32
#include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#endif
void neug_init(uint32_t *buf, uint8_t size);
uint32_t neug_get();
void neug_flush(void);
void neug_wait_full();
void hwrng_init(uint8_t *buf, size_t size);
size_t hwrng_read(uint8_t *buf, size_t len);
void hwrng_flush(void);
void hwrng_wait_full(void);
void *hwrng_task(void);
uint32_t hwrng_get(void);
#endif

View File

@@ -15,83 +15,65 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define HWRNG_PRE_LOOP 32
#include <stdint.h>
#include <string.h>
#include "picokeys.h"
#include "hwrng.h"
#include "random.h"
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
static uint8_t random_pool[256];
void random_init(void) {
int i;
hwrng_init(random_pool, sizeof(random_pool));
neug_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++) {
neug_get();
for (int i = 0; i < HWRNG_PRE_LOOP; i++) {
hwrng_task();
}
}
/*
* Return pointer to random 32-byte
*/
void random_bytes_free(const uint8_t *p);
#define MAX_RANDOM_BUFFER 1024
const uint8_t *random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER) {
return NULL;
}
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full();
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *) random_word);
static uint8_t return_word[MAX_RANDOM_BUFFER];
if (random_fill_buffer(return_word, len) != 0) {
return NULL;
}
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
*/
int random_gen(void *arg, unsigned char *out, size_t out_len) {
uint8_t *index_p = (uint8_t *) arg;
uint8_t index = index_p ? *index_p : 0;
uint8_t n;
int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
int ret = 0;
while (out_len) {
neug_wait_full();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len) {
n = (uint8_t)out_len;
if (ctx && ctx->cancel) {
ret = -1;
break;
}
size_t n = hwrng_read(out, out_len);
if (n == 0) {
hwrng_task();
continue;
}
memcpy(out, ((unsigned char *) random_word) + index, n);
out += n;
out_len -= n;
index += n;
if (index >= RANDOM_BYTES_LENGTH) {
index = 0;
neug_flush();
if (ctx) {
ctx->index = (uint8_t)((ctx->index + n) % RANDOM_BYTES_LENGTH);
}
}
if (index_p) {
*index_p = index;
}
return ret;
}
return 0;
int random_fill_buffer(uint8_t *buf, size_t n) {
return random_fill_iterator(NULL, buf, n);
}

View File

@@ -21,14 +21,18 @@
#include <stdlib.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 */
const uint8_t *random_bytes_get(size_t);
void random_bytes_free(const uint8_t *p);
extern void
random_init(void);
/* iterator returning a byta at a time */
extern int random_gen(void *arg, unsigned char *output, size_t output_len);
extern const uint8_t *random_bytes_get(size_t);
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

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_

65
src/signal.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* 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 "signal.h"
static signal_t signals[MAX_SIGNALS] = {0};
static uint8_t num_signals = 0;
int signal_add(signal_code_t code, signal_flag_t flags, signal_handler_t handler) {
if (num_signals >= MAX_SIGNALS) {
return PICOKEYS_ERR_NO_MEMORY;
}
if (handler == NULL) {
return PICOKEYS_ERR_NULL_PARAM;
}
signals[num_signals].code = code;
signals[num_signals].flags = flags;
signals[num_signals].handler = handler;
num_signals++;
return PICOKEYS_OK;
}
int signal_remove(signal_code_t code, signal_handler_t handler) {
for (int i = 0; i < num_signals; i++) {
if (signals[i].code == code && signals[i].handler == handler) {
for (int j = i; j < num_signals - 1; j++) {
signals[j] = signals[j + 1];
}
num_signals--;
return PICOKEYS_OK;
}
}
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
int signal_emit_param(signal_code_t code, void *data) {
for (int i = 0; i < num_signals; i++) {
if (signals[i].code == code) {
int ret = signals[i].handler(code, data);
if (ret != 0 && (signals[i].flags & SIGNAL_FLAG_ERROR_CONTINUE) == 0) {
return ret;
}
}
}
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
int signal_emit(signal_code_t code) {
return signal_emit_param(code, NULL);
}

56
src/signal.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* 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 _SIGNAL_H_
#define _SIGNAL_H_
#define MAX_SIGNALS 32
typedef enum {
SIGNAL_NONE = 0,
SIGNAL_BOOT = 1,
SIGNAL_USB_MOUNTED = 2,
SIGNAL_BUTTON_PRESS = 3,
SIGNAL_BUTTON_RELEASE = 4,
SIGNAL_USER_PRESENCE_REQUEST = 5,
SIGNAL_USER_PRESENCE_COMPLETED = 6,
SIGNAL_USER_PRESENCE_CANCELLED = 7,
SIGNAL_USER_PRESENCE_TIMEOUT = 8,
} signal_code_t;
typedef enum {
SIGNAL_FLAG_NONE = 0x0,
SIGNAL_FLAG_ERROR_CONTINUE = 0x1,
} signal_flag_t;
typedef int (*signal_handler_t)(signal_code_t, void *);
typedef struct {
uint32_t timeout;
} signal_user_presence_request_data_t;
typedef struct {
signal_code_t code;
signal_flag_t flags;
signal_handler_t handler;
} signal_t;
extern int signal_add(signal_code_t code, signal_flag_t flags, signal_handler_t handler);
extern int signal_remove(signal_code_t code, signal_handler_t handler);
extern int signal_emit_param(signal_code_t code, void *data);
extern int signal_emit(signal_code_t code);
#endif // _SIGNAL_H_

View File

@@ -15,32 +15,32 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "asn1.h"
#include "picokeys.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) {
return PICOKEY_ERR_NULL_PARAM;
return PICOKEYS_ERR_NULL_PARAM;
}
ctx->data = data;
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->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) {
return ctx->len;
}
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];
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
d <<= 8;
@@ -49,15 +49,15 @@ uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
return d;
}
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
uint16_t tlv_len_tag(uint16_t tag, uint16_t len) {
uint16_t ret = 1 + tlv_format_len(len, NULL) + len;
if (tag > 0x00ff) {
return ret + 1;
}
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 (out) {
*out = (uint8_t)len;
@@ -73,16 +73,12 @@ uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
}
if (out) {
*out++ = 0x82;
put_uint16_t_be(len, out);
put_uint16_be(len, out);
}
return 3;
}
int walk_tlv(const asn1_ctx_t *ctxi,
uint8_t **p,
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data) {
int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data) {
if (!p) {
return 0;
}
@@ -92,8 +88,7 @@ int walk_tlv(const asn1_ctx_t *ctxi,
if (*p - ctxi->data >= ctxi->len) {
return 0;
}
uint16_t tg = 0x0;
uint16_t tgl = 0;
uint16_t tg = 0x0, tgl = 0;
tg = *(*p)++;
if ((tg & 0x1f) == 0x1f) {
tg <<= 8;
@@ -120,14 +115,10 @@ int walk_tlv(const asn1_ctx_t *ctxi,
return 1;
}
bool asn1_find_tag(const asn1_ctx_t *ctxi,
uint16_t itag,
asn1_ctx_t *ctxo) {
uint16_t tag = 0x0;
uint8_t *p = NULL;
uint8_t *tdata = NULL;
uint16_t tlen = 0;
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo) {
uint16_t tag = 0x0, tlen = 0;
uint8_t *p = NULL, *tdata = NULL;
while (tlv_walk(ctxi, &p, &tag, &tlen, &tdata)) {
if (itag == tag) {
if (ctxo != NULL) {
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

48
src/trusted.c Normal file
View File

@@ -0,0 +1,48 @@
/*
* 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 "trusted.h"
#include "mbedtls/sha256.h"
const uint8_t *trusted_region_start(void) {
return __trusted_start;
}
const uint8_t *trusted_region_end(void) {
return __trusted_end;
}
const uint8_t *trusted_region_load_start(void) {
return __trusted_start;
}
const uint8_t *trusted_region_load_end(void) {
return __trusted_end;
}
size_t trusted_region_size(void) {
return (size_t)(__trusted_end - __trusted_start);
}
void trusted_region_init(void) {
/* The trusted measurement is always taken from its flash image range. */
}
int trusted_region_sha256(uint8_t out[32]) {
return mbedtls_sha256(__trusted_start, trusted_region_size(), out, 0);
}

38
src/trusted.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* 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 TRUSTED_FIRMWARE_H
#define TRUSTED_FIRMWARE_H
#include <stddef.h>
#include <stdint.h>
extern const uint8_t __trusted_start[];
extern const uint8_t __trusted_end[];
extern const uint8_t __trusted_load_start[];
extern const uint8_t __trusted_load_end[];
/* The canonical trusted measurement is always the flash image range. */
const uint8_t *trusted_region_start(void);
const uint8_t *trusted_region_end(void);
const uint8_t *trusted_region_load_start(void);
const uint8_t *trusted_region_load_end(void);
size_t trusted_region_size(void);
void trusted_region_init(void);
int trusted_region_sha256(uint8_t out[32]);
#endif

View File

@@ -0,0 +1,12 @@
@PICOKEYS_TRUSTED_SECTION_DIRECTIVE@
.balign 16
.globl @PICOKEYS_TRUSTED_START_SYM@
@PICOKEYS_TRUSTED_START_SYM@:
.globl @PICOKEYS_TRUSTED_LOAD_START_SYM@
@PICOKEYS_TRUSTED_LOAD_START_SYM@:
.incbin "@TRUSTED_REGION_EMBED_INPUT@"
.balign 16
.globl @PICOKEYS_TRUSTED_END_SYM@
@PICOKEYS_TRUSTED_END_SYM@:
.globl @PICOKEYS_TRUSTED_LOAD_END_SYM@
@PICOKEYS_TRUSTED_LOAD_END_SYM@:

View File

@@ -15,8 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "picokeys.h"
#include "led/led.h"
#include "random.h"
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "bsp/board.h"
#endif
@@ -27,7 +28,6 @@
#include "emulation.h"
#endif
#include "ccid.h"
#include "usb_descriptors.h"
#include "apdu.h"
#include "usb.h"
@@ -97,21 +97,22 @@ static uint8_t itf_num;
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
void ccid_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].r_ptr += offset;
}
void ccid_write(uint8_t itf, uint16_t size) {
ccid_write_offset(itf, size, 0);
}
ccid_header_t **ccid_response = NULL;
ccid_header_t **ccid_resp_fast = NULL;
ccid_header_t **ccid_header = NULL;
uint8_t sc_itf_to_usb_itf(uint8_t itf) {
static uint8_t sc_itf_to_usb_itf(uint8_t itf) {
if (itf == ITF_SC_CCID) {
return ITF_CCID;
}
@@ -121,7 +122,7 @@ uint8_t sc_itf_to_usb_itf(uint8_t itf) {
return itf;
}
void ccid_init_buffers() {
static void ccid_init_buffers(void) {
if (ITF_SC_TOTAL == 0) {
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_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
// 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;
return PICOKEY_OK;
return PICOKEYS_OK;
}
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);
do {
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);
}
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) {
DEBUG_PAYLOAD(tx_buffer, buffer_size);
}
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
if (r > 0) {
tud_vendor_n_flush(itf);
uint32_t written = tud_vendor_n_write(itf, tx_buffer, buffer_size);
if (written > 0) {
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) {
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
}
}
#ifdef ENABLE_EMULATION
tud_vendor_tx_cb(itf, r);
tud_vendor_tx_cb(itf, written);
#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);
}
@@ -201,6 +204,20 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
(void) rx_read;
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
driver_init_ccid(itf);
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);
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);
@@ -302,7 +319,7 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
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]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
@@ -327,14 +344,21 @@ void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t of
ccid_write_offset(itf, size_next+10, offset);
}
void ccid_task() {
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
int status = card_status(sc_itf_to_usb_itf(itf));
if (status == PICOKEY_OK) {
driver_exec_finished_ccid(itf, finished_data_size);
}
else if (status == PICOKEY_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf);
void ccid_task(void) {
const uint32_t status_poll_interval_ms = 1;
static uint32_t last_status_poll_ms[8] = {0};
uint32_t now_ms = board_millis();
for (uint8_t itf = 0; itf < ITF_SC_TOTAL; itf++) {
if (itf < (sizeof(last_status_poll_ms) / sizeof(last_status_poll_ms[0])) &&
now_ms - last_status_poll_ms[itf] >= status_poll_interval_ms) {
last_status_poll_ms[itf] = now_ms;
int status = card_status(sc_itf_to_usb_itf(itf));
if (status == PICOKEYS_OK) {
driver_exec_finished_ccid(itf, finished_data_size);
}
else if (status == PICOKEYS_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf);
}
}
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
if (driver_write_ccid(itf, ccid_tx[itf].buffer + ccid_tx[itf].r_ptr, ccid_tx[itf].w_ptr - ccid_tx[itf].r_ptr) > 0) {
@@ -344,17 +368,17 @@ void ccid_task() {
}
}
void ccid_init() {
void ccid_init(void) {
ccid_init_buffers();
}
#ifndef ENABLE_EMULATION
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
(void) sent_bytes;
tud_vendor_n_write_flush(itf);
}
#ifndef ENABLE_EMULATION
static void ccid_init_cb(void) {
vendord_init();
}

View File

@@ -40,4 +40,30 @@ enum ccid_state {
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_

View File

@@ -14,8 +14,14 @@
* 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 "pico_keys.h"
#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 <stdio.h>
#ifndef _MSC_VER
@@ -30,7 +36,6 @@ typedef int socket_t;
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
#else
#include <ws2tcpip.h>
#define O_NONBLOCK _O_NONBLOCK
#define close closesocket
typedef SOCKET socket_t;
@@ -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);
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
int msleep(long msec) {
static int msleep(long msec) {
struct timespec ts;
int res;
@@ -80,7 +95,7 @@ int msleep(long msec) {
}
#endif
int emul_init(char *host, uint16_t port) {
int emul_init(const char *host, uint16_t port) {
struct sockaddr_in serv_addr;
fprintf(stderr, "\n Starting emulation envionrment\n");
#ifdef _MSC_VER
@@ -90,7 +105,7 @@ int emul_init(char *host, uint16_t port) {
}
#endif
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
log_sock_error("socket(ccid)");
return -1;
}
@@ -100,13 +115,13 @@ int emul_init(char *host, uint16_t port) {
// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
perror("inet_pton");
log_sock_error("inet_pton(ccid)");
close(ccid_sock);
return -1;
}
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect");
log_sock_error("connect(ccid)");
close(ccid_sock);
return -1;
}
@@ -129,12 +144,12 @@ int emul_init(char *host, uint16_t port) {
struct sockaddr_in server_sockaddr;
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
log_sock_error("socket(hid_server)");
return -1;
}
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);
return 1;
}
@@ -154,20 +169,21 @@ int emul_init(char *host, uint16_t port) {
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
sizeof server_sockaddr) != 0) {
perror("bind");
log_sock_error("bind(hid_server)");
close(hid_server_sock);
return 1;
}
if (listen(hid_server_sock, 0) != 0) {
perror("listen");
if (listen(hid_server_sock, SOMAXCONN) != 0) {
log_sock_error("listen(hid_server)");
close(hid_server_sock);
return 1;
}
fprintf(stderr, "HID server listening on 0.0.0.0:%u\n", hid_port);
return 0;
}
socket_t get_sock_itf(uint8_t itf) {
static socket_t get_sock_itf(uint8_t itf) {
#ifdef USB_ITF_CCID
if (itf == ITF_CCID) {
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);
socket_t sock = get_sock_itf(itf);
// DEBUG_PAYLOAD(buffer,buffer_size);
#ifdef _WIN32
int ret = 0;
#else
ssize_t ret = 0;
#endif
do {
ret = send(sock, (const char *)&size, sizeof(size), 0);
if (ret == SOCKET_ERROR) {
@@ -279,7 +299,11 @@ uint16_t emul_read(uint8_t itf) {
__pragma(warning(pop))
#endif
struct timeval timeout;
#ifdef _WIN32
int valread = 0;
#else
ssize_t valread = 0;
#endif
timeout.tv_sec = 0;
timeout.tv_usec = 0 * 1000;
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
@@ -320,7 +344,7 @@ uint16_t emul_read(uint8_t itf) {
}
#endif
else {
emul_rx_size += valread;
emul_rx_size += (uint16_t)valread;
}
return (uint16_t)emul_rx_size;
}
@@ -333,7 +357,7 @@ uint16_t emul_read(uint8_t itf) {
return emul_rx_size;
}
void emul_task() {
void emul_task(void) {
#ifdef USB_ITF_CCID
emul_read(ITF_CCID);
#endif

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