diff --git a/CMakeLists.txt b/CMakeLists.txt index 79ecbfa..49b0567 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,8 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/hash_utils.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c diff --git a/src/hsm/dkek.c b/src/hsm/dkek.c new file mode 100644 index 0000000..0cd5f06 --- /dev/null +++ b/src/hsm/dkek.c @@ -0,0 +1,473 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "common.h" +#include "stdlib.h" +#include "pico/stdlib.h" +#include "dkek.h" +#include "hash_utils.h" +#include "random.h" +#include "sc_hsm.h" +#include "mbedtls/md.h" +#include "mbedtls/cmac.h" +#include "mbedtls/rsa.h" +#include "mbedtls/ecdsa.h" + +static uint8_t dkek[IV_SIZE+32]; +static uint8_t tmp_dkek[32]; +extern bool has_session_pin; +extern uint8_t session_pin[32]; + +int load_dkek() { + if (has_session_pin == false) + return HSM_NO_LOGIN; + file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); + if (!tf) + return HSM_ERR_FILE_NOT_FOUND; + memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32); + int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32); + if (ret != 0) + return HSM_EXEC_ERROR; + return HSM_OK; +} + +void release_dkek() { + memset(dkek, 0, sizeof(dkek)); +} + +void init_dkek() { + release_dkek(); + memset(tmp_dkek, 0, sizeof(tmp_dkek)); +} + +int store_dkek_key() { + aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32); + file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); + if (!tf) + return HSM_ERR_FILE_NOT_FOUND; + flash_write_data_to_file(tf, dkek, sizeof(dkek)); + low_flash_available(); + release_dkek(); + return HSM_OK; +} + +int save_dkek_key(const uint8_t *key) { + const uint8_t *iv = random_bytes_get(32); + memcpy(dkek, iv, IV_SIZE); + if (!key) + key = tmp_dkek; + memcpy(dkek+IV_SIZE, key, 32); + return store_dkek_key(); +} + +void import_dkek_share(const uint8_t *share) { + for (int i = 0; i < 32; i++) + tmp_dkek[i] ^= share[i]; +} + +int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes + uint8_t hsh[32]; + int r = load_dkek(); + if (r != HSM_OK) + return r; + hash256(dkek+IV_SIZE, 32, hsh); + release_dkek(); + memcpy(kcv, hsh, 8); +} + +int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes + uint8_t buf[32+4]; + int r = load_dkek(); + if (r != HSM_OK) + return r; + memcpy(buf, dkek+IV_SIZE, 32); + release_dkek(); + memcpy(buf+32, "\x0\x0\x0\x1", 4); + hash256(buf, sizeof(buf), kenc); + memset(buf, 0, sizeof(buf)); + return HSM_OK; +} + +int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes + uint8_t buf[32+4]; + int r = load_dkek(); + if (r != HSM_OK) + return r; + memcpy(buf, dkek+IV_SIZE, 32); + release_dkek(); + memcpy(buf+32, "\x0\x0\x0\x2", 4); + hash256(buf, sizeof(buf), kmac); + memset(buf, 0, sizeof(buf)); + return HSM_OK; +} + +int dkek_encrypt(uint8_t *data, size_t len) { + int r; + if ((r = load_dkek()) != HSM_OK) + return r; + r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); + release_dkek(); + return r; +} + +int dkek_decrypt(uint8_t *data, size_t len) { + int r; + if ((r = load_dkek()) != HSM_OK) + return r; + r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); + release_dkek(); + return r; +} + +int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) { + if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES)) + return HSM_WRONG_DATA; + + uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding) + memset(kb, 0, sizeof(kb)); + int kb_len = 0; + uint8_t *algo = NULL; + uint8_t algo_len = 0; + uint8_t *allowed = NULL; + uint8_t allowed_len = 0; + uint8_t kenc[32]; + memset(kenc, 0, sizeof(kenc)); + dkek_kenc(kenc); + + uint8_t kcv[8]; + memset(kcv, 0, sizeof(kcv)); + dkek_kcv(kcv); + + uint8_t kmac[32]; + memset(kmac, 0, sizeof(kmac)); + dkek_kmac(kmac); + + if (key_type & HSM_KEY_AES) { + if (key_type & HSM_KEY_AES_128) + kb_len = 16; + else if (key_type & HSM_KEY_AES_192) + kb_len = 24; + else if (key_type & HSM_KEY_AES_256) + kb_len = 32; + + if (kb_len != 16 && kb_len != 24 && kb_len != 32) + return HSM_WRONG_DATA; + if (*out_len < 8+1+10+6+4+(2+32+14)+16) + return HSM_WRONG_LENGTH; + + put_uint16_t(kb_len, kb+8); + memcpy(kb+10, key_ctx, kb_len); + kb_len += 2; + + algo = "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8) + algo_len = 10; + allowed = "\x00\x04\x10\x11\x18\x99"; //(2+4) + allowed_len = 6; + } + else if (key_type & HSM_KEY_RSA) { + if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading + return HSM_WRONG_LENGTH; + mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; + kb_len = 0; + put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2; + + put_uint16_t(mbedtls_mpi_size(&rsa->D), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&rsa->D, kb+8+kb_len, mbedtls_mpi_size(&rsa->D)); kb_len += mbedtls_mpi_size(&rsa->D); + put_uint16_t(mbedtls_mpi_size(&rsa->N), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&rsa->N, kb+8+kb_len, mbedtls_mpi_size(&rsa->N)); kb_len += mbedtls_mpi_size(&rsa->N); + put_uint16_t(mbedtls_mpi_size(&rsa->E), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&rsa->E, kb+8+kb_len, mbedtls_mpi_size(&rsa->E)); kb_len += mbedtls_mpi_size(&rsa->E); + + algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02"; + algo_len = 12; + } + else if (key_type & HSM_KEY_EC) { + if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading + return HSM_WRONG_LENGTH; + mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; + kb_len = 0; + put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2; + put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.A), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&ecdsa->grp.A, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.A)); kb_len += mbedtls_mpi_size(&ecdsa->grp.A); + put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.B), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&ecdsa->grp.B, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.B)); kb_len += mbedtls_mpi_size(&ecdsa->grp.B); + put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&ecdsa->grp.P, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.P)); kb_len += mbedtls_mpi_size(&ecdsa->grp.P); + put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.N), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&ecdsa->grp.N, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.N)); kb_len += mbedtls_mpi_size(&ecdsa->grp.N); + put_uint16_t(1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.Y), kb+8+kb_len); kb_len += 2; + kb[8+kb_len++] = 0x4; + mbedtls_mpi_write_binary(&ecdsa->grp.G.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.X)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.X); + mbedtls_mpi_write_binary(&ecdsa->grp.G.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.Y)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.Y); + put_uint16_t(mbedtls_mpi_size(&ecdsa->d), kb+8+kb_len); kb_len += 2; + mbedtls_mpi_write_binary(&ecdsa->d, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->d)); kb_len += mbedtls_mpi_size(&ecdsa->d); + put_uint16_t(1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.Y), kb+8+kb_len); kb_len += 2; + kb[8+kb_len++] = 0x4; + mbedtls_mpi_write_binary(&ecdsa->Q.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.X)); kb_len += mbedtls_mpi_size(&ecdsa->Q.X); + mbedtls_mpi_write_binary(&ecdsa->Q.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.Y)); kb_len += mbedtls_mpi_size(&ecdsa->Q.Y); + + algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03"; + algo_len = 12; + } + memset(out, 0, *out_len); + *out_len = 0; + + memcpy(out+*out_len, kcv, 8); + *out_len += 8; + + if (key_type & HSM_KEY_AES) + out[*out_len] = 15; + else if (key_type & HSM_KEY_RSA) + out[*out_len] = 5; + else if (key_type & HSM_KEY_EC) + out[*out_len] = 12; + *out_len += 1; + + if (algo) { + memcpy(out+*out_len, algo, algo_len); + *out_len += algo_len; + } + else + *out_len += 2; + + if (allowed) { + memcpy(out+*out_len, allowed, allowed_len); + *out_len += allowed_len; + } + else + *out_len += 2; + //add 4 zeros + *out_len += 4; + + memcpy(kb, random_bytes_get(8), 8); + kb_len += 8; //8 random bytes + int kb_len_pad = ((int)(kb_len/16))*16; + if (kb_len % 16 > 0) + kb_len_pad = ((int)(kb_len/16)+1)*16; + //key already copied at kb+10 + if (kb_len < kb_len_pad) { + kb[kb_len] = 0x80; + } + int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad); + if (r != HSM_OK) + return r; + + memcpy(out+*out_len, kb, kb_len_pad); + *out_len += kb_len_pad; + + r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, out, *out_len, out+*out_len); + + *out_len += 16; + if (r != 0) + return r; + return HSM_OK; +} + +int dkek_type_key(const uint8_t *in) { + if (in[8] == 5 || in[8] == 6) + return HSM_KEY_RSA; + else if (in[8] == 12) + return HSM_KEY_EC; + else if (in[8] == 15) + return HSM_KEY_AES; + return 0x0; +} + +int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out) { + uint8_t kcv[8]; + memset(kcv, 0, sizeof(kcv)); + dkek_kcv(kcv); + + uint8_t kmac[32]; + memset(kmac, 0, sizeof(kmac)); + dkek_kmac(kmac); + + uint8_t kenc[32]; + memset(kenc, 0, sizeof(kenc)); + dkek_kenc(kenc); + + if (memcmp(kcv, in, 8) != 0) + return HSM_WRONG_DKEK; + + uint8_t signature[16]; + int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature); + if (r != 0) + return HSM_WRONG_SIGNATURE; + if (memcmp(signature, in+in_len-16, 16) != 0) + return HSM_WRONG_SIGNATURE; + + int key_type = in[8]; + if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15) + return HSM_WRONG_DATA; + + if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0) + return HSM_WRONG_DATA; + + if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0) + return HSM_WRONG_DATA; + + if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0) + return HSM_WRONG_DATA; + + size_t ofs = 9; + + //OID + size_t len = get_uint16_t(in, ofs); + ofs += len+2; + + //Allowed algorithms + len = get_uint16_t(in, ofs); + ofs += len+2; + + //Access conditions + len = get_uint16_t(in, ofs); + ofs += len+2; + + //Key OID + len = get_uint16_t(in, ofs); + ofs += len+2; + + if ((in_len-16-ofs) % 16 != 0) + return HSM_WRONG_PADDING; + uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding) + memset(kb, 0, sizeof(kb)); + memcpy(kb, in+ofs, in_len-16-ofs); + r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs); + if (r != HSM_OK) + return r; + + int key_size = get_uint16_t(kb, 8); + if (key_size_out) + *key_size_out = key_size; + ofs = 10; + if (key_type == 5 || key_type == 6) { + mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; + mbedtls_rsa_init(rsa); + if (key_type == 5) { + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len; + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_WRONG_DATA; + } + + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len; + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_WRONG_DATA; + } + } + else if (key_type == 6) { + //DP-1 + len = get_uint16_t(kb, ofs); ofs += len+2; + + //DQ-1 + len = get_uint16_t(kb, ofs); ofs += len+2; + + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len; + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_WRONG_DATA; + } + + //PQ + len = get_uint16_t(kb, ofs); ofs += len+2; + + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len; + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_WRONG_DATA; + } + //N + len = get_uint16_t(kb, ofs); ofs += len+2; + } + + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len; + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_WRONG_DATA; + } + + if (key_type == 5) { + r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E); + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_EXEC_ERROR; + } + } + else if (key_type == 6) { + r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E); + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_EXEC_ERROR; + } + } + + r = mbedtls_rsa_complete(rsa); + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_EXEC_ERROR; + } + r = mbedtls_rsa_check_privkey(rsa); + if (r != 0) { + mbedtls_rsa_free(rsa); + return HSM_EXEC_ERROR; + } + } + else if (key_type == 12) { + mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; + mbedtls_ecdsa_init(ecdsa); + + //A + len = get_uint16_t(kb, ofs); ofs += len+2; + + //B + len = get_uint16_t(kb, ofs); ofs += len+2; + + //P + len = get_uint16_t(kb, ofs); ofs += 2; + mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len); + if (ec_id == MBEDTLS_ECP_DP_NONE) { + mbedtls_ecdsa_free(ecdsa); + return HSM_WRONG_DATA; + } + ofs += len; + + //N + len = get_uint16_t(kb, ofs); ofs += len+2; + + //G + len = get_uint16_t(kb, ofs); ofs += len+2; + + //d + len = get_uint16_t(kb, ofs); ofs += 2; + r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len); + if (r != 0) { + mbedtls_ecdsa_free(ecdsa); + return HSM_EXEC_ERROR; + } + } + else if (key_type == 15) { + memcpy(key_ctx, kb+ofs, key_size); + } + return HSM_OK; +} \ No newline at end of file diff --git a/src/hsm/dkek.h b/src/hsm/dkek.h new file mode 100644 index 0000000..0fe7501 --- /dev/null +++ b/src/hsm/dkek.h @@ -0,0 +1,36 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _DKEK_H_ +#define _DKEK_H_ + +extern int load_dkek(); +extern int save_dkek_key(const uint8_t *key); +extern int store_dkek_key(); +extern void init_dkek(); +extern void release_dkek(); +extern void import_dkek_share(const uint8_t *share); +extern int dkek_kcv(uint8_t *kcv); +extern int dkek_encrypt(uint8_t *data, size_t len); +extern int dkek_decrypt(uint8_t *data, size_t len); +extern int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len); +extern int dkek_type_key(const uint8_t *in); +extern int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out); + +#define MAX_DKEK_ENCODE_KEY_BUFFER (8+1+12+6+(8+2*4+2*4096/8+3+13)+16) + +#endif diff --git a/src/hsm/hash_utils.c b/src/hsm/hash_utils.c new file mode 100644 index 0000000..9a665df --- /dev/null +++ b/src/hsm/hash_utils.c @@ -0,0 +1,142 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "mbedtls/md.h" +#include "mbedtls/sha256.h" +#include "mbedtls/aes.h" +#include "hash_utils.h" +#include "sc_hsm.h" +#include "libopensc/card-sc-hsm.h" + +void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) { + uint8_t o1[32]; + hash_multi(pin, len, o1); + for (int i = 0; i < sizeof(o1); i++) + o1[i] ^= pin[i%len]; + hash_multi(o1, sizeof(o1), output); +} + +void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) { + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + int iters = 256; + pico_unique_board_id_t unique_id; + + pico_get_unique_board_id(&unique_id); + + mbedtls_sha256_starts (&ctx, 0); + mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id)); + + while (iters > len) + { + mbedtls_sha256_update (&ctx, input, len); + iters -= len; + } + if (iters > 0) // remaining iterations + mbedtls_sha256_update (&ctx, input, iters); + mbedtls_sha256_finish (&ctx, output); + mbedtls_sha256_free (&ctx); +} + +void hash256(const uint8_t *input, size_t len, uint8_t output[32]) { + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + + mbedtls_sha256_starts (&ctx, 0); + mbedtls_sha256_update (&ctx, input, len); + + mbedtls_sha256_finish (&ctx, output); + mbedtls_sha256_free (&ctx); +} + +void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) { + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md); + mbedtls_md_setup(&ctx, md_info, 0); + mbedtls_md_starts(&ctx); + mbedtls_md_update(&ctx, input, len); + mbedtls_md_finish(&ctx, output); + mbedtls_md_free(&ctx); +} + +int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) { + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + uint8_t tmp_iv[IV_SIZE]; + size_t iv_offset = 0; + memset(tmp_iv, 0, IV_SIZE); + if (iv) + memcpy(tmp_iv, iv, IV_SIZE); + int r = mbedtls_aes_setkey_enc(&aes, key, key_size); + if (r != 0) + return HSM_EXEC_ERROR; + if (mode == HSM_AES_MODE_CBC) + return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data); + return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data); +} + +int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) { + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + uint8_t tmp_iv[IV_SIZE]; + size_t iv_offset = 0; + memset(tmp_iv, 0, IV_SIZE); + if (iv) + memcpy(tmp_iv, iv, IV_SIZE); + int r = mbedtls_aes_setkey_dec(&aes, key, key_size); + if (r != 0) + return HSM_EXEC_ERROR; + if (mode == HSM_AES_MODE_CBC) + return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data); + r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec + return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data); +} + +int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { + return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len); +} +int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { + return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len); +} + +struct ec_curve_mbed_id { + struct sc_lv_data curve; + mbedtls_ecp_group_id id; +}; +struct ec_curve_mbed_id ec_curves_mbed[] = { + { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 }, + { { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 }, + { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 }, + { { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 }, + { { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 }, + { { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 }, + { { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 }, + { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 }, + { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 }, + { { NULL, 0 }, MBEDTLS_ECP_DP_NONE } +}; + +mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) { + for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) { + if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) { + return ec->id; + } + } + return MBEDTLS_ECP_DP_NONE; +} \ No newline at end of file diff --git a/src/hsm/hash_utils.h b/src/hsm/hash_utils.h new file mode 100644 index 0000000..c411812 --- /dev/null +++ b/src/hsm/hash_utils.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _HASH_UTILS_H_ +#define _HASH_UTILS_H_ + +#include "stdlib.h" +#include "pico/stdlib.h" +#include "mbedtls/ecp.h" +#include "mbedtls/md.h" + +#define HSM_KEY_RSA 0x1 +#define HSM_KEY_EC 0x10 +#define HSM_KEY_AES 0x100 +#define HSM_KEY_AES_128 0x300 +#define HSM_KEY_AES_192 0x500 +#define HSM_KEY_AES_256 0x900 + +#define HSM_AES_MODE_CBC 1 +#define HSM_AES_MODE_CFB 2 + +extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]); +extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]); +extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]); +extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output); +extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len); +extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len); +extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len); +extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len); +extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len); + +#endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 060833d..c0a12f9 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -30,6 +30,8 @@ #include "mbedtls/hkdf.h" #include "version.h" #include "cvcerts.h" +#include "hash_utils.h" +#include "dkek.h" const uint8_t sc_hsm_aid[] = { 11, @@ -39,7 +41,6 @@ const uint8_t sc_hsm_aid[] = { uint8_t session_pin[32], session_sopin[32]; bool has_session_pin = false, has_session_sopin = false; static uint8_t dkeks = 0, current_dkeks = 0; -static uint8_t tmp_dkek[IV_SIZE+32]; static int sc_hsm_process_apdu(); @@ -73,49 +74,6 @@ int sc_hsm_unload() { return HSM_OK; } -static int encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) -{ - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - uint8_t tmp_iv[IV_SIZE]; - size_t iv_offset = 0; - memcpy(tmp_iv, iv, IV_SIZE); - int r = mbedtls_aes_setkey_enc (&aes, key, 256); - if (r != 0) - return HSM_EXEC_ERROR; - return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data); -} - -static int decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) -{ - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - uint8_t tmp_iv[IV_SIZE]; - size_t iv_offset = 0; - memcpy(tmp_iv, iv, IV_SIZE); - int r = mbedtls_aes_setkey_enc (&aes, key, 256); - if (r != 0) - return HSM_EXEC_ERROR; - return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data); -} - -int load_dkek() { - if (has_session_pin == false) - return HSM_NO_LOGIN; - file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); - if (!tf) - return HSM_ERR_FILE_NOT_FOUND; - memcpy(tmp_dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32); - int ret = decrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32); - if (ret != 0) - return HSM_EXEC_ERROR; - return HSM_OK; -} - -void release_dkek() { - memset(tmp_dkek, 0, sizeof(tmp_dkek)); -} - void select_file(file_t *pe) { if (!pe) { @@ -268,7 +226,7 @@ int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_ free(cvcbin); return r; } - hash(cvcbin, cvclen, hsh); + hash256(cvcbin, cvclen, hsh); free(cvcbin); return HSM_OK; } @@ -580,17 +538,13 @@ static int cmd_initialize() { } p += tag_len; } - p = random_bytes_get(32); - memset(tmp_dkek, 0, sizeof(tmp_dkek)); - memcpy(tmp_dkek, p, IV_SIZE); if (dkeks == 0) { - p = random_bytes_get(32); - memcpy(tmp_dkek+IV_SIZE, p, 32); - encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32); - file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); - flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek)); + int r = save_dkek_key(random_bytes_get(32)); + if (r != HSM_OK) + return SW_EXEC_ERROR(); } - low_flash_available(); + else + init_dkek(); } else { //free memory bytes request int heap_left = heapLeft(); @@ -606,59 +560,6 @@ static int cmd_initialize() { return SW_OK(); } -void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) { - uint8_t o1[32]; - hash_multi(pin, len, o1); - for (int i = 0; i < sizeof(o1); i++) - o1[i] ^= pin[i%len]; - hash_multi(o1, sizeof(o1), output); -} - -void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) -{ - mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - int iters = 256; - - pico_get_unique_board_id(&unique_id); - - mbedtls_sha256_starts (&ctx, 0); - mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id)); - - while (iters > len) - { - mbedtls_sha256_update (&ctx, input, len); - iters -= len; - } - if (iters > 0) // remaining iterations - mbedtls_sha256_update (&ctx, input, iters); - mbedtls_sha256_finish (&ctx, output); - mbedtls_sha256_free (&ctx); -} - -void hash(const uint8_t *input, size_t len, uint8_t output[32]) -{ - mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - - mbedtls_sha256_starts (&ctx, 0); - mbedtls_sha256_update (&ctx, input, len); - - mbedtls_sha256_finish (&ctx, output); - mbedtls_sha256_free (&ctx); -} - -void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) { - mbedtls_md_context_t ctx; - mbedtls_md_init(&ctx); - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md); - mbedtls_md_setup(&ctx, md_info, 0); - mbedtls_md_starts(&ctx); - mbedtls_md_update(&ctx, input, len); - mbedtls_md_finish(&ctx, output); - mbedtls_md_free(&ctx); -} - static int cmd_import_dkek() { //if (dkeks == 0) // return SW_COMMAND_NOT_ALLOWED(); @@ -671,107 +572,92 @@ static int cmd_import_dkek() { return SW_SECURITY_STATUS_NOT_SATISFIED(); } if (apdu.cmd_apdu_data_len > 0) { - for (int i = 0; i < apdu.cmd_apdu_data_len; i++) - tmp_dkek[IV_SIZE+i] ^= apdu.cmd_apdu_data[i]; + if (apdu.cmd_apdu_data_len < 32) + return SW_WRONG_LENGTH(); + import_dkek_share(apdu.cmd_apdu_data); if (++current_dkeks == dkeks) { - encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32); - flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek)); - memset(tmp_dkek, 0, sizeof(tmp_dkek)); - low_flash_available(); + if (save_dkek_key(NULL) != HSM_OK) + return SW_FILE_NOT_FOUND(); + } } res_APDU[0] = dkeks; res_APDU[1] = dkeks-current_dkeks; - //FNV hash - uint64_t hash = 0xcbf29ce484222325; - memcpy(tmp_dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32); - decrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32); - for (int i = 0; i < 32; i++) { - hash ^= tmp_dkek[IV_SIZE+i]; - hash *= 0x00000100000001B3; - } - memset(tmp_dkek, 0, sizeof(tmp_dkek)); - memcpy(res_APDU+2,&hash,sizeof(hash)); - res_APDU_size = 2+sizeof(hash); + dkek_kcv(res_APDU+2); + res_APDU_size = 2+8; return SW_OK(); } -struct ec_curve_mbed_id { - struct sc_lv_data curve; - mbedtls_ecp_group_id id; -}; -struct ec_curve_mbed_id ec_curves_mbed[] = { - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 }, - { { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 }, - { { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 }, - { { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 }, - { { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 }, - { { NULL, 0 }, MBEDTLS_ECP_DP_NONE } -}; - //Stores the private and public keys in flash int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) { int r, key_size; - uint8_t *asn1bin, *kdata; + uint8_t *asn1bin = NULL; size_t asn1len = 0; + uint8_t kdata[4096/8]; //worst case if (type == SC_PKCS15_TYPE_PRKEY_RSA) { mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; key_size = mbedtls_mpi_size(&rsa->P)+mbedtls_mpi_size(&rsa->Q); - kdata = (uint8_t *)calloc(1, key_size); mbedtls_mpi_write_binary(&rsa->P, kdata, key_size/2); mbedtls_mpi_write_binary(&rsa->Q, kdata+key_size/2, key_size/2); } - else { + else if (type == SC_PKCS15_TYPE_PRKEY_EC) { mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; key_size = mbedtls_mpi_size(&ecdsa->d); - kdata = (uint8_t *)calloc(1, key_size+1); kdata[0] = ecdsa->grp.id & 0xff; mbedtls_mpi_write_binary(&ecdsa->d, kdata+1, key_size); key_size++; } - if ((r = load_dkek()) != HSM_OK) + else if (type & HSM_KEY_AES) { + if (type == HSM_KEY_AES_128) + key_size = 16; + else if (type == HSM_KEY_AES_192) + key_size = 24; + else if (type == HSM_KEY_AES_256) + key_size = 32; + memcpy(kdata, key_ctx, key_size); + } + r = dkek_encrypt(kdata, key_size); + if (r != HSM_OK) { return r; - if ((r = encrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size)) != 0) - return r; - release_dkek(); + } file_t *fpk = file_new((KEY_PREFIX << 8) | key_id); + if (!fpk) + return SW_MEMORY_FAILURE(); r = flash_write_data_to_file(fpk, kdata, key_size); - free(kdata); if (r != HSM_OK) return r; //add_file_to_chain(fpk, &ef_kf); + if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC) { + struct sc_pkcs15_object *p15o = (struct sc_pkcs15_object *)calloc(1,sizeof (struct sc_pkcs15_object)); - struct sc_pkcs15_object *p15o = (struct sc_pkcs15_object *)calloc(1,sizeof (struct sc_pkcs15_object)); + sc_pkcs15_prkey_info_t *prkd = (sc_pkcs15_prkey_info_t *)calloc(1, sizeof (sc_pkcs15_prkey_info_t)); + memset(prkd, 0, sizeof(sc_pkcs15_prkey_info_t)); + prkd->id.len = 1; + prkd->id.value[0] = key_id; + prkd->usage = SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_UNWRAP; + prkd->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | SC_PKCS15_PRKEY_ACCESS_LOCAL; + prkd->native = 1; + prkd->key_reference = key_id; + prkd->path.value[0] = PRKD_PREFIX; + prkd->path.value[1] = key_id; + prkd->path.len = 2; + if (type == SC_PKCS15_TYPE_PRKEY_RSA) + prkd->modulus_length = key_size; + else + prkd->field_length = key_size-1; //contains 1 byte for the grp id + + p15o->data = prkd; + p15o->type = SC_PKCS15_TYPE_PRKEY | (type & 0xff); + + r = sc_pkcs15_encode_prkdf_entry(ctx, p15o, &asn1bin, &asn1len); + free(prkd); + //sc_asn1_print_tags(asn1bin, asn1len); + } - sc_pkcs15_prkey_info_t *prkd = (sc_pkcs15_prkey_info_t *)calloc(1, sizeof (sc_pkcs15_prkey_info_t)); - memset(prkd, 0, sizeof(sc_pkcs15_prkey_info_t)); - prkd->id.len = 1; - prkd->id.value[0] = key_id; - prkd->usage = SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_UNWRAP; - prkd->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | SC_PKCS15_PRKEY_ACCESS_LOCAL; - prkd->native = 1; - prkd->key_reference = key_id; - prkd->path.value[0] = PRKD_PREFIX; - prkd->path.value[1] = key_id; - prkd->path.len = 2; - if (type == SC_PKCS15_TYPE_PRKEY_RSA) - prkd->modulus_length = key_size; - else - prkd->field_length = key_size-1; //contains 1 byte for the grp id - - p15o->data = prkd; - p15o->type = SC_PKCS15_TYPE_PRKEY | (type & 0xff); - - r = sc_pkcs15_encode_prkdf_entry(ctx, p15o, &asn1bin, &asn1len); - free(prkd); - //sc_asn1_print_tags(asn1bin, asn1len); fpk = file_new((PRKD_PREFIX << 8) | key_id); r = flash_write_data_to_file(fpk, asn1bin, asn1len); - free(asn1bin); + if (asn1bin) + free(asn1bin); if (r != HSM_OK) return r; //add_file_to_chain(fpk, &ef_prkdf); @@ -903,13 +789,7 @@ static int cmd_keypair_gen() { else if (memcmp(oid, "\x4\x0\x7F\x0\x7\x2\x2\x2\x2\x3",MIN(oid_len,10)) == 0) { //ECC size_t prime_len; const uint8_t *prime = sc_asn1_find_tag(ctx, p, tout, 0x81, &prime_len); - mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_NONE; - for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) { - if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) { - ec_id = ec->id; - break; - } - } + mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(prime, prime_len); printf("KEYPAIR ECC %d\r\n",ec_id); if (ec_id == MBEDTLS_ECP_DP_NONE) { sc_pkcs15emu_sc_hsm_free_cvc(&cvc); @@ -1136,9 +1016,9 @@ static int cmd_update_ef() { if (!ef->data) return SW_DATA_INVALID(); uint8_t *data_merge = (uint8_t *)calloc(1, offset+data_len); - memcpy(data_merge, file_read(ef->data), offset); + memcpy(data_merge, file_read(ef->data+2), offset); memcpy(data_merge+offset, data, data_len); - int r = flash_write_data_to_file(ef, data_merge, data_len); + int r = flash_write_data_to_file(ef, data_merge, offset+data_len); free(data_merge); if (r != HSM_OK) return SW_MEMORY_FAILURE(); @@ -1191,10 +1071,8 @@ static int cmd_change_pin() { //encrypt DKEK with new pin hash_multi(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, session_pin); has_session_pin = true; - encrypt(session_pin, tmp_dkek, tmp_dkek+IV_SIZE, 32); - file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); - flash_write_data_to_file(tf, tmp_dkek, sizeof(tmp_dkek)); - release_dkek(); + if (store_dkek_key() != HSM_OK) + return SW_EXEC_ERROR(); uint8_t dhash[33]; dhash[0] = apdu.cmd_apdu_data_len-pin_len; double_hash_pin(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, dhash+1); @@ -1221,21 +1099,16 @@ static int cmd_key_gen() { //at this moment, we do not use the template, as only CBC is supported by the driver (encrypt, decrypt and CMAC) uint8_t aes_key[32]; //maximum AES key size memcpy(aes_key, random_bytes_get(key_size), key_size); - if ((r = load_dkek()) != HSM_OK) - return SW_EXEC_ERROR() ; - if ((r = encrypt(tmp_dkek+IV_SIZE, tmp_dkek, aes_key, key_size)) != 0) - return SW_EXEC_ERROR() ; - release_dkek(); - file_t *fpk = file_new((KEY_PREFIX << 8) | key_id); - if (!fpk) - return SW_MEMORY_FAILURE(); - r = flash_write_data_to_file(fpk, aes_key, key_size); - if (r != HSM_OK) - return SW_MEMORY_FAILURE(); - fpk = file_new((PRKD_PREFIX << 8) | key_id); - if (!fpk) - return SW_MEMORY_FAILURE(); - r = flash_write_data_to_file(fpk, NULL, 0); + int aes_type = 0x0; + if (key_size == 16) + aes_type = HSM_KEY_AES_128; + else if (key_size == 24) + aes_type = HSM_KEY_AES_192; + else if (key_size == 32) + aes_type = HSM_KEY_AES_256; + sc_context_t *card_ctx = create_context(); + r = store_keys(aes_key, aes_type, key_id, card_ctx); + free(card_ctx); if (r != HSM_OK) return SW_MEMORY_FAILURE(); low_flash_available(); @@ -1244,26 +1117,19 @@ static int cmd_key_gen() { int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { int key_size = file_read_uint16(fkey->data); - if (load_dkek() != HSM_OK) - return SW_EXEC_ERROR(); - uint8_t *kdata = (uint8_t *)calloc(1,key_size); + uint8_t kdata[4096/8]; memcpy(kdata, file_read(fkey->data+2), key_size); - if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) { - free(kdata); + if (dkek_decrypt(kdata, key_size) != 0) { return SW_EXEC_ERROR(); } - release_dkek(); if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size/2) != 0) { mbedtls_rsa_free(ctx); - free(kdata); return SW_DATA_INVALID(); } if (mbedtls_mpi_read_binary(&ctx->Q, kdata+key_size/2, key_size/2) != 0) { mbedtls_rsa_free(ctx); - free(kdata); return SW_DATA_INVALID(); } - free(kdata); if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) { mbedtls_rsa_free(ctx); return SW_EXEC_ERROR(); @@ -1285,23 +1151,17 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) { int key_size = file_read_uint16(fkey->data); - if (load_dkek() != HSM_OK) - return HSM_EXEC_ERROR; - uint8_t *kdata = (uint8_t *)calloc(1,key_size); + uint8_t kdata[67]; //Worst case, 521 bit + 1byte memcpy(kdata, file_read(fkey->data+2), key_size); - if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) { - free(kdata); + if (dkek_decrypt(kdata, key_size) != 0) { return HSM_EXEC_ERROR; } - release_dkek(); mbedtls_ecp_group_id gid = kdata[0]; int r = mbedtls_ecp_read_key(gid, ctx, kdata+1, key_size-1); if (r != 0) { - free(kdata); mbedtls_ecdsa_free(ctx); return HSM_EXEC_ERROR; } - free(kdata); return HSM_OK; } @@ -1445,7 +1305,7 @@ static int cmd_signature() { } static int cmd_key_wrap() { - int key_id = P1(apdu); + int key_id = P1(apdu), r = 0, key_type = 0x0; if (P2(apdu) != 0x92) return SW_WRONG_P1P2(); if (!isUserAuthenticated) @@ -1453,23 +1313,115 @@ static int cmd_key_wrap() { file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id); if (!ef) return SW_FILE_NOT_FOUND(); - int key_len = file_read_uint16(ef->data); - memcpy(res_APDU, file_read(ef->data+2), key_len); - res_APDU_size = key_len; + file_t *prkd = search_dynamic_file((PRKD_PREFIX << 8) | key_id); + if (!prkd) + return SW_FILE_NOT_FOUND(); + const uint8_t *dprkd = file_read(prkd->data+2); + size_t wrap_len = MAX_DKEK_ENCODE_KEY_BUFFER; + if (*dprkd == P15_KEYTYPE_RSA) { + mbedtls_rsa_context ctx; + mbedtls_rsa_init(&ctx); + r = load_private_key_rsa(&ctx, ef); + if (r != HSM_OK) { + mbedtls_rsa_free(&ctx); + return SW_EXEC_ERROR(); + } + r = dkek_encode_key(&ctx, HSM_KEY_RSA, res_APDU, &wrap_len); + mbedtls_rsa_free(&ctx); + } + else if (*dprkd == P15_KEYTYPE_ECC) { + mbedtls_ecdsa_context ctx; + mbedtls_ecdsa_init(&ctx); + r = load_private_key_ecdsa(&ctx, ef); + if (r != HSM_OK) { + mbedtls_ecdsa_free(&ctx); + return SW_EXEC_ERROR(); + } + r = dkek_encode_key(&ctx, HSM_KEY_EC, res_APDU, &wrap_len); + mbedtls_ecdsa_free(&ctx); + } + else if (*dprkd == P15_KEYTYPE_AES) { + uint8_t kdata[32]; //maximum AES key size + int key_size = file_read_uint16(ef->data), aes_type = HSM_KEY_AES; + memcpy(kdata, file_read(ef->data+2), key_size); + if (dkek_decrypt(kdata, key_size) != 0) { + return SW_EXEC_ERROR(); + } + if (key_size == 32) + aes_type = HSM_KEY_AES_256; + else if (key_size == 24) + aes_type = HSM_KEY_AES_192; + else if (key_size == 16) + aes_type = HSM_KEY_AES_128; + r = dkek_encode_key(kdata, aes_type, res_APDU, &wrap_len); + } + if (r != HSM_OK) + return SW_EXEC_ERROR(); + res_APDU_size = wrap_len; return SW_OK(); } static int cmd_key_unwrap() { - int key_id = P1(apdu); + int key_id = P1(apdu), r = 0; if (P2(apdu) != 0x93) return SW_WRONG_P1P2(); if (!isUserAuthenticated) return SW_SECURITY_STATUS_NOT_SATISFIED(); - file_t *ef = search_dynamic_file((KEY_PREFIX << 8) | key_id); - if (!ef) - ef = file_new((KEY_PREFIX << 8) | key_id); - flash_write_data_to_file(ef, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); - low_flash_available(); + int key_type = dkek_type_key(apdu.cmd_apdu_data); + if (key_type == 0x0) + return SW_DATA_INVALID(); + if (key_type == HSM_KEY_RSA) { + mbedtls_rsa_context ctx; + mbedtls_rsa_init(&ctx); + r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); + if (r != HSM_OK) { + mbedtls_rsa_free(&ctx); + return SW_EXEC_ERROR(); + } + sc_context_t *card_ctx = create_context(); + r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_RSA, key_id, card_ctx); + free(card_ctx); + mbedtls_rsa_free(&ctx); + if (r != HSM_OK) { + return SW_EXEC_ERROR(); + } + } + else if (key_type == HSM_KEY_EC) { + mbedtls_ecdsa_context ctx; + mbedtls_ecdsa_init(&ctx); + r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); + if (r != HSM_OK) { + mbedtls_ecdsa_free(&ctx); + return SW_EXEC_ERROR(); + } + sc_context_t *card_ctx = create_context(); + r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, key_id, card_ctx); + free(card_ctx); + mbedtls_ecdsa_free(&ctx); + if (r != HSM_OK) { + return SW_EXEC_ERROR(); + } + } + else if (key_type == HSM_KEY_AES) { + uint8_t aes_key[32]; + int key_size = 0, aes_type; + r = dkek_decode_key(aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size); + if (r != HSM_OK) { + return SW_EXEC_ERROR(); + } + if (key_size == 32) + aes_type = HSM_KEY_AES_256; + else if (key_size == 24) + aes_type = HSM_KEY_AES_192; + else if (key_size == 16) + aes_type = HSM_KEY_AES_128; + sc_context_t *card_ctx = create_context(); + r = store_keys(aes_key, aes_type, key_id, card_ctx); + free(card_ctx); + if (r != HSM_OK) { + return SW_EXEC_ERROR(); + } + } return SW_OK(); } @@ -1500,15 +1452,12 @@ static int cmd_decrypt_asym() { else if (P2(apdu) == ALGO_EC_DH) { mbedtls_ecdh_context ctx; int key_size = file_read_uint16(ef->data); - if (load_dkek() != HSM_OK) - return SW_EXEC_ERROR(); uint8_t *kdata = (uint8_t *)calloc(1,key_size); memcpy(kdata, file_read(ef->data+2), key_size); - if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) { + if (dkek_decrypt(kdata, key_size) != 0) { free(kdata); return SW_EXEC_ERROR(); } - release_dkek(); mbedtls_ecdh_init(&ctx); mbedtls_ecp_group_id gid = kdata[0]; int r = 0; @@ -1557,14 +1506,11 @@ static int cmd_cipher_sym() { return SW_WRONG_LENGTH(); } int key_size = file_read_uint16(ef->data); - if (load_dkek() != HSM_OK) - return SW_EXEC_ERROR(); uint8_t kdata[32]; //maximum AES key size memcpy(kdata, file_read(ef->data+2), key_size); - if (decrypt(tmp_dkek+IV_SIZE, tmp_dkek, kdata, key_size) != 0) { + if (dkek_decrypt(kdata, key_size) != 0) { return SW_EXEC_ERROR(); } - release_dkek(); if (algo == ALGO_AES_CBC_ENCRYPT || algo == ALGO_AES_CBC_DECRYPT) { mbedtls_aes_context aes; mbedtls_aes_init(&aes); @@ -1610,7 +1556,7 @@ static int cmd_cipher_sym() { int r = mbedtls_cipher_cmac(cipher_info, kdata, key_size*8, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU); if (r != 0) return SW_EXEC_ERROR(); - res_APDU_size = apdu.cmd_apdu_data_len; + res_APDU_size = 16; } else if (algo == ALGO_AES_DERIVE) { int r = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, file_read(ef->data+2), key_size, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, apdu.cmd_apdu_data_len); diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 20113c9..c2a4f9f 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -60,6 +60,11 @@ extern const uint8_t sc_hsm_aid[]; #define HSM_ERR_BLOCKED -1004 #define HSM_NO_LOGIN -1005 #define HSM_EXEC_ERROR -1006 +#define HSM_WRONG_LENGTH -1007 +#define HSM_WRONG_DATA -1008 +#define HSM_WRONG_DKEK -1009 +#define HSM_WRONG_SIGNATURE -1010 +#define HSM_WRONG_PADDING -1011 #define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */ #define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */ @@ -92,6 +97,10 @@ extern const uint8_t sc_hsm_aid[]; #define HSM_OPT_COMBINED_AUTH 0x10 #define HSM_OPT_RRC_RESET_ONLY 0x20 +#define P15_KEYTYPE_RSA 0x30 +#define P15_KEYTYPE_ECC 0xA0 +#define P15_KEYTYPE_AES 0xA8 + extern int pin_reset_retries(const file_t *pin, bool); extern int pin_wrong_retry(const file_t *pin); diff --git a/src/hsm/version.h b/src/hsm/version.h index 23a5d22..5534f9c 100644 --- a/src/hsm/version.h +++ b/src/hsm/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define HSM_VERSION 0x0106 +#define HSM_VERSION 0x0108 #define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff) #define HSM_VERSION_MINOR (HSM_VERSION & 0xff) diff --git a/src/rng/random.h b/src/rng/random.h index 0bd11ad..d13c415 100644 --- a/src/rng/random.h +++ b/src/rng/random.h @@ -19,6 +19,9 @@ #ifndef _RANDOM_H_ #define _RANDOM_H_ +#include "stdlib.h" +#include "pico/stdlib.h" + void random_init (void); void random_fini (void);