65 Commits
v1.10 ... v2.0

Author SHA1 Message Date
Pol Henarejos
86298f3421 Upgrading to version 2.0. 2022-04-19 19:24:10 +02:00
Pol Henarejos
77971ac7e6 Using MBEDTLS from pico ccid.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-19 19:19:16 +02:00
Pol Henarejos
302f287967 Moving EAC and crypto to core.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-19 19:16:29 +02:00
Pol Henarejos
b9c08d72c4 Update .gitmodules
Updating module for pico-ccid
2022-04-19 18:42:48 +02:00
Pol Henarejos
522860f736 Splitting the core onto another repo, which can be reused by other smart applications.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-19 18:39:52 +02:00
Pol Henarejos
b09fc75913 CVCert is burn only if it does not exist. This check is only executed for first configuration.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-14 18:31:39 +02:00
Pol Henarejos
1b010c8a68 Specifying POST method
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-14 17:11:51 +02:00
Pol Henarejos
e2f424d4ab No more in the repo
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-14 01:06:50 +02:00
Pol Henarejos
b9fb224d62 Adding a tool to burn device CVC. It generates a new keypair and sends the public key to Pico HSM CA, which signs the request. The certificate, CA and private key are burned onto the firmware.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-14 01:03:03 +02:00
Pol Henarejos
69e869852e Rewritten keypair_gen response (more friendly).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 19:03:33 +02:00
Pol Henarejos
618966b742 Sanity check for keypair gen.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 18:49:13 +02:00
Pol Henarejos
b68920ff45 Added walker function for TLV parsing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 16:55:34 +02:00
Pol Henarejos
9dfe0ee7b3 Clear session pin on unload and new session.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 14:25:44 +02:00
Pol Henarejos
da6c578973 Fix tag_len computation for all TLV.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 14:14:06 +02:00
Pol Henarejos
49d9ec7cf9 Session pin is randomized.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-13 14:12:14 +02:00
Pol Henarejos
af07f1d549 Added INS for session pin generation (needs randomization).
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 19:47:43 +02:00
Pol Henarejos
db5f5fd435 When working with SM, wrap() manipulates res_APDU. Thus, we cannot change the pointer of res_APDU anymore. Everything must be memcpy-ed.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 15:11:42 +02:00
Pol Henarejos
7232625bab Merge branch 'master' into eac 2022-04-11 15:09:33 +02:00
Pol Henarejos
1557a4a039 Fix when generating keypair, which could produce wrong flash save in particular cases of concurrency.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 15:09:20 +02:00
Pol Henarejos
b61575bbc3 Adding some mutex to improve concurrency.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 15:08:10 +02:00
Pol Henarejos
3781777138 Adding some kind of permanent flash memory that does not wipe out when initializing.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 11:37:41 +02:00
Pol Henarejos
2f1f8e0c90 Fix parsing TLV in signatures.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 01:44:18 +02:00
Pol Henarejos
c4c2bf86ba Fix response APDU in secure channel.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 01:38:15 +02:00
Pol Henarejos
f26668b81d Fixed IV computation. IV is computed encrypting macCounter with a initial IV=0x0000.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-11 01:16:20 +02:00
Pol Henarejos
964af6a064 Adding wrap() to encrypt and sign response APDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-10 20:58:54 +02:00
Pol Henarejos
c3a93a46ba Adding unwrap(), to decrypt and verify secure APDU.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-10 20:23:36 +02:00
Pol Henarejos
57d593561a Moving all SM stuff to EAC.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-10 19:00:52 +02:00
Pol Henarejos
c098d80524 Adding private key of termca. It is the worst thing I can do, but first I need to develop the secure channel, which uses the private key of device. Later, I will figure out how to generate the private key and certificate during initialization, but it will be difficult, as it needs to be signed by the CA.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-10 01:55:57 +02:00
Pol Henarejos
6c892af9f1 Adding authentication command. Not finished. Needs lot of work.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-09 23:44:45 +02:00
Pol Henarejos
b545a1618b Added Manage Security Environment command.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-09 20:50:00 +02:00
Pol Henarejos
dec3d54ddd Adding more SW codes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-09 20:29:13 +02:00
Pol Henarejos
ce4d0bf102 INS 54h is also occupied too... let's try with 64h.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-08 00:38:03 +02:00
Pol Henarejos
4e6bada892 Fix first AID load.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-08 00:29:15 +02:00
Pol Henarejos
98ad2e3d55 Fix returning card data when selected AID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-07 23:32:56 +02:00
Pol Henarejos
e686b42934 Merge branch 'master' into eac 2022-04-07 18:34:40 +02:00
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
0d839c3136 Merge branch 'master' into eac 2022-04-07 18:32:49 +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
cc3bfad00a Merge branch 'master' into eac 2022-04-07 18:18:50 +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
1e6556ebdd Upgrading to version 1.12.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-06 19:16:28 +02:00
Pol Henarejos
cfd86df45e Update README.md
Added led blink meaning.
2022-04-06 17:25:07 +02:00
Pol Henarejos
c16a7a3c5c Added dynamic option to enable/disable press to confirm.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-06 15:14:23 +02:00
Pol Henarejos
7060d2d2ca 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-06 14:41:09 +02:00
Pol Henarejos
532d79bcc5 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-06 14:38:22 +02:00
Pol Henarejos
770097d6ab Added support for reading binary data.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-05 18:07:20 +02:00
Pol Henarejos
ce2a1c21de Added support to write arbitrary data EF.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-05 17:28:22 +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
6e1c47ddf4 Fix with ASN1 encapsulation for keypair generation. It only affects RSA 4096 bits.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-04 22:00:29 +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
d49e7be972 Added a new custom APDU (88h) for setting and retrieving datetime.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-04 15:48:04 +02:00
Pol Henarejos
13d17fc4f7 Fixed class with USB-ICC specs, for legacy reasons.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-04-04 15:46:53 +02:00
31 changed files with 940 additions and 4037 deletions

