CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
fido2.cpp
Go to the documentation of this file.
1
5
6#include "mod_fido2/fido2.h"
8#include "mod_fido2/ctap2.h"
9#include "mod_fido2/ctaphid.h"
10#include "mod_fido2/u2f.h"
12#include "cdc_log.h"
13#include <freertos/FreeRTOS.h>
14#include <freertos/task.h>
15#include <string.h>
16
17// USB transport hooks implemented by Fido2Module.cpp.
18namespace cdc::mod_fido2 {
20 bool fido2_usb_ready();
21 uint16_t fido2_usb_read(uint8_t* buffer);
22 bool fido2_usb_write(const uint8_t* buffer);
23}
24
25using namespace cdc::mod_fido2;
26
27static const char* TAG = "FIDO2";
28
30
31static struct {
34 TaskHandle_t task_handle;
35 bool pin_verified; // PIN was verified via ClientPIN protocol
36} g_fido2 = {};
37
42static void fido2_task(void* arg) {
43 (void)arg;
44 uint8_t packet[64];
45
46 LOG_I(TAG, "Processing task started");
47
48 while (1) {
49 // Process incoming packets and drain responses immediately to avoid overwriting
50 while (fido2_usb_available()) {
51 // If we still owe a response and USB isn't ready, pause input to avoid overwrite
53 break;
54 }
55
56 if (fido2_usb_read(packet) == 64) {
58 }
59
60 // Send pending responses before reading more packets (with brief wait)
61 int inner_retry = 0;
62 while (ctaphid_has_response()) {
63 if (fido2_usb_ready()) {
64 uint8_t response[64];
65 if (ctaphid_get_response_packet(response)) {
66 if (!fido2_usb_write(response)) {
67 LOG_W(TAG, "USB FIDO write failed");
68 break;
69 }
70 LOG_D(TAG, "Sent response packet");
71 inner_retry = 0;
72 vTaskDelay(pdMS_TO_TICKS(1));
73 }
74 } else {
75 inner_retry++;
76 if (inner_retry > 10) { // Brief wait, then continue in outer loop
77 LOG_D(TAG, "USB not ready, deferring to outer loop");
78 break;
79 }
80 vTaskDelay(pdMS_TO_TICKS(5));
81 }
82 }
83
84 // If response still pending, stop reading more packets this cycle
86 break;
87 }
88 }
89
90 // Send any remaining response packets (with retry on USB not ready)
91 int retry_count = 0;
92 while (ctaphid_has_response()) {
93 if (fido2_usb_ready()) {
94 uint8_t response[64];
95 if (ctaphid_get_response_packet(response)) {
96 if (!fido2_usb_write(response)) {
97 LOG_W(TAG, "USB FIDO write failed (outer)");
98 break;
99 }
100 LOG_D(TAG, "Sent response packet (outer)");
101 retry_count = 0; // Reset retry counter on success
102 vTaskDelay(pdMS_TO_TICKS(1));
103 }
104 } else {
105 // Wait for USB to be ready instead of giving up
106 retry_count++;
107 if (retry_count > 100) { // ~1 second timeout
108 LOG_W(TAG, "USB not ready timeout, aborting response");
109 break;
110 }
111 vTaskDelay(pdMS_TO_TICKS(10));
112 }
113 }
114
115 // Check timeouts
117
118 // Poll rate
119 vTaskDelay(pdMS_TO_TICKS(10));
120 }
121}
122
127bool fido2_init(void) {
128 LOG_I(TAG, "Initializing...");
129
130 memset(&g_fido2, 0, sizeof(g_fido2));
131
132 // Initialize storage layer
133 uint8_t cred_count = fido2_storage_init();
134 LOG_I(TAG, "Storage initialized, %d credentials", cred_count);
135
136 // Initialize CTAP2 protocol handler
137 if (!ctap2_init()) {
138 LOG_E(TAG, "CTAP2 init failed");
139 return false;
140 }
141
142 // Initialize CTAPHID transport
143 if (!ctaphid_init()) {
144 LOG_E(TAG, "CTAPHID init failed");
145 return false;
146 }
147
148 // Initialize U2F attestation certificate
149 if (!u2f_init_attestation()) {
150 LOG_W(TAG, "U2F attestation init failed (non-fatal)");
151 // Continue anyway - FIDO2 will still work, U2F might not
152 }
153
154 // Start FIDO2 processing task
155 xTaskCreate(fido2_task, "fido2", 6144, nullptr,
156 configMAX_PRIORITIES - 2, &g_fido2.task_handle);
157
158 g_fido2.initialized = true;
159 LOG_I(TAG, "Initialized");
160 return true;
161}
162
168 g_fido2.user_presence_cb = cb;
169}
170
179 const char *rp_id,
180 fido2_action_t action,
181 const char *user_name
182) {
183 if (g_fido2.user_presence_cb) {
184 return g_fido2.user_presence_cb(rp_id, action, user_name);
185 }
186 // No callback set - auto-approve (unsafe, but allows testing)
187 LOG_W(TAG, "No user presence callback - auto-approving");
188 return FIDO2_UP_APPROVED;
189}
190
195void fido2_set_pin_verified(bool verified) {
196 g_fido2.pin_verified = verified;
197 if (verified) {
198 LOG_I(TAG, "PIN verified via ClientPIN - device PIN will be skipped");
199 }
200}
201
207 return g_fido2.pin_verified;
208}
209
215 return fido2_storage_count();
216}
217
225 if (!info) return false;
226
227 // Map index to slot
228 uint8_t found = 0;
229 for (uint8_t slot = 0; slot < FIDO2_MAX_CREDENTIALS; slot++) {
230 if (fido2_storage_slot_used(slot)) {
231 if (found == index) {
232 return fido2_storage_get_credential(slot, info);
233 }
234 found++;
235 }
236 }
237
238 return false;
239}
240
249 uint8_t *out_indices, uint8_t max_indices) {
250 return fido2_storage_find_by_rp(rp_id_hash, out_indices, max_indices);
251}
252
258bool fido2_delete_credential(uint8_t slot) {
260}
261
267 LOG_W(TAG, "Factory reset requested");
268
269 // Delete all credentials
270 for (uint8_t slot = 0; slot < FIDO2_MAX_CREDENTIALS; slot++) {
271 if (fido2_storage_slot_used(slot)) {
273 }
274 }
275
276 // Drop CTAP2.1 large-blob storage and config flags, and revert the PIN floor.
279
280 LOG_I(TAG, "Factory reset complete");
281 return true;
282}
283
290}
291
298
304 return g_fido2.initialized;
305}
306
312 uint16_t ecc_start = fido2_storage_ecc_start();
313 uint16_t ecc_end = fido2_storage_ecc_end();
314 if (ecc_end < ecc_start) return 0;
315 uint16_t total = static_cast<uint16_t>(ecc_end - ecc_start + 1);
316 uint8_t used = fido2_storage_count();
317 return (total > used) ? static_cast<uint8_t>(total - used) : 0;
318}
static const char * TAG
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
Definition cdc_log.h:146
#define LOG_D(tag, fmt,...)
Definition cdc_log.h:148
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
#define LOG_E(tag, fmt,...)
Definition cdc_log.h:145
uint8_t cred_count
Definition ctap2.cpp:137
bool initialized
Definition ctap2.cpp:62
bool ctap2_init(void)
Initializes CTAP2 runtime state.
Definition ctap2.cpp:3865
bool ctaphid_init(void)
Initializes CTAPHID transport state and synchronization primitives.
Definition ctaphid.cpp:434
void ctaphid_check_timeout(void)
Expires active channels whose message assembly timeout elapsed.
Definition ctaphid.cpp:730
bool ctaphid_has_response(void)
Indicates whether any channel has a response queued for host retrieval.
Definition ctaphid.cpp:607
bool ctaphid_get_response_packet(uint8_t *packet)
Retrieves the next response HID packet from a per-channel response queue.
Definition ctaphid.cpp:634
bool ctaphid_process_packet(const uint8_t *packet)
Processes one incoming 64-byte CTAPHID packet.
Definition ctaphid.cpp:474
TaskHandle_t task_handle
Definition fido2.cpp:34
uint8_t fido2_find_credentials_by_rp(const uint8_t *rp_id_hash, uint8_t *out_indices, uint8_t max_indices)
Finds credential slots matching RP ID hash.
Definition fido2.cpp:248
uint32_t fido2_get_auth_counter(void)
Returns global authentication counter.
Definition fido2.cpp:288
void fido2_set_pin_verified(bool verified)
Stores whether PIN verification was completed via ClientPIN.
Definition fido2.cpp:195
bool fido2_is_initialized(void)
Indicates whether FIDO2 subsystem is initialized.
Definition fido2.cpp:303
fido2_user_presence_cb_t user_presence_cb
Definition fido2.cpp:33
bool fido2_get_credential_info(uint8_t index, fido2_credential_info_t *info)
Retrieves credential metadata by visible index.
Definition fido2.cpp:224
bool fido2_init(void)
Initializes storage, CTAP layers, and starts the processing task.
Definition fido2.cpp:127
void fido2_set_user_presence_callback(fido2_user_presence_cb_t cb)
Sets callback used to request user presence for CTAP operations.
Definition fido2.cpp:167
static void fido2_task(void *arg)
Background task that receives CTAPHID packets and sends responses.
Definition fido2.cpp:42
bool fido2_delete_credential(uint8_t slot)
Deletes credential in given slot.
Definition fido2.cpp:258
uint8_t fido2_get_available_slots(void)
Returns number of free credential slots.
Definition fido2.cpp:311
void fido2_increment_auth_counter(void)
Increments global authentication counter.
Definition fido2.cpp:295
fido2_user_presence_result_t fido2_request_user_presence(const char *rp_id, fido2_action_t action, const char *user_name)
Requests user presence from host/application callback.
Definition fido2.cpp:178
static struct @140260313112121147203143015136154100311031123103 g_fido2
Global FIDO2 runtime state.
bool fido2_factory_reset(void)
Removes all credentials and resets FIDO2 data.
Definition fido2.cpp:266
bool fido2_is_pin_verified(void)
Returns current PIN-verified state.
Definition fido2.cpp:206
bool pin_verified
Definition fido2.cpp:35
uint8_t fido2_get_credential_count(void)
Returns number of stored credentials.
Definition fido2.cpp:214
#define FIDO2_MAX_CREDENTIALS
Definition fido2.h:16
fido2_user_presence_result_t
Definition fido2.h:30
@ FIDO2_UP_APPROVED
Definition fido2.h:32
fido2_user_presence_result_t(* fido2_user_presence_cb_t)(const char *rp_id, fido2_action_t action, const char *user_name)
Definition fido2.h:67
fido2_action_t
Definition fido2.h:37
char rp_id[FIDO2_RP_ID_MAX_LEN]
uint8_t rp_id_hash[32]
char user_name[FIDO2_USER_NAME_MAX_LEN]
uint8_t fido2_storage_ecc_end(void)
Returns configured ECC end slot.
uint8_t fido2_storage_count(void)
Credential lookup operations using in-memory cache only.
uint32_t fido2_storage_counter_get(void)
Returns current global authentication counter.
uint8_t fido2_storage_ecc_start(void)
Returns configured ECC start slot.
bool fido2_storage_get_credential(uint8_t slot, fido2_credential_info_t *info)
Credential create/read/delete operations.
bool fido2_storage_delete_credential(uint8_t slot)
Deletes credential and associated slot data.
void fido2_storage_config_reset(void)
bool fido2_storage_counter_increment(void)
Increments and persists global authentication counter.
uint8_t fido2_storage_find_by_rp(const uint8_t *rp_id_hash, uint8_t *out_slots, uint8_t max_slots)
Finds credentials matching RP hash.
bool fido2_storage_slot_used(uint8_t slot)
Checks whether logical slot is occupied.
uint8_t fido2_storage_init(void)
Initialization and cache rebuild routines.
bool fido2_usb_available()
Indicates whether at least one USB HID packet is queued for FIDO2.
bool fido2_usb_ready()
Reports whether USB HID endpoint is ready for transmission.
uint16_t fido2_usb_read(uint8_t *buffer)
Reads one queued CTAPHID packet from USB RX queue.
bool fido2_usb_write(const uint8_t *buffer)
Sends one CTAPHID packet over USB HID.
void pin_storage_set_min_pin_floor(uint8_t min_len)
bool u2f_init_attestation(void)
Initializes attestation key material and builds self-signed attestation certificate.
Definition u2f.cpp:174