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