6
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "OpenSC"] [submodule "OpenSC"]
path = OpenSC path = OpenSC
url = https://github.com/polhenarejos/OpenSC url = https://github.com/polhenarejos/OpenSC
[submodule "mbedtls"] [submodule "pico-ccid"]
path = mbedtls path = pico-ccid
url = https://github.com/ARMmbed/mbedtls url = https://github.com/polhenarejos/pico-ccid

View File

@@ -42,50 +42,60 @@ set_source_files_properties(
PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\"" PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\""
) )
target_sources(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c find_package( PythonInterp 3.7 REQUIRED )
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/hsm/cvcerts.h)
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/burn-cvcerts.py ${CMAKE_CURRENT_LIST_DIR})
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c message("Burning CVCert")
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c endif()
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c target_sources(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hmac_drbg.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/files.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/camellia.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aria.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/nist_kw.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hmac_drbg.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chachapoly.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/camellia.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chacha20.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aria.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/poly1305.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/gcm.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ccm.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/des.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/nist_kw.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c
@@ -106,13 +116,14 @@ target_sources(pico_hsm PUBLIC
) )
target_include_directories(pico_hsm PUBLIC target_include_directories(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/fs ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/hsm ${CMAKE_CURRENT_LIST_DIR}/src/hsm
${CMAKE_CURRENT_LIST_DIR}/src/rng ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid
${CMAKE_CURRENT_LIST_DIR}/src/usb ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb
${CMAKE_CURRENT_LIST_DIR}/opensc/src ${CMAKE_CURRENT_LIST_DIR}/opensc/src
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library
) )
pico_add_extra_outputs(pico_hsm) pico_add_extra_outputs(pico_hsm)

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. - RSA key generation from 1024 to 4096 bits.
- ECDSA key generation from 192 to 521 bits. - ECDSA key generation from 192 to 521 bits.
- ECC curves secp192r1, secp256r1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, secp192k1 (insecure), secp256k1. - 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. - RSA-PSS, RSA-PKCS and raw RSA signature.
- ECDSA raw and hash signature. - ECDSA raw and hash signature.
- ECDH key derivation. - ECDH key derivation.
@@ -25,6 +25,9 @@ This is a project to create a Hardware Security Module (HSM) with a Raspberry Pi
- Extended APDU support. - Extended APDU support.
- Private keys and certificates import from WKY or PKCS#12 files.[^2][^3] - 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] - 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`). [^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. [^2]: Available via SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
@@ -86,15 +89,57 @@ For AES key generation, encryption and decryption, check [doc/aes.md](/doc/aes.m
For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096.md). For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096.md).
## Key generation time For storing and retrieving arbitrary data, check [doc/store_data.md](/doc/store_data.md).
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `2048` and `4096` bits.
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) | | RSA key length (bits) | Average time (seconds) |
| :---: | :---: | | :---: | :---: |
| 1024 | 16 | | 1024 | 16 |
| 2048 | 124 | | 2048 | 124 |
| 3072 | N/A | | 3072 | 600 |
| 4096 | N/A | | 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 ## Driver

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="1" VERSION_MAJOR="2"
VERSION_MINOR="10" VERSION_MINOR="0"
rm -rf release/* rm -rf release/*
cd build_release cd build_release

78
burn-cvcerts.py Normal file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 13 20:15:01 2022
@author: Pol Henarejos
"""
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
import base64
import urllib.request
import json
import sys
def print_var(v, name):
s = '\n'
s += "static const unsigned char "+name+"[] = {\n"
s += "\t0x{:02x},0x{:02x},\n".format((len(v) & 0xff),((len(v)>> 8) & 0xff))
for i in range(len(v)):
if (i%16 == 0):
s += '\t'
s += "0x{:02x}".format((v[i]))
if (i < len(v)-1):
s += ','
if (i%16 == 15):
s += '\n'
s += '\n'
s += '};\n'
return s
def main():
args = sys.argv[1:]
private_key = ec.generate_private_key(ec.SECP192R1(), default_backend())
public_key = private_key.public_key()
pub_num = public_key.public_numbers()
pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to_bytes(24,'big'))
user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
data = urllib.parse.urlencode({'pubkey':pbk}).encode()
req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", method='POST', data=data, headers={'User-Agent':user_agent,} ) #The assembled request
response = urllib.request.urlopen(req)
resp = response.read().decode('utf-8')
j = json.loads(resp)
cvcert = base64.b64decode(j['cvcert'])
dica = [
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
]
s = '#ifndef _CVCERTS_H_\n#define _CVCERTS_H_\n'
s += print_var(dica,'dica')
s += print_var(cvcert,'termca')
pvk = private_key.private_numbers().private_value.to_bytes(24,'big')
s += print_var(pvk,'termca_pk')
s += '\n#endif\n'
f = open(args[0] + '/src/hsm/cvcerts.h','w')
f.write(s)
f.close()
if __name__ == '__main__':
main()

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:
```
8064XX00YYZZZZRR
```
It composed by the following fields:
- `80` to indicate that it is a custom vendor type command.
- `64` 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 80640A0008
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 64 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 80640A000807E6040603132917
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 64 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 806406000101
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 64 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 806406000100
Using reader with a card: Free Software Initiative of Japan Gnuk
Sending: 80 64 06 00 01 00
Received (SW1=0x90, SW2=0x00)
```

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

@@ -17,8 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
VERSION_MAJOR="1" VERSION_MAJOR="2"
VERSION_MINOR="0A" VERSION_MINOR="0"
echo "----------------------------" echo "----------------------------"
echo "VID/PID patcher for Pico HSM" echo "VID/PID patcher for Pico HSM"

1
pico-ccid Submodule

Submodule pico-ccid added at 5e51c9a072

View File

@@ -1,427 +0,0 @@
/*
* 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 "file.h"
#include "tusb.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include "libopensc/card-sc-hsm.h"
#include <string.h>
extern const uintptr_t end_data_pool;
extern const uintptr_t start_data_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_word (uintptr_t addr, uint32_t data);
extern int flash_program_uintptr (uintptr_t addr, uintptr_t data);
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t flash_read_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern void low_flash_available();
//puts FCI in the RAPDU
void process_fci(const file_t *pe) {
uint8_t *p = res_APDU;
uint8_t buf[64];
res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0x6f;
res_APDU[res_APDU_size++] = 0x00; //computed later
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 2;
if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
res_APDU[res_APDU_size++] = len & 0xff;
}
else {
res_APDU[res_APDU_size++] = pe->data[1];
res_APDU[res_APDU_size++] = pe->data[0];
}
}
else {
memset(res_APDU+res_APDU_size, 0, 2);
res_APDU_size += 2;
}
res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size] = 0;
if (pe->type == FILE_TYPE_INTERNAL_EF)
res_APDU[res_APDU_size++] |= 0x08;
else if (pe->type == FILE_TYPE_WORKING_EF)
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
else if (pe->type == FILE_TYPE_DF)
res_APDU[res_APDU_size++] |= 0x38;
res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2;
put_uint16_t(pe->fid, res_APDU+res_APDU_size);
res_APDU_size += 2;
res_APDU[1] = res_APDU_size-2;
}
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 | 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
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
/* 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_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];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
file_t *file_pin1 = NULL;
file_t *file_retries_pin1 = NULL;
file_t *file_sopin = NULL;
file_t *file_retries_sopin = NULL;
#define MAX_DYNAMIC_FILES 64
uint16_t dynamic_files = 0;
file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent)
return true;
if (child == MF)
return false;
return is_parent(&file_entries[child->parent], parent);
}
file_t *get_parent(file_t *f) {
return &file_entries[f->parent];
}
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
return p;
}
}
return NULL;
}
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->fid != 0x0000 && p->fid == fid) {
if (!parent || (parent && is_parent(p, parent))) {
if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
return p;
}
}
}
return NULL;
}
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(pe->fid, buf);
return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
}
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH*2], *p = path;
put_uint16_t(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2;
for (int d = depth-2; d >= 0; d -= 2) {
memcpy(p, buf+d, 2);
p += 2;
}
return depth;
}
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
uint8_t path[MAX_DEPTH*2];
if (pathlen > sizeof(path)) {
return NULL;
}
for (file_t *p = file_entries; p != file_last; p++) {
uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
return p;
}
return NULL;
}
file_t *currentEF = NULL;
file_t *currentDF = NULL;
const file_t *selected_applet = NULL;
bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op];
if (acl == 0x0)
return true;
else if (acl == 0xff)
return false;
else if (acl == 0x90 || acl & 0x9F == 0x10) {
// PIN required.
if(isUserAuthenticated) {
return true;
}
else {
return false;
}
}
return false;
}
#include "libopensc/pkcs15.h"
void initialize_chain(file_chain_t **chain) {
file_chain_t *next;
for (file_chain_t *f = *chain; f; f = next) {
next = f->next;
free(f);
}
*chain = NULL;
}
void initialize_flash(bool hard) {
if (hard) {
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
low_flash_available();
}
for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
f->data = NULL;
}
dynamic_files = 0;
}
void scan_flash() {
initialize_flash(false); //soft initialization
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
{
printf("First initialization (or corrupted!)\r\n");
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
}
printf("SCAN\r\n");
uintptr_t base = flash_read_uintptr(end_data_pool);
for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) {
if (base == 0x0) //all is empty
break;
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
printf("[%x] scan fid %x, len %d\r\n",base,fid,flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t)));
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) {
file = 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 {
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
continue;
}
}
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
if (flash_read_uintptr(base) == 0x0) {
break;
}
}
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
if (file_pin1) {
if (!file_pin1->data) {
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
}
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
if (file_sopin) {
if (!file_sopin->data) {
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
}
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
if (file_retries_pin1) {
if (!file_retries_pin1->data) {
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
}
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
if (file_retries_sopin) {
if (!file_retries_sopin->data) {
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
file_t *tf = NULL;
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
}
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
low_flash_available();
}
uint8_t *file_read(const uint8_t *addr) {
return flash_read((uintptr_t)addr);
}
uint16_t file_read_uint16(const uint8_t *addr) {
return flash_read_uint16((uintptr_t)addr);
}
uint8_t file_read_uint8(const uint8_t *addr) {
return flash_read_uint8((uintptr_t)addr);
}
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) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) {
for (int j = i+1; j < dynamic_files; j++)
memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
dynamic_files--;
return HSM_OK;
}
}
return HSM_ERR_FILE_NOT_FOUND;
}
file_t *file_new(uint16_t fid) {
file_t *f;
if ((f = search_dynamic_file(fid)))
return f;
if (dynamic_files == MAX_DYNAMIC_FILES)
return NULL;
f = &dynamic_file[dynamic_files];
dynamic_files++;
file_t file = {
.fid = fid,
.parent = 5,
.name = NULL,
.type = FILE_TYPE_WORKING_EF,
.ef_structure = FILE_EF_TRANSPARENT,
.data = NULL,
.acl = {0}
};
memcpy(f, &file, sizeof(file_t));
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
return f;
}
file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) {
if (search_file_chain(file->fid, *chain))
return NULL;
file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t));
fc->file = file;
fc->next = *chain;
*chain = fc;
return fc;
}
file_t *search_file_chain(uint16_t fid, file_chain_t *chain) {
for (file_chain_t *fc = chain; fc; fc = fc->next) {
if (fid == fc->file->fid) {
return fc->file;
}
}
return NULL;
}

View File

@@ -1,124 +0,0 @@
/*
* 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 _FILE_H_
#define _FILE_H_
#include <stdlib.h>
#include "pico/stdlib.h"
#define FILE_TYPE_UNKNOWN 0x00
#define FILE_TYPE_DF 0x04
#define FILE_TYPE_INTERNAL_EF 0x03
#define FILE_TYPE_WORKING_EF 0x01
#define FILE_TYPE_BSO 0x10
#define FILE_PERSISTENT 0x20
#define FILE_DATA_FLASH 0x40
#define FILE_DATA_FUNC 0x80
/* EF structures */
#define FILE_EF_UNKNOWN 0x00
#define FILE_EF_TRANSPARENT 0x01
#define FILE_EF_LINEAR_FIXED 0x02
#define FILE_EF_LINEAR_FIXED_TLV 0x03
#define FILE_EF_LINEAR_VARIABLE 0x04
#define FILE_EF_LINEAR_VARIABLE_TLV 0x05
#define FILE_EF_CYCLIC 0x06
#define FILE_EF_CYCLIC_TLV 0x07
#define ACL_OP_DELETE_SELF 0x00
#define ACL_OP_CREATE_DF 0x01
#define ACL_OP_CREATE_EF 0x02
#define ACL_OP_DELETE_CHILD 0x03
#define ACL_OP_WRITE 0x04
#define ACL_OP_UPDATE_ERASE 0x05
#define ACL_OP_READ_SEARCH 0x06
#define SPECIFY_EF 0x1
#define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3
#define EF_DKEK 0x108F
#define EF_PRKDFS 0x6040
#define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
#define MAX_DEPTH 4
typedef struct file
{
const uint16_t fid;
const uint8_t parent; //entry number in the whole table!!
const uint8_t *name;
const uint8_t type;
const uint8_t ef_structure;
uint8_t *data; //should include 2 bytes len at begining
const uint8_t acl[7];
} __attribute__((packed)) file_t;
typedef struct file_chain
{
file_t *file;
struct file_chain *next;
} file_chain_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_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe);
extern void scan_flash();
extern void initialize_flash(bool);
extern file_t file_entries[];
extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const uint8_t *addr);
extern file_t *file_new(uint16_t);
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 file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain);
extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain);
extern bool isUserAuthenticated;
#endif

