From 89d40b7c9409b6bd4e88a6c8dcc1146b0eeb78c4 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 24 May 2022 00:29:19 +0200 Subject: [PATCH] Extending DKEK and key storage to key domains. Signed-off-by: Pol Henarejos --- src/hsm/dkek.c | 135 +++++++++++++++++++++++++---------------------- src/hsm/dkek.h | 28 ++++++---- src/hsm/sc_hsm.c | 71 +++++++++++++++---------- 3 files changed, 132 insertions(+), 102 deletions(-) diff --git a/src/hsm/dkek.c b/src/hsm/dkek.c index 6ad03ce..daa7fa2 100644 --- a/src/hsm/dkek.c +++ b/src/hsm/dkek.c @@ -29,114 +29,121 @@ #include "mbedtls/ecdsa.h" #include "files.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() { +int load_dkek(uint8_t id, uint8_t *dkek) { if (has_session_pin == false) return CCID_NO_LOGIN; - file_t *tf = search_dynamic_file(EF_DKEK); + file_t *tf = search_dynamic_file(EF_DKEK+id); if (!tf) return CCID_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); + memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), DKEK_SIZE); + int ret = aes_decrypt_cfb_256(session_pin, DKEK_IV(dkek), DKEK_KEY(dkek), DKEK_KEY_SIZE); if (ret != 0) return CCID_EXEC_ERROR; return CCID_OK; } -void release_dkek() { - memset(dkek, 0, sizeof(dkek)); +void release_dkek(uint8_t *dkek) { + memset(dkek, 0, DKEK_SIZE); } -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_dynamic_file(EF_DKEK); +int store_dkek_key(uint8_t id, uint8_t *dkek) { + file_t *tf = search_dynamic_file(EF_DKEK+id); if (!tf) return CCID_ERR_FILE_NOT_FOUND; - flash_write_data_to_file(tf, dkek, sizeof(dkek)); + aes_encrypt_cfb_256(session_pin, DKEK_IV(dkek), DKEK_KEY(dkek), DKEK_KEY_SIZE); + flash_write_data_to_file(tf, dkek, DKEK_SIZE); low_flash_available(); - release_dkek(); + release_dkek(dkek); return CCID_OK; } -int save_dkek_key(const uint8_t *key) { +int save_dkek_key(uint8_t id, const uint8_t *key) { + uint8_t dkek[DKEK_SIZE]; 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(); + memcpy(dkek, iv, DKEK_IV_SIZE); + if (!key) { + file_t *tf = search_dynamic_file(EF_DKEK+id); + if (!tf) + return CCID_ERR_FILE_NOT_FOUND; + memcpy(DKEK_KEY(dkek), file_read(tf->data+sizeof(uint16_t)), DKEK_KEY_SIZE); + } + else + memcpy(DKEK_KEY(dkek), key, DKEK_KEY_SIZE); + return store_dkek_key(id, dkek); } -void import_dkek_share(const uint8_t *share) { - for (int i = 0; i < 32; i++) +int import_dkek_share(uint8_t id, const uint8_t *share) { + uint8_t tmp_dkek[DKEK_KEY_SIZE]; + file_t *tf = search_dynamic_file(EF_DKEK+id); + if (!tf) + return CCID_ERR_FILE_NOT_FOUND; + memset(tmp_dkek, 0, sizeof(tmp_dkek)); + if (tf->data && file_read_uint16(tf->data) == DKEK_KEY_SIZE) + memcpy(tmp_dkek, file_read(tf->data+sizeof(uint16_t)),DKEK_KEY_SIZE); + for (int i = 0; i < DKEK_KEY_SIZE; i++) tmp_dkek[i] ^= share[i]; + flash_write_data_to_file(tf, tmp_dkek, DKEK_KEY_SIZE); + low_flash_available(); + return CCID_OK; } -int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes - uint8_t hsh[32]; - int r = load_dkek(); +int dkek_kcv(uint8_t id, uint8_t *kcv) { //kcv 8 bytes + uint8_t hsh[32], dkek[DKEK_SIZE]; + int r = load_dkek(id, dkek); if (r != CCID_OK) return r; - hash256(dkek+IV_SIZE, 32, hsh); - release_dkek(); + hash256(DKEK_KEY(dkek), DKEK_KEY_SIZE, hsh); + release_dkek(dkek); memcpy(kcv, hsh, 8); return CCID_OK; } -int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes - uint8_t buf[32+4]; - int r = load_dkek(); +int dkek_kenc(uint8_t id, uint8_t *kenc) { //kenc 32 bytes + uint8_t dkek[DKEK_SIZE+4]; + int r = load_dkek(id, dkek); if (r != CCID_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)); + memcpy(DKEK_KEY(dkek)+DKEK_KEY_SIZE, "\x0\x0\x0\x1", 4); + hash256(DKEK_KEY(dkek), DKEK_KEY_SIZE+4, kenc); + release_dkek(dkek); return CCID_OK; } -int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes - uint8_t buf[32+4]; - int r = load_dkek(); +int dkek_kmac(uint8_t id, uint8_t *kmac) { //kmac 32 bytes + uint8_t dkek[DKEK_SIZE+4]; + int r = load_dkek(id, dkek); if (r != CCID_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)); + memcpy(DKEK_KEY(dkek)+DKEK_KEY_SIZE, "\x0\x0\x0\x2", 4); + hash256(DKEK_KEY(dkek), DKEK_KEY_SIZE+4, kmac); + release_dkek(dkek); return CCID_OK; } -int dkek_encrypt(uint8_t *data, size_t len) { +int dkek_encrypt(uint8_t id, uint8_t *data, size_t len) { int r; - if ((r = load_dkek()) != CCID_OK) + uint8_t dkek[DKEK_SIZE+4]; + if ((r = load_dkek(id, dkek)) != CCID_OK) return r; - r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); - release_dkek(); + r = aes_encrypt_cfb_256(DKEK_KEY(dkek), DKEK_IV(dkek), data, len); + release_dkek(dkek); return r; } -int dkek_decrypt(uint8_t *data, size_t len) { +int dkek_decrypt(uint8_t id, uint8_t *data, size_t len) { int r; - if ((r = load_dkek()) != CCID_OK) + uint8_t dkek[DKEK_SIZE+4]; + if ((r = load_dkek(id, dkek)) != CCID_OK) return r; - r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); - release_dkek(); + r = aes_decrypt_cfb_256(DKEK_KEY(dkek), DKEK_IV(dkek), data, len); + release_dkek(dkek); return r; } -int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) { +int dkek_encode_key(uint8_t id, 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 CCID_WRONG_DATA; @@ -149,15 +156,15 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) uint8_t allowed_len = 0; uint8_t kenc[32]; memset(kenc, 0, sizeof(kenc)); - dkek_kenc(kenc); + dkek_kenc(id, kenc); uint8_t kcv[8]; memset(kcv, 0, sizeof(kcv)); - dkek_kcv(kcv); + dkek_kcv(id, kcv); uint8_t kmac[32]; memset(kmac, 0, sizeof(kmac)); - dkek_kmac(kmac); + dkek_kmac(id, kmac); if (key_type & HSM_KEY_AES) { if (key_type & HSM_KEY_AES_128) @@ -290,18 +297,18 @@ int dkek_type_key(const uint8_t *in) { return 0x0; } -int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out) { +int dkek_decode_key(uint8_t id, 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); + dkek_kcv(id, kcv); uint8_t kmac[32]; memset(kmac, 0, sizeof(kmac)); - dkek_kmac(kmac); + dkek_kmac(id, kmac); uint8_t kenc[32]; memset(kenc, 0, sizeof(kenc)); - dkek_kenc(kenc); + dkek_kenc(id, kenc); if (memcmp(kcv, in, 8) != 0) return CCID_WRONG_DKEK; @@ -472,4 +479,4 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si memcpy(key_ctx, kb+ofs, key_size); } return CCID_OK; -} \ No newline at end of file +} diff --git a/src/hsm/dkek.h b/src/hsm/dkek.h index 0fe7501..3047694 100644 --- a/src/hsm/dkek.h +++ b/src/hsm/dkek.h @@ -18,19 +18,27 @@ #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 int load_dkek(uint8_t, uint8_t *); +extern int save_dkek_key(uint8_t, const uint8_t *key); +extern int store_dkek_key(uint8_t, uint8_t *); extern void init_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 void release_dkek(uint8_t *); +extern int import_dkek_share(uint8_t, const uint8_t *share); +extern int dkek_kcv(uint8_t, uint8_t *kcv); +extern int dkek_encrypt(uint8_t, uint8_t *data, size_t len); +extern int dkek_decrypt(uint8_t, uint8_t *data, size_t len); +extern int dkek_encode_key(uint8_t, 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); +extern int dkek_decode_key(uint8_t, 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) +#define MAX_KEY_DOMAINS 16 + +#define DKEK_IV_SIZE (IV_SIZE) +#define DKEK_KEY_SIZE (32) +#define DKEK_SIZE (DKEK_IV_SIZE+DKEK_KEY_SIZE) +#define DKEK_KEY(p) (p+DKEK_IV_SIZE) +#define DKEK_IV(p) (p) + #endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 7b56e26..ace7ee9 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -682,7 +682,7 @@ static int cmd_initialize() { initialize_flash(true); scan_all(); dkeks = current_dkeks = 0; - uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL, kds = 1; size_t tag_len = 0; while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x80) { //options @@ -723,10 +723,12 @@ static int cmd_initialize() { file_t *tf = file_new(EF_DKEK); if (!tf) return SW_MEMORY_FAILURE(); + flash_write_data_to_file(tf, NULL, 0); low_flash_available(); } else if (tag == 0x97) { - for (int i = 0; i < MIN(*tag_data,16); i++) { + kds = MIN(*tag_data,16); + for (int i = 0; i < kds; i++) { file_t *tf = file_new(EF_DKEK+i); if (!tf) return SW_MEMORY_FAILURE(); @@ -736,12 +738,22 @@ static int cmd_initialize() { } } if (dkeks == 0) { - int r = save_dkek_key(random_bytes_get(32)); - if (r != CCID_OK) - return SW_EXEC_ERROR(); + //At least, the first DKEK shall exist + file_t *tf = search_dynamic_file(EF_DKEK); + if (!tf) { + file_t *tf = file_new(EF_DKEK); + if (!tf) + return SW_MEMORY_FAILURE(); + flash_write_data_to_file(tf, NULL, 0); + low_flash_available(); + } + for (int kd = 0; kd < kds; kd++) { + int r = save_dkek_key(kd, random_bytes_get(32)); + printf("r %d\r\n",r); + if (r != CCID_OK) + return SW_EXEC_ERROR(); + } } - else - init_dkek(); } else { //free memory bytes request int heap_left = heapLeft(); @@ -764,7 +776,7 @@ static int cmd_key_domain() { if (has_session_pin == false && apdu.cmd_apdu_data_len > 0) return SW_CONDITIONS_NOT_SATISFIED(); if (p1 == 0x0) { //dkek import - if (p2 > 0xF) + if (p2 > MAX_KEY_DOMAINS) return SW_WRONG_P1P2(); if (apdu.cmd_apdu_data_len > 0) { file_t *tf = file_new(EF_DKEK+p2); @@ -772,9 +784,9 @@ static int cmd_key_domain() { return SW_MEMORY_FAILURE(); if (apdu.cmd_apdu_data_len < 32) return SW_WRONG_LENGTH(); - import_dkek_share(apdu.cmd_apdu_data); - if (++current_dkeks == dkeks) { - if (save_dkek_key(NULL) != CCID_OK) + import_dkek_share(p2, apdu.cmd_apdu_data); + if (++current_dkeks >= dkeks) { + if (save_dkek_key(p2, NULL) != CCID_OK) return SW_FILE_NOT_FOUND(); } low_flash_available(); @@ -786,8 +798,8 @@ static int cmd_key_domain() { } memset(res_APDU,0,10); res_APDU[0] = dkeks; - res_APDU[1] = dkeks-current_dkeks; - dkek_kcv(res_APDU+2); + res_APDU[1] = dkeks > current_dkeks ? dkeks-current_dkeks : 0; + dkek_kcv(p2, res_APDU+2); res_APDU_size = 2+8; } return SW_OK(); @@ -821,7 +833,7 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) { key_size = 32; memcpy(kdata, key_ctx, key_size); } - r = dkek_encrypt(kdata, key_size); + r = dkek_encrypt(0, kdata, key_size); if (r != CCID_OK) { return r; } @@ -1260,14 +1272,17 @@ static int cmd_change_pin() { } uint8_t pin_len = file_read_uint8(file_pin1->data+2); uint16_t r = check_pin(file_pin1, apdu.cmd_apdu_data, pin_len); + uint8_t dkek[DKEK_SIZE]; if (r != 0x9000) return r; - if (load_dkek() != CCID_OK) //loads the DKEK with old pin + if (load_dkek(0, dkek) != CCID_OK) //loads the DKEK with old pin return SW_EXEC_ERROR(); //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; - if (store_dkek_key() != CCID_OK) + r = store_dkek_key(0, dkek); + release_dkek(dkek); + if (r != CCID_OK) return SW_EXEC_ERROR(); uint8_t dhash[33]; dhash[0] = apdu.cmd_apdu_data_len-pin_len; @@ -1318,7 +1333,7 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { int key_size = file_read_uint16(fkey->data); uint8_t kdata[4096/8]; memcpy(kdata, file_read(fkey->data+2), key_size); - if (dkek_decrypt(kdata, key_size) != 0) { + if (dkek_decrypt(0, kdata, key_size) != 0) { return CCID_EXEC_ERROR; } if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size/2) != 0) { @@ -1355,7 +1370,7 @@ int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) { int key_size = file_read_uint16(fkey->data); uint8_t kdata[67]; //Worst case, 521 bit + 1byte memcpy(kdata, file_read(fkey->data+2), key_size); - if (dkek_decrypt(kdata, key_size) != 0) { + if (dkek_decrypt(0, kdata, key_size) != 0) { return CCID_EXEC_ERROR; } mbedtls_ecp_group_id gid = kdata[0]; @@ -1538,7 +1553,7 @@ static int cmd_key_wrap() { return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_EXEC_ERROR(); } - r = dkek_encode_key(&ctx, HSM_KEY_RSA, res_APDU, &wrap_len); + r = dkek_encode_key(0, &ctx, HSM_KEY_RSA, res_APDU, &wrap_len); mbedtls_rsa_free(&ctx); } else if (*dprkd == P15_KEYTYPE_ECC) { @@ -1551,7 +1566,7 @@ static int cmd_key_wrap() { return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_EXEC_ERROR(); } - r = dkek_encode_key(&ctx, HSM_KEY_EC, res_APDU, &wrap_len); + r = dkek_encode_key(0, &ctx, HSM_KEY_EC, res_APDU, &wrap_len); mbedtls_ecdsa_free(&ctx); } else if (*dprkd == P15_KEYTYPE_AES) { @@ -1561,7 +1576,7 @@ static int cmd_key_wrap() { 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) { + if (dkek_decrypt(0, kdata, key_size) != 0) { return SW_EXEC_ERROR(); } if (key_size == 32) @@ -1570,7 +1585,7 @@ static int cmd_key_wrap() { 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); + r = dkek_encode_key(0, kdata, aes_type, res_APDU, &wrap_len); } if (r != CCID_OK) return SW_EXEC_ERROR(); @@ -1590,7 +1605,7 @@ static int cmd_key_unwrap() { 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); + r = dkek_decode_key(0, &ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); if (r != CCID_OK) { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); @@ -1606,7 +1621,7 @@ static int cmd_key_unwrap() { 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); + r = dkek_decode_key(0, &ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); @@ -1622,7 +1637,7 @@ static int cmd_key_unwrap() { 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); + r = dkek_decode_key(0, aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size); if (r != CCID_OK) { return SW_EXEC_ERROR(); } @@ -1677,7 +1692,7 @@ static int cmd_decrypt_asym() { int key_size = file_read_uint16(ef->data); uint8_t *kdata = (uint8_t *)calloc(1,key_size); memcpy(kdata, file_read(ef->data+2), key_size); - if (dkek_decrypt(kdata, key_size) != 0) { + if (dkek_decrypt(0, kdata, key_size) != 0) { free(kdata); return SW_EXEC_ERROR(); } @@ -1733,7 +1748,7 @@ static int cmd_cipher_sym() { int key_size = file_read_uint16(ef->data); uint8_t kdata[32]; //maximum AES key size memcpy(kdata, file_read(ef->data+2), key_size); - if (dkek_decrypt(kdata, key_size) != 0) { + if (dkek_decrypt(0, kdata, key_size) != 0) { return SW_EXEC_ERROR(); } if (algo == ALGO_AES_CBC_ENCRYPT || algo == ALGO_AES_CBC_DECRYPT) { @@ -2109,4 +2124,4 @@ int sc_hsm_process_apdu() { } } return SW_INS_NOT_SUPPORTED(); -} \ No newline at end of file +}