Coverage Report

Created: 2026-04-08 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/libfido2/src/cred.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2026 Yubico AB. All rights reserved.
3
 * Use of this source code is governed by a BSD-style
4
 * license that can be found in the LICENSE file.
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <openssl/sha.h>
9
#include <openssl/x509.h>
10
11
#include "fido.h"
12
#include "fido/es256.h"
13
14
#ifndef FIDO_MAXMSG_CRED
15
5.26k
#define FIDO_MAXMSG_CRED        4096
16
#endif
17
18
static int
19
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
20
5.93k
{
21
5.93k
        fido_cred_t *cred = arg;
22
23
5.93k
        if (cbor_isa_uint(key) == false ||
24
5.93k
            cbor_int_get_width(key) != CBOR_INT_8) {
25
48
                fido_log_debug("%s: cbor type", __func__);
26
48
                return (0); /* ignore */
27
48
        }
28
29
5.88k
        switch (cbor_get_uint8(key)) {
30
2.16k
        case 1: /* fmt */
31
2.16k
                return (cbor_decode_fmt(val, &cred->fmt));
32
2.01k
        case 2: /* authdata */
33
2.01k
                if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
34
4
                        fido_log_debug("%s: fido_blob_decode", __func__);
35
4
                        return (-1);
36
4
                }
37
2.00k
                return (cbor_decode_cred_authdata(val, cred->type,
38
2.00k
                    &cred->authdata_cbor, &cred->authdata, &cred->attcred,
39
2.00k
                    &cred->authdata_ext));
40
1.62k
        case 3: /* attestation statement */
41
1.62k
                return (cbor_decode_attstmt(val, &cred->attstmt));
42
3
        case 4: /* enterprise attestation */
43
3
                return (cbor_decode_bool(val, &cred->ea.att));
44
0
        case 5: /* large blob key */
45
0
                return (fido_blob_decode(val, &cred->largeblob_key));
46
72
        default: /* ignore */
47
72
                fido_log_debug("%s: cbor type", __func__);
48
72
                return (0);
49
5.88k
        }
50
5.88k
}
51
52
static int
53
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred,
54
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
55
6.85k
{
56
6.85k
        fido_blob_t      f;
57
6.85k
        fido_opt_t       uv = cred->uv;
58
6.85k
        cbor_item_t     *argv[10];
59
6.85k
        const uint8_t    cmd = CTAP_CBOR_MAKECRED;
60
6.85k
        int              r;
61
62
6.85k
        memset(&f, 0, sizeof(f));
63
6.85k
        memset(argv, 0, sizeof(argv));
64
65
6.85k
        if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
66
6.85k
            (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
67
6.85k
            (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
68
6.85k
            (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
69
237
                fido_log_debug("%s: cbor encode", __func__);
70
237
                r = FIDO_ERR_INTERNAL;
71
237
                goto fail;
72
237
        }
73
74
        /* excluded credentials */
75
6.62k
        if (cred->excl.len)
76
4.33k
                if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
77
900
                        fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
78
900
                        r = FIDO_ERR_INTERNAL;
79
900
                        goto fail;
80
900
                }
81
82
        /* extensions */
83
5.72k
        if (cred->ext.attr.mask)
84
4.08k
                if ((argv[5] = cbor_encode_cred_ext(dev, &cred->ext, ecdh,
85
4.08k
                    pk)) == NULL) {
86
1.19k
                        fido_log_debug("%s: cbor_encode_cred_ext", __func__);
87
1.19k
                        r = FIDO_ERR_INTERNAL;
88
1.19k
                        goto fail;
89
1.19k
                }
90
91
        /* user verification */
92
4.52k
        if (pin != NULL ||
93
4.52k
            fido_dev_puat_blob(dev) != NULL ||
94
4.52k
            (uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev))) {
95
3.65k
                if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
96
3.65k
                    pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
97
1.42k
                        fido_log_debug("%s: cbor_add_uv_params", __func__);
98
1.42k
                        goto fail;
99
1.42k
                }
100
2.22k
                uv = FIDO_OPT_OMIT;
101
2.22k
        }
102
103
        /* options */
104
3.10k
        if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
105
874
                if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) {
106
10
                        fido_log_debug("%s: cbor_encode_cred_opt", __func__);
107
10
                        r = FIDO_ERR_INTERNAL;
108
10
                        goto fail;
109
10
                }
110
111
        /* enterprise attestation */
112
3.09k
        if (cred->ea.mode != 0)
113
1.17k
                if ((argv[9] = cbor_build_uint8((uint8_t)cred->ea.mode)) ==
114
1.17k
                    NULL) {
115
2
                        fido_log_debug("%s: cbor_build_uint8", __func__);
116
2
                        r = FIDO_ERR_INTERNAL;
117
2
                        goto fail;
118
2
                }
119
120
        /* framing and transmission */
121
3.09k
        if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
122
3.09k
            fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
123
457
                fido_log_debug("%s: fido_tx", __func__);
124
457
                r = FIDO_ERR_TX;
125
457
                goto fail;
126
457
        }
127
128
2.63k
        r = FIDO_OK;
129
6.85k
fail:
130
6.85k
        cbor_vector_free(argv, nitems(argv));
131
6.85k
        free(f.ptr);
132
133
6.85k
        return (r);
134
2.63k
}
135
136
static int
137
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
138
2.63k
{
139
2.63k
        unsigned char   *reply;
140
2.63k
        int              reply_len;
141
2.63k
        int              r;
142
143
2.63k
        fido_cred_reset_rx(cred);
144
145
2.63k
        if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
146
5
                r = FIDO_ERR_INTERNAL;
147
5
                goto fail;
148
5
        }
149
150
2.62k
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
151
2.62k
            ms)) < 0) {
152
324
                fido_log_debug("%s: fido_rx", __func__);
153
324
                r = FIDO_ERR_RX;
154
324
                goto fail;
155
324
        }
156
157
2.30k
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
158
2.30k
            parse_makecred_reply)) != FIDO_OK) {
159
737
                fido_log_debug("%s: parse_makecred_reply", __func__);
160
737
                goto fail;
161
737
        }
162
163
1.56k
        if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
164
1.56k
            fido_blob_is_empty(&cred->attcred.id)) {
165
30
                r = FIDO_ERR_INVALID_CBOR;
166
30
                goto fail;
167
30
        }
168
169
1.53k
        r = FIDO_OK;
170
2.63k
fail:
171
2.63k
        free(reply);
172
173
2.63k
        if (r != FIDO_OK)
174
1.09k
                fido_cred_reset_rx(cred);
175
176
2.63k
        return (r);