View File

@@ -1,133 +0,0 @@
/*
* 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 <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hsm2040.h"
#include "tusb.h"
#include "file.h"
#include "sc_hsm.h"
/*
* ------------------------------------------------------
* | |
* | next_addr | prev_addr | fid | data (len + payload) |
* | |
* ------------------------------------------------------
*/
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE; //This is a fixed value. DO NOT CHANGE
#define FLASH_ADDR_DATA_STORAGE_START 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 void low_flash_available();
uintptr_t allocate_free_addr(uint16_t size) {
if (size > FLASH_SECTOR_SIZE)
return 0x0; //ERROR
size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size
uintptr_t next_base = 0x0;
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
uintptr_t potential_addr = base-real_size;
next_base = flash_read_uintptr(base);
//printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
if (next_base == 0x0) { //we are at the end
//now we check if we fit in the current sector
if (addr_alg <= potential_addr) //it fits in the current sector
{
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg-real_size;
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
return 0x0;
}
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked)
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
flash_program_uintptr(potential_addr, next_base);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
}
return 0x0; //probably never reached
}
int flash_clear_file(file_t *file) {
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t));
uintptr_t next_addr = flash_read_uintptr(base_addr);
//printf("nc %x->%x %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
flash_program_uintptr(prev_addr, next_addr);
flash_program_halfword((uintptr_t)file->data, 0);
if (next_addr > 0)
flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
//printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
return HSM_OK;
}
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
if (!file)
return HSM_ERR_NULL_PARAM;
if (len > FLASH_SECTOR_SIZE)
return HSM_ERR_NO_MEMORY;
if (file->data) { //already in flash
uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data);
if (len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}
else { //we clear the old file
flash_clear_file(file);
}
}
uintptr_t new_addr = allocate_free_addr(len);
//printf("na %x\r\n",new_addr);
if (new_addr == 0x0)
return HSM_ERR_NO_MEMORY;
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}

