Coverage Report

Created: 2021-07-20 18:14

/libfido2/src/assert.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
3
 * Use of this source code is governed by a BSD-style
4
 * license that can be found in the LICENSE file.
5
 */
6
7
#include <openssl/ecdsa.h>
8
#include <openssl/sha.h>
9
10
#include "fido.h"
11
#include "fido/es256.h"
12
#include "fido/rs256.h"
13
#include "fido/eddsa.h"
14
15
static int
16
adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
17
1.01k
{
18
1.01k
        fido_assert_t   *assert = arg;
19
1.01k
        uint64_t         n;
20
1.01k
21
1.01k
        /* numberOfCredentials; see section 6.2 */
22
1.01k
        if (cbor_isa_uint(key) == false ||
23
1.01k
            cbor_int_get_width(key) != CBOR_INT_8 ||
24
1.01k
            cbor_get_uint8(key) != 5) {
25
861
                fido_log_debug("%s: cbor_type", __func__);
26
861
                return (0); /* ignore */
27
861
        }
28
152
29
152
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
30
1
                fido_log_debug("%s: cbor_decode_uint64", __func__);
31
1
                return (-1);
32
1
        }
33
151
34
151
        if (assert->stmt_len != 0 || assert->stmt_cnt != 1 ||
35
151
            (size_t)n < assert->stmt_cnt) {
36
1
                fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu",
37
1
                    __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n);
38
1
                return (-1);
39
1
        }
40
150
41
150
        if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) {
42
60
                fido_log_debug("%s: fido_assert_set_count", __func__);
43
60
                return (-1);
44
60
        }
45
90
46
90
        assert->stmt_len = 0; /* XXX */
47
90
48
90
        return (0);
49
90
}
50
51
static int
52
parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
53
1.74k
{
54
1.74k
        fido_assert_stmt *stmt = arg;
55
1.74k
56
1.74k
        if (cbor_isa_uint(key) == false ||
57
1.74k
            cbor_int_get_width(key) != CBOR_INT_8) {
58
30
                fido_log_debug("%s: cbor type", __func__);
59
30
                return (0); /* ignore */
60
30
        }
61
1.71k
62
1.71k
        switch (cbor_get_uint8(key)) {
63
494
        case 1: /* credential id */
64
494
                return (cbor_decode_cred_id(val, &stmt->id));
65
422
        case 2: /* authdata */
66
422
                return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor,
67
422
                    &stmt->authdata, &stmt->authdata_ext));
68
384
        case 3: /* signature */
69
384
                return (fido_blob_decode(val, &stmt->sig));
70
326
        case 4: /* user attributes */
71
326
                return (cbor_decode_user(val, &stmt->user));
72
1
        case 7: /* large blob key */
73
1
                return (fido_blob_decode(val, &stmt->largeblob_key));
74
90
        default: /* ignore */
75
90
                fido_log_debug("%s: cbor type", __func__);
76
90
                return (0);
77
1.71k
        }
78
1.71k
}
79
80
static int
81
fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
82
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin)
83
660
{
84
660
        fido_blob_t      f;
85
660
        fido_opt_t       uv = assert->uv;
86
660
        cbor_item_t     *argv[7];
87
660
        const uint8_t    cmd = CTAP_CBOR_ASSERT;
88
660
        int              r;
89
660
90
660
        memset(argv, 0, sizeof(argv));
91
660
        memset(&f, 0, sizeof(f));
92
660
93
660
        /* do we have everything we need? */
94
660
        if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
95
0
                fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
96
0
                    (void *)assert->rp_id, (void *)assert->cdh.ptr);
97
0
                r = FIDO_ERR_INVALID_ARGUMENT;
98
0
                goto fail;
99
0
        }
100
660
101
660
        if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL ||
102
660
            (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) {
103
3
                fido_log_debug("%s: cbor encode", __func__);
104
3
                r = FIDO_ERR_INTERNAL;
105
3
                goto fail;
106
3
        }
107
657
108
657
        /* allowed credentials */
109
657
        if (assert->allow_list.len) {
110
422
                const fido_blob_array_t *cl = &assert->allow_list;
111
422
                if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) {
112
27
                        fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
113
27
                        r = FIDO_ERR_INTERNAL;
114
27
                        goto fail;
115
27
                }
116
630
        }
117
630
118
630
        if (assert->ext.mask)
119
303
                if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh,
120
303
                    pk)) == NULL) {
121
29
                        fido_log_debug("%s: cbor_encode_assert_ext", __func__);
122
29
                        r = FIDO_ERR_INTERNAL;
123
29
                        goto fail;
124
29
                }
125
601
126
601
        /* user verification */
127
601
        if (pin != NULL || (uv == FIDO_OPT_TRUE &&
128
340
            fido_dev_supports_permissions(dev))) {
129
340
                if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
130
340
                    pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) {
131
114
                        fido_log_debug("%s: cbor_add_uv_params", __func__);
132
114
                        goto fail;
133
114
                }
134
226
                uv = FIDO_OPT_OMIT;
135
226
        }
136
601
137
601
        /* options */
138
601
        if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