177
1.53k
}
178
179
static int
180
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred,
181
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
182
6.85k
{
183
6.85k
        int  r;
184
185
6.85k
        if ((r = fido_dev_make_cred_tx(dev, cred, pk, ecdh, pin, ms)) != FIDO_OK ||
186
6.85k
            (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
187
5.32k
                return (r);
188
189
1.53k
        return (FIDO_OK);
190
6.85k
}
191
192
static int
193
decrypt_hmac_secret(const fido_dev_t *dev, fido_cred_t *cred,
194
    const fido_blob_t *key)
195
0
{
196
0
        return (aes256_cbc_dec(dev, key, &cred->authdata_ext.hmac_secret_enc,
197
0
            &cred->hmac_secret));
198
0
}
199
200
static bool
201
need_ecdh(const fido_dev_t *dev, const fido_cred_t *cred, const char *pin)
202
10.8k
{
203
10.8k
        if (cred->ext.attr.mask & FIDO_EXT_HMAC_SECRET_MC)
204
3.63k
                return true;
205
206
        /* If available, prefer cached PUAT */
207
7.22k
        if (fido_dev_puat_blob(dev) != NULL)
208
349
                return false;
209
210
6.87k
        if (pin != NULL)
211
5.64k
                return true;
212
213
1.23k
        return cred->uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev);
214
6.87k
}
215
216
int
217
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
218
23.0k
{
219
23.0k
        fido_blob_t     *ecdh = NULL;
220
23.0k
        es256_pk_t      *pk = NULL;
221
23.0k
        int              ms = dev->timeout_ms;
222
23.0k
        int              r;
223
224
#ifdef USE_WINHELLO
225
        if (dev->flags & FIDO_DEV_WINHELLO)
226
                return (fido_winhello_make_cred(dev, cred, pin, ms));
227
#endif
228
23.0k
        if (fido_dev_is_fido2(dev) == false) {
229
12.1k
                if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
230
12.1k
                    cred->ext.attr.mask != 0)
231
8.00k
                        return (FIDO_ERR_UNSUPPORTED_OPTION);
232
4.17k
                return (u2f_register(dev, cred, &ms));
233
12.1k
        }
234
235
10.8k
        if (cred->cdh.ptr == NULL || cred->type == 0) {
236
14
                fido_log_debug("%s: cdh=%p, type=%d", __func__,
237
14
                    (void *)cred->cdh.ptr, cred->type);
238
14
                r = FIDO_ERR_INVALID_ARGUMENT;
239
14
                goto fail;
240
14
        }
241
242
10.8k
        if (need_ecdh(dev, cred, pin) && (r = fido_do_ecdh(dev, &pk, &ecdh,
243
9.45k
            &ms)) != FIDO_OK) {
244
4.00k
                fido_log_debug("%s: fido_do_ecdh", __func__);
245
4.00k
                goto fail;
246
4.00k
        }
247
248
6.85k
        r = fido_dev_make_cred_wait(dev, cred, pk, ecdh, pin, &ms);
249
6.85k
        if (r == FIDO_OK && (cred->ext.attr.mask & FIDO_EXT_HMAC_SECRET_MC)) {
250
0
                if (decrypt_hmac_secret(dev, cred, ecdh) < 0) {
251
0
                        fido_log_debug("%s: decrypt_hmac_secret", __func__);
252
0
                        r = FIDO_ERR_INTERNAL;
253
0
                        goto fail;
254
0
                }
255
0
        }
256
257
10.8k
fail:
258
10.8k
        es256_pk_free(&pk);
259
10.8k
        fido_blob_free(&ecdh);
260
261
10.8k
        return (r);
262
6.85k
}
263
264
static int
265
check_extensions(const fido_cred_ext_t *authdata_ext,
266
    const fido_cred_ext_t *ext)
267
8.78k
{
268
8.78k
        fido_cred_ext_t tmp;
269
270
        /*
271
         * XXX: largeBlobKey is not part of the extensions map
272
         * XXX: thirdPartyPayment has no output for make credential
273
         */
274
8.78k
        memcpy(&tmp, ext, sizeof(tmp));
275
8.78k
        tmp.mask &= ~(FIDO_EXT_LARGEBLOB_KEY | FIDO_EXT_PAYMENT);
276
277
8.78k
        return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext)));
278
8.78k
}
279
280
int
281
fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
282
12.3k
{
283
12.3k
        unsigned char expected_hash[SHA256_DIGEST_LENGTH];
284
285
12.3k
        explicit_bzero(expected_hash, sizeof(expected_hash));
286
287
12.3k
        if (SHA256((const unsigned char *)id, strlen(id),
288
12.3k
            expected_hash) != expected_hash) {
289
57
                fido_log_debug("%s: sha256", __func__);
290
57
                return (-1);
291
57
        }
292
293
12.2k
        return (timingsafe_bcmp(expected_hash, obtained_hash,
294
12.2k
            SHA256_DIGEST_LENGTH));
295
12.3k
}
296
297
static int
298
get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
299
    size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
300
    const es256_pk_t *pk)
301
479
{
302
479
        const uint8_t    zero = 0;
303
479
        const uint8_t    four = 4; /* uncompressed point */
304
479
        const EVP_MD    *md = NULL;
305
479
        EVP_MD_CTX      *ctx = NULL;
306
479
        int              ok = -1;
307
308
479
        if (dgst->len < SHA256_DIGEST_LENGTH ||
309
479
            (md = EVP_sha256()) == NULL ||
310
479
            (ctx = EVP_MD_CTX_new()) == NULL ||
311
479
            EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
312
479
            EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
313
479
            EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
314
479
            EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
315
479
            EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
316
479
            EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
317
479
            EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
318
479
            EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
319
479
            EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
320
29
                fido_log_debug("%s: sha256", __func__);
321
29
                goto fail;
322
29
        }
323
450
        dgst->len = SHA256_DIGEST_LENGTH;
324
325
450
        ok = 0;
326
479
fail:
327
479
        EVP_MD_CTX_free(ctx);
328
329
479
        return (ok);
330
450
}
331
332
static int
333
verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
334
8.28k
{
335
8.28k
        BIO             *rawcert = NULL;
336
8.28k
        X509            *cert = NULL;
337
8.28k
        EVP_PKEY        *pkey = NULL;
338
8.28k
        int              ok = -1;
339
340
8.28k
        if (!attstmt->x5c.len) {
341
0
                fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
342
0
                return (-1);
343
0
        }
344
345
        /* openssl needs ints */
346
8.28k
        if (attstmt->x5c.ptr[0].len > INT_MAX) {
347
0
                fido_log_debug("%s: x5c[0].len=%zu", __func__,
348
0
                    attstmt->x5c.ptr[0].len);
349
0
                return (-1);
350
0
        }
351
352
        /* fetch key from x509 */
353
8.28k
        if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr[0].ptr,
354
8.28k
            (int)attstmt->x5c.ptr[0].len)) == NULL ||