View File

@@ -1,248 +0,0 @@
/*
* 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 <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "pico/multicore.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include <string.h>
#define TOTAL_FLASH_PAGES 4
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;
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash;
static semaphore_t sem_wait;
static uint8_t ready_pages = 0;
bool flash_available = false;
static bool locked_out = false;
//this function has to be called from the core 0
void do_flash()
{
if (mutex_try_enter(&mtx_flash, NULL) == true) {
if (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\r\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) {
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts (ints);
while (multicore_lockout_end_timeout_us(1000) == false);
//printf("WRITEN %X !\r\n",flash_pages[r].address);
flash_pages[r].ready = false;
ready_pages--;
}
else if (flash_pages[r].erase == true) {
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING\r\n");
flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
while (multicore_lockout_end_timeout_us(1000) == false);
flash_pages[r].erase = false;
ready_pages--;
}
}
flash_available = false;
if (ready_pages != 0) {
DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES");
}
}
mutex_exit(&mtx_flash);
}
sem_release(&sem_wait);
}
//this function has to be called from the core 0
void low_flash_init() {
mutex_init(&mtx_flash);
sem_init(&sem_wait, 0, 1);
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
}
void low_flash_init_core1() {
mutex_enter_blocking(&mtx_flash);
multicore_lockout_victim_init();
locked_out = true;
mutex_exit(&mtx_flash);
}
void wait_flash_finish() {
sem_acquire_blocking(&sem_wait); //blocks until released
//wake up
sem_acquire_blocking(&sem_wait); //decrease permits
}
void low_flash_available() {
mutex_enter_blocking(&mtx_flash);
flash_available = true;
mutex_exit(&mtx_flash);
}
page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
{
p = &flash_pages[r];
if (!flash_pages[r].ready && !flash_pages[r].erase)
{
memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
ready_pages++;
p->address = addr_alg;
p->ready = true;
}
return p;
}
}
return NULL;
}
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
if (!data || len == 0)
return HSM_ERR_NULL_PARAM;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr)))
{
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash);
return HSM_ERR_MEMORY_FATAL;
}
memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
//printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr);
mutex_exit(&mtx_flash);
return HSM_OK;
}
int flash_program_halfword (uintptr_t addr, uint16_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
}
int flash_program_word (uintptr_t addr, uint32_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
}
int flash_program_uintptr (uintptr_t addr, uintptr_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
}
uint8_t *flash_read(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
//mutex_enter_blocking(&mtx_flash);
if (ready_pages > 0) {
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
//mutex_exit(&mtx_flash);
return v;
}
}
}
uint8_t *v = (uint8_t *)addr;
//mutex_exit(&mtx_flash);
return v;
}
uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uintptr_t v = 0x0;
for (int i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t)p[i]<<(8*i);
}
return v;
}
uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uint16_t v = 0x0;
for (int i = 0; i < sizeof(uint16_t); i++) {
v |= p[i]<<(8*i);
}
return v;
}
uint8_t flash_read_uint8(uintptr_t addr) {
return *flash_read(addr);
}
int flash_erase_page (uintptr_t addr, size_t page_size) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr))) {
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash);
return HSM_ERR_MEMORY_FATAL;
}
p->erase = true;
p->ready = false;
p->page_size = page_size;
mutex_exit(&mtx_flash);
return HSM_OK;
}
bool flash_check_blank(const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++) {
if (*p != 0xff)
return false;
}
return true;
}

View File

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

View File

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

View File

@@ -1,41 +0,0 @@
#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

View File

@@ -27,6 +27,7 @@
#include "mbedtls/cmac.h" #include "mbedtls/cmac.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "files.h"
static uint8_t dkek[IV_SIZE+32]; static uint8_t dkek[IV_SIZE+32];
static uint8_t tmp_dkek[32]; static uint8_t tmp_dkek[32];
@@ -35,15 +36,15 @@ extern uint8_t session_pin[32];
int load_dkek() { int load_dkek() {
if (has_session_pin == false) if (has_session_pin == false)
return HSM_NO_LOGIN; return CCID_NO_LOGIN;
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf) if (!tf)
return HSM_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32); 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); int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
if (ret != 0) if (ret != 0)
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
return HSM_OK; return CCID_OK;
} }
void release_dkek() { void release_dkek() {
@@ -59,11 +60,11 @@ int store_dkek_key() {
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32); aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf) if (!tf)
return HSM_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
flash_write_data_to_file(tf, dkek, sizeof(dkek)); flash_write_data_to_file(tf, dkek, sizeof(dkek));
low_flash_available(); low_flash_available();
release_dkek(); release_dkek();
return HSM_OK; return CCID_OK;
} }
int save_dkek_key(const uint8_t *key) { int save_dkek_key(const uint8_t *key) {
@@ -83,43 +84,43 @@ void import_dkek_share(const uint8_t *share) {
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
uint8_t hsh[32]; uint8_t hsh[32];
int r = load_dkek(); int r = load_dkek();
if (r != HSM_OK) if (r != CCID_OK)
return r; return r;
hash256(dkek+IV_SIZE, 32, hsh); hash256(dkek+IV_SIZE, 32, hsh);
release_dkek(); release_dkek();
memcpy(kcv, hsh, 8); memcpy(kcv, hsh, 8);
return HSM_OK; return CCID_OK;
} }
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
uint8_t buf[32+4]; uint8_t buf[32+4];
int r = load_dkek(); int r = load_dkek();
if (r != HSM_OK) if (r != CCID_OK)
return r; return r;
memcpy(buf, dkek+IV_SIZE, 32); memcpy(buf, dkek+IV_SIZE, 32);
release_dkek(); release_dkek();
memcpy(buf+32, "\x0\x0\x0\x1", 4); memcpy(buf+32, "\x0\x0\x0\x1", 4);
hash256(buf, sizeof(buf), kenc); hash256(buf, sizeof(buf), kenc);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
return HSM_OK; return CCID_OK;
} }
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
uint8_t buf[32+4]; uint8_t buf[32+4];
int r = load_dkek(); int r = load_dkek();
if (r != HSM_OK) if (r != CCID_OK)
return r; return r;
memcpy(buf, dkek+IV_SIZE, 32); memcpy(buf, dkek+IV_SIZE, 32);
release_dkek(); release_dkek();
memcpy(buf+32, "\x0\x0\x0\x2", 4); memcpy(buf+32, "\x0\x0\x0\x2", 4);
hash256(buf, sizeof(buf), kmac); hash256(buf, sizeof(buf), kmac);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
return HSM_OK; return CCID_OK;
} }
int dkek_encrypt(uint8_t *data, size_t len) { int dkek_encrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dkek()) != HSM_OK) if ((r = load_dkek()) != CCID_OK)
return r; return r;
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek(); release_dkek();
@@ -128,7 +129,7 @@ int dkek_encrypt(uint8_t *data, size_t len) {
int dkek_decrypt(uint8_t *data, size_t len) { int dkek_decrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dkek()) != HSM_OK) if ((r = load_dkek()) != CCID_OK)
return r; return r;
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek(); release_dkek();
@@ -137,7 +138,7 @@ int dkek_decrypt(uint8_t *data, size_t len) {
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) { 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)) if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes 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)); memset(kb, 0, sizeof(kb));
@@ -167,9 +168,9 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
kb_len = 32; kb_len = 32;
if (kb_len != 16 && kb_len != 24 && kb_len != 32) if (kb_len != 16 && kb_len != 24 && kb_len != 32)
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
if (*out_len < 8+1+10+6+4+(2+32+14)+16) if (*out_len < 8+1+10+6+4+(2+32+14)+16)
return HSM_WRONG_LENGTH; return CCID_WRONG_LENGTH;
put_uint16_t(kb_len, kb+8); put_uint16_t(kb_len, kb+8);
memcpy(kb+10, key_ctx, kb_len); memcpy(kb+10, key_ctx, kb_len);
@@ -182,7 +183,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
} }
else if (key_type & HSM_KEY_RSA) { 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 if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
return HSM_WRONG_LENGTH; return CCID_WRONG_LENGTH;
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
kb_len = 0; kb_len = 0;
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2; put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
@@ -199,7 +200,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
} }
else if (key_type & HSM_KEY_EC) { 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 if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
return HSM_WRONG_LENGTH; return CCID_WRONG_LENGTH;
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
kb_len = 0; 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.P)*8, kb+8+kb_len); kb_len += 2;
@@ -265,7 +266,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
kb[kb_len] = 0x80; kb[kb_len] = 0x80;
} }
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad); int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
if (r != HSM_OK) if (r != CCID_OK)
return r; return r;
memcpy(out+*out_len, kb, kb_len_pad); memcpy(out+*out_len, kb, kb_len_pad);
@@ -276,7 +277,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
*out_len += 16; *out_len += 16;
if (r != 0) if (r != 0)
return r; return r;
return HSM_OK; return CCID_OK;
} }
int dkek_type_key(const uint8_t *in) { int dkek_type_key(const uint8_t *in) {
@@ -303,27 +304,27 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
dkek_kenc(kenc); dkek_kenc(kenc);
if (memcmp(kcv, in, 8) != 0) if (memcmp(kcv, in, 8) != 0)
return HSM_WRONG_DKEK; return CCID_WRONG_DKEK;
uint8_t signature[16]; 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); 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) if (r != 0)
return HSM_WRONG_SIGNATURE; return CCID_WRONG_SIGNATURE;
if (memcmp(signature, in+in_len-16, 16) != 0) if (memcmp(signature, in+in_len-16, 16) != 0)
return HSM_WRONG_SIGNATURE; return CCID_WRONG_SIGNATURE;
int key_type = in[8]; int key_type = in[8];
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15) if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
return HSM_WRONG_DATA; return CCID_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) 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; return CCID_WRONG_DATA;
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0) 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; return CCID_WRONG_DATA;
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0) if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
size_t ofs = 9; size_t ofs = 9;
@@ -344,12 +345,12 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
ofs += len+2; ofs += len+2;
if ((in_len-16-ofs) % 16 != 0) if ((in_len-16-ofs) % 16 != 0)
return HSM_WRONG_PADDING; return CCID_WRONG_PADDING;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes 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)); memset(kb, 0, sizeof(kb));
memcpy(kb, in+ofs, in_len-16-ofs); memcpy(kb, in+ofs, in_len-16-ofs);
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs); r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
if (r != HSM_OK) if (r != CCID_OK)
return r; return r;
int key_size = get_uint16_t(kb, 8); int key_size = get_uint16_t(kb, 8);
@@ -364,14 +365,14 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len; r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
len = get_uint16_t(kb, ofs); ofs += 2; len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len; r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
} }
else if (key_type == 6) { else if (key_type == 6) {
@@ -385,7 +386,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len; r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
//PQ //PQ
@@ -395,7 +396,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len; r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
//N //N
len = get_uint16_t(kb, ofs); ofs += len+2; len = get_uint16_t(kb, ofs); ofs += len+2;
@@ -405,33 +406,33 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len; r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
if (key_type == 5) { if (key_type == 5) {
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E); r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
} }
else if (key_type == 6) { else if (key_type == 6) {
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E); r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
} }
r = mbedtls_rsa_complete(rsa); r = mbedtls_rsa_complete(rsa);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
r = mbedtls_rsa_check_privkey(rsa); r = mbedtls_rsa_check_privkey(rsa);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(rsa); mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
} }
else if (key_type == 12) { else if (key_type == 12) {
@@ -449,7 +450,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len); mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
if (ec_id == MBEDTLS_ECP_DP_NONE) { if (ec_id == MBEDTLS_ECP_DP_NONE) {
mbedtls_ecdsa_free(ecdsa); mbedtls_ecdsa_free(ecdsa);
return HSM_WRONG_DATA; return CCID_WRONG_DATA;
} }
ofs += len; ofs += len;
@@ -464,11 +465,11 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len); r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(ecdsa); mbedtls_ecdsa_free(ecdsa);
return HSM_EXEC_ERROR; return CCID_EXEC_ERROR;
} }
} }
else if (key_type == 15) { else if (key_type == 15) {
memcpy(key_ctx, kb+ofs, key_size); memcpy(key_ctx, kb+ofs, key_size);
} }
return HSM_OK; return CCID_OK;
} }

60
src/hsm/files.c Normal file
View File

@@ -0,0 +1,60 @@
/*
* 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 "files.h"
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 | 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
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
/* 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_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];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
file_t *file_pin1 = NULL;
file_t *file_retries_pin1 = NULL;
file_t *file_sopin = NULL;
file_t *file_retries_sopin = NULL;

View File

@@ -15,15 +15,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _NEUG_H_
#define _NEUG_H_
#define NEUG_PRE_LOOP 32 #ifndef _FILES_H_
#define _FILES_H_
void neug_init(uint32_t *buf, uint8_t size); #include "file.h"
uint32_t neug_get();
void neug_flush(void); #define EF_DKEK 0x108F
void neug_wait_full(void); #define EF_PRKDFS 0x6040
void neug_fini(void); #define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
extern file_t *file_pin1;
extern file_t *file_retries_pin1;
extern file_t *file_sopin;
extern file_t *file_retries_sopin;
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,160 +0,0 @@
/*
* 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 _HSM2040_H_
#define _HSM2040_H_
#include "ccid.h"
#include "tusb.h"
#include "file.h"
#include "pico/unique_id.h"
#define USB_REQ_CCID 0xA1
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
struct app* (*select_aid)();
int (*unload)();
} app_t;
extern int register_app(app_t * (*)());
extern const uint8_t historical_bytes[];
#define DEBUG_PAYLOAD(p,s) { \
printf("Payload %s (%d bytes):\r\n", #p,s);\
for (int i = 0; i < s; i += 16) {\
printf("%07Xh : ",i+p);\
for (int j = 0; j < 16; j++) {\
if (j < s-i) printf("%02X ",(p)[i+j]);\
else printf(" ");\
if (j == 7) printf(" ");\
} printf(": "); \
for (int j = 0; j < MIN(16,s-i); j++) {\
printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\
if (j == 7) printf(" ");\
}\
printf("\r\n");\
} printf("\r\n"); \
}
struct apdu {
uint8_t seq;
/* command APDU */
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
uint8_t *cmd_apdu_data;
size_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
size_t expected_res_size; /* Ne, calculated by Le field */
/* response APDU */
uint16_t sw;
uint16_t res_apdu_data_len;
uint8_t *res_apdu_data;
};
#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
#define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
#define CCID_MSG_HEADER_SIZE 10
#define USB_LL_BUF_SIZE 64
/* CCID thread */
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
/* OpenPGPcard 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
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
#define CLS(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
#define P1(a) a.cmd_apdu_head[2]
#define P2(a) a.cmd_apdu_head[3]
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
extern struct apdu apdu;
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
static inline const uint16_t make_uint16_t(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline const uint16_t get_uint16_t(const uint8_t *b, uint16_t offset) {
return make_uint16_t(b[offset], b[offset+1]);
}
static inline const void put_uint16_t(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
}
#ifdef DEBUG
void stdout_init (void);
#define DEBUG_MORE 1
/*
* Debug functions in debug.c
*/
void put_byte (uint8_t b);
void put_byte_with_no_nl (uint8_t b);
void put_short (uint16_t x);
void put_word (uint32_t x);
void put_int (uint32_t x);
void put_string (const char *s);
void put_binary (const char *s, int len);
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_WORD(w) put_word (w)
#define DEBUG_SHORT(h) put_short (h)
#define DEBUG_BYTE(b) put_byte (b)
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
#else
#define DEBUG_INFO(msg)
#define DEBUG_WORD(w)
#define DEBUG_SHORT(h)
#define DEBUG_BYTE(b)
#define DEBUG_BINARY(s,len)
#endif
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern pico_unique_board_id_t unique_id;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -20,50 +20,10 @@
#include <stdlib.h> #include <stdlib.h>
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "hsm2040.h" #include "ccid2040.h"
extern const uint8_t sc_hsm_aid[]; 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_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)
#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_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_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99)
#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_INCORRECT_P1P2() set_res_sw (0x6A, 0x86)
#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88)
#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 HSM_OK 0
#define HSM_ERR_NO_MEMORY -1000
#define HSM_ERR_MEMORY_FATAL -1001
#define HSM_ERR_NULL_PARAM -1002
#define HSM_ERR_FILE_NOT_FOUND -1003
#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_RAW 0x20 /* RSA signature with external padding */
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */ #define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
@@ -88,13 +48,14 @@ extern const uint8_t sc_hsm_aid[];
#define ALGO_AES_CMAC 0x18 #define ALGO_AES_CMAC 0x18
#define ALGO_AES_DERIVE 0x99 #define ALGO_AES_DERIVE 0x99
#define HSM_OPT_RRC 0x1 #define HSM_OPT_RRC 0x0001
#define HSM_OPT_TRANSPORT_PIN 0x2 #define HSM_OPT_TRANSPORT_PIN 0x0002
#define HSM_OPT_SESSION_PIN 0x4 #define HSM_OPT_SESSION_PIN 0x0004
#define HSM_OPT_SESSION_PIN_EXPL 0xC #define HSM_OPT_SESSION_PIN_EXPL 0x000C
#define HSM_OPT_REPLACE_PKA 0x8 #define HSM_OPT_REPLACE_PKA 0x0008
#define HSM_OPT_COMBINED_AUTH 0x10 #define HSM_OPT_COMBINED_AUTH 0x0010
#define HSM_OPT_RRC_RESET_ONLY 0x20 #define HSM_OPT_RRC_RESET_ONLY 0x0020
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
#define P15_KEYTYPE_RSA 0x30 #define P15_KEYTYPE_RSA 0x30
#define P15_KEYTYPE_ECC 0xA0 #define P15_KEYTYPE_ECC 0xA0
@@ -109,6 +70,4 @@ extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
extern uint8_t session_pin[32], session_sopin[32]; extern uint8_t session_pin[32], session_sopin[32];
#define IV_SIZE 16
#endif #endif

