]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libfido2/src/info.c
file: upgrade to 5.41.
[FreeBSD/FreeBSD.git] / contrib / libfido2 / src / info.c
1 /*
2  * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  */
6
7 #include "fido.h"
8
9 static int
10 decode_string(const cbor_item_t *item, void *arg)
11 {
12         fido_str_array_t        *a = arg;
13         const size_t             i = a->len;
14
15         /* keep ptr[x] and len consistent */
16         if (cbor_string_copy(item, &a->ptr[i]) < 0) {
17                 fido_log_debug("%s: cbor_string_copy", __func__);
18                 return (-1);
19         }
20
21         a->len++;
22
23         return (0);
24 }
25
26 static int
27 decode_string_array(const cbor_item_t *item, fido_str_array_t *v)
28 {
29         v->ptr = NULL;
30         v->len = 0;
31
32         if (cbor_isa_array(item) == false ||
33             cbor_array_is_definite(item) == false) {
34                 fido_log_debug("%s: cbor type", __func__);
35                 return (-1);
36         }
37
38         v->ptr = calloc(cbor_array_size(item), sizeof(char *));
39         if (v->ptr == NULL)
40                 return (-1);
41
42         if (cbor_array_iter(item, v, decode_string) < 0) {
43                 fido_log_debug("%s: decode_string", __func__);
44                 return (-1);
45         }
46
47         return (0);
48 }
49
50 static int
51 decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
52 {
53         if (cbor_isa_bytestring(item) == false ||
54             cbor_bytestring_is_definite(item) == false ||
55             cbor_bytestring_length(item) != aaguid_len) {
56                 fido_log_debug("%s: cbor type", __func__);
57                 return (-1);
58         }
59
60         memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
61
62         return (0);
63 }
64
65 static int
66 decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
67 {
68         fido_opt_array_t        *o = arg;
69         const size_t             i = o->len;
70
71         if (cbor_isa_float_ctrl(val) == false ||
72             cbor_float_get_width(val) != CBOR_FLOAT_0 ||
73             cbor_is_bool(val) == false) {
74                 fido_log_debug("%s: cbor type", __func__);
75                 return (0); /* ignore */
76         }
77
78         if (cbor_string_copy(key, &o->name[i]) < 0) {
79                 fido_log_debug("%s: cbor_string_copy", __func__);
80                 return (0); /* ignore */
81         }
82
83         /* keep name/value and len consistent */
84         o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
85         o->len++;
86
87         return (0);
88 }
89
90 static int
91 decode_options(const cbor_item_t *item, fido_opt_array_t *o)
92 {
93         o->name = NULL;
94         o->value = NULL;
95         o->len = 0;
96
97         if (cbor_isa_map(item) == false ||
98             cbor_map_is_definite(item) == false) {
99                 fido_log_debug("%s: cbor type", __func__);
100                 return (-1);
101         }
102
103         o->name = calloc(cbor_map_size(item), sizeof(char *));
104         o->value = calloc(cbor_map_size(item), sizeof(bool));
105         if (o->name == NULL || o->value == NULL)
106                 return (-1);
107
108         return (cbor_map_iter(item, o, decode_option));
109 }
110
111 static int
112 decode_protocol(const cbor_item_t *item, void *arg)
113 {
114         fido_byte_array_t       *p = arg;
115         const size_t             i = p->len;
116
117         if (cbor_isa_uint(item) == false ||
118             cbor_int_get_width(item) != CBOR_INT_8) {
119                 fido_log_debug("%s: cbor type", __func__);
120                 return (-1);
121         }
122
123         /* keep ptr[x] and len consistent */
124         p->ptr[i] = cbor_get_uint8(item);
125         p->len++;
126
127         return (0);
128 }
129
130 static int
131 decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
132 {
133         p->ptr = NULL;
134         p->len = 0;
135
136         if (cbor_isa_array(item) == false ||
137             cbor_array_is_definite(item) == false) {
138                 fido_log_debug("%s: cbor type", __func__);
139                 return (-1);
140         }
141
142         p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
143         if (p->ptr == NULL)
144                 return (-1);
145
146         if (cbor_array_iter(item, p, decode_protocol) < 0) {
147                 fido_log_debug("%s: decode_protocol", __func__);
148                 return (-1);
149         }
150
151         return (0);
152 }
153
154 static int
155 decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
156     void *arg)
157 {
158         fido_algo_t *alg = arg;
159         char *name = NULL;
160         int ok = -1;
161
162         if (cbor_string_copy(key, &name) < 0) {
163                 fido_log_debug("%s: cbor type", __func__);
164                 ok = 0; /* ignore */
165                 goto out;
166         }
167
168         if (!strcmp(name, "alg")) {
169                 if (cbor_isa_negint(val) == false ||
170                     cbor_get_int(val) > INT_MAX || alg->cose != 0) {
171                         fido_log_debug("%s: alg", __func__);
172                         goto out;
173                 }
174                 alg->cose = -(int)cbor_get_int(val) - 1;
175         } else if (!strcmp(name, "type")) {
176                 if (cbor_string_copy(val, &alg->type) < 0) {
177                         fido_log_debug("%s: type", __func__);
178                         goto out;
179                 }
180         }
181
182         ok = 0;
183 out:
184         free(name);
185
186         return (ok);
187 }
188
189 static void
190 free_algo(fido_algo_t *a)
191 {
192         free(a->type);
193         a->type = NULL;
194         a->cose = 0;
195 }
196
197 static int
198 decode_algorithm(const cbor_item_t *item, void *arg)
199 {
200         fido_algo_array_t *aa = arg;
201         const size_t i = aa->len;
202
203         if (cbor_isa_map(item) == false ||
204             cbor_map_is_definite(item) == false) {
205                 fido_log_debug("%s: cbor type", __func__);
206                 return (-1);
207         }
208
209         memset(&aa->ptr[i], 0, sizeof(aa->ptr[i]));
210
211         if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
212                 fido_log_debug("%s: decode_algorithm_entry", __func__);
213                 free_algo(&aa->ptr[i]);
214                 return (-1);
215         }
216
217         /* keep ptr[x] and len consistent */
218         aa->len++;
219
220         return (0);
221 }
222
223 static int
224 decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa)
225 {
226         aa->ptr = NULL;
227         aa->len = 0;
228
229         if (cbor_isa_array(item) == false ||
230             cbor_array_is_definite(item) == false) {
231                 fido_log_debug("%s: cbor type", __func__);
232                 return (-1);
233         }
234
235         aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t));
236         if (aa->ptr == NULL)
237                 return (-1);
238
239         if (cbor_array_iter(item, aa, decode_algorithm) < 0) {
240                 fido_log_debug("%s: decode_algorithm", __func__);
241                 return (-1);
242         }
243
244         return (0);
245 }
246
247 static int
248 parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
249 {
250         fido_cbor_info_t *ci = arg;
251
252         if (cbor_isa_uint(key) == false ||
253             cbor_int_get_width(key) != CBOR_INT_8) {
254                 fido_log_debug("%s: cbor type", __func__);
255                 return (0); /* ignore */
256         }
257
258         switch (cbor_get_uint8(key)) {
259         case 1: /* versions */
260                 return (decode_string_array(val, &ci->versions));
261         case 2: /* extensions */
262                 return (decode_string_array(val, &ci->extensions));
263         case 3: /* aaguid */
264                 return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
265         case 4: /* options */
266                 return (decode_options(val, &ci->options));
267         case 5: /* maxMsgSize */
268                 return (cbor_decode_uint64(val, &ci->maxmsgsiz));
269         case 6: /* pinProtocols */
270                 return (decode_protocols(val, &ci->protocols));
271         case 7: /* maxCredentialCountInList */
272                 return (cbor_decode_uint64(val, &ci->maxcredcntlst));
273         case 8: /* maxCredentialIdLength */
274                 return (cbor_decode_uint64(val, &ci->maxcredidlen));
275         case 9: /* transports */
276                 return (decode_string_array(val, &ci->transports));
277         case 10: /* algorithms */
278                 return (decode_algorithms(val, &ci->algorithms));
279         case 14: /* fwVersion */
280                 return (cbor_decode_uint64(val, &ci->fwversion));
281         case 15: /* maxCredBlobLen */
282                 return (cbor_decode_uint64(val, &ci->maxcredbloblen));
283         default: /* ignore */
284                 fido_log_debug("%s: cbor type", __func__);
285                 return (0);
286         }
287 }
288
289 static int
290 fido_dev_get_cbor_info_tx(fido_dev_t *dev)
291 {
292         const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
293
294         fido_log_debug("%s: dev=%p", __func__, (void *)dev);
295
296         if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
297                 fido_log_debug("%s: fido_tx", __func__);
298                 return (FIDO_ERR_TX);
299         }
300
301         return (FIDO_OK);
302 }
303
304 static int
305 fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
306 {
307         unsigned char   reply[FIDO_MAXMSG];
308         int             reply_len;
309
310         fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
311             (void *)ci, ms);
312
313         fido_cbor_info_reset(ci);
314
315         if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
316             ms)) < 0) {
317                 fido_log_debug("%s: fido_rx", __func__);
318                 return (FIDO_ERR_RX);
319         }
320
321         return (cbor_parse_reply(reply, (size_t)reply_len, ci,
322             parse_reply_element));
323 }
324
325 int
326 fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
327 {
328         int r;
329
330 #ifdef USE_WINHELLO
331         if (dev->flags & FIDO_DEV_WINHELLO)
332                 return (fido_winhello_get_cbor_info(dev, ci));
333 #endif
334         if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK ||
335             (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
336                 return (r);
337
338         return (FIDO_OK);
339 }
340
341 int
342 fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
343 {
344         return (fido_dev_get_cbor_info_wait(dev, ci, -1));
345 }
346
347 /*
348  * get/set functions for fido_cbor_info_t; always at the end of the file
349  */
350
351 fido_cbor_info_t *
352 fido_cbor_info_new(void)
353 {
354         return (calloc(1, sizeof(fido_cbor_info_t)));
355 }
356
357 static void
358 free_str_array(fido_str_array_t *sa)
359 {
360         for (size_t i = 0; i < sa->len; i++)
361                 free(sa->ptr[i]);
362
363         free(sa->ptr);
364         sa->ptr = NULL;
365         sa->len = 0;
366 }
367
368 static void
369 free_opt_array(fido_opt_array_t *oa)
370 {
371         for (size_t i = 0; i < oa->len; i++)
372                 free(oa->name[i]);
373
374         free(oa->name);
375         free(oa->value);
376         oa->name = NULL;
377         oa->value = NULL;
378 }
379
380 static void
381 free_byte_array(fido_byte_array_t *ba)
382 {
383         free(ba->ptr);
384
385         ba->ptr = NULL;
386         ba->len = 0;
387 }
388
389 static void
390 free_algo_array(fido_algo_array_t *aa)
391 {
392         for (size_t i = 0; i < aa->len; i++)
393                 free_algo(&aa->ptr[i]);
394
395         free(aa->ptr);
396         aa->ptr = NULL;
397         aa->len = 0;
398 }
399
400 void
401 fido_cbor_info_reset(fido_cbor_info_t *ci)
402 {
403         free_str_array(&ci->versions);
404         free_str_array(&ci->extensions);
405         free_str_array(&ci->transports);
406         free_opt_array(&ci->options);
407         free_byte_array(&ci->protocols);
408         free_algo_array(&ci->algorithms);
409 }
410
411 void
412 fido_cbor_info_free(fido_cbor_info_t **ci_p)
413 {
414         fido_cbor_info_t *ci;
415
416         if (ci_p == NULL || (ci = *ci_p) ==  NULL)
417                 return;
418         fido_cbor_info_reset(ci);
419         free(ci);
420         *ci_p = NULL;
421 }
422
423 char **
424 fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
425 {
426         return (ci->versions.ptr);
427 }
428
429 size_t
430 fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
431 {
432         return (ci->versions.len);
433 }
434
435 char **
436 fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
437 {
438         return (ci->extensions.ptr);
439 }
440
441 size_t
442 fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
443 {
444         return (ci->extensions.len);
445 }
446
447 char **
448 fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci)
449 {
450         return (ci->transports.ptr);
451 }
452
453 size_t
454 fido_cbor_info_transports_len(const fido_cbor_info_t *ci)
455 {
456         return (ci->transports.len);
457 }
458
459 const unsigned char *
460 fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
461 {
462         return (ci->aaguid);
463 }
464
465 size_t
466 fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
467 {
468         return (sizeof(ci->aaguid));
469 }
470
471 char **
472 fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
473 {
474         return (ci->options.name);
475 }
476
477 const bool *
478 fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
479 {
480         return (ci->options.value);
481 }
482
483 size_t
484 fido_cbor_info_options_len(const fido_cbor_info_t *ci)
485 {
486         return (ci->options.len);
487 }
488
489 uint64_t
490 fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci)
491 {
492         return (ci->maxcredbloblen);
493 }
494
495 uint64_t
496 fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
497 {
498         return (ci->maxmsgsiz);
499 }
500
501 uint64_t
502 fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
503 {
504         return (ci->maxcredcntlst);
505 }
506
507 uint64_t
508 fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
509 {
510         return (ci->maxcredidlen);
511 }
512
513 uint64_t
514 fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
515 {
516         return (ci->fwversion);
517 }
518
519 const uint8_t *
520 fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
521 {
522         return (ci->protocols.ptr);
523 }
524
525 size_t
526 fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
527 {
528         return (ci->protocols.len);
529 }
530
531 size_t
532 fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci)
533 {
534         return (ci->algorithms.len);
535 }
536
537 const char *
538 fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx)
539 {
540         if (idx >= ci->algorithms.len)
541                 return (NULL);
542
543         return (ci->algorithms.ptr[idx].type);
544 }
545
546 int
547 fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx)
548 {
549         if (idx >= ci->algorithms.len)
550                 return (0);
551
552         return (ci->algorithms.ptr[idx].cose);
553 }