xref: /freebsd-src/contrib/libfido2/src/cred.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <openssl/sha.h>
90afa8e06SEd Maste #include <openssl/x509.h>
100afa8e06SEd Maste 
110afa8e06SEd Maste #include "fido.h"
120afa8e06SEd Maste #include "fido/es256.h"
130afa8e06SEd Maste 
14f540a430SEd Maste #ifndef FIDO_MAXMSG_CRED
15f540a430SEd Maste #define FIDO_MAXMSG_CRED	4096
16f540a430SEd Maste #endif
17f540a430SEd Maste 
180afa8e06SEd Maste static int
parse_makecred_reply(const cbor_item_t * key,const cbor_item_t * val,void * arg)190afa8e06SEd Maste parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
200afa8e06SEd Maste {
210afa8e06SEd Maste 	fido_cred_t *cred = arg;
220afa8e06SEd Maste 
230afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
240afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8) {
250afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
260afa8e06SEd Maste 		return (0); /* ignore */
270afa8e06SEd Maste 	}
280afa8e06SEd Maste 
290afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
300afa8e06SEd Maste 	case 1: /* fmt */
310afa8e06SEd Maste 		return (cbor_decode_fmt(val, &cred->fmt));
320afa8e06SEd Maste 	case 2: /* authdata */
330afa8e06SEd Maste 		if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
340afa8e06SEd Maste 			fido_log_debug("%s: fido_blob_decode", __func__);
350afa8e06SEd Maste 			return (-1);
360afa8e06SEd Maste 		}
370afa8e06SEd Maste 		return (cbor_decode_cred_authdata(val, cred->type,
380afa8e06SEd Maste 		    &cred->authdata_cbor, &cred->authdata, &cred->attcred,
390afa8e06SEd Maste 		    &cred->authdata_ext));
400afa8e06SEd Maste 	case 3: /* attestation statement */
410afa8e06SEd Maste 		return (cbor_decode_attstmt(val, &cred->attstmt));
420afa8e06SEd Maste 	case 5: /* large blob key */
430afa8e06SEd Maste 		return (fido_blob_decode(val, &cred->largeblob_key));
440afa8e06SEd Maste 	default: /* ignore */
450afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
460afa8e06SEd Maste 		return (0);
470afa8e06SEd Maste 	}
480afa8e06SEd Maste }
490afa8e06SEd Maste 
500afa8e06SEd Maste static int
fido_dev_make_cred_tx(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)51f540a430SEd Maste fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
52f540a430SEd Maste     int *ms)
530afa8e06SEd Maste {
540afa8e06SEd Maste 	fido_blob_t	 f;
550afa8e06SEd Maste 	fido_blob_t	*ecdh = NULL;
560afa8e06SEd Maste 	fido_opt_t	 uv = cred->uv;
570afa8e06SEd Maste 	es256_pk_t	*pk = NULL;
580afa8e06SEd Maste 	cbor_item_t	*argv[9];
590afa8e06SEd Maste 	const uint8_t	 cmd = CTAP_CBOR_MAKECRED;
600afa8e06SEd Maste 	int		 r;
610afa8e06SEd Maste 
620afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
630afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
640afa8e06SEd Maste 
650afa8e06SEd Maste 	if (cred->cdh.ptr == NULL || cred->type == 0) {
660afa8e06SEd Maste 		fido_log_debug("%s: cdh=%p, type=%d", __func__,
670afa8e06SEd Maste 		    (void *)cred->cdh.ptr, cred->type);
680afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
690afa8e06SEd Maste 		goto fail;
700afa8e06SEd Maste 	}
710afa8e06SEd Maste 
720afa8e06SEd Maste 	if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
730afa8e06SEd Maste 	    (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
740afa8e06SEd Maste 	    (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
750afa8e06SEd Maste 	    (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
760afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
770afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
780afa8e06SEd Maste 		goto fail;
790afa8e06SEd Maste 	}
800afa8e06SEd Maste 
810afa8e06SEd Maste 	/* excluded credentials */
820afa8e06SEd Maste 	if (cred->excl.len)
830afa8e06SEd Maste 		if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
840afa8e06SEd Maste 			fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
850afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
860afa8e06SEd Maste 			goto fail;
870afa8e06SEd Maste 		}
880afa8e06SEd Maste 
890afa8e06SEd Maste 	/* extensions */
900afa8e06SEd Maste 	if (cred->ext.mask)
910afa8e06SEd Maste 		if ((argv[5] = cbor_encode_cred_ext(&cred->ext,
920afa8e06SEd Maste 		    &cred->blob)) == NULL) {
930afa8e06SEd Maste 			fido_log_debug("%s: cbor_encode_cred_ext", __func__);
940afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
950afa8e06SEd Maste 			goto fail;
960afa8e06SEd Maste 		}
970afa8e06SEd Maste 
980afa8e06SEd Maste 	/* user verification */
990afa8e06SEd Maste 	if (pin != NULL || (uv == FIDO_OPT_TRUE &&
1000afa8e06SEd Maste 	    fido_dev_supports_permissions(dev))) {
101f540a430SEd Maste 		if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
1020afa8e06SEd Maste 			fido_log_debug("%s: fido_do_ecdh", __func__);
1030afa8e06SEd Maste 			goto fail;
1040afa8e06SEd Maste 		}
1050afa8e06SEd Maste 		if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
106f540a430SEd Maste 		    pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
1070afa8e06SEd Maste 			fido_log_debug("%s: cbor_add_uv_params", __func__);
1080afa8e06SEd Maste 			goto fail;
1090afa8e06SEd Maste 		}
1100afa8e06SEd Maste 		uv = FIDO_OPT_OMIT;
1110afa8e06SEd Maste 	}
1120afa8e06SEd Maste 
1130afa8e06SEd Maste 	/* options */
1140afa8e06SEd Maste 	if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
1150afa8e06SEd Maste 		if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) {
1160afa8e06SEd Maste 			fido_log_debug("%s: cbor_encode_cred_opt", __func__);
1170afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
1180afa8e06SEd Maste 			goto fail;
1190afa8e06SEd Maste 		}
1200afa8e06SEd Maste 
1210afa8e06SEd Maste 	/* framing and transmission */
1220afa8e06SEd Maste 	if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
123f540a430SEd Maste 	    fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
1240afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
1250afa8e06SEd Maste 		r = FIDO_ERR_TX;
1260afa8e06SEd Maste 		goto fail;
1270afa8e06SEd Maste 	}
1280afa8e06SEd Maste 
1290afa8e06SEd Maste 	r = FIDO_OK;
1300afa8e06SEd Maste fail:
1310afa8e06SEd Maste 	es256_pk_free(&pk);
1320afa8e06SEd Maste 	fido_blob_free(&ecdh);
1330afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
1340afa8e06SEd Maste 	free(f.ptr);
1350afa8e06SEd Maste 
1360afa8e06SEd Maste 	return (r);
1370afa8e06SEd Maste }
1380afa8e06SEd Maste 
1390afa8e06SEd Maste static int
fido_dev_make_cred_rx(fido_dev_t * dev,fido_cred_t * cred,int * ms)140f540a430SEd Maste fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
1410afa8e06SEd Maste {
142f540a430SEd Maste 	unsigned char	*reply;
1430afa8e06SEd Maste 	int		 reply_len;
1440afa8e06SEd Maste 	int		 r;
1450afa8e06SEd Maste 
1460afa8e06SEd Maste 	fido_cred_reset_rx(cred);
1470afa8e06SEd Maste 
148f540a430SEd Maste 	if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
149f540a430SEd Maste 		r = FIDO_ERR_INTERNAL;
150f540a430SEd Maste 		goto fail;
151f540a430SEd Maste 	}
152f540a430SEd Maste 
153f540a430SEd Maste 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
1540afa8e06SEd Maste 	    ms)) < 0) {
1550afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
156f540a430SEd Maste 		r = FIDO_ERR_RX;
157f540a430SEd Maste 		goto fail;
1580afa8e06SEd Maste 	}
1590afa8e06SEd Maste 
1600afa8e06SEd Maste 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
1610afa8e06SEd Maste 	    parse_makecred_reply)) != FIDO_OK) {
1620afa8e06SEd Maste 		fido_log_debug("%s: parse_makecred_reply", __func__);
163f540a430SEd Maste 		goto fail;
1640afa8e06SEd Maste 	}
1650afa8e06SEd Maste 
1660afa8e06SEd Maste 	if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
1670afa8e06SEd Maste 	    fido_blob_is_empty(&cred->attcred.id)) {
168f540a430SEd Maste 		r = FIDO_ERR_INVALID_CBOR;
169f540a430SEd Maste 		goto fail;
1700afa8e06SEd Maste 	}
1710afa8e06SEd Maste 
172f540a430SEd Maste 	r = FIDO_OK;
173f540a430SEd Maste fail:
174f540a430SEd Maste 	free(reply);
175f540a430SEd Maste 
176f540a430SEd Maste 	if (r != FIDO_OK)
177f540a430SEd Maste 		fido_cred_reset_rx(cred);
178f540a430SEd Maste 
179f540a430SEd Maste 	return (r);
1800afa8e06SEd Maste }
1810afa8e06SEd Maste 
1820afa8e06SEd Maste static int
fido_dev_make_cred_wait(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)1830afa8e06SEd Maste fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
184f540a430SEd Maste     int *ms)
1850afa8e06SEd Maste {
1860afa8e06SEd Maste 	int  r;
1870afa8e06SEd Maste 
188f540a430SEd Maste 	if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
1890afa8e06SEd Maste 	    (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
1900afa8e06SEd Maste 		return (r);
1910afa8e06SEd Maste 
1920afa8e06SEd Maste 	return (FIDO_OK);
1930afa8e06SEd Maste }
1940afa8e06SEd Maste 
1950afa8e06SEd Maste int
fido_dev_make_cred(fido_dev_t * dev,fido_cred_t * cred,const char * pin)1960afa8e06SEd Maste fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
1970afa8e06SEd Maste {
198f540a430SEd Maste 	int ms = dev->timeout_ms;
199f540a430SEd Maste 
2000afa8e06SEd Maste #ifdef USE_WINHELLO
2010afa8e06SEd Maste 	if (dev->flags & FIDO_DEV_WINHELLO)
202f540a430SEd Maste 		return (fido_winhello_make_cred(dev, cred, pin, ms));
2030afa8e06SEd Maste #endif
2040afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) == false) {
2050afa8e06SEd Maste 		if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
2060afa8e06SEd Maste 		    cred->ext.mask != 0)
2070afa8e06SEd Maste 			return (FIDO_ERR_UNSUPPORTED_OPTION);
208f540a430SEd Maste 		return (u2f_register(dev, cred, &ms));
2090afa8e06SEd Maste 	}
2100afa8e06SEd Maste 
211f540a430SEd Maste 	return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
2120afa8e06SEd Maste }
2130afa8e06SEd Maste 
2140afa8e06SEd Maste static int
check_extensions(const fido_cred_ext_t * authdata_ext,const fido_cred_ext_t * ext)2150afa8e06SEd Maste check_extensions(const fido_cred_ext_t *authdata_ext,
2160afa8e06SEd Maste     const fido_cred_ext_t *ext)
2170afa8e06SEd Maste {
2180afa8e06SEd Maste 	fido_cred_ext_t	 tmp;
2190afa8e06SEd Maste 
2200afa8e06SEd Maste 	/* XXX: largeBlobKey is not part of the extensions map */
2210afa8e06SEd Maste 	memcpy(&tmp, ext, sizeof(tmp));
2220afa8e06SEd Maste 	tmp.mask &= ~FIDO_EXT_LARGEBLOB_KEY;
2230afa8e06SEd Maste 
2240afa8e06SEd Maste 	return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext)));
2250afa8e06SEd Maste }
2260afa8e06SEd Maste 
2270afa8e06SEd Maste int
fido_check_rp_id(const char * id,const unsigned char * obtained_hash)2280afa8e06SEd Maste fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
2290afa8e06SEd Maste {
2300afa8e06SEd Maste 	unsigned char expected_hash[SHA256_DIGEST_LENGTH];
2310afa8e06SEd Maste 
2320afa8e06SEd Maste 	explicit_bzero(expected_hash, sizeof(expected_hash));
2330afa8e06SEd Maste 
2340afa8e06SEd Maste 	if (SHA256((const unsigned char *)id, strlen(id),
2350afa8e06SEd Maste 	    expected_hash) != expected_hash) {
2360afa8e06SEd Maste 		fido_log_debug("%s: sha256", __func__);
2370afa8e06SEd Maste 		return (-1);
2380afa8e06SEd Maste 	}
2390afa8e06SEd Maste 
2400afa8e06SEd Maste 	return (timingsafe_bcmp(expected_hash, obtained_hash,
2410afa8e06SEd Maste 	    SHA256_DIGEST_LENGTH));
2420afa8e06SEd Maste }
2430afa8e06SEd Maste 
2440afa8e06SEd Maste static int
get_signed_hash_u2f(fido_blob_t * dgst,const unsigned char * rp_id,size_t rp_id_len,const fido_blob_t * clientdata,const fido_blob_t * id,const es256_pk_t * pk)2450afa8e06SEd Maste get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
2460afa8e06SEd Maste     size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
2470afa8e06SEd Maste     const es256_pk_t *pk)
2480afa8e06SEd Maste {
2490afa8e06SEd Maste 	const uint8_t	 zero = 0;
2500afa8e06SEd Maste 	const uint8_t	 four = 4; /* uncompressed point */
251f540a430SEd Maste 	const EVP_MD	*md = NULL;
252f540a430SEd Maste 	EVP_MD_CTX	*ctx = NULL;
2530afa8e06SEd Maste 	int		 ok = -1;
2540afa8e06SEd Maste 
255*2ccfa855SEd Maste 	if (dgst->len < SHA256_DIGEST_LENGTH ||
256f540a430SEd Maste 	    (md = EVP_sha256()) == NULL ||
257f540a430SEd Maste 	    (ctx = EVP_MD_CTX_new()) == NULL ||
258f540a430SEd Maste 	    EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
259f540a430SEd Maste 	    EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
260f540a430SEd Maste 	    EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
261f540a430SEd Maste 	    EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
262f540a430SEd Maste 	    EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
263f540a430SEd Maste 	    EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
264f540a430SEd Maste 	    EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
265f540a430SEd Maste 	    EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
266f540a430SEd Maste 	    EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
267f540a430SEd Maste 		fido_log_debug("%s: sha256", __func__);
2680afa8e06SEd Maste 		goto fail;
2690afa8e06SEd Maste 	}
270*2ccfa855SEd Maste 	dgst->len = SHA256_DIGEST_LENGTH;
2710afa8e06SEd Maste 
2720afa8e06SEd Maste 	ok = 0;
2730afa8e06SEd Maste fail:
274f540a430SEd Maste 	EVP_MD_CTX_free(ctx);
275f540a430SEd Maste 
276f540a430SEd Maste 	return (ok);
277f540a430SEd Maste }
278f540a430SEd Maste 
279f540a430SEd Maste static int
verify_attstmt(const fido_blob_t * dgst,const fido_attstmt_t * attstmt)280f540a430SEd Maste verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
281f540a430SEd Maste {
282f540a430SEd Maste 	BIO		*rawcert = NULL;
283f540a430SEd Maste 	X509		*cert = NULL;
284f540a430SEd Maste 	EVP_PKEY	*pkey = NULL;
285f540a430SEd Maste 	int		 ok = -1;
286f540a430SEd Maste 
287f540a430SEd Maste 	/* openssl needs ints */
288f540a430SEd Maste 	if (attstmt->x5c.len > INT_MAX) {
289f540a430SEd Maste 		fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
290f540a430SEd Maste 		return (-1);
291f540a430SEd Maste 	}
292f540a430SEd Maste 
293f540a430SEd Maste 	/* fetch key from x509 */
294f540a430SEd Maste 	if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
295f540a430SEd Maste 	    (int)attstmt->x5c.len)) == NULL ||
296f540a430SEd Maste 	    (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
297f540a430SEd Maste 	    (pkey = X509_get_pubkey(cert)) == NULL) {
298f540a430SEd Maste 		fido_log_debug("%s: x509 key", __func__);
299f540a430SEd Maste 		goto fail;
300f540a430SEd Maste 	}
301f540a430SEd Maste 
302f540a430SEd Maste 	switch (attstmt->alg) {
303f540a430SEd Maste 	case COSE_UNSPEC:
304f540a430SEd Maste 	case COSE_ES256:
305f540a430SEd Maste 		ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
306f540a430SEd Maste 		break;
307*2ccfa855SEd Maste 	case COSE_ES384:
308*2ccfa855SEd Maste 		ok = es384_verify_sig(dgst, pkey, &attstmt->sig);
309*2ccfa855SEd Maste 		break;
310f540a430SEd Maste 	case COSE_RS256:
311f540a430SEd Maste 		ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
312f540a430SEd Maste 		break;
313f540a430SEd Maste 	case COSE_RS1:
314f540a430SEd Maste 		ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
315f540a430SEd Maste 		break;
316f540a430SEd Maste 	case COSE_EDDSA:
317f540a430SEd Maste 		ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
318f540a430SEd Maste 		break;
319f540a430SEd Maste 	default:
320f540a430SEd Maste 		fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
321f540a430SEd Maste 		break;
322f540a430SEd Maste 	}
323f540a430SEd Maste 
324f540a430SEd Maste fail:
3250afa8e06SEd Maste 	BIO_free(rawcert);
3260afa8e06SEd Maste 	X509_free(cert);
3270afa8e06SEd Maste 	EVP_PKEY_free(pkey);
3280afa8e06SEd Maste 
3290afa8e06SEd Maste 	return (ok);
3300afa8e06SEd Maste }
3310afa8e06SEd Maste 
3320afa8e06SEd Maste int
fido_cred_verify(const fido_cred_t * cred)3330afa8e06SEd Maste fido_cred_verify(const fido_cred_t *cred)
3340afa8e06SEd Maste {
335*2ccfa855SEd Maste 	unsigned char	buf[1024]; /* XXX */
3360afa8e06SEd Maste 	fido_blob_t	dgst;
337*2ccfa855SEd Maste 	int		cose_alg;
3380afa8e06SEd Maste 	int		r;
3390afa8e06SEd Maste 
3400afa8e06SEd Maste 	dgst.ptr = buf;
3410afa8e06SEd Maste 	dgst.len = sizeof(buf);
3420afa8e06SEd Maste 
3430afa8e06SEd Maste 	/* do we have everything we need? */
3440afa8e06SEd Maste 	if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
3450afa8e06SEd Maste 	    cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
3460afa8e06SEd Maste 	    cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
3470afa8e06SEd Maste 	    cred->rp.id == NULL) {
3480afa8e06SEd Maste 		fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
3490afa8e06SEd Maste 		    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
3500afa8e06SEd Maste 		    (void *)cred->authdata_cbor.ptr,
3510afa8e06SEd Maste 		    (void *)cred->attstmt.x5c.ptr,
3520afa8e06SEd Maste 		    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
3530afa8e06SEd Maste 		    (void *)cred->attcred.id.ptr, cred->rp.id);
3540afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
3550afa8e06SEd Maste 		goto out;
3560afa8e06SEd Maste 	}
3570afa8e06SEd Maste 
3580afa8e06SEd Maste 	if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
3590afa8e06SEd Maste 		fido_log_debug("%s: fido_check_rp_id", __func__);
3600afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
3610afa8e06SEd Maste 		goto out;
3620afa8e06SEd Maste 	}
3630afa8e06SEd Maste 
3640afa8e06SEd Maste 	if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
3650afa8e06SEd Maste 	    cred->uv) < 0) {
3660afa8e06SEd Maste 		fido_log_debug("%s: fido_check_flags", __func__);
3670afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
3680afa8e06SEd Maste 		goto out;
3690afa8e06SEd Maste 	}
3700afa8e06SEd Maste 
3710afa8e06SEd Maste 	if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
3720afa8e06SEd Maste 		fido_log_debug("%s: check_extensions", __func__);
3730afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
3740afa8e06SEd Maste 		goto out;
3750afa8e06SEd Maste 	}
3760afa8e06SEd Maste 
377*2ccfa855SEd Maste 	if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC)
378*2ccfa855SEd Maste 		cose_alg = COSE_ES256; /* backwards compat */
379*2ccfa855SEd Maste 
3800afa8e06SEd Maste 	if (!strcmp(cred->fmt, "packed")) {
381*2ccfa855SEd Maste 		if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh,
3820afa8e06SEd Maste 		    &cred->authdata_cbor) < 0) {
3830afa8e06SEd Maste 			fido_log_debug("%s: fido_get_signed_hash", __func__);
3840afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
3850afa8e06SEd Maste 			goto out;
3860afa8e06SEd Maste 		}
3870afa8e06SEd Maste 	} else if (!strcmp(cred->fmt, "fido-u2f")) {
3880afa8e06SEd Maste 		if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
3890afa8e06SEd Maste 		    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
3900afa8e06SEd Maste 		    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
3910afa8e06SEd Maste 			fido_log_debug("%s: get_signed_hash_u2f", __func__);
3920afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
3930afa8e06SEd Maste 			goto out;
3940afa8e06SEd Maste 		}
395f540a430SEd Maste 	} else if (!strcmp(cred->fmt, "tpm")) {
396f540a430SEd Maste 		if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
397f540a430SEd Maste 		    &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
398f540a430SEd Maste 			fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
399f540a430SEd Maste 			r = FIDO_ERR_INTERNAL;
400f540a430SEd Maste 			goto out;
401f540a430SEd Maste 		}
4020afa8e06SEd Maste 	} else {
4030afa8e06SEd Maste 		fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
4040afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
4050afa8e06SEd Maste 		goto out;
4060afa8e06SEd Maste 	}
4070afa8e06SEd Maste 
408f540a430SEd Maste 	if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
409f540a430SEd Maste 		fido_log_debug("%s: verify_attstmt", __func__);
4100afa8e06SEd Maste 		r = FIDO_ERR_INVALID_SIG;
4110afa8e06SEd Maste 		goto out;
4120afa8e06SEd Maste 	}
4130afa8e06SEd Maste 
4140afa8e06SEd Maste 	r = FIDO_OK;
4150afa8e06SEd Maste out:
4160afa8e06SEd Maste 	explicit_bzero(buf, sizeof(buf));
4170afa8e06SEd Maste 
4180afa8e06SEd Maste 	return (r);
4190afa8e06SEd Maste }
4200afa8e06SEd Maste 
4210afa8e06SEd Maste int
fido_cred_verify_self(const fido_cred_t * cred)4220afa8e06SEd Maste fido_cred_verify_self(const fido_cred_t *cred)
4230afa8e06SEd Maste {
4240afa8e06SEd Maste 	unsigned char	buf[1024]; /* XXX */
4250afa8e06SEd Maste 	fido_blob_t	dgst;
4260afa8e06SEd Maste 	int		ok = -1;
4270afa8e06SEd Maste 	int		r;
4280afa8e06SEd Maste 
4290afa8e06SEd Maste 	dgst.ptr = buf;
4300afa8e06SEd Maste 	dgst.len = sizeof(buf);
4310afa8e06SEd Maste 
4320afa8e06SEd Maste 	/* do we have everything we need? */
4330afa8e06SEd Maste 	if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
4340afa8e06SEd Maste 	    cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
4350afa8e06SEd Maste 	    cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
4360afa8e06SEd Maste 	    cred->rp.id == NULL) {
4370afa8e06SEd Maste 		fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
4380afa8e06SEd Maste 		    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
4390afa8e06SEd Maste 		    (void *)cred->authdata_cbor.ptr,
4400afa8e06SEd Maste 		    (void *)cred->attstmt.x5c.ptr,
4410afa8e06SEd Maste 		    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
4420afa8e06SEd Maste 		    (void *)cred->attcred.id.ptr, cred->rp.id);
4430afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
4440afa8e06SEd Maste 		goto out;
4450afa8e06SEd Maste 	}
4460afa8e06SEd Maste 
4470afa8e06SEd Maste 	if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
4480afa8e06SEd Maste 		fido_log_debug("%s: fido_check_rp_id", __func__);
4490afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
4500afa8e06SEd Maste 		goto out;
4510afa8e06SEd Maste 	}
4520afa8e06SEd Maste 
4530afa8e06SEd Maste 	if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
4540afa8e06SEd Maste 	    cred->uv) < 0) {
4550afa8e06SEd Maste 		fido_log_debug("%s: fido_check_flags", __func__);
4560afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
4570afa8e06SEd Maste 		goto out;
4580afa8e06SEd Maste 	}
4590afa8e06SEd Maste 
4600afa8e06SEd Maste 	if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
4610afa8e06SEd Maste 		fido_log_debug("%s: check_extensions", __func__);
4620afa8e06SEd Maste 		r = FIDO_ERR_INVALID_PARAM;
4630afa8e06SEd Maste 		goto out;
4640afa8e06SEd Maste 	}
4650afa8e06SEd Maste 
4660afa8e06SEd Maste 	if (!strcmp(cred->fmt, "packed")) {
4670afa8e06SEd Maste 		if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
4680afa8e06SEd Maste 		    &cred->authdata_cbor) < 0) {
4690afa8e06SEd Maste 			fido_log_debug("%s: fido_get_signed_hash", __func__);
4700afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
4710afa8e06SEd Maste 			goto out;
4720afa8e06SEd Maste 		}
4730afa8e06SEd Maste 	} else if (!strcmp(cred->fmt, "fido-u2f")) {
4740afa8e06SEd Maste 		if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
4750afa8e06SEd Maste 		    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
4760afa8e06SEd Maste 		    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
4770afa8e06SEd Maste 			fido_log_debug("%s: get_signed_hash_u2f", __func__);
4780afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
4790afa8e06SEd Maste 			goto out;
4800afa8e06SEd Maste 		}
4810afa8e06SEd Maste 	} else {
4820afa8e06SEd Maste 		fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
4830afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
4840afa8e06SEd Maste 		goto out;
4850afa8e06SEd Maste 	}
4860afa8e06SEd Maste 
4870afa8e06SEd Maste 	switch (cred->attcred.type) {
4880afa8e06SEd Maste 	case COSE_ES256:
489f540a430SEd Maste 		ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
4900afa8e06SEd Maste 		    &cred->attstmt.sig);
4910afa8e06SEd Maste 		break;
492*2ccfa855SEd Maste 	case COSE_ES384:
493*2ccfa855SEd Maste 		ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384,
494*2ccfa855SEd Maste 		    &cred->attstmt.sig);
495*2ccfa855SEd Maste 		break;
4960afa8e06SEd Maste 	case COSE_RS256:
497f540a430SEd Maste 		ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
4980afa8e06SEd Maste 		    &cred->attstmt.sig);
4990afa8e06SEd Maste 		break;
5000afa8e06SEd Maste 	case COSE_EDDSA:
501f540a430SEd Maste 		ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
5020afa8e06SEd Maste 		    &cred->attstmt.sig);
5030afa8e06SEd Maste 		break;
5040afa8e06SEd Maste 	default:
5050afa8e06SEd Maste 		fido_log_debug("%s: unsupported cose_alg %d", __func__,
5060afa8e06SEd Maste 		    cred->attcred.type);
5070afa8e06SEd Maste 		r = FIDO_ERR_UNSUPPORTED_OPTION;
5080afa8e06SEd Maste 		goto out;
5090afa8e06SEd Maste 	}
5100afa8e06SEd Maste 
5110afa8e06SEd Maste 	if (ok < 0)
5120afa8e06SEd Maste 		r = FIDO_ERR_INVALID_SIG;
5130afa8e06SEd Maste 	else
5140afa8e06SEd Maste 		r = FIDO_OK;
5150afa8e06SEd Maste 
5160afa8e06SEd Maste out:
5170afa8e06SEd Maste 	explicit_bzero(buf, sizeof(buf));
5180afa8e06SEd Maste 
5190afa8e06SEd Maste 	return (r);
5200afa8e06SEd Maste }
5210afa8e06SEd Maste 
5220afa8e06SEd Maste fido_cred_t *
fido_cred_new(void)5230afa8e06SEd Maste fido_cred_new(void)
5240afa8e06SEd Maste {
5250afa8e06SEd Maste 	return (calloc(1, sizeof(fido_cred_t)));
5260afa8e06SEd Maste }
5270afa8e06SEd Maste 
5280afa8e06SEd Maste static void
fido_cred_clean_authdata(fido_cred_t * cred)5290afa8e06SEd Maste fido_cred_clean_authdata(fido_cred_t *cred)
5300afa8e06SEd Maste {
5310afa8e06SEd Maste 	fido_blob_reset(&cred->authdata_cbor);
5320afa8e06SEd Maste 	fido_blob_reset(&cred->authdata_raw);
5330afa8e06SEd Maste 	fido_blob_reset(&cred->attcred.id);
5340afa8e06SEd Maste 
5350afa8e06SEd Maste 	memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
5360afa8e06SEd Maste 	memset(&cred->authdata, 0, sizeof(cred->authdata));
5370afa8e06SEd Maste 	memset(&cred->attcred, 0, sizeof(cred->attcred));
5380afa8e06SEd Maste }
5390afa8e06SEd Maste 
540f540a430SEd Maste static void
fido_cred_clean_attstmt(fido_attstmt_t * attstmt)541f540a430SEd Maste fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
542f540a430SEd Maste {
543f540a430SEd Maste 	fido_blob_reset(&attstmt->certinfo);
544f540a430SEd Maste 	fido_blob_reset(&attstmt->pubarea);
545f540a430SEd Maste 	fido_blob_reset(&attstmt->cbor);
546f540a430SEd Maste 	fido_blob_reset(&attstmt->x5c);
547f540a430SEd Maste 	fido_blob_reset(&attstmt->sig);
548f540a430SEd Maste 
549f540a430SEd Maste 	memset(attstmt, 0, sizeof(*attstmt));
550f540a430SEd Maste }
551f540a430SEd Maste 
5520afa8e06SEd Maste void
fido_cred_reset_tx(fido_cred_t * cred)5530afa8e06SEd Maste fido_cred_reset_tx(fido_cred_t *cred)
5540afa8e06SEd Maste {
5550afa8e06SEd Maste 	fido_blob_reset(&cred->cd);
5560afa8e06SEd Maste 	fido_blob_reset(&cred->cdh);
5570afa8e06SEd Maste 	fido_blob_reset(&cred->user.id);
5580afa8e06SEd Maste 	fido_blob_reset(&cred->blob);
5590afa8e06SEd Maste 
5600afa8e06SEd Maste 	free(cred->rp.id);
5610afa8e06SEd Maste 	free(cred->rp.name);
5620afa8e06SEd Maste 	free(cred->user.icon);
5630afa8e06SEd Maste 	free(cred->user.name);
5640afa8e06SEd Maste 	free(cred->user.display_name);
565*2ccfa855SEd Maste 	fido_cred_empty_exclude_list(cred);
5660afa8e06SEd Maste 
5670afa8e06SEd Maste 	memset(&cred->rp, 0, sizeof(cred->rp));
5680afa8e06SEd Maste 	memset(&cred->user, 0, sizeof(cred->user));
5690afa8e06SEd Maste 	memset(&cred->ext, 0, sizeof(cred->ext));
5700afa8e06SEd Maste 
5710afa8e06SEd Maste 	cred->type = 0;
5720afa8e06SEd Maste 	cred->rk = FIDO_OPT_OMIT;
5730afa8e06SEd Maste 	cred->uv = FIDO_OPT_OMIT;
5740afa8e06SEd Maste }
5750afa8e06SEd Maste 
5760afa8e06SEd Maste void
fido_cred_reset_rx(fido_cred_t * cred)5770afa8e06SEd Maste fido_cred_reset_rx(fido_cred_t *cred)
5780afa8e06SEd Maste {
5790afa8e06SEd Maste 	free(cred->fmt);
5800afa8e06SEd Maste 	cred->fmt = NULL;
5810afa8e06SEd Maste 	fido_cred_clean_authdata(cred);
582f540a430SEd Maste 	fido_cred_clean_attstmt(&cred->attstmt);
5830afa8e06SEd Maste 	fido_blob_reset(&cred->largeblob_key);
5840afa8e06SEd Maste }
5850afa8e06SEd Maste 
5860afa8e06SEd Maste void
fido_cred_free(fido_cred_t ** cred_p)5870afa8e06SEd Maste fido_cred_free(fido_cred_t **cred_p)
5880afa8e06SEd Maste {
5890afa8e06SEd Maste 	fido_cred_t *cred;
5900afa8e06SEd Maste 
5910afa8e06SEd Maste 	if (cred_p == NULL || (cred = *cred_p) == NULL)
5920afa8e06SEd Maste 		return;
5930afa8e06SEd Maste 	fido_cred_reset_tx(cred);
5940afa8e06SEd Maste 	fido_cred_reset_rx(cred);
5950afa8e06SEd Maste 	free(cred);
5960afa8e06SEd Maste 	*cred_p = NULL;
5970afa8e06SEd Maste }
5980afa8e06SEd Maste 
5990afa8e06SEd Maste int
fido_cred_set_authdata(fido_cred_t * cred,const unsigned char * ptr,size_t len)6000afa8e06SEd Maste fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
6010afa8e06SEd Maste {
6020afa8e06SEd Maste 	cbor_item_t		*item = NULL;
6030afa8e06SEd Maste 	struct cbor_load_result	 cbor;
6040afa8e06SEd Maste 	int			 r = FIDO_ERR_INVALID_ARGUMENT;
6050afa8e06SEd Maste 
6060afa8e06SEd Maste 	fido_cred_clean_authdata(cred);
6070afa8e06SEd Maste 
6080afa8e06SEd Maste 	if (ptr == NULL || len == 0)
6090afa8e06SEd Maste 		goto fail;
6100afa8e06SEd Maste 
6110afa8e06SEd Maste 	if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
6120afa8e06SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
6130afa8e06SEd Maste 		goto fail;
6140afa8e06SEd Maste 	}
6150afa8e06SEd Maste 
6160afa8e06SEd Maste 	if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
6170afa8e06SEd Maste 		fido_log_debug("%s: fido_blob_decode", __func__);
6180afa8e06SEd Maste 		goto fail;
6190afa8e06SEd Maste 	}
6200afa8e06SEd Maste 
6210afa8e06SEd Maste 	if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
6220afa8e06SEd Maste 	    &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
6230afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
6240afa8e06SEd Maste 		goto fail;
6250afa8e06SEd Maste 	}
6260afa8e06SEd Maste 
6270afa8e06SEd Maste 	r = FIDO_OK;
6280afa8e06SEd Maste fail:
6290afa8e06SEd Maste 	if (item != NULL)
6300afa8e06SEd Maste 		cbor_decref(&item);
6310afa8e06SEd Maste 
6320afa8e06SEd Maste 	if (r != FIDO_OK)
6330afa8e06SEd Maste 		fido_cred_clean_authdata(cred);
6340afa8e06SEd Maste 
6350afa8e06SEd Maste 	return (r);
6360afa8e06SEd Maste }
6370afa8e06SEd Maste 
6380afa8e06SEd Maste int
fido_cred_set_authdata_raw(fido_cred_t * cred,const unsigned char * ptr,size_t len)6390afa8e06SEd Maste fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
6400afa8e06SEd Maste     size_t len)
6410afa8e06SEd Maste {
6420afa8e06SEd Maste 	cbor_item_t	*item = NULL;
6430afa8e06SEd Maste 	int		 r = FIDO_ERR_INVALID_ARGUMENT;
6440afa8e06SEd Maste 
6450afa8e06SEd Maste 	fido_cred_clean_authdata(cred);
6460afa8e06SEd Maste 
6470afa8e06SEd Maste 	if (ptr == NULL || len == 0)
6480afa8e06SEd Maste 		goto fail;
6490afa8e06SEd Maste 
6500afa8e06SEd Maste 	if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
6510afa8e06SEd Maste 		fido_log_debug("%s: fido_blob_set", __func__);
6520afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
6530afa8e06SEd Maste 		goto fail;
6540afa8e06SEd Maste 	}
6550afa8e06SEd Maste 
6560afa8e06SEd Maste 	if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
6570afa8e06SEd Maste 		fido_log_debug("%s: cbor_build_bytestring", __func__);
6580afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
6590afa8e06SEd Maste 		goto fail;
6600afa8e06SEd Maste 	}
6610afa8e06SEd Maste 
6620afa8e06SEd Maste 	if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
6630afa8e06SEd Maste 	    &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
6640afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
6650afa8e06SEd Maste 		goto fail;
6660afa8e06SEd Maste 	}
6670afa8e06SEd Maste 
6680afa8e06SEd Maste 	r = FIDO_OK;
6690afa8e06SEd Maste fail:
6700afa8e06SEd Maste 	if (item != NULL)
6710afa8e06SEd Maste 		cbor_decref(&item);
6720afa8e06SEd Maste 
6730afa8e06SEd Maste 	if (r != FIDO_OK)
6740afa8e06SEd Maste 		fido_cred_clean_authdata(cred);
6750afa8e06SEd Maste 
6760afa8e06SEd Maste 	return (r);
6770afa8e06SEd Maste }
6780afa8e06SEd Maste 
6790afa8e06SEd Maste int
fido_cred_set_id(fido_cred_t * cred,const unsigned char * ptr,size_t len)6800afa8e06SEd Maste fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len)
6810afa8e06SEd Maste {
6820afa8e06SEd Maste 	if (fido_blob_set(&cred->attcred.id, ptr, len) < 0)
6830afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
6840afa8e06SEd Maste 
6850afa8e06SEd Maste 	return (FIDO_OK);
6860afa8e06SEd Maste }
6870afa8e06SEd Maste 
6880afa8e06SEd Maste int
fido_cred_set_x509(fido_cred_t * cred,const unsigned char * ptr,size_t len)6890afa8e06SEd Maste fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
6900afa8e06SEd Maste {
6910afa8e06SEd Maste 	if (fido_blob_set(&cred->attstmt.x5c, ptr, len) < 0)
6920afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
6930afa8e06SEd Maste 
6940afa8e06SEd Maste 	return (FIDO_OK);
6950afa8e06SEd Maste }
6960afa8e06SEd Maste 
6970afa8e06SEd Maste int
fido_cred_set_sig(fido_cred_t * cred,const unsigned char * ptr,size_t len)6980afa8e06SEd Maste fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
6990afa8e06SEd Maste {
7000afa8e06SEd Maste 	if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0)
7010afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
7020afa8e06SEd Maste 
7030afa8e06SEd Maste 	return (FIDO_OK);
7040afa8e06SEd Maste }
7050afa8e06SEd Maste 
7060afa8e06SEd Maste int
fido_cred_set_attstmt(fido_cred_t * cred,const unsigned char * ptr,size_t len)707f540a430SEd Maste fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
708f540a430SEd Maste {
709f540a430SEd Maste 	cbor_item_t		*item = NULL;
710f540a430SEd Maste 	struct cbor_load_result	 cbor;
711f540a430SEd Maste 	int			 r = FIDO_ERR_INVALID_ARGUMENT;
712f540a430SEd Maste 
713f540a430SEd Maste 	fido_cred_clean_attstmt(&cred->attstmt);
714f540a430SEd Maste 
715f540a430SEd Maste 	if (ptr == NULL || len == 0)
716f540a430SEd Maste 		goto fail;
717f540a430SEd Maste 
718f540a430SEd Maste 	if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
719f540a430SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
720f540a430SEd Maste 		goto fail;
721f540a430SEd Maste 	}
722f540a430SEd Maste 
723f540a430SEd Maste 	if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
724f540a430SEd Maste 		fido_log_debug("%s: cbor_decode_attstmt", __func__);
725f540a430SEd Maste 		goto fail;
726f540a430SEd Maste 	}
727f540a430SEd Maste 
728f540a430SEd Maste 	r = FIDO_OK;
729f540a430SEd Maste fail:
730f540a430SEd Maste 	if (item != NULL)
731f540a430SEd Maste 		cbor_decref(&item);
732f540a430SEd Maste 
733f540a430SEd Maste 	if (r != FIDO_OK)
734f540a430SEd Maste 		fido_cred_clean_attstmt(&cred->attstmt);
735f540a430SEd Maste 
736f540a430SEd Maste 	return (r);
737f540a430SEd Maste }
738f540a430SEd Maste 
739f540a430SEd Maste int
fido_cred_exclude(fido_cred_t * cred,const unsigned char * id_ptr,size_t id_len)7400afa8e06SEd Maste fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
7410afa8e06SEd Maste {
7420afa8e06SEd Maste 	fido_blob_t id_blob;
7430afa8e06SEd Maste 	fido_blob_t *list_ptr;
7440afa8e06SEd Maste 
7450afa8e06SEd Maste 	memset(&id_blob, 0, sizeof(id_blob));
7460afa8e06SEd Maste 
7470afa8e06SEd Maste 	if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
7480afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
7490afa8e06SEd Maste 
7500afa8e06SEd Maste 	if (cred->excl.len == SIZE_MAX) {
7510afa8e06SEd Maste 		free(id_blob.ptr);
7520afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
7530afa8e06SEd Maste 	}
7540afa8e06SEd Maste 
7550afa8e06SEd Maste 	if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
7560afa8e06SEd Maste 	    cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
7570afa8e06SEd Maste 		free(id_blob.ptr);
7580afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
7590afa8e06SEd Maste 	}
7600afa8e06SEd Maste 
7610afa8e06SEd Maste 	list_ptr[cred->excl.len++] = id_blob;
7620afa8e06SEd Maste 	cred->excl.ptr = list_ptr;
7630afa8e06SEd Maste 
7640afa8e06SEd Maste 	return (FIDO_OK);
7650afa8e06SEd Maste }
7660afa8e06SEd Maste 
7670afa8e06SEd Maste int
fido_cred_empty_exclude_list(fido_cred_t * cred)768*2ccfa855SEd Maste fido_cred_empty_exclude_list(fido_cred_t *cred)
769*2ccfa855SEd Maste {
770*2ccfa855SEd Maste 	fido_free_blob_array(&cred->excl);
771*2ccfa855SEd Maste 	memset(&cred->excl, 0, sizeof(cred->excl));
772*2ccfa855SEd Maste 
773*2ccfa855SEd Maste 	return (FIDO_OK);
774*2ccfa855SEd Maste }
775*2ccfa855SEd Maste 
776*2ccfa855SEd Maste int
fido_cred_set_clientdata(fido_cred_t * cred,const unsigned char * data,size_t data_len)7770afa8e06SEd Maste fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
7780afa8e06SEd Maste     size_t data_len)
7790afa8e06SEd Maste {
7800afa8e06SEd Maste 	if (!fido_blob_is_empty(&cred->cdh) ||
7810afa8e06SEd Maste 	    fido_blob_set(&cred->cd, data, data_len) < 0) {
7820afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
7830afa8e06SEd Maste 	}
7840afa8e06SEd Maste 	if (fido_sha256(&cred->cdh, data, data_len) < 0) {
7850afa8e06SEd Maste 		fido_blob_reset(&cred->cd);
7860afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
7870afa8e06SEd Maste 	}
7880afa8e06SEd Maste 
7890afa8e06SEd Maste 	return (FIDO_OK);
7900afa8e06SEd Maste }
7910afa8e06SEd Maste 
7920afa8e06SEd Maste int
fido_cred_set_clientdata_hash(fido_cred_t * cred,const unsigned char * hash,size_t hash_len)7930afa8e06SEd Maste fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
7940afa8e06SEd Maste     size_t hash_len)
7950afa8e06SEd Maste {
7960afa8e06SEd Maste 	if (!fido_blob_is_empty(&cred->cd) ||
7970afa8e06SEd Maste 	    fido_blob_set(&cred->cdh, hash, hash_len) < 0)
7980afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
7990afa8e06SEd Maste 
8000afa8e06SEd Maste 	return (FIDO_OK);
8010afa8e06SEd Maste }
8020afa8e06SEd Maste 
8030afa8e06SEd Maste int
fido_cred_set_rp(fido_cred_t * cred,const char * id,const char * name)8040afa8e06SEd Maste fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
8050afa8e06SEd Maste {
8060afa8e06SEd Maste 	fido_rp_t *rp = &cred->rp;
8070afa8e06SEd Maste 
8080afa8e06SEd Maste 	if (rp->id != NULL) {
8090afa8e06SEd Maste 		free(rp->id);
8100afa8e06SEd Maste 		rp->id = NULL;
8110afa8e06SEd Maste 	}
8120afa8e06SEd Maste 	if (rp->name != NULL) {
8130afa8e06SEd Maste 		free(rp->name);
8140afa8e06SEd Maste 		rp->name = NULL;
8150afa8e06SEd Maste 	}
8160afa8e06SEd Maste 
8170afa8e06SEd Maste 	if (id != NULL && (rp->id = strdup(id)) == NULL)
8180afa8e06SEd Maste 		goto fail;
8190afa8e06SEd Maste 	if (name != NULL && (rp->name = strdup(name)) == NULL)
8200afa8e06SEd Maste 		goto fail;
8210afa8e06SEd Maste 
8220afa8e06SEd Maste 	return (FIDO_OK);
8230afa8e06SEd Maste fail:
8240afa8e06SEd Maste 	free(rp->id);
8250afa8e06SEd Maste 	free(rp->name);
8260afa8e06SEd Maste 	rp->id = NULL;
8270afa8e06SEd Maste 	rp->name = NULL;
8280afa8e06SEd Maste 
8290afa8e06SEd Maste 	return (FIDO_ERR_INTERNAL);
8300afa8e06SEd Maste }
8310afa8e06SEd Maste 
8320afa8e06SEd Maste int
fido_cred_set_user(fido_cred_t * cred,const unsigned char * user_id,size_t user_id_len,const char * name,const char * display_name,const char * icon)8330afa8e06SEd Maste fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
8340afa8e06SEd Maste     size_t user_id_len, const char *name, const char *display_name,
8350afa8e06SEd Maste     const char *icon)
8360afa8e06SEd Maste {
8370afa8e06SEd Maste 	fido_user_t *up = &cred->user;
8380afa8e06SEd Maste 
8390afa8e06SEd Maste 	if (up->id.ptr != NULL) {
8400afa8e06SEd Maste 		free(up->id.ptr);
8410afa8e06SEd Maste 		up->id.ptr = NULL;
8420afa8e06SEd Maste 		up->id.len = 0;
8430afa8e06SEd Maste 	}
8440afa8e06SEd Maste 	if (up->name != NULL) {
8450afa8e06SEd Maste 		free(up->name);
8460afa8e06SEd Maste 		up->name = NULL;
8470afa8e06SEd Maste 	}
8480afa8e06SEd Maste 	if (up->display_name != NULL) {
8490afa8e06SEd Maste 		free(up->display_name);
8500afa8e06SEd Maste 		up->display_name = NULL;
8510afa8e06SEd Maste 	}
8520afa8e06SEd Maste 	if (up->icon != NULL) {
8530afa8e06SEd Maste 		free(up->icon);
8540afa8e06SEd Maste 		up->icon = NULL;
8550afa8e06SEd Maste 	}
8560afa8e06SEd Maste 
8570afa8e06SEd Maste 	if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0)
8580afa8e06SEd Maste 		goto fail;
8590afa8e06SEd Maste 	if (name != NULL && (up->name = strdup(name)) == NULL)
8600afa8e06SEd Maste 		goto fail;
8610afa8e06SEd Maste 	if (display_name != NULL &&
8620afa8e06SEd Maste 	    (up->display_name = strdup(display_name)) == NULL)
8630afa8e06SEd Maste 		goto fail;
8640afa8e06SEd Maste 	if (icon != NULL && (up->icon = strdup(icon)) == NULL)
8650afa8e06SEd Maste 		goto fail;
8660afa8e06SEd Maste 
8670afa8e06SEd Maste 	return (FIDO_OK);
8680afa8e06SEd Maste fail:
8690afa8e06SEd Maste 	free(up->id.ptr);
8700afa8e06SEd Maste 	free(up->name);
8710afa8e06SEd Maste 	free(up->display_name);
8720afa8e06SEd Maste 	free(up->icon);
8730afa8e06SEd Maste 
8740afa8e06SEd Maste 	up->id.ptr = NULL;
8750afa8e06SEd Maste 	up->id.len = 0;
8760afa8e06SEd Maste 	up->name = NULL;
8770afa8e06SEd Maste 	up->display_name = NULL;
8780afa8e06SEd Maste 	up->icon = NULL;
8790afa8e06SEd Maste 
8800afa8e06SEd Maste 	return (FIDO_ERR_INTERNAL);
8810afa8e06SEd Maste }
8820afa8e06SEd Maste 
8830afa8e06SEd Maste int
fido_cred_set_extensions(fido_cred_t * cred,int ext)8840afa8e06SEd Maste fido_cred_set_extensions(fido_cred_t *cred, int ext)
8850afa8e06SEd Maste {
8860afa8e06SEd Maste 	if (ext == 0)
8870afa8e06SEd Maste 		cred->ext.mask = 0;
8880afa8e06SEd Maste 	else {
8890afa8e06SEd Maste 		if ((ext & FIDO_EXT_CRED_MASK) != ext)
8900afa8e06SEd Maste 			return (FIDO_ERR_INVALID_ARGUMENT);
8910afa8e06SEd Maste 		cred->ext.mask |= ext;
8920afa8e06SEd Maste 	}
8930afa8e06SEd Maste 
8940afa8e06SEd Maste 	return (FIDO_OK);
8950afa8e06SEd Maste }
8960afa8e06SEd Maste 
8970afa8e06SEd Maste int
fido_cred_set_options(fido_cred_t * cred,bool rk,bool uv)8980afa8e06SEd Maste fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
8990afa8e06SEd Maste {
9000afa8e06SEd Maste 	cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
9010afa8e06SEd Maste 	cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
9020afa8e06SEd Maste 
9030afa8e06SEd Maste 	return (FIDO_OK);
9040afa8e06SEd Maste }
9050afa8e06SEd Maste 
9060afa8e06SEd Maste int
fido_cred_set_rk(fido_cred_t * cred,fido_opt_t rk)9070afa8e06SEd Maste fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
9080afa8e06SEd Maste {
9090afa8e06SEd Maste 	cred->rk = rk;
9100afa8e06SEd Maste 
9110afa8e06SEd Maste 	return (FIDO_OK);
9120afa8e06SEd Maste }
9130afa8e06SEd Maste 
9140afa8e06SEd Maste int
fido_cred_set_uv(fido_cred_t * cred,fido_opt_t uv)9150afa8e06SEd Maste fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
9160afa8e06SEd Maste {
9170afa8e06SEd Maste 	cred->uv = uv;
9180afa8e06SEd Maste 
9190afa8e06SEd Maste 	return (FIDO_OK);
9200afa8e06SEd Maste }
9210afa8e06SEd Maste 
9220afa8e06SEd Maste int
fido_cred_set_prot(fido_cred_t * cred,int prot)9230afa8e06SEd Maste fido_cred_set_prot(fido_cred_t *cred, int prot)
9240afa8e06SEd Maste {
9250afa8e06SEd Maste 	if (prot == 0) {
9260afa8e06SEd Maste 		cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT;
9270afa8e06SEd Maste 		cred->ext.prot = 0;
9280afa8e06SEd Maste 	} else {
9290afa8e06SEd Maste 		if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
9300afa8e06SEd Maste 		    prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
9310afa8e06SEd Maste 		    prot != FIDO_CRED_PROT_UV_REQUIRED)
9320afa8e06SEd Maste 			return (FIDO_ERR_INVALID_ARGUMENT);
9330afa8e06SEd Maste 
9340afa8e06SEd Maste 		cred->ext.mask |= FIDO_EXT_CRED_PROTECT;
9350afa8e06SEd Maste 		cred->ext.prot = prot;
9360afa8e06SEd Maste 	}
9370afa8e06SEd Maste 
9380afa8e06SEd Maste 	return (FIDO_OK);
9390afa8e06SEd Maste }
9400afa8e06SEd Maste 
9410afa8e06SEd Maste int
fido_cred_set_pin_minlen(fido_cred_t * cred,size_t len)942f540a430SEd Maste fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
943f540a430SEd Maste {
944f540a430SEd Maste 	if (len == 0)
945f540a430SEd Maste 		cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
946f540a430SEd Maste 	else
947f540a430SEd Maste 		cred->ext.mask |= FIDO_EXT_MINPINLEN;
948f540a430SEd Maste 
949f540a430SEd Maste 	cred->ext.minpinlen = len;
950f540a430SEd Maste 
951f540a430SEd Maste 	return (FIDO_OK);
952f540a430SEd Maste }
953f540a430SEd Maste 
954f540a430SEd Maste int
fido_cred_set_blob(fido_cred_t * cred,const unsigned char * ptr,size_t len)9550afa8e06SEd Maste fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
9560afa8e06SEd Maste {
9570afa8e06SEd Maste 	if (ptr == NULL || len == 0)
9580afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
9590afa8e06SEd Maste 	if (fido_blob_set(&cred->blob, ptr, len) < 0)
9600afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
9610afa8e06SEd Maste 
9620afa8e06SEd Maste 	cred->ext.mask |= FIDO_EXT_CRED_BLOB;
9630afa8e06SEd Maste 
9640afa8e06SEd Maste 	return (FIDO_OK);
9650afa8e06SEd Maste }
9660afa8e06SEd Maste 
9670afa8e06SEd Maste int
fido_cred_set_fmt(fido_cred_t * cred,const char * fmt)9680afa8e06SEd Maste fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
9690afa8e06SEd Maste {
9700afa8e06SEd Maste 	free(cred->fmt);
9710afa8e06SEd Maste 	cred->fmt = NULL;
9720afa8e06SEd Maste 
9730afa8e06SEd Maste 	if (fmt == NULL)
9740afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
9750afa8e06SEd Maste 
9760afa8e06SEd Maste 	if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
977f540a430SEd Maste 	    strcmp(fmt, "none") && strcmp(fmt, "tpm"))
9780afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
9790afa8e06SEd Maste 
9800afa8e06SEd Maste 	if ((cred->fmt = strdup(fmt)) == NULL)
9810afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
9820afa8e06SEd Maste 
9830afa8e06SEd Maste 	return (FIDO_OK);
9840afa8e06SEd Maste }
9850afa8e06SEd Maste 
9860afa8e06SEd Maste int
fido_cred_set_type(fido_cred_t * cred,int cose_alg)9870afa8e06SEd Maste fido_cred_set_type(fido_cred_t *cred, int cose_alg)
9880afa8e06SEd Maste {
989*2ccfa855SEd Maste 	if (cred->type != 0)
990*2ccfa855SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
991*2ccfa855SEd Maste 	if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 &&
992*2ccfa855SEd Maste 	    cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA)
9930afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
9940afa8e06SEd Maste 
9950afa8e06SEd Maste 	cred->type = cose_alg;
9960afa8e06SEd Maste 
9970afa8e06SEd Maste 	return (FIDO_OK);
9980afa8e06SEd Maste }
9990afa8e06SEd Maste 
10000afa8e06SEd Maste int
fido_cred_type(const fido_cred_t * cred)10010afa8e06SEd Maste fido_cred_type(const fido_cred_t *cred)
10020afa8e06SEd Maste {
10030afa8e06SEd Maste 	return (cred->type);
10040afa8e06SEd Maste }
10050afa8e06SEd Maste 
10060afa8e06SEd Maste uint8_t
fido_cred_flags(const fido_cred_t * cred)10070afa8e06SEd Maste fido_cred_flags(const fido_cred_t *cred)
10080afa8e06SEd Maste {
10090afa8e06SEd Maste 	return (cred->authdata.flags);
10100afa8e06SEd Maste }
10110afa8e06SEd Maste 
10120afa8e06SEd Maste uint32_t
fido_cred_sigcount(const fido_cred_t * cred)10130afa8e06SEd Maste fido_cred_sigcount(const fido_cred_t *cred)
10140afa8e06SEd Maste {
10150afa8e06SEd Maste 	return (cred->authdata.sigcount);
10160afa8e06SEd Maste }
10170afa8e06SEd Maste 
10180afa8e06SEd Maste const unsigned char *
fido_cred_clientdata_hash_ptr(const fido_cred_t * cred)10190afa8e06SEd Maste fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
10200afa8e06SEd Maste {
10210afa8e06SEd Maste 	return (cred->cdh.ptr);
10220afa8e06SEd Maste }
10230afa8e06SEd Maste 
10240afa8e06SEd Maste size_t
fido_cred_clientdata_hash_len(const fido_cred_t * cred)10250afa8e06SEd Maste fido_cred_clientdata_hash_len(const fido_cred_t *cred)
10260afa8e06SEd Maste {
10270afa8e06SEd Maste 	return (cred->cdh.len);
10280afa8e06SEd Maste }
10290afa8e06SEd Maste 
10300afa8e06SEd Maste const unsigned char *
fido_cred_x5c_ptr(const fido_cred_t * cred)10310afa8e06SEd Maste fido_cred_x5c_ptr(const fido_cred_t *cred)
10320afa8e06SEd Maste {
10330afa8e06SEd Maste 	return (cred->attstmt.x5c.ptr);
10340afa8e06SEd Maste }
10350afa8e06SEd Maste 
10360afa8e06SEd Maste size_t
fido_cred_x5c_len(const fido_cred_t * cred)10370afa8e06SEd Maste fido_cred_x5c_len(const fido_cred_t *cred)
10380afa8e06SEd Maste {
10390afa8e06SEd Maste 	return (cred->attstmt.x5c.len);
10400afa8e06SEd Maste }
10410afa8e06SEd Maste 
10420afa8e06SEd Maste const unsigned char *
fido_cred_sig_ptr(const fido_cred_t * cred)10430afa8e06SEd Maste fido_cred_sig_ptr(const fido_cred_t *cred)
10440afa8e06SEd Maste {
10450afa8e06SEd Maste 	return (cred->attstmt.sig.ptr);
10460afa8e06SEd Maste }
10470afa8e06SEd Maste 
10480afa8e06SEd Maste size_t
fido_cred_sig_len(const fido_cred_t * cred)10490afa8e06SEd Maste fido_cred_sig_len(const fido_cred_t *cred)
10500afa8e06SEd Maste {
10510afa8e06SEd Maste 	return (cred->attstmt.sig.len);
10520afa8e06SEd Maste }
10530afa8e06SEd Maste 
10540afa8e06SEd Maste const unsigned char *
fido_cred_authdata_ptr(const fido_cred_t * cred)10550afa8e06SEd Maste fido_cred_authdata_ptr(const fido_cred_t *cred)
10560afa8e06SEd Maste {
10570afa8e06SEd Maste 	return (cred->authdata_cbor.ptr);
10580afa8e06SEd Maste }
10590afa8e06SEd Maste 
10600afa8e06SEd Maste size_t
fido_cred_authdata_len(const fido_cred_t * cred)10610afa8e06SEd Maste fido_cred_authdata_len(const fido_cred_t *cred)
10620afa8e06SEd Maste {
10630afa8e06SEd Maste 	return (cred->authdata_cbor.len);
10640afa8e06SEd Maste }
10650afa8e06SEd Maste 
10660afa8e06SEd Maste const unsigned char *
fido_cred_authdata_raw_ptr(const fido_cred_t * cred)10670afa8e06SEd Maste fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
10680afa8e06SEd Maste {
10690afa8e06SEd Maste 	return (cred->authdata_raw.ptr);
10700afa8e06SEd Maste }
10710afa8e06SEd Maste 
10720afa8e06SEd Maste size_t
fido_cred_authdata_raw_len(const fido_cred_t * cred)10730afa8e06SEd Maste fido_cred_authdata_raw_len(const fido_cred_t *cred)
10740afa8e06SEd Maste {
10750afa8e06SEd Maste 	return (cred->authdata_raw.len);
10760afa8e06SEd Maste }
10770afa8e06SEd Maste 
10780afa8e06SEd Maste const unsigned char *
fido_cred_attstmt_ptr(const fido_cred_t * cred)1079f540a430SEd Maste fido_cred_attstmt_ptr(const fido_cred_t *cred)
1080f540a430SEd Maste {
1081f540a430SEd Maste 	return (cred->attstmt.cbor.ptr);
1082f540a430SEd Maste }
1083f540a430SEd Maste 
1084f540a430SEd Maste size_t
fido_cred_attstmt_len(const fido_cred_t * cred)1085f540a430SEd Maste fido_cred_attstmt_len(const fido_cred_t *cred)
1086f540a430SEd Maste {
1087f540a430SEd Maste 	return (cred->attstmt.cbor.len);
1088f540a430SEd Maste }
1089f540a430SEd Maste 
1090f540a430SEd Maste const unsigned char *
fido_cred_pubkey_ptr(const fido_cred_t * cred)10910afa8e06SEd Maste fido_cred_pubkey_ptr(const fido_cred_t *cred)
10920afa8e06SEd Maste {
10930afa8e06SEd Maste 	const void *ptr;
10940afa8e06SEd Maste 
10950afa8e06SEd Maste 	switch (cred->attcred.type) {
10960afa8e06SEd Maste 	case COSE_ES256:
10970afa8e06SEd Maste 		ptr = &cred->attcred.pubkey.es256;
10980afa8e06SEd Maste 		break;
1099*2ccfa855SEd Maste 	case COSE_ES384:
1100*2ccfa855SEd Maste 		ptr = &cred->attcred.pubkey.es384;
1101*2ccfa855SEd Maste 		break;
11020afa8e06SEd Maste 	case COSE_RS256:
11030afa8e06SEd Maste 		ptr = &cred->attcred.pubkey.rs256;
11040afa8e06SEd Maste 		break;
11050afa8e06SEd Maste 	case COSE_EDDSA:
11060afa8e06SEd Maste 		ptr = &cred->attcred.pubkey.eddsa;
11070afa8e06SEd Maste 		break;
11080afa8e06SEd Maste 	default:
11090afa8e06SEd Maste 		ptr = NULL;
11100afa8e06SEd Maste 		break;
11110afa8e06SEd Maste 	}
11120afa8e06SEd Maste 
11130afa8e06SEd Maste 	return (ptr);
11140afa8e06SEd Maste }
11150afa8e06SEd Maste 
11160afa8e06SEd Maste size_t
fido_cred_pubkey_len(const fido_cred_t * cred)11170afa8e06SEd Maste fido_cred_pubkey_len(const fido_cred_t *cred)
11180afa8e06SEd Maste {
11190afa8e06SEd Maste 	size_t len;
11200afa8e06SEd Maste 
11210afa8e06SEd Maste 	switch (cred->attcred.type) {
11220afa8e06SEd Maste 	case COSE_ES256:
11230afa8e06SEd Maste 		len = sizeof(cred->attcred.pubkey.es256);
11240afa8e06SEd Maste 		break;
1125*2ccfa855SEd Maste 	case COSE_ES384:
1126*2ccfa855SEd Maste 		len = sizeof(cred->attcred.pubkey.es384);
1127*2ccfa855SEd Maste 		break;
11280afa8e06SEd Maste 	case COSE_RS256:
11290afa8e06SEd Maste 		len = sizeof(cred->attcred.pubkey.rs256);
11300afa8e06SEd Maste 		break;
11310afa8e06SEd Maste 	case COSE_EDDSA:
11320afa8e06SEd Maste 		len = sizeof(cred->attcred.pubkey.eddsa);
11330afa8e06SEd Maste 		break;
11340afa8e06SEd Maste 	default:
11350afa8e06SEd Maste 		len = 0;
11360afa8e06SEd Maste 		break;
11370afa8e06SEd Maste 	}
11380afa8e06SEd Maste 
11390afa8e06SEd Maste 	return (len);
11400afa8e06SEd Maste }
11410afa8e06SEd Maste 
11420afa8e06SEd Maste const unsigned char *
fido_cred_id_ptr(const fido_cred_t * cred)11430afa8e06SEd Maste fido_cred_id_ptr(const fido_cred_t *cred)
11440afa8e06SEd Maste {
11450afa8e06SEd Maste 	return (cred->attcred.id.ptr);
11460afa8e06SEd Maste }
11470afa8e06SEd Maste 
11480afa8e06SEd Maste size_t
fido_cred_id_len(const fido_cred_t * cred)11490afa8e06SEd Maste fido_cred_id_len(const fido_cred_t *cred)
11500afa8e06SEd Maste {
11510afa8e06SEd Maste 	return (cred->attcred.id.len);
11520afa8e06SEd Maste }
11530afa8e06SEd Maste 
11540afa8e06SEd Maste const unsigned char *
fido_cred_aaguid_ptr(const fido_cred_t * cred)11550afa8e06SEd Maste fido_cred_aaguid_ptr(const fido_cred_t *cred)
11560afa8e06SEd Maste {
11570afa8e06SEd Maste 	return (cred->attcred.aaguid);
11580afa8e06SEd Maste }
11590afa8e06SEd Maste 
11600afa8e06SEd Maste size_t
fido_cred_aaguid_len(const fido_cred_t * cred)11610afa8e06SEd Maste fido_cred_aaguid_len(const fido_cred_t *cred)
11620afa8e06SEd Maste {
11630afa8e06SEd Maste 	return (sizeof(cred->attcred.aaguid));
11640afa8e06SEd Maste }
11650afa8e06SEd Maste 
11660afa8e06SEd Maste int
fido_cred_prot(const fido_cred_t * cred)11670afa8e06SEd Maste fido_cred_prot(const fido_cred_t *cred)
11680afa8e06SEd Maste {
11690afa8e06SEd Maste 	return (cred->ext.prot);
11700afa8e06SEd Maste }
11710afa8e06SEd Maste 
1172f540a430SEd Maste size_t
fido_cred_pin_minlen(const fido_cred_t * cred)1173f540a430SEd Maste fido_cred_pin_minlen(const fido_cred_t *cred)
1174f540a430SEd Maste {
1175f540a430SEd Maste 	return (cred->ext.minpinlen);
1176f540a430SEd Maste }
1177f540a430SEd Maste 
11780afa8e06SEd Maste const char *
fido_cred_fmt(const fido_cred_t * cred)11790afa8e06SEd Maste fido_cred_fmt(const fido_cred_t *cred)
11800afa8e06SEd Maste {
11810afa8e06SEd Maste 	return (cred->fmt);
11820afa8e06SEd Maste }
11830afa8e06SEd Maste 
11840afa8e06SEd Maste const char *
fido_cred_rp_id(const fido_cred_t * cred)11850afa8e06SEd Maste fido_cred_rp_id(const fido_cred_t *cred)
11860afa8e06SEd Maste {
11870afa8e06SEd Maste 	return (cred->rp.id);
11880afa8e06SEd Maste }
11890afa8e06SEd Maste 
11900afa8e06SEd Maste const char *
fido_cred_rp_name(const fido_cred_t * cred)11910afa8e06SEd Maste fido_cred_rp_name(const fido_cred_t *cred)
11920afa8e06SEd Maste {
11930afa8e06SEd Maste 	return (cred->rp.name);
11940afa8e06SEd Maste }
11950afa8e06SEd Maste 
11960afa8e06SEd Maste const char *
fido_cred_user_name(const fido_cred_t * cred)11970afa8e06SEd Maste fido_cred_user_name(const fido_cred_t *cred)
11980afa8e06SEd Maste {
11990afa8e06SEd Maste 	return (cred->user.name);
12000afa8e06SEd Maste }
12010afa8e06SEd Maste 
12020afa8e06SEd Maste const char *
fido_cred_display_name(const fido_cred_t * cred)12030afa8e06SEd Maste fido_cred_display_name(const fido_cred_t *cred)
12040afa8e06SEd Maste {
12050afa8e06SEd Maste 	return (cred->user.display_name);
12060afa8e06SEd Maste }
12070afa8e06SEd Maste 
12080afa8e06SEd Maste const unsigned char *
fido_cred_user_id_ptr(const fido_cred_t * cred)12090afa8e06SEd Maste fido_cred_user_id_ptr(const fido_cred_t *cred)
12100afa8e06SEd Maste {
12110afa8e06SEd Maste 	return (cred->user.id.ptr);
12120afa8e06SEd Maste }
12130afa8e06SEd Maste 
12140afa8e06SEd Maste size_t
fido_cred_user_id_len(const fido_cred_t * cred)12150afa8e06SEd Maste fido_cred_user_id_len(const fido_cred_t *cred)
12160afa8e06SEd Maste {
12170afa8e06SEd Maste 	return (cred->user.id.len);
12180afa8e06SEd Maste }
12190afa8e06SEd Maste 
12200afa8e06SEd Maste const unsigned char *
fido_cred_largeblob_key_ptr(const fido_cred_t * cred)12210afa8e06SEd Maste fido_cred_largeblob_key_ptr(const fido_cred_t *cred)
12220afa8e06SEd Maste {
12230afa8e06SEd Maste 	return (cred->largeblob_key.ptr);
12240afa8e06SEd Maste }
12250afa8e06SEd Maste 
12260afa8e06SEd Maste size_t
fido_cred_largeblob_key_len(const fido_cred_t * cred)12270afa8e06SEd Maste fido_cred_largeblob_key_len(const fido_cred_t *cred)
12280afa8e06SEd Maste {
12290afa8e06SEd Maste 	return (cred->largeblob_key.len);
12300afa8e06SEd Maste }
1231