139
209
                if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) {
140
3
                        fido_log_debug("%s: cbor_encode_assert_opt", __func__);
141
3
                        r = FIDO_ERR_INTERNAL;
142
3
                        goto fail;
143
3
                }
144
484
145
484
        /* frame and transmit */
146
484
        if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
147
484
            fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
148
95
                fido_log_debug("%s: fido_tx", __func__);
149
95
                r = FIDO_ERR_TX;
150
95
                goto fail;
151
95
        }
152
389
153
389
        r = FIDO_OK;
154
660
fail:
155
660
        cbor_vector_free(argv, nitems(argv));
156
660
        free(f.ptr);
157
660
158
660
        return (r);
159
389
}
160
161
static int
162
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
163
389
{
164
389
        unsigned char   reply[FIDO_MAXMSG];
165
389
        int             reply_len;
166
389
        int             r;
167
389
168
389
        fido_assert_reset_rx(assert);
169
389
170
389
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
171
389
            ms)) < 0) {
172
37
                fido_log_debug("%s: fido_rx", __func__);
173
37
                return (FIDO_ERR_RX);
174
37
        }
175
352
176
352
        /* start with room for a single assertion */
177
352
        if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL)
178
352
                return (FIDO_ERR_INTERNAL);
179
351
180
351
        assert->stmt_len = 0;
181
351
        assert->stmt_cnt = 1;
182
351
183
351
        /* adjust as needed */
184
351
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert,
185
351
            adjust_assert_count)) != FIDO_OK) {
186
90
                fido_log_debug("%s: adjust_assert_count", __func__);
187
90
                return (r);
188
90
        }
189
261
190
261
        /* parse the first assertion */
191
261
        if ((r = cbor_parse_reply(reply, (size_t)reply_len,
192
261
            &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
193
47
                fido_log_debug("%s: parse_assert_reply", __func__);
194
47
                return (r);
195
47
        }
196
214
197
214
        assert->stmt_len++;
198
214
199
214
        return (FIDO_OK);
200
214
}
201
202
static int
203
fido_get_next_assert_tx(fido_dev_t *dev)
204
268
{
205
268
        const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT };
206
268
207
268
        if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
208
1
                fido_log_debug("%s: fido_tx", __func__);
209
1
                return (FIDO_ERR_TX);
210
1
        }
211
267
212
267
        return (FIDO_OK);
213
267
}
214
215
static int
216
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
217
267
{
218
267
        unsigned char   reply[FIDO_MAXMSG];
219
267
        int             reply_len;
220
267
        int             r;
221
267
222
267
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
223
267
            ms)) < 0) {
224
8
                fido_log_debug("%s: fido_rx", __func__);
225
8
                return (FIDO_ERR_RX);
226
8
        }
227
259
228
259
        /* sanity check */
229
259
        if (assert->stmt_len >= assert->stmt_cnt) {
230
0
                fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__,
231
0
                    assert->stmt_len, assert->stmt_cnt);
232
0
                return (FIDO_ERR_INTERNAL);
233
0
        }
234
259
235
259
        if ((r = cbor_parse_reply(reply, (size_t)reply_len,
236
259
            &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
237
18
                fido_log_debug("%s: parse_assert_reply", __func__);
238
18
                return (r);
239
18
        }
240
241
241
241
        return (FIDO_OK);
242
241
}
243
244
static int
245
fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
246
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms)
247
660
{
248
660
        int r;
249
660
250
660
        if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK ||
251
660
            (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
252
660
                return (r);
253
214
254
455
        while (assert->stmt_len < assert->stmt_cnt) {
255
268
                if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK ||
256
268
                    (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
257
268
                        return (r);
258
241
                assert->stmt_len++;
259
241
        }
260
214
261
214
        return (FIDO_OK);
262
214
}
263
264
static int
265
decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert,
266
    const fido_blob_t *key)
267
16
{
268
36
        for (size_t i = 0; i < assert->stmt_cnt; i++) {
269
21
                fido_assert_stmt *stmt = &assert->stmt[i];
270
21
                if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) {
271
8
                        if (aes256_cbc_dec(dev, key,
272
8
                            &stmt->authdata_ext.hmac_secret_enc,
273
8
                            &stmt->hmac_secret) < 0) {
274
1
                                fido_log_debug("%s: aes256_cbc_dec %zu",
275
1
                                    __func__, i);
276
1
                                return (-1);
277
1
                        }
278
8
                }
279
21
        }
280
16
281
16
        return (0);
282
16
}
283
284
int
285
fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
286
1.59k
{
287
1.59k
        fido_blob_t     *ecdh = NULL;
288
1.59k
        es256_pk_t      *pk = NULL;
289
1.59k
        int              r;
290
1.59k
291
#ifdef USE_WINHELLO
292
        if (dev->flags & FIDO_DEV_WINHELLO)
293
                return (fido_winhello_get_assert(dev, assert, pin));
294
#endif
295
1.59k
296
1.59k
        if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
297
3
                fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
298
3
                    (void *)assert->rp_id, (void *)assert->cdh.ptr);
299
3
                return (FIDO_ERR_INVALID_ARGUMENT);
300
3
        }
