Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
u2f_transport.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2025 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17/* Includes ------------------------------------------------------------------*/
18#include <string.h>
19
20#include "os.h"
21#include "os_math.h"
22#include "os_utils.h"
23#include "os_io.h"
24
25#include "u2f_types.h"
26#include "u2f_transport.h"
27
28/* Private enumerations ------------------------------------------------------*/
29
30/* Private types, structures, unions -----------------------------------------*/
31
32/* Private defines------------------------------------------------------------*/
33#ifdef HAVE_PRINTF
34// #define LOG_IO PRINTF
35#define LOG_IO(...)
36#else // !HAVE_PRINTF
37#define LOG_IO(...)
38#endif // !HAVE_PRINTF
39
40/* Private macros-------------------------------------------------------------*/
41
42/* Private functions prototypes ----------------------------------------------*/
43static u2f_error_t process_packet(u2f_transport_t *handle, uint8_t *buffer, uint16_t length);
44
45/* Exported variables --------------------------------------------------------*/
46
47/* Private variables ---------------------------------------------------------*/
48
49/* Private functions ---------------------------------------------------------*/
50static u2f_error_t process_packet(u2f_transport_t *handle, uint8_t *buffer, uint16_t length)
51{
53
54 // Check CID for USB HID transport
55 if (handle->type == U2F_TRANSPORT_TYPE_USB_HID) {
56 if (length < 4) {
57 // CID not complete, answer with broadcast CID?
58 error = CTAP1_ERR_OTHER;
59 handle->cid = U2F_BROADCAST_CID;
60 goto end;
61 }
62 uint32_t message_cid = U4BE(buffer, 0);
63 handle->tx_cid = message_cid;
64 if (message_cid == U2F_FORBIDDEN_CID) {
65 // Forbidden CID
67 goto end;
68 }
69 else if ((message_cid == U2F_BROADCAST_CID) && (length >= 5)
70 && (buffer[4] != (U2F_COMMAND_HID_INIT | 0x80))) {
71 // Broadcast CID but not an init message
73 handle->cid = message_cid;
74 goto end;
75 }
76 else if ((handle->cid != U2F_FORBIDDEN_CID) && (handle->cid != message_cid)) {
77 // CID is already set
79 goto end;
80 }
81 else if ((handle->state > U2F_STATE_CMD_FRAMING) && (length >= 5)
82 && (buffer[4] != (U2F_COMMAND_HID_CANCEL | 0x80))
84 // Good CID but a request is already in process.
85 // If previous command is CTAPHID_CANCEL (supposedly without response) a new one is
86 // still authorized.
87 // TODO: to check the use case when on-going CTAPHID_CANCEL needs to interrupt UI and to
88 // respond with ERROR_KEEPALIVE_CANCEL while a new U2F_TRANSPORT_TYPE_USB_HID is coming.
90 goto end;
91 }
92 else if (handle->cid == U2F_FORBIDDEN_CID) {
93 // Set new CID
94 handle->cid = message_cid;
95 }
96 buffer += 4;
97 length -= 4;
98 }
99
100 // Check header length
101 if (length < 1) {
102 error = CTAP1_ERR_OTHER;
103 goto end;
104 }
105
106 if (buffer[0] & 0x80) {
107 // Initialization packet
108 if (length < 3) {
109 error = CTAP1_ERR_OTHER;
110 goto end;
111 }
112
113 // Check if packet will fit in the rx buffer
114 handle->rx_message_length = (uint16_t) U2BE(buffer, 1) + 3;
115 if (handle->rx_message_length > handle->rx_message_buffer_size) {
117 goto end;
118 }
119
120 if ((handle->rx_message_length <= 3) && (buffer[0] == (U2F_COMMAND_HID_CBOR | 0x80))) {
123 goto end;
124 }
125
127 handle->rx_message_offset = 0;
128 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[0] & 0x7F; // CMD
129 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[1]; // BCNTH
130 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[2]; // BCNTL
132 buffer += 3;
133 length -= 3;
134 }
135 else {
136 // Continuation packet
137 if (handle->state != U2F_STATE_CMD_FRAMING) {
138 error = CTAP1_ERR_OTHER;
139 goto end;
140 }
141 else if (buffer[0] != handle->rx_message_expected_sequence_number) {
142 error = CTAP1_ERR_INVALID_SEQ;
143 goto end;
144 }
146 buffer += 1;
147 length -= 1;
148 }
149
150 // prevent integer underflows in the rest of the operations
151 if (handle->rx_message_length < handle->rx_message_offset) {
152 error = CTAP1_ERR_OTHER;
153 goto end;
154 }
155 if (length > handle->rx_message_length - handle->rx_message_offset) {
156 length = handle->rx_message_length - handle->rx_message_offset;
157 }
158 memcpy(&handle->rx_message_buffer[handle->rx_message_offset], buffer, length);
159 handle->rx_message_offset += length;
160
161 if (handle->rx_message_offset == handle->rx_message_length) {
163 }
164
165end:
166 return error;
167}
168
169/* Exported functions --------------------------------------------------------*/
170void U2F_TRANSPORT_init(u2f_transport_t *handle, uint8_t type)
171{
172 if (!handle) {
173 return;
174 }
175
176 handle->state = U2F_STATE_IDLE;
177 handle->cid = U2F_FORBIDDEN_CID;
178 handle->type = type;
179}
180
181void U2F_TRANSPORT_rx(u2f_transport_t *handle, uint8_t *buffer, uint16_t length)
182{
183 if (!handle || !buffer || length < 3) {
184 return;
185 }
186
187 handle->error = process_packet(handle, buffer, length);
188}
189
191 uint8_t cmd,
192 const uint8_t *buffer,
193 uint16_t length,
194 uint8_t *tx_packet_buffer,
195 uint16_t tx_packet_buffer_size)
196{
197 if (!handle || (!buffer && !handle->tx_message_buffer)) {
198 return;
199 }
200
201 if (buffer) {
202 LOG_IO("Tx : INITIALIZATION PACKET\n");
203 handle->tx_message_buffer = buffer;
204 handle->tx_message_length = length;
205 handle->tx_message_sequence_number = 0;
206 handle->tx_message_offset = 0;
207 handle->tx_packet_length = 0;
208 memset(tx_packet_buffer, 0, tx_packet_buffer_size);
209 }
210 else {
211 LOG_IO("Tx : CONTINUATION PACKET\n");
212 }
213
214 uint16_t tx_packet_offset = 0;
215 memset(tx_packet_buffer, 0, tx_packet_buffer_size);
216
217 // Add CID if necessary
218 if (handle->type == U2F_TRANSPORT_TYPE_USB_HID) {
219 U4BE_ENCODE(tx_packet_buffer, 0, handle->tx_cid);
220 tx_packet_offset += 4;
221 }
222
223 // Fill header
224 if (buffer) {
225 tx_packet_buffer[tx_packet_offset++] = cmd | 0x80; // CMD
226 U2BE_ENCODE(tx_packet_buffer, tx_packet_offset, length); // BCNT
227 tx_packet_offset += 2;
228 }
229 else {
230 tx_packet_buffer[tx_packet_offset++] = handle->tx_message_sequence_number++; // SEQ
231 }
232
233 if ((handle->tx_message_length + tx_packet_offset)
234 > (tx_packet_buffer_size + handle->tx_message_offset)) {
235 // Remaining message length doesn't fit the max packet size
236 memcpy(&tx_packet_buffer[tx_packet_offset],
237 &handle->tx_message_buffer[handle->tx_message_offset],
238 tx_packet_buffer_size - tx_packet_offset);
239 handle->tx_message_offset += tx_packet_buffer_size - tx_packet_offset;
240 tx_packet_offset = tx_packet_buffer_size;
241 }
242 else {
243 // Remaining message fits the max packet size
244 memcpy(&tx_packet_buffer[tx_packet_offset],
245 &handle->tx_message_buffer[handle->tx_message_offset],
246 handle->tx_message_length - handle->tx_message_offset);
247 tx_packet_offset += (handle->tx_message_length - handle->tx_message_offset);
248 handle->tx_message_offset = handle->tx_message_length;
249 handle->tx_message_buffer = NULL;
250 handle->cid = U2F_FORBIDDEN_CID;
251 }
252
253 handle->tx_packet_length = tx_packet_offset;
254 LOG_IO(" %d\n", handle->tx_packet_length);
255}
uint16_t rx_message_buffer_size
uint8_t * rx_message_buffer
uint16_t rx_message_length
uint16_t rx_message_expected_sequence_number
uint16_t tx_message_sequence_number
uint16_t tx_message_offset
u2f_transport_type_t type
uint16_t tx_message_length
uint16_t rx_message_offset
const uint8_t * tx_message_buffer
u2f_error_t error
uint8_t tx_packet_length
#define LOG_IO(...)
void U2F_TRANSPORT_tx(u2f_transport_t *handle, uint8_t cmd, const uint8_t *buffer, uint16_t length, uint8_t *tx_packet_buffer, uint16_t tx_packet_buffer_size)
void U2F_TRANSPORT_init(u2f_transport_t *handle, uint8_t type)
void U2F_TRANSPORT_rx(u2f_transport_t *handle, uint8_t *buffer, uint16_t length)
@ U2F_TRANSPORT_TYPE_USB_HID
#define U2F_FORBIDDEN_CID
#define U2F_BROADCAST_CID
@ U2F_STATE_IDLE
Definition u2f_types.h:26
@ U2F_STATE_CMD_PROCESSING_CANCEL
Definition u2f_types.h:30
@ U2F_STATE_CMD_FRAMING
Definition u2f_types.h:27
@ U2F_STATE_CMD_COMPLETE
Definition u2f_types.h:28
u2f_error_t
Definition u2f_types.h:64
@ CTAP1_ERR_INVALID_CHANNEL
Definition u2f_types.h:74
@ CTAP1_ERR_SUCCESS
Definition u2f_types.h:66
@ CTAP1_ERR_OTHER
Definition u2f_types.h:75
@ CTAP1_ERR_CHANNEL_BUSY
Definition u2f_types.h:72
@ CTAP1_ERR_INVALID_LENGTH
Definition u2f_types.h:69
@ CTAP2_ERR_INVALID_CBOR
Definition u2f_types.h:80
@ CTAP1_ERR_INVALID_SEQ
Definition u2f_types.h:70
@ U2F_COMMAND_HID_CBOR
Definition u2f_types.h:43
@ U2F_COMMAND_HID_INIT
Definition u2f_types.h:41
@ U2F_COMMAND_HID_CANCEL
Definition u2f_types.h:44