Embedded SDK
Embedded SDK
u2f_impl.c
Go to the documentation of this file.
1 
2 /*******************************************************************************
3  * Ledger Nano S - Secure firmware
4  * (c) 2022 Ledger
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  ********************************************************************************/
18 
19 #include <stdint.h>
20 #include <string.h>
21 
22 #ifdef HAVE_IO_U2F
23 
24 #include "os.h"
25 #include "os_io_seproxyhal.h"
26 #include "u2f_service.h"
27 #include "u2f_transport.h"
28 #include "u2f_processing.h"
29 
30 #define INIT_U2F_VERSION 0x02
31 #define INIT_DEVICE_VERSION_MAJOR 0
32 #define INIT_DEVICE_VERSION_MINOR 1
33 #define INIT_BUILD_VERSION 0
34 
35 #ifdef HAVE_FIDO2
36 #define INIT_CAPABILITIES 0x04
37 #else
38 #define INIT_CAPABILITIES 0x00
39 #endif
40 
41 #define OFFSET_CLA 0
42 #define OFFSET_INS 1
43 #define OFFSET_P1 2
44 #define OFFSET_P2 3
45 #define OFFSET_DATA 7
46 
47 #define APDU_MIN_HEADER 4
48 #define LC_FIRST_BYTE_OFFSET 4
49 #define LONG_ENC_LC_SIZE 3
50 #define LONG_ENC_LE_SIZE 2 // considering only scenarios where Lc is present
51 
52 #define FIDO_CLA 0x00
53 #define FIDO_INS_ENROLL 0x01
54 #define FIDO_INS_SIGN 0x02
55 #define U2F_HANDLE_SIGN_HEADER_SIZE (32 + 32 + 1)
56 #define FIDO_INS_GET_VERSION 0x03
57 
58 #define FIDO_INS_PROP_GET_COUNTER 0xC0 // U2F_VENDOR_FIRST
59 #define FIDO_INS_PROP_GET_INFO 0xC1 // grab the max message buffer size on 1 byte
60 
61 #define P1_SIGN_CHECK_ONLY 0x07
62 #define P1_SIGN_SIGN 0x03
63 
64 #define SIGN_USER_PRESENCE_MASK 0x01
65 
66 #ifndef U2F_PROXY_MAGIC
67 
68 static const uint8_t SW_WRONG_LENGTH[] = {0x67, 0x00};
69 
70 #else // U2F_PROXY_MAGIC
71 
72 static const uint8_t SW_BUSY[] = {0x90, 0x01};
73 static const uint8_t SW_PROOF_OF_PRESENCE_REQUIRED[] = {0x69, 0x85};
74 static const uint8_t SW_BAD_KEY_HANDLE[] = {0x6A, 0x80};
75 
76 static const uint8_t SW_UNKNOWN_INSTRUCTION[] = {0x6d, 0x00};
77 static const uint8_t SW_UNKNOWN_CLASS[] = {0x6e, 0x00};
78 static const uint8_t SW_WRONG_LENGTH[] = {0x67, 0x00};
79 static const uint8_t SW_INTERNAL[] = {0x6F, 0x00};
80 
81 static const uint8_t U2F_VERSION[] = {'U', '2', 'F', '_', 'V', '2', 0x90, 0x00};
82 
83 // take into account max header (u2f usb)
84 static const uint8_t INFO[] = {1 /*info format 1*/,
85  (char) (IO_APDU_BUFFER_SIZE - U2F_HANDLE_SIGN_HEADER_SIZE - 3 - 4),
86  0x90,
87  0x00};
88 
89 // proxy mode enroll issue an error
90 void u2f_apdu_enroll(u2f_service_t *service,
91  uint8_t p1,
92  uint8_t p2,
93  uint8_t *buffer,
94  uint16_t length)
95 {
96  UNUSED(p1);
97  UNUSED(p2);
98  UNUSED(buffer);
99  UNUSED(length);
100 
101  u2f_message_reply(service, U2F_CMD_MSG, (uint8_t *) SW_INTERNAL, sizeof(SW_INTERNAL));
102 }
103 
104 void u2f_apdu_sign(u2f_service_t *service, uint8_t p1, uint8_t p2, uint8_t *buffer, uint16_t length)
105 {
106  UNUSED(p2);
107  uint8_t keyHandleLength;
108  uint8_t i;
109 
110  // can't process the apdu if another one is already scheduled in
111  if (G_io_app.apdu_state != APDU_IDLE) {
112  u2f_message_reply(service, U2F_CMD_MSG, (uint8_t *) SW_BUSY, sizeof(SW_BUSY));
113  return;
114  }
115 
116  if (length < U2F_HANDLE_SIGN_HEADER_SIZE + 5 /*at least an apdu header*/) {
118  service, U2F_CMD_MSG, (uint8_t *) SW_WRONG_LENGTH, sizeof(SW_WRONG_LENGTH));
119  return;
120  }
121 
122  // Confirm immediately if it's just a validation call
123  if (p1 == P1_SIGN_CHECK_ONLY) {
124  u2f_message_reply(service,
125  U2F_CMD_MSG,
126  (uint8_t *) SW_PROOF_OF_PRESENCE_REQUIRED,
127  sizeof(SW_PROOF_OF_PRESENCE_REQUIRED));
128  return;
129  }
130 
131  // Unwrap magic
132  keyHandleLength = buffer[U2F_HANDLE_SIGN_HEADER_SIZE - 1];
133  if (U2F_HANDLE_SIGN_HEADER_SIZE + keyHandleLength != length) {
135  service, U2F_CMD_MSG, (uint8_t *) SW_WRONG_LENGTH, sizeof(SW_WRONG_LENGTH));
136  return;
137  }
138 
139  // reply to the "get magic" question of the host
140  if (keyHandleLength == 5) {
141  // GET U2F PROXY PARAMETERS
142  // this apdu is not subject to proxy magic masking
143  // APDU is F1 D0 00 00 00 to get the magic proxy
144  // RAPDU: <>
145  if (memcmp(buffer + U2F_HANDLE_SIGN_HEADER_SIZE, "\xF1\xD0\x00\x00\x00", 5) == 0) {
146  // U2F_PROXY_MAGIC is given as a 0 terminated string
147  G_io_apdu_buffer[0] = sizeof(U2F_PROXY_MAGIC) - 1;
148  memcpy(G_io_apdu_buffer + 1, U2F_PROXY_MAGIC, sizeof(U2F_PROXY_MAGIC) - 1);
149  memcpy(G_io_apdu_buffer + 1 + sizeof(U2F_PROXY_MAGIC) - 1, "\x90\x00\x90\x00", 4);
150  u2f_message_reply(service,
151  U2F_CMD_MSG,
152  (uint8_t *) G_io_apdu_buffer,
153  G_io_apdu_buffer[0] + 1 + 2 + 2);
154  // processing finished. don't go further in the u2f msg processing
155  return;
156  }
157  }
158 
159  for (i = 0; i < keyHandleLength; i++) {
160  buffer[U2F_HANDLE_SIGN_HEADER_SIZE + i]
161  ^= U2F_PROXY_MAGIC[i % (sizeof(U2F_PROXY_MAGIC) - 1)];
162  }
163  // Check that it looks like an APDU
164  if (length != U2F_HANDLE_SIGN_HEADER_SIZE + 5 + buffer[U2F_HANDLE_SIGN_HEADER_SIZE + 4]) {
166  service, U2F_CMD_MSG, (uint8_t *) SW_BAD_KEY_HANDLE, sizeof(SW_BAD_KEY_HANDLE));
167  return;
168  }
169 
170  // make the apdu available to higher layers
171  memmove(G_io_apdu_buffer, buffer + U2F_HANDLE_SIGN_HEADER_SIZE, keyHandleLength);
172  G_io_app.apdu_length = keyHandleLength;
173  G_io_app.apdu_media = IO_APDU_MEDIA_U2F; // the effective transport is managed by the U2F layer
174  G_io_app.apdu_state = APDU_U2F;
175 
176  // prepare for asynch reply
178 
179  // don't reset the u2f processing command state, as we still await for the io_exchange caller to
180  // make the response call
181  /*
182  app_dispatch();
183  if ((btchip_context_D.io_flags & IO_ASYNCH_REPLY) == 0) {
184  u2f_proxy_response(service, btchip_context_D.outLength);
185  }
186  */
187 }
188 
189 void u2f_apdu_get_version(u2f_service_t *service,
190  uint8_t p1,
191  uint8_t p2,
192  uint8_t *buffer,
193  uint16_t length)
194 {
195  // screen_printf("U2F version\n");
196  UNUSED(p1);
197  UNUSED(p2);
198  UNUSED(buffer);
199  UNUSED(length);
200  u2f_message_reply(service, U2F_CMD_MSG, (uint8_t *) U2F_VERSION, sizeof(U2F_VERSION));
201 }
202 
203 // Special command that returns the proxy
204 void u2f_apdu_get_info(u2f_service_t *service,
205  uint8_t p1,
206  uint8_t p2,
207  uint8_t *buffer,
208  uint16_t length)
209 {
210  UNUSED(p1);
211  UNUSED(p2);
212  UNUSED(buffer);
213  UNUSED(length);
214  u2f_message_reply(service, U2F_CMD_MSG, (uint8_t *) INFO, sizeof(INFO));
215 }
216 
217 #endif // U2F_PROXY_MAGIC
218 
219 void u2f_handle_cmd_init(u2f_service_t *service,
220  uint8_t *buffer,
221  uint16_t length,
222  uint8_t *channelInit)
223 {
224  // screen_printf("U2F init\n");
225  uint8_t channel[4];
226  (void) length;
227  if (u2f_is_channel_broadcast(channelInit)) {
228  // cx_rng_no_throw(channel, 4); // not available within the IO task, just do without
229  service->next_channel += 1;
230  U4BE_ENCODE(channel, 0, service->next_channel);
231  }
232  else {
233  memcpy(channel, channelInit, 4);
234  }
235  memmove(G_io_apdu_buffer, buffer, 8);
236  memcpy(G_io_apdu_buffer + 8, channel, 4);
237  G_io_apdu_buffer[12] = INIT_U2F_VERSION;
238  G_io_apdu_buffer[13] = INIT_DEVICE_VERSION_MAJOR;
239  G_io_apdu_buffer[14] = INIT_DEVICE_VERSION_MINOR;
240  G_io_apdu_buffer[15] = INIT_BUILD_VERSION;
241  G_io_apdu_buffer[16] = INIT_CAPABILITIES;
242 
243  if (u2f_is_channel_broadcast(channelInit)) {
244  memset(service->channel, 0xff, 4);
245  }
246  else {
247  memcpy(service->channel, channel, 4);
248  }
249  u2f_message_reply(service, U2F_CMD_INIT, G_io_apdu_buffer, 17);
250 }
251 
252 void u2f_handle_cmd_ping(u2f_service_t *service, uint8_t *buffer, uint16_t length)
253 {
254  // screen_printf("U2F ping\n");
255  u2f_message_reply(service, U2F_CMD_PING, buffer, length);
256 }
257 
258 int u2f_get_cmd_msg_data_length(const uint8_t *buffer, uint16_t length)
259 {
260  /* Parse buffer to retrieve the data length.
261  Only Extended encoding is supported */
262 
263  if (length < APDU_MIN_HEADER) {
264  return -1;
265  }
266 
267  if (length == APDU_MIN_HEADER) {
268  // Either short or extended encoding with Lc and Le omitted
269  return 0;
270  }
271 
272  if (length == APDU_MIN_HEADER + 1) {
273  // Short encoding, with next byte either Le or Lc with the other one omitted
274  // There is no way to tell so no way to check the value
275  // but anyway the data length is 0
276 
277  // Support this particular short encoding APDU as Fido Conformance Tool v1.7.0
278  // is using it even though spec requires that short encoding should not be used
279  // over HID.
280  return 0;
281  }
282 
283  if (length < APDU_MIN_HEADER + 3) {
284  // Short encoding or bad length
285  // We don't support short encoding
286  return -1;
287  }
288 
289  if (length == APDU_MIN_HEADER + 3) {
290  if (buffer[4] != 0) {
291  // Short encoding or bad length
292  // We don't support short encoding
293  return -1;
294  }
295  // Can't be short encoding as Lc = 0x00 would lead to invalid length
296  // so extended encoding and either:
297  // - Lc = 0x00 0x00 0x00 and Le is omitted
298  // - Lc omitted and Le = 0x00 0xyy 0xzz
299  // so no way to check the value
300  // but anyway the data length is 0
301  return 0;
302  }
303 
304  if (buffer[LC_FIRST_BYTE_OFFSET] != 0) {
305  // Short encoding or bad length
306  // We don't support short encoding
307  return -1;
308  }
309 
310  // Can't be short encoding as Lc = 0 would lead to invalid length
311  // so extended encoding with Lc field present, optionally Le (2B) is present too
312  uint32_t dataLength
313  = (buffer[LC_FIRST_BYTE_OFFSET + 1] << 8) | (buffer[LC_FIRST_BYTE_OFFSET + 2]);
314 
315  // Ensure that Lc value is consistent
316  if ((APDU_MIN_HEADER + LONG_ENC_LC_SIZE + dataLength != length)
317  && (APDU_MIN_HEADER + LONG_ENC_LC_SIZE + dataLength + LONG_ENC_LE_SIZE != length)) {
318  return -1;
319  }
320 
321  return dataLength;
322 }
323 
324 void u2f_handle_cmd_msg(u2f_service_t *service, uint8_t *buffer, uint16_t length)
325 {
326  // screen_printf("U2F msg\n");
327 
328 #ifdef U2F_PROXY_MAGIC
329  uint8_t cla = buffer[OFFSET_CLA];
330  uint8_t ins = buffer[OFFSET_INS];
331  uint8_t p1 = buffer[OFFSET_P1];
332  uint8_t p2 = buffer[OFFSET_P2];
333 #endif // U2F_PROXY_MAGIC
334 
335  int dataLength = u2f_get_cmd_msg_data_length(buffer, length);
336  if (dataLength < 0) {
337  // invalid size
339  service, U2F_CMD_MSG, (uint8_t *) SW_WRONG_LENGTH, sizeof(SW_WRONG_LENGTH));
340  return;
341  }
342 
343 #ifndef U2F_PROXY_MAGIC
344 
345  // No proxy mode, just pass the APDU as it is to the upper layer
346  memmove(G_io_apdu_buffer, buffer, length);
347  G_io_app.apdu_length = length;
348  G_io_app.apdu_media = IO_APDU_MEDIA_U2F; // the effective transport is managed by the U2F layer
349  G_io_app.apdu_state = APDU_U2F;
350 
351 #else // U2F_PROXY_MAGIC
352 
353  if (cla != FIDO_CLA) {
355  service, U2F_CMD_MSG, (uint8_t *) SW_UNKNOWN_CLASS, sizeof(SW_UNKNOWN_CLASS));
356  return;
357  }
358  switch (ins) {
359  case FIDO_INS_ENROLL:
360  // screen_printf("enroll\n");
361  u2f_apdu_enroll(service, p1, p2, buffer + OFFSET_DATA, dataLength);
362  break;
363  case FIDO_INS_SIGN:
364  // screen_printf("sign\n");
365  u2f_apdu_sign(service, p1, p2, buffer + OFFSET_DATA, dataLength);
366  break;
367  case FIDO_INS_GET_VERSION:
368  // screen_printf("version\n");
369  u2f_apdu_get_version(service, p1, p2, buffer + OFFSET_DATA, dataLength);
370  break;
371 
372  // only support by
373  case FIDO_INS_PROP_GET_INFO:
374  u2f_apdu_get_info(service, p1, p2, buffer + OFFSET_DATA, dataLength);
375  break;
376 
377  default:
378  // screen_printf("unsupported\n");
379  u2f_message_reply(service,
380  U2F_CMD_MSG,
381  (uint8_t *) SW_UNKNOWN_INSTRUCTION,
382  sizeof(SW_UNKNOWN_INSTRUCTION));
383  return;
384  }
385 
386 #endif // U2F_PROXY_MAGIC
387 }
388 
389 void u2f_message_complete(u2f_service_t *service)
390 {
391  uint8_t cmd = service->transportBuffer[0];
392  uint16_t length = (service->transportBuffer[1] << 8) | (service->transportBuffer[2]);
393  switch (cmd) {
394  case U2F_CMD_INIT:
395  u2f_handle_cmd_init(service, service->transportBuffer + 3, length, service->channel);
396  break;
397  case U2F_CMD_PING:
398  u2f_handle_cmd_ping(service, service->transportBuffer + 3, length);
399  break;
400  case U2F_CMD_MSG:
401  u2f_handle_cmd_msg(service, service->transportBuffer + 3, length);
402  break;
403 #ifdef HAVE_FIDO2
404  case CTAP2_CMD_CBOR:
405  ctap2_handle_cmd_cbor(service, service->transportBuffer + 3, length);
406  break;
407  case CTAP2_CMD_CANCEL:
408  ctap2_handle_cmd_cancel(service, service->transportBuffer + 3, length);
409  break;
410 #endif
411  }
412 }
413 
414 #endif
#define OFFSET_P1
Definition: offsets.h:14
#define OFFSET_P2
Definition: offsets.h:18
#define OFFSET_INS
Definition: offsets.h:10
#define OFFSET_CLA
Definition: offsets.h:6
uint32_t next_channel
Definition: u2f_service.h:62
uint8_t * transportBuffer
Definition: u2f_service.h:76
uint8_t channel[U2F_CHANNEL_ID_SIZE]
Definition: u2f_service.h:64
int u2f_get_cmd_msg_data_length(const uint8_t *buffer, uint16_t length)
void u2f_message_set_autoreply_wait_user_presence(u2f_service_t *service, bool enabled)
void u2f_message_complete(u2f_service_t *service)
void u2f_message_reply(u2f_service_t *service, uint8_t cmd, uint8_t *buffer, uint16_t length)
void ctap2_handle_cmd_cancel(u2f_service_t *service, uint8_t *buffer, uint16_t length)
void ctap2_handle_cmd_cbor(u2f_service_t *service, uint8_t *buffer, uint16_t length)
#define CTAP2_CMD_CANCEL
Definition: u2f_transport.h:29
#define CTAP2_CMD_CBOR
Definition: u2f_transport.h:28
#define U2F_CMD_INIT
Definition: u2f_transport.h:32
#define U2F_CMD_MSG
Definition: u2f_transport.h:27
bool u2f_is_channel_broadcast(uint8_t *channel)
#define U2F_CMD_PING
Definition: u2f_transport.h:26
unsigned short uint16_t
Definition: usbd_conf.h:54
unsigned char uint8_t
Definition: usbd_conf.h:53