355
8.28k
            (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
356
8.28k
            (pkey = X509_get_pubkey(cert)) == NULL) {
357
4.03k
                fido_log_debug("%s: x509 key", __func__);
358
4.03k
                goto fail;
359
4.03k
        }
360
361
4.24k
        switch (attstmt->alg) {
362
76
        case COSE_UNSPEC:
363
3.73k
        case COSE_ES256:
364
3.73k
                ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
365
3.73k
                break;
366
11
        case COSE_ES384:
367
11
                ok = es384_verify_sig(dgst, pkey, &attstmt->sig);
368
11
                break;
369
0
        case COSE_RS256:
370
0
                ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
371
0
                break;
372
478
        case COSE_RS1:
373
478
                ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
374
478
                break;
375
24
        case COSE_EDDSA:
376
24
                ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
377
24
                break;
378
0
        default:
379
0
                fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
380
0
                break;
381
4.24k
        }
382
383
8.28k
fail:
384
8.28k
        BIO_free(rawcert);
385
8.28k
        X509_free(cert);
386
8.28k
        EVP_PKEY_free(pkey);
387
388
8.28k
        return (ok);
389
4.24k
}
390
391
int
392
fido_cred_verify(const fido_cred_t *cred)
393
44.4k
{
394
44.4k
        unsigned char   buf[1024]; /* XXX */
395
44.4k
        fido_blob_t     dgst;
396
44.4k
        int             cose_alg;
397
44.4k
        int             r;
398
399
44.4k
        dgst.ptr = buf;
400
44.4k
        dgst.len = sizeof(buf);
401
402
        /* do we have everything we need? */
403
44.4k
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
404
44.4k
            cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
405
44.4k
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
406
44.4k
            cred->rp.id == NULL) {
407
33.9k
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
408
33.9k
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
409
33.9k
                    (void *)cred->authdata_cbor.ptr,
410
33.9k
                    (void *)cred->attstmt.x5c.ptr,
411
33.9k
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
412
33.9k
                    (void *)cred->attcred.id.ptr, cred->rp.id);
413
33.9k
                r = FIDO_ERR_INVALID_ARGUMENT;
414
33.9k
                goto out;
415
33.9k
        }
416
417
10.5k
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
418
1.96k
                fido_log_debug("%s: fido_check_rp_id", __func__);
419
1.96k
                r = FIDO_ERR_INVALID_PARAM;
420
1.96k
                goto out;
421
1.96k
        }
422
423
8.55k
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
424
8.55k
            cred->uv) < 0) {
425
14
                fido_log_debug("%s: fido_check_flags", __func__);
426
14
                r = FIDO_ERR_INVALID_PARAM;
427
14
                goto out;
428
14
        }
429
430
8.54k
        if (check_extensions(&cred->authdata_ext.attr, &cred->ext.attr) != 0) {
431
5
                fido_log_debug("%s: check_extensions", __func__);
432
5
                r = FIDO_ERR_INVALID_PARAM;
433
5
                goto out;
434
5
        }
435
436
8.53k
        if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC)
437
179
                cose_alg = COSE_ES256; /* backwards compat */
438
439
8.53k
        if (!strcmp(cred->fmt, "packed")) {
440
7.30k
                if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh,
441
7.30k
                    &cred->authdata_cbor) < 0) {
442
143
                        fido_log_debug("%s: fido_get_signed_hash", __func__);
443
143
                        r = FIDO_ERR_INTERNAL;
444
143
                        goto out;
445
143
                }
446
7.30k
        } else if (!strcmp(cred->fmt, "fido-u2f")) {
447
450
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
448
450
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
449
450
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
450
29
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
451
29
                        r = FIDO_ERR_INTERNAL;
452
29
                        goto out;
453
29
                }
454
786
        } else if (!strcmp(cred->fmt, "tpm")) {
455
780
                if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
456
780
                    &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
457
75
                        fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
458
75
                        r = FIDO_ERR_INTERNAL;
459
75
                        goto out;
460
75
                }
461
780
        } else {
462
6
                fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
463
6
                r = FIDO_ERR_INVALID_ARGUMENT;
464
6
                goto out;
465
6
        }
466
467
8.28k
        if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
468
8.28k
                fido_log_debug("%s: verify_attstmt", __func__);
469
8.28k
                r = FIDO_ERR_INVALID_SIG;
470
8.28k
                goto out;
471
8.28k
        }
472
473
4
        r = FIDO_OK;
474
44.4k
out:
475
44.4k
        explicit_bzero(buf, sizeof(buf));
476
477
44.4k
        return (r);
478
4
}
479
480
int
481
fido_cred_verify_self(const fido_cred_t *cred)
482
26.0k
{
483
26.0k
        unsigned char   buf[1024]; /* XXX */
484
26.0k
        fido_blob_t     dgst;
485
26.0k
        int             ok = -1;
486
26.0k
        int             r;
487
488
26.0k
        dgst.ptr = buf;
489
26.0k
        dgst.len = sizeof(buf);
490
491
        /* do we have everything we need? */
492
26.0k
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
493
26.0k
            cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
494
26.0k
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
495
26.0k
            cred->rp.id == NULL) {
496
25.6k
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
497
25.6k
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
498
25.6k
                    (void *)cred->authdata_cbor.ptr,
499
25.6k
                    (void *)cred->attstmt.x5c.ptr,
500
25.6k
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
501
25.6k
                    (void *)cred->attcred.id.ptr, cred->rp.id);
502
25.6k
                r = FIDO_ERR_INVALID_ARGUMENT;
503
25.6k
                goto out;
504
25.6k
        }
505
506
360
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
507
108
                fido_log_debug("%s: fido_check_rp_id", __func__);
508
108
                r = FIDO_ERR_INVALID_PARAM;
509
108
                goto out;
510
108
        }
511
512
252
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
513
252
            cred->uv) < 0) {
514
6
                fido_log_debug("%s: fido_check_flags", __func__);
515
6
                r = FIDO_ERR_INVALID_PARAM;
516
6
                goto out;
517
6
        }
518
519
246
        if (check_extensions(&cred->authdata_ext.attr, &cred->ext.attr) != 0) {
520
5
                fido_log_debug("%s: check_extensions", __func__);
521
5
                r = FIDO_ERR_INVALID_PARAM;
522
5
                goto out;
523
5
        }
