Skey: a FIDO2 security key on the Raspberry Pi Pico
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>
This commit is contained in:
commit
6c7e6ab5f5
41 files changed
+4218
No files matched your search
@@ -0,0 +1,86 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/rand.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "platform.h"
|
||||
|
||||
// The storage region is the last 64 KB of flash, far past the firmware image.
|
||||
#define STORAGE_FLASH_OFFSET (PICO_FLASH_SIZE_BYTES - STORAGE_SIZE)
|
||||
|
||||
_Static_assert(STORAGE_SECTOR_SIZE == FLASH_SECTOR_SIZE, "sector size mismatch");
|
||||
_Static_assert(STORAGE_PAGE_SIZE == FLASH_PAGE_SIZE, "page size mismatch");
|
||||
|
||||
extern char __flash_binary_end;
|
||||
|
||||
void platform_led(bool on) {
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
gpio_put(PICO_DEFAULT_LED_PIN, on);
|
||||
#else
|
||||
(void)on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void platform_init(void) {
|
||||
if ((uintptr_t)&__flash_binary_end > XIP_BASE + STORAGE_FLASH_OFFSET)
|
||||
platform_panic("firmware overlaps the storage region");
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t platform_millis(void) {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
// pico_rand mixes fresh hardware entropy (ROSC jitter, timers, and the TRNG
|
||||
// on RP2350) into every call. Each output block hashes many of those calls.
|
||||
void platform_random(uint8_t *buf, size_t len) {
|
||||
uint64_t samples[32];
|
||||
uint8_t block[32];
|
||||
while (len > 0) {
|
||||
for (size_t i = 0; i < 32; i++) samples[i] = get_rand_64();
|
||||
crypto_part_t part = {samples, sizeof(samples)};
|
||||
crypto_sha256(&part, 1, block);
|
||||
size_t n = len < sizeof(block) ? len : sizeof(block);
|
||||
memcpy(buf, block, n);
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
crypto_wipe(samples, sizeof(samples));
|
||||
crypto_wipe(block, sizeof(block));
|
||||
}
|
||||
|
||||
void platform_panic(const char *msg) {
|
||||
panic("%s", msg);
|
||||
}
|
||||
|
||||
void platform_wink(void) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
platform_led(true);
|
||||
sleep_ms(100);
|
||||
platform_led(false);
|
||||
sleep_ms(100);
|
||||
}
|
||||
}
|
||||
|
||||
void platform_flash_read(uint32_t offset, void *buf, size_t len) {
|
||||
memcpy(buf, (const void *)(XIP_BASE + STORAGE_FLASH_OFFSET + offset), len);
|
||||
}
|
||||
|
||||
// Flash is unavailable for execution while it is being written, so interrupts
|
||||
// (whose handlers live in flash) stay off for the duration.
|
||||
void platform_flash_erase(uint32_t offset) {
|
||||
uint32_t irq = save_and_disable_interrupts();
|
||||
flash_range_erase(STORAGE_FLASH_OFFSET + offset, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts(irq);
|
||||
}
|
||||
|
||||
void platform_flash_program(uint32_t offset, const void *buf, size_t len) {
|
||||
uint32_t irq = save_and_disable_interrupts();
|
||||
flash_range_program(STORAGE_FLASH_OFFSET + offset, buf, len);
|
||||
restore_interrupts(irq);
|
||||
}
|
||||
Reference in new issue
Block a user