Firmware for the Pico / Pico 2 that acts as a USB FIDO2 authenticator: CTAP2 and U2F, passkeys, BOOTSEL as the touch button, and clientPIN with PIN/UV auth protocols 1 and 2. A host simulator runs the same core so the python-fido2 test suite exercises it without hardware. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
1.7 KiB
C
61 lines
1.7 KiB
C
// Persistent state: master secret, signature counter and resident credentials.
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "cred.h"
|
|
|
|
#define RK_SLOTS 64
|
|
#define RK_MAX_USER_ID 64
|
|
#define RK_MAX_RP_ID 128
|
|
#define RK_MAX_NAME 64
|
|
|
|
// One resident (discoverable) credential. Exactly one 512-byte flash slot.
|
|
typedef struct {
|
|
uint32_t magic; // managed by storage.c
|
|
uint32_t created; // signature counter at creation, orders credentials
|
|
uint8_t rp_id_hash[32];
|
|
uint8_t cred_id[CRED_ID_LEN];
|
|
uint8_t user_id_len;
|
|
uint8_t user_id[RK_MAX_USER_ID];
|
|
uint8_t rp_id_len;
|
|
char rp_id[RK_MAX_RP_ID];
|
|
uint8_t user_name_len;
|
|
char user_name[RK_MAX_NAME];
|
|
uint8_t display_name_len;
|
|
char display_name[RK_MAX_NAME];
|
|
uint8_t reserved[99];
|
|
} rk_record_t;
|
|
|
|
_Static_assert(sizeof(rk_record_t) == 512, "rk_record_t must fill one slot");
|
|
|
|
void storage_init(void);
|
|
const uint8_t *storage_master_secret(void);
|
|
|
|
// Increments the global signature counter and returns the new value.
|
|
uint32_t storage_counter_next(void);
|
|
|
|
// Generates a new master secret and deletes all resident credentials and the PIN.
|
|
void storage_reset(void);
|
|
|
|
// Returns false if the slot does not hold a credential.
|
|
bool storage_rk_read(int slot, rk_record_t *out);
|
|
|
|
// Stores a credential, replacing any with the same RP and user ID. Returns a
|
|
// CTAP status code.
|
|
int storage_rk_save(const rk_record_t *rec);
|
|
|
|
void storage_rk_delete(int slot);
|
|
|
|
// PIN state. The PIN itself is never stored, only LEFT(SHA-256(PIN), 16).
|
|
typedef struct {
|
|
bool set;
|
|
uint8_t retries;
|
|
uint8_t hash[16];
|
|
} pin_state_t;
|
|
|
|
// Returns false if no PIN state was saved since the last reset.
|
|
bool storage_pin_load(pin_state_t *out);
|
|
void storage_pin_save(const pin_state_t *state);
|