524
525
241
        if (!strcmp(cred->fmt, "packed")) {
526
208
                if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
527
208
                    &cred->authdata_cbor) < 0) {
528
12
                        fido_log_debug("%s: fido_get_signed_hash", __func__);
529
12
                        r = FIDO_ERR_INTERNAL;
530
12
                        goto out;
531
12
                }
532
208
        } else if (!strcmp(cred->fmt, "fido-u2f")) {
533
29
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
534
29
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
535
29
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
536
0
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
537
0
                        r = FIDO_ERR_INTERNAL;
538
0
                        goto out;
539
0
                }
540
29
        } else {
541
4
                fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
542
4
                r = FIDO_ERR_INVALID_ARGUMENT;
543
4
                goto out;
544
4
        }
545
546
225
        switch (cred->attcred.type) {
547
45
        case COSE_ES256:
548
45
                ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
549
45
                    &cred->attstmt.sig);
550
45
                break;
551
114
        case COSE_ES384:
552
114
                ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384,
553
114
                    &cred->attstmt.sig);
554
114
                break;
555
17
        case COSE_RS256:
556
17
                ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
557
17
                    &cred->attstmt.sig);
558
17
                break;
559
49
        case COSE_EDDSA:
560
49
                ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
561
49
                    &cred->attstmt.sig);
562
49
                break;
563
0
        default:
564
0
                fido_log_debug("%s: unsupported cose_alg %d", __func__,
565
0
                    cred->attcred.type);
566
0
                r = FIDO_ERR_UNSUPPORTED_OPTION;
567
0
                goto out;
568
225
        }
569
570
225
        if (ok < 0)
571
225
                r = FIDO_ERR_INVALID_SIG;
572
0
        else
573
0
                r = FIDO_OK;
574
575
26.0k
out:
576
26.0k
        explicit_bzero(buf, sizeof(buf));
577
578
26.0k
        return (r);
579
225
}
580
581
fido_cred_t *
582
fido_cred_new(void)
583
105k
{
584
105k
        return (calloc(1, sizeof(fido_cred_t)));
585
105k
}
586
587
static void
588
fido_cred_clean_authdata(fido_cred_t *cred)
589
406k
{
590
406k
        fido_blob_reset(&cred->authdata_cbor);
591
406k
        fido_blob_reset(&cred->authdata_raw);
592
406k
        fido_blob_reset(&cred->attcred.id);
593
406k
        fido_blob_reset(&cred->authdata_ext.hmac_secret_enc);
594
595
406k
        memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
596
406k
        memset(&cred->authdata, 0, sizeof(cred->authdata));
597
406k
        memset(&cred->attcred, 0, sizeof(cred->attcred));
598
406k
}
599
600
static void
601
fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
602
310k
{
603
310k
        fido_blob_reset(&attstmt->certinfo);
604
310k
        fido_blob_reset(&attstmt->pubarea);
605
310k
        fido_blob_reset(&attstmt->cbor);
606
310k
        fido_free_blob_array(&attstmt->x5c);
607
310k
        fido_blob_reset(&attstmt->sig);
608
609
310k
        memset(attstmt, 0, sizeof(*attstmt));
610
310k
}
611
612
static void
613
fido_cred_clean_attobj(fido_cred_t *cred)
614
209k
{
615
209k
        free(cred->fmt);
616
209k
        cred->fmt = NULL;
617
209k
        fido_cred_clean_authdata(cred);
618
209k
        fido_cred_clean_attstmt(&cred->attstmt);
619
209k
}
620
621
void
622
fido_cred_reset_tx(fido_cred_t *cred)
623
187k
{
624
187k
        fido_blob_reset(&cred->cd);
625
187k
        fido_blob_reset(&cred->cdh);
626
187k
        fido_blob_reset(&cred->user.id);
627
187k
        fido_blob_reset(&cred->ext.blob);
628
187k
        fido_blob_reset(&cred->ext.hmac_salt);
629
630
187k
        free(cred->rp.id);
631
187k
        free(cred->rp.name);
632
187k
        free(cred->user.icon);
633
187k
        free(cred->user.name);
634
187k
        free(cred->user.display_name);
635
187k
        fido_cred_empty_exclude_list(cred);
636
637
187k
        memset(&cred->rp, 0, sizeof(cred->rp));
638
187k
        memset(&cred->user, 0, sizeof(cred->user));
639
187k
        memset(&cred->ext, 0, sizeof(cred->ext));
640
641
187k
        cred->type = 0;
642
187k
        cred->rk = FIDO_OPT_OMIT;
643
187k
        cred->uv = FIDO_OPT_OMIT;
644
187k
        cred->ea.mode = 0;
645
187k
}
646
647
void
648
fido_cred_reset_rx(fido_cred_t *cred)
649
190k
{
650
190k
        fido_cred_clean_attobj(cred);
651
190k
        fido_blob_reset(&cred->largeblob_key);
652
190k
        fido_blob_reset(&cred->hmac_secret);
653
190k
        cred->ea.att = false;
654
190k
}
655
656
void
657
fido_cred_free(fido_cred_t **cred_p)
658
105k
{
659
105k
        fido_cred_t *cred;
660
661
105k
        if (cred_p == NULL || (cred = *cred_p) == NULL)
662
14
                return;
663
105k
        fido_cred_reset_tx(cred);
664
105k
        fido_cred_reset_rx(cred);
665
105k
        free(cred);
666
105k
        *cred_p = NULL;
667
105k
}
668
669
int
670
fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
671
52.6k
{
672
52.6k
        cbor_item_t             *item = NULL;
673
52.6k
        struct cbor_load_result  cbor;
674
52.6k
        int                      r = FIDO_ERR_INVALID_ARGUMENT;
675
676
52.6k
        fido_cred_clean_authdata(cred);
677
678
52.6k
        if (ptr == NULL || len == 0)
679
47.9k
                goto fail;
680
681
4.61k
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
682
220
                fido_log_debug("%s: cbor_load", __func__);
683
220
                goto fail;
684
220
        }
685
686
4.39k
        if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
687
23
                fido_log_debug("%s: fido_blob_decode", __func__);
688
23
                goto fail;
689
23
        }
690
691
4.37k
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
692
4.37k
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
693
121
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
694
121
                goto fail;
695
121
        }
696
697
4.24k
        r = FIDO_OK;
698
52.6k
fail:
699
52.6k
        if (item != NULL)
700
4.39k
                cbor_decref(&item);
701
702
52.6k
        if (r != FIDO_OK)
703
48.3k
                fido_cred_clean_authdata(cred);
704
705
52.6k
        return (r);
706
4.24k
}
707
708
int
709
fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
710
    size_t len)
