From b4cb9a0cb4ea0fdecba2566c5d90c7ab98b4e6bf Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 9 Aug 2026 01:32:01 +0200 Subject: [PATCH] Fix credential and container for imported credentials. Signed-off-by: Pol Henarejos --- src/fido/credential.c | 2 ++ src/fido/credential.h | 1 + src/fido/resident_container.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/fido/credential.c b/src/fido/credential.c index 9c66bdb..d147aa0 100644 --- a/src/fido/credential.c +++ b/src/fido/credential.c @@ -990,6 +990,7 @@ int credential_load_resident(const file_t *ef, const uint8_t *rp_id_hash, Creden if (!file_has_data(ef) || !rp_id_hash || !cred) { return CTAP1_ERR_INVALID_PARAMETER; } + cred->imported = false; if (resident_container_is_marker(ef)) { if (!credential_resident_usable(ef)) { return CTAP2_ERR_NO_CREDENTIALS; @@ -1017,6 +1018,7 @@ int credential_load_resident(const file_t *ef, const uint8_t *rp_id_hash, Creden fido_resident_metadata_t resident_metadata; ret = resident_container_read_metadata((uint8_t)ef->fid, &resident_metadata); if (ret == PICOKEYS_OK && resident_metadata.properties == FIDO_RESIDENT_PROPERTY_IMPORTED) { + cred->imported = true; ret = credential_resident_container_read_alloc(ef, FIDO_RESIDENT_OBJECT_METADATA, &metadata, &metadata_len); if (ret == PICOKEYS_OK) ret = credential_resident_container_read_alloc(ef, FIDO_RESIDENT_OBJECT_PRIVATE_KEY, &private_key, &private_key_len); if (ret == PICOKEYS_OK) ret = credential_parse_metadata(metadata, metadata_len, cred); diff --git a/src/fido/credential.h b/src/fido/credential.h index 7c8c993..ccc3847 100644 --- a/src/fido/credential.h +++ b/src/fido/credential.h @@ -54,6 +54,7 @@ typedef struct Credential { CborByteString residentId; CborByteString privateKey; CredOptions opts; + bool imported; bool present; uint64_t rtc_creation; } Credential; diff --git a/src/fido/resident_container.c b/src/fido/resident_container.c index 32bdf40..de41dae 100644 --- a/src/fido/resident_container.c +++ b/src/fido/resident_container.c @@ -26,6 +26,10 @@ #define FIDO_RESIDENT_MANIFEST_SLOT_1_PREFIX 0xd2u #define FIDO_RESIDENT_RECORD_SLOT_0_PREFIX 0xd3u #define FIDO_RESIDENT_RECORD_SLOT_1_PREFIX 0xd7u +#define FIDO_RESIDENT_RECORD_PRIVATE_SLOT_0_PREFIX 0xe0u +#define FIDO_RESIDENT_RECORD_PRIVATE_SLOT_1_PREFIX 0xe1u +#define FIDO_RESIDENT_RECORD_STATE_SLOT_0_PREFIX 0xe2u +#define FIDO_RESIDENT_RECORD_STATE_SLOT_1_PREFIX 0xe3u #define FIDO_RESIDENT_CONTAINER_MARKER_SIZE 8u #define FIDO_RESIDENT_CONTAINER_MARKER_VERSION_OFFSET 4u #define FIDO_RESIDENT_CONTAINER_MARKER_SLOT_OFFSET 5u @@ -53,12 +57,30 @@ static uint16_t resident_record_fid(uint8_t slot, uint8_t manifest_slot, uint16_ prefix = manifest_slot == 0 ? 0xdbu : 0xdcu; return (uint16_t)((prefix << 8) | slot); } + else if (object_type == FIDO_RESIDENT_OBJECT_PRIVATE_KEY) { + prefix = manifest_slot == 0 ? FIDO_RESIDENT_RECORD_PRIVATE_SLOT_0_PREFIX : FIDO_RESIDENT_RECORD_PRIVATE_SLOT_1_PREFIX; + return (uint16_t)((prefix << 8) | slot); + } + else if (object_type == FIDO_RESIDENT_OBJECT_STATE) { + prefix = manifest_slot == 0 ? FIDO_RESIDENT_RECORD_STATE_SLOT_0_PREFIX : FIDO_RESIDENT_RECORD_STATE_SLOT_1_PREFIX; + return (uint16_t)((prefix << 8) | slot); + } else { prefix = manifest_slot == 0 ? FIDO_RESIDENT_RECORD_SLOT_0_PREFIX : FIDO_RESIDENT_RECORD_SLOT_1_PREFIX; } return (uint16_t)(((prefix + object_type - 1u) << 8) | slot); } +static uint16_t resident_record_fid_legacy(uint8_t slot, uint8_t manifest_slot, uint16_t object_type) { + uint8_t prefix; + if (object_type == FIDO_RESIDENT_OBJECT_METADATA) { + prefix = manifest_slot == 0 ? 0xdbu : 0xdcu; + return (uint16_t)((prefix << 8) | slot); + } + prefix = manifest_slot == 0 ? FIDO_RESIDENT_RECORD_SLOT_0_PREFIX : FIDO_RESIDENT_RECORD_SLOT_1_PREFIX; + return (uint16_t)(((prefix + object_type - 1u) << 8) | slot); +} + static bool resident_object_type_valid(uint16_t object_type) { return object_type >= FIDO_RESIDENT_OBJECT_RP_ID_HASH && object_type <= FIDO_RESIDENT_OBJECT_STATE; } @@ -68,7 +90,13 @@ static bool resident_record_id_valid(uint8_t slot, const file_object_descriptor_ return false; } uint16_t record_fid = (uint16_t)object->record_id; - return record_fid == resident_record_fid(slot, 0, object->object_type) || record_fid == resident_record_fid(slot, 1, object->object_type); + if (record_fid == resident_record_fid(slot, 0, object->object_type) || record_fid == resident_record_fid(slot, 1, object->object_type)) { + return true; + } + if (object->object_type == FIDO_RESIDENT_OBJECT_PRIVATE_KEY || object->object_type == FIDO_RESIDENT_OBJECT_STATE) { + return record_fid == resident_record_fid_legacy(slot, 0, object->object_type) || record_fid == resident_record_fid_legacy(slot, 1, object->object_type); + } + return false; } static int resident_replace_file(uint16_t fid, const uint8_t *data, uint32_t data_size) {