Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d41a488eda | ||
|
|
375a18ebac | ||
|
|
20216ac4ba | ||
|
|
d27d8b0c5b | ||
|
|
a619527482 | ||
|
|
85ff92c4de | ||
|
|
b1121718db | ||
|
|
2905dcc8c0 | ||
|
|
c9855f7214 | ||
|
|
853b8f29a2 | ||
|
|
d5378ffa41 | ||
|
|
4400eba974 | ||
|
|
0cc656c6c0 | ||
|
|
c9b32ab5d0 | ||
|
|
f9ffd39661 | ||
|
|
bfc12d6856 | ||
|
|
11874b52de | ||
|
|
33a2222cd8 | ||
|
|
923e05a36c | ||
|
|
ad66170379 | ||
|
|
86e38419ac |
@@ -51,7 +51,7 @@ target_sources(pico_hsm PUBLIC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
|
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hash_utils.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
|
||||||
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
||||||
@@ -119,7 +119,7 @@ pico_add_extra_outputs(pico_hsm)
|
|||||||
|
|
||||||
#target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
|
#target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
|
||||||
|
|
||||||
target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id)
|
target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)
|
||||||
|
|
||||||
#
|
#
|
||||||
#project(flash_nuke C CXX ASM)
|
#project(flash_nuke C CXX ASM)
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -23,10 +23,12 @@ This is a project to create a Hardware Security Module (HSM) with a Raspberry Pi
|
|||||||
- DKEK n-of-m threshold scheme.
|
- DKEK n-of-m threshold scheme.
|
||||||
- USB/CCID support with OpenSC, openssl, etc.
|
- USB/CCID support with OpenSC, openssl, etc.
|
||||||
- Extended APDU support.
|
- Extended APDU support.
|
||||||
- Private keys and certificates import from WKY or PKCS#12 files.[^2]
|
- Private keys and certificates import from WKY or PKCS#12 files.[^2][^3]
|
||||||
|
- Transport PIN for provisioning and forcing to set a new PIN.[^2]
|
||||||
|
|
||||||
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
|
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
|
||||||
[^2]: 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.
|
[^2]: Available via SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
|
||||||
|
[^3]: Imports are available only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process.
|
||||||
|
|
||||||
## Security considerations
|
## 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 and only during the process. All keys (including DKEK) are loaded and cleared every time to avoid potential security 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.
|
||||||
@@ -82,7 +84,7 @@ 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 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).
|
For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096.md).
|
||||||
|
|
||||||
## Key generation time
|
## Key generation time
|
||||||
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `2048` and `4096` bits.
|
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `2048` and `4096` bits.
|
||||||
@@ -104,7 +106,7 @@ The way to communicate is exactly the same as with other cards, such as OpenPGP
|
|||||||
|
|
||||||
For an advanced usage, see the docs and examples.
|
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.
|
Pico HSM also supports SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
|
||||||
|
|
||||||
### Important
|
### 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.
|
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,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
VERSION_MAJOR="1"
|
VERSION_MAJOR="1"
|
||||||
VERSION_MINOR="8"
|
VERSION_MINOR="10"
|
||||||
|
|
||||||
rm -rf release/*
|
rm -rf release/*
|
||||||
cd build_release
|
cd build_release
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
VERSION_MAJOR="1"
|
VERSION_MAJOR="1"
|
||||||
VERSION_MINOR="8"
|
VERSION_MINOR="0A"
|
||||||
|
|
||||||
echo "----------------------------"
|
echo "----------------------------"
|
||||||
echo "VID/PID patcher for Pico HSM"
|
echo "VID/PID patcher for Pico HSM"
|
||||||
|
|||||||
@@ -99,15 +99,16 @@ file_t file_entries[] = {
|
|||||||
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
||||||
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
||||||
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
||||||
/* 16 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
|
||||||
/* 17 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
||||||
/* 18 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
||||||
/* 19 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
||||||
/* 20 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
||||||
/* 21 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
||||||
///* 22 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
||||||
/* 23 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||||
/* 24 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
|
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||||
|
/* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
|
||||||
};
|
};
|
||||||
|
|
||||||
const file_t *MF = &file_entries[0];
|
const file_t *MF = &file_entries[0];
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#define EF_AODFS 0x6043
|
#define EF_AODFS 0x6043
|
||||||
#define EF_DODFS 0x6044
|
#define EF_DODFS 0x6044
|
||||||
#define EF_SKDFS 0x6045
|
#define EF_SKDFS 0x6045
|
||||||
|
#define EF_DEVOPS 0x100E
|
||||||
|
|
||||||
#define MAX_DEPTH 4
|
#define MAX_DEPTH 4
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "mbedtls/md.h"
|
#include "mbedtls/md.h"
|
||||||
#include "mbedtls/sha256.h"
|
#include "mbedtls/sha256.h"
|
||||||
#include "mbedtls/aes.h"
|
#include "mbedtls/aes.h"
|
||||||
#include "hash_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
#include "libopensc/card-sc-hsm.h"
|
#include "libopensc/card-sc-hsm.h"
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _HASH_UTILS_H_
|
#ifndef _CRYPTO_UTILS_H_
|
||||||
#define _HASH_UTILS_H_
|
#define _CRYPTO_UTILS_H_
|
||||||
|
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "dkek.h"
|
#include "dkek.h"
|
||||||
#include "hash_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
#include "mbedtls/md.h"
|
#include "mbedtls/md.h"
|
||||||
@@ -88,6 +88,7 @@ int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
|
|||||||
hash256(dkek+IV_SIZE, 32, hsh);
|
hash256(dkek+IV_SIZE, 32, hsh);
|
||||||
release_dkek();
|
release_dkek();
|
||||||
memcpy(kcv, hsh, 8);
|
memcpy(kcv, hsh, 8);
|
||||||
|
return HSM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
|
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "hsm2040.h"
|
#include "hsm2040.h"
|
||||||
|
#include "hardware/rtc.h"
|
||||||
|
|
||||||
extern void do_flash();
|
extern void do_flash();
|
||||||
extern void low_flash_init();
|
extern void low_flash_init();
|
||||||
@@ -1628,6 +1629,7 @@ int main(void)
|
|||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
led_off_all();
|
led_off_all();
|
||||||
|
|
||||||
@@ -1638,6 +1640,8 @@ int main(void)
|
|||||||
random_init();
|
random_init();
|
||||||
|
|
||||||
low_flash_init();
|
low_flash_init();
|
||||||
|
|
||||||
|
rtc_init();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|||||||
129
src/hsm/sc_hsm.c
129
src/hsm/sc_hsm.c
@@ -30,8 +30,9 @@
|
|||||||
#include "mbedtls/hkdf.h"
|
#include "mbedtls/hkdf.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "cvcerts.h"
|
#include "cvcerts.h"
|
||||||
#include "hash_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "dkek.h"
|
#include "dkek.h"
|
||||||
|
#include "hardware/rtc.h"
|
||||||
|
|
||||||
const uint8_t sc_hsm_aid[] = {
|
const uint8_t sc_hsm_aid[] = {
|
||||||
11,
|
11,
|
||||||
@@ -92,6 +93,14 @@ void select_file(file_t *pe) {
|
|||||||
//sc_hsm_unload(); //reset auth status
|
//sc_hsm_unload(); //reset auth status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t get_device_options() {
|
||||||
|
file_t *ef = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
||||||
|
if (ef && ef->data)
|
||||||
|
return (file_read_uint8(ef->data+2) << 8) | file_read_uint8(ef->data+3);
|
||||||
|
return 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
static int cmd_select() {
|
static int cmd_select() {
|
||||||
uint8_t p1 = P1(apdu);
|
uint8_t p1 = P1(apdu);
|
||||||
uint8_t p2 = P2(apdu);
|
uint8_t p2 = P2(apdu);
|
||||||
@@ -171,8 +180,9 @@ static int cmd_select() {
|
|||||||
if (pe == file_sc_hsm) {
|
if (pe == file_sc_hsm) {
|
||||||
res_APDU[res_APDU_size++] = 0x85;
|
res_APDU[res_APDU_size++] = 0x85;
|
||||||
res_APDU[res_APDU_size++] = 4;
|
res_APDU[res_APDU_size++] = 4;
|
||||||
res_APDU[res_APDU_size++] = 0xff; //options
|
uint16_t opts = get_device_options();
|
||||||
res_APDU[res_APDU_size++] = 0xff;
|
res_APDU[res_APDU_size++] = opts & 0xff;
|
||||||
|
res_APDU[res_APDU_size++] = opts >> 8;
|
||||||
res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR;
|
res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR;
|
||||||
res_APDU[res_APDU_size++] = HSM_VERSION_MINOR;
|
res_APDU[res_APDU_size++] = HSM_VERSION_MINOR;
|
||||||
res_APDU[1] = res_APDU_size-2;
|
res_APDU[1] = res_APDU_size-2;
|
||||||
@@ -400,11 +410,12 @@ int pin_wrong_retry(const file_t *pin) {
|
|||||||
|
|
||||||
int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
|
int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
|
||||||
if (!pin)
|
if (!pin)
|
||||||
return SW_FILE_NOT_FOUND();
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
if (!pin->data) {
|
if (!pin->data) {
|
||||||
return SW_REFERENCE_NOT_FOUND();
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
isUserAuthenticated = false;
|
isUserAuthenticated = false;
|
||||||
|
has_session_pin = has_session_sopin = false;
|
||||||
uint8_t dhash[32];
|
uint8_t dhash[32];
|
||||||
double_hash_pin(data, len, dhash);
|
double_hash_pin(data, len, dhash);
|
||||||
if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len
|
if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len
|
||||||
@@ -422,7 +433,10 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
|
|||||||
return SW_MEMORY_FAILURE();
|
return SW_MEMORY_FAILURE();
|
||||||
isUserAuthenticated = true;
|
isUserAuthenticated = true;
|
||||||
hash_multi(data, len, session_pin);
|
hash_multi(data, len, session_pin);
|
||||||
has_session_pin = true;
|
if (pin == file_pin1)
|
||||||
|
has_session_pin = true;
|
||||||
|
else if (pin == file_sopin)
|
||||||
|
has_session_sopin = true;
|
||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,46 +448,94 @@ static int cmd_verify() {
|
|||||||
return SW_WRONG_P1P2();
|
return SW_WRONG_P1P2();
|
||||||
uint8_t qualifier = p2&0x1f;
|
uint8_t qualifier = p2&0x1f;
|
||||||
if (p2 == 0x81) { //UserPin
|
if (p2 == 0x81) { //UserPin
|
||||||
|
uint16_t opts = get_device_options();
|
||||||
|
if (opts & HSM_OPT_TRANSPORT_PIN)
|
||||||
|
return SW_DATA_INVALID();
|
||||||
|
if (file_read_uint8(file_pin1->data+2) == 0) //not initialized
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
if (apdu.cmd_apdu_data_len > 0) {
|
if (apdu.cmd_apdu_data_len > 0) {
|
||||||
return check_pin(file_pin1, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
return check_pin(file_pin1, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
||||||
}
|
}
|
||||||
if (file_read_uint8(file_retries_pin1->data+2) == 0)
|
if (file_read_uint8(file_retries_pin1->data+2) == 0)
|
||||||
return SW_PIN_BLOCKED();
|
return SW_PIN_BLOCKED();
|
||||||
|
if (has_session_pin)
|
||||||
|
return SW_OK();
|
||||||
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_pin1->data+2));
|
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_pin1->data+2));
|
||||||
}
|
}
|
||||||
else if (p2 == 0x88) { //SOPin
|
else if (p2 == 0x88) { //SOPin
|
||||||
|
if (file_read_uint8(file_sopin->data+2) == 0) //not initialized
|
||||||
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
if (apdu.cmd_apdu_data_len > 0) {
|
if (apdu.cmd_apdu_data_len > 0) {
|
||||||
return check_pin(file_sopin, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
return check_pin(file_sopin, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
|
||||||
}
|
}
|
||||||
if (file_read_uint8(file_retries_sopin->data+2) == 0)
|
if (file_read_uint8(file_retries_sopin->data+2) == 0)
|
||||||
return SW_PIN_BLOCKED();
|
return SW_PIN_BLOCKED();
|
||||||
|
if (has_session_sopin)
|
||||||
|
return SW_OK();
|
||||||
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2));
|
return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2));
|
||||||
}
|
}
|
||||||
return SW_REFERENCE_NOT_FOUND();
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_reset_retry() {
|
static int cmd_reset_retry() {
|
||||||
if (P1(apdu) == 0x0) {
|
if (P2(apdu) != 0x81)
|
||||||
if (P2(apdu) == 0x81) {
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
if (!file_sopin || !file_pin1) {
|
if (!file_sopin || !file_pin1) {
|
||||||
return SW_FILE_NOT_FOUND();
|
return SW_FILE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
if (!file_sopin->data) {
|
if (!file_sopin->data) {
|
||||||
return SW_REFERENCE_NOT_FOUND();
|
return SW_REFERENCE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
|
uint16_t opts = get_device_options();
|
||||||
|
if (!(opts & HSM_OPT_RRC))
|
||||||
|
return SW_COMMAND_NOT_ALLOWED();
|
||||||
|
if (P1(apdu) == 0x0 || P1(apdu) == 0x2) {
|
||||||
|
int newpin_len = 0;
|
||||||
|
if (P1(apdu) == 0x0) {
|
||||||
|
if (apdu.cmd_apdu_data_len <= 8)
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
uint16_t r = check_pin(file_sopin, apdu.cmd_apdu_data, 8);
|
uint16_t r = check_pin(file_sopin, apdu.cmd_apdu_data, 8);
|
||||||
if (r != 0x9000)
|
if (r != 0x9000)
|
||||||
return r;
|
return r;
|
||||||
uint8_t dhash[33];
|
newpin_len = apdu.cmd_apdu_data_len-8;
|
||||||
dhash[0] = apdu.cmd_apdu_data_len-8;
|
|
||||||
double_hash_pin(apdu.cmd_apdu_data+8, apdu.cmd_apdu_data_len-8, dhash+1);
|
|
||||||
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
|
||||||
if (pin_reset_retries(file_pin1, true) != HSM_OK)
|
|
||||||
return SW_MEMORY_FAILURE();
|
|
||||||
low_flash_available();
|
|
||||||
return SW_OK();
|
|
||||||
}
|
}
|
||||||
|
else if (P1(apdu) == 0x2) {
|
||||||
|
if (!has_session_sopin)
|
||||||
|
return SW_CONDITIONS_NOT_SATISFIED();
|
||||||
|
if (apdu.cmd_apdu_data_len > 16)
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
newpin_len = apdu.cmd_apdu_data_len;
|
||||||
|
}
|
||||||
|
uint8_t dhash[33];
|
||||||
|
dhash[0] = newpin_len;
|
||||||
|
double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1);
|
||||||
|
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
|
||||||
|
if (pin_reset_retries(file_pin1, true) != HSM_OK)
|
||||||
|
return SW_MEMORY_FAILURE();
|
||||||
|
low_flash_available();
|
||||||
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
else if (P1(apdu) == 0x1 || P1(apdu) == 0x3) {
|
||||||
|
if (!(opts & HSM_OPT_RRC_RESET_ONLY))
|
||||||
|
return SW_COMMAND_NOT_ALLOWED();
|
||||||
|
if (P1(apdu) == 0x1) {
|
||||||
|
if (apdu.cmd_apdu_data_len != 8)
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
uint16_t r = check_pin(file_sopin, apdu.cmd_apdu_data, 8);
|
||||||
|
if (r != 0x9000)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else if (P1(apdu) == 0x3) {
|
||||||
|
if (!has_session_sopin)
|
||||||
|
return SW_CONDITIONS_NOT_SATISFIED();
|
||||||
|
if (apdu.cmd_apdu_data_len != 0)
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
}
|
||||||
|
if (pin_reset_retries(file_pin1, true) != HSM_OK)
|
||||||
|
return SW_MEMORY_FAILURE();
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_challenge() {
|
static int cmd_challenge() {
|
||||||
@@ -503,6 +565,8 @@ static int cmd_initialize() {
|
|||||||
uint8_t tag = *p++;
|
uint8_t tag = *p++;
|
||||||
uint8_t tag_len = *p++;
|
uint8_t tag_len = *p++;
|
||||||
if (tag == 0x80) { //options
|
if (tag == 0x80) { //options
|
||||||
|
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
||||||
|
flash_write_data_to_file(tf, p, tag_len);
|
||||||
}
|
}
|
||||||
else if (tag == 0x81) { //user pin
|
else if (tag == 0x81) { //user pin
|
||||||
if (file_pin1 && file_pin1->data) {
|
if (file_pin1 && file_pin1->data) {
|
||||||
@@ -581,6 +645,7 @@ static int cmd_import_dkek() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memset(res_APDU,0,10);
|
||||||
res_APDU[0] = dkeks;
|
res_APDU[0] = dkeks;
|
||||||
res_APDU[1] = dkeks-current_dkeks;
|
res_APDU[1] = dkeks-current_dkeks;
|
||||||
dkek_kcv(res_APDU+2);
|
dkek_kcv(res_APDU+2);
|
||||||
@@ -1036,7 +1101,7 @@ static int cmd_delete_file() {
|
|||||||
if (apdu.cmd_apdu_data_len == 0) {
|
if (apdu.cmd_apdu_data_len == 0) {
|
||||||
ef = currentEF;
|
ef = currentEF;
|
||||||
if (!(ef = search_dynamic_file(ef->fid)))
|
if (!(ef = search_dynamic_file(ef->fid)))
|
||||||
return SW_FILE_INVALID();
|
return SW_FILE_NOT_FOUND();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint16_t fid = (apdu.cmd_apdu_data[0] << 8) | apdu.cmd_apdu_data[1];
|
uint16_t fid = (apdu.cmd_apdu_data[0] << 8) | apdu.cmd_apdu_data[1];
|
||||||
@@ -1649,6 +1714,24 @@ static int cmd_derive_asym() {
|
|||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmd_datetime() {
|
||||||
|
if (P1(apdu) != 0x0 || P2(apdu) != 0x0)
|
||||||
|
return SW_INCORRECT_P1P2();
|
||||||
|
if (apdu.cmd_apdu_data_len != 8)
|
||||||
|
return SW_WRONG_LENGTH();
|
||||||
|
datetime_t dt;
|
||||||
|
dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]);
|
||||||
|
dt.month = apdu.cmd_apdu_data[2];
|
||||||
|
dt.day = apdu.cmd_apdu_data[3];
|
||||||
|
dt.dotw = apdu.cmd_apdu_data[4];
|
||||||
|
dt.hour = apdu.cmd_apdu_data[5];
|
||||||
|
dt.min = apdu.cmd_apdu_data[6];
|
||||||
|
dt.sec = apdu.cmd_apdu_data[7];
|
||||||
|
if (!rtc_set_datetime(&dt))
|
||||||
|
return SW_WRONG_DATA();
|
||||||
|
return SW_OK();
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct cmd
|
typedef struct cmd
|
||||||
{
|
{
|
||||||
uint8_t ins;
|
uint8_t ins;
|
||||||
@@ -1670,6 +1753,7 @@ typedef struct cmd
|
|||||||
#define INS_DERIVE_ASYM 0x76
|
#define INS_DERIVE_ASYM 0x76
|
||||||
#define INS_CIPHER_SYM 0x78
|
#define INS_CIPHER_SYM 0x78
|
||||||
#define INS_CHALLENGE 0x84
|
#define INS_CHALLENGE 0x84
|
||||||
|
#define INS_DATETIME 0x88
|
||||||
#define INS_SELECT_FILE 0xA4
|
#define INS_SELECT_FILE 0xA4
|
||||||
#define INS_READ_BINARY 0xB0
|
#define INS_READ_BINARY 0xB0
|
||||||
#define INS_READ_BINARY_ODD 0xB1
|
#define INS_READ_BINARY_ODD 0xB1
|
||||||
@@ -1697,6 +1781,7 @@ static const cmd_t cmds[] = {
|
|||||||
{ INS_DECRYPT_ASYM, cmd_decrypt_asym },
|
{ INS_DECRYPT_ASYM, cmd_decrypt_asym },
|
||||||
{ INS_CIPHER_SYM, cmd_cipher_sym },
|
{ INS_CIPHER_SYM, cmd_cipher_sym },
|
||||||
{ INS_DERIVE_ASYM, cmd_derive_asym },
|
{ INS_DERIVE_ASYM, cmd_derive_asym },
|
||||||
|
{ INS_DATETIME, cmd_datetime },
|
||||||
{ 0x00, 0x0}
|
{ 0x00, 0x0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
|
|
||||||
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
||||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
||||||
#define SW_PIN_BLOCKED() set_res_sw (0x63, 0x00)
|
|
||||||
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
|
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
|
||||||
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
||||||
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
|
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
|
||||||
@@ -34,7 +33,7 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
|
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
|
||||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
|
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
|
||||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
|
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
|
||||||
#define SW_FILE_INVALID() set_res_sw (0x69, 0x83)
|
#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83)
|
||||||
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
|
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
|
||||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
||||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#ifndef __VERSION_H_
|
#ifndef __VERSION_H_
|
||||||
#define __VERSION_H_
|
#define __VERSION_H_
|
||||||
|
|
||||||
#define HSM_VERSION 0x0108
|
#define HSM_VERSION 0x010A
|
||||||
|
|
||||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||||
|
|||||||
Reference in New Issue
Block a user