711
48.3k
{
712
48.3k
        cbor_item_t     *item = NULL;
713
48.3k
        int              r = FIDO_ERR_INVALID_ARGUMENT;
714
715
48.3k
        fido_cred_clean_authdata(cred);
716
717
48.3k
        if (ptr == NULL || len == 0)
718
47.9k
                goto fail;
719
720
352
        if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
721
1
                fido_log_debug("%s: fido_blob_set", __func__);
722
1
                r = FIDO_ERR_INTERNAL;
723
1
                goto fail;
724
1
        }
725
726
351
        if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
727
0
                fido_log_debug("%s: cbor_build_bytestring", __func__);
728
0
                r = FIDO_ERR_INTERNAL;
729
0
                goto fail;
730
0
        }
731
732
351
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
733
351
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
734
208
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
735
208
                goto fail;
736
208
        }
737
738
143
        r = FIDO_OK;
739
48.3k
fail:
740
48.3k
        if (item != NULL)
741
351
                cbor_decref(&item);
742
743
48.3k
        if (r != FIDO_OK)
744
48.2k
                fido_cred_clean_authdata(cred);
745
746
48.3k
        return (r);
747
143
}
748
749
int
750
fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len)
751
35.1k
{
752
35.1k
        if (fido_blob_set(&cred->attcred.id, ptr, len) < 0)
753
266
                return (FIDO_ERR_INVALID_ARGUMENT);
754
755
34.8k
        return (FIDO_OK);
756
35.1k
}
757
758
int
759
fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
760
74.2k
{
761
74.2k
        fido_blob_t x5c_blob;
762
74.2k
        fido_blob_t *list_ptr = NULL;
763
764
74.2k
        memset(&x5c_blob, 0, sizeof(x5c_blob));
765
74.2k
        fido_free_blob_array(&cred->attstmt.x5c);
766
767
74.2k
        if (fido_blob_set(&x5c_blob, ptr, len) < 0)
768
72.5k
                return (FIDO_ERR_INVALID_ARGUMENT);
769
770
1.71k
        if (cred->attstmt.x5c.len == SIZE_MAX) {
771
0
                fido_blob_reset(&x5c_blob);
772
0
                return (FIDO_ERR_INVALID_ARGUMENT);
773
0
        }
774
775
1.71k
        if ((list_ptr = recallocarray(cred->attstmt.x5c.ptr,
776
1.71k
            cred->attstmt.x5c.len, cred->attstmt.x5c.len + 1,
777
1.71k
            sizeof(x5c_blob))) == NULL) {
778
31
                fido_blob_reset(&x5c_blob);
779
31
                return (FIDO_ERR_INTERNAL);
780
31
        }
781
782
1.68k
        list_ptr[cred->attstmt.x5c.len++] = x5c_blob;
783
1.68k
        cred->attstmt.x5c.ptr = list_ptr;
784
785
1.68k
        return (FIDO_OK);
786
1.71k
}
787
788
int
789
fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
790
74.2k
{
791
74.2k
        if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0)
792
72.2k
                return (FIDO_ERR_INVALID_ARGUMENT);
793
794
2.06k
        return (FIDO_OK);
795
74.2k
}
796
797
int
798
fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
799
52.5k
{
800
52.5k
        cbor_item_t             *item = NULL;
801
52.5k
        struct cbor_load_result  cbor;
802
52.5k
        int                      r = FIDO_ERR_INVALID_ARGUMENT;
803
804
52.5k
        fido_cred_clean_attstmt(&cred->attstmt);
805
806
52.5k
        if (ptr == NULL || len == 0)
807
48.0k
                goto fail;
808
809
4.49k
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
810
27
                fido_log_debug("%s: cbor_load", __func__);
811
27
                goto fail;
812
27
        }
813
814
4.47k
        if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
815
116
                fido_log_debug("%s: cbor_decode_attstmt", __func__);
816
116
                goto fail;
817
116
        }
818
819
4.35k
        r = FIDO_OK;
820
52.5k
fail:
821
52.5k
        if (item != NULL)
822
4.47k
                cbor_decref(&item);
823
824
52.5k
        if (r != FIDO_OK)
825
48.2k
                fido_cred_clean_attstmt(&cred->attstmt);
826
827
52.5k
        return (r);
828
4.35k
}
829
830
int
831
fido_cred_set_attobj(fido_cred_t *cred, const unsigned char *ptr, size_t len)
832
18.3k
{
833
18.3k
        cbor_item_t             *item = NULL;
834
18.3k
        struct cbor_load_result  cbor;
835
18.3k
        int                      r = FIDO_ERR_INVALID_ARGUMENT;
836
837
18.3k
        fido_cred_clean_attobj(cred);
838
839
18.3k
        if (ptr == NULL || len == 0)
840
12
                goto fail;
841
842
18.3k
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
843
704
                fido_log_debug("%s: cbor_load", __func__);
844
704
                goto fail;
845
704
        }
846
17.6k
        if (cbor_decode_attobj(item, cred) != 0) {
847
13.4k
                fido_log_debug("%s: cbor_decode_attobj", __func__);
848
13.4k
                goto fail;
849
13.4k
        }
850
851
4.20k
        r = FIDO_OK;
852
18.3k
fail:
853
18.3k
        if (item != NULL)
854
17.6k
                cbor_decref(&item);
855
856
18.3k
        return (r);
857
4.20k
}
858
859
int
860
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
861
1.07M
{
862
1.07M
        fido_blob_t id_blob;
863
1.07M
        fido_blob_t *list_ptr;
864
865
1.07M
        memset(&id_blob, 0, sizeof(id_blob));
866
867
1.07M
        if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
868
4.61k
                return (FIDO_ERR_INVALID_ARGUMENT);
869
870
1.06M
        if (cred->excl.len == SIZE_MAX) {
871
0
                free(id_blob.ptr);
872
0
                return (FIDO_ERR_INVALID_ARGUMENT);
873
0
        }
874
875
1.06M
        if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
876
1.06M
            cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
877
2.77k
                free(id_blob.ptr);
878
2.77k
                return (FIDO_ERR_INTERNAL);
879
2.77k
        }
880
881
1.06M
        list_ptr[cred->excl.len++] = id_blob;
882
1.06M
        cred->excl.ptr = list_ptr;
883
884
1.06M
        return (FIDO_OK);
885
1.06M
}
886
887
int
888
fido_cred_empty_exclude_list(fido_cred_t *cred)
889
187k
{
890
187k
        fido_free_blob_array(&cred->excl);
891
187k
        memset(&cred->excl, 0, sizeof(cred->excl));
892
893
187k
        return (FIDO_OK);
894
187k
}
895
896
int
897
fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
898
    size_t data_len)
