80 Commits
v1.6 ... v1.12

Author SHA1 Message Date
Pol Henarejos
239e01c3f8 Update extra_command.md
Using new extra INS, from 0x88 to 0x54
2022-04-07 18:34:14 +02:00
Pol Henarejos
4a57698173 Moving out INS_EXTRAS from 0x88 (taken by ISO 7816) to 0x54 (presumably free).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:32:31 +02:00
Pol Henarejos
468051288c Upgrading to version 1.12.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
565ea12d88 Added dynamic option to enable/disable press to confirm.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
1c7ef50568 Added custom INS (named EXTRAS) to support different extra commands. At this moment:
- 0xA: gets/sets the datetime.
- 0x6: enables/disables press to confirm (BOOTSEL). It allows other dynamic device options. At this moment, only press to confirm option is available.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
878eae9787 Added press button to confirm. Everytime a private/secret key is loaded, the Pico HSM waits for BOOTSEL button press. This mechanism guarantees that no private/secret operations are made without user consent. To confirm the operation, the user must press the BOOTSEL button. In the meanwhile, the device gets into waiting state and no other operation is performed. After release the button, the operation continues normally.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
24b1d6807b Added support for reading binary data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
6bc081a1e1 Added support to write arbitrary data EF.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
afb16fff65 Fix with ASN1 encapsulation for keypair generation. It only affects RSA 4096 bits.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
cf81a82645 Added a new custom APDU (88h) for setting and retrieving datetime.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
dc820a60ae Fixed class with USB-ICC specs, for legacy reasons.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 18:18:24 +02:00
Pol Henarejos
c57cc139f6 Update README.md 2022-04-07 00:10:09 +02:00
Pol Henarejos
79426f35cd Update extra_command.md
Added dynamic options and press-to-confirm enabling/disabling.
2022-04-07 00:06:44 +02:00
Pol Henarejos
502a7ba81c Create store_data.md 2022-04-06 23:56:29 +02:00
Pol Henarejos
deef209687 Update README.md
Added press-to-confirm description.
Added links to storage binary data.
Added links to extra command to enable/disable button.
Added links to setting/getting datetime.
2022-04-06 19:52:10 +02:00
Pol Henarejos
bb09f212d2 Create extra_command.md
Add get/set datetime explanation.
2022-04-06 19:51:05 +02:00
Pol Henarejos
cfd86df45e Update README.md
Added led blink meaning.
2022-04-06 17:25:07 +02:00
Pol Henarejos
d16c9b2324 Update README.md
Adding operation time for RSA (signature and decrypt). It is relevant for RSA 3K and 4K.
2022-04-04 22:27:33 +02:00
Pol Henarejos
f1630023c7 Update README.md
Added keygen time for 3k and 4k.
2022-04-04 21:56:40 +02:00
Pol Henarejos
d41a488eda Adding support for Transport PIN.
Adding support for initialize options.
2022-04-04 10:07:23 +02:00
Pol Henarejos
375a18ebac Update README.md
Fix RSA 4096 doc link.
2022-04-04 10:04:47 +02:00
Pol Henarejos
20216ac4ba Update README.md 2022-04-04 10:01:16 +02:00
Pol Henarejos
d27d8b0c5b Upgrading to version 1.10
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-04 09:57:19 +02:00
Pol Henarejos
a619527482 Adding P1=0x2 and P1=0x3 for reset retry counter.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-03 20:59:50 +02:00
Pol Henarejos
85ff92c4de Adding check for device options whether it can reset retry counter with PIN or without.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-03 20:40:16 +02:00
Pol Henarejos
b1121718db Adding capability to reset retry counter without new PIN
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-03 20:37:16 +02:00
Pol Henarejos
2905dcc8c0 Adding custom command to set datetime.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-03 19:57:56 +02:00
Pol Henarejos
c9855f7214 Fix displaying device options.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 19:43:33 +02:00
Pol Henarejos
853b8f29a2 Fix returning kcv when pin is not provided. It always return 0x0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 19:31:56 +02:00
Pol Henarejos
d5378ffa41 If has_session_pin is true, it returns sw_ok
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 19:31:22 +02:00
Pol Henarejos
4400eba974 Fix returning kcv
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 19:31:02 +02:00
Pol Henarejos
0cc656c6c0 Adding transport PIN option. It does not allow to authenticate and returns sw code 0x6984
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 19:12:56 +02:00
Pol Henarejos
c9b32ab5d0 Fix return pin blocked sw code.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 18:59:54 +02:00
Pol Henarejos
f9ffd39661 Adding EF_DEVOPS to store the device options during the initialization.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 18:56:42 +02:00
Pol Henarejos
bfc12d6856 Renaming files
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 18:27:00 +02:00
Pol Henarejos
11874b52de Merge branch 'master' into eac 2022-03-31 14:46:28 +02:00
Pol Henarejos
b4e928588e Updating tools to 1.8
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 14:32:57 +02:00
Pol Henarejos
33a2222cd8 Revert "PIN remaining tries only returned when user is not logged in. If so, it returns always OK."
This reverts commit 86e38419ac.
2022-03-31 14:30:50 +02:00
Pol Henarejos
923e05a36c Revert "Also for SOPIN."
This reverts commit ad66170379.
2022-03-31 14:30:50 +02:00
Pol Henarejos
b5cc4d6fd7 Update README.md 2022-03-31 13:32:18 +02:00
Pol Henarejos
25291f978f Create rsa_4096.md 2022-03-31 13:23:02 +02:00
Pol Henarejos
ad66170379 Also for SOPIN.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 13:18:56 +02:00
Pol Henarejos
86e38419ac PIN remaining tries only returned when user is not logged in. If so, it returns always OK.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 13:17:16 +02:00
Pol Henarejos
1a5e6a7edc Merge branch 'eac'. Support for PKCS#12 imports with SCS3. 2022-03-31 11:37:50 +02:00
Pol Henarejos
7cf166d615 Upgrading to version 1.8
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 11:18:52 +02:00
Pol Henarejos
413c3e0208 Fix update ef when offset is required.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 01:08:39 +02:00
Pol Henarejos
7410498df1 Fix with RSA CRT import mode (keytype 6).
In RSA CRT import, the N parameter shall not be imported. Otherwise, mbedtls will fail (it is deduced from N=PQ).

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-31 00:24:50 +02:00
Pol Henarejos
7aee18110e Fix kmac and kenc computation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-30 23:59:06 +02:00
Pol Henarejos
7aca7b323a Fix loading kcv, kenc and kmac.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-30 23:21:23 +02:00
Pol Henarejos
4651a0e224 Adding AES wrapping/unwrapping
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-30 01:33:54 +02:00
Pol Henarejos
d018e3b9b9 Adding RSA and EC wrap/unwrap, compatible with SC HSM wrap format.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-30 00:59:37 +02:00
Pol Henarejos
1c272842a7 Adding dkek_decode_key for unwrapping.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 20:18:08 +02:00
Pol Henarejos
0141e0ab4e Adding ec curve find from prime.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 20:17:42 +02:00
Pol Henarejos
e7d8695394 Added length checks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 19:16:15 +02:00
Pol Henarejos
6876edea5a Some fix in encode key
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 19:06:00 +02:00
Pol Henarejos
2e655d6341 Fixes with AES encryption
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 18:25:47 +02:00
Pol Henarejos
2f4cca19c4 Moving some dkek crypt stuff to dkek.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 13:45:28 +02:00
Pol Henarejos
5eb74d8ca3 Adding encode_key with dkek (for wrapping).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 13:45:07 +02:00
Pol Henarejos
7b0d5a6700 Fix loading aes key in decrypt function
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 09:35:06 +02:00
Pol Henarejos
427260663f Replacing CFB to CBC AES proc
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-29 09:34:44 +02:00
Pol Henarejos
047a443536 Adding dkek procedures to wrap/unwrap.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 17:38:15 +02:00
Pol Henarejos
7a9ee8145d Adding headers to random.h
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 17:38:02 +02:00
Pol Henarejos
2535d0e537 Adding generic aes encryption/decryption.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 17:37:53 +02:00
Pol Henarejos
6fe7d7991b Len of CMAC is always 16.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 17:37:24 +02:00
Pol Henarejos
d061958f90 Moving hash to other file.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 16:02:28 +02:00
Pol Henarejos
3112200eb6 Merge branch 'eac' 2022-03-28 14:04:05 +02:00
Pol Henarejos
69a406832d Adding hsm initializing options
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 01:37:36 +02:00
Pol Henarejos
cd4ceb0a61 Fix returning current dkeks when the device is initialized without dkeks.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-28 01:37:19 +02:00
Pol Henarejos
450ec5dec1 Also list PRKD files.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 20:47:11 +02:00
Pol Henarejos
c7abd1a067 Adding DKEK report
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 20:27:10 +02:00
Pol Henarejos
c6d87756ab Adding SOPIN verification.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 19:00:21 +02:00
Pol Henarejos
0916489388 Initialization now returns free memory if no parameters are given.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 18:53:41 +02:00
Pol Henarejos
b1e83c92e9 Adding cvcerts and dica
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 18:15:16 +02:00
Pol Henarejos
d01e06aa11 2F02 returns terminal's cvcert and DICA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 18:15:06 +02:00
Pol Henarejos
464107b13f Adding tag 85 for FCP when selecting applet
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 12:26:36 +02:00
Pol Henarejos
e431b25fc1 Not used
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 12:26:36 +02:00
Pol Henarejos
e4ed917c1c Updating to v1.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 12:26:35 +02:00
Pol Henarejos
ade3e6d2fb Added sanity check for some boards without led.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 12:26:35 +02:00
Pol Henarejos
d12d18261f Changing name of generic pico.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-03-27 12:26:35 +02:00
Pol Henarejos
525b4439c9 Update README.md 2022-03-25 16:56:53 +01:00
22 changed files with 1701 additions and 758 deletions