301
1.59k
302
1.59k
        if (fido_dev_is_fido2(dev) == false) {
303
778
                if (pin != NULL || assert->ext.mask != 0)
304
258
                        return (FIDO_ERR_UNSUPPORTED_OPTION);
305
520
                return (u2f_authenticate(dev, assert, -1));
306
520
        }
307
818
308
818
        if (pin != NULL || (assert->uv == FIDO_OPT_TRUE &&
309
373
            fido_dev_supports_permissions(dev)) ||
310
818
            (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
311
553
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
312
158
                        fido_log_debug("%s: fido_do_ecdh", __func__);
313
158
                        goto fail;
314
158
                }
315
660
        }
316
660
317
660
        r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
318
660
        if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET))
319
16
                if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) {
320
1
                        fido_log_debug("%s: decrypt_hmac_secrets", __func__);
321
1
                        r = FIDO_ERR_INTERNAL;
322
1
                        goto fail;
323
1
                }
324
818
325
818
fail:
326
818
        es256_pk_free(&pk);
327
818
        fido_blob_free(&ecdh);
328
818
329
818
        return (r);
330
660
}
331
332
int
333
fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv)
334
567
{
335
567
        fido_log_debug("%s: flags=%02x", __func__, flags);
336
567
        fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv);
337
567
338
567
        if (up == FIDO_OPT_TRUE &&
339
567
            (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) {
340
13
                fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__);
341
13
                return (-1); /* user not present */
342
13
        }
343
554
344
554
        if (uv == FIDO_OPT_TRUE &&
345
554
            (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) {
346
26
                fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__);
347
26
                return (-1); /* user not verified */
348
26
        }
349
528
350
528
        return (0);
351
528
}
352
353
static int
354
check_extensions(int authdata_ext, int ext)
355
429
{
356
429
        /* XXX: largeBlobKey is not part of extensions map */
357
429
        ext &= ~FIDO_EXT_LARGEBLOB_KEY;
358
429
        if (authdata_ext != ext) {
359
22
                fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
360
22
                    authdata_ext, ext);
361
22
                return (-1);
362
22
        }
363
407
364
407
        return (0);
365
407
}
366
367
int
368
fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
369
    const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor)
370
394
{
371
394
        cbor_item_t             *item = NULL;
372
394
        unsigned char           *authdata_ptr = NULL;
373
394
        size_t                   authdata_len;
374
394
        struct cbor_load_result  cbor;
375
394
        SHA256_CTX               ctx;
376
394
        int                      ok = -1;
377
394
378
394
        if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
379
394
            &cbor)) == NULL || cbor_isa_bytestring(item) == false ||
380
394
            cbor_bytestring_is_definite(item) == false) {
381
11
                fido_log_debug("%s: authdata", __func__);
382
11
                goto fail;
383
11
        }
384
383
385
383
        authdata_ptr = cbor_bytestring_handle(item);
386
383
        authdata_len = cbor_bytestring_length(item);
387
383
388
383
        if (cose_alg != COSE_EDDSA) {
389
274
                if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
390
274
                    SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
391
274
                    SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
392
274
                    SHA256_Final(dgst->ptr, &ctx) == 0) {
393
31
                        fido_log_debug("%s: sha256", __func__);
394
31
                        goto fail;
395
31
                }
396
243
                dgst->len = SHA256_DIGEST_LENGTH;
397
243
        } else {
398
109
                if (SIZE_MAX - authdata_len < clientdata->len ||
399
109
                    dgst->len < authdata_len + clientdata->len) {
400
12
                        fido_log_debug("%s: memcpy", __func__);
401
12
                        goto fail;
402
12
                }
403
97
                memcpy(dgst->ptr, authdata_ptr, authdata_len);
404
97
                memcpy(dgst->ptr + authdata_len, clientdata->ptr,
405
97
                    clientdata->len);
406
97
                dgst->len = authdata_len + clientdata->len;
407
97
        }
408
383
409
383
        ok = 0;
410
394
fail:
411
394
        if (item != NULL)
412
394
                cbor_decref(&item);
413
394
414
394
        return (ok);
415
340
}
416
417
int
418
fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
419
    const fido_blob_t *sig)
420
124
{
421
124
        EVP_PKEY        *pkey = NULL;
422
124
        EC_KEY          *ec = NULL;
423
124
        int              ok = -1;
424
124
425
124
        /* ECDSA_verify needs ints */
426
124
        if (dgst->len > INT_MAX || sig->len > INT_MAX) {
427
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
428
0
                    dgst->len, sig->len);
429
0
                return (-1);
430
0
        }
431
124
432
124
        if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
433
124
            (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
434
86
                fido_log_debug("%s: pk -> ec", __func__);
435
86
                goto fail;
436
86
        }
437
38
438
38
        if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
439
38
            (int)sig->len, ec) != 1) {
440
38
                fido_log_debug("%s: ECDSA_verify", __func__);
441
38
                goto fail;
442
38
        }
443
0
444
0
        ok = 0;
445
124
fail:
446
124
        if (pkey != NULL)
447
124
                EVP_PKEY_free(pkey);
448
124
449
124
        return (ok);
