CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
Fido2Module.cpp
Go to the documentation of this file.
4#include "cdc_core/EventBus.h"
5#include "cdc_log.h"
6#include "mod_fido2/Fido2Ui.h"
7#include "mod_fido2/fido2.h"
9#include "mod_fido2/ctaphid.h"
10#include "usb_badge/usb_hid.h"
11
12#include <freertos/FreeRTOS.h>
13#include <freertos/queue.h>
14#include <string.h>
15
16static const char* TAG = "FIDO2";
17
18namespace cdc::mod_fido2 {
19
21static const uint8_t s_fido_report_desc[] = {
22 0x06, 0xD0, 0xF1, // Usage Page (FIDO Alliance)
23 0x09, 0x01, // Usage (U2F HID Authenticator Device)
24 0xA1, 0x01, // Collection (Application)
25 0x09, 0x20, // Usage (Input Report Data)
26 0x15, 0x00, // Logical Minimum (0)
27 0x26, 0xFF, 0x00, // Logical Maximum (255)
28 0x75, 0x08, // Report Size (8)
29 0x95, CTAPHID_PACKET_SIZE, // Report Count (64)
30 0x81, 0x02, // Input (Data, Variable, Absolute)
31 0x09, 0x21, // Usage (Output Report Data)
32 0x15, 0x00, // Logical Minimum (0)
33 0x26, 0xFF, 0x00, // Logical Maximum (255)
34 0x75, 0x08, // Report Size (8)
35 0x95, CTAPHID_PACKET_SIZE, // Report Count (64)
36 0x91, 0x02, // Output (Data, Variable, Absolute)
37 0xC0 // End Collection
38};
39
41static constexpr size_t FIDO_QUEUE_SIZE = 8;
42static QueueHandle_t s_rx_queue = nullptr;
43
44struct FidoPacket {
46};
47
49static uint8_t s_hid_instance = 0;
50
60static uint16_t onFidoGetReport(uint8_t report_id, uint8_t report_type,
61 uint8_t* buffer, uint16_t reqlen) {
62 (void)report_id;
63 (void)report_type;
64 (void)buffer;
65 (void)reqlen;
66 return 0; // FIDO doesn't use GET_REPORT
67}
68
76static void onFidoSetReport(uint8_t report_id, uint8_t report_type,
77 uint8_t const* buffer, uint16_t bufsize) {
78 (void)report_id;
79 (void)report_type;
80
81 if (!s_rx_queue || !buffer || bufsize != CTAPHID_PACKET_SIZE) {
82 return;
83 }
84
85 FidoPacket pkt;
86 memcpy(pkt.data, buffer, CTAPHID_PACKET_SIZE);
87
88 // TinyUSB callbacks run in task context, not ISR
89 if (xQueueSend(s_rx_queue, &pkt, 0) != pdTRUE) {
90 LOG_W(TAG, "RX queue full, dropping packet");
91 }
92}
93
99static void onFidoReportComplete(uint8_t const* report, uint16_t len) {
100 (void)report;
101 (void)len;
102}
103
108Fido2Module& Fido2Module::instance() {
109 static Fido2Module inst;
110 return inst;
111}
112
118 LOG_I(TAG, "Initializing FIDO2 module");
119
120 // Create RX queue
121 if (!s_rx_queue) {
122 s_rx_queue = xQueueCreate(FIDO_QUEUE_SIZE, sizeof(FidoPacket));
123 if (!s_rx_queue) {
124 LOG_E(TAG, "Failed to create RX queue");
125 return false;
126 }
127 }
128
131
132 if (slotRange_.hasEcc && slotRange_.hasRmem) {
133 uint16_t eccCount = static_cast<uint16_t>(slotRange_.eccEnd - slotRange_.eccStart + 1);
134 uint16_t rmemCount = static_cast<uint16_t>(slotRange_.rmemEnd - slotRange_.rmemStart + 1);
135 if (rmemCount < eccCount) {
137 getName(), "FIDO2 R-MEM range smaller than ECC range");
139 return false;
140 }
141 fido2_storage_set_slot_range(slotRange_.eccStart, slotRange_.eccEnd,
142 slotRange_.rmemStart, slotRange_.rmemEnd);
144 } else {
145 core::ModuleRegistry::instance().reportModuleError(getName(), "FIDO2 slot range missing");
147 return false;
148 }
149
151 return true;
152}
153
159 if (state_ != core::ServiceState::INITIALIZED &&
160 state_ != core::ServiceState::STOPPED) {
161 return false;
162 }
163
166 spec.name = "FIDO2";
168 spec.reportDescLen = sizeof(s_fido_report_desc);
169 spec.protocol = 0; // HID_ITF_PROTOCOL_NONE
170 spec.hasOut = true;
176
177 if (!core::UsbManager::instance().registerInterface(core::UsbHidInterface::Fido, getName(), spec)) {
178 LOG_W(TAG, "Failed to register FIDO HID interface");
179 return false;
180 }
181
182 // FIDO is the first HID interface registered, so instance = 0
183 s_hid_instance = 0;
184
185 if (!fido2_is_initialized()) {
186 if (!fido2_init()) {
190 return false;
191 }
192 }
194
195 static bool sleepHandlerRegistered = false;
196 if (!sleepHandlerRegistered) {
197 auto& bus = core::EventBus::instance();
198 bus.subscribe([](const core::Event&) {
199 if (fido2_ui_abort_prompt()) {
200 LOG_I(TAG, "Aborted active FIDO2 prompt before sleep");
201 }
203 sleepHandlerRegistered = true;
204 }
205
207 return true;
208}
209
218
224 slotRange_ = range;
225}
226
233 req.mapName = getName();
234 req.minEccSlots = 1;
235 req.minRmemSlots = 1;
236 return req;
237}
238
245uint8_t Fido2Module::getMenuItems(core::ModuleMenuItem* items, uint8_t maxItems) {
246 if (!items || maxItems == 0) return 0;
247
248 items[0] = {fido2_ui_get_label(), 50, []() -> ui::IView* {
249 return fido2_ui_get_list_view();
250 }, nullptr, getName(), core::MenuLocation::MAIN_MENU, nullptr};
251
252 return 1;
253}
254
260 if (!s_rx_queue) return false;
261 return uxQueueMessagesWaiting(s_rx_queue) > 0;
262}
263
271
277uint16_t fido2_usb_read(uint8_t* buffer) {
278 if (!s_rx_queue || !buffer) return 0;
279
280 FidoPacket pkt;
281 if (xQueueReceive(s_rx_queue, &pkt, 0) == pdTRUE) {
282 memcpy(buffer, pkt.data, CTAPHID_PACKET_SIZE);
283 return CTAPHID_PACKET_SIZE;
284 }
285 return 0;
286}
287
293bool fido2_usb_write(const uint8_t* buffer) {
294 if (!buffer) return false;
296}
297
298} // namespace cdc::mod_fido2
299
303extern "C" void mod_fido2_register() {
305 auto& module = cdc::mod_fido2::Fido2Module::instance();
306 module.init();
307 });
308}
static const char * TAG
void mod_fido2_register()
Registers FIDO2 module initializer.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
Definition cdc_log.h:146
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
#define LOG_E(tag, fmt,...)
Definition cdc_log.h:145
static EventBus & instance()
Returns singleton event-bus instance.
Definition EventBus.cpp:19
static constexpr uint32_t eventMask(EventType type)
Definition EventBus.h:127
void reportModuleError(const char *name, const char *message)
Records and publishes an operational module error by module name.
bool registerModule(IModule *module)
Registers a module instance in the runtime registry.
static ModuleRegistry & instance()
Returns the singleton module registry instance.
void registerInitializer(ModuleInitFunc initFunc)
Registers a deferred module initializer callback.
void clearModuleErrorByName(const char *name)
Clears stored module error by module name.
static UsbManager & instance()
Returns singleton USB manager instance.
void unregisterInterface(UsbHidInterface type, const char *moduleName)
Unregisters a previously registered HID interface.
uint8_t getMenuItems(core::ModuleMenuItem *items, uint8_t maxItems) override
Provides main-menu entry for FIDO2 credential list.
core::IModule::SlotRequest getSlotRequest() const override
Declares slot requirements for FIDO2 module.
static Fido2Module & instance()
Returns the singleton instance of the FIDO2 module.
const char * getName() const override
Definition Fido2Module.h:9
void setSlotRange(const core::IModule::SlotRange &range) override
Stores slot range assignment.
bool start() override
Starts FIDO2 module, USB HID interface, and core stack.
bool init() override
Initializes FIDO2 module resources and slot mapping.
void stop() override
Stops FIDO2 module and unregisters USB interface.
#define CTAPHID_PACKET_SIZE
Definition ctaphid.h:13
bool fido2_is_initialized(void)
Indicates whether FIDO2 subsystem is initialized.
Definition fido2.cpp:298
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
bool fido2_storage_counter_flush(void)
No-op flush retained for API stability; per-increment path commits.
void fido2_storage_set_slot_range(uint8_t ecc_start, uint8_t ecc_end, uint16_t rmem_start, uint16_t rmem_end)
Configures FIDO2 storage slot ranges.
cdc::ui::IView * fido2_ui_get_list_view()
Returns FIDO2 credential list view.
Definition Fido2Ui.cpp:440
bool fido2_usb_available()
Indicates whether at least one USB HID packet is queued for FIDO2.
static uint16_t onFidoGetReport(uint8_t report_id, uint8_t report_type, uint8_t *buffer, uint16_t reqlen)
USB HID callbacks for FIDO transport.
bool fido2_ui_abort_prompt()
Forcibly denies any in-flight user-presence prompt.
Definition Fido2Ui.cpp:677
static constexpr size_t FIDO_QUEUE_SIZE
Queue for incoming HID reports.
void fido2_ui_init()
Initializes FIDO2 UI resources and list views.
Definition Fido2Ui.cpp:422
static void onFidoSetReport(uint8_t report_id, uint8_t report_type, uint8_t const *buffer, uint16_t bufsize)
HID SET_REPORT callback queuing incoming CTAPHID packets.
static void onFidoReportComplete(uint8_t const *report, uint16_t len)
HID transfer-complete callback (currently unused).
bool fido2_usb_ready()
Reports whether USB HID endpoint is ready for transmission.
static uint8_t s_hid_instance
HID interface instance index assigned at registration time.
uint16_t fido2_usb_read(uint8_t *buffer)
Reads one queued CTAPHID packet from USB RX queue.
static const uint8_t s_fido_report_desc[]
FIDO U2F HID report descriptor (CTAPHID standard).
static QueueHandle_t s_rx_queue
fido2_user_presence_result_t fido2_ui_user_presence_callback(const char *rp_id, fido2_action_t action, const char *user_name)
User-presence callback used by FIDO2 core for approval prompts.
Definition Fido2Ui.cpp:463
const char * fido2_ui_get_label()
Returns localized module label for menus.
Definition Fido2Ui.cpp:452
bool fido2_usb_write(const uint8_t *buffer)
Sends one CTAPHID packet over USB HID.
Menu item registered by a module.
Definition IModule.h:29
void(* onReportComplete)(uint8_t const *report, uint16_t len)
Definition UsbManager.h:24
void(* onSetReport)(uint8_t report_id, uint8_t report_type, uint8_t const *buffer, uint16_t bufsize)
Definition UsbManager.h:22
uint16_t(* onGetReport)(uint8_t report_id, uint8_t report_type, uint8_t *buffer, uint16_t reqlen)
Definition UsbManager.h:20
const uint8_t * reportDesc
Definition UsbManager.h:30
UsbInterfaceClass cls
Definition UsbManager.h:28
UsbHidCallbacks callbacks
Definition UsbManager.h:36
uint8_t data[CTAPHID_PACKET_SIZE]
bool usb_hid_send_report(uint8_t instance, uint8_t report_id, const uint8_t *data, uint16_t len)
Sends one HID report on the selected interface instance.
Definition usb_hid.cpp:414
bool usb_hid_instance_ready(uint8_t instance)
Returns whether a specific HID instance endpoint is ready.
Definition usb_hid.cpp:402