Coverage Report

Created: 2021-03-26 11:35

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