Coverage Report

Created: 2020-09-01 07:05

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