899
0
{
900
0
        if (!fido_blob_is_empty(&cred->cdh) ||
901
0
            fido_blob_set(&cred->cd, data, data_len) < 0) {
902
0
                return (FIDO_ERR_INVALID_ARGUMENT);
903
0
        }
904
0
        if (fido_sha256(&cred->cdh, data, data_len) < 0) {
905
0
                fido_blob_reset(&cred->cd);
906
0
                return (FIDO_ERR_INTERNAL);
907
0
        }
908
909
0
        return (FIDO_OK);
910
0
}
911
912
int
913
fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
914
    size_t hash_len)
915
90.5k
{
916
90.5k
        if (!fido_blob_is_empty(&cred->cd) ||
917
90.5k
            fido_blob_set(&cred->cdh, hash, hash_len) < 0)
918
8.22k
                return (FIDO_ERR_INVALID_ARGUMENT);
919
920
82.3k
        return (FIDO_OK);
921
90.5k
}
922
923
int
924
fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
925
90.5k
{
926
90.5k
        fido_rp_t *rp = &cred->rp;
927
928
90.5k
        if (rp->id != NULL) {
929
22.9k
                free(rp->id);
930
22.9k
                rp->id = NULL;
931
22.9k
        }
932
90.5k
        if (rp->name != NULL) {
933
22.9k
                free(rp->name);
934
22.9k
                rp->name = NULL;
935
22.9k
        }
936
937
90.5k
        if (id != NULL && (rp->id = strdup(id)) == NULL)
938
267
                goto fail;
939
90.2k
        if (name != NULL && (rp->name = strdup(name)) == NULL)
940
209
                goto fail;
941
942
90.0k
        return (FIDO_OK);
943
476
fail:
944
476
        free(rp->id);
945
476
        free(rp->name);
946
476
        rp->id = NULL;
947
476
        rp->name = NULL;
948
949
476
        return (FIDO_ERR_INTERNAL);
950
90.2k
}
951
952
int
953
fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
954
    size_t user_id_len, const char *name, const char *display_name,
955
    const char *icon)
956
55.1k
{
957
55.1k
        fido_user_t *up = &cred->user;
958
959
55.1k
        if (up->id.ptr != NULL) {
960
22.7k
                free(up->id.ptr);
961
22.7k
                up->id.ptr = NULL;
962
22.7k
                up->id.len = 0;
963
22.7k
        }
964
55.1k
        if (up->name != NULL) {
965
22.7k
                free(up->name);
966
22.7k
                up->name = NULL;
967
22.7k
        }
968
55.1k
        if (up->display_name != NULL) {
969
22.7k
                free(up->display_name);
970
22.7k
                up->display_name = NULL;
971
22.7k
        }
972
55.1k
        if (up->icon != NULL) {
973
22.7k
                free(up->icon);
974
22.7k
                up->icon = NULL;
975
22.7k
        }
976
977
55.1k
        if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0)
978
263
                goto fail;
979
54.8k
        if (name != NULL && (up->name = strdup(name)) == NULL)
980
276
                goto fail;
981
54.5k
        if (display_name != NULL &&
982
54.5k
            (up->display_name = strdup(display_name)) == NULL)
983
169
                goto fail;
984
54.4k
        if (icon != NULL && (up->icon = strdup(icon)) == NULL)
985
129
                goto fail;
986
987
54.2k
        return (FIDO_OK);
988
837
fail:
989
837
        free(up->id.ptr);
990
837
        free(up->name);
991
837
        free(up->display_name);
992
837
        free(up->icon);
993
994
837
        up->id.ptr = NULL;
995
837
        up->id.len = 0;
996
837
        up->name = NULL;
997
837
        up->display_name = NULL;
998
837
        up->icon = NULL;
999
1000
837
        return (FIDO_ERR_INTERNAL);
1001
54.4k
}
1002
1003
int
1004
fido_cred_set_hmac_salt(fido_cred_t *cred, const unsigned char *salt,
1005
    size_t salt_len)
1006
23.0k
{
1007
23.0k
        if ((salt_len != 32 && salt_len != 64) ||
1008
23.0k
            fido_blob_set(&cred->ext.hmac_salt, salt, salt_len) < 0)
1009
22.8k
                return (FIDO_ERR_INVALID_ARGUMENT);
1010
1011
249
        return (FIDO_OK);
1012
23.0k
}
1013
1014
int
1015
fido_cred_set_hmac_secret(fido_cred_t *cred,
1016
    const unsigned char *secret, size_t secret_len)
1017
0
{
1018
0
        if ((secret_len != 32 && secret_len != 64) ||
1019
0
            fido_blob_set(&cred->hmac_secret, secret, secret_len) < 0)
1020
0
                return (FIDO_ERR_INVALID_ARGUMENT);
1021
1022
0
        return (FIDO_OK);
1023
0
}
1024
1025
const unsigned char *
1026
fido_cred_hmac_secret_ptr(const fido_cred_t *cred)
1027
26.0k
{
1028
26.0k
        return (cred->hmac_secret.ptr);
1029
26.0k
}
1030
1031
size_t
1032
fido_cred_hmac_secret_len(const fido_cred_t *cred)
1033
26.0k
{
1034
26.0k
        return (cred->hmac_secret.len);
1035
26.0k
}
1036
1037
int
1038
fido_cred_set_extensions(fido_cred_t *cred, int ext)
1039
52.8k
{
1040
52.8k
        if (ext == 0)
1041
1.39k
                cred->ext.attr.mask = 0;
1042
51.4k
        else {
1043
51.4k
                if ((ext & FIDO_EXT_CRED_MASK) != ext)
1044
24.0k
                        return (FIDO_ERR_INVALID_ARGUMENT);
1045
27.3k
                cred->ext.attr.mask |= ext;
1046
27.3k
        }
1047
1048
28.7k
        return (FIDO_OK);
1049
52.8k
}
1050
1051
int
1052
fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
1053
0
{
1054
0
        cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
1055
0
        cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
1056
1057
0
        return (FIDO_OK);
1058
0
}
1059
1060
int
1061
fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
1062
15.5k
{
1063
15.5k
        cred->rk = rk;
1064
1065
15.5k
        return (FIDO_OK);
1066
15.5k
}
1067
1068
int
1069
fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
1070
16.1k
{
1071
16.1k
        cred->uv = uv;
1072
1073
16.1k
        return (FIDO_OK);
1074
16.1k
}
1075
1076
int
1077
fido_cred_set_entattest(fido_cred_t *cred, int ea)
1078
22.1k
{
1079
22.1k
        if (ea != 0 && ea != FIDO_ENTATTEST_VENDOR &&
1080
22.1k
            ea != FIDO_ENTATTEST_PLATFORM)
1081
4.72k
                return (FIDO_ERR_INVALID_ARGUMENT);
1082
1083
17.4k
        cred->ea.mode = ea;
1084
1085
17.4k
        return (FIDO_OK);
1086
22.1k
}
1087
1088
int
1089
fido_cred_set_prot(fido_cred_t *cred, int prot)
1090
50.5k
{
1091
50.5k
        if (prot == 0) {
1092
29.1k
                cred->ext.attr.mask &= ~FIDO_EXT_CRED_PROTECT;
1093
29.1k
                cred->ext.attr.prot = 0;
1094
29.1k
        } else {
1095
21.3k
                if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
1096
21.3k
                    prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
1097
21.3k
                    prot != FIDO_CRED_PROT_UV_REQUIRED)
1098
56
                        return (FIDO_ERR_INVALID_ARGUMENT);
1099
1100
21.3k
                cred->ext.attr.mask |= FIDO_EXT_CRED_PROTECT;
1101
21.3k
                cred->ext.attr.prot = prot;
1102
21.3k
        }
