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