From ac7e34522a4f1847d280250b230400008eebc87d Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 12:33:35 +0100 Subject: [PATCH 01/12] Fixed resident credential storage when two userId have the same prefix. Added a specific test for this case. Fixes #241. Signed-off-by: Pol Henarejos --- src/fido/credential.c | 2 +- tests/pico-fido/test_022_discoverable.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/fido/credential.c b/src/fido/credential.c index 6bc479a..645417d 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -319,7 +319,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t * credential_free(&rcred); continue; } - if (memcmp(rcred.userId.data, cred.userId.data, MIN(rcred.userId.len, cred.userId.len)) == 0) { + if (rcred.userId.len == cred.userId.len && memcmp(rcred.userId.data, cred.userId.data, rcred.userId.len) == 0) { sloti = i; credential_free(&rcred); new_record = false; diff --git a/tests/pico-fido/test_022_discoverable.py b/tests/pico-fido/test_022_discoverable.py index 36b7055..92596de 100644 --- a/tests/pico-fido/test_022_discoverable.py +++ b/tests/pico-fido/test_022_discoverable.py @@ -202,10 +202,29 @@ def test_rk_with_allowlist_of_different_rp(resetdevice): assert e.value.code == CtapError.ERR.NO_CREDENTIALS +def test_same_prefix_userId(device): + """ + A make credential request with two different UserIds that share the same prefix should NOT overwrite. + """ + rp = {"id": "sameprefix.org", "name": "Example"} + user1 = {"id": b"user_12", "name": "A fixed name", "displayName": "A fixed display name"} + user2 = {"id": b"user_123", "name": "A fixed name", "displayName": "A fixed display name"} + + mc_res1 = device.MC(rp = rp, options={"rk":True}, user = user1) + + # Should not overwrite the first credential. + mc_res2 = device.MC(rp = rp, options={"rk":True}, user = user2) + + ga_res = device.GA(rp_id=rp['id'])['res'] + + assert ga_res.number_of_credentials == 2 + + def test_same_userId_overwrites_rk(resetdevice): """ A make credential request with a UserId & Rp that is the same as an existing one should overwrite. """ + resetdevice.reset() rp = {"id": "overwrite.org", "name": "Example"} user = generate_random_user() @@ -249,6 +268,7 @@ def test_returned_credential(device): ga_res = device.GA(allow_list=allow_list,options={'up':False})['res'] + print(ga_res) # No other credentials should be returned with pytest.raises(CtapError) as e: From 5fc84d70978347875a6f95dc53d1305694956fda Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 12:36:44 +0100 Subject: [PATCH 02/12] Reset internal state of GA to avoid phantom requests on GNA. When a previous GA had more than 1 credential, it stored the full list in the internal state. Later, if a GA had only 1 credential, subsequent GNA returned older state of previous non-related GA. Signed-off-by: Pol Henarejos --- src/fido/cbor.c | 4 ++++ src/fido/cbor_get_assertion.c | 30 +++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/fido/cbor.c b/src/fido/cbor.c index fec4d2f..f9ca3ed 100644 --- a/src/fido/cbor.c +++ b/src/fido/cbor.c @@ -41,6 +41,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len); int cbor_config(const uint8_t *data, size_t len); int cbor_vendor(const uint8_t *data, size_t len); int cbor_large_blobs(const uint8_t *data, size_t len); +extern void reset_gna_state(); extern int cmd_read_config(); @@ -59,6 +60,9 @@ int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { } if (cap_supported(CAP_FIDO2)) { if (cmd == CTAPHID_CBOR) { + if (data[0] != CTAP_GET_NEXT_ASSERTION) { + reset_gna_state(); + } if (data[0] == CTAP_MAKE_CREDENTIAL) { return cbor_make_credential(data + 1, len - 1); } diff --git a/src/fido/cbor_get_assertion.c b/src/fido/cbor_get_assertion.c index ee25e79..fac8e01 100644 --- a/src/fido/cbor_get_assertion.c +++ b/src/fido/cbor_get_assertion.c @@ -42,6 +42,22 @@ uint32_t timerx = 0; uint8_t *datax = NULL; size_t lenx = 0; +void reset_gna_state() { + for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { + credential_free(&credsx[i]); + } + if (datax) { + free(datax); + datax = NULL; + } + lenx = 0; + residentx = false; + timerx = 0; + flagsx = 0; + credentialCounter = 0; + numberOfCredentialsx = 0; +} + int cbor_get_next_assertion(const uint8_t *data, size_t len) { (void) data; (void) len; @@ -57,19 +73,7 @@ int cbor_get_next_assertion(const uint8_t *data, size_t len) { credentialCounter++; err: if (error != CborNoError || credentialCounter == numberOfCredentialsx) { - for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { - credential_free(&credsx[i]); - } - if (datax) { - free(datax); - datax = NULL; - } - lenx = 0; - residentx = false; - timerx = 0; - flagsx = 0; - credentialCounter = 0; - numberOfCredentialsx = 0; + reset_gna_state(); if (error == CborErrorImproperValue) { return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; } From bd499ae1d44c89c6d8302b599ba3a555de17c3ff Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 19:37:27 +0100 Subject: [PATCH 03/12] Remove print Signed-off-by: Pol Henarejos --- tests/pico-fido/test_022_discoverable.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pico-fido/test_022_discoverable.py b/tests/pico-fido/test_022_discoverable.py index 92596de..2faa2ed 100644 --- a/tests/pico-fido/test_022_discoverable.py +++ b/tests/pico-fido/test_022_discoverable.py @@ -268,7 +268,6 @@ def test_returned_credential(device): ga_res = device.GA(allow_list=allow_list,options={'up':False})['res'] - print(ga_res) # No other credentials should be returned with pytest.raises(CtapError) as e: From becdc943399067f1b09825e9e151f286e0000691 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 19:37:30 +0100 Subject: [PATCH 04/12] Disable button press by default since LED may not be properly configured until it is commissioned. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 7e6e3c8..08dc94a 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 7e6e3c8f3c7d4f7e9aa5f7f94de4a3560fbf59cb +Subproject commit 08dc94a144b4a7a4f1207052df26b28b0399c8c9 From 2e0333677b9a5b528000b3b1986e216379469c7b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 19:39:46 +0100 Subject: [PATCH 05/12] Fix button logic. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 08dc94a..7de9855 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 08dc94a144b4a7a4f1207052df26b28b0399c8c9 +Subproject commit 7de98552d1003de077fde1e644cd610c0b95b614 From d16016cf1ee318090ed4d56adc216db993516856 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 19:51:11 +0100 Subject: [PATCH 06/12] Upgrade Pico Keys SDK to v8.2 Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 7de9855..263e554 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 7de98552d1003de077fde1e644cd610c0b95b614 +Subproject commit 263e554cc6c59a5f168f8589c4bdabe6e1e64c25 From 81d97f1a18856f73b0ffed50afeaf735cc2c1a54 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 5 Jan 2026 19:56:09 +0100 Subject: [PATCH 07/12] Upgrade to v7.2 Signed-off-by: Pol Henarejos --- build_pico_fido.sh | 2 +- src/fido/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_pico_fido.sh b/build_pico_fido.sh index ab83499..497d70d 100755 --- a/build_pico_fido.sh +++ b/build_pico_fido.sh @@ -1,7 +1,7 @@ #!/bin/bash VERSION_MAJOR="7" -VERSION_MINOR="0" +VERSION_MINOR="2" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" #if ! [[ -z "${GITHUB_SHA}" ]]; then # SUFFIX="${SUFFIX}.${GITHUB_SHA}" diff --git a/src/fido/version.h b/src/fido/version.h index 7417630..f8625ce 100644 --- a/src/fido/version.h +++ b/src/fido/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define PICO_FIDO_VERSION 0x0700 +#define PICO_FIDO_VERSION 0x0702 #define PICO_FIDO_VERSION_MAJOR ((PICO_FIDO_VERSION >> 8) & 0xff) #define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff) From fe49149d86aeb05695d30b2cfe5015c8b19cd12d Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 6 Jan 2026 21:20:04 +0100 Subject: [PATCH 08/12] Update README with up-to-date info. Signed-off-by: Pol Henarejos --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 77f34ce..e12f571 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Pico FIDO This project transforms your Raspberry Pi Pico or ESP32 microcontroller into an integrated FIDO Passkey, functioning like a standard USB Passkey for authentication. -If you are looking for a Fido + OpenPGP, see: https://github.com/polhenarejos/pico-fido2 +If you are looking for a OpenPGP + Fido, see: https://github.com/polhenarejos/pico-fido2. Available through [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App"). ## Features Pico FIDO includes the following features: @@ -36,12 +36,13 @@ Pico FIDO includes the following features: - Challenge-response generation - Emulated keyboard interface - Button press generates an OTP that is directly typed +- Yubico Authenticator app compatible - Yubico YKMAN compatible - Nitrokey nitropy and nitroapp compatible - Secure Boot and Secure Lock in RP2350 and ESP32-S3 MCUs - One Time Programming to store the master key that encrypts all resident keys and seeds. - Rescue interface to allow recovery of the device if it becomes unresponsive or undetectable. -- LED customization with Pico Commissioner. +- LED customization with PicoKey App. All features comply with the specifications. If you encounter unexpected behavior or deviations from the specifications, please open an issue. @@ -55,11 +56,11 @@ Microcontrollers RP2350 and ESP32-S3 are designed to support secure environments If you own a Raspberry Pico (RP2040 or RP2350), go to [Download page](https://www.picokeys.com/getting-started/), select your vendor and model and download the proper firmware; or go to [Release page](https://www.github.com/polhenarejos/pico-fido/releases/) and download the UF2 file for your board. -Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with other proprietary tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner"). +Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with OpenSC or similar tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App"). You can use whatever VID/PID (i.e., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own. -Note that the pure-browser option [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") is the most recommended. +Note that the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App") is the most recommended. ## Build for Raspberry Pico Before building, ensure you have installed the toolchain for the Pico and that the Pico SDK is properly located on your drive. From 804ee68e86755c7b6e67fd612161c1f41a28d54a Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 8 Jan 2026 10:46:51 +0100 Subject: [PATCH 09/12] Remove non-standard MAKE CREDENTIAL step. It may collide with other userName and the purpose is achieved cleaner via Rescue interface. Signed-off-by: Pol Henarejos --- src/fido/cbor_make_credential.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/fido/cbor_make_credential.c b/src/fido/cbor_make_credential.c index 25a5d41..b53cd58 100644 --- a/src/fido/cbor_make_credential.c +++ b/src/fido/cbor_make_credential.c @@ -613,24 +613,6 @@ int cbor_make_credential(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PROCESSING); } - if (user.id.len > 0 && user.parent.name.len > 0 && user.displayName.len > 0) { - if (memcmp(user.parent.name.data, "+pico", 5) == 0) { - options.rk = pfalse; -#ifndef ENABLE_EMULATION - uint8_t *p = (uint8_t *)user.parent.name.data + 5; - if (memcmp(p, "CommissionProfile", 17) == 0) { - ret = phy_unserialize_data(user.id.data, (uint16_t)user.id.len, &phy_data); - if (ret == PICOKEY_OK) { - ret = phy_save(); - } - } -#endif - if (ret != PICOKEY_OK) { - CBOR_ERROR(CTAP2_ERR_PROCESSING); - } - } - } - uint8_t largeBlobKey[32] = {0}; if (extensions.largeBlobKey == ptrue && options.rk == ptrue) { ret = credential_derive_large_blob_key(cred_id, cred_id_len, largeBlobKey); From dc4565a8fb806ba95345576f6d62e9031dd8017d Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 15 Jan 2026 01:17:18 +0100 Subject: [PATCH 10/12] Fix LED default parameters in Pimoroni boards. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index 263e554..f108eeb 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 263e554cc6c59a5f168f8589c4bdabe6e1e64c25 +Subproject commit f108eebb936d0cac3201a4be58b37265e700a6cc From c23cc9ffe1dbbea889ce45707300c45554c1898b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 19 Jan 2026 16:36:49 +0100 Subject: [PATCH 11/12] Add set/get RTC. Signed-off-by: Pol Henarejos --- pico-keys-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico-keys-sdk b/pico-keys-sdk index f108eeb..8a0ef0b 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit f108eebb936d0cac3201a4be58b37265e700a6cc +Subproject commit 8a0ef0b30cf4fa586b415a37578695efe35a04be From 7ed90007ef7003c5d9b20bd0af8dcdd243a8303e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 19 Jan 2026 16:37:19 +0100 Subject: [PATCH 12/12] Add support for slots 3 & 4 in OTP. Both slots are activated by clicking three or four times the BOOTSEL button. Signed-off-by: Pol Henarejos --- src/fido/files.h | 2 ++ src/fido/otp.c | 81 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/fido/files.h b/src/fido/files.h index 1fe844b..715a306 100644 --- a/src/fido/files.h +++ b/src/fido/files.h @@ -40,6 +40,8 @@ #define EF_OATH_CODE 0xBAFF #define EF_OTP_SLOT1 0xBB00 #define EF_OTP_SLOT2 0xBB01 +#define EF_OTP_SLOT3 0xBB02 +#define EF_OTP_SLOT4 0xBB03 #define EF_OTP_PIN 0x10A0 // Nitrokey OTP PIN extern file_t *ef_keydev; diff --git a/src/fido/otp.c b/src/fido/otp.c index 29d7da8..3cc5811 100644 --- a/src/fido/otp.c +++ b/src/fido/otp.c @@ -49,6 +49,11 @@ void append_keyboard_buffer(const uint8_t *buf, size_t len) {} #define CONFIG_LED_INV 0x10 #define CONFIG_STATUS_MASK 0x1f +#define CONFIG3_VALID 0x01 +#define CONFIG4_VALID 0x02 +#define CONFIG3_TOUCH 0x04 +#define CONFIG4_TOUCH 0x08 + /* EXT Flags */ #define SERIAL_BTN_VISIBLE 0x01 // Serial number visible at startup (button press) #define SERIAL_USB_VISIBLE 0x02 // Serial number visible in USB iSerial field @@ -161,7 +166,7 @@ extern void scan_all(); void init_otp() { if (scanned == false) { scan_all(); - for (uint8_t i = 0; i < 2; i++) { + for (uint8_t i = 0; i < 4; i++) { file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i); uint8_t *data = file_get_data(ef); otp_config_t *otp_config = (otp_config_t *) data; @@ -207,7 +212,8 @@ int otp_button_pressed(uint8_t slot) { if (!cap_supported(CAP_OTP)) { return 3; } - file_t *ef = search_dynamic_file(slot == 1 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); + uint16_t slot_ef = EF_OTP_SLOT1 + slot - 1; + file_t *ef = search_dynamic_file(slot_ef); const uint8_t *data = file_get_data(ef); otp_config_t *otp_config = (otp_config_t *) data; if (file_has_data(ef) == false) { @@ -333,6 +339,39 @@ int otp_unload() { } uint8_t status_byte = 0x0; +uint16_t otp_status_ext() { + for (int i = 0; i < 4; i++) { + file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i); + if (file_has_data(ef)) { + res_APDU[res_APDU_size++] = 0xB0 + i; + res_APDU[res_APDU_size++] = 0; // Filled later + uint8_t *p = res_APDU + res_APDU_size; + otp_config_t *otp_config = (otp_config_t *)file_get_data(ef); + *p++ = 0xA0; + *p++ = 2; + *p++ = otp_config->tkt_flags; + *p++ = otp_config->cfg_flags; + if (otp_config->cfg_flags & CHAL_YUBICO && otp_config->tkt_flags & CHAL_RESP) { + + } + else if (otp_config->tkt_flags & OATH_HOTP) { + } + else if (otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET) { + } + else { + *p++ = 0xC0; + *p++ = 6; + memcpy(p, otp_config->fixed_data, 6); + p += 6; + } + uint8_t len = p - (res_APDU + res_APDU_size); + res_APDU[res_APDU_size - 1] = len; + res_APDU_size += len; + } + } + return SW_OK(); +} + uint16_t otp_status(bool is_otp) { if (scanned == false) { scan_all(); @@ -384,12 +423,13 @@ bool check_crc(const otp_config_t *data) { bool _is_otp = false; int cmd_otp() { uint8_t p1 = P1(apdu), p2 = P2(apdu); - if (p2 != 0x00) { - return SW_INCORRECT_P1P2(); - } if (p1 == 0x01 || p1 == 0x03) { // Configure slot otp_config_t *odata = (otp_config_t *) apdu.data; - file_t *ef = file_new(p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); + if (p1 == 0x03 && p2 != 0x0) { + return SW_INCORRECT_P1P2(); + } + uint16_t slot = (p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2; + file_t *ef = file_new(slot); if (file_has_data(ef)) { otp_config_t *otpc = (otp_config_t *) file_get_data(ef); if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) { @@ -415,10 +455,14 @@ int cmd_otp() { } else if (p1 == 0x04 || p1 == 0x05) { // Update slot otp_config_t *odata = (otp_config_t *) apdu.data; + if (p1 == 0x05 && p2 != 0x0) { + return SW_INCORRECT_P1P2(); + } + uint16_t slot = (p1 == 0x04 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2; if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) { return SW_WRONG_DATA(); } - file_t *ef = search_dynamic_file(p1 == 0x04 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); + file_t *ef = search_dynamic_file(slot); if (file_has_data(ef)) { otp_config_t *otpc = (otp_config_t *) file_get_data(ef); if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) { @@ -446,8 +490,16 @@ int cmd_otp() { else if (p1 == 0x06) { // Swap slots uint8_t tmp[otp_config_size + 8]; bool ef1_data = false; - file_t *ef1 = file_new(EF_OTP_SLOT1); - file_t *ef2 = file_new(EF_OTP_SLOT2); + uint16_t slot1 = EF_OTP_SLOT1, slot2 = EF_OTP_SLOT2; + if (apdu.ne > 0) { + if (apdu.ne != 2) { + return SW_WRONG_LENGTH(); + } + slot1 += apdu.data[0]; + slot2 += apdu.data[1]; + } + file_t *ef1 = file_new(slot1); + file_t *ef2 = file_new(slot2); if (file_has_data(ef1)) { memcpy(tmp, file_get_data(ef1), file_get_size(ef1)); ef1_data = true; @@ -458,7 +510,7 @@ int cmd_otp() { else { delete_file(ef1); // When a dynamic file is deleted, existing referenes are invalidated - ef2 = file_new(EF_OTP_SLOT2); + ef2 = file_new(slot2); } if (ef1_data) { file_put_data(ef2, tmp, sizeof(tmp)); @@ -478,8 +530,15 @@ int cmd_otp() { else if (p1 == 0x13) { // Get config man_get_config(); } + else if (p1 == 0x14) { + otp_status_ext(); + } else if (p1 == 0x30 || p1 == 0x38 || p1 == 0x20 || p1 == 0x28) { // Calculate OTP - file_t *ef = search_dynamic_file(p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); + if ((p1 == 0x38 || p1 == 0x28) && p2 != 0x0) { + return SW_INCORRECT_P1P2(); + } + uint16_t slot = (p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2; + file_t *ef = search_dynamic_file(slot); if (file_has_data(ef)) { otp_config_t *otp_config = (otp_config_t *) file_get_data(ef); if (!(otp_config->tkt_flags & CHAL_RESP)) {