mirror of
https://github.com/polhenarejos/pico-hsm
synced 2026-06-15 23:30:12 +02:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
251b35dd9c | ||
|
|
0eebdd330a | ||
|
|
2a4ee5d42f | ||
|
|
d5b0a94ba4 | ||
|
|
504bb0fc05 | ||
|
|
f1d927d4ef | ||
|
|
1b322755a1 | ||
|
|
e8a398f508 | ||
|
|
5297e368d1 | ||
|
|
7c8b39ff82 | ||
|
|
254159d44d | ||
|
|
75c56bb2c7 | ||
|
|
1f96fe619b | ||
|
|
3af776ec26 | ||
|
|
54cba3efdf | ||
|
|
1ced9f6267 | ||
|
|
c14a12d9d1 | ||
|
|
bbbf28cb42 | ||
|
|
db9d6ef2f5 | ||
|
|
983a5b7d10 | ||
|
|
839fb431c4 | ||
|
|
cc0e4e43ca | ||
|
|
7a12177745 | ||
|
|
2874353804 | ||
|
|
64c4afb5d9 | ||
|
|
aae66e7db3 | ||
|
|
2d25ed9939 | ||
|
|
0ad7e3a610 | ||
|
|
25889094e5 | ||
|
|
710f4324ad | ||
|
|
b78c1485c1 |
@@ -38,7 +38,7 @@ else()
|
||||
set(__FOR_CI 0)
|
||||
endif()
|
||||
if(__FOR_CI)
|
||||
add_definitions(-D__FOR_CI)
|
||||
add_compile_definitions(__FOR_CI)
|
||||
endif()
|
||||
|
||||
add_executable(pico_hsm)
|
||||
@@ -74,7 +74,6 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_derive_asym.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_extras.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_general_authenticate.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_session_pin.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_puk_auth.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_pso.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/cmd_bip_slip.c
|
||||
@@ -83,7 +82,7 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hsm/kek.c
|
||||
)
|
||||
|
||||
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/hsm/version.h" 3)
|
||||
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/hsm/version.h")
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
project(pico_hsm)
|
||||
@@ -96,13 +95,23 @@ if(NOT ESP_PLATFORM)
|
||||
target_sources(pico_hsm PUBLIC ${SOURCES})
|
||||
target_include_directories(pico_hsm PUBLIC ${INCLUDES})
|
||||
|
||||
target_compile_options(pico_hsm PUBLIC
|
||||
set(COMMON_COMPILE_OPTIONS
|
||||
-Wall
|
||||
)
|
||||
target_compile_options(pico_hsm PRIVATE ${COMMON_COMPILE_OPTIONS})
|
||||
|
||||
pico_keys_apply_strict_flags(
|
||||
SOURCES ${SOURCES}
|
||||
FILTER_REGEX "/src/hsm/|/pico-keys-sdk/src/|/pico-keys-sdk/config/"
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(pico_hsm PUBLIC
|
||||
-Werror
|
||||
)
|
||||
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
|
||||
if(${COMPILER_COLON} GREATER_EQUAL 0)
|
||||
target_compile_options(pico_hsm PRIVATE
|
||||
-Wno-error=use-after-free
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
@@ -127,7 +136,11 @@ if(NOT ESP_PLATFORM)
|
||||
-Wl,--gc-sections
|
||||
)
|
||||
endif(APPLE)
|
||||
target_link_libraries(pico_hsm PRIVATE pico_keys_sdk pthread m mbedtls)
|
||||
set(PICO_HSM_EMU_LIBS pico_keys_sdk pthread m)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
list(APPEND PICO_HSM_EMU_LIBS mbedtls)
|
||||
endif()
|
||||
target_link_libraries(pico_hsm PRIVATE ${PICO_HSM_EMU_LIBS})
|
||||
else()
|
||||
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
@@ -195,8 +195,8 @@ Before building, ensure you have installed the toolchain for the Pico and the Pi
|
||||
|
||||
```
|
||||
git clone https://github.com/polhenarejos/pico-hsm
|
||||
git submodule update --init --recursive
|
||||
cd pico-hsm
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION_MAJOR="6"
|
||||
VERSION_MINOR="4"
|
||||
VERSION_MINOR="6"
|
||||
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
|
||||
#if ! [[ -z "${GITHUB_SHA}" ]]; then
|
||||
# SUFFIX="${SUFFIX}.${GITHUB_SHA}"
|
||||
|
||||
Submodule pico-keys-sdk updated: 6f996c67c2...44ee025416
@@ -9,6 +9,7 @@ CONFIG_TINYUSB_TASK_STACK_SIZE=16384
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x10000
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
|
||||
@@ -27,11 +27,11 @@ const uint8_t *sym_seed = (const uint8_t *) "Symmetric key seed";
|
||||
mbedtls_ecp_keypair hd_context = { 0 };
|
||||
uint8_t hd_keytype = 0;
|
||||
|
||||
int node_derive_bip_child(const mbedtls_ecp_keypair *parent,
|
||||
const uint8_t cpar[32],
|
||||
const uint8_t *i,
|
||||
mbedtls_ecp_keypair *child,
|
||||
uint8_t cchild[32]) {
|
||||
static int node_derive_bip_child(const mbedtls_ecp_keypair *parent,
|
||||
const uint8_t cpar[32],
|
||||
const uint8_t *i,
|
||||
mbedtls_ecp_keypair *child,
|
||||
uint8_t cchild[32]) {
|
||||
uint8_t data[1 + 32 + 4], I[64], *iL = I, *iR = I + 32;
|
||||
mbedtls_mpi il, kchild;
|
||||
mbedtls_mpi_init(&il);
|
||||
@@ -75,19 +75,19 @@ int node_derive_bip_child(const mbedtls_ecp_keypair *parent,
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int sha256_ripemd160(const uint8_t *buffer, size_t buffer_len, uint8_t *output) {
|
||||
static int sha256_ripemd160(const uint8_t *buffer, size_t buffer_len, uint8_t *output) {
|
||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), buffer, buffer_len, output);
|
||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_RIPEMD160), output, 32, output);
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int sha256_sha256(const uint8_t *buffer, size_t buffer_len, uint8_t *output) {
|
||||
static int sha256_sha256(const uint8_t *buffer, size_t buffer_len, uint8_t *output) {
|
||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), buffer, buffer_len, output);
|
||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), output, 32, output);
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int node_fingerprint_bip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
static int node_fingerprint_bip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
size_t olen = 0;
|
||||
uint8_t buffer[33];
|
||||
mbedtls_ecp_point_write_binary(&ctx->grp,
|
||||
@@ -101,7 +101,7 @@ int node_fingerprint_bip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int node_fingerprint_slip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
static int node_fingerprint_slip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
uint8_t buffer[32];
|
||||
mbedtls_mpi_write_binary(&ctx->d, buffer, sizeof(buffer));
|
||||
sha256_ripemd160(buffer, sizeof(buffer), buffer);
|
||||
@@ -109,8 +109,8 @@ int node_fingerprint_slip(mbedtls_ecp_keypair *ctx, uint8_t fingerprint[4]) {
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int load_master_bip(uint16_t mid, mbedtls_ecp_keypair *ctx, uint8_t chain[32],
|
||||
uint8_t key_type[1]) {
|
||||
static int load_master_bip(uint16_t mid, mbedtls_ecp_keypair *ctx, uint8_t chain[32],
|
||||
uint8_t key_type[1]) {
|
||||
uint8_t mkey[65];
|
||||
mbedtls_ecp_keypair_init(ctx);
|
||||
file_t *ef = search_file(EF_MASTER_SEED | mid);
|
||||
@@ -146,14 +146,14 @@ int load_master_bip(uint16_t mid, mbedtls_ecp_keypair *ctx, uint8_t chain[32],
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int node_derive_path(const uint8_t *path,
|
||||
uint16_t path_len,
|
||||
mbedtls_ecp_keypair *ctx,
|
||||
uint8_t chain[32],
|
||||
uint8_t fingerprint[4],
|
||||
uint8_t *nodes,
|
||||
uint8_t last_node[4],
|
||||
uint8_t key_type[1]) {
|
||||
static int node_derive_path(const uint8_t *path,
|
||||
uint16_t path_len,
|
||||
mbedtls_ecp_keypair *ctx,
|
||||
uint8_t chain[32],
|
||||
uint8_t fingerprint[4],
|
||||
uint8_t *nodes,
|
||||
uint8_t last_node[4],
|
||||
uint8_t key_type[1]) {
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0, tag = 0x0;
|
||||
uint8_t node = 0, N[64] = { 0 };
|
||||
@@ -205,7 +205,7 @@ int node_derive_path(const uint8_t *path,
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int cmd_bip_slip() {
|
||||
int cmd_bip_slip(void) {
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
if (p1 == 0x1 || p1 == 0x2 || p1 == 0x3) { // Master generation (K1 and P1)
|
||||
if (p2 >= 10) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
uint8_t challenge[256];
|
||||
uint8_t challenge_len = 0;
|
||||
|
||||
int cmd_challenge() {
|
||||
int cmd_challenge(void) {
|
||||
uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
|
||||
if (!rb) {
|
||||
return SW_WRONG_LENGTH();
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "sc_hsm.h"
|
||||
#include "kek.h"
|
||||
|
||||
int cmd_change_pin() {
|
||||
int cmd_change_pin(void) {
|
||||
if (P1(apdu) == 0x0) {
|
||||
if (P2(apdu) == 0x81 || P2(apdu) == 0x88) {
|
||||
file_t *file_pin = NULL;
|
||||
@@ -48,11 +48,11 @@ int cmd_change_pin() {
|
||||
//encrypt MKEK with new pin
|
||||
|
||||
if (P2(apdu) == 0x81) {
|
||||
hash_multi(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_pin);
|
||||
pin_derive_session(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
else if (P2(apdu) == 0x88) {
|
||||
hash_multi(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_sopin);
|
||||
pin_derive_session(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
r = store_mkek(mkek);
|
||||
@@ -60,9 +60,10 @@ int cmd_change_pin() {
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
uint8_t dhash[33];
|
||||
uint8_t dhash[34];
|
||||
dhash[0] = (uint8_t)apdu.nc - pin_len;
|
||||
double_hash_pin(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), dhash + 1);
|
||||
dhash[1] = 1; // Format
|
||||
pin_derive_verifier(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), dhash + 2);
|
||||
file_put_data(file_pin, dhash, sizeof(dhash));
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
|
||||
@@ -77,11 +77,19 @@ static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_asn1_get_int(&p, end, (int *)keylen)) != 0) {
|
||||
int keylen_i = 0;
|
||||
if ((ret = mbedtls_asn1_get_int(&p, end, &keylen_i)) != 0) {
|
||||
if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
|
||||
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
|
||||
}
|
||||
}
|
||||
else if (keylen_i < 0 || keylen_i > UINT16_MAX) {
|
||||
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
|
||||
MBEDTLS_ERR_ASN1_INVALID_LENGTH);
|
||||
}
|
||||
else {
|
||||
*keylen = (uint16_t) keylen_i;
|
||||
}
|
||||
|
||||
if (p == end) {
|
||||
return 0;
|
||||
@@ -104,13 +112,13 @@ static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
|
||||
}
|
||||
|
||||
/* Taken from https://github.com/Mbed-TLS/mbedtls/issues/2335 */
|
||||
int mbedtls_ansi_x963_kdf(mbedtls_md_type_t md_type,
|
||||
uint16_t input_len,
|
||||
uint8_t *input,
|
||||
uint16_t shared_info_len,
|
||||
uint8_t *shared_info,
|
||||
uint16_t output_len,
|
||||
uint8_t *output) {
|
||||
static int mbedtls_ansi_x963_kdf(mbedtls_md_type_t md_type,
|
||||
uint16_t input_len,
|
||||
uint8_t *input,
|
||||
uint16_t shared_info_len,
|
||||
uint8_t *shared_info,
|
||||
uint16_t output_len,
|
||||
uint8_t *output) {
|
||||
mbedtls_md_context_t md_ctx;
|
||||
const mbedtls_md_info_t *md_info = NULL;
|
||||
int hashlen = 0, exit_code = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
|
||||
@@ -128,7 +136,7 @@ int mbedtls_ansi_x963_kdf(mbedtls_md_type_t md_type,
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
if (input_len + shared_info_len + 4 >= (1ULL << 61) - 1) {
|
||||
if ((uint64_t) input_len + (uint64_t) shared_info_len + 4ULL >= (1ULL << 61) - 1) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
@@ -158,7 +166,7 @@ int mbedtls_ansi_x963_kdf(mbedtls_md_type_t md_type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_cipher_sym() {
|
||||
int cmd_cipher_sym(void) {
|
||||
uint8_t key_id = P1(apdu), algo = P2(apdu);
|
||||
if (!isUserAuthenticated) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "random.h"
|
||||
#include "oid.h"
|
||||
|
||||
int cmd_decrypt_asym() {
|
||||
int cmd_decrypt_asym(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
uint8_t p2 = P2(apdu);
|
||||
if (!isUserAuthenticated) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "sc_hsm.h"
|
||||
|
||||
int cmd_delete_file() {
|
||||
int cmd_delete_file(void) {
|
||||
file_t *ef = NULL;
|
||||
if (!isUserAuthenticated) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
|
||||
@@ -35,7 +35,7 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_derive_asym() {
|
||||
int cmd_derive_asym(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
uint8_t dest_id = P2(apdu);
|
||||
file_t *fkey;
|
||||
|
||||
@@ -24,7 +24,7 @@ extern file_t *ef_puk_aut;
|
||||
extern uint8_t challenge[256];
|
||||
extern uint8_t challenge_len;
|
||||
|
||||
int cmd_external_authenticate() {
|
||||
int cmd_external_authenticate(void) {
|
||||
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
|
||||
@@ -17,13 +17,6 @@
|
||||
|
||||
#include "sc_hsm.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "pico/aon_timer.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include "files.h"
|
||||
#include "random.h"
|
||||
#include "kek.h"
|
||||
@@ -45,7 +38,7 @@
|
||||
#define CMD_OTP 0x4C
|
||||
#define CMD_MEMORY 0x5
|
||||
|
||||
int cmd_extras() {
|
||||
int cmd_extras(void) {
|
||||
int cmd = P1(apdu);
|
||||
#ifndef ENABLE_EMULATION
|
||||
// Only allow change PHY without PIN
|
||||
@@ -57,50 +50,7 @@ int cmd_extras() {
|
||||
if (wait_button_pressed() == true) {
|
||||
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||
}
|
||||
if (cmd == CMD_DATETIME) { //datetime operations
|
||||
if (P2(apdu) != 0x0) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (apdu.nc == 0) {
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv;
|
||||
aon_timer_get_time(&tv);
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
#endif
|
||||
struct tm *tm = localtime(&tv.tv_sec);
|
||||
res_APDU_size += put_uint16_t_be(tm->tm_year + 1900, res_APDU);
|
||||
res_APDU[res_APDU_size++] = tm->tm_mon;
|
||||
res_APDU[res_APDU_size++] = tm->tm_mday;
|
||||
res_APDU[res_APDU_size++] = tm->tm_wday;
|
||||
res_APDU[res_APDU_size++] = tm->tm_hour;
|
||||
res_APDU[res_APDU_size++] = tm->tm_min;
|
||||
res_APDU[res_APDU_size++] = tm->tm_sec;
|
||||
}
|
||||
else {
|
||||
if (apdu.nc != 8) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
struct tm tm;
|
||||
tm.tm_year = get_uint16_t_be(apdu.data) - 1900;
|
||||
tm.tm_mon = apdu.data[2];
|
||||
tm.tm_mday = apdu.data[3];
|
||||
tm.tm_wday = apdu.data[4];
|
||||
tm.tm_hour = apdu.data[5];
|
||||
tm.tm_min = apdu.data[6];
|
||||
tm.tm_sec = apdu.data[7];
|
||||
time_t tv_sec = mktime(&tm);
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {.tv_sec = tv_sec, .tv_nsec = 0};
|
||||
aon_timer_set_time(&tv);
|
||||
#else
|
||||
struct timeval tv = {.tv_sec = tv_sec, .tv_usec = 0};
|
||||
settimeofday(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (cmd == CMD_DYNOPS) { //dynamic options
|
||||
if (cmd == CMD_DYNOPS) { //dynamic options
|
||||
if (P2(apdu) != 0x0) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
@@ -172,7 +122,7 @@ int cmd_extras() {
|
||||
if ((P2(apdu) == SECURE_LOCK_ENABLE && !(opts & HSM_OPT_SECURE_LOCK)) ||
|
||||
(P2(apdu) == SECURE_LOCK_DISABLE && (opts & HSM_OPT_SECURE_LOCK))) {
|
||||
uint16_t tfids[] = { EF_MKEK, EF_MKEK_SO };
|
||||
for (int t = 0; t < sizeof(tfids) / sizeof(uint16_t); t++) {
|
||||
for (size_t t = 0; t < sizeof(tfids) / sizeof(uint16_t); t++) {
|
||||
file_t *tf = search_file(tfids[t]);
|
||||
if (tf) {
|
||||
uint8_t *tmp = (uint8_t *) calloc(1, file_get_size(tf));
|
||||
@@ -201,106 +151,6 @@ int cmd_extras() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef ENABLE_EMULATION
|
||||
else if (cmd == CMD_PHY) { // Set PHY
|
||||
if (apdu.nc == 0) {
|
||||
if (file_has_data(ef_phy)) {
|
||||
res_APDU_size = file_get_size(ef_phy);
|
||||
memcpy(res_APDU, file_get_data(ef_phy), res_APDU_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (P2(apdu) == PHY_VIDPID) { // VIDPID
|
||||
if (apdu.nc != 4) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
phy_data.vid = get_uint16_t_be(apdu.data);
|
||||
phy_data.pid = get_uint16_t_be(apdu.data + 2);
|
||||
phy_data.vidpid_present = true;
|
||||
}
|
||||
else if (P2(apdu) == PHY_LED_GPIO) {
|
||||
phy_data.led_gpio = apdu.data[0];
|
||||
phy_data.led_gpio_present = true;
|
||||
}
|
||||
else if (P2(apdu) == PHY_LED_BTNESS) {
|
||||
phy_data.led_brightness = apdu.data[0];
|
||||
phy_data.led_brightness_present = true;
|
||||
}
|
||||
else if (P2(apdu) == PHY_OPTS) {
|
||||
if (apdu.nc != 2) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
phy_data.opts = get_uint16_t_be(apdu.data);
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (phy_save() != PICOKEY_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if PICO_RP2350
|
||||
else if (cmd == CMD_OTP) {
|
||||
if (apdu.nc < 2) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
uint16_t row = get_uint16_t_be(apdu.data);
|
||||
bool israw = P2(apdu) == 0x1;
|
||||
if (apdu.nc == 2) {
|
||||
if (row > 0xbf && row < 0xf48) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (israw) {
|
||||
memcpy(res_APDU, otp_buffer_raw(row), apdu.ne);
|
||||
}
|
||||
else {
|
||||
memcpy(res_APDU, otp_buffer(row), apdu.ne);
|
||||
}
|
||||
res_APDU_size = apdu.ne;
|
||||
}
|
||||
else {
|
||||
apdu.nc -= 2;
|
||||
apdu.data += 2;
|
||||
if (apdu.nc > 1024) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
if (apdu.nc % (israw ? 4 : 2)) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
uint8_t adata[1024] __attribute__((aligned(4)));
|
||||
memcpy(adata, apdu.data, apdu.nc);
|
||||
int ret = 0;
|
||||
if (israw) {
|
||||
ret = otp_write_data_raw(row, adata, apdu.nc);
|
||||
}
|
||||
else {
|
||||
ret = otp_write_data(row, adata, apdu.nc);
|
||||
}
|
||||
if (ret != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef PICO_PLATFORM
|
||||
else if (cmd == CMD_REBOOT) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
watchdog_reboot(0, 0, 100);
|
||||
}
|
||||
#endif
|
||||
else if (cmd == CMD_MEMORY) {
|
||||
res_APDU_size = 0;
|
||||
uint32_t free = flash_free_space(), total = flash_total_space(), used = flash_used_space(), nfiles = flash_num_files(), size = flash_size();
|
||||
res_APDU_size += put_uint32_t_be(free, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(used, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(total, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(nfiles, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(size, res_APDU + res_APDU_size);
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "files.h"
|
||||
#include "otp.h"
|
||||
|
||||
int cmd_general_authenticate() {
|
||||
int cmd_general_authenticate(void) {
|
||||
if (P1(apdu) == 0x0 && P2(apdu) == 0x0) {
|
||||
if (apdu.data[0] == 0x7C) {
|
||||
int r = 0;
|
||||
|
||||
@@ -25,10 +25,8 @@
|
||||
#include "cvc.h"
|
||||
#include "otp.h"
|
||||
|
||||
extern void scan_all();
|
||||
|
||||
extern char __StackLimit;
|
||||
int heapLeft() {
|
||||
static int heapLeft(void) {
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
char *p = malloc(256); // try to avoid undue fragmentation
|
||||
int left = &__StackLimit - p;
|
||||
@@ -39,8 +37,7 @@ int heapLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
extern void reset_puk_store();
|
||||
int cmd_initialize() {
|
||||
int cmd_initialize(void) {
|
||||
if (apdu.nc > 0) {
|
||||
uint8_t mkek[MKEK_SIZE];
|
||||
uint16_t opts = get_device_options();
|
||||
@@ -63,21 +60,23 @@ int cmd_initialize() {
|
||||
}
|
||||
else if (tag == 0x81) { //user pin
|
||||
if (file_pin1 && file_pin1->data) {
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = (uint8_t)tag_len;
|
||||
double_hash_pin(tag_data, tag_len, dhash + 1);
|
||||
file_put_data(file_pin1, dhash, sizeof(dhash));
|
||||
hash_multi(tag_data, tag_len, session_pin);
|
||||
uint8_t pin_data[34];
|
||||
pin_data[0] = (uint8_t)tag_len;
|
||||
pin_data[1] = 1; // Format
|
||||
pin_derive_verifier(tag_data, tag_len, pin_data + 2);
|
||||
file_put_data(file_pin1, pin_data, sizeof(pin_data));
|
||||
pin_derive_session(tag_data, 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] = (uint8_t)tag_len;
|
||||
double_hash_pin(tag_data, tag_len, dhash + 1);
|
||||
file_put_data(file_sopin, dhash, sizeof(dhash));
|
||||
hash_multi(tag_data, tag_len, session_sopin);
|
||||
uint8_t pin_data[34];
|
||||
pin_data[0] = (uint8_t)tag_len;
|
||||
pin_data[1] = 1; // Format
|
||||
pin_derive_verifier(tag_data, tag_len, pin_data + 2);
|
||||
file_put_data(file_sopin, pin_data, sizeof(pin_data));
|
||||
pin_derive_session(tag_data, tag_len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ uint8_t get_key_domain(file_t *fkey) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
int cmd_key_domain() {
|
||||
int cmd_key_domain(void) {
|
||||
//if (dkeks == 0)
|
||||
// return SW_COMMAND_NOT_ALLOWED();
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "sc_hsm.h"
|
||||
#include "random.h"
|
||||
|
||||
int cmd_key_gen() {
|
||||
int cmd_key_gen(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
uint8_t p2 = P2(apdu);
|
||||
uint8_t key_size = 32;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "kek.h"
|
||||
#include "cvc.h"
|
||||
|
||||
int cmd_key_unwrap() {
|
||||
int cmd_key_unwrap(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
int r = 0;
|
||||
if (P2(apdu) != 0x93) {
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
#include "kek.h"
|
||||
#include "files.h"
|
||||
|
||||
extern uint8_t get_key_domain(file_t *fkey);
|
||||
|
||||
int cmd_key_wrap() {
|
||||
int cmd_key_wrap(void) {
|
||||
int r = 0;
|
||||
uint8_t key_id = P1(apdu);
|
||||
if (P2(apdu) != 0x92) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "random.h"
|
||||
#include "kek.h"
|
||||
|
||||
int cmd_keypair_gen() {
|
||||
int cmd_keypair_gen(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
if (!isUserAuthenticated) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "sc_hsm.h"
|
||||
#include "files.h"
|
||||
|
||||
int cmd_list_keys() {
|
||||
int cmd_list_keys(void) {
|
||||
/* First we send DEV private key */
|
||||
/* Both below conditions should be always TRUE */
|
||||
if (search_file(EF_PRKD_DEV)) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
file_t *ef_puk_aut = NULL;
|
||||
|
||||
int cmd_mse() {
|
||||
int cmd_mse(void) {
|
||||
int p1 = P1(apdu);
|
||||
int p2 = P2(apdu);
|
||||
if (p2 != 0xA4 && p2 != 0xA6 && p2 != 0xAA && p2 != 0xB4 && p2 != 0xB6 && p2 != 0xB8) {
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
#include "asn1.h"
|
||||
#include "cvc.h"
|
||||
|
||||
extern int add_cert_puk_store(const uint8_t *data, uint16_t data_len, bool copy);
|
||||
extern PUK *current_puk;
|
||||
|
||||
int cmd_pso() {
|
||||
int cmd_pso(void) {
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
if (p1 == 0x0 && (p2 == 0x92 || p2 == 0xAE || p2 == 0xBE)) { /* Verify certificate */
|
||||
if (apdu.nc == 0) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "files.h"
|
||||
#include "cvc.h"
|
||||
|
||||
int cmd_puk_auth() {
|
||||
int cmd_puk_auth(void) {
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
file_t *ef_puk = search_file(EF_PUKAUT);
|
||||
if (!file_has_data(ef_puk)) {
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
|
||||
#include "sc_hsm.h"
|
||||
|
||||
int cmd_read_binary() {
|
||||
typedef int (*file_data_handler_t)(const file_t *f, int mode);
|
||||
|
||||
int cmd_read_binary(void) {
|
||||
uint16_t offset = 0;
|
||||
uint8_t ins = INS(apdu), p1 = P1(apdu), p2 = P2(apdu);
|
||||
const file_t *ef = NULL;
|
||||
file_t *ef = NULL;
|
||||
|
||||
if ((ins & 0x1) == 0) {
|
||||
if ((p1 & 0x80) != 0) {
|
||||
@@ -60,12 +62,28 @@ int cmd_read_binary() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ef == NULL) {
|
||||
return SW_FILE_NOT_FOUND();
|
||||
}
|
||||
|
||||
if (offset > 0x7fff) {
|
||||
return SW_WRONG_P1P2();
|
||||
}
|
||||
|
||||
if ((ef->fid >> 8) == PROT_DATA_PREFIX) {
|
||||
memset(ef->acl, 0x90, sizeof(ef->acl)); //force PIN for protected data objects
|
||||
}
|
||||
|
||||
if ((ef->fid >> 8) == KEY_PREFIX || !authenticate_action(ef, ACL_OP_READ_SEARCH)) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
if (ef->data) {
|
||||
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||
uint16_t data_len = (uint16_t)((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, 1); //already copies content to res_APDU
|
||||
union {
|
||||
uint8_t *data;
|
||||
file_data_handler_t handler;
|
||||
} data_func = { .data = ef->data };
|
||||
uint16_t data_len = (uint16_t)data_func.handler((const file_t *) ef, 1); //already copies content to res_APDU
|
||||
if (offset > data_len) {
|
||||
return SW_WRONG_P1P2();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "sc_hsm.h"
|
||||
#include "kek.h"
|
||||
|
||||
int cmd_reset_retry() {
|
||||
int cmd_reset_retry(void) {
|
||||
if (P2(apdu) != 0x81) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
@@ -55,10 +55,6 @@ int cmd_reset_retry() {
|
||||
}
|
||||
newpin_len = (uint8_t)apdu.nc;
|
||||
}
|
||||
uint8_t dhash[33];
|
||||
dhash[0] = newpin_len;
|
||||
double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1);
|
||||
file_put_data(file_pin1, dhash, sizeof(dhash));
|
||||
if (pin_reset_retries(file_pin1, true) != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
@@ -67,13 +63,18 @@ int cmd_reset_retry() {
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
hash_multi(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pin);
|
||||
pin_derive_session(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pin);
|
||||
has_session_pin = true;
|
||||
r = store_mkek(mkek);
|
||||
release_mkek(mkek);
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
uint8_t dhash[34];
|
||||
dhash[0] = newpin_len;
|
||||
dhash[1] = 1; // Format
|
||||
pin_derive_verifier(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 2);
|
||||
file_put_data(file_pin1, dhash, sizeof(dhash));
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ void select_file(file_t *pe) {
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_select() {
|
||||
int cmd_select(void) {
|
||||
uint8_t p1 = P1(apdu);
|
||||
uint8_t p2 = P2(apdu);
|
||||
file_t *pe = NULL;
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sc_hsm.h"
|
||||
#include "random.h"
|
||||
#include "eac.h"
|
||||
|
||||
int cmd_session_pin() {
|
||||
if (P1(apdu) == 0x01 && P2(apdu) == 0x81) {
|
||||
memcpy(sm_session_pin, random_bytes_get(8), 8);
|
||||
sm_session_pin_len = 8;
|
||||
|
||||
memcpy(res_APDU, sm_session_pin, sm_session_pin_len);
|
||||
res_APDU_size = sm_session_pin_len;
|
||||
apdu.ne = sm_session_pin_len;
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
@@ -72,11 +72,11 @@ static const struct digest_info_prefix {
|
||||
{ MBEDTLS_MD_RIPEMD160, hdr_ripemd160, sizeof(hdr_ripemd160), 20 },
|
||||
{ 0, NULL, 0, 0 }
|
||||
};
|
||||
int pkcs1_strip_digest_info_prefix(mbedtls_md_type_t *algorithm,
|
||||
const uint8_t *in_dat,
|
||||
uint16_t in_len,
|
||||
uint8_t *out_dat,
|
||||
uint16_t *out_len) {
|
||||
static int pkcs1_strip_digest_info_prefix(mbedtls_md_type_t *algorithm,
|
||||
const uint8_t *in_dat,
|
||||
uint16_t in_len,
|
||||
uint8_t *out_dat,
|
||||
uint16_t *out_len) {
|
||||
for (int i = 0; digest_info_prefix[i].algorithm != 0; i++) {
|
||||
uint16_t hdr_len = digest_info_prefix[i].hdr_len, hash_len = digest_info_prefix[i].hash_len;
|
||||
const uint8_t *hdr = digest_info_prefix[i].hdr;
|
||||
@@ -99,7 +99,7 @@ int pkcs1_strip_digest_info_prefix(mbedtls_md_type_t *algorithm,
|
||||
}
|
||||
//-----
|
||||
|
||||
int cmd_signature() {
|
||||
int cmd_signature(void) {
|
||||
uint8_t key_id = P1(apdu);
|
||||
uint8_t p2 = P2(apdu);
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_NONE;
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#include "sc_hsm.h"
|
||||
#include "asn1.h"
|
||||
|
||||
extern void select_file(file_t *pe);
|
||||
|
||||
int cmd_update_ef() {
|
||||
int cmd_update_ef(void) {
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
uint16_t fid = (p1 << 8) | p2;
|
||||
uint8_t *data = NULL;
|
||||
@@ -86,9 +84,12 @@ int cmd_update_ef() {
|
||||
if (!file_has_data(ef)) {
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
if (offset + data_len > 4032) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
|
||||
uint8_t *data_merge = (uint8_t *) calloc(1, offset + data_len);
|
||||
memcpy(data_merge, file_get_data(ef), offset);
|
||||
uint8_t *data_merge = (uint8_t *) calloc(1, MAX(offset + data_len, file_get_size(ef)));
|
||||
memcpy(data_merge, file_get_data(ef), file_get_size(ef));
|
||||
memcpy(data_merge + offset, data, data_len);
|
||||
int r = file_put_data(ef, data_merge, offset + data_len);
|
||||
free(data_merge);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "sc_hsm.h"
|
||||
|
||||
int cmd_verify() {
|
||||
int cmd_verify(void) {
|
||||
uint8_t p1 = P1(apdu);
|
||||
uint8_t p2 = P2(apdu);
|
||||
|
||||
|
||||
@@ -30,10 +30,7 @@
|
||||
#include "mbedtls/eddsa.h"
|
||||
#endif
|
||||
|
||||
extern const uint8_t *dev_name;
|
||||
extern uint16_t dev_name_len;
|
||||
|
||||
uint16_t asn1_cvc_public_key_rsa(mbedtls_rsa_context *rsa, uint8_t *buf, uint16_t buf_len) {
|
||||
static uint16_t asn1_cvc_public_key_rsa(mbedtls_rsa_context *rsa, uint8_t *buf, uint16_t buf_len) {
|
||||
const uint8_t oid_rsa[] = { 0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x02, 0x01, 0x02 };
|
||||
uint16_t n_size = (uint16_t)mbedtls_mpi_size(&rsa->N), e_size = (uint16_t)mbedtls_mpi_size(&rsa->E);
|
||||
uint16_t ntot_size = asn1_len_tag(0x81, n_size), etot_size = asn1_len_tag(0x82, e_size);
|
||||
@@ -74,7 +71,7 @@ const uint8_t *pointA[] = {
|
||||
"\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\xFC",
|
||||
};
|
||||
|
||||
uint16_t asn1_cvc_public_key_ecdsa(mbedtls_ecp_keypair *ecdsa, uint8_t *buf, uint16_t buf_len) {
|
||||
static uint16_t asn1_cvc_public_key_ecdsa(mbedtls_ecp_keypair *ecdsa, uint8_t *buf, uint16_t buf_len) {
|
||||
uint8_t Y_buf[MBEDTLS_ECP_MAX_PT_LEN], G_buf[MBEDTLS_ECP_MAX_PT_LEN];
|
||||
const uint8_t oid_ecdsa[] = { 0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x03 };
|
||||
const uint8_t oid_ri[] = { 0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x05, 0x02, 0x03 };
|
||||
@@ -167,13 +164,13 @@ uint16_t asn1_cvc_public_key_ecdsa(mbedtls_ecp_keypair *ecdsa, uint8_t *buf, uin
|
||||
return tot_len;
|
||||
}
|
||||
|
||||
uint16_t asn1_cvc_cert_body(void *rsa_ecdsa,
|
||||
uint8_t key_type,
|
||||
uint8_t *buf,
|
||||
uint16_t buf_len,
|
||||
const uint8_t *ext,
|
||||
uint16_t ext_len,
|
||||
bool full) {
|
||||
static uint16_t asn1_cvc_cert_body(void *rsa_ecdsa,
|
||||
uint8_t key_type,
|
||||
uint8_t *buf,
|
||||
uint16_t buf_len,
|
||||
const uint8_t *ext,
|
||||
uint16_t ext_len,
|
||||
bool full) {
|
||||
uint16_t pubkey_size = 0;
|
||||
if (key_type & PICO_KEYS_KEY_RSA) {
|
||||
pubkey_size = asn1_cvc_public_key_rsa(rsa_ecdsa, NULL, 0);
|
||||
@@ -611,7 +608,7 @@ const uint8_t *cvc_get_field(const uint8_t *data, uint16_t len, uint16_t *olen,
|
||||
return ctxo.data;
|
||||
}
|
||||
|
||||
const uint8_t *cvc_get_body(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
static const uint8_t *cvc_get_body(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
const uint8_t *bkdata = data;
|
||||
if ((data = cvc_get_field(data, len, olen, 0x67)) == NULL) { /* Check for CSR */
|
||||
data = bkdata;
|
||||
@@ -622,7 +619,7 @@ const uint8_t *cvc_get_body(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint8_t *cvc_get_sig(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
static const uint8_t *cvc_get_sig(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
const uint8_t *bkdata = data;
|
||||
if ((data = cvc_get_field(data, len, olen, 0x67)) == NULL) { /* Check for CSR */
|
||||
data = bkdata;
|
||||
@@ -664,7 +661,7 @@ const uint8_t *cvc_get_ext(const uint8_t *data, uint16_t len, uint16_t *olen) {
|
||||
extern PUK puk_store[MAX_PUK_STORE_ENTRIES];
|
||||
extern int puk_store_entries;
|
||||
|
||||
int puk_store_index(const uint8_t *chr, uint16_t chr_len) {
|
||||
static int puk_store_index(const uint8_t *chr, uint16_t chr_len) {
|
||||
for (int i = 0; i < puk_store_entries; i++) {
|
||||
if (memcmp(puk_store[i].chr, chr, chr_len) == 0) {
|
||||
return i;
|
||||
|
||||
306
src/hsm/files.c
306
src/hsm/files.c
@@ -22,88 +22,230 @@ extern int parse_token_info(const file_t *f, int mode);
|
||||
extern int parse_ef_dir(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 | FILE_DATA_FUNC, .data = (uint8_t *) parse_ef_dir,
|
||||
.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 = EF_TERMCA, .parent = 0, .name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.GDO
|
||||
/* 4 */ { .fid = 0x2f03, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) parse_token_info,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.TokenInfo
|
||||
/* 5 */ { .fid = 0x5015, .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
|
||||
.ef_structure = 0, .acl = { 0 } }, //DF.PKCS15
|
||||
/* 6 */ { .fid = 0x5031, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.ODF
|
||||
/* 7 */ { .fid = 0x5032, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.TokenInfo
|
||||
/* 8 */ { .fid = 0x5033, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.UnusedSpace
|
||||
/* 9 */ { .fid = EF_PIN1, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //PIN (PIN1)
|
||||
/* 10 */ { .fid = EF_PIN1_MAX_RETRIES, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //max retries PIN (PIN1)
|
||||
/* 11 */ { .fid = EF_PIN1_RETRIES, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //retries PIN (PIN1)
|
||||
/* 12 */ { .fid = EF_SOPIN, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //PIN (SOPIN)
|
||||
/* 13 */ { .fid = EF_SOPIN_MAX_RETRIES, .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 = EF_SOPIN_RETRIES, .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_DEVOPS, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //Device options
|
||||
/* 16 */ { .fid = EF_PRKDFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.PrKDFs
|
||||
/* 17 */ { .fid = EF_PUKDFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.PuKDFs
|
||||
/* 18 */ { .fid = EF_CDFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.CDFs
|
||||
/* 19 */ { .fid = EF_AODFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.AODFs
|
||||
/* 20 */ { .fid = EF_DODFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.DODFs
|
||||
/* 21 */ { .fid = EF_SKDFS, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } }, //EF.SKDFs
|
||||
/* 22 */ { .fid = EF_KEY_DOMAIN, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //Key domain options
|
||||
/* 23 */ { .fid = EF_META, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //EF.CDFs
|
||||
/* 24 */ { .fid = EF_PUKAUT, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //Public Key Authentication
|
||||
/* 25 */ { .fid = EF_KEY_DEV, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //Device Key
|
||||
/* 26 */ { .fid = EF_PRKD_DEV, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //PrKD Device
|
||||
/* 27 */ { .fid = EF_EE_DEV, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //End Entity Certificate Device
|
||||
/* 28 */ { .fid = EF_MKEK, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //MKEK
|
||||
/* 29 */ { .fid = EF_MKEK_SO, .parent = 5, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, //MKEK with SO-PIN
|
||||
///* 30 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||
/* 31 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0 } },
|
||||
/* 32 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
|
||||
.ef_structure = 0, .acl = { 0 } } //end
|
||||
/* 0 */ { .fid = 0x3f00, // MF
|
||||
.parent = 0xff,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_DF,
|
||||
.data = NULL,
|
||||
.ef_structure = 0,
|
||||
.acl = ACL_ALL },
|
||||
/* 1 */ { .fid = 0x2f00, //EF.DIR
|
||||
.parent = 0,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,
|
||||
.data = (uint8_t *) parse_ef_dir,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 2 */ { .fid = 0x2f01, // EF.ATR
|
||||
.parent = 0,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 3 */ { .fid = EF_TERMCA, // EF.GDO
|
||||
.parent = 0,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 4 */ { .fid = 0x2f03, // EF.TokenInfo
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,
|
||||
.data = (uint8_t *) parse_token_info,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 5 */ { .fid = 0x5015, // DF.PKCS15
|
||||
.parent = 0,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_DF,
|
||||
.data = NULL,
|
||||
.ef_structure = 0,
|
||||
.acl = ACL_ALL },
|
||||
/* 6 */ { .fid = 0x5031, // EF.ODF
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 7 */ { .fid = 0x5032, // EF.TokenInfo
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 8 */ { .fid = 0x5033, // EF.UnusedSpace
|
||||
.parent = 0,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 9 */ { .fid = EF_PIN1, // PIN (PIN1)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 10 */ { .fid = EF_PIN1_MAX_RETRIES, // max retries PIN (PIN1)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 11 */ { .fid = EF_PIN1_RETRIES, // retries PIN (PIN1)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 12 */ { .fid = EF_SOPIN, // PIN (SOPIN)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 13 */ { .fid = EF_SOPIN_MAX_RETRIES, // max retries PIN (SOPIN)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 14 */ { .fid = EF_SOPIN_RETRIES, // retries PIN (SOPIN)
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 15 */ { .fid = EF_DEVOPS, // Device options
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 16 */ { .fid = EF_PRKDFS, // EF.PrKDFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 17 */ { .fid = EF_PUKDFS, // EF.PuKDFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 18 */ { .fid = EF_CDFS, // EF.CDFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 19 */ { .fid = EF_AODFS, // EF.AODFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 20 */ { .fid = EF_DODFS, // EF.DODFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 21 */ { .fid = EF_SKDFS, // EF.SKDFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 22 */ { .fid = EF_KEY_DOMAIN, // Key domain options
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 23 */ { .fid = EF_META, // EF.CDFs
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 24 */ { .fid = EF_PUKAUT, // Public Key Authentication
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 25 */ { .fid = EF_KEY_DEV, // Device Key
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 26 */ { .fid = EF_PRKD_DEV, // PrKD Device
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_RO },
|
||||
/* 27 */ { .fid = EF_EE_DEV, // End Entity Certificate Device
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_R_WP },
|
||||
/* 28 */ { .fid = EF_MKEK, // MKEK
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 29 */ { .fid = EF_MKEK_SO, // MKEK with SO-PIN
|
||||
.parent = 5,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_NONE },
|
||||
/* 30 */ { .fid = 0x0000,
|
||||
.parent = 5,
|
||||
.name = sc_hsm_aid,
|
||||
.type = FILE_TYPE_WORKING_EF,
|
||||
.data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT,
|
||||
.acl = ACL_ALL },
|
||||
/* 31 */ { .fid = 0x0000, // end
|
||||
.parent = 0xff,
|
||||
.name = NULL,
|
||||
.type = FILE_TYPE_NOT_KNOWN,
|
||||
.data = NULL,
|
||||
.ef_structure = 0,
|
||||
.acl = { 0 } }
|
||||
};
|
||||
|
||||
const file_t *MF = &file_entries[0];
|
||||
|
||||
@@ -51,9 +51,4 @@
|
||||
#define EF_TOKENINFO 0x2F03
|
||||
#define EF_STATICTOKEN 0xCB00
|
||||
|
||||
extern file_t *file_pin1;
|
||||
extern file_t *file_retries_pin1;
|
||||
extern file_t *file_sopin;
|
||||
extern file_t *file_retries_sopin;
|
||||
|
||||
#endif
|
||||
|
||||
106
src/hsm/kek.c
106
src/hsm/kek.c
@@ -31,13 +31,11 @@
|
||||
#include "files.h"
|
||||
#include "otp.h"
|
||||
|
||||
extern bool has_session_pin, has_session_sopin;
|
||||
extern uint8_t session_pin[32], session_sopin[32];
|
||||
uint8_t mkek_mask[MKEK_KEY_SIZE];
|
||||
bool has_mkek_mask = false;
|
||||
uint8_t pending_save_dkek = 0xff;
|
||||
|
||||
void mkek_masked(uint8_t *mkek, const uint8_t *mask) {
|
||||
static void mkek_masked(uint8_t *mkek, const uint8_t *mask) {
|
||||
if (mask) {
|
||||
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
|
||||
MKEK_KEY(mkek)[i] ^= mask[i];
|
||||
@@ -49,18 +47,19 @@ int load_mkek(uint8_t *mkek) {
|
||||
if (has_session_pin == false && has_session_sopin == false) {
|
||||
return PICOKEY_NO_LOGIN;
|
||||
}
|
||||
file_t *ef = NULL;
|
||||
const uint8_t *pin = NULL;
|
||||
if (pin == NULL && has_session_pin == true) {
|
||||
file_t *tf = search_file(EF_MKEK);
|
||||
if (file_has_data(tf)) {
|
||||
memcpy(mkek, file_get_data(tf), MKEK_SIZE);
|
||||
ef = tf;
|
||||
pin = session_pin;
|
||||
}
|
||||
}
|
||||
if (pin == NULL && has_session_sopin == true) {
|
||||
file_t *tf = search_file(EF_MKEK_SO);
|
||||
if (file_has_data(tf)) {
|
||||
memcpy(mkek, file_get_data(tf), MKEK_SIZE);
|
||||
ef = tf;
|
||||
pin = session_sopin;
|
||||
}
|
||||
}
|
||||
@@ -68,19 +67,42 @@ int load_mkek(uint8_t *mkek) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
}
|
||||
|
||||
if (has_mkek_mask) {
|
||||
mkek_masked(mkek, mkek_mask);
|
||||
uint16_t fid_size = file_get_size(ef);
|
||||
if (fid_size == MKEK_SIZE_OLD) {
|
||||
memcpy(mkek, file_get_data(ef), MKEK_SIZE_OLD);
|
||||
if (has_mkek_mask) {
|
||||
mkek_masked(mkek, mkek_mask);
|
||||
}
|
||||
int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||
if (ret != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
}
|
||||
uint32_t mkek_checksum = 0;
|
||||
memcpy(&mkek_checksum, MKEK_CHECKSUM(mkek), sizeof(mkek_checksum));
|
||||
if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != mkek_checksum) {
|
||||
return PICOKEY_WRONG_DKEK;
|
||||
}
|
||||
if (otp_key_1) {
|
||||
mkek_masked(mkek, otp_key_1);
|
||||
}
|
||||
}
|
||||
|
||||
int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||
if (ret != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
else if (fid_size == MKEK_FILE_SIZE) {
|
||||
uint8_t format = *file_get_data(ef);
|
||||
if (format == 0x03) { // Format indicator
|
||||
uint8_t tmp_key[MKEK_FILE_SIZE];
|
||||
memcpy(tmp_key, file_get_data(ef), sizeof(tmp_key));
|
||||
int ret = decrypt_with_aad(pin, tmp_key + 1, MKEK_FILE_SIZE - 1, 2, mkek);
|
||||
mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key));
|
||||
if (ret != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != *(uint32_t *) MKEK_CHECKSUM(mkek)) {
|
||||
return PICOKEY_WRONG_DKEK;
|
||||
}
|
||||
if (otp_key_1) {
|
||||
mkek_masked(mkek, otp_key_1);
|
||||
else {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
@@ -96,7 +118,7 @@ int mse_decrypt_ct(uint8_t *data, size_t len) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int load_dkek(uint8_t id, uint8_t *dkek) {
|
||||
static int load_dkek(uint8_t id, uint8_t *dkek) {
|
||||
file_t *tf = search_file(EF_DKEK + id);
|
||||
if (!file_has_data(tf)) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
@@ -113,46 +135,30 @@ int store_mkek(const uint8_t *mkek) {
|
||||
if (has_session_pin == false && has_session_sopin == false) {
|
||||
return PICOKEY_NO_LOGIN;
|
||||
}
|
||||
uint8_t tmp_mkek[MKEK_SIZE];
|
||||
uint8_t tmp_mkek[MKEK_FILE_SIZE];
|
||||
tmp_mkek[0] = 0x03; // Format indicator
|
||||
if (mkek == NULL) {
|
||||
const uint8_t *rd = random_bytes_get(MKEK_IV_SIZE + MKEK_KEY_SIZE);
|
||||
memcpy(tmp_mkek, rd, MKEK_IV_SIZE + MKEK_KEY_SIZE);
|
||||
mkek = random_bytes_get(MKEK_SIZE);
|
||||
}
|
||||
else {
|
||||
memcpy(tmp_mkek, mkek, MKEK_SIZE);
|
||||
}
|
||||
if (otp_key_1) {
|
||||
mkek_masked(tmp_mkek, otp_key_1);
|
||||
}
|
||||
*(uint32_t *) MKEK_CHECKSUM(tmp_mkek) = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE);
|
||||
if (has_session_pin) {
|
||||
uint8_t tmp_mkek_pin[MKEK_SIZE];
|
||||
memcpy(tmp_mkek_pin, tmp_mkek, MKEK_SIZE);
|
||||
file_t *tf = search_file(EF_MKEK);
|
||||
if (!tf) {
|
||||
release_mkek(tmp_mkek);
|
||||
release_mkek(tmp_mkek_pin);
|
||||
file_t *ef = search_file(EF_MKEK);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
aes_encrypt_cfb_256(session_pin, MKEK_IV(tmp_mkek_pin), MKEK_KEY(tmp_mkek_pin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||
file_put_data(tf, tmp_mkek_pin, MKEK_SIZE);
|
||||
release_mkek(tmp_mkek_pin);
|
||||
encrypt_with_aad(session_pin, mkek, MKEK_SIZE, 2, tmp_mkek + 1);
|
||||
file_put_data(ef, tmp_mkek, sizeof(tmp_mkek));
|
||||
}
|
||||
if (has_session_sopin) {
|
||||
uint8_t tmp_mkek_sopin[MKEK_SIZE];
|
||||
memcpy(tmp_mkek_sopin, tmp_mkek, MKEK_SIZE);
|
||||
file_t *tf = search_file(EF_MKEK_SO);
|
||||
if (!tf) {
|
||||
release_mkek(tmp_mkek);
|
||||
release_mkek(tmp_mkek_sopin);
|
||||
file_t *ef = search_file(EF_MKEK_SO);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
aes_encrypt_cfb_256(session_sopin, MKEK_IV(tmp_mkek_sopin), MKEK_KEY(tmp_mkek_sopin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||
file_put_data(tf, tmp_mkek_sopin, MKEK_SIZE);
|
||||
release_mkek(tmp_mkek_sopin);
|
||||
encrypt_with_aad(session_sopin, mkek, MKEK_SIZE, 2, tmp_mkek + 1);
|
||||
file_put_data(ef, tmp_mkek, sizeof(tmp_mkek));
|
||||
}
|
||||
low_flash_available();
|
||||
release_mkek(tmp_mkek);
|
||||
mbedtls_platform_zeroize(tmp_mkek, sizeof(tmp_mkek));
|
||||
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
@@ -217,7 +223,7 @@ int dkek_kcv(uint8_t id, uint8_t *kcv) { //kcv 8 bytes
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int dkek_kenc(uint8_t id, uint8_t *kenc) { //kenc 32 bytes
|
||||
static int dkek_kenc(uint8_t id, uint8_t *kenc) { //kenc 32 bytes
|
||||
uint8_t dkek[DKEK_KEY_SIZE + 4];
|
||||
memset(kenc, 0, 32);
|
||||
int r = load_dkek(id, dkek);
|
||||
@@ -230,7 +236,7 @@ int dkek_kenc(uint8_t id, uint8_t *kenc) { //kenc 32 bytes
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int dkek_kmac(uint8_t id, uint8_t *kmac) { //kmac 32 bytes
|
||||
static int dkek_kmac(uint8_t id, uint8_t *kmac) { //kmac 32 bytes
|
||||
uint8_t dkek[DKEK_KEY_SIZE + 4];
|
||||
memset(kmac, 0, 32);
|
||||
int r = load_dkek(id, dkek);
|
||||
@@ -245,7 +251,7 @@ int dkek_kmac(uint8_t id, uint8_t *kmac) { //kmac 32 bytes
|
||||
|
||||
int mkek_encrypt(uint8_t *data, uint16_t len) {
|
||||
int r;
|
||||
uint8_t mkek[MKEK_SIZE + 4];
|
||||
uint8_t mkek[MKEK_SIZE];
|
||||
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
|
||||
return r;
|
||||
}
|
||||
@@ -256,7 +262,7 @@ int mkek_encrypt(uint8_t *data, uint16_t len) {
|
||||
|
||||
int mkek_decrypt(uint8_t *data, uint16_t len) {
|
||||
int r;
|
||||
uint8_t mkek[MKEK_SIZE + 4];
|
||||
uint8_t mkek[MKEK_SIZE];
|
||||
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -28,27 +28,15 @@ extern int load_mkek(uint8_t *);
|
||||
extern int store_mkek(const uint8_t *);
|
||||
extern int save_dkek_key(uint8_t, const uint8_t *key);
|
||||
extern int store_dkek_key(uint8_t, uint8_t *);
|
||||
extern void init_mkek();
|
||||
extern void init_mkek(void);
|
||||
extern void release_mkek(uint8_t *);
|
||||
extern int import_dkek_share(uint8_t, const uint8_t *share);
|
||||
extern int dkek_kcv(uint8_t, uint8_t *kcv);
|
||||
extern int mkek_encrypt(uint8_t *data, uint16_t len);
|
||||
extern int mkek_decrypt(uint8_t *data, uint16_t len);
|
||||
extern int dkek_encode_key(uint8_t,
|
||||
void *key_ctx,
|
||||
int key_type,
|
||||
uint8_t *out,
|
||||
uint16_t *out_len,
|
||||
const uint8_t *,
|
||||
uint16_t);
|
||||
extern int dkek_encode_key(uint8_t, void *key_ctx, int key_type, uint8_t *out, uint16_t *out_len, const uint8_t *, uint16_t);
|
||||
extern int dkek_type_key(const uint8_t *in);
|
||||
extern int dkek_decode_key(uint8_t,
|
||||
void *key_ctx,
|
||||
const uint8_t *in,
|
||||
uint16_t in_len,
|
||||
int *key_size_out,
|
||||
uint8_t **,
|
||||
uint16_t *);
|
||||
extern int dkek_decode_key(uint8_t, void *key_ctx, const uint8_t *in, uint16_t in_len, int *key_size_out, uint8_t **, uint16_t *);
|
||||
|
||||
#define MAX_DKEK_ENCODE_KEY_BUFFER (8 + 1 + 12 + 6 + (8 + 2 * 4 + 2 * 4096 / 8 + 3 + 13) + 16)
|
||||
|
||||
@@ -57,12 +45,15 @@ extern int dkek_decode_key(uint8_t,
|
||||
#define MKEK_IV_SIZE (IV_SIZE)
|
||||
#define MKEK_KEY_SIZE (32)
|
||||
#define MKEK_KEY_CS_SIZE (4)
|
||||
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
|
||||
#define MKEK_SIZE_OLD (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
|
||||
#define MKEK_IV(p) (p)
|
||||
#define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE)
|
||||
#define MKEK_CHECKSUM(p) (MKEK_KEY(p) + MKEK_KEY_SIZE)
|
||||
#define DKEK_KEY_SIZE (32)
|
||||
|
||||
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE)
|
||||
#define MKEK_FILE_SIZE (1 + (12 + MKEK_SIZE + 16))
|
||||
|
||||
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
|
||||
extern bool has_mkek_mask;
|
||||
|
||||
|
||||
145
src/hsm/sc_hsm.c
145
src/hsm/sc_hsm.c
@@ -48,44 +48,14 @@ uint8_t PICO_PRODUCT = 1;
|
||||
uint8_t PICO_VERSION_MAJOR = HSM_VERSION_MAJOR;
|
||||
uint8_t PICO_VERSION_MINOR = HSM_VERSION_MINOR;
|
||||
|
||||
static int sc_hsm_process_apdu();
|
||||
static int sc_hsm_process_apdu(void);
|
||||
|
||||
static void init_sc_hsm();
|
||||
static int sc_hsm_unload();
|
||||
|
||||
extern int cmd_select();
|
||||
extern void select_file(file_t *pe);
|
||||
extern int cmd_list_keys();
|
||||
|
||||
extern int cmd_read_binary();
|
||||
extern int cmd_verify();
|
||||
extern int cmd_reset_retry();
|
||||
extern int cmd_challenge();
|
||||
extern int cmd_external_authenticate();
|
||||
extern int cmd_mse();
|
||||
extern int cmd_initialize();
|
||||
extern int cmd_key_domain();
|
||||
extern int cmd_key_wrap();
|
||||
extern int cmd_keypair_gen();
|
||||
extern int cmd_update_ef();
|
||||
extern int cmd_delete_file();
|
||||
extern int cmd_change_pin();
|
||||
extern int cmd_key_gen();
|
||||
extern int cmd_signature();
|
||||
extern int cmd_key_unwrap();
|
||||
extern int cmd_decrypt_asym();
|
||||
extern int cmd_cipher_sym();
|
||||
extern int cmd_derive_asym();
|
||||
extern int cmd_extras();
|
||||
extern int cmd_general_authenticate();
|
||||
extern int cmd_session_pin();
|
||||
extern int cmd_puk_auth();
|
||||
extern int cmd_pso();
|
||||
extern int cmd_bip_slip();
|
||||
static void init_sc_hsm(void);
|
||||
static int sc_hsm_unload(void);
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
|
||||
int sc_hsm_select_aid(app_t *a, uint8_t force) {
|
||||
static int sc_hsm_select_aid(app_t *a, uint8_t force) {
|
||||
(void) force;
|
||||
a->process_apdu = sc_hsm_process_apdu;
|
||||
a->unload = sc_hsm_unload;
|
||||
@@ -99,7 +69,7 @@ INITIALIZER( sc_hsm_ctor ) {
|
||||
register_app(sc_hsm_select_aid, sc_hsm_aid);
|
||||
}
|
||||
|
||||
void scan_files() {
|
||||
static void scan_files(void) {
|
||||
file_pin1 = search_file(EF_PIN1);
|
||||
if (file_pin1) {
|
||||
if (!file_pin1->data) {
|
||||
@@ -171,7 +141,7 @@ void scan_files() {
|
||||
low_flash_available();
|
||||
}
|
||||
|
||||
void scan_all() {
|
||||
void scan_all(void) {
|
||||
scan_flash();
|
||||
scan_files();
|
||||
}
|
||||
@@ -223,7 +193,7 @@ int puk_store_select_chr(const uint8_t *chr) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
void reset_puk_store() {
|
||||
void reset_puk_store(void) {
|
||||
if (puk_store_entries > 0) { /* From previous session */
|
||||
for (int i = 0; i < puk_store_entries; i++) {
|
||||
if (puk_store[i].copied == true) {
|
||||
@@ -254,7 +224,7 @@ void reset_puk_store() {
|
||||
memset(puk_status, 0, sizeof(puk_status));
|
||||
}
|
||||
|
||||
void init_sc_hsm() {
|
||||
void init_sc_hsm(void) {
|
||||
scan_all();
|
||||
has_session_pin = has_session_sopin = false;
|
||||
isUserAuthenticated = false;
|
||||
@@ -262,14 +232,13 @@ void init_sc_hsm() {
|
||||
reset_puk_store();
|
||||
}
|
||||
|
||||
int sc_hsm_unload() {
|
||||
int sc_hsm_unload(void) {
|
||||
has_session_pin = has_session_sopin = false;
|
||||
isUserAuthenticated = false;
|
||||
sm_session_pin_len = 0;
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
uint16_t get_device_options() {
|
||||
uint16_t get_device_options(void) {
|
||||
file_t *ef = search_file(EF_DEVOPS);
|
||||
if (file_has_data(ef)) {
|
||||
return get_uint16_t_be(file_get_data(ef));
|
||||
@@ -277,7 +246,7 @@ uint16_t get_device_options() {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
bool wait_button_pressed() {
|
||||
bool wait_button_pressed(void) {
|
||||
uint32_t val = EV_PRESS_BUTTON;
|
||||
#ifndef ENABLE_EMULATION
|
||||
uint16_t opts = get_device_options();
|
||||
@@ -294,11 +263,11 @@ bool wait_button_pressed() {
|
||||
int parse_token_info(const file_t *f, int mode) {
|
||||
(void)f;
|
||||
#ifdef __FOR_CI
|
||||
char *label = "SmartCard-HSM";
|
||||
const char *label = "SmartCard-HSM";
|
||||
#else
|
||||
char *label = "Pico-HSM";
|
||||
const char *label = "Pico-HSM";
|
||||
#endif
|
||||
char *manu = "Pol Henarejos";
|
||||
const char *manu = "Pol Henarejos";
|
||||
if (mode == 1) {
|
||||
uint8_t *p = res_APDU;
|
||||
*p++ = 0x30;
|
||||
@@ -321,9 +290,9 @@ int parse_token_info(const file_t *f, int mode) {
|
||||
int parse_ef_dir(const file_t *f, int mode) {
|
||||
(void)f;
|
||||
#ifdef __FOR_CI
|
||||
char *label = "SmartCard-HSM";
|
||||
const char *label = "SmartCard-HSM";
|
||||
#else
|
||||
char *label = "Pico-HSM";
|
||||
const char *label = "Pico-HSM";
|
||||
#endif
|
||||
if (mode == 1) {
|
||||
uint8_t *p = res_APDU;
|
||||
@@ -380,7 +349,7 @@ int pin_wrong_retry(const file_t *pin) {
|
||||
return PICOKEY_ERR_BLOCKED;
|
||||
}
|
||||
|
||||
bool pka_enabled() {
|
||||
bool pka_enabled(void) {
|
||||
file_t *ef_puk = search_file(EF_PUKAUT);
|
||||
return file_has_data(ef_puk) && file_read_uint8(ef_puk) > 0;
|
||||
}
|
||||
@@ -393,28 +362,23 @@ uint16_t check_pin(const file_t *pin, const uint8_t *data, uint16_t len) {
|
||||
isUserAuthenticated = false;
|
||||
}
|
||||
has_session_pin = has_session_sopin = false;
|
||||
if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) {
|
||||
if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) {
|
||||
int retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) {
|
||||
return SW_PIN_BLOCKED();
|
||||
}
|
||||
return set_res_sw(0x63, 0xc0 | (uint8_t)retries);
|
||||
}
|
||||
uint8_t dhash[32], off = 2;
|
||||
if (sizeof(dhash) == file_get_size(pin) - 1) { // Old style
|
||||
off = 1;
|
||||
double_hash_pin(data, len, dhash);
|
||||
}
|
||||
else if (sizeof(dhash) == file_get_size(pin) - 2) {
|
||||
pin_derive_verifier(data, len, dhash);
|
||||
}
|
||||
else {
|
||||
uint8_t dhash[32];
|
||||
double_hash_pin(data, len, dhash);
|
||||
if (sizeof(dhash) != file_get_size(pin) - 1) { // 1 byte for pin len
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
if (memcmp(file_get_data(pin) + 1, dhash, sizeof(dhash)) != 0) {
|
||||
int retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) {
|
||||
return SW_PIN_BLOCKED();
|
||||
}
|
||||
return set_res_sw(0x63, 0xc0 | (uint8_t)retries);
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (memcmp(file_get_data(pin) + off, dhash, sizeof(dhash)) != 0) {
|
||||
int retries;
|
||||
if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) {
|
||||
return SW_PIN_BLOCKED();
|
||||
}
|
||||
return set_res_sw(0x63, 0xc0 | (uint8_t)retries);
|
||||
}
|
||||
int r = pin_reset_retries(pin, false);
|
||||
if (r == PICOKEY_ERR_BLOCKED) {
|
||||
@@ -423,15 +387,54 @@ uint16_t check_pin(const file_t *pin, const uint8_t *data, uint16_t len) {
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
if (off == 1) { // Upgrade PIN format
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
if (pin == file_pin1) {
|
||||
hash_multi(data, len, session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
else if (pin == file_sopin) {
|
||||
hash_multi(data, len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
uint8_t mkek[MKEK_SIZE_OLD]; // Old MKEK size, as it is encrypted with old PIN format
|
||||
r = load_mkek(mkek); //loads the MKEK with old format
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
if (pin == file_pin1) {
|
||||
pin_derive_session(data, len, session_pin);
|
||||
}
|
||||
else if (pin == file_sopin) {
|
||||
pin_derive_session(data, len, session_sopin);
|
||||
}
|
||||
r = store_mkek(mkek); //stores the MKEK with new format
|
||||
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
|
||||
uint8_t pin_data[34];
|
||||
pin_data[0] = len;
|
||||
pin_data[1] = 1; // new format indicator
|
||||
pin_derive_verifier(data, len, pin_data + 2);
|
||||
r = file_put_data((file_t *) pin, pin_data, sizeof(pin_data));
|
||||
if (r != PICOKEY_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
low_flash_available();
|
||||
}
|
||||
if (pka_enabled() == false) {
|
||||
isUserAuthenticated = true;
|
||||
}
|
||||
if (pin == file_pin1) {
|
||||
hash_multi(data, len, session_pin);
|
||||
pin_derive_session(data, len, session_pin);
|
||||
has_session_pin = true;
|
||||
}
|
||||
else if (pin == file_sopin) {
|
||||
hash_multi(data, len, session_sopin);
|
||||
pin_derive_session(data, len, session_sopin);
|
||||
has_session_sopin = true;
|
||||
}
|
||||
if (pending_save_dkek != 0xff) {
|
||||
@@ -714,7 +717,6 @@ int load_private_key_ecdh(mbedtls_ecp_keypair *ctx, file_t *fkey) {
|
||||
#define INS_KEY_DOMAIN 0x52
|
||||
#define INS_PUK_AUTH 0x54
|
||||
#define INS_LIST_KEYS 0x58
|
||||
#define INS_SESSION_PIN 0x5A
|
||||
#define INS_DECRYPT_ASYM 0x62
|
||||
#define INS_EXTRAS 0x64
|
||||
#define INS_SIGNATURE 0x68
|
||||
@@ -755,7 +757,6 @@ static const cmd_t cmds[] = {
|
||||
{ INS_EXTRAS, cmd_extras },
|
||||
{ INS_MSE, cmd_mse },
|
||||
{ INS_GENERAL_AUTHENTICATE, cmd_general_authenticate },
|
||||
{ INS_SESSION_PIN, cmd_session_pin },
|
||||
{ INS_PUK_AUTH, cmd_puk_auth },
|
||||
{ INS_PSO, cmd_pso },
|
||||
{ INS_EXTERNAL_AUTHENTICATE, cmd_external_authenticate },
|
||||
@@ -763,7 +764,7 @@ static const cmd_t cmds[] = {
|
||||
{ 0x00, 0x0 }
|
||||
};
|
||||
|
||||
int sc_hsm_process_apdu() {
|
||||
int sc_hsm_process_apdu(void) {
|
||||
uint32_t ne = apdu.ne;
|
||||
int r = sm_unwrap();
|
||||
if (r != PICOKEY_OK) {
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
#define _SC_HSM_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef ESP_PLATFORM
|
||||
#include "common.h"
|
||||
#else
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
#endif
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
@@ -82,8 +78,6 @@ extern const uint8_t sc_hsm_aid[];
|
||||
|
||||
#define HSM_OPT_RRC 0x0001
|
||||
#define HSM_OPT_TRANSPORT_PIN 0x0002
|
||||
#define HSM_OPT_SESSION_PIN 0x0004
|
||||
#define HSM_OPT_SESSION_PIN_EXPL 0x000C
|
||||
#define HSM_OPT_REPLACE_PKA 0x0008
|
||||
#define HSM_OPT_COMBINED_AUTH 0x0010
|
||||
#define HSM_OPT_RRC_RESET_ONLY 0x0020
|
||||
@@ -108,27 +102,59 @@ extern const uint8_t sc_hsm_aid[];
|
||||
|
||||
extern int pin_reset_retries(const file_t *pin, bool);
|
||||
extern int pin_wrong_retry(const file_t *pin);
|
||||
extern void select_file(file_t *pe);
|
||||
|
||||
extern void hash(const uint8_t *input, uint16_t len, uint8_t output[32]);
|
||||
extern uint16_t get_device_options();
|
||||
extern int add_cert_puk_store(const uint8_t *data, uint16_t data_len, bool copy);
|
||||
extern int parse_token_info(const file_t *f, int mode);
|
||||
extern int parse_ef_dir(const file_t *f, int mode);
|
||||
extern void scan_all(void);
|
||||
extern void reset_puk_store(void);
|
||||
extern uint16_t get_device_options(void);
|
||||
extern bool has_session_pin, has_session_sopin;
|
||||
extern uint8_t session_pin[32], session_sopin[32];
|
||||
extern uint16_t check_pin(const file_t *pin, const uint8_t *data, uint16_t len);
|
||||
extern bool pka_enabled();
|
||||
extern bool pka_enabled(void);
|
||||
extern const uint8_t *dev_name;
|
||||
extern uint16_t dev_name_len;
|
||||
extern uint8_t puk_status[MAX_PUK];
|
||||
extern int puk_store_select_chr(const uint8_t *chr);
|
||||
extern int delete_file(file_t *ef);
|
||||
extern const uint8_t *get_meta_tag(file_t *ef, uint16_t meta_tag, uint16_t *tag_len);
|
||||
extern bool key_has_purpose(file_t *ef, uint8_t purpose);
|
||||
extern int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey);
|
||||
extern int load_private_key_ec(mbedtls_ecp_keypair *ctx, file_t *fkey);
|
||||
extern int load_private_key_ecdh(mbedtls_ecp_keypair *ctx, file_t *fkey);
|
||||
extern bool wait_button_pressed();
|
||||
extern bool wait_button_pressed(void);
|
||||
extern int store_keys(void *key_ctx, int type, uint8_t key_id);
|
||||
extern int find_and_store_meta_key(uint8_t key_id);
|
||||
extern uint32_t get_key_counter(file_t *fkey);
|
||||
extern uint32_t decrement_key_counter(file_t *fkey);
|
||||
extern int cmd_select(void);
|
||||
extern int cmd_list_keys(void);
|
||||
extern int cmd_read_binary(void);
|
||||
extern int cmd_verify(void);
|
||||
extern int cmd_reset_retry(void);
|
||||
extern int cmd_challenge(void);
|
||||
extern int cmd_external_authenticate(void);
|
||||
extern int cmd_mse(void);
|
||||
extern int cmd_initialize(void);
|
||||
extern int cmd_key_domain(void);
|
||||
extern int cmd_key_wrap(void);
|
||||
extern int cmd_keypair_gen(void);
|
||||
extern int cmd_update_ef(void);
|
||||
extern int cmd_delete_file(void);
|
||||
extern int cmd_change_pin(void);
|
||||
extern int cmd_key_gen(void);
|
||||
extern int cmd_signature(void);
|
||||
extern int cmd_key_unwrap(void);
|
||||
extern int cmd_decrypt_asym(void);
|
||||
extern int cmd_cipher_sym(void);
|
||||
extern int cmd_derive_asym(void);
|
||||
extern int cmd_extras(void);
|
||||
extern int cmd_general_authenticate(void);
|
||||
extern int cmd_puk_auth(void);
|
||||
extern int cmd_pso(void);
|
||||
extern int cmd_bip_slip(void);
|
||||
extern uint8_t get_key_domain(file_t *fkey);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define HSM_VERSION 0x0604
|
||||
#define HSM_VERSION 0x0606
|
||||
|
||||
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||
|
||||
Binary file not shown.
@@ -23,15 +23,15 @@ def test_select(device):
|
||||
device.select_applet()
|
||||
|
||||
def test_initialization(device):
|
||||
device.initialize(no_dev_cert=True)
|
||||
device.initialize()
|
||||
|
||||
def test_termca(device):
|
||||
data = device.get_termca()
|
||||
assert(b'ESPICOHSMTR' == data['cv']['chr'][:11])
|
||||
assert(b'ESPICOHSMDV' == data['cv']['car'][:11] or b'ESPICOHSMTR' == data['cv']['car'][:11])
|
||||
assert(b'ESPICOHSMTR' == data['dev']['chr'][:11])
|
||||
assert(b'ESPICOHSMDV' == data['dev']['car'][:11] or b'ESPICOHSMTR' == data['dev']['car'][:11])
|
||||
assert(b'ESPICOHSMDV' == data['dv']['chr'][:11] or b'ESPICOHSMTR' == data['dv']['chr'][:11])
|
||||
assert(b'ESPICOHSMCA' == data['dv']['car'][:11] or b'ESPICOHSMTR' == data['dv']['car'][:11])
|
||||
assert(data['cv']['car'] == data['dv']['chr'])
|
||||
assert(data['dev']['car'] == data['dv']['chr'])
|
||||
|
||||
def test_get_version(device):
|
||||
version = device.get_version()
|
||||
|
||||
@@ -27,7 +27,7 @@ KEY_DOMAINS = 3
|
||||
TEST_KEY_DOMAIN = 1
|
||||
|
||||
def test_key_domains(device):
|
||||
device.initialize(key_domains=KEY_DOMAINS, no_dev_cert=True)
|
||||
device.initialize(key_domains=KEY_DOMAINS)
|
||||
for k in range(KEY_DOMAINS):
|
||||
kd = device.get_key_domain(key_domain=k)
|
||||
assert('error' in kd)
|
||||
|
||||
@@ -23,7 +23,7 @@ from picohsm.const import DEFAULT_DKEK_SHARES, DEFAULT_PIN, DEFAULT_RETRIES
|
||||
from const import DEFAULT_DKEK
|
||||
|
||||
def test_dkek(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
device.login(DEFAULT_PIN)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
assert('dkek' in resp)
|
||||
|
||||
@@ -24,16 +24,17 @@ from picohsm.const import DEFAULT_PIN, DEFAULT_RETRIES
|
||||
WRONG_PIN = '112233'
|
||||
|
||||
def test_pin_init_retries(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES)
|
||||
device.logout()
|
||||
retries = device.get_login_retries()
|
||||
assert(retries == DEFAULT_RETRIES)
|
||||
|
||||
def test_pin_login(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES)
|
||||
device.login(DEFAULT_PIN)
|
||||
|
||||
def test_pin_retries(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES)
|
||||
device.login(DEFAULT_PIN)
|
||||
|
||||
for ret in range(DEFAULT_RETRIES-1):
|
||||
@@ -45,7 +46,8 @@ def test_pin_retries(device):
|
||||
device.login(WRONG_PIN)
|
||||
assert(e.value.sw == SWCodes.SW_PIN_BLOCKED)
|
||||
|
||||
device.initialize(retries=DEFAULT_RETRIES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES)
|
||||
device.logout()
|
||||
retries = device.get_login_retries()
|
||||
assert(retries == DEFAULT_RETRIES)
|
||||
|
||||
|
||||
131
tests/pico-hsm/test_011_security_regressions.py
Normal file
131
tests/pico-hsm/test_011_security_regressions.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from picokey import APDUResponse, SWCodes
|
||||
from picohsm.DO import DOPrefixes
|
||||
from picohsm.const import DEFAULT_PIN
|
||||
|
||||
|
||||
def raw_send(device, command, cla=0x00, p1=0x00, p2=0x00, data=None, ne=None):
|
||||
# Use low-level transport to avoid automatic PIN retry/login behavior.
|
||||
return device._PicoHSM__card.send(command=command, cla=cla, p1=p1, p2=p2, data=data, ne=ne, codes=[])
|
||||
|
||||
|
||||
def read_binary_raw(device, fid):
|
||||
return raw_send(
|
||||
device,
|
||||
command=0xB1,
|
||||
p1=(fid >> 8) & 0xFF,
|
||||
p2=fid & 0xFF,
|
||||
data=[0x54, 0x02, 0x00, 0x00],
|
||||
ne=0,
|
||||
)
|
||||
|
||||
|
||||
def test_01_protected_data_requires_pin_for_read(device):
|
||||
fid = (DOPrefixes.PROT_DATA_PREFIX << 8) | 0x01
|
||||
payload = b"protected-regression"
|
||||
|
||||
device.initialize()
|
||||
device.login(DEFAULT_PIN)
|
||||
device.put_contents(p1=fid, data=payload)
|
||||
device.logout()
|
||||
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
read_binary_raw(device, fid)
|
||||
assert e.value.sw == SWCodes.SW_SECURITY_STATUS_NOT_SATISFIED
|
||||
|
||||
device.login(DEFAULT_PIN)
|
||||
data, sw = read_binary_raw(device, fid)
|
||||
assert sw == 0x9000
|
||||
assert bytes(data) == payload
|
||||
|
||||
|
||||
def test_02_static_sensitive_files_are_not_readable(device):
|
||||
device.initialize()
|
||||
device.logout()
|
||||
|
||||
for fid in (0x1081, 0x100E, 0x100A, 0x100B):
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
read_binary_raw(device, fid)
|
||||
assert e.value.sw == SWCodes.SW_SECURITY_STATUS_NOT_SATISFIED
|
||||
|
||||
|
||||
def test_03_key_object_readout_is_blocked_even_when_authenticated(device):
|
||||
# #3 depends on #2 class of bug: private key material must not be readable.
|
||||
# KEY_PREFIX objects are blocked by policy for READ BINARY.
|
||||
device.initialize()
|
||||
device.logout()
|
||||
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
read_binary_raw(device, 0xCC00) # EF_KEY_DEV
|
||||
assert e.value.sw in (SWCodes.SW_SECURITY_STATUS_NOT_SATISFIED, SWCodes.SW_FILE_NOT_FOUND)
|
||||
|
||||
device.login(DEFAULT_PIN)
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
read_binary_raw(device, 0xCC00) # EF_KEY_DEV
|
||||
assert e.value.sw in (SWCodes.SW_SECURITY_STATUS_NOT_SATISFIED, SWCodes.SW_FILE_NOT_FOUND)
|
||||
|
||||
|
||||
def test_04_otp_extra_command_is_not_available(device):
|
||||
# #4: OTP command path was removed.
|
||||
device.initialize()
|
||||
device.login(DEFAULT_PIN)
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
raw_send(device, cla=0x80, command=0x64, p1=0x4C, p2=0x00, data=[0x00, 0x00])
|
||||
assert e.value.sw == SWCodes.SW_INCORRECT_P1P2
|
||||
|
||||
|
||||
def test_04_session_pin_instruction_removed(device):
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
raw_send(device, command=0x5A, p1=0x01, p2=0x81)
|
||||
assert e.value.sw1 == 0x6D and e.value.sw2 == 0x00
|
||||
|
||||
|
||||
def test_06_update_ef_rejects_out_of_bounds_offset(device):
|
||||
fid = (DOPrefixes.DATA_PREFIX << 8) | 0x10
|
||||
device.initialize()
|
||||
device.login(DEFAULT_PIN)
|
||||
device.put_contents(p1=fid, data=b"0123456789abcdef")
|
||||
|
||||
# offset=4030, len=8 => 4038 (>4032) must be rejected.
|
||||
data = [0x54, 0x02, 0x0F, 0xBE, 0x53, 0x08] + [0xAA] * 8
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
raw_send(device, command=0xD7, p1=(fid >> 8) & 0xFF, p2=fid & 0xFF, data=data)
|
||||
assert e.value.sw1 == 0x67 and e.value.sw2 == 0x00
|
||||
|
||||
|
||||
def test_07_secure_messaging_requires_valid_mac(device):
|
||||
device.initialize()
|
||||
device.logout()
|
||||
|
||||
# GA must fail without an authenticated session.
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
device.general_authentication()
|
||||
assert e.value.sw1 == 0x64 and e.value.sw2 == 0x00
|
||||
|
||||
# After PIN verification, GA should be available and SM can be established.
|
||||
device.login(DEFAULT_PIN)
|
||||
device.general_authentication()
|
||||
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
raw_send(device, command=0x84, cla=0x0C, data=[0x97, 0x01, 0x10], ne=0)
|
||||
assert e.value.sw1 == 0x69 and e.value.sw2 in (0x84, 0x87, 0x88)
|
||||
@@ -21,7 +21,7 @@ import pytest
|
||||
from picohsm import KeyType, DOPrefixes
|
||||
|
||||
def test_gen_initialize(device):
|
||||
device.initialize(no_dev_cert=True)
|
||||
device.initialize()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"curve", ['secp192r1', 'secp256r1', 'secp384r1', 'secp521r1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp192k1', 'secp256k1', 'curve25519', 'curve448', 'ed25519', 'ed448']
|
||||
|
||||
@@ -27,7 +27,7 @@ from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
|
||||
from const import DEFAULT_DKEK
|
||||
|
||||
def test_prepare_dkek(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
||||
|
||||
@@ -25,7 +25,7 @@ from picohsm.const import DEFAULT_RETRIES, DEFAULT_DKEK_SHARES
|
||||
from const import DEFAULT_DKEK
|
||||
|
||||
def test_prepare_dkek(device):
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(retries=DEFAULT_RETRIES, dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
kcv = hashlib.sha256(b'\x00'*32).digest()[:8]
|
||||
|
||||
@@ -29,7 +29,7 @@ from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
def test_initialize(device):
|
||||
device.initialize(key_domains=1, no_dev_cert=True)
|
||||
device.initialize(key_domains=1)
|
||||
assert(device.get_key_domains() == 1)
|
||||
|
||||
device.set_key_domain(key_domain=0, total=2)
|
||||
|
||||
@@ -27,7 +27,7 @@ from const import DEFAULT_DKEK
|
||||
MESSAGE = b'a secret message'
|
||||
|
||||
def test_prepare_aes(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ MESSAGE = b'a secret message'
|
||||
AAD = b'this is a tag for AAD'
|
||||
|
||||
def test_prepare_chachapoly(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ MESSAGE = b'a secret message'
|
||||
AAD = b'this is a tag for AAD'
|
||||
|
||||
def test_prepare_aes(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ from const import DEFAULT_DKEK
|
||||
MESSAGE = b'a secret message'
|
||||
|
||||
def test_prepare_aes(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
||||
INFO = b'info message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
||||
INFO = b'info message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from picohsm import DOPrefixes
|
||||
INFO = b'shared message'
|
||||
|
||||
def test_prepare_kd(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ AUT_PUK = unhexlify('678201ed7f218201937f4e82014b5f290100421045535049434f48534d5
|
||||
term_chr = CVC().decode(TERM_CERT).chr()
|
||||
|
||||
def test_initialize(device):
|
||||
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=False)
|
||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
||||
device.logout()
|
||||
|
||||
def test_register_puk(device):
|
||||
@@ -102,7 +102,7 @@ def test_enumerate_puk_1(device):
|
||||
assert(puks[0]['status'] == 0)
|
||||
|
||||
def test_enumerate_puk_2(device):
|
||||
device.initialize(puk_auts=2, puk_min_auts=1, no_dev_cert=True)
|
||||
device.initialize(puk_auts=2, puk_min_auts=1)
|
||||
puks = device.enumerate_puk()
|
||||
assert(len(puks) == 2)
|
||||
assert(puks[0]['status'] == -1)
|
||||
@@ -115,7 +115,7 @@ def test_enumerate_puk_2(device):
|
||||
assert(puks[1]['status'] == -1)
|
||||
|
||||
def test_register_more_puks(device):
|
||||
device.initialize(puk_auts=2, puk_min_auts=1, no_dev_cert=True)
|
||||
device.initialize(puk_auts=2, puk_min_auts=1)
|
||||
status = device.get_puk_status()
|
||||
assert(status == bytes([2,2,1,0]))
|
||||
|
||||
@@ -123,14 +123,14 @@ def test_register_more_puks(device):
|
||||
assert(status == bytes([2,1,1,0]))
|
||||
|
||||
def test_is_pku(device):
|
||||
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=True)
|
||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
||||
assert(device.is_puk() == True)
|
||||
|
||||
device.initialize(no_dev_cert=True)
|
||||
device.initialize()
|
||||
assert(device.is_puk() == False)
|
||||
|
||||
def test_check_puk_key(device):
|
||||
device.initialize(puk_auts=1, puk_min_auts=1, no_dev_cert=True)
|
||||
device.initialize(puk_auts=1, puk_min_auts=1)
|
||||
status = device.check_puk_key(term_chr)
|
||||
assert(status == -1)
|
||||
|
||||
@@ -140,7 +140,7 @@ def test_check_puk_key(device):
|
||||
|
||||
|
||||
def test_register_puk_with_no_puk(device):
|
||||
device.initialize(no_dev_cert=True)
|
||||
device.initialize()
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
device.register_puk(AUT_PUK, TERM_CERT, DICA_CERT)
|
||||
assert(e.value.sw == SWCodes.SW_FILE_NOT_FOUND)
|
||||
|
||||
@@ -31,14 +31,10 @@ from picokey import APDUResponse, SWCodes
|
||||
KDM = unhexlify(b'30820420060b2b0601040181c31f0402016181ed7f2181e97f4e81a25f290100421045535049434f48534d434130303030327f494f060a04007f00070202020203864104e66b473ec328caf39eaed840f9c7a4ba237e1dd19004861fa3f4f134bd2d5ea5f71c6c2e6321add4c8a7793ba41119c5783f48a5d9dfc0898d9ae9e7b14da8d65f201045535049434f48534d445630303030327f4c12060904007f000703010202530580000000045f25060205000400065f24060206000400065f3740a645594c6c338cd6bda6cad039cee54fd822b1011c0af1e4e3a2a6d03d43bdbb8be68a66a8757e7b1f963589bdd80d8e65de5055b722609041ec63f0498ddc8b6281e97f2181e57f4e819e5f290100421045535049434f48534d445630303030327f494f060a04007f000702020202038641043359f5234ce62e0eb80460046d8fd1aae018cc8b9e687b40aa2c047e352409b45153d1ad888e4e7e780a3b1fa8c69ca8998bd271c8849137149142e96816a5a45f201045535049434f48534d54524a5a58314a7f4c0e060904007f0007030102025301005f25060205010102085f24060206010102085f37409add1c1c8a05e7bc56a8bd846c9122d9214cc43c86b6952a961dce525d830a58130cbb275e9408af38dc16160f958d2b9ac6ac4f0f1b9b863284f00121d447ce638201f1678201ed7f218201937f4e82014b5f290100421045535049434f48534d54524a5a58314a7f4982011d060a04007f000702020202038120a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e537782207d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9832026dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b68441048bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f0469978520a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a78641049de55b50b921de72bbf740d3518905ff893e8208cfe8d144de34d79da3645d1c0cb551a19d6e6a5fee050e479a65d36fdf638af741e52dad4df9960b8ed443d18701015f201045535049434f48534d54524a5a58314a5f374099dede270b9a2def89a4d12dc0314e6289bd565808683f362e9f9ac9554ec5113bf7e412ecc386af12d2a9b43f27e54e10dfc6d8f2d6b618b1776459c13c0bec421045535049434f48534d54524a5a58314a5f3740459f6385f28a84f1c57f421a7f6cb4f1177084497321be94c87998c2e01af0202bab6984411cde1aab34e4e59cc27961b85855bae6340305281ff838253b0f3554404b6a2fe6947faa91f6ffa0d707cd4cbb43192935f561be137f4b3680304fc28b41210b671b8b033e06b4ad720010bcd36b92282844616261f944f3c4f67bfda5')
|
||||
|
||||
def test_initialize(device):
|
||||
device.initialize(key_domains=1, no_dev_cert=True)
|
||||
device.initialize(key_domains=1)
|
||||
device.logout()
|
||||
|
||||
def test_create_xkek(device):
|
||||
with pytest.raises(APDUResponse) as e:
|
||||
device.create_xkek(KDM)
|
||||
assert(e.value.sw == SWCodes.SW_CONDITIONS_NOT_SATISFIED)
|
||||
|
||||
device.login()
|
||||
kcv, did = device.create_xkek(KDM)
|
||||
assert(kcv == b'\x00'*8)
|
||||
|
||||
@@ -37,7 +37,7 @@ def sha256_sha256(data):
|
||||
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
|
||||
|
||||
def test_initialize(device):
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES, no_dev_cert=True)
|
||||
device.initialize(dkek_shares=DEFAULT_DKEK_SHARES)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
resp = device.import_dkek(DEFAULT_DKEK)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ for alg in ${algs[*]}; do
|
||||
grep -q "Key ref[[:blank:]]*: 10" <<< $e && exit $? || echo -e ".\t${OK}"
|
||||
echo -n " Unwrap key..."
|
||||
sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force > /dev/null 2>&1
|
||||
test $? -eq 0 && echo -n "." || exit $?
|
||||
echo -n "." || exit $?
|
||||
e=$(pkcs15-tool -D 2>&1)
|
||||
grep -q "Key ref[[:blank:]]*: 10" <<< $e && echo -e ".\t${OK}" || exit $?
|
||||
echo -n " Cleaning..."
|
||||
|
||||
@@ -21,7 +21,7 @@ gen_and_check() {
|
||||
glabel="EC_POINT 512 bits"
|
||||
;;
|
||||
*"521"*)
|
||||
glabel="EC_POINT 528 bits"
|
||||
glabel="EC_POINT 52"
|
||||
;;
|
||||
*"rsa"*)
|
||||
IFS=: read -r v1 bits <<< "$1"
|
||||
|
||||
@@ -50,6 +50,13 @@ test $? -eq 0 || {
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "==== Test PKCS11 security regressions ===="
|
||||
./tests/scripts/pkcs11_security_regressions.sh
|
||||
test $? -eq 0 || {
|
||||
echo -e "\t${FAIL}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "==== Test backup and restore ===="
|
||||
./tests/scripts/backup.sh
|
||||
test $? -eq 0 || {
|
||||
|
||||
56
tests/scripts/pkcs11_security_regressions.sh
Executable file
56
tests/scripts/pkcs11_security_regressions.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
source ./tests/scripts/func.sh
|
||||
|
||||
TMP_SIGN_DATA=".pkcs11_sec_reg_data"
|
||||
TMP_PRIV_DATA=".pkcs11_sec_reg_priv_data"
|
||||
TMP_SIG_OUT=".pkcs11_sec_reg.sig"
|
||||
|
||||
cleanup() {
|
||||
rm -f "$TMP_SIGN_DATA" "$TMP_PRIV_DATA" "$TMP_SIG_OUT"
|
||||
pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 || true
|
||||
pkcs11-tool -l --pin 648219 --delete-object --type data --label 'sec_priv_data' > /dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
reset
|
||||
test $? -eq 0 || exit $?
|
||||
|
||||
echo "security regression data" > "$TMP_SIGN_DATA"
|
||||
|
||||
echo -n " Security regression: private key operation requires login..."
|
||||
pkcs11-tool -l --pin 648219 --keypairgen --key-type rsa:2048 --id 1 --label "SecRegression" > /dev/null 2>&1
|
||||
test $? -eq 0 && echo -n "." || exit $?
|
||||
e=$(pkcs11-tool --id 1 --sign --mechanism RSA-PKCS -i "$TMP_SIGN_DATA" -o "$TMP_SIG_OUT" 2>&1)
|
||||
test $? -ne 0 && echo -n "." || exit $?
|
||||
(
|
||||
grep -q "CKR_USER_NOT_LOGGED_IN" <<< "$e" ||
|
||||
grep -q "CKR_PIN_REQUIRED" <<< "$e" ||
|
||||
grep -q "util_getpass error" <<< "$e"
|
||||
) && echo -e ".\t${OK}" || exit $?
|
||||
|
||||
echo -n " Security regression: private key material is not exportable..."
|
||||
e=$(pkcs11-tool --read-object --type privkey --id 1 --pin 648219 2>&1)
|
||||
test $? -eq 0 && echo -n "." || exit $?
|
||||
(
|
||||
grep -q "CKR_ATTRIBUTE_SENSITIVE" <<< "$e" ||
|
||||
grep -q "CKR_ACTION_PROHIBITED" <<< "$e" ||
|
||||
grep -q "reading private keys not (yet) supported" <<< "$e" ||
|
||||
grep -q "error: object not found" <<< "$e"
|
||||
) && echo -e ".\t${OK}" || exit $?
|
||||
|
||||
echo -n " Security regression: private data object cannot be read without login..."
|
||||
echo "private data regression" > "$TMP_PRIV_DATA"
|
||||
pkcs11-tool --pin 648219 --write-object "$TMP_PRIV_DATA" --type data --id 2 --label 'sec_priv_data' --private > /dev/null 2>&1
|
||||
test $? -eq 0 && echo -n "." || exit $?
|
||||
e=$(pkcs11-tool --read-object --type data --label 'sec_priv_data' 2>&1)
|
||||
test $? -eq 1 && echo -n "." || exit $?
|
||||
(
|
||||
grep -q "error: object not found" <<< "$e" ||
|
||||
grep -q "CKR_USER_NOT_LOGGED_IN" <<< "$e" ||
|
||||
grep -q "CKR_PIN_REQUIRED" <<< "$e"
|
||||
) && echo -n "." || exit $?
|
||||
e=$(pkcs11-tool --read-object --type data --label 'sec_priv_data' --pin 648219 2>&1)
|
||||
test $? -eq 0 && echo -n "." || exit $?
|
||||
grep -q "private data regression" <<< "$e" && echo -e ".\t${OK}" || exit $?
|
||||
Reference in New Issue
Block a user