Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4e928588e | ||
|
|
b5cc4d6fd7 | ||
|
|
25291f978f | ||
|
|
1a5e6a7edc | ||
|
|
7cf166d615 | ||
|
|
413c3e0208 | ||
|
|
7410498df1 | ||
|
|
7aee18110e | ||
|
|
7aca7b323a | ||
|
|
4651a0e224 | ||
|
|
d018e3b9b9 | ||
|
|
1c272842a7 | ||
|
|
0141e0ab4e | ||
|
|
e7d8695394 | ||
|
|
6876edea5a | ||
|
|
2e655d6341 | ||
|
|
2f4cca19c4 | ||
|
|
5eb74d8ca3 | ||
|
|
7b0d5a6700 | ||
|
|
427260663f | ||
|
|
047a443536 | ||
|
|
7a9ee8145d | ||
|
|
2535d0e537 | ||
|
|
6fe7d7991b | ||
|
|
d061958f90 | ||
|
|
3112200eb6 | ||
|
|
69a406832d | ||
|
|
cd4ceb0a61 | ||
|
|
450ec5dec1 | ||
|
|
c7abd1a067 | ||
|
|
c6d87756ab | ||
|
|
0916489388 | ||
|
|
b1e83c92e9 | ||
|
|
d01e06aa11 | ||
|
|
464107b13f | ||
|
|
e431b25fc1 | ||
|
|
e4ed917c1c | ||
|
|
ade3e6d2fb | ||
|
|
d12d18261f | ||
|
|
525b4439c9 |
@@ -51,6 +51,8 @@ target_sources(pico_hsm PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hash_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
|
||||
|
||||
18
README.md
18
README.md
@@ -23,11 +23,13 @@ This is a project to create a Hardware Security Module (HSM) with a Raspberry Pi
|
||||
- DKEK n-of-m threshold scheme.
|
||||
- USB/CCID support with OpenSC, openssl, etc.
|
||||
- Extended APDU support.
|
||||
- Private keys and certificates import from WKY or PKCS#12 files.[^2]
|
||||
|
||||
[^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]: Imports are available via SCS3 tool, and only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process. See [SCS3](/doc/rsa_4096_support.md "SCS3") for more information.
|
||||
|
||||
## Security considerations
|
||||
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DKEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations. All keys (including DKEK) are loaded and cleared every time to avoid potential flaws.
|
||||
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DKEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations and only during the process. All keys (including DKEK) are loaded and cleared every time to avoid potential security flaws.
|
||||
|
||||
At the same time, DKEK is encrypted with doubled salted and hashed PIN. Also, the PIN is hashed in memory during the session. Hence, PIN is never stored in plain text neither in flash nor in memory. Note that PIN is conveyed from the host to the HSM in plain text if no secure channel is provided.
|
||||
|
||||
@@ -80,6 +82,18 @@ For backup, restore and DKEK share management, check [doc/backup-and-restore.md]
|
||||
|
||||
For AES key generation, encryption and decryption, check [doc/aes.md](/doc/aes.md).
|
||||
|
||||
For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096_support.md).
|
||||
|
||||
## Key generation time
|
||||
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `2048` and `4096` bits.
|
||||
|
||||
| RSA key length (bits) | Average time (seconds) |
|
||||
| :---: | :---: |
|
||||
| 1024 | 16 |
|
||||
| 2048 | 124 |
|
||||
| 3072 | N/A |
|
||||
| 4096 | N/A |
|
||||
|
||||
## Driver
|
||||
|
||||
Pico HSM uses the `sc-hsm` driver provided by [OpenSC](https://github.com/OpenSC/OpenSC/ "OpenSC") or the `sc-hsm-embedded` driver provided by [CardContact](https://github.com/CardContact/sc-hsm-embedded "CardContact"). This driver utilizes the standardized PKCS#11 interface to communicate with the user and it can be used with many engines that accept PKCS#11 interface, such as OpenSSL, P11 library or pkcs11-tool.
|
||||
@@ -90,6 +104,8 @@ The way to communicate is exactly the same as with other cards, such as OpenPGP
|
||||
|
||||
For an advanced usage, see the docs and examples.
|
||||
|
||||
Pico HSM also supports SCS3 tool. See [SCS3](/doc/rsa_4096_support.md "SCS3") for more information.
|
||||
|
||||
### Important
|
||||
OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a pair of VID/PID of supported readers. In order to be detectable, you must patch the UF2 binary (if you just downloaded from the [Release section](https://github.com/polhenarejos/pico-hsm/releases "Release section")) or configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION_MAJOR="1"
|
||||
VERSION_MINOR="6"
|
||||
VERSION_MINOR="8"
|
||||
|
||||
rm -rf release/*
|
||||
cd build
|
||||
cd build_release
|
||||
|
||||
for board in adafruit_feather_rp2040 adafruit_itsybitsy_rp2040 adafruit_qtpy_rp2040 adafruit_trinkey_qt2040 arduino_nano_rp2040_connect melopero_shake_rp2040 pimoroni_interstate75 pimoroni_keybow2040 pimoroni_pga2040 pimoroni_picolipo_4mb pimoroni_picolipo_16mb pimoroni_picosystem pimoroni_plasma2040 pimoroni_tiny2040 pybstick26_rp2040 sparkfun_micromod sparkfun_promicro sparkfun_thingplus vgaboard waveshare_rp2040_lcd_0.96 waveshare_rp2040_plus_4mb waveshare_rp2040_plus_16mb waveshare_rp2040_zero
|
||||
do
|
||||
@@ -18,4 +18,4 @@ done
|
||||
rm -rf *
|
||||
PICO_SDK_PATH=~/Devel/pico/pico-sdk cmake ..
|
||||
make -kj20
|
||||
mv pico_hsm.uf2 ../release/pico_hsm-$VERSION_MAJOR.$VERSION_MINOR.uf2
|
||||
mv pico_hsm.uf2 ../release/pico_hsm_pico_generic-$VERSION_MAJOR.$VERSION_MINOR.uf2
|
||||
49
doc/rsa_4096.md
Normal file
49
doc/rsa_4096.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# RSA 4096 support
|
||||
|
||||
Generating 4096 bits key in the Pico HSM is highly expensive. It may take minutes or hours to finish the generation. Therefore, it is extremely recommendable to generate the key in the host and import it into the Pico HSM.
|
||||
|
||||
## SCS3 tool
|
||||
|
||||
Unfortunately, there is no pkcs11 tool or equivalent capable to perform the import. Since it uses the SC-HSM driver, it also supports the communication with the [SCS3 tool](https://www.openscdp.org/scsh3/ "SCS3 tool"). It can be downloaded from [here](https://www.openscdp.org/scsh3/download.html "here").
|
||||
|
||||
However, SCS3 only works with those HSM manufactured by CardContact. The check is performed by means of trust store against the manufacturing certificates. For obvious reasons, these certificates can only be signed with the private keys of the Certificate Authorities listed in the trust store.
|
||||
|
||||
Pico HSM is shipped with its own CA certificates. To load this certificate onto the trust store of SCS3, the following line has to be appended to `SmartCardHSM.rootCerts` variable, near line `235` in the file `scs3/scsh/sc-hsm/SmartCardHSM.js`.
|
||||
|
||||
```
|
||||
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
|
||||
```
|
||||
|
||||
Therefore, the whole variable becomes:
|
||||
|
||||
```
|
||||
SmartCardHSM.rootCerts = {
|
||||
DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)),
|
||||
UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX)),
|
||||
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
|
||||
}
|
||||
````
|
||||
|
||||
After this ammendment, the KeyManager can be invoked (CTRL+M) and it will output something similar to:
|
||||
```
|
||||
>load("keymanager/keymanager.js");
|
||||
|
||||
SmartCard-HSM Version 1.6 on JCOP Free memory 217104 byte
|
||||
Issuer Certificate : CVC id-AT DV (official domestic) CAR=ESCVCAHSM00001 CHR=ESDVCAHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2025
|
||||
Device Certificate : CVC id-AT Terminal CAR=ESDVCAHSM00001 CHR=ESTERMHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2023
|
||||
Default Key Domain : 0F89B400975EDD2D425ABF85F2FBD318779B3D85475E65D4
|
||||
-------------------------------------------------------------------
|
||||
Please right-click on nodes in the outline to see possible actions.
|
||||
For most operations you will need to authenticate first using a
|
||||
mechanism from the User PIN context menu.
|
||||
>
|
||||
```
|
||||
|
||||
The SCS3 tool is ready to import private keys and certificates, wraped in WKY files or in PKCS#12 format. Also, all stored keys can be exported, combined with their respective certificates. Note that the user has to be previously logged in.
|
||||
|
||||
## DKEK requirement
|
||||
|
||||
In order to perform the import, private keys must be wrapped with the same DKEK present in the Pico HSM. Thus, the Pico HSM must be previously initialized with at minimum of 1 DKEK share. This share will be used to wrap the private key before import.
|
||||
|
||||
Note that the DKEK share shall be available before the import. In this way, all custodians must be present during the import process, since they will have to introduce their respective DKEK.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#
|
||||
|
||||
VERSION_MAJOR="1"
|
||||
VERSION_MINOR="4"
|
||||
VERSION_MINOR="8"
|
||||
|
||||
echo "----------------------------"
|
||||
echo "VID/PID patcher for Pico HSM"
|
||||
|
||||
@@ -78,55 +78,15 @@ void process_fci(const file_t *pe) {
|
||||
res_APDU[1] = res_APDU_size-2;
|
||||
}
|
||||
|
||||
const uint8_t cvca[] = {
|
||||
0x6A, 0x01,
|
||||
0x7f, 0x21, 0x82, 0x01, 0x65, 0x7f, 0x4e, 0x82, 0x01, 0x2d, 0x5f,
|
||||
0x29, 0x01, 0x00, 0x42, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
|
||||
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x49, 0x81,
|
||||
0xdd, 0x06, 0x0a, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x02, 0x02, 0x02,
|
||||
0x02, 0x03, 0x81, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x18, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x83,
|
||||
0x18, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7, 0x0f, 0xa7,
|
||||
0xe9, 0xab, 0x72, 0x24, 0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1,
|
||||
0x46, 0xb9, 0xb1, 0x84, 0x31, 0x04, 0x18, 0x8d, 0xa8, 0x0e, 0xb0,
|
||||
0x30, 0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00,
|
||||
0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12, 0x07, 0x19, 0x2b,
|
||||
0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
|
||||
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11, 0x85,
|
||||
0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x99, 0xde, 0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4,
|
||||
0xd2, 0x28, 0x31, 0x86, 0x31, 0x04, 0x4d, 0x28, 0x34, 0x67, 0xb5,
|
||||
0x43, 0xfd, 0x84, 0x22, 0x09, 0xbd, 0xd2, 0xd6, 0x26, 0x27, 0x2d,
|
||||
0x53, 0xa7, 0xdf, 0x52, 0x8f, 0xc2, 0xde, 0x7c, 0x9a, 0xcd, 0x1f,
|
||||
0xf2, 0x10, 0x42, 0x7c, 0x13, 0x44, 0x03, 0xb0, 0xa5, 0xdf, 0x8a,
|
||||
0xd4, 0x59, 0xd1, 0x86, 0x4b, 0xde, 0x33, 0xb1, 0x60, 0x17, 0x87,
|
||||
0x01, 0x01, 0x5f, 0x20, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
|
||||
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x4c, 0x12,
|
||||
0x06, 0x09, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x01, 0x02, 0x02,
|
||||
0x53, 0x05, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x25, 0x06, 0x02,
|
||||
0x02, 0x00, 0x02, 0x01, 0x09, 0x5f, 0x24, 0x06, 0x03, 0x00, 0x01,
|
||||
0x02, 0x03, 0x01, 0x5f, 0x37, 0x30, 0x26, 0x2d, 0x6f, 0xa6, 0xd0,
|
||||
0x52, 0x01, 0xf1, 0x41, 0x1e, 0xe9, 0x33, 0x29, 0x19, 0x42, 0x42,
|
||||
0x9b, 0xb0, 0xeb, 0xf7, 0x46, 0x20, 0xcb, 0x81, 0xfe, 0xda, 0xd7,
|
||||
0xab, 0x2b, 0xdc, 0xa7, 0x38, 0xf4, 0xc8, 0xec, 0x4c, 0x66, 0xb4,
|
||||
0x0a, 0x2d, 0x16, 0xfb, 0xf3, 0x79, 0xe9, 0x93, 0xc8, 0x25
|
||||
};
|
||||
const uint8_t token_info[] = {
|
||||
0x28, 0x00, //litle endian
|
||||
0x30, 0x26, 0x2, 0x1, 0x1, 0x4, 0x4, 0xd, 0x0, 0x0, 0x0, 0xc, 0xd, 0x50, 0x6f, 0x6c, 0x20, 0x48, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x6a, 0x6f, 0x73, 0x80, 0x8, 0x48, 0x53, 0x4d, 0x20, 0x32, 0x30, 0x34, 0x30, 0x3, 0x2, 0x4, 0xf0
|
||||
};
|
||||
|
||||
extern const uint8_t sc_hsm_aid[];
|
||||
extern int parse_token_info(const file_t *f, int mode);
|
||||
extern int parse_cvca(const file_t *f, int mode);
|
||||
|
||||
file_t file_entries[] = {
|
||||
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
|
||||
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
|
||||
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
|
||||
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
||||
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
||||
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
|
||||
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
|
||||
|
||||
41
src/hsm/cvcerts.h
Normal file
41
src/hsm/cvcerts.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef CVCERTS_H_
|
||||
#define CVCERTS_H_
|
||||
|
||||
static const unsigned char termca[] = {
|
||||
0xfa, 0x00,
|
||||
0x7f,0x21,0x81,0xf6,0x7f,0x4e,0x81,0xbf,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||
0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x0f,0x89,
|
||||
0xb4,0x00,0x97,0x5e,0xdd,0x2d,0x42,0x5a,0xbf,0x85,0xf2,0xfb,0xd3,0x18,0x77,0x9b,
|
||||
0x3d,0x85,0x47,0x5e,0x65,0xd4,0xd8,0x58,0x69,0xd3,0x04,0x14,0xb7,0x1f,0x16,0x1e,
|
||||
0xb0,0x40,0xd9,0xf7,0xa7,0xe3,0x73,0xa3,0x15,0xc7,0xd9,0x9a,0x51,0xf5,0x5f,0x20,
|
||||
0x0e,0x45,0x53,0x54,0x45,0x52,0x4d,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x00,
|
||||
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||
0x02,0x03,0x01,0x02,0x03,0x01,0x65,0x2f,0x73,0x2d,0x06,0x09,0x04,0x00,0x7f,0x00,
|
||||
0x07,0x03,0x01,0x03,0x01,0x80,0x20,0x68,0x53,0x30,0xc7,0x9a,0x47,0xad,0xfd,0x37,
|
||||
0xaa,0xe8,0x53,0xf4,0xbd,0x77,0x3a,0x40,0x89,0x3a,0x79,0x7e,0x3c,0x27,0x18,0x3b,
|
||||
0x39,0x67,0xdf,0x8d,0x4f,0xe5,0x99,0x5f,0x37,0x30,0x10,0xff,0x17,0x96,0x0d,0x93,
|
||||
0x07,0xc0,0x69,0x8e,0x3a,0xa0,0x44,0x69,0x70,0x88,0xe6,0x9c,0xb4,0xd3,0x16,0x9a,
|
||||
0x22,0x4e,0x5c,0x77,0xa9,0xe7,0x83,0x75,0x9a,0xd2,0x7e,0x92,0xf2,0x04,0x93,0xb1,
|
||||
0xe9,0xc9,0xe5,0x10,0xc9,0x94,0xff,0x9d,0xe2,0x00
|
||||
};
|
||||
|
||||
static const unsigned char dica[] = {
|
||||
0xc9, 0x00,
|
||||
0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||
0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e,
|
||||
0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb,
|
||||
0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08,
|
||||
0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20,
|
||||
0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80,
|
||||
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||
0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5,
|
||||
0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d,
|
||||
0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99,
|
||||
0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d
|
||||
};
|
||||
|
||||
#endif
|
||||
473
src/hsm/dkek.c
Normal file
473
src/hsm/dkek.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "stdlib.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "dkek.h"
|
||||
#include "hash_utils.h"
|
||||
#include "random.h"
|
||||
#include "sc_hsm.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
|
||||
static uint8_t dkek[IV_SIZE+32];
|
||||
static uint8_t tmp_dkek[32];
|
||||
extern bool has_session_pin;
|
||||
extern uint8_t session_pin[32];
|
||||
|
||||
int load_dkek() {
|
||||
if (has_session_pin == false)
|
||||
return HSM_NO_LOGIN;
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!tf)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
|
||||
int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||
if (ret != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
void release_dkek() {
|
||||
memset(dkek, 0, sizeof(dkek));
|
||||
}
|
||||
|
||||
void init_dkek() {
|
||||
release_dkek();
|
||||
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||
}
|
||||
|
||||
int store_dkek_key() {
|
||||
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!tf)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
flash_write_data_to_file(tf, dkek, sizeof(dkek));
|
||||
low_flash_available();
|
||||
release_dkek();
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int save_dkek_key(const uint8_t *key) {
|
||||
const uint8_t *iv = random_bytes_get(32);
|
||||
memcpy(dkek, iv, IV_SIZE);
|
||||
if (!key)
|
||||
key = tmp_dkek;
|
||||
memcpy(dkek+IV_SIZE, key, 32);
|
||||
return store_dkek_key();
|
||||
}
|
||||
|
||||
void import_dkek_share(const uint8_t *share) {
|
||||
for (int i = 0; i < 32; i++)
|
||||
tmp_dkek[i] ^= share[i];
|
||||
}
|
||||
|
||||
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
|
||||
uint8_t hsh[32];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
hash256(dkek+IV_SIZE, 32, hsh);
|
||||
release_dkek();
|
||||
memcpy(kcv, hsh, 8);
|
||||
}
|
||||
|
||||
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
|
||||
uint8_t buf[32+4];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
memcpy(buf, dkek+IV_SIZE, 32);
|
||||
release_dkek();
|
||||
memcpy(buf+32, "\x0\x0\x0\x1", 4);
|
||||
hash256(buf, sizeof(buf), kenc);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
|
||||
uint8_t buf[32+4];
|
||||
int r = load_dkek();
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
memcpy(buf, dkek+IV_SIZE, 32);
|
||||
release_dkek();
|
||||
memcpy(buf+32, "\x0\x0\x0\x2", 4);
|
||||
hash256(buf, sizeof(buf), kmac);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int dkek_encrypt(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
return r;
|
||||
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||
release_dkek();
|
||||
return r;
|
||||
}
|
||||
|
||||
int dkek_decrypt(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
return r;
|
||||
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||
release_dkek();
|
||||
return r;
|
||||
}
|
||||
|
||||
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) {
|
||||
if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
|
||||
return HSM_WRONG_DATA;
|
||||
|
||||
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||
memset(kb, 0, sizeof(kb));
|
||||
int kb_len = 0;
|
||||
uint8_t *algo = NULL;
|
||||
uint8_t algo_len = 0;
|
||||
uint8_t *allowed = NULL;
|
||||
uint8_t allowed_len = 0;
|
||||
uint8_t kenc[32];
|
||||
memset(kenc, 0, sizeof(kenc));
|
||||
dkek_kenc(kenc);
|
||||
|
||||
uint8_t kcv[8];
|
||||
memset(kcv, 0, sizeof(kcv));
|
||||
dkek_kcv(kcv);
|
||||
|
||||
uint8_t kmac[32];
|
||||
memset(kmac, 0, sizeof(kmac));
|
||||
dkek_kmac(kmac);
|
||||
|
||||
if (key_type & HSM_KEY_AES) {
|
||||
if (key_type & HSM_KEY_AES_128)
|
||||
kb_len = 16;
|
||||
else if (key_type & HSM_KEY_AES_192)
|
||||
kb_len = 24;
|
||||
else if (key_type & HSM_KEY_AES_256)
|
||||
kb_len = 32;
|
||||
|
||||
if (kb_len != 16 && kb_len != 24 && kb_len != 32)
|
||||
return HSM_WRONG_DATA;
|
||||
if (*out_len < 8+1+10+6+4+(2+32+14)+16)
|
||||
return HSM_WRONG_LENGTH;
|
||||
|
||||
put_uint16_t(kb_len, kb+8);
|
||||
memcpy(kb+10, key_ctx, kb_len);
|
||||
kb_len += 2;
|
||||
|
||||
algo = "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8)
|
||||
algo_len = 10;
|
||||
allowed = "\x00\x04\x10\x11\x18\x99"; //(2+4)
|
||||
allowed_len = 6;
|
||||
}
|
||||
else if (key_type & HSM_KEY_RSA) {
|
||||
if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
|
||||
return HSM_WRONG_LENGTH;
|
||||
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||
kb_len = 0;
|
||||
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
|
||||
|
||||
put_uint16_t(mbedtls_mpi_size(&rsa->D), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&rsa->D, kb+8+kb_len, mbedtls_mpi_size(&rsa->D)); kb_len += mbedtls_mpi_size(&rsa->D);
|
||||
put_uint16_t(mbedtls_mpi_size(&rsa->N), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&rsa->N, kb+8+kb_len, mbedtls_mpi_size(&rsa->N)); kb_len += mbedtls_mpi_size(&rsa->N);
|
||||
put_uint16_t(mbedtls_mpi_size(&rsa->E), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&rsa->E, kb+8+kb_len, mbedtls_mpi_size(&rsa->E)); kb_len += mbedtls_mpi_size(&rsa->E);
|
||||
|
||||
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02";
|
||||
algo_len = 12;
|
||||
}
|
||||
else if (key_type & HSM_KEY_EC) {
|
||||
if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
|
||||
return HSM_WRONG_LENGTH;
|
||||
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||
kb_len = 0;
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2;
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.A), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.A, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.A)); kb_len += mbedtls_mpi_size(&ecdsa->grp.A);
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.B), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.B, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.B)); kb_len += mbedtls_mpi_size(&ecdsa->grp.B);
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.P, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.P)); kb_len += mbedtls_mpi_size(&ecdsa->grp.P);
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.N), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.N, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.N)); kb_len += mbedtls_mpi_size(&ecdsa->grp.N);
|
||||
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.Y), kb+8+kb_len); kb_len += 2;
|
||||
kb[8+kb_len++] = 0x4;
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.G.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.X)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.X);
|
||||
mbedtls_mpi_write_binary(&ecdsa->grp.G.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.Y)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.Y);
|
||||
put_uint16_t(mbedtls_mpi_size(&ecdsa->d), kb+8+kb_len); kb_len += 2;
|
||||
mbedtls_mpi_write_binary(&ecdsa->d, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->d)); kb_len += mbedtls_mpi_size(&ecdsa->d);
|
||||
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.Y), kb+8+kb_len); kb_len += 2;
|
||||
kb[8+kb_len++] = 0x4;
|
||||
mbedtls_mpi_write_binary(&ecdsa->Q.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.X)); kb_len += mbedtls_mpi_size(&ecdsa->Q.X);
|
||||
mbedtls_mpi_write_binary(&ecdsa->Q.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.Y)); kb_len += mbedtls_mpi_size(&ecdsa->Q.Y);
|
||||
|
||||
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03";
|
||||
algo_len = 12;
|
||||
}
|
||||
memset(out, 0, *out_len);
|
||||
*out_len = 0;
|
||||
|
||||
memcpy(out+*out_len, kcv, 8);
|
||||
*out_len += 8;
|
||||
|
||||
if (key_type & HSM_KEY_AES)
|
||||
out[*out_len] = 15;
|
||||
else if (key_type & HSM_KEY_RSA)
|
||||
out[*out_len] = 5;
|
||||
else if (key_type & HSM_KEY_EC)
|
||||
out[*out_len] = 12;
|
||||
*out_len += 1;
|
||||
|
||||
if (algo) {
|
||||
memcpy(out+*out_len, algo, algo_len);
|
||||
*out_len += algo_len;
|
||||
}
|
||||
else
|
||||
*out_len += 2;
|
||||
|
||||
if (allowed) {
|
||||
memcpy(out+*out_len, allowed, allowed_len);
|
||||
*out_len += allowed_len;
|
||||
}
|
||||
else
|
||||
*out_len += 2;
|
||||
//add 4 zeros
|
||||
*out_len += 4;
|
||||
|
||||
memcpy(kb, random_bytes_get(8), 8);
|
||||
kb_len += 8; //8 random bytes
|
||||
int kb_len_pad = ((int)(kb_len/16))*16;
|
||||
if (kb_len % 16 > 0)
|
||||
kb_len_pad = ((int)(kb_len/16)+1)*16;
|
||||
//key already copied at kb+10
|
||||
if (kb_len < kb_len_pad) {
|
||||
kb[kb_len] = 0x80;
|
||||
}
|
||||
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
|
||||
memcpy(out+*out_len, kb, kb_len_pad);
|
||||
*out_len += kb_len_pad;
|
||||
|
||||
r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, out, *out_len, out+*out_len);
|
||||
|
||||
*out_len += 16;
|
||||
if (r != 0)
|
||||
return r;
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int dkek_type_key(const uint8_t *in) {
|
||||
if (in[8] == 5 || in[8] == 6)
|
||||
return HSM_KEY_RSA;
|
||||
else if (in[8] == 12)
|
||||
return HSM_KEY_EC;
|
||||
else if (in[8] == 15)
|
||||
return HSM_KEY_AES;
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out) {
|
||||
uint8_t kcv[8];
|
||||
memset(kcv, 0, sizeof(kcv));
|
||||
dkek_kcv(kcv);
|
||||
|
||||
uint8_t kmac[32];
|
||||
memset(kmac, 0, sizeof(kmac));
|
||||
dkek_kmac(kmac);
|
||||
|
||||
uint8_t kenc[32];
|
||||
memset(kenc, 0, sizeof(kenc));
|
||||
dkek_kenc(kenc);
|
||||
|
||||
if (memcmp(kcv, in, 8) != 0)
|
||||
return HSM_WRONG_DKEK;
|
||||
|
||||
uint8_t signature[16];
|
||||
int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature);
|
||||
if (r != 0)
|
||||
return HSM_WRONG_SIGNATURE;
|
||||
if (memcmp(signature, in+in_len-16, 16) != 0)
|
||||
return HSM_WRONG_SIGNATURE;
|
||||
|
||||
int key_type = in[8];
|
||||
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
|
||||
return HSM_WRONG_DATA;
|
||||
|
||||
if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
|
||||
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
|
||||
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
|
||||
return HSM_WRONG_DATA;
|
||||
|
||||
size_t ofs = 9;
|
||||
|
||||
//OID
|
||||
size_t len = get_uint16_t(in, ofs);
|
||||
ofs += len+2;
|
||||
|
||||
//Allowed algorithms
|
||||
len = get_uint16_t(in, ofs);
|
||||
ofs += len+2;
|
||||
|
||||
//Access conditions
|
||||
len = get_uint16_t(in, ofs);
|
||||
ofs += len+2;
|
||||
|
||||
//Key OID
|
||||
len = get_uint16_t(in, ofs);
|
||||
ofs += len+2;
|
||||
|
||||
if ((in_len-16-ofs) % 16 != 0)
|
||||
return HSM_WRONG_PADDING;
|
||||
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||
memset(kb, 0, sizeof(kb));
|
||||
memcpy(kb, in+ofs, in_len-16-ofs);
|
||||
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
|
||||
int key_size = get_uint16_t(kb, 8);
|
||||
if (key_size_out)
|
||||
*key_size_out = key_size;
|
||||
ofs = 10;
|
||||
if (key_type == 5 || key_type == 6) {
|
||||
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||
mbedtls_rsa_init(rsa);
|
||||
if (key_type == 5) {
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
}
|
||||
else if (key_type == 6) {
|
||||
//DP-1
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
//DQ-1
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
|
||||
//PQ
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
//N
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
}
|
||||
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
|
||||
if (key_type == 5) {
|
||||
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 6) {
|
||||
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
r = mbedtls_rsa_complete(rsa);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
r = mbedtls_rsa_check_privkey(rsa);
|
||||
if (r != 0) {
|
||||
mbedtls_rsa_free(rsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 12) {
|
||||
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||
mbedtls_ecdsa_init(ecdsa);
|
||||
|
||||
//A
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
//B
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
//P
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
|
||||
if (ec_id == MBEDTLS_ECP_DP_NONE) {
|
||||
mbedtls_ecdsa_free(ecdsa);
|
||||
return HSM_WRONG_DATA;
|
||||
}
|
||||
ofs += len;
|
||||
|
||||
//N
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
//G
|
||||
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||
|
||||
//d
|
||||
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
|
||||
if (r != 0) {
|
||||
mbedtls_ecdsa_free(ecdsa);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else if (key_type == 15) {
|
||||
memcpy(key_ctx, kb+ofs, key_size);
|
||||
}
|
||||
return HSM_OK;
|
||||
}
|
||||
36
src/hsm/dkek.h
Normal file
36
src/hsm/dkek.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DKEK_H_
|
||||
#define _DKEK_H_
|
||||
|
||||
extern int load_dkek();
|
||||
extern int save_dkek_key(const uint8_t *key);
|
||||
extern int store_dkek_key();
|
||||
extern void init_dkek();
|
||||
extern void release_dkek();
|
||||
extern void import_dkek_share(const uint8_t *share);
|
||||
extern int dkek_kcv(uint8_t *kcv);
|
||||
extern int dkek_encrypt(uint8_t *data, size_t len);
|
||||
extern int dkek_decrypt(uint8_t *data, size_t len);
|
||||
extern int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len);
|
||||
extern int dkek_type_key(const uint8_t *in);
|
||||
extern int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out);
|
||||
|
||||
#define MAX_DKEK_ENCODE_KEY_BUFFER (8+1+12+6+(8+2*4+2*4096/8+3+13)+16)
|
||||
|
||||
#endif
|
||||
142
src/hsm/hash_utils.c
Normal file
142
src/hsm/hash_utils.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pico/unique_id.h>
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "hash_utils.h"
|
||||
#include "sc_hsm.h"
|
||||
#include "libopensc/card-sc-hsm.h"
|
||||
|
||||
void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
|
||||
uint8_t o1[32];
|
||||
hash_multi(pin, len, o1);
|
||||
for (int i = 0; i < sizeof(o1); i++)
|
||||
o1[i] ^= pin[i%len];
|
||||
hash_multi(o1, sizeof(o1), output);
|
||||
}
|
||||
|
||||
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
int iters = 256;
|
||||
pico_unique_board_id_t unique_id;
|
||||
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
|
||||
mbedtls_sha256_starts (&ctx, 0);
|
||||
mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id));
|
||||
|
||||
while (iters > len)
|
||||
{
|
||||
mbedtls_sha256_update (&ctx, input, len);
|
||||
iters -= len;
|
||||
}
|
||||
if (iters > 0) // remaining iterations
|
||||
mbedtls_sha256_update (&ctx, input, iters);
|
||||
mbedtls_sha256_finish (&ctx, output);
|
||||
mbedtls_sha256_free (&ctx);
|
||||
}
|
||||
|
||||
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
|
||||
mbedtls_sha256_starts (&ctx, 0);
|
||||
mbedtls_sha256_update (&ctx, input, len);
|
||||
|
||||
mbedtls_sha256_finish (&ctx, output);
|
||||
mbedtls_sha256_free (&ctx);
|
||||
}
|
||||
|
||||
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_init(&ctx);
|
||||
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
|
||||
mbedtls_md_setup(&ctx, md_info, 0);
|
||||
mbedtls_md_starts(&ctx);
|
||||
mbedtls_md_update(&ctx, input, len);
|
||||
mbedtls_md_finish(&ctx, output);
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
|
||||
int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memset(tmp_iv, 0, IV_SIZE);
|
||||
if (iv)
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
if (mode == HSM_AES_MODE_CBC)
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memset(tmp_iv, 0, IV_SIZE);
|
||||
if (iv)
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
if (mode == HSM_AES_MODE_CBC)
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
|
||||
return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
|
||||
}
|
||||
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
|
||||
return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
|
||||
}
|
||||
|
||||
struct ec_curve_mbed_id {
|
||||
struct sc_lv_data curve;
|
||||
mbedtls_ecp_group_id id;
|
||||
};
|
||||
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 },
|
||||
{ { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 },
|
||||
{ { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 },
|
||||
{ { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 },
|
||||
{ { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 },
|
||||
{ { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 },
|
||||
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
|
||||
};
|
||||
|
||||
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
|
||||
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
|
||||
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
|
||||
return ec->id;
|
||||
}
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
46
src/hsm/hash_utils.h
Normal file
46
src/hsm/hash_utils.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _HASH_UTILS_H_
|
||||
#define _HASH_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
|
||||
@@ -1570,6 +1570,7 @@ void tud_mount_cb()
|
||||
|
||||
void led_blinking_task()
|
||||
{
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
static uint32_t start_ms = 0;
|
||||
static uint8_t led_state = false;
|
||||
static uint8_t led_color = PICO_DEFAULT_LED_PIN;
|
||||
@@ -1587,6 +1588,7 @@ void led_blinking_task()
|
||||
|
||||
gpio_put(led_color, led_state);
|
||||
led_state ^= 1; // toggle
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_off_all()
|
||||
@@ -1596,8 +1598,10 @@ void led_off_all()
|
||||
gpio_put(TINY2040_LED_G_PIN, 1);
|
||||
gpio_put(TINY2040_LED_B_PIN, 1);
|
||||
#else
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void neug_task();
|
||||
@@ -1619,8 +1623,10 @@ int main(void)
|
||||
gpio_init(TINY2040_LED_B_PIN);
|
||||
gpio_set_dir(TINY2040_LED_B_PIN, GPIO_OUT);
|
||||
#else
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
led_off_all();
|
||||
|
||||
653
src/hsm/sc_hsm.c
653
src/hsm/sc_hsm.c
@@ -29,6 +29,9 @@
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "mbedtls/hkdf.h"
|
||||
#include "version.h"
|
||||
#include "cvcerts.h"
|
||||
#include "hash_utils.h"
|
||||
#include "dkek.h"
|
||||
|
||||
const uint8_t sc_hsm_aid[] = {
|
||||
11,
|
||||
@@ -38,7 +41,6 @@ const uint8_t sc_hsm_aid[] = {
|
||||
uint8_t session_pin[32], session_sopin[32];
|
||||
bool has_session_pin = false, has_session_sopin = false;
|
||||
static uint8_t dkeks = 0, current_dkeks = 0;
|
||||
static uint8_t tmp_dkek[IV_SIZE+32];
|
||||
|
||||
static int sc_hsm_process_apdu();
|
||||
|
||||
@@ -72,49 +74,6 @@ int sc_hsm_unload() {
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
static int encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_enc (&aes, key, 256);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
static int decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
|
||||
{
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
uint8_t tmp_iv[IV_SIZE];
|
||||
size_t iv_offset = 0;
|
||||
memcpy(tmp_iv, iv, IV_SIZE);
|
||||
int r = mbedtls_aes_setkey_enc (&aes, key, 256);
|
||||
if (r != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
|
||||
int load_dkek() {
|
||||
if (has_session_pin == false)
|
||||
return HSM_NO_LOGIN;
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!tf)
|
||||
return HSM_ERR_FILE_NOT_FOUND;
|
||||
memcpy(tmp_dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
|
||||
int ret = decrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32);
|
||||
if (ret != 0)
|
||||
return HSM_EXEC_ERROR;
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
void release_dkek() {
|
||||
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||
}
|
||||
|
||||
void select_file(file_t *pe) {
|
||||
if (!pe)
|
||||
{
|
||||
@@ -146,6 +105,9 @@ static int cmd_select() {
|
||||
|
||||
if (apdu.cmd_apdu_data_len >= 2)
|
||||
fid = get_uint16_t(apdu.cmd_apdu_data, 0);
|
||||
|
||||
//if ((fid & 0xff00) == (KEY_PREFIX << 8))
|
||||
// fid = (PRKD_PREFIX << 8) | (fid & 0xff);
|
||||
|
||||
if ((fid & 0xff00) == (PRKD_PREFIX << 8)) {
|
||||
if (!(pe = search_dynamic_file(fid)))
|
||||
@@ -206,6 +168,15 @@ static int cmd_select() {
|
||||
}
|
||||
if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
|
||||
process_fci(pe);
|
||||
if (pe == file_sc_hsm) {
|
||||
res_APDU[res_APDU_size++] = 0x85;
|
||||
res_APDU[res_APDU_size++] = 4;
|
||||
res_APDU[res_APDU_size++] = 0xff; //options
|
||||
res_APDU[res_APDU_size++] = 0xff;
|
||||
res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR;
|
||||
res_APDU[res_APDU_size++] = HSM_VERSION_MINOR;
|
||||
res_APDU[1] = res_APDU_size-2;
|
||||
}
|
||||
}
|
||||
else
|
||||
return SW_INCORRECT_P1P2();
|
||||
@@ -213,6 +184,53 @@ static int cmd_select() {
|
||||
return SW_OK ();
|
||||
}
|
||||
|
||||
sc_context_t *create_context() {
|
||||
sc_context_t *ctx;
|
||||
sc_context_param_t ctx_opts;
|
||||
memset(&ctx_opts, 0, sizeof(sc_context_param_t));
|
||||
ctx_opts.ver = 0;
|
||||
ctx_opts.app_name = "hsm2040";
|
||||
sc_context_create(&ctx, &ctx_opts);
|
||||
ctx->debug = 0;
|
||||
sc_ctx_log_to_file(ctx, "stdout");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void cvc_init_common(sc_cvc_t *cvc, sc_context_t *ctx) {
|
||||
memset(cvc, 0, sizeof(sc_cvc_t));
|
||||
|
||||
size_t lencar = 0, lenchr = 0;
|
||||
const unsigned char *car = sc_asn1_find_tag(ctx, (const uint8_t *)apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, 0x42, &lencar);
|
||||
const unsigned char *chr = sc_asn1_find_tag(ctx, (const uint8_t *)apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, 0x5f20, &lenchr);
|
||||
if (car && lencar > 0)
|
||||
strlcpy(cvc->car, car, MIN(lencar,sizeof(cvc->car)));
|
||||
else
|
||||
strlcpy(cvc->car, "UTSRCACC100001", sizeof(cvc->car));
|
||||
if (chr && lenchr > 0)
|
||||
strlcpy(cvc->chr, chr, MIN(lenchr, sizeof(cvc->chr)));
|
||||
else
|
||||
strlcpy(cvc->chr, "ESHSMCVCA00001", sizeof(cvc->chr));
|
||||
strlcpy(cvc->outer_car, "ESHSM00001", sizeof(cvc->outer_car));
|
||||
}
|
||||
|
||||
int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_len, uint8_t *hsh) {
|
||||
uint8_t *cvcbin;
|
||||
size_t cvclen;
|
||||
cvc->signatureLen = sig_len;
|
||||
cvc->signature = (uint8_t *)calloc(1, sig_len);
|
||||
cvc->outerSignatureLen = 4;
|
||||
cvc->outerSignature = (uint8_t *)calloc(1, sig_len);
|
||||
int r = sc_pkcs15emu_sc_hsm_encode_cvc(p15card, cvc, &cvcbin, &cvclen);
|
||||
if (r != SC_SUCCESS) {
|
||||
if (cvcbin)
|
||||
free(cvcbin);
|
||||
return r;
|
||||
}
|
||||
hash256(cvcbin, cvclen, hsh);
|
||||
free(cvcbin);
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
int parse_token_info(const file_t *f, int mode) {
|
||||
char *label = "Pico-HSM";
|
||||
char *manu = "Pol Henarejos";
|
||||
@@ -238,6 +256,16 @@ int parse_token_info(const file_t *f, int mode) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int parse_cvca(const file_t *f, int mode) {
|
||||
size_t termca_len = file_read_uint16(termca);
|
||||
size_t dica_len = file_read_uint16(dica);
|
||||
if (mode == 1) {
|
||||
memcpy(res_APDU, termca+2, termca_len);
|
||||
memcpy(res_APDU+termca_len, dica+2, dica_len);
|
||||
res_APDU_size = termca_len+dica_len;
|
||||
}
|
||||
return termca_len+dica_len;
|
||||
}
|
||||
|
||||
static int cmd_list_keys()
|
||||
{
|
||||
@@ -245,6 +273,8 @@ static int cmd_list_keys()
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
file_t *f = &dynamic_file[i];
|
||||
if ((f->fid & 0xff00) == (PRKD_PREFIX << 8)) {
|
||||
res_APDU[res_APDU_size++] = PRKD_PREFIX;
|
||||
res_APDU[res_APDU_size++] = f->fid & 0xff;
|
||||
res_APDU[res_APDU_size++] = KEY_PREFIX;
|
||||
res_APDU[res_APDU_size++] = f->fid & 0xff;
|
||||
}
|
||||
@@ -412,6 +442,12 @@ static int cmd_verify() {
|
||||
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_pin1->data+2));
|
||||
}
|
||||
else if (p2 == 0x88) { //SOPin
|
||||
if (apdu.cmd_apdu_data_len > 0) {
|
||||
return check_pin(file_sopin, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
||||
}
|
||||
if (file_read_uint8(file_retries_sopin->data+2) == 0)
|
||||
return SW_PIN_BLOCKED();
|
||||
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2));
|
||||
}
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
@@ -449,229 +485,179 @@ static int cmd_challenge() {
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
extern char __StackLimit;
|
||||
int heapLeft() {
|
||||
char *p = malloc(256); // try to avoid undue fragmentation
|
||||
int left = &__StackLimit - p;
|
||||
free(p);
|
||||
return left;
|
||||
}
|
||||
|
||||
static int cmd_initialize() {
|
||||
initialize_flash(true);
|
||||
scan_flash();
|
||||
dkeks = 0;
|
||||
const uint8_t *p = apdu.cmd_apdu_data;
|
||||
while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) {
|
||||
uint8_t tag = *p++;
|
||||
uint8_t tag_len = *p++;
|
||||
if (tag == 0x80) { //options
|
||||
}
|
||||
else if (tag == 0x81) { //user pin
|
||||
if (file_pin1 && file_pin1->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
}
|
||||
else if (tag == 0x82) { //user pin
|
||||
if (file_sopin && file_sopin->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_sopin, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
}
|
||||
else if (tag == 0x91) { //user pin
|
||||
file_t *tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
|
||||
if (tf && tf->data) {
|
||||
flash_write_data_to_file(tf, p, tag_len);
|
||||
if (apdu.cmd_apdu_data_len > 0) {
|
||||
initialize_flash(true);
|
||||
scan_flash();
|
||||
dkeks = current_dkeks = 0;
|
||||
const uint8_t *p = apdu.cmd_apdu_data;
|
||||
while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) {
|
||||
uint8_t tag = *p++;
|
||||
uint8_t tag_len = *p++;
|
||||
if (tag == 0x80) { //options
|
||||
}
|
||||
if (file_retries_pin1 && file_retries_pin1->data) {
|
||||
flash_write_data_to_file(file_retries_pin1, p, tag_len);
|
||||
else if (tag == 0x81) { //user pin
|
||||
if (file_pin1 && file_pin1->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
}
|
||||
else if (tag == 0x82) { //sopin pin
|
||||
if (file_sopin && file_sopin->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = tag_len;
|
||||
double_hash_pin(p, tag_len, dhash+1);
|
||||
flash_write_data_to_file(file_sopin, dhash, sizeof(dhash));
|
||||
hash_multi(p, tag_len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
}
|
||||
else if (tag == 0x91) { //retries user pin
|
||||
file_t *tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
|
||||
if (tf && tf->data) {
|
||||
flash_write_data_to_file(tf, p, tag_len);
|
||||
}
|
||||
if (file_retries_pin1 && file_retries_pin1->data) {
|
||||
flash_write_data_to_file(file_retries_pin1, p, tag_len);
|
||||
}
|
||||
}
|
||||
else if (tag == 0x92) {
|
||||
dkeks = *p;
|
||||
}
|
||||
p += tag_len;
|
||||
}
|
||||
else if (tag == 0x92) {
|
||||
dkeks = *p;
|
||||
current_dkeks = 0;
|
||||
if (dkeks == 0) {
|
||||
int r = save_dkek_key(random_bytes_get(32));
|
||||
if (r != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
p += tag_len;
|
||||
else
|
||||
init_dkek();
|
||||
}
|
||||
p = random_bytes_get(32);
|
||||
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||
memcpy(tmp_dkek, p, IV_SIZE);
|
||||
if (dkeks == 0) {
|
||||
p = random_bytes_get(32);
|
||||
memcpy(tmp_dkek+IV_SIZE, p, 32);
|
||||
encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32);
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek));
|
||||
else { //free memory bytes request
|
||||
int heap_left = heapLeft();
|
||||
res_APDU[0] = ((heap_left >> 24) & 0xff);
|
||||
res_APDU[1] = ((heap_left >> 16) & 0xff);
|
||||
res_APDU[2] = ((heap_left >> 8) & 0xff);
|
||||
res_APDU[3] = ((heap_left >> 0) & 0xff);
|
||||
res_APDU[4] = 0;
|
||||
res_APDU[5] = HSM_VERSION_MAJOR;
|
||||
res_APDU[6] = HSM_VERSION_MINOR;
|
||||
res_APDU_size = 7;
|
||||
}
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
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_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 hash(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);
|
||||
}
|
||||
|
||||
static int cmd_import_dkek() {
|
||||
if (dkeks == 0)
|
||||
return SW_COMMAND_NOT_ALLOWED();
|
||||
if (has_session_pin == false)
|
||||
//if (dkeks == 0)
|
||||
// return SW_COMMAND_NOT_ALLOWED();
|
||||
if (P1(apdu) != 0x0 || P2(apdu) != 0x0)
|
||||
return SW_INCORRECT_P1P2();
|
||||
if (has_session_pin == false && apdu.cmd_apdu_data_len > 0)
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
if (!authenticate_action(get_parent(tf), ACL_OP_CREATE_EF)) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
if (apdu.cmd_apdu_data_len > 0) {
|
||||
for (int i = 0; i < apdu.cmd_apdu_data_len; i++)
|
||||
tmp_dkek[IV_SIZE+i] ^= apdu.cmd_apdu_data[i];
|
||||
if (apdu.cmd_apdu_data_len < 32)
|
||||
return SW_WRONG_LENGTH();
|
||||
import_dkek_share(apdu.cmd_apdu_data);
|
||||
if (++current_dkeks == dkeks) {
|
||||
encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32);
|
||||
flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek));
|
||||
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||
low_flash_available();
|
||||
if (save_dkek_key(NULL) != HSM_OK)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
|
||||
}
|
||||
}
|
||||
res_APDU[0] = dkeks;
|
||||
res_APDU[1] = dkeks-current_dkeks;
|
||||
//FNV hash
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
memcpy(tmp_dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
|
||||
decrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
hash ^= tmp_dkek[IV_SIZE+i];
|
||||
hash *= 0x00000100000001B3;
|
||||
}
|
||||
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||
memcpy(res_APDU+2,&hash,sizeof(hash));
|
||||
res_APDU_size = 2+sizeof(hash);
|
||||
dkek_kcv(res_APDU+2);
|
||||
res_APDU_size = 2+8;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
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 }
|
||||
};
|
||||
|
||||
//Stores the private and public keys in flash
|
||||
int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
|
||||
int r, key_size;
|
||||
uint8_t *asn1bin, *kdata;
|
||||
uint8_t *asn1bin = NULL;
|
||||
size_t asn1len = 0;
|
||||
uint8_t kdata[4096/8]; //worst case
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||
key_size = mbedtls_mpi_size(&rsa->P)+mbedtls_mpi_size(&rsa->Q);
|
||||
kdata = (uint8_t *)calloc(1, key_size);
|
||||
mbedtls_mpi_write_binary(&rsa->P, kdata, key_size/2);
|
||||
mbedtls_mpi_write_binary(&rsa->Q, kdata+key_size/2, key_size/2);
|
||||
}
|
||||
else {
|
||||
else if (type == SC_PKCS15_TYPE_PRKEY_EC) {
|
||||
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||
key_size = mbedtls_mpi_size(&ecdsa->d);
|
||||
kdata = (uint8_t *)calloc(1, key_size+1);
|
||||
kdata[0] = ecdsa->grp.id & 0xff;
|
||||
mbedtls_mpi_write_binary(&ecdsa->d, kdata+1, key_size);
|
||||
key_size++;
|
||||
}
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
else if (type & HSM_KEY_AES) {
|
||||
if (type == HSM_KEY_AES_128)
|
||||
key_size = 16;
|
||||
else if (type == HSM_KEY_AES_192)
|
||||
key_size = 24;
|
||||
else if (type == HSM_KEY_AES_256)
|
||||
key_size = 32;
|
||||
memcpy(kdata, key_ctx, key_size);
|
||||
}
|
||||
r = dkek_encrypt(kdata, key_size);
|
||||
if (r != HSM_OK) {
|
||||
return r;
|
||||
if ((r = encrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size)) != 0)
|
||||
return r;
|
||||
release_dkek();
|
||||
}
|
||||
file_t *fpk = file_new((KEY_PREFIX << 8) | key_id);
|
||||
if (!fpk)
|
||||
return SW_MEMORY_FAILURE();
|
||||
r = flash_write_data_to_file(fpk, kdata, key_size);
|
||||
free(kdata);
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
//add_file_to_chain(fpk, &ef_kf);
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC) {
|
||||
struct sc_pkcs15_object *p15o = (struct sc_pkcs15_object *)calloc(1,sizeof (struct sc_pkcs15_object));
|
||||
|
||||
struct sc_pkcs15_object *p15o = (struct sc_pkcs15_object *)calloc(1,sizeof (struct sc_pkcs15_object));
|
||||
sc_pkcs15_prkey_info_t *prkd = (sc_pkcs15_prkey_info_t *)calloc(1, sizeof (sc_pkcs15_prkey_info_t));
|
||||
memset(prkd, 0, sizeof(sc_pkcs15_prkey_info_t));
|
||||
prkd->id.len = 1;
|
||||
prkd->id.value[0] = key_id;
|
||||
prkd->usage = SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_UNWRAP;
|
||||
prkd->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
||||
prkd->native = 1;
|
||||
prkd->key_reference = key_id;
|
||||
prkd->path.value[0] = PRKD_PREFIX;
|
||||
prkd->path.value[1] = key_id;
|
||||
prkd->path.len = 2;
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA)
|
||||
prkd->modulus_length = key_size;
|
||||
else
|
||||
prkd->field_length = key_size-1; //contains 1 byte for the grp id
|
||||
|
||||
p15o->data = prkd;
|
||||
p15o->type = SC_PKCS15_TYPE_PRKEY | (type & 0xff);
|
||||
|
||||
r = sc_pkcs15_encode_prkdf_entry(ctx, p15o, &asn1bin, &asn1len);
|
||||
free(prkd);
|
||||
//sc_asn1_print_tags(asn1bin, asn1len);
|
||||
}
|
||||
|
||||
sc_pkcs15_prkey_info_t *prkd = (sc_pkcs15_prkey_info_t *)calloc(1, sizeof (sc_pkcs15_prkey_info_t));
|
||||
memset(prkd, 0, sizeof(sc_pkcs15_prkey_info_t));
|
||||
prkd->id.len = 1;
|
||||
prkd->id.value[0] = key_id;
|
||||
prkd->usage = SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_UNWRAP;
|
||||
prkd->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
||||
prkd->native = 1;
|
||||
prkd->key_reference = key_id;
|
||||
prkd->path.value[0] = PRKD_PREFIX;
|
||||
prkd->path.value[1] = key_id;
|
||||
prkd->path.len = 2;
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA)
|
||||
prkd->modulus_length = key_size;
|
||||
else
|
||||
prkd->field_length = key_size-1; //contains 1 byte for the grp id
|
||||
|
||||
p15o->data = prkd;
|
||||
p15o->type = SC_PKCS15_TYPE_PRKEY | (type & 0xff);
|
||||
|
||||
r = sc_pkcs15_encode_prkdf_entry(ctx, p15o, &asn1bin, &asn1len);
|
||||
free(prkd);
|
||||
//sc_asn1_print_tags(asn1bin, asn1len);
|
||||
fpk = file_new((PRKD_PREFIX << 8) | key_id);
|
||||
r = flash_write_data_to_file(fpk, asn1bin, asn1len);
|
||||
free(asn1bin);
|
||||
if (asn1bin)
|
||||
free(asn1bin);
|
||||
if (r != HSM_OK)
|
||||
return r;
|
||||
//add_file_to_chain(fpk, &ef_prkdf);
|
||||
@@ -711,53 +697,6 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
sc_context_t *create_context() {
|
||||
sc_context_t *ctx;
|
||||
sc_context_param_t ctx_opts;
|
||||
memset(&ctx_opts, 0, sizeof(sc_context_param_t));
|
||||
ctx_opts.ver = 0;
|
||||
ctx_opts.app_name = "hsm2040";
|
||||
sc_context_create(&ctx, &ctx_opts);
|
||||
ctx->debug = 0;
|
||||
sc_ctx_log_to_file(ctx, "stdout");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void cvc_init_common(sc_cvc_t *cvc, sc_context_t *ctx) {
|
||||
memset(cvc, 0, sizeof(sc_cvc_t));
|
||||
|
||||
size_t lencar = 0, lenchr = 0;
|
||||
const unsigned char *car = sc_asn1_find_tag(ctx, (const uint8_t *)apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, 0x42, &lencar);
|
||||
const unsigned char *chr = sc_asn1_find_tag(ctx, (const uint8_t *)apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, 0x5f20, &lenchr);
|
||||
if (car && lencar > 0)
|
||||
strlcpy(cvc->car, car, MIN(lencar,sizeof(cvc->car)));
|
||||
else
|
||||
strlcpy(cvc->car, "UTCA00001", sizeof(cvc->car));
|
||||
if (chr && lenchr > 0)
|
||||
strlcpy(cvc->chr, chr, MIN(lenchr, sizeof(cvc->chr)));
|
||||
else
|
||||
strlcpy(cvc->chr, "ESHSMCVCA00001", sizeof(cvc->chr));
|
||||
strlcpy(cvc->outer_car, "ESHSM00001", sizeof(cvc->outer_car));
|
||||
}
|
||||
|
||||
int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_len, uint8_t *hsh) {
|
||||
uint8_t *cvcbin;
|
||||
size_t cvclen;
|
||||
cvc->signatureLen = sig_len;
|
||||
cvc->signature = (uint8_t *)calloc(1, sig_len);
|
||||
cvc->outerSignatureLen = 4;
|
||||
cvc->outerSignature = (uint8_t *)calloc(1, sig_len);
|
||||
int r = sc_pkcs15emu_sc_hsm_encode_cvc(p15card, cvc, &cvcbin, &cvclen);
|
||||
if (r != SC_SUCCESS) {
|
||||
if (cvcbin)
|
||||
free(cvcbin);
|
||||
return r;
|
||||
}
|
||||
hash(cvcbin, cvclen, hsh);
|
||||
free(cvcbin);
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
static int cmd_keypair_gen() {
|
||||
uint8_t key_id = P1(apdu);
|
||||
uint8_t auth_key_id = P2(apdu);
|
||||
@@ -850,13 +789,7 @@ static int cmd_keypair_gen() {
|
||||
else if (memcmp(oid, "\x4\x0\x7F\x0\x7\x2\x2\x2\x2\x3",MIN(oid_len,10)) == 0) { //ECC
|
||||
size_t prime_len;
|
||||
const uint8_t *prime = sc_asn1_find_tag(ctx, p, tout, 0x81, &prime_len);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_NONE;
|
||||
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) {
|
||||
ec_id = ec->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(prime, prime_len);
|
||||
printf("KEYPAIR ECC %d\r\n",ec_id);
|
||||
if (ec_id == MBEDTLS_ECP_DP_NONE) {
|
||||
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
||||
@@ -1083,9 +1016,9 @@ static int cmd_update_ef() {
|
||||
if (!ef->data)
|
||||
return SW_DATA_INVALID();
|
||||
uint8_t *data_merge = (uint8_t *)calloc(1, offset+data_len);
|
||||
memcpy(data_merge, file_read(ef->data), offset);
|
||||
memcpy(data_merge, file_read(ef->data+2), offset);
|
||||
memcpy(data_merge+offset, data, data_len);
|
||||
int r = flash_write_data_to_file(ef, data_merge, data_len);
|
||||
int r = flash_write_data_to_file(ef, data_merge, offset+data_len);
|
||||
free(data_merge);
|
||||
if (r != HSM_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
@@ -1138,10 +1071,8 @@ static int cmd_change_pin() {
|
||||
//encrypt DKEK with new pin
|
||||
hash_multi(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, session_pin);
|
||||
has_session_pin = true;
|
||||
encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32);
|
||||
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||
flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek));
|
||||
release_dkek();
|
||||
if (store_dkek_key() != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = apdu.cmd_apdu_data_len-pin_len;
|
||||
double_hash_pin(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, dhash+1);
|
||||
@@ -1168,21 +1099,16 @@ static int cmd_key_gen() {
|
||||
//at this moment, we do not use the template, as only CBC is supported by the driver (encrypt, decrypt and CMAC)
|
||||
uint8_t aes_key[32]; //maximum AES key size
|
||||
memcpy(aes_key, random_bytes_get(key_size), key_size);
|
||||
if ((r = load_dkek()) != HSM_OK)
|
||||
return SW_EXEC_ERROR() ;
|
||||
if ((r = encrypt(tmp_dkek+IV_SIZE, tmp_dkek, aes_key, key_size)) != 0)
|
||||
return SW_EXEC_ERROR() ;
|
||||
release_dkek();
|
||||
file_t *fpk = file_new((KEY_PREFIX << 8) | key_id);
|
||||
if (!fpk)
|
||||
return SW_MEMORY_FAILURE();
|
||||
r = flash_write_data_to_file(fpk, aes_key, key_size);
|
||||
if (r != HSM_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
fpk = file_new((PRKD_PREFIX << 8) | key_id);
|
||||
if (!fpk)
|
||||
return SW_MEMORY_FAILURE();
|
||||
r = flash_write_data_to_file(fpk, NULL, 0);
|
||||
int aes_type = 0x0;
|
||||
if (key_size == 16)
|
||||
aes_type = HSM_KEY_AES_128;
|
||||
else if (key_size == 24)
|
||||
aes_type = HSM_KEY_AES_192;
|
||||
else if (key_size == 32)
|
||||
aes_type = HSM_KEY_AES_256;
|
||||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(aes_key, aes_type, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
if (r != HSM_OK)
|
||||
return SW_MEMORY_FAILURE();
|
||||
low_flash_available();
|
||||
@@ -1191,26 +1117,19 @@ static int cmd_key_gen() {
|
||||
|
||||
int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) {
|
||||
int key_size = file_read_uint16(fkey->data);
|
||||
if (load_dkek() != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
uint8_t *kdata = (uint8_t *)calloc(1,key_size);
|
||||
uint8_t kdata[4096/8];
|
||||
memcpy(kdata, file_read(fkey->data+2), key_size);
|
||||
if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) {
|
||||
free(kdata);
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
release_dkek();
|
||||
if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size/2) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
free(kdata);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&ctx->Q, kdata+key_size/2, key_size/2) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
free(kdata);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
free(kdata);
|
||||
if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
@@ -1232,23 +1151,17 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) {
|
||||
|
||||
int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
|
||||
int key_size = file_read_uint16(fkey->data);
|
||||
if (load_dkek() != HSM_OK)
|
||||
return HSM_EXEC_ERROR;
|
||||
uint8_t *kdata = (uint8_t *)calloc(1,key_size);
|
||||
uint8_t kdata[67]; //Worst case, 521 bit + 1byte
|
||||
memcpy(kdata, file_read(fkey->data+2), key_size);
|
||||
if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) {
|
||||
free(kdata);
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
release_dkek();
|
||||
mbedtls_ecp_group_id gid = kdata[0];
|
||||
int r = mbedtls_ecp_read_key(gid, ctx, kdata+1, key_size-1);
|
||||
if (r != 0) {
|
||||
free(kdata);
|
||||
mbedtls_ecdsa_free(ctx);
|
||||
return HSM_EXEC_ERROR;
|
||||
}
|
||||
free(kdata);
|
||||
return HSM_OK;
|
||||
}
|
||||
|
||||
@@ -1392,7 +1305,7 @@ static int cmd_signature() {
|
||||
}
|
||||
|
||||
static int cmd_key_wrap() {
|
||||
int key_id = P1(apdu);
|
||||
int key_id = P1(apdu), r = 0, key_type = 0x0;
|
||||
if (P2(apdu) != 0x92)
|
||||
return SW_WRONG_P1P2();
|
||||
if (!isUserAuthenticated)
|
||||
@@ -1400,23 +1313,115 @@ static int cmd_key_wrap() {
|
||||
file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id);
|
||||
if (!ef)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
int key_len = file_read_uint16(ef->data);
|
||||
memcpy(res_APDU, file_read(ef->data+2), key_len);
|
||||
res_APDU_size = key_len;
|
||||
file_t *prkd = search_dynamic_file((PRKD_PREFIX << 8) | key_id);
|
||||
if (!prkd)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
const uint8_t *dprkd = file_read(prkd->data+2);
|
||||
size_t wrap_len = MAX_DKEK_ENCODE_KEY_BUFFER;
|
||||
if (*dprkd == P15_KEYTYPE_RSA) {
|
||||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
r = load_private_key_rsa(&ctx, ef);
|
||||
if (r != HSM_OK) {
|
||||
mbedtls_rsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
r = dkek_encode_key(&ctx, HSM_KEY_RSA, res_APDU, &wrap_len);
|
||||
mbedtls_rsa_free(&ctx);
|
||||
}
|
||||
else if (*dprkd == P15_KEYTYPE_ECC) {
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
r = load_private_key_ecdsa(&ctx, ef);
|
||||
if (r != HSM_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
r = dkek_encode_key(&ctx, HSM_KEY_EC, res_APDU, &wrap_len);
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
}
|
||||
else if (*dprkd == P15_KEYTYPE_AES) {
|
||||
uint8_t kdata[32]; //maximum AES key size
|
||||
int key_size = file_read_uint16(ef->data), aes_type = HSM_KEY_AES;
|
||||
memcpy(kdata, file_read(ef->data+2), key_size);
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
if (key_size == 32)
|
||||
aes_type = HSM_KEY_AES_256;
|
||||
else if (key_size == 24)
|
||||
aes_type = HSM_KEY_AES_192;
|
||||
else if (key_size == 16)
|
||||
aes_type = HSM_KEY_AES_128;
|
||||
r = dkek_encode_key(kdata, aes_type, res_APDU, &wrap_len);
|
||||
}
|
||||
if (r != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
res_APDU_size = wrap_len;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
static int cmd_key_unwrap() {
|
||||
int key_id = P1(apdu);
|
||||
int key_id = P1(apdu), r = 0;
|
||||
if (P2(apdu) != 0x93)
|
||||
return SW_WRONG_P1P2();
|
||||
if (!isUserAuthenticated)
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id);
|
||||
if (!ef)
|
||||
ef = file_new((KEY_PREFIX << 8) | key_id);
|
||||
flash_write_data_to_file(ef, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
||||
low_flash_available();
|
||||
int key_type = dkek_type_key(apdu.cmd_apdu_data);
|
||||
if (key_type == 0x0)
|
||||
return SW_DATA_INVALID();
|
||||
if (key_type == HSM_KEY_RSA) {
|
||||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
|
||||
if (r != HSM_OK) {
|
||||
mbedtls_rsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_RSA, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
mbedtls_rsa_free(&ctx);
|
||||
if (r != HSM_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
else if (key_type == HSM_KEY_EC) {
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
|
||||
if (r != HSM_OK) {
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
if (r != HSM_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
else if (key_type == HSM_KEY_AES) {
|
||||
uint8_t aes_key[32];
|
||||
int key_size = 0, aes_type;
|
||||
r = dkek_decode_key(aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size);
|
||||
if (r != HSM_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
if (key_size == 32)
|
||||
aes_type = HSM_KEY_AES_256;
|
||||
else if (key_size == 24)
|
||||
aes_type = HSM_KEY_AES_192;
|
||||
else if (key_size == 16)
|
||||
aes_type = HSM_KEY_AES_128;
|
||||
sc_context_t *card_ctx = create_context();
|
||||
r = store_keys(aes_key, aes_type, key_id, card_ctx);
|
||||
free(card_ctx);
|
||||
if (r != HSM_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
@@ -1447,15 +1452,12 @@ static int cmd_decrypt_asym() {
|
||||
else if (P2(apdu) == ALGO_EC_DH) {
|
||||
mbedtls_ecdh_context ctx;
|
||||
int key_size = file_read_uint16(ef->data);
|
||||
if (load_dkek() != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
uint8_t *kdata = (uint8_t *)calloc(1,key_size);
|
||||
memcpy(kdata, file_read(ef->data+2), key_size);
|
||||
if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) {
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
free(kdata);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
release_dkek();
|
||||
mbedtls_ecdh_init(&ctx);
|
||||
mbedtls_ecp_group_id gid = kdata[0];
|
||||
int r = 0;
|
||||
@@ -1504,14 +1506,11 @@ static int cmd_cipher_sym() {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
int key_size = file_read_uint16(ef->data);
|
||||
if (load_dkek() != HSM_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
uint8_t kdata[32]; //maximum AES key size
|
||||
memcpy(kdata, file_read(ef->data+2), key_size);
|
||||
if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) {
|
||||
if (dkek_decrypt(kdata, key_size) != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
release_dkek();
|
||||
if (algo == ALGO_AES_CBC_ENCRYPT || algo == ALGO_AES_CBC_DECRYPT) {
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
@@ -1557,7 +1556,7 @@ static int cmd_cipher_sym() {
|
||||
int r = mbedtls_cipher_cmac(cipher_info, kdata, key_size*8, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU);
|
||||
if (r != 0)
|
||||
return SW_EXEC_ERROR();
|
||||
res_APDU_size = apdu.cmd_apdu_data_len;
|
||||
res_APDU_size = 16;
|
||||
}
|
||||
else if (algo == ALGO_AES_DERIVE) {
|
||||
int r = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, file_read(ef->data+2), key_size, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, apdu.cmd_apdu_data_len);
|
||||
|
||||
@@ -60,6 +60,11 @@ extern const uint8_t sc_hsm_aid[];
|
||||
#define HSM_ERR_BLOCKED -1004
|
||||
#define HSM_NO_LOGIN -1005
|
||||
#define HSM_EXEC_ERROR -1006
|
||||
#define HSM_WRONG_LENGTH -1007
|
||||
#define HSM_WRONG_DATA -1008
|
||||
#define HSM_WRONG_DKEK -1009
|
||||
#define HSM_WRONG_SIGNATURE -1010
|
||||
#define HSM_WRONG_PADDING -1011
|
||||
|
||||
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
|
||||
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
|
||||
@@ -84,6 +89,18 @@ extern const uint8_t sc_hsm_aid[];
|
||||
#define ALGO_AES_CMAC 0x18
|
||||
#define ALGO_AES_DERIVE 0x99
|
||||
|
||||
#define HSM_OPT_RRC 0x1
|
||||
#define HSM_OPT_TRANSPORT_PIN 0x2
|
||||
#define HSM_OPT_SESSION_PIN 0x4
|
||||
#define HSM_OPT_SESSION_PIN_EXPL 0xC
|
||||
#define HSM_OPT_REPLACE_PKA 0x8
|
||||
#define HSM_OPT_COMBINED_AUTH 0x10
|
||||
#define HSM_OPT_RRC_RESET_ONLY 0x20
|
||||
|
||||
#define P15_KEYTYPE_RSA 0x30
|
||||
#define P15_KEYTYPE_ECC 0xA0
|
||||
#define P15_KEYTYPE_AES 0xA8
|
||||
|
||||
extern int pin_reset_retries(const file_t *pin, bool);
|
||||
extern int pin_wrong_retry(const file_t *pin);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define HSM_VERSION 0x0104
|
||||
#define HSM_VERSION 0x0108
|
||||
|
||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
void random_init (void);
|
||||
void random_fini (void);
|
||||
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2015 Frank Morgner
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
#ifndef _CCID_TYPES_H
|
||||
#define _CCID_TYPES_H
|
||||
|
||||
#include "pico/types.h"
|
||||
#include "hardware/structs/usb.h"
|
||||
|
||||
#define USB_REQ_CCID 0xA1
|
||||
|
||||
#define CCID_CONTROL_ABORT 0x01
|
||||
#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define CCID_CONTROL_GET_DATA_RATES 0x03
|
||||
|
||||
#define CCID_OPERATION_VERIFY 0x00;
|
||||
#define CCID_OPERATION_MODIFY 0x01;
|
||||
#define CCID_ENTRY_VALIDATE 0x02
|
||||
|
||||
#define CCID_BERROR_CMD_ABORTED 0xff /** Host aborted the current activity */
|
||||
#define CCID_BERROR_ICC_MUTE 0xfe /** CCID timed out while talking to the ICC */
|
||||
#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /** Parity error while talking to the ICC */
|
||||
#define CCID_BERROR_XFR_OVERRUN 0xfc /** Overrun error while talking to the ICC */
|
||||
#define CCID_BERROR_HW_ERROR 0xfb /** An all inclusive hardware error occurred */
|
||||
#define CCID_BERROR_BAD_ATR_TS 0xf
|
||||
#define CCID_BERROR_BAD_ATR_TCK 0xf
|
||||
#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6
|
||||
#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5
|
||||
#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4
|
||||
#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3
|
||||
#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /** Automatic Sequence Ongoing */
|
||||
#define CCID_BERROR_PIN_TIMEOUT 0xf0
|
||||
#define CCID_BERROR_PIN_CANCELLED 0xef
|
||||
#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /** A second command was sent to a slot which was already processing a command. */
|
||||
#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00
|
||||
#define CCID_BERROR_OK 0x00
|
||||
|
||||
#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */
|
||||
#define CCID_BSTATUS_OK_INACTIVE 0x01 /** No error. ICC is present and inactive */
|
||||
#define CCID_BSTATUS_OK_NOICC 0x02 /** No error. No ICC is present */
|
||||
#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /** Failed. An ICC is present and active */
|
||||
#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /** Failed. ICC is present and inactive */
|
||||
#define CCID_BSTATUS_ERROR_NOICC 0x42 /** Failed. No ICC is present */
|
||||
|
||||
#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /** APDU begins and ends with this command */
|
||||
#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /** APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */
|
||||
#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /** abData field continues a command APDU and ends the APDU command */
|
||||
#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /** abData field continues a command APDU and another block is to follow */
|
||||
#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /** empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */
|
||||
|
||||
#define CCID_PIN_ENCODING_BIN 0x00
|
||||
#define CCID_PIN_ENCODING_BCD 0x01
|
||||
#define CCID_PIN_ENCODING_ASCII 0x02
|
||||
#define CCID_PIN_UNITS_BYTES 0x80
|
||||
#define CCID_PIN_JUSTIFY_RIGHT 0x04
|
||||
#define CCID_PIN_CONFIRM_NEW 0x01
|
||||
#define CCID_PIN_INSERT_OLD 0x02
|
||||
#define CCID_PIN_NO_MSG 0x00
|
||||
#define CCID_PIN_MSG1 0x01
|
||||
#define CCID_PIN_MSG2 0x02
|
||||
#define CCID_PIN_MSG_REF 0x03
|
||||
#define CCID_PIN_MSG_DEFAULT 0xff
|
||||
|
||||
#define CCID_SLOTS_UNCHANGED 0x00
|
||||
#define CCID_SLOT1_CARD_PRESENT 0x01
|
||||
#define CCID_SLOT1_CHANGED 0x02
|
||||
#define CCID_SLOT2_CARD_PRESENT 0x04
|
||||
#define CCID_SLOT2_CHANGED 0x08
|
||||
#define CCID_SLOT3_CARD_PRESENT 0x10
|
||||
#define CCID_SLOT3_CHANGED 0x20
|
||||
#define CCID_SLOT4_CARD_PRESENT 0x40
|
||||
#define CCID_SLOT4_CHANGED 0x80
|
||||
|
||||
#define CCID_EXT_APDU_MAX (4 + 3 + 0xffff + 3)
|
||||
#define CCID_SHORT_APDU_MAX (4 + 1 + 0xff + 1)
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdCCID;
|
||||
uint8_t bMaxSlotIndex;
|
||||
uint8_t bVoltageSupport;
|
||||
uint32_t dwProtocols;
|
||||
uint32_t dwDefaultClock;
|
||||
uint32_t dwMaximumClock;
|
||||
uint8_t bNumClockSupport;
|
||||
uint32_t dwDataRate;
|
||||
uint32_t dwMaxDataRate;
|
||||
uint8_t bNumDataRatesSupported;
|
||||
uint32_t dwMaxIFSD;
|
||||
uint32_t dwSynchProtocols;
|
||||
uint32_t dwMechanical;
|
||||
uint32_t dwFeatures;
|
||||
uint32_t dwMaxCCIDMessageLength;
|
||||
uint8_t bClassGetResponse;
|
||||
uint8_t bclassEnvelope;
|
||||
uint16_t wLcdLayout;
|
||||
uint8_t bPINSupport;
|
||||
uint8_t bMaxCCIDBusySlots;
|
||||
} class_desc_ccid_t;
|
||||
|
||||
struct abProtocolDataStructure_T0 {
|
||||
uint8_t bmFindexDindex;
|
||||
uint8_t bmTCCKST0;
|
||||
uint8_t bGuardTimeT0;
|
||||
uint8_t bWaitingIntegerT0;
|
||||
uint8_t bClockStop;
|
||||
} __packed;
|
||||
|
||||
struct abProtocolDataStructure_T1 {
|
||||
uint8_t bmFindexDindex;
|
||||
uint8_t bmTCCKST1;
|
||||
uint8_t bGuardTimeT1;
|
||||
uint8_t bWaitingIntegersT1;
|
||||
uint8_t bClockStop;
|
||||
uint8_t bIFSC;
|
||||
uint8_t bNadValue;
|
||||
} __packed;
|
||||
|
||||
struct abPINDataStucture_Verification {
|
||||
uint8_t bTimeOut;
|
||||
uint8_t bmFormatString;
|
||||
uint8_t bmPINBlockString;
|
||||
uint8_t bmPINLengthFormat;
|
||||
uint16_t wPINMaxExtraDigit;
|
||||
uint8_t bEntryValidationCondition;
|
||||
uint8_t bNumberMessage;
|
||||
uint16_t wLangId;
|
||||
uint8_t bMsgIndex;
|
||||
uint8_t bTeoPrologue1;
|
||||
uint16_t bTeoPrologue2;
|
||||
} __packed;
|
||||
|
||||
struct abPINDataStucture_Modification {
|
||||
uint8_t bTimeOut;
|
||||
uint8_t bmFormatString;
|
||||
uint8_t bmPINBlockString;
|
||||
uint8_t bmPINLengthFormat;
|
||||
uint8_t bInsertionOffsetOld;
|
||||
uint8_t bInsertionOffsetNew;
|
||||
uint16_t wPINMaxExtraDigit;
|
||||
uint8_t bConfirmPIN;
|
||||
uint8_t bEntryValidationCondition;
|
||||
uint8_t bNumberMessage;
|
||||
uint16_t wLangId;
|
||||
uint8_t bMsgIndex1;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_XfrBlock {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bBWI;
|
||||
uint16_t wLevelParameter;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_IccPowerOff {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t abRFU1;
|
||||
uint16_t abRFU2;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_GetSlotStatus {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t abRFU1;
|
||||
uint16_t abRFU2;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_GetParameters {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t abRFU1;
|
||||
uint16_t abRFU2;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_ResetParameters {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t abRFU1;
|
||||
uint16_t abRFU2;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_SetParameters {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bProtocolNum;
|
||||
uint16_t abRFU;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_Secure {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bBWI;
|
||||
uint16_t wLevelParameter;
|
||||
} __packed;
|
||||
|
||||
struct PC_to_RDR_IccPowerOn {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bPowerSelect;
|
||||
uint16_t abRFU;
|
||||
} __packed;
|
||||
|
||||
struct RDR_to_PC_SlotStatus {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bStatus;
|
||||
uint8_t bError;
|
||||
uint8_t bClockStatus;
|
||||
} __packed;
|
||||
|
||||
struct RDR_to_PC_DataBlock {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bStatus;
|
||||
uint8_t bError;
|
||||
uint8_t bChainParameter;
|
||||
} __packed;
|
||||
|
||||
struct RDR_to_PC_Parameters {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
uint8_t bStatus;
|
||||
uint8_t bError;
|
||||
uint8_t bProtocolNum;
|
||||
} __packed;
|
||||
|
||||
struct RDR_to_PC_NotifySlotChange {
|
||||
uint8_t bMessageType;
|
||||
uint8_t bmSlotICCState; /* we support 1 slots, so we need 2*1 bits = 1 byte */
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user