450
0
}
451
452
int
453
fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
454
    const fido_blob_t *sig)
455
111
{
456
111
        EVP_PKEY        *pkey = NULL;
457
111
        RSA             *rsa = NULL;
458
111
        int              ok = -1;
459
111
460
111
        /* RSA_verify needs unsigned ints */
461
111
        if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
462
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
463
0
                    dgst->len, sig->len);
464
0
                return (-1);
465
0
        }
466
111
467
111
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
468
111
            (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
469
36
                fido_log_debug("%s: pk -> ec", __func__);
470
36
                goto fail;
471
36
        }
472
75
473
75
        if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
474
75
            (unsigned int)sig->len, rsa) != 1) {
475
75
                fido_log_debug("%s: RSA_verify", __func__);
476
75
                goto fail;
477
75
        }
478
0
479
0
        ok = 0;
480
111
fail:
481
111
        if (pkey != NULL)
482
111
                EVP_PKEY_free(pkey);
483
111
484
111
        return (ok);
485
0
}
486
487
int
488
fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
489
    const fido_blob_t *sig)
490
97
{
491
97
        EVP_PKEY        *pkey = NULL;
492
97
        EVP_MD_CTX      *mdctx = NULL;
493
97
        int              ok = -1;
494
97
495
97
        /* EVP_DigestVerify needs ints */
496
97
        if (dgst->len > INT_MAX || sig->len > INT_MAX) {
497
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
498
0
                    dgst->len, sig->len);
499
0
                return (-1);
500
0
        }
501
97
502
97
        if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
503
4
                fido_log_debug("%s: pk -> pkey", __func__);
504
4
                goto fail;
505
4
        }
506
93
507
93
        if ((mdctx = EVP_MD_CTX_new()) == NULL) {
508
4
                fido_log_debug("%s: EVP_MD_CTX_new", __func__);
509
4
                goto fail;
510
4
        }
511
89
512
89
        if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
513
4
                fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
514
4
                goto fail;
515
4
        }
516
85
517
85
        if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
518
85
            dgst->len) != 1) {
519
85
                fido_log_debug("%s: EVP_DigestVerify", __func__);
520
85
                goto fail;
521
85
        }
522
0
523
0
        ok = 0;
524
97
fail:
525
97
        if (mdctx != NULL)
526
97
                EVP_MD_CTX_free(mdctx);
527
97
528
97
        if (pkey != NULL)
529
97
                EVP_PKEY_free(pkey);
530
97
531
97
        return (ok);
532
0
}
533
534
int
535
fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
536
    const void *pk)
537
34.0k
{
538
34.0k
        unsigned char            buf[1024]; /* XXX */
539
34.0k
        fido_blob_t              dgst;
540
34.0k
        const fido_assert_stmt  *stmt = NULL;
541
34.0k
        int                      ok = -1;
542
34.0k
        int                      r;
543
34.0k
544
34.0k
        dgst.ptr = buf;
545
34.0k
        dgst.len = sizeof(buf);
546
34.0k
547
34.0k
        if (idx >= assert->stmt_len || pk == NULL) {
548
116
                r = FIDO_ERR_INVALID_ARGUMENT;
549
116
                goto out;
550
116
        }
551
33.8k
552
33.8k
        stmt = &assert->stmt[idx];
553
33.8k
554
33.8k
        /* do we have everything we need? */
555
33.8k
        if (assert->cdh.ptr == NULL || assert->rp_id == NULL ||
556
33.8k
            stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) {
557
33.4k
                fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p",
558
33.4k
                    __func__, (void *)assert->cdh.ptr, assert->rp_id,
559
33.4k
                    (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr);
560
33.4k
                r = FIDO_ERR_INVALID_ARGUMENT;
561
33.4k
                goto out;
562
33.4k
        }
563
465
564
465
        if (fido_check_flags(stmt->authdata.flags, assert->up,
565
465
            assert->uv) < 0) {
566
36
                fido_log_debug("%s: fido_check_flags", __func__);
567
36
                r = FIDO_ERR_INVALID_PARAM;
568
36
                goto out;
569
36
        }
570
429
571
429
        if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) {
572
22
                fido_log_debug("%s: check_extensions", __func__);
573
22
                r = FIDO_ERR_INVALID_PARAM;
574
22
                goto out;
575
22
        }
576
407
577
407
        if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) {
578
84
                fido_log_debug("%s: fido_check_rp_id", __func__);
579
84
                r = FIDO_ERR_INVALID_PARAM;
580
84
                goto out;
581
84
        }
582
323
583
323
        if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh,
584
323
            &stmt->authdata_cbor) < 0) {
585
48
                fido_log_debug("%s: fido_get_signed_hash", __func__);
586
48
                r = FIDO_ERR_INTERNAL;
587
48
                goto out;
588
48
        }
589
275
590
275
        switch (cose_alg) {
591
113
        case COSE_ES256:
592
113
                ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig);
593
113
                break;
594
94
        case COSE_RS256:
595
94
                ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig);
596
94
                break;
597
68
        case COSE_EDDSA:
598
68
                ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig);
599
68
                break;
600
0
        default:
