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))) {
83 // Good CID but a request is already in process
85 goto end;
86 }
87 else if (handle->cid == U2F_FORBIDDEN_CID) {
88 // Set new CID
89 handle->cid = message_cid;
90 }
91 buffer += 4;
92 length -= 4;
93 }
94
95 // Check header length
96 if (length < 1) {
97 error = CTAP1_ERR_OTHER;
98 goto end;
99 }
100
101 if (buffer[0] & 0x80) {
102 // Initialization packet
103 if (length < 3) {
104 error = CTAP1_ERR_OTHER;
105 goto end;
106 }
107
108 // Check if packet will fit in the rx buffer
109 handle->rx_message_length = (uint16_t) U2BE(buffer, 1) + 3;
110 if (handle->rx_message_length > handle->rx_message_buffer_size) {
112 goto end;
113 }
114
115 if ((handle->rx_message_length <= 3) && (buffer[0] == (U2F_COMMAND_HID_CBOR | 0x80))) {
118 goto end;
119 }
120
122 handle->rx_message_offset = 0;
123 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[0] & 0x7F; // CMD
124 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[1]; // BCNTH
125 handle->rx_message_buffer[handle->rx_message_offset++] = buffer[2]; // BCNTL
127 buffer += 3;
128 length -= 3;
129 }
130 else {
131 // Continuation packet
132 if (handle->state != U2F_STATE_CMD_FRAMING) {
133 error = CTAP1_ERR_OTHER;
134 goto end;
135 }
136 else if (buffer[0] != handle->rx_message_expected_sequence_number) {
137 error = CTAP1_ERR_INVALID_SEQ;
138 goto end;
139 }
141 buffer += 1;
142 length -= 1;
143 }
144
145 // prevent integer underflows in the rest of the operations
146 if (handle->rx_message_length < handle->rx_message_offset) {
147 error = CTAP1_ERR_OTHER;
148 goto end;
149 }
150 if (length > handle->rx_message_length - handle->rx_message_offset) {
151 length = handle->rx_message_length - handle->rx_message_offset;
152 }
153 memcpy(&handle->rx_message_buffer[handle->rx_message_offset], buffer, length);
154 handle->rx_message_offset += length;
155
156 if (handle->rx_message_offset == handle->rx_message_length) {
158 }
159
160end:
161 return error;
162}
163
164/* Exported functions --------------------------------------------------------*/
165void U2F_TRANSPORT_init(u2f_transport_t *handle, uint8_t type)
166{
167 if (!handle) {
168 return;
169 }
170
171 handle->state = U2F_STATE_IDLE;
172 handle->cid = U2F_FORBIDDEN_CID;
173 handle->type = type;
174}
175
176void U2F_TRANSPORT_rx(u2f_transport_t *handle, uint8_t *buffer, uint16_t length)
177{
178 if (!handle || !buffer || length < 3) {
179 return;
180 }
181
182 handle->error = process_packet(handle, buffer, length);
183}
184
186 uint8_t cmd,
187 const uint8_t *buffer,
188 uint16_t length,
189 uint8_t *tx_packet_buffer,
190 uint16_t tx_packet_buffer_size)
191{
192 if (!handle || (!buffer && !handle->tx_message_buffer)) {
193 return;
194 }
195
196 if (buffer) {
197 LOG_IO("Tx : INITIALIZATION PACKET\n");
198 handle->tx_message_buffer = buffer;
199 handle->tx_message_length = length;
200 handle->tx_message_sequence_number = 0;
201 handle->tx_message_offset = 0;
202 handle->tx_packet_length = 0;
203 memset(tx_packet_buffer, 0, tx_packet_buffer_size);
204 }
205 else {
206 LOG_IO("Tx : CONTINUATION PACKET\n");
207 }
208
209 uint16_t tx_packet_offset = 0;
210 memset(tx_packet_buffer, 0, tx_packet_buffer_size);
211
212 // Add CID if necessary
213 if (handle->type == U2F_TRANSPORT_TYPE_USB_HID) {
214 U4BE_ENCODE(tx_packet_buffer, 0, handle->tx_cid);
215 tx_packet_offset += 4;
216 }
217
218 // Fill header
219 if (buffer) {
220 tx_packet_buffer[tx_packet_offset++] = cmd | 0x80; // CMD
221 U2BE_ENCODE(tx_packet_buffer, tx_packet_offset, length); // BCNT
222 tx_packet_offset += 2;
223 }
224 else {
225 tx_packet_buffer[tx_packet_offset++] = handle->tx_message_sequence_number++; // SEQ
226 }
227
228 if ((handle->tx_message_length + tx_packet_offset)
229 > (tx_packet_buffer_size + handle->tx_message_offset)) {
230 // Remaining message length doesn't fit the max packet size
231 memcpy(&tx_packet_buffer[tx_packet_offset],
232 &handle->tx_message_buffer[handle->tx_message_offset],
233 tx_packet_buffer_size - tx_packet_offset);
234 handle->tx_message_offset += tx_packet_buffer_size - tx_packet_offset;
235 tx_packet_offset = tx_packet_buffer_size;
236 }
237 else {
238 // Remaining message fits the max packet size
239 memcpy(&tx_packet_buffer[tx_packet_offset],
240 &handle->tx_message_buffer[handle->tx_message_offset],
241 handle->tx_message_length - handle->tx_message_offset);
242 tx_packet_offset += (handle->tx_message_length - handle->tx_message_offset);
243 handle->tx_message_offset = handle->tx_message_length;
244 handle->tx_message_buffer = NULL;
245 handle->cid = U2F_FORBIDDEN_CID;
246 }
247
248 handle->tx_packet_length = tx_packet_offset;
249 LOG_IO(" %d\n", handle->tx_packet_length);
250}
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_FRAMING
Definition u2f_types.h:27
@ U2F_STATE_CMD_COMPLETE
Definition u2f_types.h:28
u2f_error_t
Definition u2f_types.h:63
@ CTAP1_ERR_INVALID_CHANNEL
Definition u2f_types.h:73
@ CTAP1_ERR_SUCCESS
Definition u2f_types.h:65
@ CTAP1_ERR_OTHER
Definition u2f_types.h:74
@ CTAP1_ERR_CHANNEL_BUSY
Definition u2f_types.h:71
@ CTAP1_ERR_INVALID_LENGTH
Definition u2f_types.h:68
@ CTAP2_ERR_INVALID_CBOR
Definition u2f_types.h:79
@ CTAP1_ERR_INVALID_SEQ
Definition u2f_types.h:69
@ U2F_COMMAND_HID_CBOR
Definition u2f_types.h:42
@ U2F_COMMAND_HID_INIT
Definition u2f_types.h:40
@ U2F_COMMAND_HID_CANCEL
Definition u2f_types.h:43