1d75efeb7Sdjm /*
2*ab19a69eSdjm * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
3d75efeb7Sdjm * Use of this source code is governed by a BSD-style
4d75efeb7Sdjm * license that can be found in the LICENSE file.
5d75efeb7Sdjm */
6d75efeb7Sdjm
7d75efeb7Sdjm #include <openssl/sha.h>
8d75efeb7Sdjm #include <openssl/x509.h>
9d75efeb7Sdjm
10d75efeb7Sdjm #include "fido.h"
11d75efeb7Sdjm #include "fido/es256.h"
12d75efeb7Sdjm
13*ab19a69eSdjm #ifndef FIDO_MAXMSG_CRED
14*ab19a69eSdjm #define FIDO_MAXMSG_CRED 4096
15*ab19a69eSdjm #endif
16*ab19a69eSdjm
17d75efeb7Sdjm static int
parse_makecred_reply(const cbor_item_t * key,const cbor_item_t * val,void * arg)18d75efeb7Sdjm parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
19d75efeb7Sdjm {
20d75efeb7Sdjm fido_cred_t *cred = arg;
21d75efeb7Sdjm
22d75efeb7Sdjm if (cbor_isa_uint(key) == false ||
23d75efeb7Sdjm cbor_int_get_width(key) != CBOR_INT_8) {
2432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
25d75efeb7Sdjm return (0); /* ignore */
26d75efeb7Sdjm }
27d75efeb7Sdjm
28d75efeb7Sdjm switch (cbor_get_uint8(key)) {
29d75efeb7Sdjm case 1: /* fmt */
3032a20e26Sdjm return (cbor_decode_fmt(val, &cred->fmt));
31d75efeb7Sdjm case 2: /* authdata */
32c4a807edSdjm if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
33c4a807edSdjm fido_log_debug("%s: fido_blob_decode", __func__);
34c4a807edSdjm return (-1);
35c4a807edSdjm }
3632a20e26Sdjm return (cbor_decode_cred_authdata(val, cred->type,
37d75efeb7Sdjm &cred->authdata_cbor, &cred->authdata, &cred->attcred,
38d75efeb7Sdjm &cred->authdata_ext));
39d75efeb7Sdjm case 3: /* attestation statement */
4032a20e26Sdjm return (cbor_decode_attstmt(val, &cred->attstmt));
41c4a807edSdjm case 5: /* large blob key */
42c4a807edSdjm return (fido_blob_decode(val, &cred->largeblob_key));
43d75efeb7Sdjm default: /* ignore */
4432a20e26Sdjm fido_log_debug("%s: cbor type", __func__);
45d75efeb7Sdjm return (0);
46d75efeb7Sdjm }
47d75efeb7Sdjm }
48d75efeb7Sdjm
49d75efeb7Sdjm static int
fido_dev_make_cred_tx(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)50*ab19a69eSdjm fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
51*ab19a69eSdjm int *ms)
52d75efeb7Sdjm {
53d75efeb7Sdjm fido_blob_t f;
54d75efeb7Sdjm fido_blob_t *ecdh = NULL;
55c4a807edSdjm fido_opt_t uv = cred->uv;
56d75efeb7Sdjm es256_pk_t *pk = NULL;
57d75efeb7Sdjm cbor_item_t *argv[9];
58c4a807edSdjm const uint8_t cmd = CTAP_CBOR_MAKECRED;
59d75efeb7Sdjm int r;
60d75efeb7Sdjm
61d75efeb7Sdjm memset(&f, 0, sizeof(f));
62d75efeb7Sdjm memset(argv, 0, sizeof(argv));
63d75efeb7Sdjm
64d75efeb7Sdjm if (cred->cdh.ptr == NULL || cred->type == 0) {
6532a20e26Sdjm fido_log_debug("%s: cdh=%p, type=%d", __func__,
66d75efeb7Sdjm (void *)cred->cdh.ptr, cred->type);
67d75efeb7Sdjm r = FIDO_ERR_INVALID_ARGUMENT;
68d75efeb7Sdjm goto fail;
69d75efeb7Sdjm }
70d75efeb7Sdjm
71d75efeb7Sdjm if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
7232a20e26Sdjm (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
7332a20e26Sdjm (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
7432a20e26Sdjm (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
7532a20e26Sdjm fido_log_debug("%s: cbor encode", __func__);
76d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
77d75efeb7Sdjm goto fail;
78d75efeb7Sdjm }
79d75efeb7Sdjm
80d75efeb7Sdjm /* excluded credentials */
81d75efeb7Sdjm if (cred->excl.len)
8232a20e26Sdjm if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
8332a20e26Sdjm fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
84d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
85d75efeb7Sdjm goto fail;
86d75efeb7Sdjm }
87d75efeb7Sdjm
88d75efeb7Sdjm /* extensions */
8932a20e26Sdjm if (cred->ext.mask)
90c4a807edSdjm if ((argv[5] = cbor_encode_cred_ext(&cred->ext,
91c4a807edSdjm &cred->blob)) == NULL) {
92c4a807edSdjm fido_log_debug("%s: cbor_encode_cred_ext", __func__);
93d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
94d75efeb7Sdjm goto fail;
95d75efeb7Sdjm }
96d75efeb7Sdjm
97c4a807edSdjm /* user verification */
98c4a807edSdjm if (pin != NULL || (uv == FIDO_OPT_TRUE &&
99c4a807edSdjm fido_dev_supports_permissions(dev))) {
100*ab19a69eSdjm if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
10132a20e26Sdjm fido_log_debug("%s: fido_do_ecdh", __func__);
102d75efeb7Sdjm goto fail;
103d75efeb7Sdjm }
104c4a807edSdjm if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
105*ab19a69eSdjm pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
106c4a807edSdjm fido_log_debug("%s: cbor_add_uv_params", __func__);
107d75efeb7Sdjm goto fail;
108d75efeb7Sdjm }
109c4a807edSdjm uv = FIDO_OPT_OMIT;
110c4a807edSdjm }
111c4a807edSdjm
112c4a807edSdjm /* options */
113c4a807edSdjm if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
114c4a807edSdjm if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) {
115c4a807edSdjm fido_log_debug("%s: cbor_encode_cred_opt", __func__);
116c4a807edSdjm r = FIDO_ERR_INTERNAL;
117c4a807edSdjm goto fail;
118d75efeb7Sdjm }
119d75efeb7Sdjm
120d75efeb7Sdjm /* framing and transmission */
121c4a807edSdjm if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
122*ab19a69eSdjm fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
12332a20e26Sdjm fido_log_debug("%s: fido_tx", __func__);
124d75efeb7Sdjm r = FIDO_ERR_TX;
125d75efeb7Sdjm goto fail;
126d75efeb7Sdjm }
127d75efeb7Sdjm
128d75efeb7Sdjm r = FIDO_OK;
129d75efeb7Sdjm fail:
130d75efeb7Sdjm es256_pk_free(&pk);
131d75efeb7Sdjm fido_blob_free(&ecdh);
132d75efeb7Sdjm cbor_vector_free(argv, nitems(argv));
133d75efeb7Sdjm free(f.ptr);
134d75efeb7Sdjm
135d75efeb7Sdjm return (r);
136d75efeb7Sdjm }
137d75efeb7Sdjm
138d75efeb7Sdjm static int
fido_dev_make_cred_rx(fido_dev_t * dev,fido_cred_t * cred,int * ms)139*ab19a69eSdjm fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
140d75efeb7Sdjm {
141*ab19a69eSdjm unsigned char *reply;
142d75efeb7Sdjm int reply_len;
143d75efeb7Sdjm int r;
144d75efeb7Sdjm
145d75efeb7Sdjm fido_cred_reset_rx(cred);
146d75efeb7Sdjm
147*ab19a69eSdjm if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
148*ab19a69eSdjm r = FIDO_ERR_INTERNAL;
149*ab19a69eSdjm goto fail;
150*ab19a69eSdjm }
151*ab19a69eSdjm
152*ab19a69eSdjm if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
15332a20e26Sdjm ms)) < 0) {
15432a20e26Sdjm fido_log_debug("%s: fido_rx", __func__);
155*ab19a69eSdjm r = FIDO_ERR_RX;
156*ab19a69eSdjm goto fail;
157d75efeb7Sdjm }
158d75efeb7Sdjm
15932a20e26Sdjm if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
160d75efeb7Sdjm parse_makecred_reply)) != FIDO_OK) {
16132a20e26Sdjm fido_log_debug("%s: parse_makecred_reply", __func__);
162*ab19a69eSdjm goto fail;
163d75efeb7Sdjm }
164d75efeb7Sdjm
165d75efeb7Sdjm if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
166c4a807edSdjm fido_blob_is_empty(&cred->attcred.id)) {
167*ab19a69eSdjm r = FIDO_ERR_INVALID_CBOR;
168*ab19a69eSdjm goto fail;
169d75efeb7Sdjm }
170d75efeb7Sdjm
171*ab19a69eSdjm r = FIDO_OK;
172*ab19a69eSdjm fail:
173*ab19a69eSdjm free(reply);
174*ab19a69eSdjm
175*ab19a69eSdjm if (r != FIDO_OK)
176*ab19a69eSdjm fido_cred_reset_rx(cred);
177*ab19a69eSdjm
178*ab19a69eSdjm return (r);
179d75efeb7Sdjm }
180d75efeb7Sdjm
181d75efeb7Sdjm static int
fido_dev_make_cred_wait(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)182c4a807edSdjm fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
183*ab19a69eSdjm int *ms)
184d75efeb7Sdjm {
185d75efeb7Sdjm int r;
186d75efeb7Sdjm
187*ab19a69eSdjm if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
188d75efeb7Sdjm (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
189d75efeb7Sdjm return (r);
190d75efeb7Sdjm
191d75efeb7Sdjm return (FIDO_OK);
192d75efeb7Sdjm }
193d75efeb7Sdjm
194d75efeb7Sdjm int
fido_dev_make_cred(fido_dev_t * dev,fido_cred_t * cred,const char * pin)195d75efeb7Sdjm fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
196d75efeb7Sdjm {
197*ab19a69eSdjm int ms = dev->timeout_ms;
198*ab19a69eSdjm
199c4a807edSdjm #ifdef USE_WINHELLO
200c4a807edSdjm if (dev->flags & FIDO_DEV_WINHELLO)
201*ab19a69eSdjm return (fido_winhello_make_cred(dev, cred, pin, ms));
202c4a807edSdjm #endif
203d75efeb7Sdjm if (fido_dev_is_fido2(dev) == false) {
20432a20e26Sdjm if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
20532a20e26Sdjm cred->ext.mask != 0)
206d75efeb7Sdjm return (FIDO_ERR_UNSUPPORTED_OPTION);
207*ab19a69eSdjm return (u2f_register(dev, cred, &ms));
208d75efeb7Sdjm }
209d75efeb7Sdjm
210*ab19a69eSdjm return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
211d75efeb7Sdjm }
212d75efeb7Sdjm
213d75efeb7Sdjm static int
check_extensions(const fido_cred_ext_t * authdata_ext,const fido_cred_ext_t * ext)214c4a807edSdjm check_extensions(const fido_cred_ext_t *authdata_ext,
215c4a807edSdjm const fido_cred_ext_t *ext)
216d75efeb7Sdjm {
217c4a807edSdjm fido_cred_ext_t tmp;
218c4a807edSdjm
219c4a807edSdjm /* XXX: largeBlobKey is not part of the extensions map */
220c4a807edSdjm memcpy(&tmp, ext, sizeof(tmp));
221c4a807edSdjm tmp.mask &= ~FIDO_EXT_LARGEBLOB_KEY;
222c4a807edSdjm
223c4a807edSdjm return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext)));
224d75efeb7Sdjm }
225d75efeb7Sdjm
226d75efeb7Sdjm int
fido_check_rp_id(const char * id,const unsigned char * obtained_hash)22732a20e26Sdjm fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
228d75efeb7Sdjm {
229d75efeb7Sdjm unsigned char expected_hash[SHA256_DIGEST_LENGTH];
230d75efeb7Sdjm
231d75efeb7Sdjm explicit_bzero(expected_hash, sizeof(expected_hash));
232d75efeb7Sdjm
233d75efeb7Sdjm if (SHA256((const unsigned char *)id, strlen(id),
234d75efeb7Sdjm expected_hash) != expected_hash) {
23532a20e26Sdjm fido_log_debug("%s: sha256", __func__);
236d75efeb7Sdjm return (-1);
237d75efeb7Sdjm }
238d75efeb7Sdjm
239d75efeb7Sdjm return (timingsafe_bcmp(expected_hash, obtained_hash,
240d75efeb7Sdjm SHA256_DIGEST_LENGTH));
241d75efeb7Sdjm }
242d75efeb7Sdjm
243d75efeb7Sdjm 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)244d75efeb7Sdjm get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
245d75efeb7Sdjm size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
246d75efeb7Sdjm const es256_pk_t *pk)
247d75efeb7Sdjm {
248d75efeb7Sdjm const uint8_t zero = 0;
249d75efeb7Sdjm const uint8_t four = 4; /* uncompressed point */
250*ab19a69eSdjm const EVP_MD *md = NULL;
251*ab19a69eSdjm EVP_MD_CTX *ctx = NULL;
252d75efeb7Sdjm int ok = -1;
253d75efeb7Sdjm
254*ab19a69eSdjm if (dgst->len != SHA256_DIGEST_LENGTH ||
255*ab19a69eSdjm (md = EVP_sha256()) == NULL ||
256*ab19a69eSdjm (ctx = EVP_MD_CTX_new()) == NULL ||
257*ab19a69eSdjm EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
258*ab19a69eSdjm EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
259*ab19a69eSdjm EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
260*ab19a69eSdjm EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
261*ab19a69eSdjm EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
262*ab19a69eSdjm EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
263*ab19a69eSdjm EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
264*ab19a69eSdjm EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
265*ab19a69eSdjm EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
266*ab19a69eSdjm fido_log_debug("%s: sha256", __func__);
267d75efeb7Sdjm goto fail;
268d75efeb7Sdjm }
269d75efeb7Sdjm
270d75efeb7Sdjm ok = 0;
271d75efeb7Sdjm fail:
272*ab19a69eSdjm EVP_MD_CTX_free(ctx);
273*ab19a69eSdjm
274*ab19a69eSdjm return (ok);
275*ab19a69eSdjm }
276*ab19a69eSdjm
277*ab19a69eSdjm static int
verify_attstmt(const fido_blob_t * dgst,const fido_attstmt_t * attstmt)278*ab19a69eSdjm verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
279*ab19a69eSdjm {
280*ab19a69eSdjm BIO *rawcert = NULL;
281*ab19a69eSdjm X509 *cert = NULL;
282*ab19a69eSdjm EVP_PKEY *pkey = NULL;
283*ab19a69eSdjm int ok = -1;
284*ab19a69eSdjm
285*ab19a69eSdjm /* openssl needs ints */
286*ab19a69eSdjm if (attstmt->x5c.len > INT_MAX) {
287*ab19a69eSdjm fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
288*ab19a69eSdjm return (-1);
289*ab19a69eSdjm }
290*ab19a69eSdjm
291*ab19a69eSdjm /* fetch key from x509 */
292*ab19a69eSdjm if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
293*ab19a69eSdjm (int)attstmt->x5c.len)) == NULL ||
294*ab19a69eSdjm (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
295*ab19a69eSdjm (pkey = X509_get_pubkey(cert)) == NULL) {
296*ab19a69eSdjm fido_log_debug("%s: x509 key", __func__);
297*ab19a69eSdjm goto fail;
298*ab19a69eSdjm }
299*ab19a69eSdjm
300*ab19a69eSdjm switch (attstmt->alg) {
301*ab19a69eSdjm case COSE_UNSPEC:
302*ab19a69eSdjm case COSE_ES256:
303*ab19a69eSdjm ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
304*ab19a69eSdjm break;
305*ab19a69eSdjm case COSE_RS256:
306*ab19a69eSdjm ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
307*ab19a69eSdjm break;
308*ab19a69eSdjm case COSE_RS1:
309*ab19a69eSdjm ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
310*ab19a69eSdjm break;
311*ab19a69eSdjm case COSE_EDDSA:
312*ab19a69eSdjm ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
313*ab19a69eSdjm break;
314*ab19a69eSdjm default:
315*ab19a69eSdjm fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
316*ab19a69eSdjm break;
317*ab19a69eSdjm }
318*ab19a69eSdjm
319*ab19a69eSdjm fail:
320d75efeb7Sdjm BIO_free(rawcert);
321d75efeb7Sdjm X509_free(cert);
322d75efeb7Sdjm EVP_PKEY_free(pkey);
323d75efeb7Sdjm
324d75efeb7Sdjm return (ok);
325d75efeb7Sdjm }
326d75efeb7Sdjm
327d75efeb7Sdjm int
fido_cred_verify(const fido_cred_t * cred)328d75efeb7Sdjm fido_cred_verify(const fido_cred_t *cred)
329d75efeb7Sdjm {
330d75efeb7Sdjm unsigned char buf[SHA256_DIGEST_LENGTH];
331d75efeb7Sdjm fido_blob_t dgst;
332d75efeb7Sdjm int r;
333d75efeb7Sdjm
334d75efeb7Sdjm dgst.ptr = buf;
335d75efeb7Sdjm dgst.len = sizeof(buf);
336d75efeb7Sdjm
337d75efeb7Sdjm /* do we have everything we need? */
338d75efeb7Sdjm if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
339d75efeb7Sdjm cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
340d75efeb7Sdjm cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
341d75efeb7Sdjm cred->rp.id == NULL) {
34232a20e26Sdjm fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
34332a20e26Sdjm "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
344d75efeb7Sdjm (void *)cred->authdata_cbor.ptr,
345d75efeb7Sdjm (void *)cred->attstmt.x5c.ptr,
346d75efeb7Sdjm (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
347d75efeb7Sdjm (void *)cred->attcred.id.ptr, cred->rp.id);
348d75efeb7Sdjm r = FIDO_ERR_INVALID_ARGUMENT;
349d75efeb7Sdjm goto out;
350d75efeb7Sdjm }
351d75efeb7Sdjm
35232a20e26Sdjm if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
35332a20e26Sdjm fido_log_debug("%s: fido_check_rp_id", __func__);
354d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
355d75efeb7Sdjm goto out;
356d75efeb7Sdjm }
357d75efeb7Sdjm
35832a20e26Sdjm if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
35932a20e26Sdjm cred->uv) < 0) {
36032a20e26Sdjm fido_log_debug("%s: fido_check_flags", __func__);
361d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
362d75efeb7Sdjm goto out;
363d75efeb7Sdjm }
364d75efeb7Sdjm
36532a20e26Sdjm if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
36632a20e26Sdjm fido_log_debug("%s: check_extensions", __func__);
367d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
368d75efeb7Sdjm goto out;
369d75efeb7Sdjm }
370d75efeb7Sdjm
371d75efeb7Sdjm if (!strcmp(cred->fmt, "packed")) {
372739189a3Sdjm if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh,
373d75efeb7Sdjm &cred->authdata_cbor) < 0) {
374739189a3Sdjm fido_log_debug("%s: fido_get_signed_hash", __func__);
375d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
376d75efeb7Sdjm goto out;
377d75efeb7Sdjm }
378c4a807edSdjm } else if (!strcmp(cred->fmt, "fido-u2f")) {
379d75efeb7Sdjm if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
380d75efeb7Sdjm sizeof(cred->authdata.rp_id_hash), &cred->cdh,
381d75efeb7Sdjm &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
38232a20e26Sdjm fido_log_debug("%s: get_signed_hash_u2f", __func__);
383d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
384d75efeb7Sdjm goto out;
385d75efeb7Sdjm }
386*ab19a69eSdjm } else if (!strcmp(cred->fmt, "tpm")) {
387*ab19a69eSdjm if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
388*ab19a69eSdjm &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
389*ab19a69eSdjm fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
390*ab19a69eSdjm r = FIDO_ERR_INTERNAL;
391*ab19a69eSdjm goto out;
392*ab19a69eSdjm }
393c4a807edSdjm } else {
394c4a807edSdjm fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
395c4a807edSdjm r = FIDO_ERR_INVALID_ARGUMENT;
396c4a807edSdjm goto out;
397d75efeb7Sdjm }
398d75efeb7Sdjm
399*ab19a69eSdjm if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
400*ab19a69eSdjm fido_log_debug("%s: verify_attstmt", __func__);
401d75efeb7Sdjm r = FIDO_ERR_INVALID_SIG;
402d75efeb7Sdjm goto out;
403d75efeb7Sdjm }
404d75efeb7Sdjm
405d75efeb7Sdjm r = FIDO_OK;
406d75efeb7Sdjm out:
407d75efeb7Sdjm explicit_bzero(buf, sizeof(buf));
408d75efeb7Sdjm
409d75efeb7Sdjm return (r);
410d75efeb7Sdjm }
411d75efeb7Sdjm
412d75efeb7Sdjm int
fido_cred_verify_self(const fido_cred_t * cred)413d75efeb7Sdjm fido_cred_verify_self(const fido_cred_t *cred)
414d75efeb7Sdjm {
415739189a3Sdjm unsigned char buf[1024]; /* XXX */
416d75efeb7Sdjm fido_blob_t dgst;
417d75efeb7Sdjm int ok = -1;
418d75efeb7Sdjm int r;
419d75efeb7Sdjm
420d75efeb7Sdjm dgst.ptr = buf;
421d75efeb7Sdjm dgst.len = sizeof(buf);
422d75efeb7Sdjm
423d75efeb7Sdjm /* do we have everything we need? */
424d75efeb7Sdjm if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
425d75efeb7Sdjm cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
426d75efeb7Sdjm cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
427d75efeb7Sdjm cred->rp.id == NULL) {
42832a20e26Sdjm fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
42932a20e26Sdjm "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
430d75efeb7Sdjm (void *)cred->authdata_cbor.ptr,
431d75efeb7Sdjm (void *)cred->attstmt.x5c.ptr,
432d75efeb7Sdjm (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
433d75efeb7Sdjm (void *)cred->attcred.id.ptr, cred->rp.id);
434d75efeb7Sdjm r = FIDO_ERR_INVALID_ARGUMENT;
435d75efeb7Sdjm goto out;
436d75efeb7Sdjm }
437d75efeb7Sdjm
43832a20e26Sdjm if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
43932a20e26Sdjm fido_log_debug("%s: fido_check_rp_id", __func__);
440d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
441d75efeb7Sdjm goto out;
442d75efeb7Sdjm }
443d75efeb7Sdjm
44432a20e26Sdjm if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
44532a20e26Sdjm cred->uv) < 0) {
44632a20e26Sdjm fido_log_debug("%s: fido_check_flags", __func__);
447d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
448d75efeb7Sdjm goto out;
449d75efeb7Sdjm }
450d75efeb7Sdjm
45132a20e26Sdjm if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
45232a20e26Sdjm fido_log_debug("%s: check_extensions", __func__);
453d75efeb7Sdjm r = FIDO_ERR_INVALID_PARAM;
454d75efeb7Sdjm goto out;
455d75efeb7Sdjm }
456d75efeb7Sdjm
457d75efeb7Sdjm if (!strcmp(cred->fmt, "packed")) {
458739189a3Sdjm if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
459d75efeb7Sdjm &cred->authdata_cbor) < 0) {
460739189a3Sdjm fido_log_debug("%s: fido_get_signed_hash", __func__);
461d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
462d75efeb7Sdjm goto out;
463d75efeb7Sdjm }
464c4a807edSdjm } else if (!strcmp(cred->fmt, "fido-u2f")) {
465d75efeb7Sdjm if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
466d75efeb7Sdjm sizeof(cred->authdata.rp_id_hash), &cred->cdh,
467d75efeb7Sdjm &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
46832a20e26Sdjm fido_log_debug("%s: get_signed_hash_u2f", __func__);
469d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
470d75efeb7Sdjm goto out;
471d75efeb7Sdjm }
472c4a807edSdjm } else {
473c4a807edSdjm fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
474c4a807edSdjm r = FIDO_ERR_INVALID_ARGUMENT;
475c4a807edSdjm goto out;
476d75efeb7Sdjm }
477d75efeb7Sdjm
478d75efeb7Sdjm switch (cred->attcred.type) {
479d75efeb7Sdjm case COSE_ES256:
480*ab19a69eSdjm ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
481d75efeb7Sdjm &cred->attstmt.sig);
482d75efeb7Sdjm break;
483d75efeb7Sdjm case COSE_RS256:
484*ab19a69eSdjm ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
485d75efeb7Sdjm &cred->attstmt.sig);
486d75efeb7Sdjm break;
487d75efeb7Sdjm case COSE_EDDSA:
488*ab19a69eSdjm ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
489d75efeb7Sdjm &cred->attstmt.sig);
490d75efeb7Sdjm break;
491d75efeb7Sdjm default:
49232a20e26Sdjm fido_log_debug("%s: unsupported cose_alg %d", __func__,
493d75efeb7Sdjm cred->attcred.type);
494d75efeb7Sdjm r = FIDO_ERR_UNSUPPORTED_OPTION;
495d75efeb7Sdjm goto out;
496d75efeb7Sdjm }
497d75efeb7Sdjm
498d75efeb7Sdjm if (ok < 0)
499d75efeb7Sdjm r = FIDO_ERR_INVALID_SIG;
500d75efeb7Sdjm else
501d75efeb7Sdjm r = FIDO_OK;
502d75efeb7Sdjm
503d75efeb7Sdjm out:
504d75efeb7Sdjm explicit_bzero(buf, sizeof(buf));
505d75efeb7Sdjm
506d75efeb7Sdjm return (r);
507d75efeb7Sdjm }
508d75efeb7Sdjm
509d75efeb7Sdjm fido_cred_t *
fido_cred_new(void)510d75efeb7Sdjm fido_cred_new(void)
511d75efeb7Sdjm {
512d75efeb7Sdjm return (calloc(1, sizeof(fido_cred_t)));
513d75efeb7Sdjm }
514d75efeb7Sdjm
515d75efeb7Sdjm static void
fido_cred_clean_authdata(fido_cred_t * cred)516d75efeb7Sdjm fido_cred_clean_authdata(fido_cred_t *cred)
517d75efeb7Sdjm {
518c4a807edSdjm fido_blob_reset(&cred->authdata_cbor);
519c4a807edSdjm fido_blob_reset(&cred->authdata_raw);
520c4a807edSdjm fido_blob_reset(&cred->attcred.id);
521d75efeb7Sdjm
522d75efeb7Sdjm memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
523d75efeb7Sdjm memset(&cred->authdata, 0, sizeof(cred->authdata));
524d75efeb7Sdjm memset(&cred->attcred, 0, sizeof(cred->attcred));
525d75efeb7Sdjm }
526d75efeb7Sdjm
527*ab19a69eSdjm static void
fido_cred_clean_attstmt(fido_attstmt_t * attstmt)528*ab19a69eSdjm fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
529*ab19a69eSdjm {
530*ab19a69eSdjm fido_blob_reset(&attstmt->certinfo);
531*ab19a69eSdjm fido_blob_reset(&attstmt->pubarea);
532*ab19a69eSdjm fido_blob_reset(&attstmt->cbor);
533*ab19a69eSdjm fido_blob_reset(&attstmt->x5c);
534*ab19a69eSdjm fido_blob_reset(&attstmt->sig);
535*ab19a69eSdjm
536*ab19a69eSdjm memset(attstmt, 0, sizeof(*attstmt));
537*ab19a69eSdjm }
538*ab19a69eSdjm
539d75efeb7Sdjm void
fido_cred_reset_tx(fido_cred_t * cred)540d75efeb7Sdjm fido_cred_reset_tx(fido_cred_t *cred)
541d75efeb7Sdjm {
542c4a807edSdjm fido_blob_reset(&cred->cd);
543c4a807edSdjm fido_blob_reset(&cred->cdh);
544c4a807edSdjm fido_blob_reset(&cred->user.id);
545c4a807edSdjm fido_blob_reset(&cred->blob);
546c4a807edSdjm
547d75efeb7Sdjm free(cred->rp.id);
548d75efeb7Sdjm free(cred->rp.name);
549d75efeb7Sdjm free(cred->user.icon);
550d75efeb7Sdjm free(cred->user.name);
551d75efeb7Sdjm free(cred->user.display_name);
55232a20e26Sdjm fido_free_blob_array(&cred->excl);
553d75efeb7Sdjm
554d75efeb7Sdjm memset(&cred->rp, 0, sizeof(cred->rp));
555d75efeb7Sdjm memset(&cred->user, 0, sizeof(cred->user));
556d75efeb7Sdjm memset(&cred->excl, 0, sizeof(cred->excl));
55732a20e26Sdjm memset(&cred->ext, 0, sizeof(cred->ext));
558d75efeb7Sdjm
559d75efeb7Sdjm cred->type = 0;
560d75efeb7Sdjm cred->rk = FIDO_OPT_OMIT;
561d75efeb7Sdjm cred->uv = FIDO_OPT_OMIT;
562d75efeb7Sdjm }
563d75efeb7Sdjm
564d75efeb7Sdjm void
fido_cred_reset_rx(fido_cred_t * cred)565d75efeb7Sdjm fido_cred_reset_rx(fido_cred_t *cred)
566d75efeb7Sdjm {
567d75efeb7Sdjm free(cred->fmt);
568d75efeb7Sdjm cred->fmt = NULL;
569d75efeb7Sdjm fido_cred_clean_authdata(cred);
570*ab19a69eSdjm fido_cred_clean_attstmt(&cred->attstmt);
571c4a807edSdjm fido_blob_reset(&cred->largeblob_key);
572d75efeb7Sdjm }
573d75efeb7Sdjm
574d75efeb7Sdjm void
fido_cred_free(fido_cred_t ** cred_p)575d75efeb7Sdjm fido_cred_free(fido_cred_t **cred_p)
576d75efeb7Sdjm {
577d75efeb7Sdjm fido_cred_t *cred;
578d75efeb7Sdjm
579d75efeb7Sdjm if (cred_p == NULL || (cred = *cred_p) == NULL)
580d75efeb7Sdjm return;
581d75efeb7Sdjm fido_cred_reset_tx(cred);
582d75efeb7Sdjm fido_cred_reset_rx(cred);
583d75efeb7Sdjm free(cred);
584d75efeb7Sdjm *cred_p = NULL;
585d75efeb7Sdjm }
586d75efeb7Sdjm
587d75efeb7Sdjm int
fido_cred_set_authdata(fido_cred_t * cred,const unsigned char * ptr,size_t len)588d75efeb7Sdjm fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
589d75efeb7Sdjm {
590d75efeb7Sdjm cbor_item_t *item = NULL;
591d75efeb7Sdjm struct cbor_load_result cbor;
592c4a807edSdjm int r = FIDO_ERR_INVALID_ARGUMENT;
593d75efeb7Sdjm
594d75efeb7Sdjm fido_cred_clean_authdata(cred);
595d75efeb7Sdjm
596c4a807edSdjm if (ptr == NULL || len == 0)
597d75efeb7Sdjm goto fail;
598d75efeb7Sdjm
599d75efeb7Sdjm if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
60032a20e26Sdjm fido_log_debug("%s: cbor_load", __func__);
601c4a807edSdjm goto fail;
602c4a807edSdjm }
603c4a807edSdjm
604c4a807edSdjm if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
605c4a807edSdjm fido_log_debug("%s: fido_blob_decode", __func__);
606d75efeb7Sdjm goto fail;
607d75efeb7Sdjm }
608d75efeb7Sdjm
60932a20e26Sdjm if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
610d75efeb7Sdjm &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
61132a20e26Sdjm fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
612d75efeb7Sdjm goto fail;
613d75efeb7Sdjm }
614d75efeb7Sdjm
615d75efeb7Sdjm r = FIDO_OK;
616d75efeb7Sdjm fail:
617d75efeb7Sdjm if (item != NULL)
618d75efeb7Sdjm cbor_decref(&item);
619d75efeb7Sdjm
620d75efeb7Sdjm if (r != FIDO_OK)
621d75efeb7Sdjm fido_cred_clean_authdata(cred);
622d75efeb7Sdjm
623d75efeb7Sdjm return (r);
624d75efeb7Sdjm }
625d75efeb7Sdjm
626d75efeb7Sdjm int
fido_cred_set_authdata_raw(fido_cred_t * cred,const unsigned char * ptr,size_t len)627d75efeb7Sdjm fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
628d75efeb7Sdjm size_t len)
629d75efeb7Sdjm {
630d75efeb7Sdjm cbor_item_t *item = NULL;
631c4a807edSdjm int r = FIDO_ERR_INVALID_ARGUMENT;
632d75efeb7Sdjm
633d75efeb7Sdjm fido_cred_clean_authdata(cred);
634d75efeb7Sdjm
635c4a807edSdjm if (ptr == NULL || len == 0)
636c4a807edSdjm goto fail;
637c4a807edSdjm
638c4a807edSdjm if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
639c4a807edSdjm fido_log_debug("%s: fido_blob_set", __func__);
640c4a807edSdjm r = FIDO_ERR_INTERNAL;
641d75efeb7Sdjm goto fail;
642d75efeb7Sdjm }
643d75efeb7Sdjm
644d75efeb7Sdjm if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
64532a20e26Sdjm fido_log_debug("%s: cbor_build_bytestring", __func__);
646d75efeb7Sdjm r = FIDO_ERR_INTERNAL;
647d75efeb7Sdjm goto fail;
648d75efeb7Sdjm }
649d75efeb7Sdjm
65032a20e26Sdjm if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
651d75efeb7Sdjm &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
65232a20e26Sdjm fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
653d75efeb7Sdjm goto fail;
654d75efeb7Sdjm }
655d75efeb7Sdjm
656d75efeb7Sdjm r = FIDO_OK;
657d75efeb7Sdjm fail:
658d75efeb7Sdjm if (item != NULL)
659d75efeb7Sdjm cbor_decref(&item);
660d75efeb7Sdjm
661d75efeb7Sdjm if (r != FIDO_OK)
662d75efeb7Sdjm fido_cred_clean_authdata(cred);
663d75efeb7Sdjm
664d75efeb7Sdjm return (r);
665d75efeb7Sdjm }
666d75efeb7Sdjm
667d75efeb7Sdjm int
fido_cred_set_id(fido_cred_t * cred,const unsigned char * ptr,size_t len)668c4a807edSdjm fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len)
669c4a807edSdjm {
670c4a807edSdjm if (fido_blob_set(&cred->attcred.id, ptr, len) < 0)
671c4a807edSdjm return (FIDO_ERR_INVALID_ARGUMENT);
672c4a807edSdjm
673c4a807edSdjm return (FIDO_OK);
674c4a807edSdjm }
675c4a807edSdjm
676c4a807edSdjm int
fido_cred_set_x509(fido_cred_t * cred,const unsigned char * ptr,size_t len)677d75efeb7Sdjm fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
678d75efeb7Sdjm {
679c4a807edSdjm if (fido_blob_set(&cred->attstmt.x5c, ptr, len) < 0)
680d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
681d75efeb7Sdjm
682d75efeb7Sdjm return (FIDO_OK);
683d75efeb7Sdjm }
684d75efeb7Sdjm
685d75efeb7Sdjm int
fido_cred_set_sig(fido_cred_t * cred,const unsigned char * ptr,size_t len)686d75efeb7Sdjm fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
687d75efeb7Sdjm {
688c4a807edSdjm if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0)
689d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
690d75efeb7Sdjm
691d75efeb7Sdjm return (FIDO_OK);
692d75efeb7Sdjm }
693d75efeb7Sdjm
694d75efeb7Sdjm int
fido_cred_set_attstmt(fido_cred_t * cred,const unsigned char * ptr,size_t len)695*ab19a69eSdjm fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
696*ab19a69eSdjm {
697*ab19a69eSdjm cbor_item_t *item = NULL;
698*ab19a69eSdjm struct cbor_load_result cbor;
699*ab19a69eSdjm int r = FIDO_ERR_INVALID_ARGUMENT;
700*ab19a69eSdjm
701*ab19a69eSdjm fido_cred_clean_attstmt(&cred->attstmt);
702*ab19a69eSdjm
703*ab19a69eSdjm if (ptr == NULL || len == 0)
704*ab19a69eSdjm goto fail;
705*ab19a69eSdjm
706*ab19a69eSdjm if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
707*ab19a69eSdjm fido_log_debug("%s: cbor_load", __func__);
708*ab19a69eSdjm goto fail;
709*ab19a69eSdjm }
710*ab19a69eSdjm
711*ab19a69eSdjm if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
712*ab19a69eSdjm fido_log_debug("%s: cbor_decode_attstmt", __func__);
713*ab19a69eSdjm goto fail;
714*ab19a69eSdjm }
715*ab19a69eSdjm
716*ab19a69eSdjm r = FIDO_OK;
717*ab19a69eSdjm fail:
718*ab19a69eSdjm if (item != NULL)
719*ab19a69eSdjm cbor_decref(&item);
720*ab19a69eSdjm
721*ab19a69eSdjm if (r != FIDO_OK)
722*ab19a69eSdjm fido_cred_clean_attstmt(&cred->attstmt);
723*ab19a69eSdjm
724*ab19a69eSdjm return (r);
725*ab19a69eSdjm }
726*ab19a69eSdjm
727*ab19a69eSdjm int
fido_cred_exclude(fido_cred_t * cred,const unsigned char * id_ptr,size_t id_len)728d75efeb7Sdjm fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
729d75efeb7Sdjm {
730d75efeb7Sdjm fido_blob_t id_blob;
731d75efeb7Sdjm fido_blob_t *list_ptr;
732d75efeb7Sdjm
733d75efeb7Sdjm memset(&id_blob, 0, sizeof(id_blob));
734d75efeb7Sdjm
735d75efeb7Sdjm if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
736d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
737d75efeb7Sdjm
738d75efeb7Sdjm if (cred->excl.len == SIZE_MAX) {
739d75efeb7Sdjm free(id_blob.ptr);
740d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
741d75efeb7Sdjm }
742d75efeb7Sdjm
743d75efeb7Sdjm if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
744d75efeb7Sdjm cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
745d75efeb7Sdjm free(id_blob.ptr);
746d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
747d75efeb7Sdjm }
748d75efeb7Sdjm
749d75efeb7Sdjm list_ptr[cred->excl.len++] = id_blob;
750d75efeb7Sdjm cred->excl.ptr = list_ptr;
751d75efeb7Sdjm
752d75efeb7Sdjm return (FIDO_OK);
753d75efeb7Sdjm }
754d75efeb7Sdjm
755d75efeb7Sdjm int
fido_cred_set_clientdata(fido_cred_t * cred,const unsigned char * data,size_t data_len)756c4a807edSdjm fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
757c4a807edSdjm size_t data_len)
758c4a807edSdjm {
759c4a807edSdjm if (!fido_blob_is_empty(&cred->cdh) ||
760c4a807edSdjm fido_blob_set(&cred->cd, data, data_len) < 0) {
761c4a807edSdjm return (FIDO_ERR_INVALID_ARGUMENT);
762c4a807edSdjm }
763c4a807edSdjm if (fido_sha256(&cred->cdh, data, data_len) < 0) {
764c4a807edSdjm fido_blob_reset(&cred->cd);
765c4a807edSdjm return (FIDO_ERR_INTERNAL);
766c4a807edSdjm }
767c4a807edSdjm
768c4a807edSdjm return (FIDO_OK);
769c4a807edSdjm }
770c4a807edSdjm
771c4a807edSdjm int
fido_cred_set_clientdata_hash(fido_cred_t * cred,const unsigned char * hash,size_t hash_len)772d75efeb7Sdjm fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
773d75efeb7Sdjm size_t hash_len)
774d75efeb7Sdjm {
775c4a807edSdjm if (!fido_blob_is_empty(&cred->cd) ||
776c4a807edSdjm fido_blob_set(&cred->cdh, hash, hash_len) < 0)
777d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
778d75efeb7Sdjm
779d75efeb7Sdjm return (FIDO_OK);
780d75efeb7Sdjm }
781d75efeb7Sdjm
782d75efeb7Sdjm int
fido_cred_set_rp(fido_cred_t * cred,const char * id,const char * name)783d75efeb7Sdjm fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
784d75efeb7Sdjm {
785d75efeb7Sdjm fido_rp_t *rp = &cred->rp;
786d75efeb7Sdjm
787d75efeb7Sdjm if (rp->id != NULL) {
788d75efeb7Sdjm free(rp->id);
789d75efeb7Sdjm rp->id = NULL;
790d75efeb7Sdjm }
791d75efeb7Sdjm if (rp->name != NULL) {
792d75efeb7Sdjm free(rp->name);
793d75efeb7Sdjm rp->name = NULL;
794d75efeb7Sdjm }
795d75efeb7Sdjm
796d75efeb7Sdjm if (id != NULL && (rp->id = strdup(id)) == NULL)
797d75efeb7Sdjm goto fail;
798d75efeb7Sdjm if (name != NULL && (rp->name = strdup(name)) == NULL)
799d75efeb7Sdjm goto fail;
800d75efeb7Sdjm
801d75efeb7Sdjm return (FIDO_OK);
802d75efeb7Sdjm fail:
803d75efeb7Sdjm free(rp->id);
804d75efeb7Sdjm free(rp->name);
805d75efeb7Sdjm rp->id = NULL;
806d75efeb7Sdjm rp->name = NULL;
807d75efeb7Sdjm
808d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
809d75efeb7Sdjm }
810d75efeb7Sdjm
811d75efeb7Sdjm 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)812d75efeb7Sdjm fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
813d75efeb7Sdjm size_t user_id_len, const char *name, const char *display_name,
814d75efeb7Sdjm const char *icon)
815d75efeb7Sdjm {
816d75efeb7Sdjm fido_user_t *up = &cred->user;
817d75efeb7Sdjm
818d75efeb7Sdjm if (up->id.ptr != NULL) {
819d75efeb7Sdjm free(up->id.ptr);
820d75efeb7Sdjm up->id.ptr = NULL;
821d75efeb7Sdjm up->id.len = 0;
822d75efeb7Sdjm }
823d75efeb7Sdjm if (up->name != NULL) {
824d75efeb7Sdjm free(up->name);
825d75efeb7Sdjm up->name = NULL;
826d75efeb7Sdjm }
827d75efeb7Sdjm if (up->display_name != NULL) {
828d75efeb7Sdjm free(up->display_name);
829d75efeb7Sdjm up->display_name = NULL;
830d75efeb7Sdjm }
831d75efeb7Sdjm if (up->icon != NULL) {
832d75efeb7Sdjm free(up->icon);
833d75efeb7Sdjm up->icon = NULL;
834d75efeb7Sdjm }
835d75efeb7Sdjm
836c4a807edSdjm if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0)
837d75efeb7Sdjm goto fail;
838d75efeb7Sdjm if (name != NULL && (up->name = strdup(name)) == NULL)
839d75efeb7Sdjm goto fail;
840d75efeb7Sdjm if (display_name != NULL &&
841d75efeb7Sdjm (up->display_name = strdup(display_name)) == NULL)
842d75efeb7Sdjm goto fail;
843d75efeb7Sdjm if (icon != NULL && (up->icon = strdup(icon)) == NULL)
844d75efeb7Sdjm goto fail;
845d75efeb7Sdjm
846d75efeb7Sdjm return (FIDO_OK);
847d75efeb7Sdjm fail:
848d75efeb7Sdjm free(up->id.ptr);
849d75efeb7Sdjm free(up->name);
850d75efeb7Sdjm free(up->display_name);
851d75efeb7Sdjm free(up->icon);
852d75efeb7Sdjm
853d75efeb7Sdjm up->id.ptr = NULL;
854d75efeb7Sdjm up->id.len = 0;
855d75efeb7Sdjm up->name = NULL;
856d75efeb7Sdjm up->display_name = NULL;
857d75efeb7Sdjm up->icon = NULL;
858d75efeb7Sdjm
859d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
860d75efeb7Sdjm }
861d75efeb7Sdjm
862d75efeb7Sdjm int
fido_cred_set_extensions(fido_cred_t * cred,int ext)863d75efeb7Sdjm fido_cred_set_extensions(fido_cred_t *cred, int ext)
864d75efeb7Sdjm {
86532a20e26Sdjm if (ext == 0)
86632a20e26Sdjm cred->ext.mask = 0;
86732a20e26Sdjm else {
868c4a807edSdjm if ((ext & FIDO_EXT_CRED_MASK) != ext)
869d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
87032a20e26Sdjm cred->ext.mask |= ext;
87132a20e26Sdjm }
872d75efeb7Sdjm
873d75efeb7Sdjm return (FIDO_OK);
874d75efeb7Sdjm }
875d75efeb7Sdjm
876d75efeb7Sdjm int
fido_cred_set_options(fido_cred_t * cred,bool rk,bool uv)877d75efeb7Sdjm fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
878d75efeb7Sdjm {
879d75efeb7Sdjm cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
880d75efeb7Sdjm cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
881d75efeb7Sdjm
882d75efeb7Sdjm return (FIDO_OK);
883d75efeb7Sdjm }
884d75efeb7Sdjm
885d75efeb7Sdjm int
fido_cred_set_rk(fido_cred_t * cred,fido_opt_t rk)886d75efeb7Sdjm fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
887d75efeb7Sdjm {
888d75efeb7Sdjm cred->rk = rk;
889d75efeb7Sdjm
890d75efeb7Sdjm return (FIDO_OK);
891d75efeb7Sdjm }
892d75efeb7Sdjm
893d75efeb7Sdjm int
fido_cred_set_uv(fido_cred_t * cred,fido_opt_t uv)894d75efeb7Sdjm fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
895d75efeb7Sdjm {
896d75efeb7Sdjm cred->uv = uv;
897d75efeb7Sdjm
898d75efeb7Sdjm return (FIDO_OK);
899d75efeb7Sdjm }
900d75efeb7Sdjm
901d75efeb7Sdjm int
fido_cred_set_prot(fido_cred_t * cred,int prot)90232a20e26Sdjm fido_cred_set_prot(fido_cred_t *cred, int prot)
90332a20e26Sdjm {
90432a20e26Sdjm if (prot == 0) {
90532a20e26Sdjm cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT;
90632a20e26Sdjm cred->ext.prot = 0;
90732a20e26Sdjm } else {
90832a20e26Sdjm if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
90932a20e26Sdjm prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
91032a20e26Sdjm prot != FIDO_CRED_PROT_UV_REQUIRED)
91132a20e26Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
91232a20e26Sdjm
91332a20e26Sdjm cred->ext.mask |= FIDO_EXT_CRED_PROTECT;
91432a20e26Sdjm cred->ext.prot = prot;
91532a20e26Sdjm }
91632a20e26Sdjm
91732a20e26Sdjm return (FIDO_OK);
91832a20e26Sdjm }
91932a20e26Sdjm
92032a20e26Sdjm int
fido_cred_set_pin_minlen(fido_cred_t * cred,size_t len)921*ab19a69eSdjm fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
922*ab19a69eSdjm {
923*ab19a69eSdjm if (len == 0)
924*ab19a69eSdjm cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
925*ab19a69eSdjm else
926*ab19a69eSdjm cred->ext.mask |= FIDO_EXT_MINPINLEN;
927*ab19a69eSdjm
928*ab19a69eSdjm cred->ext.minpinlen = len;
929*ab19a69eSdjm
930*ab19a69eSdjm return (FIDO_OK);
931*ab19a69eSdjm }
932*ab19a69eSdjm
933*ab19a69eSdjm int
fido_cred_set_blob(fido_cred_t * cred,const unsigned char * ptr,size_t len)934c4a807edSdjm fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
935c4a807edSdjm {
936c4a807edSdjm if (ptr == NULL || len == 0)
937c4a807edSdjm return (FIDO_ERR_INVALID_ARGUMENT);
938c4a807edSdjm if (fido_blob_set(&cred->blob, ptr, len) < 0)
939c4a807edSdjm return (FIDO_ERR_INTERNAL);
940c4a807edSdjm
941c4a807edSdjm cred->ext.mask |= FIDO_EXT_CRED_BLOB;
942c4a807edSdjm
943c4a807edSdjm return (FIDO_OK);
944c4a807edSdjm }
945c4a807edSdjm
946c4a807edSdjm int
fido_cred_set_fmt(fido_cred_t * cred,const char * fmt)947d75efeb7Sdjm fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
948d75efeb7Sdjm {
949d75efeb7Sdjm free(cred->fmt);
950d75efeb7Sdjm cred->fmt = NULL;
951d75efeb7Sdjm
952d75efeb7Sdjm if (fmt == NULL)
953d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
954d75efeb7Sdjm
955c4a807edSdjm if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
956*ab19a69eSdjm strcmp(fmt, "none") && strcmp(fmt, "tpm"))
957d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
958d75efeb7Sdjm
959d75efeb7Sdjm if ((cred->fmt = strdup(fmt)) == NULL)
960d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
961d75efeb7Sdjm
962d75efeb7Sdjm return (FIDO_OK);
963d75efeb7Sdjm }
964d75efeb7Sdjm
965d75efeb7Sdjm int
fido_cred_set_type(fido_cred_t * cred,int cose_alg)966d75efeb7Sdjm fido_cred_set_type(fido_cred_t *cred, int cose_alg)
967d75efeb7Sdjm {
968d75efeb7Sdjm if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 &&
969d75efeb7Sdjm cose_alg != COSE_EDDSA) || cred->type != 0)
970d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
971d75efeb7Sdjm
972d75efeb7Sdjm cred->type = cose_alg;
973d75efeb7Sdjm
974d75efeb7Sdjm return (FIDO_OK);
975d75efeb7Sdjm }
976d75efeb7Sdjm
977d75efeb7Sdjm int
fido_cred_type(const fido_cred_t * cred)978d75efeb7Sdjm fido_cred_type(const fido_cred_t *cred)
979d75efeb7Sdjm {
980d75efeb7Sdjm return (cred->type);
981d75efeb7Sdjm }
982d75efeb7Sdjm
983d75efeb7Sdjm uint8_t
fido_cred_flags(const fido_cred_t * cred)984d75efeb7Sdjm fido_cred_flags(const fido_cred_t *cred)
985d75efeb7Sdjm {
986d75efeb7Sdjm return (cred->authdata.flags);
987d75efeb7Sdjm }
988d75efeb7Sdjm
989c4a807edSdjm uint32_t
fido_cred_sigcount(const fido_cred_t * cred)990c4a807edSdjm fido_cred_sigcount(const fido_cred_t *cred)
991c4a807edSdjm {
992c4a807edSdjm return (cred->authdata.sigcount);
993c4a807edSdjm }
994c4a807edSdjm
995d75efeb7Sdjm const unsigned char *
fido_cred_clientdata_hash_ptr(const fido_cred_t * cred)996d75efeb7Sdjm fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
997d75efeb7Sdjm {
998d75efeb7Sdjm return (cred->cdh.ptr);
999d75efeb7Sdjm }
1000d75efeb7Sdjm
1001d75efeb7Sdjm size_t
fido_cred_clientdata_hash_len(const fido_cred_t * cred)1002d75efeb7Sdjm fido_cred_clientdata_hash_len(const fido_cred_t *cred)
1003d75efeb7Sdjm {
1004d75efeb7Sdjm return (cred->cdh.len);
1005d75efeb7Sdjm }
1006d75efeb7Sdjm
1007d75efeb7Sdjm const unsigned char *
fido_cred_x5c_ptr(const fido_cred_t * cred)1008d75efeb7Sdjm fido_cred_x5c_ptr(const fido_cred_t *cred)
1009d75efeb7Sdjm {
1010d75efeb7Sdjm return (cred->attstmt.x5c.ptr);
1011d75efeb7Sdjm }
1012d75efeb7Sdjm
1013d75efeb7Sdjm size_t
fido_cred_x5c_len(const fido_cred_t * cred)1014d75efeb7Sdjm fido_cred_x5c_len(const fido_cred_t *cred)
1015d75efeb7Sdjm {
1016d75efeb7Sdjm return (cred->attstmt.x5c.len);
1017d75efeb7Sdjm }
1018d75efeb7Sdjm
1019d75efeb7Sdjm const unsigned char *
fido_cred_sig_ptr(const fido_cred_t * cred)1020d75efeb7Sdjm fido_cred_sig_ptr(const fido_cred_t *cred)
1021d75efeb7Sdjm {
1022d75efeb7Sdjm return (cred->attstmt.sig.ptr);
1023d75efeb7Sdjm }
1024d75efeb7Sdjm
1025d75efeb7Sdjm size_t
fido_cred_sig_len(const fido_cred_t * cred)1026d75efeb7Sdjm fido_cred_sig_len(const fido_cred_t *cred)
1027d75efeb7Sdjm {
1028d75efeb7Sdjm return (cred->attstmt.sig.len);
1029d75efeb7Sdjm }
1030d75efeb7Sdjm
1031d75efeb7Sdjm const unsigned char *
fido_cred_authdata_ptr(const fido_cred_t * cred)1032d75efeb7Sdjm fido_cred_authdata_ptr(const fido_cred_t *cred)
1033d75efeb7Sdjm {
1034d75efeb7Sdjm return (cred->authdata_cbor.ptr);
1035d75efeb7Sdjm }
1036d75efeb7Sdjm
1037d75efeb7Sdjm size_t
fido_cred_authdata_len(const fido_cred_t * cred)1038d75efeb7Sdjm fido_cred_authdata_len(const fido_cred_t *cred)
1039d75efeb7Sdjm {
1040d75efeb7Sdjm return (cred->authdata_cbor.len);
1041d75efeb7Sdjm }
1042d75efeb7Sdjm
1043d75efeb7Sdjm const unsigned char *
fido_cred_authdata_raw_ptr(const fido_cred_t * cred)1044c4a807edSdjm fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
1045c4a807edSdjm {
1046c4a807edSdjm return (cred->authdata_raw.ptr);
1047c4a807edSdjm }
1048c4a807edSdjm
1049c4a807edSdjm size_t
fido_cred_authdata_raw_len(const fido_cred_t * cred)1050c4a807edSdjm fido_cred_authdata_raw_len(const fido_cred_t *cred)
1051c4a807edSdjm {
1052c4a807edSdjm return (cred->authdata_raw.len);
1053c4a807edSdjm }
1054c4a807edSdjm
1055c4a807edSdjm const unsigned char *
fido_cred_attstmt_ptr(const fido_cred_t * cred)1056*ab19a69eSdjm fido_cred_attstmt_ptr(const fido_cred_t *cred)
1057*ab19a69eSdjm {
1058*ab19a69eSdjm return (cred->attstmt.cbor.ptr);
1059*ab19a69eSdjm }
1060*ab19a69eSdjm
1061*ab19a69eSdjm size_t
fido_cred_attstmt_len(const fido_cred_t * cred)1062*ab19a69eSdjm fido_cred_attstmt_len(const fido_cred_t *cred)
1063*ab19a69eSdjm {
1064*ab19a69eSdjm return (cred->attstmt.cbor.len);
1065*ab19a69eSdjm }
1066*ab19a69eSdjm
1067*ab19a69eSdjm const unsigned char *
fido_cred_pubkey_ptr(const fido_cred_t * cred)1068d75efeb7Sdjm fido_cred_pubkey_ptr(const fido_cred_t *cred)
1069d75efeb7Sdjm {
1070d75efeb7Sdjm const void *ptr;
1071d75efeb7Sdjm
1072d75efeb7Sdjm switch (cred->attcred.type) {
1073d75efeb7Sdjm case COSE_ES256:
1074d75efeb7Sdjm ptr = &cred->attcred.pubkey.es256;
1075d75efeb7Sdjm break;
1076d75efeb7Sdjm case COSE_RS256:
1077d75efeb7Sdjm ptr = &cred->attcred.pubkey.rs256;
1078d75efeb7Sdjm break;
1079d75efeb7Sdjm case COSE_EDDSA:
1080d75efeb7Sdjm ptr = &cred->attcred.pubkey.eddsa;
1081d75efeb7Sdjm break;
1082d75efeb7Sdjm default:
1083d75efeb7Sdjm ptr = NULL;
1084d75efeb7Sdjm break;
1085d75efeb7Sdjm }
1086d75efeb7Sdjm
1087d75efeb7Sdjm return (ptr);
1088d75efeb7Sdjm }
1089d75efeb7Sdjm
1090d75efeb7Sdjm size_t
fido_cred_pubkey_len(const fido_cred_t * cred)1091d75efeb7Sdjm fido_cred_pubkey_len(const fido_cred_t *cred)
1092d75efeb7Sdjm {
1093d75efeb7Sdjm size_t len;
1094d75efeb7Sdjm
1095d75efeb7Sdjm switch (cred->attcred.type) {
1096d75efeb7Sdjm case COSE_ES256:
1097d75efeb7Sdjm len = sizeof(cred->attcred.pubkey.es256);
1098d75efeb7Sdjm break;
1099d75efeb7Sdjm case COSE_RS256:
1100d75efeb7Sdjm len = sizeof(cred->attcred.pubkey.rs256);
1101d75efeb7Sdjm break;
1102d75efeb7Sdjm case COSE_EDDSA:
1103d75efeb7Sdjm len = sizeof(cred->attcred.pubkey.eddsa);
1104d75efeb7Sdjm break;
1105d75efeb7Sdjm default:
1106d75efeb7Sdjm len = 0;
1107d75efeb7Sdjm break;
1108d75efeb7Sdjm }
1109d75efeb7Sdjm
1110d75efeb7Sdjm return (len);
1111d75efeb7Sdjm }
1112d75efeb7Sdjm
1113d75efeb7Sdjm const unsigned char *
fido_cred_id_ptr(const fido_cred_t * cred)1114d75efeb7Sdjm fido_cred_id_ptr(const fido_cred_t *cred)
1115d75efeb7Sdjm {
1116d75efeb7Sdjm return (cred->attcred.id.ptr);
1117d75efeb7Sdjm }
1118d75efeb7Sdjm
1119d75efeb7Sdjm size_t
fido_cred_id_len(const fido_cred_t * cred)1120d75efeb7Sdjm fido_cred_id_len(const fido_cred_t *cred)
1121d75efeb7Sdjm {
1122d75efeb7Sdjm return (cred->attcred.id.len);
1123d75efeb7Sdjm }
1124d75efeb7Sdjm
1125739189a3Sdjm const unsigned char *
fido_cred_aaguid_ptr(const fido_cred_t * cred)1126739189a3Sdjm fido_cred_aaguid_ptr(const fido_cred_t *cred)
1127739189a3Sdjm {
1128739189a3Sdjm return (cred->attcred.aaguid);
1129739189a3Sdjm }
1130739189a3Sdjm
1131739189a3Sdjm size_t
fido_cred_aaguid_len(const fido_cred_t * cred)1132739189a3Sdjm fido_cred_aaguid_len(const fido_cred_t *cred)
1133739189a3Sdjm {
1134739189a3Sdjm return (sizeof(cred->attcred.aaguid));
1135739189a3Sdjm }
1136739189a3Sdjm
113732a20e26Sdjm int
fido_cred_prot(const fido_cred_t * cred)113832a20e26Sdjm fido_cred_prot(const fido_cred_t *cred)
113932a20e26Sdjm {
114032a20e26Sdjm return (cred->ext.prot);
114132a20e26Sdjm }
114232a20e26Sdjm
1143*ab19a69eSdjm size_t
fido_cred_pin_minlen(const fido_cred_t * cred)1144*ab19a69eSdjm fido_cred_pin_minlen(const fido_cred_t *cred)
1145*ab19a69eSdjm {
1146*ab19a69eSdjm return (cred->ext.minpinlen);
1147*ab19a69eSdjm }
1148*ab19a69eSdjm
1149d75efeb7Sdjm const char *
fido_cred_fmt(const fido_cred_t * cred)1150d75efeb7Sdjm fido_cred_fmt(const fido_cred_t *cred)
1151d75efeb7Sdjm {
1152d75efeb7Sdjm return (cred->fmt);
1153d75efeb7Sdjm }
1154d75efeb7Sdjm
1155d75efeb7Sdjm const char *
fido_cred_rp_id(const fido_cred_t * cred)1156d75efeb7Sdjm fido_cred_rp_id(const fido_cred_t *cred)
1157d75efeb7Sdjm {
1158d75efeb7Sdjm return (cred->rp.id);
1159d75efeb7Sdjm }
1160d75efeb7Sdjm
1161d75efeb7Sdjm const char *
fido_cred_rp_name(const fido_cred_t * cred)1162d75efeb7Sdjm fido_cred_rp_name(const fido_cred_t *cred)
1163d75efeb7Sdjm {
1164d75efeb7Sdjm return (cred->rp.name);
1165d75efeb7Sdjm }
1166d75efeb7Sdjm
1167d75efeb7Sdjm const char *
fido_cred_user_name(const fido_cred_t * cred)1168d75efeb7Sdjm fido_cred_user_name(const fido_cred_t *cred)
1169d75efeb7Sdjm {
1170d75efeb7Sdjm return (cred->user.name);
1171d75efeb7Sdjm }
1172d75efeb7Sdjm
1173d75efeb7Sdjm const char *
fido_cred_display_name(const fido_cred_t * cred)1174d75efeb7Sdjm fido_cred_display_name(const fido_cred_t *cred)
1175d75efeb7Sdjm {
1176d75efeb7Sdjm return (cred->user.display_name);
1177d75efeb7Sdjm }
1178d75efeb7Sdjm
1179d75efeb7Sdjm const unsigned char *
fido_cred_user_id_ptr(const fido_cred_t * cred)1180d75efeb7Sdjm fido_cred_user_id_ptr(const fido_cred_t *cred)
1181d75efeb7Sdjm {
1182d75efeb7Sdjm return (cred->user.id.ptr);
1183d75efeb7Sdjm }
1184d75efeb7Sdjm
1185d75efeb7Sdjm size_t
fido_cred_user_id_len(const fido_cred_t * cred)1186d75efeb7Sdjm fido_cred_user_id_len(const fido_cred_t *cred)
1187d75efeb7Sdjm {
1188d75efeb7Sdjm return (cred->user.id.len);
1189d75efeb7Sdjm }
1190c4a807edSdjm
1191c4a807edSdjm const unsigned char *
fido_cred_largeblob_key_ptr(const fido_cred_t * cred)1192c4a807edSdjm fido_cred_largeblob_key_ptr(const fido_cred_t *cred)
1193c4a807edSdjm {
1194c4a807edSdjm return (cred->largeblob_key.ptr);
1195c4a807edSdjm }
1196c4a807edSdjm
1197c4a807edSdjm size_t
fido_cred_largeblob_key_len(const fido_cred_t * cred)1198c4a807edSdjm fido_cred_largeblob_key_len(const fido_cred_t *cred)
1199c4a807edSdjm {
1200c4a807edSdjm return (cred->largeblob_key.len);
1201c4a807edSdjm }
1202