From 881d670b54f3d25cd5b8f31efa72adbf3c48dcda Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 14 Aug 2026 19:45:23 +0200 Subject: [PATCH] Reject truncated data object responses Signed-off-by: Pol Henarejos --- src/openpgp/cmd_get_data.c | 9 +++++++-- src/openpgp/cmd_put_data.c | 3 +++ src/openpgp/files.c | 4 ++-- src/openpgp/files.h | 1 + tests/card_test_empty_card.py | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/openpgp/cmd_get_data.c b/src/openpgp/cmd_get_data.c index 3a92ef3..56cea80 100644 --- a/src/openpgp/cmd_get_data.c +++ b/src/openpgp/cmd_get_data.c @@ -66,6 +66,9 @@ int cmd_get_data(void) { else { select_file(ef); } + if ((file_get_type(ef) & FILE_DATA_FLASH) && file_get_size(ef) > OPENPGP_MAX_DO_SIZE) { + return SW_MEMORY_FAILURE(); + } if (ef->data) { if (requested_fid == EF_PW_STATUS || requested_fid == EF_HIST_BYTES || requested_fid == EF_FULL_AID || requested_fid == EF_SEC_TPL) { @@ -73,7 +76,6 @@ int cmd_get_data(void) { } uint16_t fids[] = { 1, ef->fid }; uint16_t data_len = parse_do(fids, 1); - data_len = MIN(data_len, res_APDU_size); if (!(file_get_type(ef) & FILE_DATA_FLASH)) { uint8_t *p = NULL; tlv_item_t item; @@ -105,7 +107,10 @@ int cmd_get_data(void) { if (data_len >= 256) { off++; } - data_len = MIN(data_len, OPENPGP_MAX_RESPONSE_SIZE - off); + if (data_len > OPENPGP_MAX_RESPONSE_SIZE - off) { + res_APDU_size = 0; + return SW_MEMORY_FAILURE(); + } res_APDU_size = data_len; memmove(res_APDU + off, res_APDU, data_len); off = 0; diff --git a/src/openpgp/cmd_put_data.c b/src/openpgp/cmd_put_data.c index ceb6a10..f2722d6 100644 --- a/src/openpgp/cmd_put_data.c +++ b/src/openpgp/cmd_put_data.c @@ -51,6 +51,9 @@ int cmd_put_data(void) { if (!put_data_authorized(requested_fid)) { return SW_SECURITY_STATUS_NOT_SATISFIED(); } + if (apdu.nc > OPENPGP_MAX_DO_SIZE) { + return SW_WRONG_DATA(); + } uint16_t max_size = fixed_do_max_size(requested_fid); if (max_size != 0 && apdu.nc > max_size) { diff --git a/src/openpgp/files.c b/src/openpgp/files.c index 54ca13f..e0d2fe6 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -60,8 +60,8 @@ uint8_t extended_capabilities[] = { */ 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ (uint8_t)(OPENPGP_MAX_CHALLENGE_SIZE >> 8), (uint8_t)OPENPGP_MAX_CHALLENGE_SIZE, /* Max size of GET CHALLENGE */ - 0x08, 0x00, /* max. length of cardholder certificate (2KiB) */ - 0x08, 0x00, /* max. length of private DO (2KiB) */ + (uint8_t)(OPENPGP_MAX_DO_SIZE >> 8), (uint8_t)OPENPGP_MAX_DO_SIZE, + (uint8_t)(OPENPGP_MAX_DO_SIZE >> 8), (uint8_t)OPENPGP_MAX_DO_SIZE, 0x00, 0x1 }; diff --git a/src/openpgp/files.h b/src/openpgp/files.h index fa2f584..a4cc774 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -89,6 +89,7 @@ #define EF_GFM 0x7f74 //C #define OPENPGP_MAX_CHALLENGE_SIZE 1024u +#define OPENPGP_MAX_DO_SIZE 2036u // PIV diff --git a/tests/card_test_empty_card.py b/tests/card_test_empty_card.py index dbc7c5d..1fd24ee 100644 --- a/tests/card_test_empty_card.py +++ b/tests/card_test_empty_card.py @@ -201,7 +201,7 @@ def test_extended_capabilities(card): pytest.skip("Yubikey returns 6B00 when no key") else: a = get_data_object(card, 0xc0) - assert a == None or match(b'[\x70\x7F\x75\x77]\x00(?:\x00.|\x04\x00)[\x00\x08]\x00\x08\x00[\x00\x01][\x00\x01]', a) + assert a == None or match(b'[\x70\x7F\x75\x77]\x00(?:\x00.|\x04\x00)(?:[\x00\x08]\x00|\x07\xf4)(?:\x08\x00|\x07\xf4)[\x00\x01][\x00\x01]', a) def test_key_attributes_1(card): if card.is_yubikey: