Coverage Report

Created: 2020-12-02 17:02

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