601
0
                fido_log_debug("%s: unsupported cose_alg %d", __func__,
602
0
                    cose_alg);
603
0
                r = FIDO_ERR_UNSUPPORTED_OPTION;
604
0
                goto out;
605
275
        }
606
275
607
275
        if (ok < 0)
608
275
                r = FIDO_ERR_INVALID_SIG;
609
275
        else
610
275
                r = FIDO_OK;
611
34.0k
out:
612
34.0k
        explicit_bzero(buf, sizeof(buf));
613
34.0k
614
34.0k
        return (r);
615
275
}
616
617
int
618
fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data,
619
    size_t data_len)
620
0
{
621
0
        if (!fido_blob_is_empty(&assert->cdh) ||
622
0
            fido_blob_set(&assert->cd, data, data_len) < 0) {
623
0
                return (FIDO_ERR_INVALID_ARGUMENT);
624
0
        }
625
0
        if (fido_sha256(&assert->cdh, data, data_len) < 0) {
626
0
                fido_blob_reset(&assert->cd);
627
0
                return (FIDO_ERR_INTERNAL);
628
0
        }
629
0
630
0
        return (FIDO_OK);
631
0
}
632
633
int
634
fido_assert_set_clientdata_hash(fido_assert_t *assert,
635
    const unsigned char *hash, size_t hash_len)
636
37.2k
{
637
37.2k
        if (!fido_blob_is_empty(&assert->cd) ||
638
37.2k
            fido_blob_set(&assert->cdh, hash, hash_len) < 0)
639
366
                return (FIDO_ERR_INVALID_ARGUMENT);
640
36.8k
641
36.8k
        return (FIDO_OK);
642
36.8k
}
643
644
int
645
fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt,
646
    size_t salt_len)
647
3.19k
{
648
3.19k
        if ((salt_len != 32 && salt_len != 64) ||
649
3.19k
            fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0)
650
3.05k
                return (FIDO_ERR_INVALID_ARGUMENT);
651
141
652
141
        return (FIDO_OK);
653
141
}
654
655
int
656
fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx,
657
    const unsigned char *secret, size_t secret_len)
658
0
{
659
0
        if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) ||
660
0
            fido_blob_set(&assert->stmt[idx].hmac_secret, secret,
661
0
            secret_len) < 0)
662
0
                return (FIDO_ERR_INVALID_ARGUMENT);
663
0
664
0
        return (FIDO_OK);
665
0
}
666
667
int
668
fido_assert_set_rp(fido_assert_t *assert, const char *id)
669
37.2k
{
670
37.2k
        if (assert->rp_id != NULL) {
671
1.58k
                free(assert->rp_id);
672
1.58k
                assert->rp_id = NULL;
673
1.58k
        }
674
37.2k
675
37.2k
        if (id == NULL)
676
37.2k
                return (FIDO_ERR_INVALID_ARGUMENT);
677
36.9k
678
36.9k
        if ((assert->rp_id = strdup(id)) == NULL)
679
36.9k
                return (FIDO_ERR_INTERNAL);
680
36.8k
681
36.8k
        return (FIDO_OK);
682
36.8k
}
683
684
int
685
fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr,
686
    size_t len)