View File

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

View File

@@ -1,182 +0,0 @@
/*
* 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/>.
*/
//Part of the code is taken from GnuK (GPLv3)
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "neug.h"
#include "hardware/structs/rosc.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "bsp/board.h"
#include "pico/unique_id.h"
void adc_start() {
adc_init();
adc_gpio_init(27);
adc_select_input(1);
}
void adc_stop() {
}
static uint64_t random_word = 0xcbf29ce484222325;
static uint8_t ep_round = 0;
static void ep_init() {
random_word = 0xcbf29ce484222325;
ep_round = 0;
}
/* Here, we assume a little endian architecture. */
static int ep_process () {
if (ep_round == 0) {
ep_init();
}
uint64_t word = 0x0;
for (int n = 0; n < 64; n++) {
uint8_t bit1, bit2;
do
{
bit1 = rosc_hw->randombit&0xff;
//sleep_ms(1);
bit2 = rosc_hw->randombit&0xff;
} while(bit1 == bit2);
word = (word << 1) | bit1;
}
random_word ^= word^board_millis()^adc_read();
random_word *= 0x00000100000001B3;
if (++ep_round == 8) {
ep_round = 0;
return 2; //2 words
}
return 0;
}
static const uint32_t *ep_output() {
return (uint32_t *)&random_word;
}
struct rng_rb {
uint32_t *buf;
uint8_t head, tail;
uint8_t size;
unsigned int full :1;
unsigned int empty :1;
};
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
rb->buf = p;
rb->size = size;
rb->head = rb->tail = 0;
rb->full = 0;
rb->empty = 1;
}
static void rb_add(struct rng_rb *rb, uint32_t v) {
rb->buf[rb->tail++] = v;
if (rb->tail == rb->size)
rb->tail = 0;
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;
vp = ep_output();
for (i = 0; i < n; i++) {
rb_add (rb, *vp++);
if (rb->full)
break;
}
}
return NULL;
}
void neug_init(uint32_t *buf, uint8_t size) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
const uint32_t *u = (const uint32_t *)unique_id.id;
struct rng_rb *rb = &the_ring_buffer;
int i;
rb_init(rb, buf, size);
adc_start();
ep_init();
}
void neug_flush(void) {
struct rng_rb *rb = &the_ring_buffer;
while (!rb->empty)
rb_del (rb);
}
uint32_t neug_get(int kick) {
struct rng_rb *rb = &the_ring_buffer;
uint32_t v;
while (rb->empty)
neug_task();
v = rb_del(rb);
return v;
}
void neug_wait_full(void) { //should be called only on core1
struct rng_rb *rb = &the_ring_buffer;
while (!rb->full) {
sleep_ms(1);
}
}
void neug_fini(void) {
neug_get(1);
}

