1 /*
2 * Copyright (c) 2018-2022 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 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8 #include <openssl/sha.h>
9 #include "fido.h"
10 #include "fido/es256.h"
11
12 #define CTAP21_UV_TOKEN_PERM_MAKECRED 0x01
13 #define CTAP21_UV_TOKEN_PERM_ASSERT 0x02
14 #define CTAP21_UV_TOKEN_PERM_CRED_MGMT 0x04
15 #define CTAP21_UV_TOKEN_PERM_BIO 0x08
16 #define CTAP21_UV_TOKEN_PERM_LARGEBLOB 0x10
17 #define CTAP21_UV_TOKEN_PERM_CONFIG 0x20
18
19 int
fido_sha256(fido_blob_t * digest,const u_char * data,size_t data_len)20 fido_sha256(fido_blob_t *digest, const u_char *data, size_t data_len)
21 {
22 if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
23 return (-1);
24
25 digest->len = SHA256_DIGEST_LENGTH;
26
27 if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
28 fido_blob_reset(digest);
29 return (-1);
30 }
31
32 return (0);
33 }
34
35 static int
pin_sha256_enc(const fido_dev_t * dev,const fido_blob_t * shared,const fido_blob_t * pin,fido_blob_t ** out)36 pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared,
37 const fido_blob_t *pin, fido_blob_t **out)
38 {
39 fido_blob_t *ph = NULL;
40 int r;
41
42 if ((*out = fido_blob_new()) == NULL ||
43 (ph = fido_blob_new()) == NULL) {
44 r = FIDO_ERR_INTERNAL;
45 goto fail;
46 }
47
48 if (fido_sha256(ph, pin->ptr, pin->len) < 0 || ph->len < 16) {
49 fido_log_debug("%s: SHA256", __func__);
50 r = FIDO_ERR_INTERNAL;
51 goto fail;
52 }
53
54 ph->len = 16; /* first 16 bytes */
55
56 if (aes256_cbc_enc(dev, shared, ph, *out) < 0) {
57 fido_log_debug("%s: aes256_cbc_enc", __func__);
58 r = FIDO_ERR_INTERNAL;
59 goto fail;
60 }
61
62 r = FIDO_OK;
63 fail:
64 fido_blob_free(&ph);
65
66 return (r);
67 }
68
69 static int
pad64(const char * pin,fido_blob_t ** ppin)70 pad64(const char *pin, fido_blob_t **ppin)
71 {
72 size_t pin_len;
73 size_t ppin_len;
74
75 pin_len = strlen(pin);
76 if (pin_len < 4 || pin_len > 63) {
77 fido_log_debug("%s: invalid pin length", __func__);
78 return (FIDO_ERR_PIN_POLICY_VIOLATION);
79 }
80
81 if ((*ppin = fido_blob_new()) == NULL)
82 return (FIDO_ERR_INTERNAL);
83
84 ppin_len = (pin_len + 63U) & ~63U;
85 if (ppin_len < pin_len ||
86 ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
87 fido_blob_free(ppin);
88 return (FIDO_ERR_INTERNAL);
89 }
90
91 memcpy((*ppin)->ptr, pin, pin_len);
92 (*ppin)->len = ppin_len;
93
94 return (FIDO_OK);
95 }
96
97 static int
pin_pad64_enc(const fido_dev_t * dev,const fido_blob_t * shared,const char * pin,fido_blob_t ** out)98 pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared,
99 const char *pin, fido_blob_t **out)
100 {
101 fido_blob_t *ppin = NULL;
102 int r;
103
104 if ((r = pad64(pin, &ppin)) != FIDO_OK) {
105 fido_log_debug("%s: pad64", __func__);
106 goto fail;
107 }
108
109 if ((*out = fido_blob_new()) == NULL) {
110 r = FIDO_ERR_INTERNAL;
111 goto fail;
112 }
113
114 if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) {
115 fido_log_debug("%s: aes256_cbc_enc", __func__);
116 r = FIDO_ERR_INTERNAL;
117 goto fail;
118 }
119
120 r = FIDO_OK;
121 fail:
122 fido_blob_free(&ppin);
123
124 return (r);
125 }
126
127 static cbor_item_t *
encode_uv_permission(uint8_t cmd)128 encode_uv_permission(uint8_t cmd)
129 {
130 switch (cmd) {
131 case CTAP_CBOR_ASSERT:
132 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT));
133 case CTAP_CBOR_BIO_ENROLL_PRE:
134 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO));
135 case CTAP_CBOR_CONFIG:
136 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG));
137 case CTAP_CBOR_MAKECRED:
138 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED));
139 case CTAP_CBOR_CRED_MGMT_PRE:
140 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT));
141 case CTAP_CBOR_LARGEBLOB:
142 return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB));
143 default:
144 fido_log_debug("%s: cmd 0x%02x", __func__, cmd);
145 return (NULL);
146 }
147 }
148
149 static int
ctap20_uv_token_tx(fido_dev_t * dev,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,int * ms)150 ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
151 const es256_pk_t *pk, int *ms)
152 {
153 fido_blob_t f;
154 fido_blob_t *p = NULL;
155 fido_blob_t *phe = NULL;
156 cbor_item_t *argv[6];
157 int r;
158
159 memset(&f, 0, sizeof(f));
160 memset(argv, 0, sizeof(argv));
161
162 if (pin == NULL) {
163 fido_log_debug("%s: NULL pin", __func__);
164 r = FIDO_ERR_PIN_REQUIRED;
165 goto fail;
166 }
167
168 if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
169 (const unsigned char *)pin, strlen(pin)) < 0) {
170 fido_log_debug("%s: fido_blob_set", __func__);
171 r = FIDO_ERR_INVALID_ARGUMENT;
172 goto fail;
173 }
174
175 if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
176 fido_log_debug("%s: pin_sha256_enc", __func__);
177 goto fail;
178 }
179
180 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
181 (argv[1] = cbor_build_uint8(5)) == NULL ||
182 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
183 (argv[5] = fido_blob_encode(phe)) == NULL) {
184 fido_log_debug("%s: cbor encode", __func__);
185 r = FIDO_ERR_INTERNAL;
186 goto fail;
187 }
188
189 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
190 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
191 fido_log_debug("%s: fido_tx", __func__);
192 r = FIDO_ERR_TX;
193 goto fail;
194 }
195
196 r = FIDO_OK;
197 fail:
198 cbor_vector_free(argv, nitems(argv));
199 fido_blob_free(&p);
200 fido_blob_free(&phe);
201 free(f.ptr);
202
203 return (r);
204 }
205
206 static int
ctap21_uv_token_tx(fido_dev_t * dev,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,uint8_t cmd,const char * rpid,int * ms)207 ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
208 const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms)
209 {
210 fido_blob_t f;
211 fido_blob_t *p = NULL;
212 fido_blob_t *phe = NULL;
213 cbor_item_t *argv[10];
214 uint8_t subcmd;
215 int r;
216
217 memset(&f, 0, sizeof(f));
218 memset(argv, 0, sizeof(argv));
219
220 if (pin != NULL) {
221 if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
222 (const unsigned char *)pin, strlen(pin)) < 0) {
223 fido_log_debug("%s: fido_blob_set", __func__);
224 r = FIDO_ERR_INVALID_ARGUMENT;
225 goto fail;
226 }
227 if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
228 fido_log_debug("%s: pin_sha256_enc", __func__);
229 goto fail;
230 }
231 subcmd = 9; /* getPinUvAuthTokenUsingPinWithPermissions */
232 } else {
233 if (fido_dev_has_uv(dev) == false) {
234 fido_log_debug("%s: fido_dev_has_uv", __func__);
235 r = FIDO_ERR_PIN_REQUIRED;
236 goto fail;
237 }
238 subcmd = 6; /* getPinUvAuthTokenUsingUvWithPermissions */
239 }
240
241 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
242 (argv[1] = cbor_build_uint8(subcmd)) == NULL ||
243 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
244 (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) ||
245 (argv[8] = encode_uv_permission(cmd)) == NULL ||
246 (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) {
247 fido_log_debug("%s: cbor encode", __func__);
248 r = FIDO_ERR_INTERNAL;
249 goto fail;
250 }
251
252 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
253 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
254 fido_log_debug("%s: fido_tx", __func__);
255 r = FIDO_ERR_TX;
256 goto fail;
257 }
258
259 r = FIDO_OK;
260 fail:
261 cbor_vector_free(argv, nitems(argv));
262 fido_blob_free(&p);
263 fido_blob_free(&phe);
264 free(f.ptr);
265
266 return (r);
267 }
268
269 static int
parse_uv_token(const cbor_item_t * key,const cbor_item_t * val,void * arg)270 parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg)
271 {
272 fido_blob_t *token = arg;
273
274 if (cbor_isa_uint(key) == false ||
275 cbor_int_get_width(key) != CBOR_INT_8 ||
276 cbor_get_uint8(key) != 2) {
277 fido_log_debug("%s: cbor type", __func__);
278 return (0); /* ignore */
279 }
280
281 return (fido_blob_decode(val, token));
282 }
283
284 static int
uv_token_rx(fido_dev_t * dev,const fido_blob_t * ecdh,fido_blob_t * token,int * ms)285 uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
286 int *ms)
287 {
288 fido_blob_t *aes_token = NULL;
289 unsigned char *msg = NULL;
290 int msglen;
291 int r;
292
293 if ((aes_token = fido_blob_new()) == NULL) {
294 r = FIDO_ERR_INTERNAL;
295 goto fail;
296 }
297
298 if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
299 r = FIDO_ERR_INTERNAL;
300 goto fail;
301 }
302
303 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
304 fido_log_debug("%s: fido_rx", __func__);
305 r = FIDO_ERR_RX;
306 goto fail;
307 }
308
309 if ((r = cbor_parse_reply(msg, (size_t)msglen, aes_token,
310 parse_uv_token)) != FIDO_OK) {
311 fido_log_debug("%s: parse_uv_token", __func__);
312 goto fail;
313 }
314
315 if (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) {
316 fido_log_debug("%s: aes256_cbc_dec", __func__);
317 r = FIDO_ERR_RX;
318 goto fail;
319 }
320
321 r = FIDO_OK;
322 fail:
323 fido_blob_free(&aes_token);
324 freezero(msg, FIDO_MAXMSG);
325
326 return (r);
327 }
328
329 static int
uv_token_wait(fido_dev_t * dev,uint8_t cmd,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,const char * rpid,fido_blob_t * token,int * ms)330 uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
331 const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
332 fido_blob_t *token, int *ms)
333 {
334 int r;
335
336 if (ecdh == NULL || pk == NULL)
337 return (FIDO_ERR_INVALID_ARGUMENT);
338 if (fido_dev_supports_permissions(dev))
339 r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms);
340 else
341 r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms);
342 if (r != FIDO_OK)
343 return (r);
344
345 return (uv_token_rx(dev, ecdh, token, ms));
346 }
347
348 int
fido_dev_get_uv_token(fido_dev_t * dev,uint8_t cmd,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,const char * rpid,fido_blob_t * token,int * ms)349 fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin,
350 const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
351 fido_blob_t *token, int *ms)
352 {
353 return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms));
354 }
355
356 static int
fido_dev_change_pin_tx(fido_dev_t * dev,const char * pin,const char * oldpin,int * ms)357 fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin,
358 int *ms)
359 {
360 fido_blob_t f;
361 fido_blob_t *ppine = NULL;
362 fido_blob_t *ecdh = NULL;
363 fido_blob_t *opin = NULL;
364 fido_blob_t *opinhe = NULL;
365 cbor_item_t *argv[6];
366 es256_pk_t *pk = NULL;
367 int r;
368
369 memset(&f, 0, sizeof(f));
370 memset(argv, 0, sizeof(argv));
371
372 if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin,
373 (const unsigned char *)oldpin, strlen(oldpin)) < 0) {
374 fido_log_debug("%s: fido_blob_set", __func__);
375 r = FIDO_ERR_INVALID_ARGUMENT;
376 goto fail;
377 }
378
379 if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
380 fido_log_debug("%s: fido_do_ecdh", __func__);
381 goto fail;
382 }
383
384 /* pad and encrypt new pin */
385 if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
386 fido_log_debug("%s: pin_pad64_enc", __func__);
387 goto fail;
388 }
389
390 /* hash and encrypt old pin */
391 if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) {
392 fido_log_debug("%s: pin_sha256_enc", __func__);
393 goto fail;
394 }
395
396 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
397 (argv[1] = cbor_build_uint8(4)) == NULL ||
398 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
399 (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL ||
400 (argv[4] = fido_blob_encode(ppine)) == NULL ||
401 (argv[5] = fido_blob_encode(opinhe)) == NULL) {
402 fido_log_debug("%s: cbor encode", __func__);
403 r = FIDO_ERR_INTERNAL;
404 goto fail;
405 }
406
407 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
408 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
409 fido_log_debug("%s: fido_tx", __func__);
410 r = FIDO_ERR_TX;
411 goto fail;
412 }
413
414 r = FIDO_OK;
415 fail:
416 cbor_vector_free(argv, nitems(argv));
417 es256_pk_free(&pk);
418 fido_blob_free(&ppine);
419 fido_blob_free(&ecdh);
420 fido_blob_free(&opin);
421 fido_blob_free(&opinhe);
422 free(f.ptr);
423
424 return (r);
425
426 }
427
428 static int
fido_dev_set_pin_tx(fido_dev_t * dev,const char * pin,int * ms)429 fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms)
430 {
431 fido_blob_t f;
432 fido_blob_t *ppine = NULL;
433 fido_blob_t *ecdh = NULL;
434 cbor_item_t *argv[5];
435 es256_pk_t *pk = NULL;
436 int r;
437
438 memset(&f, 0, sizeof(f));
439 memset(argv, 0, sizeof(argv));
440
441 if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
442 fido_log_debug("%s: fido_do_ecdh", __func__);
443 goto fail;
444 }
445
446 if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
447 fido_log_debug("%s: pin_pad64_enc", __func__);
448 goto fail;
449 }
450
451 if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
452 (argv[1] = cbor_build_uint8(3)) == NULL ||
453 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
454 (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL ||
455 (argv[4] = fido_blob_encode(ppine)) == NULL) {
456 fido_log_debug("%s: cbor encode", __func__);
457 r = FIDO_ERR_INTERNAL;
458 goto fail;
459 }
460
461 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
462 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
463 fido_log_debug("%s: fido_tx", __func__);
464 r = FIDO_ERR_TX;
465 goto fail;
466 }
467
468 r = FIDO_OK;
469 fail:
470 cbor_vector_free(argv, nitems(argv));
471 es256_pk_free(&pk);
472 fido_blob_free(&ppine);
473 fido_blob_free(&ecdh);
474 free(f.ptr);
475
476 return (r);
477 }
478
479 static int
fido_dev_set_pin_wait(fido_dev_t * dev,const char * pin,const char * oldpin,int * ms)480 fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
481 int *ms)
482 {
483 int r;
484
485 if (oldpin != NULL) {
486 if ((r = fido_dev_change_pin_tx(dev, pin, oldpin,
487 ms)) != FIDO_OK) {
488 fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
489 return (r);
490 }
491 } else {
492 if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) {
493 fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
494 return (r);
495 }
496 }
497
498 if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
499 fido_log_debug("%s: fido_rx_cbor_status", __func__);
500 return (r);
501 }
502
503 if (dev->flags & FIDO_DEV_PIN_UNSET) {
504 dev->flags &= ~FIDO_DEV_PIN_UNSET;
505 dev->flags |= FIDO_DEV_PIN_SET;
506 }
507
508 return (FIDO_OK);
509 }
510
511 int
fido_dev_set_pin(fido_dev_t * dev,const char * pin,const char * oldpin)512 fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
513 {
514 int ms = dev->timeout_ms;
515
516 return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms));
517 }
518
519 static int
parse_retry_count(const uint8_t keyval,const cbor_item_t * key,const cbor_item_t * val,void * arg)520 parse_retry_count(const uint8_t keyval, const cbor_item_t *key,
521 const cbor_item_t *val, void *arg)
522 {
523 int *retries = arg;
524 uint64_t n;
525
526 if (cbor_isa_uint(key) == false ||
527 cbor_int_get_width(key) != CBOR_INT_8 ||
528 cbor_get_uint8(key) != keyval) {
529 fido_log_debug("%s: cbor type", __func__);
530 return (0); /* ignore */
531 }
532
533 if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) {
534 fido_log_debug("%s: cbor_decode_uint64", __func__);
535 return (-1);
536 }
537
538 *retries = (int)n;
539
540 return (0);
541 }
542
543 static int
parse_pin_retry_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)544 parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
545 {
546 return (parse_retry_count(3, key, val, arg));
547 }
548
549 static int
parse_uv_retry_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)550 parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
551 {
552 return (parse_retry_count(5, key, val, arg));
553 }
554
555 static int
fido_dev_get_retry_count_tx(fido_dev_t * dev,uint8_t subcmd,int * ms)556 fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms)
557 {
558 fido_blob_t f;
559 cbor_item_t *argv[2];
560 int r;
561
562 memset(&f, 0, sizeof(f));
563 memset(argv, 0, sizeof(argv));
564
565 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
566 (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
567 r = FIDO_ERR_INTERNAL;
568 goto fail;
569 }
570
571 if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
572 &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
573 fido_log_debug("%s: fido_tx", __func__);
574 r = FIDO_ERR_TX;
575 goto fail;
576 }
577
578 r = FIDO_OK;
579 fail:
580 cbor_vector_free(argv, nitems(argv));
581 free(f.ptr);
582
583 return (r);
584 }
585
586 static int
fido_dev_get_pin_retry_count_rx(fido_dev_t * dev,int * retries,int * ms)587 fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
588 {
589 unsigned char *msg;
590 int msglen;
591 int r;
592
593 *retries = 0;
594
595 if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
596 r = FIDO_ERR_INTERNAL;
597 goto fail;
598 }
599
600 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
601 fido_log_debug("%s: fido_rx", __func__);
602 r = FIDO_ERR_RX;
603 goto fail;
604 }
605
606 if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
607 parse_pin_retry_count)) != FIDO_OK) {
608 fido_log_debug("%s: parse_pin_retry_count", __func__);
609 goto fail;
610 }
611
612 r = FIDO_OK;
613 fail:
614 freezero(msg, FIDO_MAXMSG);
615
616 return (r);
617 }
618
619 static int
fido_dev_get_pin_retry_count_wait(fido_dev_t * dev,int * retries,int * ms)620 fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
621 {
622 int r;
623
624 if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK ||
625 (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK)
626 return (r);
627
628 return (FIDO_OK);
629 }
630
631 int
fido_dev_get_retry_count(fido_dev_t * dev,int * retries)632 fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
633 {
634 int ms = dev->timeout_ms;
635
636 return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms));
637 }
638
639 static int
fido_dev_get_uv_retry_count_rx(fido_dev_t * dev,int * retries,int * ms)640 fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
641 {
642 unsigned char *msg;
643 int msglen;
644 int r;
645
646 *retries = 0;
647
648 if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
649 r = FIDO_ERR_INTERNAL;
650 goto fail;
651 }
652
653 if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
654 fido_log_debug("%s: fido_rx", __func__);
655 r = FIDO_ERR_RX;
656 goto fail;
657 }
658
659 if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
660 parse_uv_retry_count)) != FIDO_OK) {
661 fido_log_debug("%s: parse_uv_retry_count", __func__);
662 goto fail;
663 }
664
665 r = FIDO_OK;
666 fail:
667 freezero(msg, FIDO_MAXMSG);
668
669 return (r);
670 }
671
672 static int
fido_dev_get_uv_retry_count_wait(fido_dev_t * dev,int * retries,int * ms)673 fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
674 {
675 int r;
676
677 if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK ||
678 (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK)
679 return (r);
680
681 return (FIDO_OK);
682 }
683
684 int
fido_dev_get_uv_retry_count(fido_dev_t * dev,int * retries)685 fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries)
686 {
687 int ms = dev->timeout_ms;
688
689 return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms));
690 }
691
692 int
cbor_add_uv_params(fido_dev_t * dev,uint8_t cmd,const fido_blob_t * hmac_data,const es256_pk_t * pk,const fido_blob_t * ecdh,const char * pin,const char * rpid,cbor_item_t ** auth,cbor_item_t ** opt,int * ms)693 cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
694 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
695 const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms)
696 {
697 fido_blob_t *token = NULL;
698 int r;
699
700 if ((token = fido_blob_new()) == NULL) {
701 r = FIDO_ERR_INTERNAL;
702 goto fail;
703 }
704
705 if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid,
706 token, ms)) != FIDO_OK) {
707 fido_log_debug("%s: fido_dev_get_uv_token", __func__);
708 goto fail;
709 }
710
711 if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL ||
712 (*opt = cbor_encode_pin_opt(dev)) == NULL) {
713 fido_log_debug("%s: cbor encode", __func__);
714 r = FIDO_ERR_INTERNAL;
715 goto fail;
716 }
717
718 r = FIDO_OK;
719 fail:
720 fido_blob_free(&token);
721
722 return (r);
723 }
724