Coverage Report

Created: 2020-03-07 10:10

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