View File

@@ -1,109 +0,0 @@
/*
* 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 <stdint.h>
#include <string.h>
#include "neug.h"
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void random_init(void) {
int i;
neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++)
neug_get();
}
void random_fini(void) {
neug_fini ();
}
/*
* Return pointer to random 32-byte
*/
void random_bytes_free (const uint8_t *p);
#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 (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full();
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *)random_word);
}
return (const uint8_t *)return_word;
}
/*
* 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();
}
/*
* Return 4-byte salt
*/
void random_get_salt(uint8_t *p) {
uint32_t rnd;
rnd = neug_get();
memcpy(p, &rnd, sizeof (uint32_t));
rnd = neug_get();
memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
}
/*
* Random byte iterator
*/
int random_gen(void *arg, unsigned char *out, size_t out_len) {
uint8_t *index_p = (uint8_t *)arg;
uint8_t index = index_p ? *index_p : 0;
size_t n;
while (out_len) {
neug_wait_full();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len)
n = out_len;
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 (index_p)
*index_p = index;
return 0;
}

View File

@@ -1,38 +0,0 @@
/*
* 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 _RANDOM_H_
#define _RANDOM_H_
#include "stdlib.h"
#include "pico/stdlib.h"
void random_init (void);
void random_fini (void);
/* 32-byte random bytes */
const uint8_t *random_bytes_get (size_t);
void random_bytes_free (const uint8_t *p);
/* 8-byte salt */
void random_get_salt (uint8_t *p);
/* iterator returning a byta at a time */
int random_gen (void *arg, unsigned char *output, size_t output_len);
#endif

