xref: /freebsd/contrib/libfido2/src/u2f.c (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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 <openssl/x509.h>
10 
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
14 #include <errno.h>
15 
16 #include "fido.h"
17 #include "fido/es256.h"
18 #include "fallthrough.h"
19 
20 #define U2F_PACE_MS (100)
21 
22 #if defined(_MSC_VER)
23 static int
24 usleep(unsigned int usec)
25 {
26 	Sleep(usec / 1000);
27 
28 	return (0);
29 }
30 #endif
31 
32 static int
33 delay_ms(unsigned int ms, int *ms_remain)
34 {
35 	if (*ms_remain > -1 && (unsigned int)*ms_remain < ms)
36 		ms = (unsigned int)*ms_remain;
37 
38 	if (ms > UINT_MAX / 1000) {
39 		fido_log_debug("%s: ms=%u", __func__, ms);
40 		return (-1);
41 	}
42 
43 	if (usleep(ms * 1000) < 0) {
44 		fido_log_error(errno, "%s: usleep", __func__);
45 		return (-1);
46 	}
47 
48 	if (*ms_remain > -1)
49 		*ms_remain -= (int)ms;
50 
51 	return (0);
52 }
53 
54 static int
55 sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
56 {
57 	sig->len = *len; /* consume the whole buffer */
58 	if ((sig->ptr = calloc(1, sig->len)) == NULL ||
59 	    fido_buf_read(buf, len, sig->ptr, sig->len) < 0) {
60 		fido_log_debug("%s: fido_buf_read", __func__);
61 		fido_blob_reset(sig);
62 		return (-1);
63 	}
64 
65 	return (0);
66 }
67 
68 static int
69 x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len)
70 {
71 	X509	*cert = NULL;
72 	int	 ok = -1;
73 
74 	if (*len > LONG_MAX) {
75 		fido_log_debug("%s: invalid len %zu", __func__, *len);
76 		goto fail;
77 	}
78 
79 	/* find out the certificate's length */
80 	const unsigned char *end = *buf;
81 	if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf ||
82 	    (x5c->len = (size_t)(end - *buf)) >= *len) {
83 		fido_log_debug("%s: d2i_X509", __func__);
84 		goto fail;
85 	}
86 
87 	/* read accordingly */
88 	if ((x5c->ptr = calloc(1, x5c->len)) == NULL ||
89 	    fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) {
90 		fido_log_debug("%s: fido_buf_read", __func__);
91 		goto fail;
92 	}
93 
94 	ok = 0;
95 fail:
96 	if (cert != NULL)
97 		X509_free(cert);
98 
99 	if (ok < 0)
100 		fido_blob_reset(x5c);
101 
102 	return (ok);
103 }
104 
105 static int
106 authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
107     fido_blob_t *fake_cbor_ad)
108 {
109 	fido_authdata_t	 ad;
110 	cbor_item_t	*item = NULL;
111 	size_t		 alloc_len;
112 
113 	memset(&ad, 0, sizeof(ad));
114 
115 	if (SHA256((const void *)rp_id, strlen(rp_id),
116 	    ad.rp_id_hash) != ad.rp_id_hash) {
117 		fido_log_debug("%s: sha256", __func__);
118 		return (-1);
119 	}
120 
121 	ad.flags = flags; /* XXX translate? */
122 	ad.sigcount = sigcount;
123 
124 	if ((item = cbor_build_bytestring((const unsigned char *)&ad,
125 	    sizeof(ad))) == NULL) {
126 		fido_log_debug("%s: cbor_build_bytestring", __func__);
127 		return (-1);
128 	}
129 
130 	if (fake_cbor_ad->ptr != NULL ||
131 	    (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr,
132 	    &alloc_len)) == 0) {
133 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
134 		cbor_decref(&item);
135 		return (-1);
136 	}
137 
138 	cbor_decref(&item);
139 
140 	return (0);
141 }
142 
143 /* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
144 static int
145 send_dummy_register(fido_dev_t *dev, int *ms)
146 {
147 	iso7816_apdu_t	*apdu = NULL;
148 	unsigned char	*reply = NULL;
149 	unsigned char	 challenge[SHA256_DIGEST_LENGTH];
150 	unsigned char	 application[SHA256_DIGEST_LENGTH];
151 	int		 r;
152 
153 	/* dummy challenge & application */
154 	memset(&challenge, 0xff, sizeof(challenge));
155 	memset(&application, 0xff, sizeof(application));
156 
157 	if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
158 	    SHA256_DIGEST_LENGTH)) == NULL ||
159 	    iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
160 	    iso7816_add(apdu, &application, sizeof(application)) < 0) {
161 		fido_log_debug("%s: iso7816", __func__);
162 		r = FIDO_ERR_INTERNAL;
163 		goto fail;
164 	}
165 
166 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
167 		fido_log_debug("%s: malloc", __func__);
168 		r = FIDO_ERR_INTERNAL;
169 		goto fail;
170 	}
171 
172 	do {
173 		if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
174 		    iso7816_len(apdu), ms) < 0) {
175 			fido_log_debug("%s: fido_tx", __func__);
176 			r = FIDO_ERR_TX;
177 			goto fail;
178 		}
179 		if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) < 2) {
180 			fido_log_debug("%s: fido_rx", __func__);
181 			r = FIDO_ERR_RX;
182 			goto fail;
183 		}
184 		if (delay_ms(U2F_PACE_MS, ms) != 0) {
185 			fido_log_debug("%s: delay_ms", __func__);
186 			r = FIDO_ERR_RX;
187 			goto fail;
188 		}
189 	} while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
190 
191 	r = FIDO_OK;
192 fail:
193 	iso7816_free(&apdu);
194 	freezero(reply, FIDO_MAXMSG);
195 
196 	return (r);
197 }
198 
199 static int
200 key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
201     int *found, int *ms)
202 {
203 	iso7816_apdu_t	*apdu = NULL;
204 	unsigned char	*reply = NULL;
205 	unsigned char	 challenge[SHA256_DIGEST_LENGTH];
206 	unsigned char	 rp_id_hash[SHA256_DIGEST_LENGTH];
207 	uint8_t		 key_id_len;
208 	int		 r;
209 
210 	if (key_id->len > UINT8_MAX || rp_id == NULL) {
211 		fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__,
212 		    key_id->len, (const void *)rp_id);
213 		r = FIDO_ERR_INVALID_ARGUMENT;
214 		goto fail;
215 	}
216 
217 	memset(&challenge, 0xff, sizeof(challenge));
218 	memset(&rp_id_hash, 0, sizeof(rp_id_hash));
219 
220 	if (SHA256((const void *)rp_id, strlen(rp_id),
221 	    rp_id_hash) != rp_id_hash) {
222 		fido_log_debug("%s: sha256", __func__);
223 		r = FIDO_ERR_INTERNAL;
224 		goto fail;
225 	}
226 
227 	key_id_len = (uint8_t)key_id->len;
228 
229 	if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
230 	    SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
231 	    iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
232 	    iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
233 	    iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
234 	    iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
235 		fido_log_debug("%s: iso7816", __func__);
236 		r = FIDO_ERR_INTERNAL;
237 		goto fail;
238 	}
239 
240 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
241 		fido_log_debug("%s: malloc", __func__);
242 		r = FIDO_ERR_INTERNAL;
243 		goto fail;
244 	}
245 
246 	if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
247 	    iso7816_len(apdu), ms) < 0) {
248 		fido_log_debug("%s: fido_tx", __func__);
249 		r = FIDO_ERR_TX;
250 		goto fail;
251 	}
252 	if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) != 2) {
253 		fido_log_debug("%s: fido_rx", __func__);
254 		r = FIDO_ERR_RX;
255 		goto fail;
256 	}
257 
258 	switch ((reply[0] << 8) | reply[1]) {
259 	case SW_CONDITIONS_NOT_SATISFIED:
260 		*found = 1; /* key exists */
261 		break;
262 	case SW_WRONG_DATA:
263 	case SW_WRONG_LENGTH:
264 		*found = 0; /* key does not exist */
265 		break;
266 	default:
267 		/* unexpected sw */
268 		r = FIDO_ERR_INTERNAL;
269 		goto fail;
270 	}
271 
272 	r = FIDO_OK;
273 fail:
274 	iso7816_free(&apdu);
275 	freezero(reply, FIDO_MAXMSG);
276 
277 	return (r);
278 }
279 
280 static int
281 parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id,
282     const unsigned char *reply, size_t len)
283 {
284 	uint8_t		flags;
285 	uint32_t	sigcount;
286 
287 	if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
288 		fido_log_debug("%s: unexpected sw", __func__);
289 		return (FIDO_ERR_RX);
290 	}
291 
292 	len -= 2;
293 
294 	if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 ||
295 	    fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) {
296 		fido_log_debug("%s: fido_buf_read", __func__);
297 		return (FIDO_ERR_RX);
298 	}
299 
300 	if (sig_get(sig, &reply, &len) < 0) {
301 		fido_log_debug("%s: sig_get", __func__);
302 		return (FIDO_ERR_RX);
303 	}
304 
305 	if (authdata_fake(rp_id, flags, sigcount, ad) < 0) {
306 		fido_log_debug("%s; authdata_fake", __func__);
307 		return (FIDO_ERR_RX);
308 	}
309 
310 	return (FIDO_OK);
311 }
312 
313 static int
314 do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
315     const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms)
316 {
317 	iso7816_apdu_t	*apdu = NULL;
318 	unsigned char	*reply = NULL;
319 	unsigned char	 rp_id_hash[SHA256_DIGEST_LENGTH];
320 	int		 reply_len;
321 	uint8_t		 key_id_len;
322 	int		 r;
323 
324 #ifdef FIDO_FUZZ
325 	*ms = 0; /* XXX */
326 #endif
327 
328 	if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
329 	    rp_id == NULL) {
330 		r = FIDO_ERR_INVALID_ARGUMENT;
331 		goto fail;
332 	}
333 
334 	memset(&rp_id_hash, 0, sizeof(rp_id_hash));
335 
336 	if (SHA256((const void *)rp_id, strlen(rp_id),
337 	    rp_id_hash) != rp_id_hash) {
338 		fido_log_debug("%s: sha256", __func__);
339 		r = FIDO_ERR_INTERNAL;
340 		goto fail;
341 	}
342 
343 	key_id_len = (uint8_t)key_id->len;
344 
345 	if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
346 	    SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
347 	    iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
348 	    iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
349 	    iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
350 	    iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
351 		fido_log_debug("%s: iso7816", __func__);
352 		r = FIDO_ERR_INTERNAL;
353 		goto fail;
354 	}
355 
356 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
357 		fido_log_debug("%s: malloc", __func__);
358 		r = FIDO_ERR_INTERNAL;
359 		goto fail;
360 	}
361 
362 	do {
363 		if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
364 		    iso7816_len(apdu), ms) < 0) {
365 			fido_log_debug("%s: fido_tx", __func__);
366 			r = FIDO_ERR_TX;
367 			goto fail;
368 		}
369 		if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
370 		    FIDO_MAXMSG, ms)) < 2) {
371 			fido_log_debug("%s: fido_rx", __func__);
372 			r = FIDO_ERR_RX;
373 			goto fail;
374 		}
375 		if (delay_ms(U2F_PACE_MS, ms) != 0) {
376 			fido_log_debug("%s: delay_ms", __func__);
377 			r = FIDO_ERR_RX;
378 			goto fail;
379 		}
380 	} while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
381 
382 	if ((r = parse_auth_reply(sig, ad, rp_id, reply,
383 	    (size_t)reply_len)) != FIDO_OK) {
384 		fido_log_debug("%s: parse_auth_reply", __func__);
385 		goto fail;
386 	}
387 
388 fail:
389 	iso7816_free(&apdu);
390 	freezero(reply, FIDO_MAXMSG);
391 
392 	return (r);
393 }
394 
395 static int
396 cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len,
397     fido_blob_t *cbor_blob)
398 {
399 	es256_pk_t	*pk = NULL;
400 	cbor_item_t	*pk_cbor = NULL;
401 	size_t		 alloc_len;
402 	int		 ok = -1;
403 
404 	/* only handle uncompressed points */
405 	if (ec_point_len != 65 || ec_point[0] != 0x04) {
406 		fido_log_debug("%s: unexpected format", __func__);
407 		goto fail;
408 	}
409 
410 	if ((pk = es256_pk_new()) == NULL ||
411 	    es256_pk_set_x(pk, &ec_point[1]) < 0 ||
412 	    es256_pk_set_y(pk, &ec_point[33]) < 0) {
413 		fido_log_debug("%s: es256_pk_set", __func__);
414 		goto fail;
415 	}
416 
417 	if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) {
418 		fido_log_debug("%s: es256_pk_encode", __func__);
419 		goto fail;
420 	}
421 
422 	if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr,
423 	    &alloc_len)) != 77) {
424 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
425 		goto fail;
426 	}
427 
428 	ok = 0;
429 fail:
430 	es256_pk_free(&pk);
431 
432 	if (pk_cbor)
433 		cbor_decref(&pk_cbor);
434 
435 	return (ok);
436 }
437 
438 static int
439 encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c,
440     const fido_blob_t *sig, fido_blob_t *out)
441 {
442 	cbor_item_t		*item = NULL;
443 	cbor_item_t		*x5c_cbor = NULL;
444 	const uint8_t		 alg_cbor = (uint8_t)(-cose_alg - 1);
445 	struct cbor_pair	 kv[3];
446 	size_t			 alloc_len;
447 	int			 ok = -1;
448 
449 	memset(&kv, 0, sizeof(kv));
450 	memset(out, 0, sizeof(*out));
451 
452 	if ((item = cbor_new_definite_map(3)) == NULL) {
453 		fido_log_debug("%s: cbor_new_definite_map", __func__);
454 		goto fail;
455 	}
456 
457 	if ((kv[0].key = cbor_build_string("alg")) == NULL ||
458 	    (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL ||
459 	    !cbor_map_add(item, kv[0])) {
460 		fido_log_debug("%s: alg", __func__);
461 		goto fail;
462 	}
463 
464 	if ((kv[1].key = cbor_build_string("sig")) == NULL ||
465 	    (kv[1].value = fido_blob_encode(sig)) == NULL ||
466 	    !cbor_map_add(item, kv[1])) {
467 		fido_log_debug("%s: sig", __func__);
468 		goto fail;
469 	}
470 
471 	if ((kv[2].key = cbor_build_string("x5c")) == NULL ||
472 	    (kv[2].value = cbor_new_definite_array(1)) == NULL ||
473 	    (x5c_cbor = fido_blob_encode(x5c)) == NULL ||
474 	    !cbor_array_push(kv[2].value, x5c_cbor) ||
475 	    !cbor_map_add(item, kv[2])) {
476 		fido_log_debug("%s: x5c", __func__);
477 		goto fail;
478 	}
479 
480 	if ((out->len = cbor_serialize_alloc(item, &out->ptr,
481 	    &alloc_len)) == 0) {
482 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
483 		goto fail;
484 	}
485 
486 	ok = 0;
487 fail:
488 	if (item != NULL)
489 		cbor_decref(&item);
490 	if (x5c_cbor != NULL)
491 		cbor_decref(&x5c_cbor);
492 
493 	for (size_t i = 0; i < nitems(kv); i++) {
494 		if (kv[i].key)
495 			cbor_decref(&kv[i].key);
496 		if (kv[i].value)
497 			cbor_decref(&kv[i].value);
498 	}
499 
500 	return (ok);
501 }
502 
503 static int
504 encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
505     const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out)
506 {
507 	fido_authdata_t	 	 authdata;
508 	fido_attcred_raw_t	 attcred_raw;
509 	fido_blob_t		 pk_blob;
510 	fido_blob_t		 authdata_blob;
511 	cbor_item_t		*authdata_cbor = NULL;
512 	unsigned char		*ptr;
513 	size_t			 len;
514 	size_t			 alloc_len;
515 	int			 ok = -1;
516 
517 	memset(&pk_blob, 0, sizeof(pk_blob));
518 	memset(&authdata, 0, sizeof(authdata));
519 	memset(&authdata_blob, 0, sizeof(authdata_blob));
520 	memset(out, 0, sizeof(*out));
521 
522 	if (rp_id == NULL) {
523 		fido_log_debug("%s: NULL rp_id", __func__);
524 		goto fail;
525 	}
526 
527 	if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) {
528 		fido_log_debug("%s: cbor_blob_from_ec_point", __func__);
529 		goto fail;
530 	}
531 
532 	if (SHA256((const void *)rp_id, strlen(rp_id),
533 	    authdata.rp_id_hash) != authdata.rp_id_hash) {
534 		fido_log_debug("%s: sha256", __func__);
535 		goto fail;
536 	}
537 
538 	authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT);
539 	authdata.sigcount = 0;
540 
541 	memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
542 	attcred_raw.id_len = htobe16(kh_len);
543 
544 	len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
545 	    kh_len + pk_blob.len;
546 	ptr = authdata_blob.ptr = calloc(1, authdata_blob.len);
547 
548 	fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len);
549 
550 	if (authdata_blob.ptr == NULL)
551 		goto fail;
552 
553 	if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 ||
554 	    fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 ||
555 	    fido_buf_write(&ptr, &len, kh, kh_len) < 0 ||
556 	    fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) {
557 		fido_log_debug("%s: fido_buf_write", __func__);
558 		goto fail;
559 	}
560 
561 	if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) {
562 		fido_log_debug("%s: fido_blob_encode", __func__);
563 		goto fail;
564 	}
565 
566 	if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr,
567 	    &alloc_len)) == 0) {
568 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
569 		goto fail;
570 	}
571 
572 	ok = 0;
573 fail:
574 	if (authdata_cbor)
575 		cbor_decref(&authdata_cbor);
576 
577 	fido_blob_reset(&pk_blob);
578 	fido_blob_reset(&authdata_blob);
579 
580 	return (ok);
581 }
582 
583 static int
584 parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
585 {
586 	fido_blob_t	 x5c;
587 	fido_blob_t	 sig;
588 	fido_blob_t	 ad;
589 	fido_blob_t	 stmt;
590 	uint8_t		 dummy;
591 	uint8_t		 pubkey[65];
592 	uint8_t		 kh_len = 0;
593 	uint8_t		*kh = NULL;
594 	int		 r;
595 
596 	memset(&x5c, 0, sizeof(x5c));
597 	memset(&sig, 0, sizeof(sig));
598 	memset(&ad, 0, sizeof(ad));
599 	memset(&stmt, 0, sizeof(stmt));
600 	r = FIDO_ERR_RX;
601 
602 	/* status word */
603 	if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
604 		fido_log_debug("%s: unexpected sw", __func__);
605 		goto fail;
606 	}
607 
608 	len -= 2;
609 
610 	/* reserved byte */
611 	if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 ||
612 	    dummy != 0x05) {
613 		fido_log_debug("%s: reserved byte", __func__);
614 		goto fail;
615 	}
616 
617 	/* pubkey + key handle */
618 	if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 ||
619 	    fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 ||
620 	    (kh = calloc(1, kh_len)) == NULL ||
621 	    fido_buf_read(&reply, &len, kh, kh_len) < 0) {
622 		fido_log_debug("%s: fido_buf_read", __func__);
623 		goto fail;
624 	}
625 
626 	/* x5c + sig */
627 	if (x5c_get(&x5c, &reply, &len) < 0 ||
628 	    sig_get(&sig, &reply, &len) < 0) {
629 		fido_log_debug("%s: x5c || sig", __func__);
630 		goto fail;
631 	}
632 
633 	/* attstmt */
634 	if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) {
635 		fido_log_debug("%s: encode_cred_attstmt", __func__);
636 		goto fail;
637 	}
638 
639 	/* authdata */
640 	if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
641 	    sizeof(pubkey), &ad) < 0) {
642 		fido_log_debug("%s: encode_cred_authdata", __func__);
643 		goto fail;
644 	}
645 
646 	if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
647 	    fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
648 	    fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) {
649 		fido_log_debug("%s: fido_cred_set", __func__);
650 		r = FIDO_ERR_INTERNAL;
651 		goto fail;
652 	}
653 
654 	r = FIDO_OK;
655 fail:
656 	freezero(kh, kh_len);
657 	fido_blob_reset(&x5c);
658 	fido_blob_reset(&sig);
659 	fido_blob_reset(&ad);
660 	fido_blob_reset(&stmt);
661 
662 	return (r);
663 }
664 
665 int
666 u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms)
667 {
668 	iso7816_apdu_t	*apdu = NULL;
669 	unsigned char	 rp_id_hash[SHA256_DIGEST_LENGTH];
670 	unsigned char	*reply = NULL;
671 	int		 reply_len;
672 	int		 found;
673 	int		 r;
674 
675 	if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
676 		fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
677 		    cred->uv);
678 		return (FIDO_ERR_UNSUPPORTED_OPTION);
679 	}
680 
681 	if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL ||
682 	    cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) {
683 		fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__,
684 		    cred->type, (void *)cred->cdh.ptr, cred->cdh.len);
685 		return (FIDO_ERR_INVALID_ARGUMENT);
686 	}
687 
688 	for (size_t i = 0; i < cred->excl.len; i++) {
689 		if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i],
690 		    &found, ms)) != FIDO_OK) {
691 			fido_log_debug("%s: key_lookup", __func__);
692 			return (r);
693 		}
694 		if (found) {
695 			if ((r = send_dummy_register(dev, ms)) != FIDO_OK) {
696 				fido_log_debug("%s: send_dummy_register",
697 				    __func__);
698 				return (r);
699 			}
700 			return (FIDO_ERR_CREDENTIAL_EXCLUDED);
701 		}
702 	}
703 
704 	memset(&rp_id_hash, 0, sizeof(rp_id_hash));
705 
706 	if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id),
707 	    rp_id_hash) != rp_id_hash) {
708 		fido_log_debug("%s: sha256", __func__);
709 		return (FIDO_ERR_INTERNAL);
710 	}
711 
712 	if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
713 	    SHA256_DIGEST_LENGTH)) == NULL ||
714 	    iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 ||
715 	    iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
716 		fido_log_debug("%s: iso7816", __func__);
717 		r = FIDO_ERR_INTERNAL;
718 		goto fail;
719 	}
720 
721 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
722 		fido_log_debug("%s: malloc", __func__);
723 		r = FIDO_ERR_INTERNAL;
724 		goto fail;
725 	}
726 
727 	do {
728 		if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
729 		    iso7816_len(apdu), ms) < 0) {
730 			fido_log_debug("%s: fido_tx", __func__);
731 			r = FIDO_ERR_TX;
732 			goto fail;
733 		}
734 		if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
735 		    FIDO_MAXMSG, ms)) < 2) {
736 			fido_log_debug("%s: fido_rx", __func__);
737 			r = FIDO_ERR_RX;
738 			goto fail;
739 		}
740 		if (delay_ms(U2F_PACE_MS, ms) != 0) {
741 			fido_log_debug("%s: delay_ms", __func__);
742 			r = FIDO_ERR_RX;
743 			goto fail;
744 		}
745 	} while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
746 
747 	if ((r = parse_register_reply(cred, reply,
748 	    (size_t)reply_len)) != FIDO_OK) {
749 		fido_log_debug("%s: parse_register_reply", __func__);
750 		goto fail;
751 	}
752 fail:
753 	iso7816_free(&apdu);
754 	freezero(reply, FIDO_MAXMSG);
755 
756 	return (r);
757 }
758 
759 static int
760 u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
761     fido_assert_t *fa, size_t idx, int *ms)
762 {
763 	fido_blob_t	sig;
764 	fido_blob_t	ad;
765 	int		found;
766 	int		r;
767 
768 	memset(&sig, 0, sizeof(sig));
769 	memset(&ad, 0, sizeof(ad));
770 
771 	if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) {
772 		fido_log_debug("%s: key_lookup", __func__);
773 		goto fail;
774 	}
775 
776 	if (!found) {
777 		fido_log_debug("%s: not found", __func__);
778 		r = FIDO_ERR_CREDENTIAL_EXCLUDED;
779 		goto fail;
780 	}
781 
782 	if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) {
783 		fido_log_debug("%s: fido_blob_set", __func__);
784 		r = FIDO_ERR_INTERNAL;
785 		goto fail;
786 	}
787 
788 	if (fa->up == FIDO_OPT_FALSE) {
789 		fido_log_debug("%s: checking for key existence only", __func__);
790 		r = FIDO_ERR_USER_PRESENCE_REQUIRED;
791 		goto fail;
792 	}
793 
794 	if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad,
795 	    ms)) != FIDO_OK) {
796 		fido_log_debug("%s: do_auth", __func__);
797 		goto fail;
798 	}
799 
800 	if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK ||
801 	    fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) {
802 		fido_log_debug("%s: fido_assert_set", __func__);
803 		r = FIDO_ERR_INTERNAL;
804 		goto fail;
805 	}
806 
807 	r = FIDO_OK;
808 fail:
809 	fido_blob_reset(&sig);
810 	fido_blob_reset(&ad);
811 
812 	return (r);
813 }
814 
815 int
816 u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms)
817 {
818 	size_t	nfound = 0;
819 	size_t	nauth_ok = 0;
820 	int	r;
821 
822 	if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
823 		fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv,
824 		    (void *)fa->allow_list.ptr);
825 		return (FIDO_ERR_UNSUPPORTED_OPTION);
826 	}
827 
828 	if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) {
829 		fido_log_debug("%s: fido_assert_set_count", __func__);
830 		return (r);
831 	}
832 
833 	for (size_t i = 0; i < fa->allow_list.len; i++) {
834 		switch ((r = u2f_authenticate_single(dev,
835 		    &fa->allow_list.ptr[i], fa, nfound, ms))) {
836 		case FIDO_OK:
837 			nauth_ok++;
838 			FALLTHROUGH
839 		case FIDO_ERR_USER_PRESENCE_REQUIRED:
840 			nfound++;
841 			break;
842 		default:
843 			if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) {
844 				fido_log_debug("%s: u2f_authenticate_single",
845 				    __func__);
846 				return (r);
847 			}
848 			/* ignore credentials that don't exist */
849 		}
850 	}
851 
852 	fa->stmt_len = nfound;
853 
854 	if (nfound == 0)
855 		return (FIDO_ERR_NO_CREDENTIALS);
856 	if (nauth_ok == 0)
857 		return (FIDO_ERR_USER_PRESENCE_REQUIRED);
858 
859 	return (FIDO_OK);
860 }
861 
862 int
863 u2f_get_touch_begin(fido_dev_t *dev, int *ms)
864 {
865 	iso7816_apdu_t	*apdu = NULL;
866 	const char	*clientdata = FIDO_DUMMY_CLIENTDATA;
867 	const char	*rp_id = FIDO_DUMMY_RP_ID;
868 	unsigned char	*reply = NULL;
869 	unsigned char	 clientdata_hash[SHA256_DIGEST_LENGTH];
870 	unsigned char	 rp_id_hash[SHA256_DIGEST_LENGTH];
871 	int		 r;
872 
873 	memset(&clientdata_hash, 0, sizeof(clientdata_hash));
874 	memset(&rp_id_hash, 0, sizeof(rp_id_hash));
875 
876 	if (SHA256((const void *)clientdata, strlen(clientdata),
877 	    clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
878 	    strlen(rp_id), rp_id_hash) != rp_id_hash) {
879 		fido_log_debug("%s: sha256", __func__);
880 		return (FIDO_ERR_INTERNAL);
881 	}
882 
883 	if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
884 	    SHA256_DIGEST_LENGTH)) == NULL ||
885 	    iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
886 	    iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
887 		fido_log_debug("%s: iso7816", __func__);
888 		r = FIDO_ERR_INTERNAL;
889 		goto fail;
890 	}
891 
892 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
893 		fido_log_debug("%s: malloc", __func__);
894 		r =  FIDO_ERR_INTERNAL;
895 		goto fail;
896 	}
897 
898 	if (dev->attr.flags & FIDO_CAP_WINK) {
899 		fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms);
900 		fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms);
901 	}
902 
903 	if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
904 	    iso7816_len(apdu), ms) < 0) {
905 		fido_log_debug("%s: fido_tx", __func__);
906 		r = FIDO_ERR_TX;
907 		goto fail;
908 	}
909 
910 	r = FIDO_OK;
911 fail:
912 	iso7816_free(&apdu);
913 	freezero(reply, FIDO_MAXMSG);
914 
915 	return (r);
916 }
917 
918 int
919 u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms)
920 {
921 	unsigned char	*reply;
922 	int		 reply_len;
923 	int		 r;
924 
925 	if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
926 		fido_log_debug("%s: malloc", __func__);
927 		r =  FIDO_ERR_INTERNAL;
928 		goto out;
929 	}
930 
931 	if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG,
932 	    ms)) < 2) {
933 		fido_log_debug("%s: fido_rx", __func__);
934 		r = FIDO_OK; /* ignore */
935 		goto out;
936 	}
937 
938 	switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
939 	case SW_CONDITIONS_NOT_SATISFIED:
940 		if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) {
941 			fido_log_debug("%s: u2f_get_touch_begin", __func__);
942 			goto out;
943 		}
944 		*touched = 0;
945 		break;
946 	case SW_NO_ERROR:
947 		*touched = 1;
948 		break;
949 	default:
950 		fido_log_debug("%s: unexpected sw", __func__);
951 		r = FIDO_ERR_RX;
952 		goto out;
953 	}
954 
955 	r = FIDO_OK;
956 out:
957 	freezero(reply, FIDO_MAXMSG);
958 
959 	return (r);
960 }
961