1103
1104
50.4k
        return (FIDO_OK);
1105
50.5k
}
1106
1107
int
1108
fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
1109
32.1k
{
1110
32.1k
        if (len == 0)
1111
23.0k
                cred->ext.attr.mask &= ~FIDO_EXT_MINPINLEN;
1112
9.06k
        else
1113
9.06k
                cred->ext.attr.mask |= FIDO_EXT_MINPINLEN;
1114
1115
32.1k
        cred->ext.attr.minpinlen = len;
1116
1117
32.1k
        return (FIDO_OK);
1118
32.1k
}
1119
1120
int
1121
fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
1122
5.48k
{
1123
5.48k
        if (ptr == NULL || len == 0)
1124
5
                return (FIDO_ERR_INVALID_ARGUMENT);
1125
5.48k
        if (fido_blob_set(&cred->ext.blob, ptr, len) < 0)
1126
12
                return (FIDO_ERR_INTERNAL);
1127
1128
5.47k
        cred->ext.attr.mask |= FIDO_EXT_CRED_BLOB;
1129
1130
5.47k
        return (FIDO_OK);
1131
5.48k
}
1132
1133
int
1134
fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
1135
2.58k
{
1136
2.58k
        free(cred->fmt);
1137
2.58k
        cred->fmt = NULL;
1138
1139
2.58k
        if (fmt == NULL)
1140
0
                return (FIDO_ERR_INVALID_ARGUMENT);
1141
1142
2.58k
        if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
1143
2.58k
            strcmp(fmt, "none") && strcmp(fmt, "tpm"))
1144
0
                return (FIDO_ERR_INVALID_ARGUMENT);
1145
1146
2.58k
        if ((cred->fmt = strdup(fmt)) == NULL)
1147
21
                return (FIDO_ERR_INTERNAL);
1148
1149
2.56k
        return (FIDO_OK);
1150
2.58k
}
1151
1152
int
1153
fido_cred_set_type(fido_cred_t *cred, int cose_alg)
1154
90.5k
{
1155
90.5k
        if (cred->type != 0)
1156
23.0k
                return (FIDO_ERR_INVALID_ARGUMENT);
1157
67.4k
        if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 &&
1158
67.4k
            cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA)
1159
0
                return (FIDO_ERR_INVALID_ARGUMENT);
1160
1161
67.4k
        cred->type = cose_alg;
1162
1163
67.4k
        return (FIDO_OK);