View File

@@ -1,71 +0,0 @@
/*
* 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 _CCID_H_
#define _CCID_H_
#include "libopensc/ccid-types.h"
static const struct ccid_class_descriptor desc_ccid = {
.bLength = sizeof(struct ccid_class_descriptor),
.bDescriptorType = 0x21,
.bcdCCID = (0x0110),
.bMaxSlotIndex = 0,
.bVoltageSupport = 0x01, // 5.0V
.dwProtocols = (
0x01| // T=0
0x02), // T=1
.dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC),
.bNumClockSupport = 1,
.dwDataRate = (0x2580),
.dwMaxDataRate = (0x2580),
.bNumDataRatesSupported = 1,
.dwMaxIFSD = (0xFF), // 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),
.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,
};
#endif

View File

@@ -1,119 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#endif
// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#endif
// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_PICO
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 1
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 16
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#include "pico/types.h"
static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); }
static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); }
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View File

@@ -1,209 +0,0 @@
/*
* 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 "tusb.h"
#include "usb_descriptors.h"
#include "ccid.h"
#include "pico/unique_id.h"
#include "version.h"
#ifndef USB_VID
#define USB_VID 0xFEFF
#endif
#ifndef USB_PID
#define USB_PID 0xFCFD
#endif
#define USB_BCD 0x0200
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#define MAX_USB_POWER 1
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = (USB_BCD),
.bDeviceClass = 0x00,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = (USB_VID),
.idProduct = (USB_PID),
.bcdDevice = HSM_VERSION,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
tusb_desc_interface_t const desc_interface =
{
.bLength = sizeof(tusb_desc_interface_t),
.bDescriptorType = TUSB_DESC_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = TUSB_CLASS_SMART_CARD,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 5,
};
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
tusb_desc_configuration_t const desc_config =
{
.bLength = sizeof(tusb_desc_configuration_t),
.bDescriptorType = TUSB_DESC_CONFIGURATION,
.wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 4,
.bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1),
};
tusb_desc_endpoint_t const desc_ep1 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = TUSB_DIR_IN_MASK | 1,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
};
tusb_desc_endpoint_t const desc_ep2 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = 2,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
};
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)];
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
static uint8_t initd = 0;
if (initd == 0)
{
uint8_t *p = desc_config_extended;
memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t);
memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t);
memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor);
memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
initd = 1;
}
return (const uint8_t *)desc_config_extended;
}
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
uint8_t const desc_bos[] =
{
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2)
};
uint8_t const * tud_descriptor_bos_cb(void)
{
return desc_bos;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Pol Henarejos", // 1: Manufacturer
"Pico HSM", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Pico HSM Config", // 4: Vendor Interface
"Pico HSM Interface"
};
static uint16_t _desc_str[32];
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if (index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}
else {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
return NULL;
const char* str = string_desc_arr[index];
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
if (index == 3) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
str = unique_id_str;
}
chr_count = strlen(str);
if ( chr_count > 31 )
chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++) {
_desc_str[1+i] = str[i];
}
}
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
return _desc_str;
}

View File

@@ -1,29 +0,0 @@
/*
* 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 USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_
enum
{
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
extern uint8_t const desc_ms_os_20[];
#endif /* USB_DESCRIPTORS_H_ */