From 2aab5cf5cde2a8ca14fd4b614689edbe237cf7dd Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 14 Aug 2026 19:54:10 +0200 Subject: [PATCH] Harden blocked PIN and terminate handling Signed-off-by: Pol Henarejos --- src/openpgp/cmd_terminate_df.c | 15 +++++++++++++-- src/openpgp/openpgp.c | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/openpgp/cmd_terminate_df.c b/src/openpgp/cmd_terminate_df.c index bcc0eed..4aab445 100644 --- a/src/openpgp/cmd_terminate_df.c +++ b/src/openpgp/cmd_terminate_df.c @@ -17,6 +17,11 @@ #include "openpgp.h" +static bool pw3_verifier_unusable(void) { + file_t *pw3 = file_search_by_fid(EF_PW3, NULL, SPECIFY_EF); + return !pw3 || !file_has_data(pw3) || file_get_size(pw3) < 3 || file_get_data(pw3)[0] == 0; +} + int cmd_terminate_df(void) { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { return SW_INCORRECT_P1P2(); @@ -25,8 +30,14 @@ int cmd_terminate_df(void) { if (!(retries = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); } - if (!has_pw3 && *(file_get_data(retries) + 6) > 0) { - return SW_SECURITY_STATUS_NOT_SATISFIED(); + bool pw3_unusable = pw3_verifier_unusable(); + if (!has_pw3 && !pw3_unusable) { + if (file_get_size(retries) <= 6) { + return SW_MEMORY_FAILURE(); + } + if (file_get_data(retries)[6] > 0) { + return SW_SECURITY_STATUS_NOT_SATISFIED(); + } } if (apdu.nc != 0) { return SW_WRONG_LENGTH(); diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index c0de7cf..67fd422 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -1046,10 +1046,23 @@ static void clear_pin_access_status(const file_t *pin) { } } +static bool pin_retry_blocked(const file_t *pin) { + file_t *pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF); + if (!pin || !pw_status || !file_has_data(pw_status)) { + return false; + } + uint16_t status_len = MIN(file_get_size(pw_status), 64u); + uint16_t retry_idx = 3u + (pin->fid & 0xfu); + return retry_idx < status_len && file_get_data(pw_status)[retry_idx] == 0; +} + int check_pin(const file_t *pin, const uint8_t *data, size_t len) { if (!file_has_data(pin)) { return SW_REFERENCE_NOT_FOUND(); } + if (pin_retry_blocked(pin)) { + return SW_PIN_BLOCKED(); + } if (offered_pin_len_impossible(pin, len)) { return SW_WRONG_DATA(); }