View File

@@ -51,6 +51,8 @@ target_sources(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
@@ -117,7 +119,7 @@ pico_add_extra_outputs(pico_hsm)
#target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id)
target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)
#
#project(flash_nuke C CXX ASM)

View File

@@ -6,7 +6,7 @@ This is a project to create a Hardware Security Module (HSM) with a Raspberry Pi
- RSA key generation from 1024 to 4096 bits.
- ECDSA key generation from 192 to 521 bits.
- ECC curves secp192r1, secp256r1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, secp192k1 (insecure), secp256k1.
- SHA1, SHA224, SHA256, SHA384, SHA256 digests.
- SHA1, SHA224, SHA256, SHA384, SHA512 digests.
- RSA-PSS, RSA-PKCS and raw RSA signature.
- ECDSA raw and hash signature.
- ECDH key derivation.
@@ -23,11 +23,18 @@ This is a project to create a Hardware Security Module (HSM) with a Raspberry Pi
- DKEK n-of-m threshold scheme.
- USB/CCID support with OpenSC, openssl, etc.
- Extended APDU support.
- Private keys and certificates import from WKY or PKCS#12 files.[^2][^3]
- Transport PIN for provisioning and forcing to set a new PIN.[^2]
- Press-to-confirm button optional feature to authorize operations with private/secret keys.
- Store and retrieve binary data.
- Real time clock with external datetime setting and getting.
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
[^2]: Available via SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
[^3]: Imports are available only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process.
## Security considerations
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DKEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations. All keys (including DKEK) are loaded and cleared every time to avoid potential flaws.
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DKEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations and only during the process. All keys (including DKEK) are loaded and cleared every time to avoid potential security flaws.
At the same time, DKEK is encrypted with doubled salted and hashed PIN. Also, the PIN is hashed in memory during the session. Hence, PIN is never stored in plain text neither in flash nor in memory. Note that PIN is conveyed from the host to the HSM in plain text if no secure channel is provided.
@@ -80,6 +87,60 @@ For backup, restore and DKEK share management, check [doc/backup-and-restore.md]
For AES key generation, encryption and decryption, check [doc/aes.md](/doc/aes.md).
For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096.md).
For storing and retrieving arbitrary data, check [doc/store_data.md](/doc/store_data.md).
For extra options, such as set/get real datetime or enable/disable press-to-confirm button, check [doc/extra_command.md](/doc/extra_command.md).
## Operation time
### Keypair generation
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `3072` and `4096` bits.
| RSA key length (bits) | Average time (seconds) |
| :---: | :---: |
| 1024 | 16 |
| 2048 | 124 |
| 3072 | 600 |
| 4096 | ~1000 |
### Signature and decrypt
| RSA key length (bits) | Average time (seconds) |
| :---: | :---: |
| 1024 | 1 |
| 2048 | 3 |
| 3072 | 7 |
| 4096 | 15 |
## Press-to-confirm button
Raspberry Pico comes with the BOOTSEL button to load the firmware. When this firmware is running, the button can be used for other purposes. Pico HSM uses this button to confirm private/secret operations. This feature is optional and it shall be enabled. For more information, see [doc/extra_command.md](/doc/extra_command.md).
With this feature enabled, everytime that a private/secret key is loaded, the Pico HSM awaits for the user confirmation by pressing the BOOTSEL button. The Led of the Pico HSM will remain almost illuminated, turning off quickly once a second, indicating that the user must press the button to confirm the operation. Otherwise, the Pico HSM waits indefinitely. See [Led blink](#press-to-confirm) for a picture of the blinking sequence. When in this mode, the Pico HSM sends periodic timeout commands to the host to do not trigger the timeout operation.
This feature is an extra layer of security, as it requires the user intervention to sign or decrypt and it ensures that any application will use the Pico HSM without user awareness. However, it is not recommended for servers or other environments where operations are authomatized, since it requires a physical access to the Pico HSM to push the button.
## Led blink
Pico HSM uses the led to indicate the current status. Four states are available:
### Press to confirm
The Led is almost on all the time. It goes off for 100 miliseconds every second.
![Press to confirm](https://user-images.githubusercontent.com/55573252/162008917-6a730eac-396c-44cc-890e-802294be30a3.gif)
### Idle mode
In idle mode, the Pico HSM goes to sleep. It waits for a command and it is awaken by the driver. The Led is almost off all the time. It goes on for 500 milliseconds every second.
![Idle mode](https://user-images.githubusercontent.com/55573252/162008980-d5a5caad-072e-400c-98e3-2c606b4b2af9.gif)
### Active mode
In active mode, the Pico HSM is awaken and ready to receive a command. It blinks four times in a second.
![Active](https://user-images.githubusercontent.com/55573252/162008997-1ea8cd7e-5384-4893-9dcb-b473153fc375.gif)
### Processing
While processing, the Pico HSM is busy and cannot receive additional commands until the current is processed. In this state, the Led blinks 20 times in a second.
![Processing](https://user-images.githubusercontent.com/55573252/162009007-df45111e-2473-4a92-97c5-15c3cd19babd.gif)
## Driver
Pico HSM uses the `sc-hsm` driver provided by [OpenSC](https://github.com/OpenSC/OpenSC/ "OpenSC") or the `sc-hsm-embedded` driver provided by [CardContact](https://github.com/CardContact/sc-hsm-embedded "CardContact"). This driver utilizes the standardized PKCS#11 interface to communicate with the user and it can be used with many engines that accept PKCS#11 interface, such as OpenSSL, P11 library or pkcs11-tool.
@@ -90,6 +151,8 @@ The way to communicate is exactly the same as with other cards, such as OpenPGP
For an advanced usage, see the docs and examples.
Pico HSM also supports SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
### Important
OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a pair of VID/PID of supported readers. In order to be detectable, you must patch the UF2 binary (if you just downloaded from the [Release section](https://github.com/polhenarejos/pico-hsm/releases "Release section")) or configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.

View File

@@ -1,10 +1,10 @@
#!/bin/bash
VERSION_MAJOR="1"
VERSION_MINOR="6"
VERSION_MINOR="12"
rm -rf release/*
cd build
cd build_release
for board in adafruit_feather_rp2040 adafruit_itsybitsy_rp2040 adafruit_qtpy_rp2040 adafruit_trinkey_qt2040 arduino_nano_rp2040_connect melopero_shake_rp2040 pimoroni_interstate75 pimoroni_keybow2040 pimoroni_pga2040 pimoroni_picolipo_4mb pimoroni_picolipo_16mb pimoroni_picosystem pimoroni_plasma2040 pimoroni_tiny2040 pybstick26_rp2040 sparkfun_micromod sparkfun_promicro sparkfun_thingplus vgaboard waveshare_rp2040_lcd_0.96 waveshare_rp2040_plus_4mb waveshare_rp2040_plus_16mb waveshare_rp2040_zero
do
@@ -18,4 +18,4 @@ done
rm -rf *
PICO_SDK_PATH=~/Devel/pico/pico-sdk cmake ..
make -kj20
mv pico_hsm.uf2 ../release/pico_hsm-$VERSION_MAJOR.$VERSION_MINOR.uf2
mv pico_hsm.uf2 ../release/pico_hsm_pico_generic-$VERSION_MAJOR.$VERSION_MINOR.uf2

86
doc/extra_command.md Normal file
View File

@@ -0,0 +1,86 @@
# Extra command
Pico HSM supports a customized extra command to use with different options. Since the drivers in the market do not support the following features, a raw APDU command shall be sent.
To send a raw APDU command, `opensc-tool -s <APDU>` can be used. The `APDU` parameter is a string of hexadecimal numbers and it takes the following form:
```
8054XX00YYZZZZRR
```
It composed by the following fields:
- `80` to indicate that it is a custom vendor type command.
- `54` is the `INS` custom command.
- `XX` is the command to execute. It varies depending on the targeted command.
- `00` is the parameter of the command. At this moment, no commands support parameters.
- `YY` is the length of the data. If no data is provided, this field is absent.
- `ZZZZ` is the data to be sent. Optional. The length is variable.
- `RR` is the length of the expected response. If no response is expected, this field is absent.
## Real time clock and datetime
Pico HSM has an internal real time clock (RTC) which can track precisely the date and the time. However, when it is reset or powered down, the Pico HSM is reset to the initial datetime: 2020 January 1, 00:00:00.
### Getting the datetime
To obtain the current datetime (referenced to 00:00:00 2020/01/01), the `XX` parameter must be set to `0A`. There is no data and, thus, `YY` and `ZZZZ` are absent. The expected response is 8 bytes length.
For example, to obtain the current datetime:
```
$ opensc-tool -s 80540A0008
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 54 0A 00 08
Received (SW1=0x90, SW2=0x00):
07 E6 04 06 03 13 29 1E ......).
```
The response is composed by 8 bytes:
- The first two bytes are the current year, MSB first. Hence, `07E6h` equals to `2022`.
- 1 byte for the current month, `01h` is January and `0Ch` is December.
- 1 byte for the current day, from `01h` (1) to `1Fh` (31).
- 1 byte for the day of the week, `00h` is Sunday, `01h` is Monday, etc.
- 1 byte for the hours, from `00h` (0) to `17h` (23).
- 1 byte for the minutes, from `00h` (0) to `3Bh` (59).
- 1 byte for the seconds, from `00h` (0) to `3Bh` (59).
If the command is correctly received, `SW1=0x90` and `SW2=0x00`. Other values mean that an error has ocurred.
### Setting the datetime
To set the reference datetime, a datetime string must be provided. For example:
```
$ opensc-tool -s 80540A000807E6040603132917
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 54 0A 00 08 07 E6 04 06 03 13 29 17
Received (SW1=0x90, SW2=0x00)
```
will set the reference datetime to `Wednesday, 2022 April 6th, 19:41:23`.
## Dynamic options
Pico HSM support initialize options, such as setting Transport PIN or reset retry counter options. However, once it is initialized, these options cannot be modified anymore, without a new initialization (loosing all stored keys). Pico HSM offers the chance to define a set of dynamic options that can be enabled/disabled dynamically without initializing the device at every moment.
To specify a set of options, the `XX` parameter shall be set to `06`. The data parameter shall be 1 byte, where the options are combined with the or operand `|`. The length `YY` shall be set to `01`.
### Press-to-confirm button
Press-to-confirm button offers an extra security layer by requiring the user confirmation everytime that a private/secret key is loaded. This avoids ghost applications thay may perform hidden opperations without noticing the user, such as signing or decrypting. Pico HSM will inform the user that is awaiting for a confirmation by making almost a fixed Led blink.
This feature is disabled by default but can be enabled rapidly by setting the LSB bit to 1:
```
$ opensc-tool -s 805406000101
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 54 06 00 01 01
Received (SW1=0x90, SW2=0x00)
```
At this moment, when a private/secret key is loaded, the Pico HSM will wait for the pressed BOOTSEL button to confirm the operation.
To disable, the LSB bit must be set to 0:
```
$ opensc-tool -s 805406000100
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 54 06 00 01 00
Received (SW1=0x90, SW2=0x00)
```

49
doc/rsa_4096.md Normal file
View File

@@ -0,0 +1,49 @@
# RSA 4096 support
Generating 4096 bits key in the Pico HSM is highly expensive. It may take minutes or hours to finish the generation. Therefore, it is extremely recommendable to generate the key in the host and import it into the Pico HSM.
## SCS3 tool
Unfortunately, there is no pkcs11 tool or equivalent capable to perform the import. Since it uses the SC-HSM driver, it also supports the communication with the [SCS3 tool](https://www.openscdp.org/scsh3/ "SCS3 tool"). It can be downloaded from [here](https://www.openscdp.org/scsh3/download.html "here").
However, SCS3 only works with those HSM manufactured by CardContact. The check is performed by means of trust store against the manufacturing certificates. For obvious reasons, these certificates can only be signed with the private keys of the Certificate Authorities listed in the trust store.
Pico HSM is shipped with its own CA certificates. To load this certificate onto the trust store of SCS3, the following line has to be appended to `SmartCardHSM.rootCerts` variable, near line `235` in the file `scs3/scsh/sc-hsm/SmartCardHSM.js`.
```
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
```
Therefore, the whole variable becomes:
```
SmartCardHSM.rootCerts = {
DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)),
UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX)),
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
}
````
After this ammendment, the KeyManager can be invoked (CTRL+M) and it will output something similar to:
```
>load("keymanager/keymanager.js");
SmartCard-HSM Version 1.6 on JCOP Free memory 217104 byte
Issuer Certificate : CVC id-AT DV (official domestic) CAR=ESCVCAHSM00001 CHR=ESDVCAHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2025
Device Certificate : CVC id-AT Terminal CAR=ESDVCAHSM00001 CHR=ESTERMHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2023
Default Key Domain : 0F89B400975EDD2D425ABF85F2FBD318779B3D85475E65D4
-------------------------------------------------------------------
Please right-click on nodes in the outline to see possible actions.
For most operations you will need to authenticate first using a
mechanism from the User PIN context menu.
>
```
The SCS3 tool is ready to import private keys and certificates, wraped in WKY files or in PKCS#12 format. Also, all stored keys can be exported, combined with their respective certificates. Note that the user has to be previously logged in.
## DKEK requirement
In order to perform the import, private keys must be wrapped with the same DKEK present in the Pico HSM. Thus, the Pico HSM must be previously initialized with at minimum of 1 DKEK share. This share will be used to wrap the private key before import.
Note that the DKEK share shall be available before the import. In this way, all custodians must be present during the import process, since they will have to introduce their respective DKEK.

117
doc/store_data.md Normal file
View File

@@ -0,0 +1,117 @@
# Store binary data
Pico HSM has a internal flash which can store binary data. With this approach, you can save different files, encrypt into the Pico HSM and retrieve them after.
## Maximum size
Due to internal constraints with the flash components, the maximum file size is `4096` bytes. This mechanism is mainly used to store small files, such as keys in plain text, certificates, credentials, etc.
## Store a file
Before writting a file into the Pico HSM, we generate the data file with the following text:
```
$ echo 'Pico HSM is awesome!' > test
```
Then, we can store the data file with the following command:
```
$ pkcs11-tool --pin 648219 --write-object test --type data --id 1 --label 'test1'
Using slot 0 with a present token (0x0)
Created Data Object:
Data object 1236368320
label: 'test1'
application: 'test1'
app_id: <empty>
flags: modifiable
```
This file can also be protected with the PIN. In this case, use the previous command with the `--private` flag:
```
$ pkcs11-tool --pin 648219 --write-object test --type data --id 2 --label 'test2' --private
Using slot 0 with a present token (0x0)
Created Data Object:
Data object 1329612320
label: 'test2'
application: 'test2'
app_id: <empty>
flags: modifiable private
```
Always provide a unique `--label`, as it will be used to index and reference the file for retrieving.
## Retrieve a file
To view the stored file, we can use the following command with the same label we employed:
```
$ pkcs11-tool --read-object --type data --label 'test1'
Using slot 0 with a present token (0x0)
Pico HSM is awesome!
```
Note that if the `--private` flag is not provided during the writting stage, the file can be accessed without the PIN.
To retrieve a private file with the PIN:
```
$ pkcs11-tool --read-object --type data --label 'test2' --pin 648219
Using slot 0 with a present token (0x0)
Pico HSM is awesome!
```
## Using `pkcs15-tool`
PKCS15 tool can be used to list the stored files. For instance:
```
$ pkcs15-tool -D
Using reader with a card: Free Software Initiative of Japan Gnuk
PKCS#15 Card [Pico-HSM]:
Version : 1
Serial number : ESTERMHSM
Manufacturer ID: Pol Henarejos
Flags : PRN generation, EID compliant
PIN [UserPIN]
Object Flags : [0x03], private, modifiable
Auth ID : 02
ID : 01
Flags : [0x812], local, initialized, exchangeRefData
Length : min_len:6, max_len:15, stored_len:0
Pad char : 0x00
Reference : 129 (0x81)
Type : ascii-numeric
Path : e82b0601040181c31f0201::
Tries left : 3
PIN [SOPIN]
Object Flags : [0x01], private
ID : 02
Flags : [0x9A], local, unblock-disabled, initialized, soPin
Length : min_len:16, max_len:16, stored_len:0
Pad char : 0x00
Reference : 136 (0x88)
Type : bcd
Path : e82b0601040181c31f0201::
Tries left : 15
Data object 'test1'
applicationName: test1
Path: e82b0601040181c31f0201::cf00
Data (21 bytes): 5069636F2048534D20697320617765736F6D65210A
Data object 'test2'
applicationName: test2
Path: e82b0601040181c31f0201::cd01
Auth ID: 01
```
As expected, the public file is displayed (in hexadecimal string). The private file contains the `Auth ID` flag and it is not displayed.
## Delete a file
A stored file can be deleted with the following command:
```
$ pkcs11-tool --login --pin 648219 --delete-object --type data --application-label test1
```

View File

@@ -18,7 +18,7 @@
#
VERSION_MAJOR="1"
VERSION_MINOR="4"
VERSION_MINOR="0C"
echo "----------------------------"
echo "VID/PID patcher for Pico HSM"

View File

@@ -78,55 +78,15 @@ void process_fci(const file_t *pe) {
res_APDU[1] = res_APDU_size-2;
}
const uint8_t cvca[] = {
0x6A, 0x01,
0x7f, 0x21, 0x82, 0x01, 0x65, 0x7f, 0x4e, 0x82, 0x01, 0x2d, 0x5f,
0x29, 0x01, 0x00, 0x42, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x49, 0x81,
0xdd, 0x06, 0x0a, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x02, 0x02, 0x02,
0x02, 0x03, 0x81, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x18, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x83,
0x18, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7, 0x0f, 0xa7,
0xe9, 0xab, 0x72, 0x24, 0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1,
0x46, 0xb9, 0xb1, 0x84, 0x31, 0x04, 0x18, 0x8d, 0xa8, 0x0e, 0xb0,
0x30, 0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00,
0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12, 0x07, 0x19, 0x2b,
0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11, 0x85,
0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x99, 0xde, 0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4,
0xd2, 0x28, 0x31, 0x86, 0x31, 0x04, 0x4d, 0x28, 0x34, 0x67, 0xb5,
0x43, 0xfd, 0x84, 0x22, 0x09, 0xbd, 0xd2, 0xd6, 0x26, 0x27, 0x2d,
0x53, 0xa7, 0xdf, 0x52, 0x8f, 0xc2, 0xde, 0x7c, 0x9a, 0xcd, 0x1f,
0xf2, 0x10, 0x42, 0x7c, 0x13, 0x44, 0x03, 0xb0, 0xa5, 0xdf, 0x8a,
0xd4, 0x59, 0xd1, 0x86, 0x4b, 0xde, 0x33, 0xb1, 0x60, 0x17, 0x87,
0x01, 0x01, 0x5f, 0x20, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x4c, 0x12,
0x06, 0x09, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x01, 0x02, 0x02,
0x53, 0x05, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x25, 0x06, 0x02,
0x02, 0x00, 0x02, 0x01, 0x09, 0x5f, 0x24, 0x06, 0x03, 0x00, 0x01,
0x02, 0x03, 0x01, 0x5f, 0x37, 0x30, 0x26, 0x2d, 0x6f, 0xa6, 0xd0,
0x52, 0x01, 0xf1, 0x41, 0x1e, 0xe9, 0x33, 0x29, 0x19, 0x42, 0x42,
0x9b, 0xb0, 0xeb, 0xf7, 0x46, 0x20, 0xcb, 0x81, 0xfe, 0xda, 0xd7,
0xab, 0x2b, 0xdc, 0xa7, 0x38, 0xf4, 0xc8, 0xec, 0x4c, 0x66, 0xb4,
0x0a, 0x2d, 0x16, 0xfb, 0xf3, 0x79, 0xe9, 0x93, 0xc8, 0x25
};
const uint8_t token_info[] = {
0x28, 0x00, //litle endian
0x30, 0x26, 0x2, 0x1, 0x1, 0x4, 0x4, 0xd, 0x0, 0x0, 0x0, 0xc, 0xd, 0x50, 0x6f, 0x6c, 0x20, 0x48, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x6a, 0x6f, 0x73, 0x80, 0x8, 0x48, 0x53, 0x4d, 0x20, 0x32, 0x30, 0x34, 0x30, 0x3, 0x2, 0x4, 0xf0
};
extern const uint8_t sc_hsm_aid[];
extern int parse_token_info(const file_t *f, int mode);
extern int parse_cvca(const file_t *f, int mode);
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 = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
@@ -139,15 +99,16 @@ file_t file_entries[] = {
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
/* 16 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
/* 17 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
/* 18 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
/* 19 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
/* 20 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
/* 21 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
///* 22 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 23 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 24 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
};
const file_t *MF = &file_entries[0];
@@ -301,19 +262,8 @@ void scan_flash() {
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) {
file = file_new(fid);
if ((fid & 0xff00) == (KEY_PREFIX << 8)) {
//add_file_to_chain(file, &ef_kf);
}
else if ((fid & 0xff00) == (PRKD_PREFIX << 8)) {
//add_file_to_chain(file, &ef_prkdf);
}
else if ((fid & 0xff00) == (CD_PREFIX << 8)) {
//add_file_to_chain(file, &ef_cdf);
}
else if ((fid & 0xff00) == (EE_CERTIFICATE_PREFIX << 8)) {
//add_file_to_chain(file, &ef_pukdf);
}
else {
uint8_t pfx = fid >> 8;
if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) {
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
continue;
}

View File

@@ -60,6 +60,7 @@
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
#define MAX_DEPTH 4

142
src/hsm/crypto_utils.c Normal file
View File

@@ -0,0 +1,142 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <pico/unique_id.h>
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "crypto_utils.h"
#include "sc_hsm.h"
#include "libopensc/card-sc-hsm.h"
void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
uint8_t o1[32];
hash_multi(pin, len, o1);
for (int i = 0; i < sizeof(o1); i++)
o1[i] ^= pin[i%len];
hash_multi(o1, sizeof(o1), output);
}
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
int iters = 256;
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id));
while (iters > len)
{
mbedtls_sha256_update (&ctx, input, len);
iters -= len;
}
if (iters > 0) // remaining iterations
mbedtls_sha256_update (&ctx, input, iters);
mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_free (&ctx);
}
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update (&ctx, input, len);
mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_free (&ctx);
}
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
mbedtls_md_setup(&ctx, md_info, 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, input, len);
mbedtls_md_finish(&ctx, output);
mbedtls_md_free(&ctx);
}
int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv)
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0)
return HSM_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE);
if (iv)
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0)
return HSM_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
}
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
}
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
}
struct ec_curve_mbed_id {
struct sc_lv_data curve;
mbedtls_ecp_group_id id;
};
struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 },
{ { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 },
{ { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 },
{ { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 },
{ { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 },
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 },
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
};
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
return ec->id;
}
}
return MBEDTLS_ECP_DP_NONE;
}

46
src/hsm/crypto_utils.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CRYPTO_UTILS_H_
#define _CRYPTO_UTILS_H_
#include "stdlib.h"
#include "pico/stdlib.h"
#include "mbedtls/ecp.h"
#include "mbedtls/md.h"
#define HSM_KEY_RSA 0x1
#define HSM_KEY_EC 0x10
#define HSM_KEY_AES 0x100
#define HSM_KEY_AES_128 0x300
#define HSM_KEY_AES_192 0x500
#define HSM_KEY_AES_256 0x900
#define HSM_AES_MODE_CBC 1
#define HSM_AES_MODE_CFB 2
extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]);
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output);
extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
#endif

41
src/hsm/cvcerts.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef CVCERTS_H_
#define CVCERTS_H_
static const unsigned char termca[] = {
0xfa, 0x00,
0x7f,0x21,0x81,0xf6,0x7f,0x4e,0x81,0xbf,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x0f,0x89,
0xb4,0x00,0x97,0x5e,0xdd,0x2d,0x42,0x5a,0xbf,0x85,0xf2,0xfb,0xd3,0x18,0x77,0x9b,
0x3d,0x85,0x47,0x5e,0x65,0xd4,0xd8,0x58,0x69,0xd3,0x04,0x14,0xb7,0x1f,0x16,0x1e,
0xb0,0x40,0xd9,0xf7,0xa7,0xe3,0x73,0xa3,0x15,0xc7,0xd9,0x9a,0x51,0xf5,0x5f,0x20,
0x0e,0x45,0x53,0x54,0x45,0x52,0x4d,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x00,
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
0x02,0x03,0x01,0x02,0x03,0x01,0x65,0x2f,0x73,0x2d,0x06,0x09,0x04,0x00,0x7f,0x00,
0x07,0x03,0x01,0x03,0x01,0x80,0x20,0x68,0x53,0x30,0xc7,0x9a,0x47,0xad,0xfd,0x37,
0xaa,0xe8,0x53,0xf4,0xbd,0x77,0x3a,0x40,0x89,0x3a,0x79,0x7e,0x3c,0x27,0x18,0x3b,
0x39,0x67,0xdf,0x8d,0x4f,0xe5,0x99,0x5f,0x37,0x30,0x10,0xff,0x17,0x96,0x0d,0x93,
0x07,0xc0,0x69,0x8e,0x3a,0xa0,0x44,0x69,0x70,0x88,0xe6,0x9c,0xb4,0xd3,0x16,0x9a,
0x22,0x4e,0x5c,0x77,0xa9,0xe7,0x83,0x75,0x9a,0xd2,0x7e,0x92,0xf2,0x04,0x93,0xb1,
0xe9,0xc9,0xe5,0x10,0xc9,0x94,0xff,0x9d,0xe2,0x00
};
static const unsigned char dica[] = {
0xc9, 0x00,
0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e,
0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb,
0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08,
0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20,
0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80,
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5,
0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d,
0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99,
0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d
};
#endif

474
src/hsm/dkek.c Normal file
View File

@@ -0,0 +1,474 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* 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 <string.h>
#include "common.h"
#include "stdlib.h"
#include "pico/stdlib.h"
#include "dkek.h"
#include "crypto_utils.h"
#include "random.h"
#include "sc_hsm.h"
#include "mbedtls/md.h"
#include "mbedtls/cmac.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
static uint8_t dkek[IV_SIZE+32];
static uint8_t tmp_dkek[32];
extern bool has_session_pin;
extern uint8_t session_pin[32];
int load_dkek() {
if (has_session_pin == false)
return HSM_NO_LOGIN;
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf)
return HSM_ERR_FILE_NOT_FOUND;
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
if (ret != 0)
return HSM_EXEC_ERROR;
return HSM_OK;
}
void release_dkek() {
memset(dkek, 0, sizeof(dkek));
}
void init_dkek() {
release_dkek();
memset(tmp_dkek, 0, sizeof(tmp_dkek));
}
int store_dkek_key() {
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf)
return HSM_ERR_FILE_NOT_FOUND;
flash_write_data_to_file(tf, dkek, sizeof(dkek));
low_flash_available();
release_dkek();
return HSM_OK;
}
int save_dkek_key(const uint8_t *key) {
const uint8_t *iv = random_bytes_get(32);
memcpy(dkek, iv, IV_SIZE);
if (!key)
key = tmp_dkek;
memcpy(dkek+IV_SIZE, key, 32);
return store_dkek_key();
}
void import_dkek_share(const uint8_t *share) {
for (int i = 0; i < 32; i++)
tmp_dkek[i] ^= share[i];
}
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
uint8_t hsh[32];
int r = load_dkek();
if (r != HSM_OK)
return r;
hash256(dkek+IV_SIZE, 32, hsh);
release_dkek();
memcpy(kcv, hsh, 8);
return HSM_OK;
}
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
uint8_t buf[32+4];
int r = load_dkek();
if (r != HSM_OK)
return r;
memcpy(buf, dkek+IV_SIZE, 32);
release_dkek();
memcpy(buf+32, "\x0\x0\x0\x1", 4);
hash256(buf, sizeof(buf), kenc);
memset(buf, 0, sizeof(buf));
return HSM_OK;
}
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
uint8_t buf[32+4];
int r = load_dkek();
if (r != HSM_OK)
return r;
memcpy(buf, dkek+IV_SIZE, 32);
release_dkek();
memcpy(buf+32, "\x0\x0\x0\x2", 4);
hash256(buf, sizeof(buf), kmac);
memset(buf, 0, sizeof(buf));
return HSM_OK;
}
int dkek_encrypt(uint8_t *data, size_t len) {
int r;
if ((r = load_dkek()) != HSM_OK)
return r;
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek();
return r;
}
int dkek_decrypt(uint8_t *data, size_t len) {
int r;
if ((r = load_dkek()) != HSM_OK)
return r;
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek();
return r;
}
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) {
if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
return HSM_WRONG_DATA;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
memset(kb, 0, sizeof(kb));
int kb_len = 0;
uint8_t *algo = NULL;
uint8_t algo_len = 0;
uint8_t *allowed = NULL;
uint8_t allowed_len = 0;
uint8_t kenc[32];
memset(kenc, 0, sizeof(kenc));
dkek_kenc(kenc);
uint8_t kcv[8];
memset(kcv, 0, sizeof(kcv));
dkek_kcv(kcv);
uint8_t kmac[32];
memset(kmac, 0, sizeof(kmac));
dkek_kmac(kmac);
if (key_type & HSM_KEY_AES) {
if (key_type & HSM_KEY_AES_128)
kb_len = 16;
else if (key_type & HSM_KEY_AES_192)
kb_len = 24;
else if (key_type & HSM_KEY_AES_256)
kb_len = 32;
if (kb_len != 16 && kb_len != 24 && kb_len != 32)
return HSM_WRONG_DATA;
if (*out_len < 8+1+10+6+4+(2+32+14)+16)
return HSM_WRONG_LENGTH;
put_uint16_t(kb_len, kb+8);
memcpy(kb+10, key_ctx, kb_len);
kb_len += 2;
algo = "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8)
algo_len = 10;
allowed = "\x00\x04\x10\x11\x18\x99"; //(2+4)
allowed_len = 6;
}
else if (key_type & HSM_KEY_RSA) {
if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
return HSM_WRONG_LENGTH;
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
kb_len = 0;
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
put_uint16_t(mbedtls_mpi_size(&rsa->D), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&rsa->D, kb+8+kb_len, mbedtls_mpi_size(&rsa->D)); kb_len += mbedtls_mpi_size(&rsa->D);
put_uint16_t(mbedtls_mpi_size(&rsa->N), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&rsa->N, kb+8+kb_len, mbedtls_mpi_size(&rsa->N)); kb_len += mbedtls_mpi_size(&rsa->N);
put_uint16_t(mbedtls_mpi_size(&rsa->E), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&rsa->E, kb+8+kb_len, mbedtls_mpi_size(&rsa->E)); kb_len += mbedtls_mpi_size(&rsa->E);
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02";
algo_len = 12;
}
else if (key_type & HSM_KEY_EC) {
if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
return HSM_WRONG_LENGTH;
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
kb_len = 0;
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2;
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.A), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&ecdsa->grp.A, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.A)); kb_len += mbedtls_mpi_size(&ecdsa->grp.A);
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.B), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&ecdsa->grp.B, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.B)); kb_len += mbedtls_mpi_size(&ecdsa->grp.B);
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&ecdsa->grp.P, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.P)); kb_len += mbedtls_mpi_size(&ecdsa->grp.P);
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.N), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&ecdsa->grp.N, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.N)); kb_len += mbedtls_mpi_size(&ecdsa->grp.N);
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.Y), kb+8+kb_len); kb_len += 2;
kb[8+kb_len++] = 0x4;
mbedtls_mpi_write_binary(&ecdsa->grp.G.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.X)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.X);
mbedtls_mpi_write_binary(&ecdsa->grp.G.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.Y)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.Y);
put_uint16_t(mbedtls_mpi_size(&ecdsa->d), kb+8+kb_len); kb_len += 2;
mbedtls_mpi_write_binary(&ecdsa->d, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->d)); kb_len += mbedtls_mpi_size(&ecdsa->d);
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.Y), kb+8+kb_len); kb_len += 2;
kb[8+kb_len++] = 0x4;
mbedtls_mpi_write_binary(&ecdsa->Q.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.X)); kb_len += mbedtls_mpi_size(&ecdsa->Q.X);
mbedtls_mpi_write_binary(&ecdsa->Q.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.Y)); kb_len += mbedtls_mpi_size(&ecdsa->Q.Y);
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03";
algo_len = 12;
}
memset(out, 0, *out_len);
*out_len = 0;
memcpy(out+*out_len, kcv, 8);
*out_len += 8;
if (key_type & HSM_KEY_AES)
out[*out_len] = 15;
else if (key_type & HSM_KEY_RSA)
out[*out_len] = 5;
else if (key_type & HSM_KEY_EC)
out[*out_len] = 12;
*out_len += 1;
if (algo) {
memcpy(out+*out_len, algo, algo_len);
*out_len += algo_len;
}
else
*out_len += 2;
if (allowed) {
memcpy(out+*out_len, allowed, allowed_len);
*out_len += allowed_len;
}
else
*out_len += 2;
//add 4 zeros
*out_len += 4;
memcpy(kb, random_bytes_get(8), 8);
kb_len += 8; //8 random bytes
int kb_len_pad = ((int)(kb_len/16))*16;
if (kb_len % 16 > 0)
kb_len_pad = ((int)(kb_len/16)+1)*16;
//key already copied at kb+10
if (kb_len < kb_len_pad) {
kb[kb_len] = 0x80;
}
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
if (r != HSM_OK)
return r;
memcpy(out+*out_len, kb, kb_len_pad);
*out_len += kb_len_pad;
r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, out, *out_len, out+*out_len);
*out_len += 16;
if (r != 0)
return r;
return HSM_OK;
}
int dkek_type_key(const uint8_t *in) {
if (in[8] == 5 || in[8] == 6)
return HSM_KEY_RSA;
else if (in[8] == 12)
return HSM_KEY_EC;
else if (in[8] == 15)
return HSM_KEY_AES;
return 0x0;
}
int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out) {
uint8_t kcv[8];
memset(kcv, 0, sizeof(kcv));
dkek_kcv(kcv);
uint8_t kmac[32];
memset(kmac, 0, sizeof(kmac));
dkek_kmac(kmac);
uint8_t kenc[32];
memset(kenc, 0, sizeof(kenc));
dkek_kenc(kenc);
if (memcmp(kcv, in, 8) != 0)
return HSM_WRONG_DKEK;
uint8_t signature[16];
int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature);
if (r != 0)
return HSM_WRONG_SIGNATURE;
if (memcmp(signature, in+in_len-16, 16) != 0)
return HSM_WRONG_SIGNATURE;
int key_type = in[8];
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
return HSM_WRONG_DATA;
if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0)
return HSM_WRONG_DATA;
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0)
return HSM_WRONG_DATA;
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
return HSM_WRONG_DATA;
size_t ofs = 9;
//OID
size_t len = get_uint16_t(in, ofs);
ofs += len+2;
//Allowed algorithms
len = get_uint16_t(in, ofs);
ofs += len+2;
//Access conditions
len = get_uint16_t(in, ofs);
ofs += len+2;
//Key OID
len = get_uint16_t(in, ofs);
ofs += len+2;
if ((in_len-16-ofs) % 16 != 0)
return HSM_WRONG_PADDING;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
memset(kb, 0, sizeof(kb));
memcpy(kb, in+ofs, in_len-16-ofs);
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
if (r != HSM_OK)
return r;
int key_size = get_uint16_t(kb, 8);
if (key_size_out)
*key_size_out = key_size;
ofs = 10;
if (key_type == 5 || key_type == 6) {
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
mbedtls_rsa_init(rsa);
if (key_type == 5) {
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
}
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
}
}
else if (key_type == 6) {
//DP-1
len = get_uint16_t(kb, ofs); ofs += len+2;
//DQ-1
len = get_uint16_t(kb, ofs); ofs += len+2;
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
}
//PQ
len = get_uint16_t(kb, ofs); ofs += len+2;
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
}
//N
len = get_uint16_t(kb, ofs); ofs += len+2;
}
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
}
if (key_type == 5) {
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
}
}
else if (key_type == 6) {
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
}
}
r = mbedtls_rsa_complete(rsa);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
}
r = mbedtls_rsa_check_privkey(rsa);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
}
}
else if (key_type == 12) {
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
mbedtls_ecdsa_init(ecdsa);
//A
len = get_uint16_t(kb, ofs); ofs += len+2;
//B
len = get_uint16_t(kb, ofs); ofs += len+2;
//P
len = get_uint16_t(kb, ofs); ofs += 2;
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
if (ec_id == MBEDTLS_ECP_DP_NONE) {
mbedtls_ecdsa_free(ecdsa);
return HSM_WRONG_DATA;
}
ofs += len;
//N
len = get_uint16_t(kb, ofs); ofs += len+2;
//G
len = get_uint16_t(kb, ofs); ofs += len+2;
//d
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
if (r != 0) {
mbedtls_ecdsa_free(ecdsa);
return HSM_EXEC_ERROR;
}
}
else if (key_type == 15) {
memcpy(key_ctx, kb+ofs, key_size);
}
return HSM_OK;
}

36
src/hsm/dkek.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DKEK_H_
#define _DKEK_H_
extern int load_dkek();
extern int save_dkek_key(const uint8_t *key);
extern int store_dkek_key();
extern void init_dkek();
extern void release_dkek();
extern void import_dkek_share(const uint8_t *share);
extern int dkek_kcv(uint8_t *kcv);
extern int dkek_encrypt(uint8_t *data, size_t len);
extern int dkek_decrypt(uint8_t *data, size_t len);
extern int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len);
extern int dkek_type_key(const uint8_t *in);
extern int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out);
#define MAX_DKEK_ENCODE_KEY_BUFFER (8+1+12+6+(8+2*4+2*4096/8+3+13)+16)
#endif

View File

@@ -29,10 +29,10 @@
#include "tusb.h"
#include "usb_descriptors.h"
#include "device/usbd_pvt.h"
#include "pico/util/queue.h"
#include "pico/multicore.h"
#include "random.h"
#include "hsm2040.h"
#include "hardware/rtc.h"
extern void do_flash();
extern void low_flash_init();
@@ -93,7 +93,8 @@ app_t *current_app = NULL;
extern void card_thread();
static queue_t *card_comm;
queue_t *card_comm = NULL;
queue_t *ccid_comm = NULL;
extern void low_flash_init_core1();
int register_app(app_t * (*select_aid)()) {
@@ -373,18 +374,28 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
return &ccid_driver;
}
enum {
BLINK_NOT_MOUNTED = (250 << 16) | 250,
BLINK_MOUNTED = (250 << 16) | 250,
BLINK_SUSPENDED = (500 << 16) | 1000,
BLINK_PROCESSING = (50 << 16) | 50,
BLINK_ALWAYS_ON = UINT32_MAX,
BLINK_ALWAYS_OFF = 0
};
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
void led_set_blink(uint32_t mode) {
blink_interval_ms = mode;
}
void execute_tasks();
static void wait_button() {
led_set_blink((1000 << 16) | 100);
while (board_button_read() == false) {
execute_tasks();
//sleep_ms(10);
}
while (board_button_read() == true) {
execute_tasks();
//sleep_ms(10);
}
led_set_blink(BLINK_PROCESSING);
}
void usb_tx_enable(const uint8_t *buf, uint32_t len)
{
if (len > 0) {
@@ -484,7 +495,7 @@ static enum ccid_state ccid_power_on(struct ccid *c)
DEBUG_INFO("ON\r\n");
c->tx_busy = 1;
blink_interval_ms = BLINK_MOUNTED;
led_set_blink(BLINK_MOUNTED);
return CCID_STATE_WAIT;
}
@@ -531,7 +542,7 @@ static enum ccid_state ccid_power_off(struct ccid *c)
ccid_send_status (c);
DEBUG_INFO ("OFF\r\n");
c->tx_busy = 1;
blink_interval_ms = BLINK_SUSPENDED;
led_set_blink(BLINK_SUSPENDED);
return CCID_STATE_START;
}
@@ -1375,7 +1386,7 @@ void prepare_ccid()
}
int process_apdu() {
blink_interval_ms = BLINK_PROCESSING;
led_set_blink(BLINK_PROCESSING);
if (!current_app) {
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
for (int a = 0; a < num_apps; a++) {
@@ -1405,7 +1416,7 @@ static void card_init (void)
void card_thread()
{
queue_t *ccid_comm = (queue_t *)multicore_fifo_pop_blocking();
ccid_comm = (queue_t *)multicore_fifo_pop_blocking();
card_comm = (queue_t *)multicore_fifo_pop_blocking();
card_init ();
@@ -1530,7 +1541,7 @@ void ccid_task(void)
{
DEBUG_INFO ("ERR05\r\n");
}
blink_interval_ms = BLINK_MOUNTED;
led_set_blink(BLINK_MOUNTED);
}
else if (m == EV_TX_FINISHED)
{
@@ -1541,6 +1552,11 @@ void ccid_task(void)
if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE)
ccid_prepare_receive(c);
}
else if (m == EV_PRESS_BUTTON) {
wait_button();
uint32_t flag = EV_BUTTON_PRESSED;
queue_try_add(&c->card_comm, &flag);
}
}
else /* Timeout */
{
@@ -1570,6 +1586,7 @@ void tud_mount_cb()
void led_blinking_task()
{
#ifdef PICO_DEFAULT_LED_PIN
static uint32_t start_ms = 0;
static uint8_t led_state = false;
static uint8_t led_color = PICO_DEFAULT_LED_PIN;
@@ -1587,6 +1604,7 @@ void led_blinking_task()
gpio_put(led_color, led_state);
led_state ^= 1; // toggle
#endif
}
void led_off_all()
@@ -1596,14 +1614,38 @@ void led_off_all()
gpio_put(TINY2040_LED_G_PIN, 1);
gpio_put(TINY2040_LED_B_PIN, 1);
#else
#ifdef PICO_DEFAULT_LED_PIN
gpio_put(PICO_DEFAULT_LED_PIN, 0);
#endif
#endif
}
void init_rtc() {
rtc_init();
datetime_t dt = {
.year = 2020,
.month = 1,
.day = 1,
.dotw = 3, // 0 is Sunday, so 5 is Friday
.hour = 00,
.min = 00,
.sec = 00
};
rtc_set_datetime(&dt);
}
extern void neug_task();
pico_unique_board_id_t unique_id;
void execute_tasks() {
prev_millis = board_millis();
ccid_task();
tud_task(); // tinyusb device task
led_blinking_task();
}
int main(void)
{
struct apdu *a = &apdu;
@@ -1619,9 +1661,12 @@ int main(void)
gpio_init(TINY2040_LED_B_PIN);
gpio_set_dir(TINY2040_LED_B_PIN, GPIO_OUT);
#else
#ifdef PICO_DEFAULT_LED_PIN
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
#endif
#endif
led_off_all();
@@ -1632,13 +1677,12 @@ int main(void)
random_init();
low_flash_init();
init_rtc();
while (1)
{
prev_millis = board_millis();
ccid_task();
tud_task(); // tinyusb device task
led_blinking_task();
execute_tasks();
neug_task();
do_flash();
}

View File

@@ -22,6 +22,7 @@
#include "tusb.h"
#include "file.h"
#include "pico/unique_id.h"
#include "pico/util/queue.h"
#define USB_REQ_CCID 0xA1
@@ -79,13 +80,18 @@ struct apdu {
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
#define EV_PRESS_BUTTON 32
/* OpenPGPcard thread */
/* SC HSM thread */
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_EXIT 8
#define EV_PINPAD_INPUT_DONE 16
#define EV_BUTTON_PRESSED 16
//Variables set by core1
extern queue_t *ccid_comm;
extern queue_t *card_comm;
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
@@ -157,4 +163,16 @@ extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern pico_unique_board_id_t unique_id;
enum {
BLINK_NOT_MOUNTED = (250 << 16) | 250,
BLINK_MOUNTED = (250 << 16) | 250,
BLINK_SUSPENDED = (500 << 16) | 1000,
BLINK_PROCESSING = (50 << 16) | 50,
BLINK_ALWAYS_ON = UINT32_MAX,
BLINK_ALWAYS_OFF = 0
};
extern void led_set_blink(uint32_t mode);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,6 @@ extern const uint8_t sc_hsm_aid[];
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
#define SW_PIN_BLOCKED() set_res_sw (0x63, 0x00)
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
@@ -34,7 +33,7 @@ extern const uint8_t sc_hsm_aid[];
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
#define SW_FILE_INVALID() set_res_sw (0x69, 0x83)
#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)
@@ -60,6 +59,11 @@ extern const uint8_t sc_hsm_aid[];
#define HSM_ERR_BLOCKED -1004
#define HSM_NO_LOGIN -1005
#define HSM_EXEC_ERROR -1006
#define HSM_WRONG_LENGTH -1007
#define HSM_WRONG_DATA -1008
#define HSM_WRONG_DKEK -1009
#define HSM_WRONG_SIGNATURE -1010
#define HSM_WRONG_PADDING -1011
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
@@ -84,6 +88,19 @@ extern const uint8_t sc_hsm_aid[];
#define ALGO_AES_CMAC 0x18
#define ALGO_AES_DERIVE 0x99
#define HSM_OPT_RRC 0x0001
#define HSM_OPT_TRANSPORT_PIN 0x0002
#define HSM_OPT_SESSION_PIN 0x0004
#define HSM_OPT_SESSION_PIN_EXPL 0x000C
#define HSM_OPT_REPLACE_PKA 0x0008
#define HSM_OPT_COMBINED_AUTH 0x0010
#define HSM_OPT_RRC_RESET_ONLY 0x0020
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
#define P15_KEYTYPE_RSA 0x30
#define P15_KEYTYPE_ECC 0xA0
#define P15_KEYTYPE_AES 0xA8
extern int pin_reset_retries(const file_t *pin, bool);
extern int pin_wrong_retry(const file_t *pin);

View File

@@ -18,7 +18,7 @@
#ifndef __VERSION_H_
#define __VERSION_H_
#define HSM_VERSION 0x0104
#define HSM_VERSION 0x010C
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)

View File

@@ -19,6 +19,9 @@
#ifndef _RANDOM_H_
#define _RANDOM_H_
#include "stdlib.h"
#include "pico/stdlib.h"
void random_init (void);
void random_fini (void);

View File

@@ -1,273 +0,0 @@
/*
* Copyright (C) 2009-2015 Frank Morgner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* @file
*/
#ifndef _CCID_TYPES_H
#define _CCID_TYPES_H
#include "pico/types.h"
#include "hardware/structs/usb.h"
#define USB_REQ_CCID 0xA1
#define CCID_CONTROL_ABORT 0x01
#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02
#define CCID_CONTROL_GET_DATA_RATES 0x03
#define CCID_OPERATION_VERIFY 0x00;
#define CCID_OPERATION_MODIFY 0x01;
#define CCID_ENTRY_VALIDATE 0x02
#define CCID_BERROR_CMD_ABORTED 0xff /** Host aborted the current activity */
#define CCID_BERROR_ICC_MUTE 0xfe /** CCID timed out while talking to the ICC */
#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /** Parity error while talking to the ICC */
#define CCID_BERROR_XFR_OVERRUN 0xfc /** Overrun error while talking to the ICC */
#define CCID_BERROR_HW_ERROR 0xfb /** An all inclusive hardware error occurred */
#define CCID_BERROR_BAD_ATR_TS 0xf
#define CCID_BERROR_BAD_ATR_TCK 0xf
#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6
#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5
#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4
#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3
#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /** Automatic Sequence Ongoing */
#define CCID_BERROR_PIN_TIMEOUT 0xf0
#define CCID_BERROR_PIN_CANCELLED 0xef
#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /** A second command was sent to a slot which was already processing a command. */
#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00
#define CCID_BERROR_OK 0x00
#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */
#define CCID_BSTATUS_OK_INACTIVE 0x01 /** No error. ICC is present and inactive */
#define CCID_BSTATUS_OK_NOICC 0x02 /** No error. No ICC is present */
#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /** Failed. An ICC is present and active */
#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /** Failed. ICC is present and inactive */
#define CCID_BSTATUS_ERROR_NOICC 0x42 /** Failed. No ICC is present */
#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /** APDU begins and ends with this command */
#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /** APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */
#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /** abData field continues a command APDU and ends the APDU command */
#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /** abData field continues a command APDU and another block is to follow */
#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /** empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */
#define CCID_PIN_ENCODING_BIN 0x00
#define CCID_PIN_ENCODING_BCD 0x01
#define CCID_PIN_ENCODING_ASCII 0x02
#define CCID_PIN_UNITS_BYTES 0x80
#define CCID_PIN_JUSTIFY_RIGHT 0x04
#define CCID_PIN_CONFIRM_NEW 0x01
#define CCID_PIN_INSERT_OLD 0x02
#define CCID_PIN_NO_MSG 0x00
#define CCID_PIN_MSG1 0x01
#define CCID_PIN_MSG2 0x02
#define CCID_PIN_MSG_REF 0x03
#define CCID_PIN_MSG_DEFAULT 0xff
#define CCID_SLOTS_UNCHANGED 0x00
#define CCID_SLOT1_CARD_PRESENT 0x01
#define CCID_SLOT1_CHANGED 0x02
#define CCID_SLOT2_CARD_PRESENT 0x04
#define CCID_SLOT2_CHANGED 0x08
#define CCID_SLOT3_CARD_PRESENT 0x10
#define CCID_SLOT3_CHANGED 0x20
#define CCID_SLOT4_CARD_PRESENT 0x40
#define CCID_SLOT4_CHANGED 0x80
#define CCID_EXT_APDU_MAX (4 + 3 + 0xffff + 3)
#define CCID_SHORT_APDU_MAX (4 + 1 + 0xff + 1)
typedef struct TU_ATTR_PACKED {
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;
} class_desc_ccid_t;
struct abProtocolDataStructure_T0 {
uint8_t bmFindexDindex;
uint8_t bmTCCKST0;
uint8_t bGuardTimeT0;
uint8_t bWaitingIntegerT0;
uint8_t bClockStop;
} __packed;
struct abProtocolDataStructure_T1 {
uint8_t bmFindexDindex;
uint8_t bmTCCKST1;
uint8_t bGuardTimeT1;
uint8_t bWaitingIntegersT1;
uint8_t bClockStop;
uint8_t bIFSC;
uint8_t bNadValue;
} __packed;
struct abPINDataStucture_Verification {
uint8_t bTimeOut;
uint8_t bmFormatString;
uint8_t bmPINBlockString;
uint8_t bmPINLengthFormat;
uint16_t wPINMaxExtraDigit;
uint8_t bEntryValidationCondition;
uint8_t bNumberMessage;
uint16_t wLangId;
uint8_t bMsgIndex;
uint8_t bTeoPrologue1;
uint16_t bTeoPrologue2;
} __packed;
struct abPINDataStucture_Modification {
uint8_t bTimeOut;
uint8_t bmFormatString;
uint8_t bmPINBlockString;
uint8_t bmPINLengthFormat;
uint8_t bInsertionOffsetOld;
uint8_t bInsertionOffsetNew;
uint16_t wPINMaxExtraDigit;
uint8_t bConfirmPIN;
uint8_t bEntryValidationCondition;
uint8_t bNumberMessage;
uint16_t wLangId;
uint8_t bMsgIndex1;
} __packed;
struct PC_to_RDR_XfrBlock {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bBWI;
uint16_t wLevelParameter;
} __packed;
struct PC_to_RDR_IccPowerOff {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t abRFU1;
uint16_t abRFU2;
} __packed;
struct PC_to_RDR_GetSlotStatus {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t abRFU1;
uint16_t abRFU2;
} __packed;
struct PC_to_RDR_GetParameters {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t abRFU1;
uint16_t abRFU2;
} __packed;
struct PC_to_RDR_ResetParameters {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t abRFU1;
uint16_t abRFU2;
} __packed;
struct PC_to_RDR_SetParameters {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bProtocolNum;
uint16_t abRFU;
} __packed;
struct PC_to_RDR_Secure {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bBWI;
uint16_t wLevelParameter;
} __packed;
struct PC_to_RDR_IccPowerOn {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bPowerSelect;
uint16_t abRFU;
} __packed;
struct RDR_to_PC_SlotStatus {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bStatus;
uint8_t bError;
uint8_t bClockStatus;
} __packed;
struct RDR_to_PC_DataBlock {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bStatus;
uint8_t bError;
uint8_t bChainParameter;
} __packed;
struct RDR_to_PC_Parameters {
uint8_t bMessageType;
uint32_t dwLength;
uint8_t bSlot;
uint8_t bSeq;
uint8_t bStatus;
uint8_t bError;
uint8_t bProtocolNum;
} __packed;
struct RDR_to_PC_NotifySlotChange {
uint8_t bMessageType;
uint8_t bmSlotICCState; /* we support 1 slots, so we need 2*1 bits = 1 byte */
} __packed;
#endif

View File

@@ -31,40 +31,19 @@ static const struct ccid_class_descriptor desc_ccid = {
0x02), // T=1
.dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC),
.bNumClockSupport = 1,
.bNumClockSupport = 0,
.dwDataRate = (0x2580),
.dwMaxDataRate = (0x2580),
.bNumDataRatesSupported = 1,
.dwMaxIFSD = (0xFF), // IFSD is handled by the real reader driver
.bNumDataRatesSupported = 0,
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
.dwSynchProtocols = (0),
.dwMechanical = (0),
.dwFeatures = (
0x00000002| // Automatic parameter configuration based on ATR data
0x00000004| // Automatic activation of ICC on inserting
0x00000008| // Automatic ICC voltage selection
0x00000010| // Automatic ICC clock frequency change
0x00000020| // Automatic baud rate change
0x00000040| // Automatic parameters negotiation
0x00000080| // Automatic PPS
0x00000400| // Automatic IFSD exchange as first exchange
0x00040000| // Short and Extended APDU level exchange with CCID
0x00100000), // USB Wake up signaling supported
.dwMaxCCIDMessageLength = (CCID_EXT_APDU_MAX),
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
.dwMaxCCIDMessageLength = 65544+10,
.bClassGetResponse = 0xFF,
.bclassEnvelope = 0xFF,
.wLcdLayout = 0x0,
/*
(
0xFF00| // Number of lines for the LCD display
0x00FF), // Number of characters per line
*/
.bPINSupport = 0x0,
/*
0x1| // PIN Verification supported
0x2| // PIN Modification supported
0x10| // PIN PACE Capabilities supported
0x20, // PIN PACE Verification supported
*/
.bMaxCCIDBusySlots = 0x01,
};