1164
67.4k
}
1165
1166
int
1167
fido_cred_type(const fido_cred_t *cred)
1168
32.0k
{
1169
32.0k
        return (cred->type);
1170
32.0k
}
1171
1172
uint8_t
1173
fido_cred_flags(const fido_cred_t *cred)
1174
26.0k
{
1175
26.0k
        return (cred->authdata.flags);
1176
26.0k
}
1177
1178
uint32_t
1179
fido_cred_sigcount(const fido_cred_t *cred)
1180
26.0k
{
1181
26.0k
        return (cred->authdata.sigcount);
1182
26.0k
}
1183
1184
const unsigned char *
1185
fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
1186
26.1k
{
1187
26.1k
        return (cred->cdh.ptr);
1188
26.1k
}
1189
1190
size_t
1191
fido_cred_clientdata_hash_len(const fido_cred_t *cred)
1192
26.1k
{
1193
26.1k
        return (cred->cdh.len);
1194
26.1k
}
1195
1196
const unsigned char *
1197
fido_cred_x5c_ptr(const fido_cred_t *cred)
1198
26.1k
{
1199
26.1k
        return (fido_cred_x5c_list_ptr(cred, 0));
1200
26.1k
}
1201
1202
size_t
1203
fido_cred_x5c_len(const fido_cred_t *cred)
1204
26.1k
{
1205
26.1k
        return (fido_cred_x5c_list_len(cred, 0));
1206
26.1k
}
1207
1208
size_t
1209
fido_cred_x5c_list_count(const fido_cred_t *cred)
1210
54.2k
{
1211
54.2k
        return (cred->attstmt.x5c.len);
1212
54.2k
}
1213
1214
const unsigned char *
1215
fido_cred_x5c_list_ptr(const fido_cred_t *cred, size_t i)
1216
54.3k
{
1217
54.3k
        if (i >= cred->attstmt.x5c.len)
1218
50.4k
                return (NULL);
1219
1220
3.80k
        return (cred->attstmt.x5c.ptr[i].ptr);
1221
54.3k
}
1222
1223
size_t
1224
fido_cred_x5c_list_len(const fido_cred_t *cred, size_t i)
1225
54.3k
{
1226
54.3k
        if (i >= cred->attstmt.x5c.len)
1227
50.4k
                return (0);
1228
1229
3.80k
        return (cred->attstmt.x5c.ptr[i].len);
1230
54.3k
}
1231
1232
const unsigned char *
1233
fido_cred_sig_ptr(const fido_cred_t *cred)
1234
26.1k
{
1235
26.1k
        return (cred->attstmt.sig.ptr);
1236
26.1k
}
1237
1238
size_t
1239
fido_cred_sig_len(const fido_cred_t *cred)
1240
26.1k
{
1241
26.1k
        return (cred->attstmt.sig.len);
1242
26.1k
}
1243
1244
const unsigned char *
1245
fido_cred_authdata_ptr(const fido_cred_t *cred)
1246
44.5k
{
1247
44.5k
        return (cred->authdata_cbor.ptr);
1248
44.5k
}
1249
1250
size_t
1251
fido_cred_authdata_len(const fido_cred_t *cred)
1252
44.5k
{
1253
44.5k
        return (cred->authdata_cbor.len);
1254
44.5k
}
1255
1256
const unsigned char *
1257
fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
1258
26.1k
{
1259
26.1k
        return (cred->authdata_raw.ptr);
1260
26.1k
}
1261
1262
size_t
1263
fido_cred_authdata_raw_len(const fido_cred_t *cred)
1264
26.1k
{
1265
26.1k
        return (cred->authdata_raw.len);
1266
26.1k
}
1267
1268
const unsigned char *
1269
fido_cred_attstmt_ptr(const fido_cred_t *cred)
1270
44.5k
{
1271
44.5k
        return (cred->attstmt.cbor.ptr);
1272
44.5k
}
1273
1274
size_t
1275
fido_cred_attstmt_len(const fido_cred_t *cred)
1276
44.5k
{
1277
44.5k
        return (cred->attstmt.cbor.len);
1278
44.5k
}
1279
1280
const unsigned char *
1281
fido_cred_pubkey_ptr(const fido_cred_t *cred)
1282
32.0k
{
1283
32.0k
        const void *ptr;
1284
1285
32.0k
        switch (cred->attcred.type) {
1286
3.26k
        case COSE_ES256:
1287
3.26k
                ptr = &cred->attcred.pubkey.es256;
1288
3.26k
                break;
1289
144
        case COSE_ES384:
1290
144
                ptr = &cred->attcred.pubkey.es384;
1291
144
                break;
1292
102
        case COSE_RS256:
1293
102
                ptr = &cred->attcred.pubkey.rs256;
1294
102
                break;
1295
471
        case COSE_EDDSA:
1296
471
                ptr = &cred->attcred.pubkey.eddsa;
1297
471
                break;
1298
28.1k
        default:
1299
28.1k
                ptr = NULL;
1300
28.1k
                break;
1301
32.0k
        }
1302
1303
32.0k
        return (ptr);
1304
32.0k
}
1305
1306
size_t
1307
fido_cred_pubkey_len(const fido_cred_t *cred)
1308
32.0k
{
1309
32.0k
        size_t len;
1310
1311
32.0k
        switch (cred->attcred.type) {
1312
3.26k
        case COSE_ES256:
1313
3.26k
                len = sizeof(cred->attcred.pubkey.es256);
1314
3.26k
                break;
1315
144
        case COSE_ES384:
1316
144
                len = sizeof(cred->attcred.pubkey.es384);
1317
144
                break;
1318
102
        case COSE_RS256:
1319
102
                len = sizeof(cred->attcred.pubkey.rs256);
1320
102
                break;
1321
471
        case COSE_EDDSA:
1322
471
                len = sizeof(cred->attcred.pubkey.eddsa);
1323
471
                break;
1324
28.1k
        default:
1325
28.1k
                len = 0;
1326
28.1k
                break;
1327
32.0k
        }
1328
1329
32.0k
        return (len);
1330
32.0k
}
1331
1332
const unsigned char *
1333
fido_cred_id_ptr(const fido_cred_t *cred)
1334
58.2k
{
1335
58.2k
        return (cred->attcred.id.ptr);
1336
58.2k
}
1337
1338
size_t
1339
fido_cred_id_len(const fido_cred_t *cred)
1340
58.2k
{
1341
58.2k
        return (cred->attcred.id.len);
1342
58.2k
}
1343
1344
const unsigned char *
1345
fido_cred_aaguid_ptr(const fido_cred_t *cred)
1346
26.0k
{
1347
26.0k
        return (cred->attcred.aaguid);
1348
26.0k
}
1349
1350
size_t
1351
fido_cred_aaguid_len(const fido_cred_t *cred)
1352
26.0k
{
1353
26.0k
        return (sizeof(cred->attcred.aaguid));
1354
26.0k
}
1355
1356
int
1357
fido_cred_prot(const fido_cred_t *cred)
1358
32.1k
{
1359
32.1k
        return (cred->ext.attr.prot);
1360
32.1k
}
1361
1362
size_t
1363
fido_cred_pin_minlen(const fido_cred_t *cred)
1364
52.1k
{
1365
52.1k
        return (cred->ext.attr.minpinlen);
1366
52.1k
}
1367
1368
const char *
1369
fido_cred_fmt(const fido_cred_t *cred)
1370
44.5k
{
1371
44.5k
        return (cred->fmt);
1372
44.5k
}
1373
1374
const char *
1375
fido_cred_rp_id(const fido_cred_t *cred)
1376
26.1k
{
1377
26.1k
        return (cred->rp.id);
1378
26.1k
}
1379
1380
const char *
1381
fido_cred_rp_name(const fido_cred_t *cred)
1382
26.1k
{
1383
26.1k
        return (cred->rp.name);
1384
26.1k
}
1385
1386
const char *
1387
fido_cred_user_name(const fido_cred_t *cred)
1388
32.0k
{
1389
32.0k
        return (cred->user.name);
1390
32.0k
}
1391
1392
const char *
1393
fido_cred_display_name(const fido_cred_t *cred)
1394
32.0k
{
1395
32.0k
        return (cred->user.display_name);
1396
32.0k
}
1397
1398
const unsigned char *
1399
fido_cred_user_id_ptr(const fido_cred_t *cred)
1400
32.0k
{
1401
32.0k
        return (cred->user.id.ptr);
1402
32.0k
}
1403
1404
size_t
1405
fido_cred_user_id_len(const fido_cred_t *cred)
1406
32.0k
{
1407
32.0k
        return (cred->user.id.len);
1408
32.0k
}
1409
1410
const unsigned char *
1411
fido_cred_largeblob_key_ptr(const fido_cred_t *cred)
1412
26.0k
{
1413
26.0k
        return (cred->largeblob_key.ptr);
1414
26.0k
}
1415
1416
size_t
1417
fido_cred_largeblob_key_len(const fido_cred_t *cred)
1418
26.0k
{
1419
26.0k
        return (cred->largeblob_key.len);
1420
26.0k
}
1421
1422
bool
1423
fido_cred_entattest(const fido_cred_t *cred)
1424
26.0k
{
1425
26.0k
        return (cred->ea.att);
1426
26.0k
}
1427
1428
/* XXX mainly useful for credentials retrieved via fido_credman_rk() */
1429
bool
1430
fido_cred_payment(const fido_cred_t *cred)
1431
6.05k
{
1432
6.05k
        return (cred->ext.attr.mask & FIDO_EXT_PAYMENT);
1433
6.05k
}