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"
11#include "cdc_log.h"
12#include <freertos/FreeRTOS.h>
13#include <freertos/task.h>
14#include <string.h>
15
16// USB transport hooks implemented by Fido2Module.cpp.
17namespace cdc::mod_fido2 {
19 bool fido2_usb_ready();
20 uint16_t fido2_usb_read(uint8_t* buffer);
21 bool fido2_usb_write(const uint8_t* buffer);
22}
23
24using namespace cdc::mod_fido2;
25
26static const char* TAG = "FIDO2";
27
29
30static struct {
33 TaskHandle_t task_handle;
34 bool pin_verified; // PIN was verified via ClientPIN protocol
35} g_fido2 = {};
36
41static void fido2_task(void* arg) {
42 (void)arg;
43 uint8_t packet[64];
44
45 LOG_I(TAG, "Processing task started");
46
47 while (1) {
48 // Process incoming packets and drain responses immediately to avoid overwriting
49 while (fido2_usb_available()) {
50 // If we still owe a response and USB isn't ready, pause input to avoid overwrite
52 break;
53 }
54
55 if (fido2_usb_read(packet) == 64) {
57 }
58
59 // Send pending responses before reading more packets (with brief wait)
60 int inner_retry = 0;
61 while (ctaphid_has_response()) {
62 if (fido2_usb_ready()) {
63 uint8_t response[64];
64 if (ctaphid_get_response_packet(response)) {
65 if (!fido2_usb_write(response)) {
66 LOG_W(TAG, "USB FIDO write failed");
67 break;
68 }
69 LOG_D(TAG, "Sent response packet");
70 inner_retry = 0;
71 vTaskDelay(pdMS_TO_TICKS(1));
72 }
73 } else {
74 inner_retry++;
75 if (inner_retry > 10) { // Brief wait, then continue in outer loop
76 LOG_D(TAG, "USB not ready, deferring to outer loop");
77 break;
78 }
79 vTaskDelay(pdMS_TO_TICKS(5));
80 }
81 }
82
83 // If response still pending, stop reading more packets this cycle
85 break;
86 }
87 }
88
89 // Send any remaining response packets (with retry on USB not ready)
90 int retry_count = 0;
91 while (ctaphid_has_response()) {
92 if (fido2_usb_ready()) {
93 uint8_t response[64];
94 if (ctaphid_get_response_packet(response)) {
95 if (!fido2_usb_write(response)) {
96 LOG_W(TAG, "USB FIDO write failed (outer)");
97 break;
98 }
99 LOG_D(TAG, "Sent response packet (outer)");
100 retry_count = 0; // Reset retry counter on success
101 vTaskDelay(pdMS_TO_TICKS(1));
102 }
103 } else {
104 // Wait for USB to be ready instead of giving up
105 retry_count++;
106 if (retry_count > 100) { // ~1 second timeout
107 LOG_W(TAG, "USB not ready timeout, aborting response");
108 break;
109 }
110 vTaskDelay(pdMS_TO_TICKS(10));
111 }
112 }
113
114 // Check timeouts
116
117 // Poll rate
118 vTaskDelay(pdMS_TO_TICKS(10));
119 }
120}
121
126bool fido2_init(void) {
127 LOG_I(TAG, "Initializing...");
128
129 memset(&g_fido2, 0, sizeof(g_fido2));
130
131 // Initialize storage layer
132 uint8_t cred_count = fido2_storage_init();
133 LOG_I(TAG, "Storage initialized, %d credentials", cred_count);
134
135 // Initialize CTAP2 protocol handler
136 if (!ctap2_init()) {
137 LOG_E(TAG, "CTAP2 init failed");
138 return false;
139 }
140
141 // Initialize CTAPHID transport
142 if (!ctaphid_init()) {
143 LOG_E(TAG, "CTAPHID init failed");
144 return false;
145 }
146
147 // Initialize U2F attestation certificate
148 if (!u2f_init_attestation()) {
149 LOG_W(TAG, "U2F attestation init failed (non-fatal)");
150 // Continue anyway - FIDO2 will still work, U2F might not
151 }
152
153 // Start FIDO2 processing task
154 xTaskCreate(fido2_task, "fido2", 6144, nullptr,
155 configMAX_PRIORITIES - 2, &g_fido2.task_handle);
156
157 g_fido2.initialized = true;
158 LOG_I(TAG, "Initialized");
159 return true;
160}
161
167 g_fido2.user_presence_cb = cb;
168}
169
178 const char *rp_id,
179 fido2_action_t action,
180 const char *user_name
181) {
182 if (g_fido2.user_presence_cb) {
183 return g_fido2.user_presence_cb(rp_id, action, user_name);
184 }
185 // No callback set - auto-approve (unsafe, but allows testing)
186 LOG_W(TAG, "No user presence callback - auto-approving");
187 return FIDO2_UP_APPROVED;
188}
189
194void fido2_set_pin_verified(bool verified) {
195 g_fido2.pin_verified = verified;
196 if (verified) {
197 LOG_I(TAG, "PIN verified via ClientPIN - device PIN will be skipped");
198 }
199}
200
206 return g_fido2.pin_verified;
207}
208
214 return fido2_storage_count();
215}
216
224 if (!info) return false;
225
226 // Map index to slot
227 uint8_t found = 0;
228 for (uint8_t slot = 0; slot < FIDO2_MAX_CREDENTIALS; slot++) {
229 if (fido2_storage_slot_used(slot)) {
230 if (found == index) {
231 return fido2_storage_get_credential(slot, info);
232 }
233 found++;
234 }
235 }
236
237 return false;
238}
239
248 uint8_t *out_indices, uint8_t max_indices) {
249 return fido2_storage_find_by_rp(rp_id_hash, out_indices, max_indices);
250}
251
257bool fido2_delete_credential(uint8_t slot) {
259}
260
266 LOG_W(TAG, "Factory reset requested");
267
268 // Delete all credentials
269 for (uint8_t slot = 0; slot < FIDO2_MAX_CREDENTIALS; slot++) {
270 if (fido2_storage_slot_used(slot)) {
272 }
273 }
274
275 LOG_I(TAG, "Factory reset complete");
276 return true;
277}
278
285}
286
293
299 return g_fido2.initialized;
300}
301
307 uint16_t ecc_start = fido2_storage_ecc_start();
308 uint16_t ecc_end = fido2_storage_ecc_end();
309 if (ecc_end < ecc_start) return 0;
310 uint16_t total = static_cast<uint16_t>(ecc_end - ecc_start + 1);
311 uint8_t used = fido2_storage_count();
312 return (total > used) ? static_cast<uint8_t>(total - used) : 0;
313}
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:136
bool initialized
Definition ctap2.cpp:61
bool ctap2_init(void)
Initializes CTAP2 runtime state.
Definition ctap2.cpp:3513
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:33
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:247
uint32_t fido2_get_auth_counter(void)
Returns global authentication counter.
Definition fido2.cpp:283
void fido2_set_pin_verified(bool verified)
Stores whether PIN verification was completed via ClientPIN.
Definition fido2.cpp:194
bool fido2_is_initialized(void)
Indicates whether FIDO2 subsystem is initialized.
Definition fido2.cpp:298
fido2_user_presence_cb_t user_presence_cb
Definition fido2.cpp:32
bool fido2_get_credential_info(uint8_t index, fido2_credential_info_t *info)
Retrieves credential metadata by visible index.
Definition fido2.cpp:223
bool fido2_init(void)
Initializes storage, CTAP layers, and starts the processing task.
Definition fido2.cpp:126
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:166
static void fido2_task(void *arg)
Background task that receives CTAPHID packets and sends responses.
Definition fido2.cpp:41
bool fido2_delete_credential(uint8_t slot)
Deletes credential in given slot.
Definition fido2.cpp:257
uint8_t fido2_get_available_slots(void)
Returns number of free credential slots.
Definition fido2.cpp:306
void fido2_increment_auth_counter(void)
Increments global authentication counter.
Definition fido2.cpp:290
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:177
static struct @140260313112121147203143015136154100311031123103 g_fido2
Global FIDO2 runtime state.
bool fido2_factory_reset(void)
Removes all credentials and resets FIDO2 data.
Definition fido2.cpp:265
bool fido2_is_pin_verified(void)
Returns current PIN-verified state.
Definition fido2.cpp:205
bool pin_verified
Definition fido2.cpp:34
uint8_t fido2_get_credential_count(void)
Returns number of stored credentials.
Definition fido2.cpp:213
#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.
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.
bool u2f_init_attestation(void)
Initializes attestation key material and builds self-signed attestation certificate.
Definition u2f.cpp:122