687
68.7k
{
688
68.7k
        fido_blob_t      id;
689
68.7k
        fido_blob_t     *list_ptr;
690
68.7k
        int              r;
691
68.7k
692
68.7k
        memset(&id, 0, sizeof(id));
693
68.7k
694
68.7k
        if (assert->allow_list.len == SIZE_MAX) {
695
0
                r = FIDO_ERR_INVALID_ARGUMENT;
696
0
                goto fail;
697
0
        }
698
68.7k
699
68.7k
        if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr =
700
68.5k
            recallocarray(assert->allow_list.ptr, assert->allow_list.len,
701
68.5k
            assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) {
702
436
                r = FIDO_ERR_INVALID_ARGUMENT;
703
436
                goto fail;
704
436
        }
705
68.3k
706
68.3k
        list_ptr[assert->allow_list.len++] = id;
707
68.3k
        assert->allow_list.ptr = list_ptr;
708
68.3k
709
68.3k
        return (FIDO_OK);
710
436
fail:
711
436
        free(id.ptr);
712
436
713
436
        return (r);
714
68.3k
715
68.3k
}
716
717
int
718
fido_assert_set_extensions(fido_assert_t *assert, int ext)
719
35.0k
{
720
35.0k
        if (ext == 0)
721
2.42k
                assert->ext.mask = 0;
722
32.6k
        else {
723
32.6k
                if ((ext & FIDO_EXT_ASSERT_MASK) != ext)
724
31.5k
                        return (FIDO_ERR_INVALID_ARGUMENT);
725
1.08k
                assert->ext.mask |= ext;
726
1.08k
        }
727
35.0k
728
35.0k
        return (FIDO_OK);
729
35.0k
}
730
731
int
732
fido_assert_set_options(fido_assert_t *assert, bool up, bool uv)
733
0
{
734
0
        assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
735
0
        assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
736
0
737
0
        return (FIDO_OK);
738
0
}
739
740
int
741
fido_assert_set_up(fido_assert_t *assert, fido_opt_t up)
742
17.1k
{
743
17.1k
        assert->up = up;
744
17.1k
745
17.1k
        return (FIDO_OK);
746
17.1k
}
747
748
int
749
fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv)
750
924
{
751
924
        assert->uv = uv;
752
924
753
924
        return (FIDO_OK);
754
924
}
755
756
const unsigned char *
757
fido_assert_clientdata_hash_ptr(const fido_assert_t *assert)
758
34.1k
{
759
34.1k
        return (assert->cdh.ptr);
760
34.1k
}
761
762
size_t
763
fido_assert_clientdata_hash_len(const fido_assert_t *assert)
764
34.1k
{
765
34.1k
        return (assert->cdh.len);
766
34.1k
}
767
768
fido_assert_t *
769
fido_assert_new(void)
770
35.9k
{
771
35.9k
        return (calloc(1, sizeof(fido_assert_t)));
772
35.9k
}
773
774
void
775
fido_assert_reset_tx(fido_assert_t *assert)
776
35.8k
{
777
35.8k
        free(assert->rp_id);
778
35.8k
        fido_blob_reset(&assert->cd);
779
35.8k
        fido_blob_reset(&assert->cdh);
780
35.8k
        fido_blob_reset(&assert->ext.hmac_salt);
781
35.8k
        fido_free_blob_array(&assert->allow_list);
782
35.8k
        memset(&assert->ext, 0, sizeof(assert->ext));
783
35.8k
        memset(&assert->allow_list, 0, sizeof(assert->allow_list));
784
35.8k
        assert->rp_id = NULL;
785
35.8k
        assert->up = FIDO_OPT_OMIT;
786
35.8k
        assert->uv = FIDO_OPT_OMIT;
787
35.8k
}
788
789
static void fido_assert_reset_extattr(fido_assert_extattr_t *ext)
790
69.4k
{
791
69.4k
        fido_blob_reset(&ext->hmac_secret_enc);
792
69.4k
        fido_blob_reset(&ext->blob);
793
69.4k
        memset(ext, 0, sizeof(*ext));
794
69.4k
}
795
796
void
797
fido_assert_reset_rx(fido_assert_t *assert)
798
36.2k
{
799
104k
        for (size_t i = 0; i < assert->stmt_cnt; i++) {
800
68.2k
                free(assert->stmt[i].user.icon);
801
68.2k
                free(assert->stmt[i].user.name);
802
68.2k
                free(assert->stmt[i].user.display_name);
803
68.2k
                fido_blob_reset(&assert->stmt[i].user.id);
804
68.2k
                fido_blob_reset(&assert->stmt[i].id);
805
68.2k
                fido_blob_reset(&assert->stmt[i].hmac_secret);
806
68.2k
                fido_blob_reset(&assert->stmt[i].authdata_cbor);
807
68.2k
                fido_blob_reset(&assert->stmt[i].largeblob_key);
808
68.2k
                fido_blob_reset(&assert->stmt[i].sig);
809
68.2k
                fido_assert_reset_extattr(&assert->stmt[i].authdata_ext);
810
68.2k
                memset(&assert->stmt[i], 0, sizeof(assert->stmt[i]));
811
68.2k
        }
812
36.2k
        free(assert->stmt);
813
36.2k
        assert->stmt = NULL;
814
36.2k
        assert->stmt_len = 0;
815
36.2k
        assert->stmt_cnt = 0;
816
36.2k
}
817
818
void
819
fido_assert_free(fido_assert_t **assert_p)
820
35.8k
{
821
35.8k
        fido_assert_t *assert;
822
35.8k
823
35.8k
        if (assert_p == NULL || (assert = *assert_p) == NULL)
824
35.8k
                return;
825
35.8k
        fido_assert_reset_tx(assert);
826
35.8k
        fido_assert_reset_rx(assert);
827
35.8k
        free(assert);
828
35.8k
        *assert_p = NULL;
829
35.8k
}
830
831
size_t
832
fido_assert_count(const fido_assert_t *assert)
833
35.9k
{
834
35.9k
        return (assert->stmt_len);
835
35.9k
}
836
837
const char *
838
fido_assert_rp_id(const fido_assert_t *assert)
839
34.1k
{
840
34.1k
        return (assert->rp_id);
841
34.1k
}
842
843
uint8_t
844
fido_assert_flags(const fido_assert_t *assert, size_t idx)
845
34.1k
{
846
34.1k
        if (idx >= assert->stmt_len)
847
1.84k
                return (0);
848
32.2k
849
32.2k
        return (assert->stmt[idx].authdata.flags);
850
32.2k
}
851
852
uint32_t
853
fido_assert_sigcount(const fido_assert_t *assert, size_t idx)
854
34.1k
{
855
34.1k
        if (idx >= assert->stmt_len)
856
1.84k
                return (0);
857
32.2k
858
32.2k
        return (assert->stmt[idx].authdata.sigcount);
859
32.2k
}
860
861
const unsigned char *
862
fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx)
863
34.1k
{
864
34.1k
        if (idx >= assert->stmt_len)
865
1.84k
                return (NULL);
866
32.2k
867
32.2k
        return (assert->stmt[idx].authdata_cbor.ptr);
868
32.2k
}
869
870
size_t
871
fido_assert_authdata_len(const fido_assert_t *assert, size_t idx)
872
34.1k
{
873
34.1k
        if (idx >= assert->stmt_len)
874
1.84k
                return (0);
875
32.2k
876
32.2k
        return (assert->stmt[idx].authdata_cbor.len);
877
32.2k
}
878
879
const unsigned char *
880
fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx)
881
34.1k
{
882
34.1k
        if (idx >= assert->stmt_len)
883
1.84k
                return (NULL);
884
32.2k
885
32.2k
        return (assert->stmt[idx].sig.ptr);
886
32.2k
}
887
888
size_t
889
fido_assert_sig_len(const fido_assert_t *assert, size_t idx)
890
34.1k
{
891
34.1k
        if (idx >= assert->stmt_len)
892
1.84k
                return (0);
893
32.2k
894
32.2k
        return (assert->stmt[idx].sig.len);
895
32.2k
}
896
897
const unsigned char *
898
fido_assert_id_ptr(const fido_assert_t *assert, size_t idx)
899
34.1k
{
900
34.1k
        if (idx >= assert->stmt_len)
901
1.84k
                return (NULL);
902
32.2k
903
32.2k
        return (assert->stmt[idx].id.ptr);
904
32.2k
}
905
906
size_t
907
fido_assert_id_len(const fido_assert_t *assert, size_t idx)
908
34.1k
{
909
34.1k
        if (idx >= assert->stmt_len)
910
1.84k
                return (0);
911
32.2k
912
32.2k
        return (assert->stmt[idx].id.len);
913
32.2k
}
914
915
const unsigned char *
916
fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx)
917
34.1k
{
918
34.1k
        if (idx >= assert->stmt_len)
919
1.84k
                return (NULL);
920
32.2k
921
32.2k
        return (assert->stmt[idx].user.id.ptr);
922
32.2k
}
923
924
size_t
925
fido_assert_user_id_len(const fido_assert_t *assert, size_t idx)
926
34.1k
{
927
34.1k
        if (idx >= assert->stmt_len)
928
1.84k
                return (0);
929
32.2k
930
32.2k
        return (assert->stmt[idx].user.id.len);
931
32.2k
}
932
933
const char *
934
fido_assert_user_icon(const fido_assert_t *assert, size_t idx)
935
34.1k
{
936
34.1k
        if (idx >= assert->stmt_len)
937
1.84k
                return (NULL);
938
32.2k
939
32.2k
        return (assert->stmt[idx].user.icon);
940
32.2k
}
941
942
const char *
943
fido_assert_user_name(const fido_assert_t *assert, size_t idx)
944
34.1k
{
945
34.1k
        if (idx >= assert->stmt_len)
946
1.84k
                return (NULL);
947
32.2k
948
32.2k
        return (assert->stmt[idx].user.name);
949
32.2k
}
950
951
const char *
952
fido_assert_user_display_name(const fido_assert_t *assert, size_t idx)
953
34.1k
{
954
34.1k
        if (idx >= assert->stmt_len)
955
1.84k
                return (NULL);
956
32.2k
957
32.2k
        return (assert->stmt[idx].user.display_name);
958
32.2k
}
959
960
const unsigned char *
961
fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx)
962
34.1k
{
963
34.1k
        if (idx >= assert->stmt_len)
964
1.84k
                return (NULL);
965
32.2k
966
32.2k
        return (assert->stmt[idx].hmac_secret.ptr);
967
32.2k
}
968
969
size_t
970
fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx)
971
34.1k
{
972
34.1k
        if (idx >= assert->stmt_len)
973
1.84k
                return (0);
974
32.2k
975
32.2k
        return (assert->stmt[idx].hmac_secret.len);
976
32.2k
}
977
978
const unsigned char *
979
fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx)
980
34.1k
{
981
34.1k
        if (idx >= assert->stmt_len)
982
1.84k
                return (NULL);
983
32.2k
984
32.2k
        return (assert->stmt[idx].largeblob_key.ptr);
985
32.2k
}
986
987
size_t
988
fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx)
989
34.1k
{
990
34.1k
        if (idx >= assert->stmt_len)
991
1.84k
                return (0);
992
32.2k
993
32.2k
        return (assert->stmt[idx].largeblob_key.len);
994
32.2k
}
995
996
const unsigned char *
997
fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx)
998
34.1k
{
999
34.1k
        if (idx >= assert->stmt_len)
1000
1.84k
                return (NULL);
1001
32.2k
1002
32.2k
        return (assert->stmt[idx].authdata_ext.blob.ptr);
1003
32.2k
}
1004
1005
size_t
1006
fido_assert_blob_len(const fido_assert_t *assert, size_t idx)
1007
34.1k
{
1008
34.1k
        if (idx >= assert->stmt_len)
1009
1.84k
                return (0);
1010
32.2k
1011
32.2k
        return (assert->stmt[idx].authdata_ext.blob.len);
1012
32.2k
}
1013
1014
static void
1015
fido_assert_clean_authdata(fido_assert_stmt *stmt)
1016
1.26k
{
1017
1.26k
        fido_blob_reset(&stmt->authdata_cbor);
1018
1.26k
        fido_assert_reset_extattr(&stmt->authdata_ext);
1019
1.26k
        memset(&stmt->authdata, 0, sizeof(stmt->authdata));
1020
1.26k
}
1021
1022
int
1023
fido_assert_set_authdata(fido_assert_t *assert, size_t idx,
1024
    const unsigned char *ptr, size_t len)
