Home | History | Annotate | Line # | Download | only in src
      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