From 55c8a666138beb5d2f410f57fc88ce73340d0b05 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sat, 13 Aug 2022 02:58:36 +0200 Subject: [PATCH] Fix wrap/unwrap keys with specific allowed algorithms. Signed-off-by: Pol Henarejos --- src/hsm/dkek.c | 13 ++++++------- src/hsm/dkek.h | 4 ++-- src/hsm/sc_hsm.c | 35 +++++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/hsm/dkek.c b/src/hsm/dkek.c index bbf7b8e..79774a3 100644 --- a/src/hsm/dkek.c +++ b/src/hsm/dkek.c @@ -212,7 +212,7 @@ int mkek_decrypt(uint8_t *data, size_t len) { return r; } -int dkek_encode_key(uint8_t id, 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, const uint8_t *allowed, size_t allowed_len) { if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES)) return CCID_WRONG_DATA; @@ -221,8 +221,6 @@ int dkek_encode_key(uint8_t id, void *key_ctx, int key_type, uint8_t *out, size_ int kb_len = 0, r = 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)); r = dkek_kenc(id, kenc); @@ -260,8 +258,6 @@ int dkek_encode_key(uint8_t id, void *key_ctx, int key_type, uint8_t *out, size_ algo = (uint8_t *)"\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8) algo_len = 10; - allowed = (uint8_t *)"\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 @@ -329,7 +325,8 @@ int dkek_encode_key(uint8_t id, void *key_ctx, int key_type, uint8_t *out, size_ else *out_len += 2; - if (allowed) { + if (allowed && allowed_len > 0) { + put_uint16_t(allowed_len, out+*out_len); *out_len += 2; memcpy(out+*out_len, allowed, allowed_len); *out_len += allowed_len; } @@ -372,7 +369,7 @@ int dkek_type_key(const uint8_t *in) { return 0x0; } -int dkek_decode_key(uint8_t id, 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 **allowed, size_t *allowed_len) { uint8_t kcv[8]; int r = 0; memset(kcv, 0, sizeof(kcv)); @@ -423,6 +420,8 @@ int dkek_decode_key(uint8_t id, void *key_ctx, const uint8_t *in, size_t in_len, //Allowed algorithms len = get_uint16_t(in, ofs); + *allowed = (uint8_t *)(in+ofs+2); + *allowed_len = len; ofs += len+2; //Access conditions diff --git a/src/hsm/dkek.h b/src/hsm/dkek.h index 0d7fbfb..cd18240 100644 --- a/src/hsm/dkek.h +++ b/src/hsm/dkek.h @@ -28,9 +28,9 @@ extern int import_dkek_share(uint8_t, const uint8_t *share); extern int dkek_kcv(uint8_t, uint8_t *kcv); extern int mkek_encrypt(uint8_t *data, size_t len); extern int mkek_decrypt(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_encode_key(uint8_t, void *key_ctx, int key_type, uint8_t *out, size_t *out_len, const uint8_t *, size_t); extern int dkek_type_key(const uint8_t *in); -extern int dkek_decode_key(uint8_t, 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, uint8_t **, size_t *); #define MAX_DKEK_ENCODE_KEY_BUFFER (8+1+12+6+(8+2*4+2*4096/8+3+13)+16) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 43476ed..59035f4 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1709,6 +1709,8 @@ static int cmd_key_wrap() { return SW_FILE_NOT_FOUND(); const uint8_t *dprkd = file_get_data(prkd); size_t wrap_len = MAX_DKEK_ENCODE_KEY_BUFFER; + size_t tag_len = 0; + const uint8_t *meta_tag = get_meta_tag(ef, 0x91, &tag_len); if (*dprkd == P15_KEYTYPE_RSA) { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); @@ -1719,7 +1721,7 @@ static int cmd_key_wrap() { return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_EXEC_ERROR(); } - r = dkek_encode_key(kdom, &ctx, HSM_KEY_RSA, res_APDU, &wrap_len); + r = dkek_encode_key(kdom, &ctx, HSM_KEY_RSA, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_rsa_free(&ctx); } else if (*dprkd == P15_KEYTYPE_ECC) { @@ -1732,7 +1734,7 @@ static int cmd_key_wrap() { return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_EXEC_ERROR(); } - r = dkek_encode_key(kdom, &ctx, HSM_KEY_EC, res_APDU, &wrap_len); + r = dkek_encode_key(kdom, &ctx, HSM_KEY_EC, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_ecdsa_free(&ctx); } else if (*dprkd == P15_KEYTYPE_AES) { @@ -1751,7 +1753,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(kdom, kdata, aes_type, res_APDU, &wrap_len); + r = dkek_encode_key(kdom, kdata, aes_type, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_platform_zeroize(kdata, sizeof(kdata)); } if (r != CCID_OK) @@ -1767,14 +1769,15 @@ static int cmd_key_unwrap() { if (!isUserAuthenticated) return SW_SECURITY_STATUS_NOT_SATISFIED(); int key_type = dkek_type_key(apdu.data); - uint8_t kdom = -1; + uint8_t kdom = -1, *allowed = NULL; + size_t allowed_len = 0; if (key_type == 0x0) return SW_DATA_INVALID(); if (key_type == HSM_KEY_RSA) { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); do { - r = dkek_decode_key(++kdom, &ctx, apdu.data, apdu.nc, NULL); + r = dkek_decode_key(++kdom, &ctx, apdu.data, apdu.nc, NULL, &allowed, &allowed_len); } while((r == CCID_ERR_FILE_NOT_FOUND || r == CCID_WRONG_DKEK) && kdom < MAX_KEY_DOMAINS); if (r != CCID_OK) { mbedtls_rsa_free(&ctx); @@ -1790,7 +1793,7 @@ static int cmd_key_unwrap() { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); do { - r = dkek_decode_key(++kdom, &ctx, apdu.data, apdu.nc, NULL); + r = dkek_decode_key(++kdom, &ctx, apdu.data, apdu.nc, NULL, &allowed, &allowed_len); } while((r == CCID_ERR_FILE_NOT_FOUND || r == CCID_WRONG_DKEK) && kdom < MAX_KEY_DOMAINS); if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); @@ -1806,7 +1809,7 @@ static int cmd_key_unwrap() { uint8_t aes_key[32]; int key_size = 0, aes_type = 0; do { - r = dkek_decode_key(++kdom, aes_key, apdu.data, apdu.nc, &key_size); + r = dkek_decode_key(++kdom, aes_key, apdu.data, apdu.nc, &key_size, &allowed, &allowed_len); } while((r == CCID_ERR_FILE_NOT_FOUND || r == CCID_WRONG_DKEK) && kdom < MAX_KEY_DOMAINS); if (r != CCID_OK) { return SW_EXEC_ERROR(); @@ -1824,9 +1827,21 @@ static int cmd_key_unwrap() { return SW_EXEC_ERROR(); } } - if (kdom >= 0) { - uint8_t meta[3] = {0x92,1,kdom}; - r = meta_add((KEY_PREFIX << 8) | key_id, meta, sizeof(meta)); + if ((allowed != NULL && allowed_len > 0) || kdom >= 0) { + size_t meta_len = (allowed_len > 0 ? 2+allowed_len : 0) + (kdom >= 0 ? 3 : 0); + uint8_t *meta = (uint8_t *)calloc(1,meta_len), *m = meta; + if (allowed_len > 0) { + *m++ = 0x91; + *m++ = allowed_len; + memcpy(m, allowed, allowed_len); m += allowed_len; + } + if (kdom >= 0) { + *m++ = 0x92; + *m++ = 1; + *m++ = kdom; + } + r = meta_add((KEY_PREFIX << 8) | key_id, meta, meta_len); + free(meta); if (r != CCID_OK) return r; }