1025
68.1k
{
1026
68.1k
        cbor_item_t             *item = NULL;
1027
68.1k
        fido_assert_stmt        *stmt = NULL;
1028
68.1k
        struct cbor_load_result  cbor;
1029
68.1k
        int                      r;
1030
68.1k
1031
68.1k
        if (idx >= assert->stmt_len || ptr == NULL || len == 0)
1032
66.9k
                return (FIDO_ERR_INVALID_ARGUMENT);
1033
1.14k
1034
1.14k
        stmt = &assert->stmt[idx];
1035
1.14k
        fido_assert_clean_authdata(stmt);
1036
1.14k
1037
1.14k
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
1038
18
                fido_log_debug("%s: cbor_load", __func__);
1039
18
                r = FIDO_ERR_INVALID_ARGUMENT;
1040
18
                goto fail;
1041
18
        }
1042
1.12k
1043
1.12k
        if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
1044
1.12k
            &stmt->authdata, &stmt->authdata_ext) < 0) {
1045
27
                fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
1046
27
                r = FIDO_ERR_INVALID_ARGUMENT;
1047
27
                goto fail;
1048
27
        }
1049
1.10k
1050
1.10k
        r = FIDO_OK;
1051
1.14k
fail:
1052
1.14k
        if (item != NULL)
