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