From 54eb4838dd231e092f5eb7857b01688561a0ef36 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 21 Apr 2022 19:20:45 +0200 Subject: [PATCH] Adding RSA keypair generation. Signed-off-by: Pol Henarejos --- src/openpgp/files.c | 18 +++-- src/openpgp/files.h | 6 ++ src/openpgp/openpgp.c | 163 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 175 insertions(+), 12 deletions(-) diff --git a/src/openpgp/files.c b/src/openpgp/files.c index d7495fa..856f116 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -123,18 +123,24 @@ file_t file_entries[] = { /* 37 */ { .fid = EF_APP_DATA, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_app_data, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, /* 38 */ { .fid = EF_DISCRETE_DO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_discrete_do, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, - /* 39 */ { .fid = EF_PW1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, - /* 40 */ { .fid = EF_RC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 39 */ { .fid = EF_PW1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 40 */ { .fid = EF_RC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, /* 41 */ { .fid = EF_PW3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, /* 42 */ { .fid = EF_PW1_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, - /* 43 */ { .fid = EF_RC_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 43 */ { .fid = EF_RC_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, /* 44 */ { .fid = EF_PW3_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, /* 45 */ { .fid = EF_ALGO_PRIV1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, - /* 46 */ { .fid = EF_ALGO_PRIV2, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 46 */ { .fid = EF_ALGO_PRIV2, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, /* 47 */ { .fid = EF_ALGO_PRIV3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 48 */ { .fid = EF_PK_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 49 */ { .fid = EF_PK_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 50 */ { .fid = EF_PK_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 51 */ { .fid = EF_PB_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 52 */ { .fid = EF_PB_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 53 */ { .fid = EF_PB_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, - /* 48 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, - /* 49 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end + /* 54 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 55 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end }; const file_t *MF = &file_entries[0]; diff --git a/src/openpgp/files.h b/src/openpgp/files.h index af3ef5e..63aa4c2 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -30,6 +30,12 @@ #define EF_ALGO_PRIV1 0x10c1 #define EF_ALGO_PRIV2 0x10c2 #define EF_ALGO_PRIV3 0x10c3 +#define EF_PK_SIG 0x10d1 +#define EF_PK_DEC 0x10d2 +#define EF_PK_AUT 0x10d3 +#define EF_PB_SIG 0x10d4 +#define EF_PB_DEC 0x10d5 +#define EF_PB_AUT 0x10d6 #define EF_EXT_HEADER 0x004d //C #define EF_FULL_AID 0x004f //S diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index e01b0a3..557d9c3 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -15,14 +15,19 @@ * along with this program. If not, see . */ +#include "common.h" #include "openpgp.h" #include "version.h" #include "files.h" +#include "random.h" #include "eac.h" #include "crypto_utils.h" +#include "mbedtls/rsa.h" +#include "mbedtls/ecdsa.h" bool has_pw1 = false; bool has_pw3 = false; +uint8_t session_pw3[32]; uint8_t openpgp_aid[] = { 6, @@ -374,9 +379,13 @@ int parse_pw_status(const file_t *f, int mode) { return res_APDU_size-init_len; } -#define ALGO_RSA 0x01 -#define ALGO_ECDH 0x12 -#define ALGO_ECDSA 0x13 +#define ALGO_RSA 0x01 +#define ALGO_ECDH 0x12 +#define ALGO_ECDSA 0x13 +#define ALGO_AES 0x70 +#define ALGO_AES_128 0x71 +#define ALGO_AES_192 0x72 +#define ALGO_AES_256 0x74 static const uint8_t algorithm_attr_x448[] = { 4, @@ -628,11 +637,12 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { if (r != CCID_OK) return SW_MEMORY_FAILURE(); isUserAuthenticated = true; - //hash_multi(data, len, session_pin); if (pin->fid == EF_PW1) has_pw1 = true; - else if (pin->fid == EF_PW3) + else if (pin->fid == EF_PW3) { has_pw3 = true; + hash_multi(data, len, session_pw3); + } return SW_OK(); } @@ -736,9 +746,150 @@ static int cmd_reset_retry() { return SW_INCORRECT_P1P2(); } +int store_keys(void *key_ctx, int type, uint16_t key_id) { + int r, key_size; + uint8_t kdata[4096/8]; //worst + + if (!has_pw3) + return CCID_NO_LOGIN; + file_t *pw3 = search_by_fid(EF_PW3, NULL, SPECIFY_EF); + if (!pw3) + return CCID_ERR_FILE_NOT_FOUND; + file_t *ef = search_by_fid(key_id, NULL, SPECIFY_EF); + if (!ef) + return CCID_ERR_FILE_NOT_FOUND; + if (type == ALGO_RSA) { + mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; + key_size = mbedtls_mpi_size(&rsa->P)+mbedtls_mpi_size(&rsa->Q); + mbedtls_mpi_write_binary(&rsa->P, kdata, key_size/2); + mbedtls_mpi_write_binary(&rsa->Q, kdata+key_size/2, key_size/2); + } + else if (type == ALGO_ECDSA || type == ALGO_ECDH) { + mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; + key_size = mbedtls_mpi_size(&ecdsa->d); + kdata[0] = ecdsa->grp.id & 0xff; + mbedtls_mpi_write_binary(&ecdsa->d, kdata+1, key_size); + key_size++; + } + else if (type & ALGO_AES) { + if (type == ALGO_AES_128) + key_size = 16; + else if (type == ALGO_AES_192) + key_size = 24; + else if (type == ALGO_AES_256) + key_size = 32; + memcpy(kdata, key_ctx, key_size); + } + r = aes_decrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size); + if (r != CCID_OK) + return r; + r = flash_write_data_to_file(ef, kdata, key_size); + if (r != CCID_OK) + return r; + low_flash_available(); + return CCID_OK; +} + +mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) { + if (memcmp(algorithm_attr_p256k1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_SECP256K1; + else if (memcmp(algorithm_attr_p256r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_SECP256R1; + else if (memcmp(algorithm_attr_p384r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_SECP384R1; + else if (memcmp(algorithm_attr_p521r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_SECP521R1; + else if (memcmp(algorithm_attr_bp256r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_BP256R1; + else if (memcmp(algorithm_attr_bp384r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_BP384R1; + else if (memcmp(algorithm_attr_bp512r1, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_BP512R1; + else if (memcmp(algorithm_attr_cv25519, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_CURVE25519; + else if (memcmp(algorithm_attr_x448, algo, algo_len) == 0) + return MBEDTLS_ECP_DP_CURVE448; + return MBEDTLS_ECP_DP_NONE; +} + static int cmd_keypair_gen() { + if (P2(apdu) != 0x0) + return SW_INCORRECT_P1P2(); + if (apdu.cmd_apdu_data_len != 2 && apdu.cmd_apdu_data_len != 5) + return SW_WRONG_LENGTH(); + + uint16_t fid = 0x0; + int r = CCID_OK; + if (apdu.cmd_apdu_data[0] == 0xB6) + fid = EF_PK_SIG; + else if (apdu.cmd_apdu_data[0] == 0xB8) + fid = EF_PK_DEC; + else if (apdu.cmd_apdu_data[0] == 0xA4) + fid = EF_PK_AUT; + else + return SW_WRONG_DATA(); if (P1(apdu) == 0x80) { //generate - + file_t *algo_ef = search_by_fid(fid-0x0010, NULL, SPECIFY_EF); + const uint8_t *algo = algorithm_attr_rsa2k+1; + uint16_t algo_len = algorithm_attr_rsa2k[0]; + if (algo_ef && algo_ef->data) { + algo_len = file_read_uint16(algo_ef->data); + algo = file_read(algo_ef->data+2); + } + if (algo[0] == ALGO_RSA) { + int exponent = 65537, nlen = (algo[1] << 8) | algo[2]; + printf("KEYPAIR RSA %d\r\n",nlen); + //if (nlen != 2048 && nlen != 4096) + // return SW_FUNC_NOT_SUPPORTED(); + mbedtls_rsa_context rsa; + mbedtls_rsa_init(&rsa); + uint8_t index = 0; + r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent); + printf("r %d\r\n",r); + if (r != 0) { + mbedtls_rsa_free(&rsa); + return SW_EXEC_ERROR(); + } + r = store_keys(&rsa, ALGO_RSA, fid); + printf("r %d\r\n",r); + memcpy(res_APDU, "\x7f\x49\x82\x00\x00", 5); + uint8_t *lp = res_APDU+3; + res_APDU_size = 5; + res_APDU[res_APDU_size++] = 0x81; + res_APDU[res_APDU_size++] = 0x82; + put_uint16_t(mbedtls_mpi_size(&rsa.N), res_APDU+res_APDU_size); res_APDU_size += 2; + mbedtls_mpi_write_binary(&rsa.N, res_APDU+res_APDU_size, mbedtls_mpi_size(&rsa.N)); res_APDU_size += mbedtls_mpi_size(&rsa.N); + res_APDU[res_APDU_size++] = 0x82; + res_APDU[res_APDU_size++] = mbedtls_mpi_size(&rsa.E) & 0xff; + mbedtls_mpi_write_binary(&rsa.E, res_APDU+res_APDU_size, mbedtls_mpi_size(&rsa.E)); res_APDU_size += mbedtls_mpi_size(&rsa.E); + put_uint16_t(res_APDU_size-5, res_APDU+3); + mbedtls_rsa_free(&rsa); + if (r != CCID_OK) + return SW_EXEC_ERROR(); + } + else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA) { + printf("KEYPAIR ECDSA\r\n"); + mbedtls_ecp_group_id gid = get_ec_group_id_from_attr(algo, algo_len); + if (gid == MBEDTLS_ECP_DP_NONE) + return SW_FUNC_NOT_SUPPORTED(); + if ((gid == MBEDTLS_ECP_DP_CURVE25519 || gid == MBEDTLS_ECP_DP_CURVE448) && (fid == EF_PK_SIG || fid == EF_PK_AUT)) + return SW_FUNC_NOT_SUPPORTED(); + mbedtls_ecdsa_context ecdsa; + mbedtls_ecdsa_init(&ecdsa); + uint8_t index = 0; + r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index); + if (r != 0) { + mbedtls_ecdsa_free(&ecdsa); + return SW_EXEC_ERROR(); + } + r = store_keys(&ecdsa, algo[0], fid); + mbedtls_ecdsa_free(&ecdsa); + if (r != CCID_OK) + return SW_EXEC_ERROR(); + } + else + return SW_FUNC_NOT_SUPPORTED(); + return SW_OK(); } else if (P1(apdu) == 0x81) { //read