1053
1.14k
                cbor_decref(&item);
1054
1.14k
1055
1.14k
        if (r != FIDO_OK)
1056
1.14k
                fido_assert_clean_authdata(stmt);
1057
1.14k
1058
1.14k
        return (r);
1059
1.10k
}
1060
1061
int
1062
fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx,
1063
    const unsigned char *ptr, size_t len)
1064
67.0k
{
1065
67.0k
        cbor_item_t             *item = NULL;
1066
67.0k
        fido_assert_stmt        *stmt = NULL;
1067
67.0k
        int                      r;
1068
67.0k
1069
67.0k
        if (idx >= assert->stmt_len || ptr == NULL || len == 0)
1070
66.9k
                return (FIDO_ERR_INVALID_ARGUMENT);
1071
44
1072
44
        stmt = &assert->stmt[idx];
1073
44
        fido_assert_clean_authdata(stmt);
1074
44
1075
44
        if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
1076
1
                fido_log_debug("%s: cbor_build_bytestring", __func__);
1077
1
                r = FIDO_ERR_INTERNAL;
1078
1
                goto fail;
1079
1
        }
1080
43
1081
43
        if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
1082
43
            &stmt->authdata, &stmt->authdata_ext) < 0) {
1083
32
                fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
1084
32
                r = FIDO_ERR_INVALID_ARGUMENT;
1085
32
                goto fail;
1086
32
        }
1087
11
1088
11
        r = FIDO_OK;
1089
44
fail:
1090
44
        if (item != NULL)
1091
44
                cbor_decref(&item);
1092
44
1093
44
        if (r != FIDO_OK)
1094
44
                fido_assert_clean_authdata(stmt);
1095
44
1096
44
        return (r);
1097
11
}
1098
1099
int
1100
fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
1101
    size_t len)
1102
68.1k
{
1103
68.1k
        if (idx >= a->stmt_len || ptr == NULL || len == 0)
1104
67.0k
                return (FIDO_ERR_INVALID_ARGUMENT);
1105
1.09k
        if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0)
1106
14
                return (FIDO_ERR_INTERNAL);
1107
1.07k
1108
1.07k
        return (FIDO_OK);
1109
1.07k
}
1110
1111
/* XXX shrinking leaks memory; fortunately that shouldn't happen */
1112
int
1113
fido_assert_set_count(fido_assert_t *assert, size_t n)
1114
34.6k
{
1115
34.6k
        void *new_stmt;
1116
34.6k
1117
34.6k
#ifdef FIDO_FUZZ
1118
34.6k
        if (n > UINT8_MAX) {
1119
60
                fido_log_debug("%s: n > UINT8_MAX", __func__);
1120
60
                return (FIDO_ERR_INTERNAL);
1121
60
        }
1122
34.5k
#endif
1123
34.5k
1124
34.5k
        new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n,
1125
34.5k
            sizeof(fido_assert_stmt));
1126
34.5k
        if (new_stmt == NULL)
1127
34.5k
                return (FIDO_ERR_INTERNAL);
1128
34.4k
1129
34.4k
        assert->stmt = new_stmt;
1130
34.4k
        assert->stmt_cnt = n;
1131
34.4k
        assert->stmt_len = n;
1132
34.4k
1133
34.4k
        return (FIDO_OK);
1134
34.4k
}