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);