From d157ea907217c5e4fcde17398a7169f0beb05201 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 9 Jul 2026 17:21:13 +0200 Subject: [PATCH] fix(openpgp): harden stored data and key handling --- src/openpgp/cmd_get_data.c | 20 ++- src/openpgp/cmd_import_data.c | 6 + src/openpgp/cmd_internal_aut.c | 7 +- src/openpgp/cmd_keypair_gen.c | 15 +- src/openpgp/cmd_pso.c | 68 ++++++-- src/openpgp/cmd_put_data.c | 46 +++++- src/openpgp/cmd_select_data.c | 19 ++- src/openpgp/do.c | 80 +++++++-- src/openpgp/files.c | 5 +- src/openpgp/openpgp.c | 285 +++++++++++++++++++++++++++------ src/openpgp/openpgp.h | 22 +-- 11 files changed, 465 insertions(+), 108 deletions(-) diff --git a/src/openpgp/cmd_get_data.c b/src/openpgp/cmd_get_data.c index 79584a7..e79b708 100644 --- a/src/openpgp/cmd_get_data.c +++ b/src/openpgp/cmd_get_data.c @@ -24,7 +24,9 @@ int cmd_get_data(void) { if (apdu.nc > 0) { return SW_WRONG_LENGTH(); } + res_APDU_size = 0; uint16_t fid = (P1(apdu) << 8) | P2(apdu); + uint16_t requested_fid = fid; file_t *ef; if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); @@ -42,18 +44,28 @@ int cmd_get_data(void) { else if (!file_authenticate_action(ef, ACL_OP_READ_SEARCH)) { return SW_SECURITY_STATUS_NOT_SATISFIED(); } - if (currentEF && currentEF->fid == fid) { // previously selected same EF + if (fid == EF_CH_CERT) { + if (currentEF && currentEF->fid >= EF_CH_1 && currentEF->fid <= EF_CH_3) { + ef = currentEF; + } + else if (!(ef = file_search_by_fid(EF_CH_1, NULL, SPECIFY_EF))) { + return SW_REFERENCE_NOT_FOUND(); + } + } + else if (currentEF && currentEF->fid == fid) { // previously selected same EF ef = currentEF; } else { select_file(ef); } if (ef->data) { - if (fid == EF_PW_STATUS || fid == EF_HIST_BYTES || fid == EF_FULL_AID || fid == EF_SEC_TPL) { + if (requested_fid == EF_PW_STATUS || requested_fid == EF_HIST_BYTES || + requested_fid == EF_FULL_AID || requested_fid == EF_SEC_TPL) { is_gpg = true; } - uint16_t fids[] = { 1, fid }; + uint16_t fids[] = { 1, ef->fid }; uint16_t data_len = parse_do(fids, 1); + data_len = MIN(data_len, res_APDU_size); if (!(ef->type & FILE_DATA_FLASH)) { uint8_t *p = NULL; uint16_t tg = 0; @@ -86,6 +98,8 @@ int cmd_get_data(void) { if (data_len >= 256) { off++; } + data_len = MIN(data_len, OPENPGP_MAX_RESPONSE_SIZE - off); + res_APDU_size = data_len; memmove(res_APDU + off, res_APDU, data_len); off = 0; if (P1(apdu) > 0x0) { diff --git a/src/openpgp/cmd_import_data.c b/src/openpgp/cmd_import_data.c index 1d87e00..e946846 100644 --- a/src/openpgp/cmd_import_data.c +++ b/src/openpgp/cmd_import_data.c @@ -142,8 +142,14 @@ int cmd_import_data(void) { algo = file_get_data(algo_ef); algo_len = file_get_size(algo_ef); } + if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) { + return SW_WRONG_DATA(); + } int r = 0; if (algo[0] == ALGO_RSA) { + if (algo_len < 3) { + return SW_WRONG_DATA(); + } mbedtls_rsa_context rsa; if (p[0] == NULL || len[0] == 0 || p[1] == NULL || len[1] == 0 || p[2] == NULL || len[2] == 0) { diff --git a/src/openpgp/cmd_internal_aut.c b/src/openpgp/cmd_internal_aut.c index 98cd117..b04b341 100644 --- a/src/openpgp/cmd_internal_aut.c +++ b/src/openpgp/cmd_internal_aut.c @@ -32,12 +32,17 @@ int cmd_internal_aut(void) { const uint8_t *algo = algorithm_attr_rsa2k + 1; if (algo_ef && algo_ef->data) { algo = file_get_data(algo_ef); + uint16_t algo_len = file_get_size(algo_ef); + if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) { + return SW_WRONG_DATA(); + } } file_t *ef = file_search_by_fid(pk_aut, NULL, SPECIFY_EF); if (!ef) { return SW_REFERENCE_NOT_FOUND(); } - if (wait_button_pressed_fid(EF_UIF_AUT) == true) { + uint16_t uif_fid = pk_aut == EF_PK_DEC ? EF_UIF_DEC : EF_UIF_AUT; + if (wait_button_pressed_fid(uif_fid) == true) { return SW_SECURE_MESSAGE_EXEC_ERROR(); } int r = PICOKEYS_OK; diff --git a/src/openpgp/cmd_keypair_gen.c b/src/openpgp/cmd_keypair_gen.c index 3bf368a..c7bc63d 100644 --- a/src/openpgp/cmd_keypair_gen.c +++ b/src/openpgp/cmd_keypair_gen.c @@ -56,8 +56,14 @@ int cmd_keypair_gen(void) { algo = file_get_data(algo_ef); algo_len = file_get_size(algo_ef); } + if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) { + return SW_WRONG_DATA(); + } if (P1(apdu) == 0x80) { //generate if (algo[0] == ALGO_RSA) { + if (algo_len < 3) { + return SW_WRONG_DATA(); + } int exponent = 65537, nlen = (algo[1] << 8) | algo[2]; printf("KEYPAIR RSA %d\r\n", nlen); //if (nlen != 2048 && nlen != 4096) @@ -117,9 +123,10 @@ int cmd_keypair_gen(void) { uint8_t key_size = 32; memcpy(aes_key, random_bytes_get(key_size), key_size); r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true); - /* if storing the key fails, we silently continue */ - //if (r != PICOKEYS_OK) - // return SW_EXEC_ERROR(); + mbedtls_platform_zeroize(aes_key, sizeof(aes_key)); + if (r != PICOKEYS_OK) { + return SW_EXEC_ERROR(); + } } flash_commit(); return SW_OK(); @@ -129,7 +136,7 @@ int cmd_keypair_gen(void) { if (!file_has_data(ef)) { return SW_REFERENCE_NOT_FOUND(); } - res_APDU_size = file_get_size(ef); + res_APDU_size = MIN(file_get_size(ef), OPENPGP_MAX_RESPONSE_SIZE); memcpy(res_APDU, file_get_data(ef), res_APDU_size); return SW_OK(); } diff --git a/src/openpgp/cmd_pso.c b/src/openpgp/cmd_pso.c index af7fc83..db333d8 100644 --- a/src/openpgp/cmd_pso.c +++ b/src/openpgp/cmd_pso.c @@ -27,6 +27,7 @@ int cmd_pso(void) { uint16_t algo_fid = 0x0, pk_fid = 0x0; + uint16_t uif_fid = 0x0; bool is_aes = false; if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { if (!has_pw3 && !has_pw1) { @@ -34,6 +35,7 @@ int cmd_pso(void) { } algo_fid = EF_ALGO_PRIV1; pk_fid = EF_PK_SIG; + uif_fid = EF_UIF_SIG; } else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { if (!has_pw3 && !has_pw2) { @@ -41,6 +43,15 @@ int cmd_pso(void) { } algo_fid = algo_dec; pk_fid = pk_dec; + uif_fid = pk_dec == EF_PK_AUT ? EF_UIF_AUT : EF_UIF_DEC; + } + else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { + if (!has_pw3 && !has_pw2) { + return SW_SECURITY_STATUS_NOT_SATISFIED(); + } + algo_fid = algo_dec; + pk_fid = pk_dec; + uif_fid = pk_dec == EF_PK_AUT ? EF_UIF_AUT : EF_UIF_DEC; } else { return SW_INCORRECT_P1P2(); @@ -52,32 +63,41 @@ int cmd_pso(void) { const uint8_t *algo = algorithm_attr_rsa2k + 1; if (algo_ef && algo_ef->data) { algo = file_get_data(algo_ef); - } - if (apdu.data[0] == 0x2) { //AES PSO? - if (((apdu.nc - 1) % 16 == 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86) || - (apdu.nc % 16 == 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80)) { - pk_fid = EF_AES_KEY; - is_aes = true; + uint16_t algo_len = file_get_size(algo_ef); + if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) { + return SW_WRONG_DATA(); } } + bool aes_decipher = apdu.nc > 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86 && + apdu.data[0] == 0x02 && (apdu.nc - 1) % 16 == 0; + bool aes_encipher = apdu.nc > 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80 && + apdu.nc % 16 == 0; + if (aes_decipher || aes_encipher) { + pk_fid = EF_AES_KEY; + is_aes = true; + } + else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { + return SW_WRONG_LENGTH(); + } file_t *ef = file_search_by_fid(pk_fid, NULL, SPECIFY_EF); if (!ef) { return SW_REFERENCE_NOT_FOUND(); } - if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) { + if (wait_button_pressed_fid(uif_fid) == true) { return SW_SECURE_MESSAGE_EXEC_ERROR(); } int r = PICOKEYS_OK; - size_t key_size = file_get_size(ef); + size_t key_size = 0; if (is_aes) { uint8_t aes_key[32]; - r = load_aes_key(aes_key, ef); + r = load_aes_key(aes_key, &key_size, ef); if (r != PICOKEYS_OK) { memset(aes_key, 0, sizeof(aes_key)); return SW_EXEC_ERROR(); } + const uint16_t aes_key_bits = (uint16_t)(key_size * 8); if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher - r = aes_decrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1); + r = aes_decrypt(aes_key, NULL, aes_key_bits, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1); memset(aes_key, 0, sizeof(aes_key)); if (r != PICOKEYS_OK) { return SW_EXEC_ERROR(); @@ -86,7 +106,7 @@ int cmd_pso(void) { res_APDU_size = apdu.nc - 1; } else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher - r = aes_encrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc); + r = aes_encrypt(aes_key, NULL, aes_key_bits, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc); memset(aes_key, 0, sizeof(aes_key)); if (r != PICOKEYS_OK) { return SW_EXEC_ERROR(); @@ -105,6 +125,7 @@ int cmd_pso(void) { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } + key_size = mbedtls_rsa_get_len(&ctx); if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { size_t olen = 0; r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen); @@ -165,23 +186,42 @@ int cmd_pso(void) { } //if (len != 2*key_size-1) // return SW_WRONG_LENGTH(); - memcpy(kdata, file_get_data(ef), key_size); - if (dek_decrypt(kdata, key_size) != 0) { + if (load_key_data(ef, kdata, sizeof(kdata), &key_size, true) != PICOKEYS_OK || + key_size < 2) { + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return SW_EXEC_ERROR(); } mbedtls_ecdh_init(&ctx); mbedtls_ecp_group_id gid = kdata[0]; r = mbedtls_ecdh_setup(&ctx, gid); if (r != 0) { + mbedtls_platform_zeroize(kdata, sizeof(kdata)); mbedtls_ecdh_free(&ctx); return SW_DATA_INVALID(); } r = mbedtls_ecp_read_key(gid, (mbedtls_ecdsa_context *)&ctx.ctx.mbed_ecdh, kdata + 1, key_size - 1); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); if (r != 0) { mbedtls_ecdh_free(&ctx); return SW_DATA_INVALID(); } - r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1); + if (mbedtls_ecp_get_type(&ctx.ctx.mbed_ecdh.grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + size_t montgomery_len = mbedtls_mpi_size(&ctx.ctx.mbed_ecdh.grp.P); + const uint8_t *peer = data; + if (len == montgomery_len + 1 && data[0] == 0x40) { + peer = data + 1; + len--; + } + if (len != montgomery_len) { + mbedtls_ecdh_free(&ctx); + return SW_WRONG_LENGTH(); + } + r = mbedtls_ecp_point_read_binary(&ctx.ctx.mbed_ecdh.grp, &ctx.ctx.mbed_ecdh.Qp, + peer, len); + } + else { + r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1); + } if (r != 0) { mbedtls_ecdh_free(&ctx); return SW_DATA_INVALID(); diff --git a/src/openpgp/cmd_put_data.c b/src/openpgp/cmd_put_data.c index d6d4034..51a5afc 100644 --- a/src/openpgp/cmd_put_data.c +++ b/src/openpgp/cmd_put_data.c @@ -19,13 +19,20 @@ int cmd_put_data(void) { uint16_t fid = (P1(apdu) << 8) | P2(apdu); + uint16_t requested_fid = fid; + bool is_algorithm_attr = fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT; file_t *ef; if (fid == EF_RESET_CODE) { fid = EF_RC; } - else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) { + else if (is_algorithm_attr) { fid |= 0x1000; } + if (is_algorithm_attr && apdu.nc > 0 && + (apdu.nc > OPENPGP_MAX_ALGORITHM_ATTR_SIZE || + (apdu.data[0] == ALGO_RSA && apdu.nc < 3))) { + return SW_WRONG_DATA(); + } if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); } @@ -40,15 +47,39 @@ int cmd_put_data(void) { } if (fid == EF_PW_STATUS) { fid = EF_PW_PRIV; - apdu.nc = 4; //we silently ommit the reset parameters + if (apdu.nc == 0) { + return SW_WRONG_LENGTH(); + } + if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) { + return SW_REFERENCE_NOT_FOUND(); + } } - if (currentEF && currentEF->fid == fid) { // previously selected same EF + if (requested_fid == EF_CH_CERT) { + if (currentEF && currentEF->fid >= EF_CH_1 && currentEF->fid <= EF_CH_3) { + ef = currentEF; + } + else if (!(ef = file_search_by_fid(EF_CH_1, NULL, SPECIFY_EF))) { + return SW_REFERENCE_NOT_FOUND(); + } + fid = ef->fid; + } + else if (currentEF && currentEF->fid == fid) { // previously selected same EF ef = currentEF; } if (ef->type & FILE_DATA_FLASH) { int r = 0; if (apdu.nc > 0) { - if (fid == EF_RC) { + if (requested_fid == EF_PW_STATUS) { + uint8_t pw_status[7] = { 0x1, 127, 127, 127, 3, 3, 3 }; + if (file_has_data(ef)) { + memset(pw_status, 0, sizeof(pw_status)); + uint16_t status_len = MIN(file_get_size(ef), sizeof(pw_status)); + memcpy(pw_status, file_get_data(ef), status_len); + } + memcpy(pw_status, apdu.data, MIN(apdu.nc, 4)); + r = file_put_data(ef, pw_status, sizeof(pw_status)); + } + else if (fid == EF_RC) { has_rc = false; if ((r = load_dek()) != PICOKEYS_OK) { return SW_EXEC_ERROR(); @@ -59,7 +90,7 @@ int cmd_put_data(void) { pin_derive_verifier(apdu.data, apdu.nc, dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); - file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF); + file_t *tf = file_search_by_fid(EF_DEK_RC, NULL, SPECIFY_EF); if (!tf) { return SW_REFERENCE_NOT_FOUND(); } @@ -79,7 +110,10 @@ int cmd_put_data(void) { flash_commit(); } else { - file_delete(ef); + if (flash_clear_file(ef) != PICOKEYS_OK) { + return SW_MEMORY_FAILURE(); + } + flash_commit(); } } return SW_OK(); diff --git a/src/openpgp/cmd_select_data.c b/src/openpgp/cmd_select_data.c index ce6a8bb..8c2eca6 100644 --- a/src/openpgp/cmd_select_data.c +++ b/src/openpgp/cmd_select_data.c @@ -23,29 +23,40 @@ int cmd_select_data(void) { if (P2(apdu) != 0x4) { return SW_WRONG_P1P2(); } + if (apdu.nc < 5u) { + return SW_WRONG_LENGTH(); + } if (apdu.data[0] != 0x60) { return SW_WRONG_DATA(); } - if (apdu.nc != (uint32_t) apdu.data[1] + 2u || apdu.nc < 5u) { + if (apdu.nc != (uint32_t) apdu.data[1] + 2u) { return SW_WRONG_LENGTH(); } if (apdu.data[2] != 0x5C) { return SW_WRONG_DATA(); } if (apdu.data[3] == 2) { + if (apdu.nc < 6u) { + return SW_WRONG_LENGTH(); + } fid = (apdu.data[4] << 8) | apdu.data[5]; } - else { + else if (apdu.data[3] == 1) { fid = apdu.data[4]; } + else { + return SW_WRONG_DATA(); + } + if (fid != EF_CH_CERT || P1(apdu) >= 3) { + return SW_REFERENCE_NOT_FOUND(); + } if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); } if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { return SW_SECURITY_STATUS_NOT_SATISFIED(); } - fid &= ~0x6000; //Now get private DO - fid += P1(apdu); + fid = EF_CH_1 + P1(apdu); if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); } diff --git a/src/openpgp/do.c b/src/openpgp/do.c index 9d94107..8789585 100644 --- a/src/openpgp/do.c +++ b/src/openpgp/do.c @@ -32,6 +32,32 @@ int parse_algoinfo(const file_t *f, int mode); int parse_app_data(const file_t *f, int mode); int parse_discrete_do(const file_t *f, int mode); +static uint16_t response_remaining(void) { + return res_APDU_size < OPENPGP_MAX_RESPONSE_SIZE ? + OPENPGP_MAX_RESPONSE_SIZE - res_APDU_size : 0; +} + +static uint8_t encoded_len_size(uint16_t len) { + if (len >= 256) { + return 3; + } + if (len >= 128) { + return 2; + } + return 1; +} + +static uint16_t fit_tlv_value(uint16_t len, uint16_t available, uint8_t tag_size) { + if (available <= tag_size + 1) { + return 0; + } + uint16_t fitted = MIN(len, available - tag_size - 1); + while (fitted + tag_size + encoded_len_size(fitted) > available) { + fitted--; + } + return fitted; +} + int parse_do(uint16_t *fids, int mode) { int len = 0; file_t *ef; @@ -39,14 +65,27 @@ int parse_do(uint16_t *fids, int mode) { if ((ef = file_search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) { uint16_t data_len; if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { + if (mode == 1 && response_remaining() < 16) { + break; + } int (*file_data_func)(const file_t *, int) = NULL; memcpy(&file_data_func, &ef->data, sizeof(file_data_func)); + uint16_t initial_size = res_APDU_size; data_len = file_data_func(ef, mode); + if (mode == 1) { + data_len = res_APDU_size - initial_size; + } } else { data_len = file_get_size(ef); if (mode == 1) { if (fids[0] > 1 && res_APDU_size > 0) { + uint8_t tag_size = fids[i + 1] < 0x0100 ? 1 : 2; + uint16_t available = response_remaining(); + data_len = fit_tlv_value(data_len, available, tag_size); + if (available < tag_size + encoded_len_size(data_len)) { + break; + } if (fids[i + 1] < 0x0100) { res_APDU[res_APDU_size++] = fids[i + 1] & 0xff; } @@ -56,6 +95,9 @@ int parse_do(uint16_t *fids, int mode) { } res_APDU_size += tlv_format_len(data_len, res_APDU + res_APDU_size); } + else { + data_len = MIN(data_len, response_remaining()); + } if (file_has_data(ef)) { memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); } @@ -69,19 +111,24 @@ int parse_do(uint16_t *fids, int mode) { } int parse_trium(uint16_t fid, uint8_t num, size_t size) { + uint16_t initial_size = res_APDU_size; for (uint8_t i = 0; i < num; i++) { + uint16_t output_len = MIN(size, response_remaining()); + if (output_len == 0) { + break; + } file_t *ef; if ((ef = file_search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) { - uint16_t data_len = file_get_size(ef); + uint16_t data_len = MIN(file_get_size(ef), output_len); memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); - res_APDU_size += data_len; + memset(res_APDU + res_APDU_size + data_len, 0, output_len - data_len); } else { - memset(res_APDU + res_APDU_size, 0, size); - res_APDU_size += size; + memset(res_APDU + res_APDU_size, 0, output_len); } + res_APDU_size += output_len; } - return num * size; + return res_APDU_size - initial_size; } int parse_ch_data(const file_t *f, int mode) { @@ -106,13 +153,15 @@ int parse_sec_tpl(const file_t *f, int mode) { (void) mode; res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff; res_APDU[res_APDU_size++] = 5; + res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff; + res_APDU[res_APDU_size++] = 3; + memset(res_APDU + res_APDU_size, 0, 3); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); if (ef && ef->data) { - res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff; - res_APDU[res_APDU_size++] = 3; - memcpy(res_APDU + res_APDU_size, file_get_data(ef), 3); - res_APDU_size += 3; + uint16_t data_len = MIN(file_get_size(ef), 3); + memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); } + res_APDU_size += 3; return 5 + 2; } @@ -193,10 +242,12 @@ int parse_pw_status(const file_t *f, int mode) { res_APDU[res_APDU_size++] = 7; } ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY); + memset(res_APDU + res_APDU_size, 0, 7); if (ef && ef->data) { - memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7); - res_APDU_size += 7; + uint16_t data_len = MIN(file_get_size(ef), 7); + memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); } + res_APDU_size += 7; return res_APDU_size - init_len; } @@ -373,8 +424,13 @@ int parse_algoinfo(const file_t *f, int mode) { datalen += parse_algo(algorithm_attr_rsa2k, f->fid); } else { - uint16_t len = file_get_size(ef); + uint16_t len = MIN(file_get_size(ef), OPENPGP_MAX_ALGORITHM_ATTR_SIZE); + len = MIN(len, response_remaining()); if (res_APDU_size > 0) { + if (response_remaining() < 2) { + return datalen; + } + len = MIN(len, response_remaining() - 2); res_APDU[res_APDU_size++] = f->fid & 0xff; res_APDU[res_APDU_size++] = len & 0xff; datalen += 2; diff --git a/src/openpgp/files.c b/src/openpgp/files.c index e4f8b51..87cad82 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -252,8 +252,11 @@ file_t file_entries[] = { /* 59 */ { .fid = EF_DEK_PW3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, + /* 60 */ { .fid = EF_AES_KEY, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, // ** PIV ** // - /* 60 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL, + /* 61 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, /* 61 */ { .fid = EF_PIV_ATTESTATION, .parent = 0, .name = NULL, diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index a3575e8..dd4aabf 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -26,6 +26,8 @@ #include "random.h" #include "eac.h" #include "mbedtls/asn1.h" +#include "mbedtls/gcm.h" +#include "mbedtls/md.h" #include "usb.h" #include "ccid/ccid.h" #include "otp.h" @@ -44,6 +46,7 @@ uint8_t session_rc[32]; uint8_t session_pw3[32]; uint8_t dek[DEK_SIZE]; uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC, pk_aut = EF_PK_AUT; +extern bool is_gpg; uint8_t openpgp_aid[] = { 6, @@ -272,7 +275,7 @@ static void release_dek(void) { extern bool has_pwpiv; extern uint8_t session_pwpiv[32]; int load_dek(void) { - if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) { + if (!has_pw1 && !has_pw2 && !has_pw3 && !has_rc && !has_pwpiv) { return PICOKEYS_NO_LOGIN; } int r = PICOKEYS_OK; @@ -298,6 +301,28 @@ int load_dek(void) { r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32); } } + else if (has_rc) { + file_t *ef_dek_rc = file_search(EF_DEK_RC); + if (file_has_data(ef_dek_rc)) { + uint8_t *ef_data = file_get_data(ef_dek_rc); + if (ef_data[0] == 0x3) { // Format + r = decrypt_with_aad(session_rc, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek); + } + else { + return PICOKEYS_ERR_NULL_PARAM; + } + } + else { + file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF); + if (!tf) { + return PICOKEYS_ERR_FILE_NOT_FOUND; + } + + memcpy(dek, file_get_data(tf), IV_SIZE); + memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32, 32); + r = aes_decrypt_cfb_256(session_rc, dek, dek + IV_SIZE, 32); + } + } else if (has_pw3) { file_t *ef_dek_pw3 = file_search(EF_DEK_PW3); if (file_has_data(ef_dek_pw3)) { @@ -349,17 +374,7 @@ int load_dek(void) { return PICOKEYS_OK; } -int dek_encrypt(uint8_t *data, size_t len) { - int r; - if ((r = load_dek()) != PICOKEYS_OK) { - return r; - } - r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len); - release_dek(); - return r; -} - -int dek_decrypt(uint8_t *data, size_t len) { +static int dek_decrypt_legacy(uint8_t *data, size_t len) { int r; if ((r = load_dek()) != PICOKEYS_OK) { return r; @@ -369,6 +384,164 @@ int dek_decrypt(uint8_t *data, size_t len) { return r; } +#define ENCRYPTED_KEY_MAGIC_SIZE 4 +#define ENCRYPTED_KEY_NONCE_SIZE 12 +#define ENCRYPTED_KEY_TAG_SIZE 16 +#define ENCRYPTED_KEY_OVERHEAD (ENCRYPTED_KEY_MAGIC_SIZE + ENCRYPTED_KEY_NONCE_SIZE + ENCRYPTED_KEY_TAG_SIZE) + +static const uint8_t encrypted_key_magic[ENCRYPTED_KEY_MAGIC_SIZE] = { 'P', 'G', 'K', 1 }; + +static int derive_encrypted_key_nonce(uint16_t fid, const uint8_t *plaintext, size_t plaintext_len, uint8_t nonce[ENCRYPTED_KEY_NONCE_SIZE]) { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (!md_info) { + return PICOKEYS_EXEC_ERROR; + } + mbedtls_md_context_t md; + mbedtls_md_init(&md); + uint8_t digest[32] = { 0 }; + uint8_t fid_data[2] = { fid >> 8, fid & 0xff }; + int r = mbedtls_md_setup(&md, md_info, 1); + if (r == 0) { + r = mbedtls_md_hmac_starts(&md, dek, sizeof(dek)); + } + if (r == 0) { + r = mbedtls_md_hmac_update(&md, fid_data, sizeof(fid_data)); + } + if (r == 0) { + r = mbedtls_md_hmac_update(&md, plaintext, plaintext_len); + } + if (r == 0) { + r = mbedtls_md_hmac_finish(&md, digest); + } + mbedtls_md_free(&md); + if (r == 0) { + memcpy(nonce, digest, ENCRYPTED_KEY_NONCE_SIZE); + } + mbedtls_platform_zeroize(digest, sizeof(digest)); + return r == 0 ? PICOKEYS_OK : PICOKEYS_EXEC_ERROR; +} + +static void encrypted_key_aad(uint16_t fid, uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2]) { + memcpy(aad, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE); + aad[ENCRYPTED_KEY_MAGIC_SIZE] = fid >> 8; + aad[ENCRYPTED_KEY_MAGIC_SIZE + 1] = fid & 0xff; +} + +static int store_encrypted_key(file_t *ef, const uint8_t *plaintext, size_t plaintext_len) { + if (!ef || !plaintext || plaintext_len > UINT16_MAX - ENCRYPTED_KEY_OVERHEAD) { + return PICOKEYS_WRONG_DATA; + } + int r = load_dek(); + if (r != PICOKEYS_OK) { + return r; + } + + size_t record_len = plaintext_len + ENCRYPTED_KEY_OVERHEAD; + uint8_t *record = calloc(1, record_len); + if (!record) { + release_dek(); + return PICOKEYS_ERR_MEMORY_FATAL; + } + memcpy(record, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE); + uint8_t *nonce = record + ENCRYPTED_KEY_MAGIC_SIZE; + uint8_t *ciphertext = nonce + ENCRYPTED_KEY_NONCE_SIZE; + uint8_t *tag = ciphertext + plaintext_len; + uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2]; + encrypted_key_aad(ef->fid, aad); + + r = derive_encrypted_key_nonce(ef->fid, plaintext, plaintext_len, nonce); + mbedtls_gcm_context gcm; + mbedtls_gcm_init(&gcm); + if (r == PICOKEYS_OK) { + r = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, dek + IV_SIZE, 256); + } + if (r == 0) { + r = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, plaintext_len, nonce, ENCRYPTED_KEY_NONCE_SIZE, aad, sizeof(aad), plaintext, ciphertext, ENCRYPTED_KEY_TAG_SIZE, tag); + } + mbedtls_gcm_free(&gcm); + release_dek(); + if (r != 0) { + mbedtls_platform_zeroize(record, record_len); + free(record); + return PICOKEYS_EXEC_ERROR; + } + + r = file_put_data(ef, record, (uint16_t)record_len); + mbedtls_platform_zeroize(record, record_len); + free(record); + return r; +} + +int load_key_data(file_t *fkey, uint8_t *out, size_t out_size, size_t *out_len, bool use_dek) { + if (!file_has_data(fkey) || !out || !out_len) { + return PICOKEYS_WRONG_DATA; + } + size_t stored_len = file_get_size(fkey); + const uint8_t *stored = file_get_data(fkey); + + if (!use_dek) { + if (stored_len > out_size) { + return PICOKEYS_WRONG_DATA; + } + memcpy(out, stored, stored_len); + *out_len = stored_len; + return PICOKEYS_OK; + } + + if (stored_len >= ENCRYPTED_KEY_MAGIC_SIZE && + memcmp(stored, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE) == 0) { + if (stored_len < ENCRYPTED_KEY_OVERHEAD) { + return PICOKEYS_WRONG_DATA; + } + size_t plaintext_len = stored_len - ENCRYPTED_KEY_OVERHEAD; + if (plaintext_len > out_size) { + return PICOKEYS_WRONG_DATA; + } + const uint8_t *nonce = stored + ENCRYPTED_KEY_MAGIC_SIZE; + const uint8_t *ciphertext = nonce + ENCRYPTED_KEY_NONCE_SIZE; + const uint8_t *tag = ciphertext + plaintext_len; + uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2]; + encrypted_key_aad(fkey->fid, aad); + + int r = load_dek(); + if (r != PICOKEYS_OK) { + return r; + } + mbedtls_gcm_context gcm; + mbedtls_gcm_init(&gcm); + r = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, dek + IV_SIZE, 256); + if (r == 0) { + r = mbedtls_gcm_auth_decrypt(&gcm, plaintext_len, nonce, ENCRYPTED_KEY_NONCE_SIZE, aad, sizeof(aad), tag, ENCRYPTED_KEY_TAG_SIZE, ciphertext, out); + } + mbedtls_gcm_free(&gcm); + release_dek(); + if (r != 0) { + mbedtls_platform_zeroize(out, out_size); + return PICOKEYS_WRONG_DATA; + } + *out_len = plaintext_len; + return PICOKEYS_OK; + } + + if (stored_len > out_size) { + return PICOKEYS_WRONG_DATA; + } + memcpy(out, stored, stored_len); + int r = dek_decrypt_legacy(out, stored_len); + if (r != 0) { + mbedtls_platform_zeroize(out, out_size); + return PICOKEYS_EXEC_ERROR; + } + r = store_encrypted_key(fkey, out, stored_len); + if (r != PICOKEYS_OK) { + mbedtls_platform_zeroize(out, out_size); + return r; + } + flash_commit(); + *out_len = stored_len; + return PICOKEYS_OK; +} + static void init_openpgp(void) { isUserAuthenticated = false; has_pw1 = has_pw2 = has_pw3 = false; @@ -406,6 +579,7 @@ static int openpgp_select_aid(app_t *a, uint8_t force) { (void) force; a->process_apdu = openpgp_process_apdu; a->unload = openpgp_unload; + is_gpg = true; init_openpgp(); file_process_fci(file_openpgp, 1); memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4); @@ -674,16 +848,8 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) { } memcpy(kdata, key_ctx, key_size); } - if (use_kek) { - r = dek_encrypt(kdata, key_size); - if (r != PICOKEYS_OK) { - return r; - } - } - //r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size); - //if (r != PICOKEYS_OK) - // return r; - r = file_put_data(ef, kdata, key_size); + r = use_kek ? store_encrypted_key(ef, kdata, key_size) : file_put_data(ef, kdata, key_size); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); if (r != PICOKEYS_OK) { return r; } @@ -692,54 +858,72 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) { } int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) { - int key_size = file_get_size(fkey); + size_t key_size = 0; uint8_t kdata[4096 / 8]; - memcpy(kdata, file_get_data(fkey), key_size); - if (use_dek && dek_decrypt(kdata, key_size) != 0) { - return PICOKEYS_EXEC_ERROR; + int r = load_key_data(fkey, kdata, sizeof(kdata), &key_size, use_dek); + if (r != PICOKEYS_OK || key_size == 0 || key_size % 2 != 0) { + mbedtls_platform_zeroize(kdata, sizeof(kdata)); + return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r; } if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_WRONG_DATA; } if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_WRONG_DATA; } if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_EXEC_ERROR; } if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_WRONG_DATA; } if (mbedtls_rsa_complete(ctx) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_WRONG_DATA; } if (mbedtls_rsa_check_privkey(ctx) != 0) { mbedtls_rsa_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_WRONG_DATA; } + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_OK; } int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) { - int key_size = file_get_size(fkey); + size_t key_size = 0; uint8_t kdata[67]; //Worst case, 521 bit + 1byte - memcpy(kdata, file_get_data(fkey), key_size); - if (use_dek && dek_decrypt(kdata, key_size) != 0) { - return PICOKEYS_EXEC_ERROR; + int r = load_key_data(fkey, kdata, sizeof(kdata), &key_size, use_dek); + if (r != PICOKEYS_OK || key_size < 2) { + mbedtls_platform_zeroize(kdata, sizeof(kdata)); + return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r; } mbedtls_ecp_group_id gid = kdata[0]; - int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1); + r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1); if (r != 0) { mbedtls_ecp_keypair_free(ctx); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); return PICOKEYS_EXEC_ERROR; } mbedtls_platform_zeroize(kdata, sizeof(kdata)); - r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL); +#if defined(MBEDTLS_ECP_EDWARDS_ENABLED) + if (mbedtls_ecp_get_type(&ctx->grp) == MBEDTLS_ECP_TYPE_EDWARDS) { + r = mbedtls_ecp_point_edwards(&ctx->grp, &ctx->Q, &ctx->d, random_fill_iterator, NULL); + } + else +#endif + { + r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL); + } if (r != 0) { mbedtls_ecp_keypair_free(ctx); return PICOKEYS_EXEC_ERROR; @@ -747,51 +931,54 @@ int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) return PICOKEYS_OK; } -int load_aes_key(uint8_t *aes_key, file_t *fkey) { - int key_size = file_get_size(fkey); - memcpy(aes_key, file_get_data(fkey), key_size); - if (dek_decrypt(aes_key, key_size) != 0) { - return PICOKEYS_EXEC_ERROR; +int load_aes_key(uint8_t *aes_key, size_t *key_size, file_t *fkey) { + int r = load_key_data(fkey, aes_key, 32, key_size, true); + if (r != PICOKEYS_OK || (*key_size != 16 && *key_size != 24 && *key_size != 32)) { + mbedtls_platform_zeroize(aes_key, 32); + return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r; } - return PICOKEYS_OK; + return r; } mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) { - if (memcmp(algorithm_attr_p256k1 + 2, algo, algo_len) == 0) { +#define ALGORITHM_ATTR_MATCH(attr) \ + (algo_len == (size_t)((attr)[0] - 1u) && memcmp((attr) + 2, algo, algo_len) == 0) + if (ALGORITHM_ATTR_MATCH(algorithm_attr_p256k1)) { return MBEDTLS_ECP_DP_SECP256K1; } - else if (memcmp(algorithm_attr_p256r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p256r1)) { return MBEDTLS_ECP_DP_SECP256R1; } - else if (memcmp(algorithm_attr_p384r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p384r1)) { return MBEDTLS_ECP_DP_SECP384R1; } - else if (memcmp(algorithm_attr_p521r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p521r1)) { return MBEDTLS_ECP_DP_SECP521R1; } - else if (memcmp(algorithm_attr_bp256r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp256r1)) { return MBEDTLS_ECP_DP_BP256R1; } - else if (memcmp(algorithm_attr_bp384r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp384r1)) { return MBEDTLS_ECP_DP_BP384R1; } - else if (memcmp(algorithm_attr_bp512r1 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp512r1)) { return MBEDTLS_ECP_DP_BP512R1; } - else if (memcmp(algorithm_attr_cv25519 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_cv25519)) { return MBEDTLS_ECP_DP_CURVE25519; } - else if (memcmp(algorithm_attr_x448 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_x448)) { return MBEDTLS_ECP_DP_CURVE448; } #ifdef MBEDTLS_EDDSA_C - else if (memcmp(algorithm_attr_ed25519 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_ed25519)) { return MBEDTLS_ECP_DP_ED25519; } - else if (memcmp(algorithm_attr_ed448 + 2, algo, algo_len) == 0) { + else if (ALGORITHM_ATTR_MATCH(algorithm_attr_ed448)) { return MBEDTLS_ECP_DP_ED448; } #endif +#undef ALGORITHM_ATTR_MATCH return MBEDTLS_ECP_DP_NONE; } diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h index 0b763a2..f21e474 100644 --- a/src/openpgp/openpgp.h +++ b/src/openpgp/openpgp.h @@ -42,16 +42,8 @@ extern uint8_t dek[IV_SIZE + 32]; extern int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek); extern void make_rsa_response(mbedtls_rsa_context *rsa); extern void make_ecdsa_response(mbedtls_ecdsa_context *ecdsa); -extern int ecdsa_sign(mbedtls_ecdsa_context *ctx, - const uint8_t *data, - size_t data_len, - uint8_t *out, - size_t *out_len); -extern int rsa_sign(mbedtls_rsa_context *ctx, - const uint8_t *data, - size_t data_len, - uint8_t *out, - size_t *out_len); +extern int ecdsa_sign(mbedtls_ecdsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len); +extern int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len); extern int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek); extern int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey, bool use_dek); extern int pin_reset_retries(const file_t *pin, bool force); @@ -74,11 +66,9 @@ extern int reset_sig_count(void); extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut; extern bool wait_button_pressed_fid(uint16_t fid); extern void scan_files_openpgp(void); -extern int load_aes_key(uint8_t *aes_key, file_t *fkey); +extern int load_aes_key(uint8_t *aes_key, size_t *key_size, file_t *fkey); +extern int load_key_data(file_t *fkey, uint8_t *out, size_t out_size, size_t *out_len, bool use_dek); extern int inc_sig_count(void); -extern int dek_encrypt(uint8_t *data, size_t len); -extern int dek_decrypt(uint8_t *data, size_t len); - int cmd_select(void); int cmd_get_data(void); int cmd_get_next_data(void); @@ -104,4 +94,8 @@ int cmd_get_bulk_data(void); #define DEK_FILE_SIZE_OLD (IV_SIZE + 32 + 32 + 32 + 32) +#define OPENPGP_MAX_ALGORITHM_ATTR_SIZE 16 +#define OPENPGP_MAX_OBJECT_SIZE 2048 +#define OPENPGP_MAX_RESPONSE_SIZE 2048 + #endif