Coverage Report

Created: 2020-12-02 17:02

/libfido2/src/cred.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/evp.h>
9
#include <openssl/sha.h>
10
#include <openssl/x509.h>
11
12
#include <string.h>
13
#include "fido.h"
14
#include "fido/es256.h"
15
16
static int
17
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
18
989
{
19
989
        fido_cred_t *cred = arg;
20
989
21
989
        if (cbor_isa_uint(key) == false ||
22
989
            cbor_int_get_width(key) != CBOR_INT_8) {
23
15
                fido_log_debug("%s: cbor type", __func__);
24
15
                return (0); /* ignore */
25
15
        }
26
974
27
974
        switch (cbor_get_uint8(key)) {
28
408
        case 1: /* fmt */
29
408
                return (cbor_decode_fmt(val, &cred->fmt));
30
372
        case 2: /* authdata */
31
372
                if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
32
1
                        fido_log_debug("%s: fido_blob_decode", __func__);
33
1
                        return (-1);
34
1
                }
35
371
                return (cbor_decode_cred_authdata(val, cred->type,
36
371
                    &cred->authdata_cbor, &cred->authdata, &cred->attcred,
37
371
                    &cred->authdata_ext));
38
371
        case 3: /* attestation statement */
39
183
                return (cbor_decode_attstmt(val, &cred->attstmt));
40
371
        default: /* ignore */
41
11
                fido_log_debug("%s: cbor type", __func__);
42
11
                return (0);
43
974
        }
44
974
}
45
46
static int
47
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
48
867
{
49
867
        fido_blob_t      f;
50
867
        fido_blob_t     *ecdh = NULL;
51
867
        es256_pk_t      *pk = NULL;
52
867
        cbor_item_t     *argv[9];
53
867
        int              r;
54
867
55
867
        memset(&f, 0, sizeof(f));
56
867
        memset(argv, 0, sizeof(argv));
57
867
58
867
        if (cred->cdh.ptr == NULL || cred->type == 0) {
59
2
                fido_log_debug("%s: cdh=%p, type=%d", __func__,
60
2
                    (void *)cred->cdh.ptr, cred->type);
61
2
                r = FIDO_ERR_INVALID_ARGUMENT;
62
2
                goto fail;
63
2
        }
64
865
65
865
        if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
66
865
            (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
67
865
            (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
68
865
            (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
69
40
                fido_log_debug("%s: cbor encode", __func__);
70
40
                r = FIDO_ERR_INTERNAL;
71
40
                goto fail;
72
40
        }
73
825
74
825
        /* excluded credentials */
75
825
        if (cred->excl.len)
76
564
                if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
77
41
                        fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
78
41
                        r = FIDO_ERR_INTERNAL;
79
41
                        goto fail;
80
41
                }
81
784
82
784
        /* extensions */
83
784
        if (cred->ext.mask)
84
440
                if ((argv[5] = cbor_encode_extensions(&cred->ext)) == NULL) {
85
5
                        fido_log_debug("%s: cbor_encode_extensions", __func__);
86
5
                        r = FIDO_ERR_INTERNAL;
87
5
                        goto fail;
88
5
                }
89
779
90
779
        /* options */
91
779
        if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT)
92
436
                if ((argv[6] = cbor_encode_options(cred->rk,
93
436
                    cred->uv)) == NULL) {
94
4
                        fido_log_debug("%s: cbor_encode_options", __func__);
95
4
                        r = FIDO_ERR_INTERNAL;
96
4
                        goto fail;
97
4
                }
98
775
99
775
        /* pin authentication */
100
775
        if (pin) {
101
639
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
102
172
                        fido_log_debug("%s: fido_do_ecdh", __func__);
103
172
                        goto fail;
104
172
                }
105
467
                if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin,
106
467
                    &argv[7], &argv[8])) != FIDO_OK) {
107
82
                        fido_log_debug("%s: cbor_add_pin_params", __func__);
108
82
                        goto fail;
109
82
                }
110
521
        }
111
521
112
521
        /* framing and transmission */
113
521
        if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
114
521
            fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
115
61
                fido_log_debug("%s: fido_tx", __func__);
116
61
                r = FIDO_ERR_TX;
117
61
                goto fail;
118
61
        }
119
460
120
460
        r = FIDO_OK;
121
867
fail:
122
867
        es256_pk_free(&pk);
123
867
        fido_blob_free(&ecdh);
124
867
        cbor_vector_free(argv, nitems(argv));
125
867
        free(f.ptr);
126
867
127
867
        return (r);
128
460
}
129
130
static int
131
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
132
460
{
133
460
        unsigned char   reply[FIDO_MAXMSG];
134
460
        int             reply_len;
135
460
        int             r;
136
460
137
460
        fido_cred_reset_rx(cred);
138
460
139
460
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
140
460
            ms)) < 0) {
141
32
                fido_log_debug("%s: fido_rx", __func__);
142
32
                return (FIDO_ERR_RX);
143
32
        }
144
428
145
428
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
146
428
            parse_makecred_reply)) != FIDO_OK) {
147
288
                fido_log_debug("%s: parse_makecred_reply", __func__);
148
288
                return (r);
149
288
        }
150
140
151
140
        if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
152
140
            fido_blob_is_empty(&cred->attcred.id) ||
153
140
            fido_blob_is_empty(&cred->attstmt.sig)) {
154
30
                fido_cred_reset_rx(cred);
155
30
                return (FIDO_ERR_INVALID_CBOR);
156
30
        }
157
110
158
110
        return (FIDO_OK);
159
110
}
160
161
static int
162
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms)
163
867
{
164
867
        int  r;
165
867
166
867
        if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK ||
167
867
            (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
168
867
                return (r);
169
110
170
110
        return (FIDO_OK);
171
110
}
172
173
int
174
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
175
1.57k
{
176
1.57k
        if (fido_dev_is_fido2(dev) == false) {
177
709
                if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
178
709
                    cred->ext.mask != 0)
179
410
                        return (FIDO_ERR_UNSUPPORTED_OPTION);
180
299
                return (u2f_register(dev, cred, -1));
181
299
        }
182
867
183
867
        return (fido_dev_make_cred_wait(dev, cred, pin, -1));
184
867
}
185
186
static int
187
check_extensions(const fido_cred_ext_t *authdata_ext, const fido_cred_ext_t *ext)
188
91
{
189
91
        return (timingsafe_bcmp(authdata_ext, ext, sizeof(*authdata_ext)));
190
91
}
191
192
int
193
fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
194
500
{
195
500
        unsigned char expected_hash[SHA256_DIGEST_LENGTH];
196
500
197
500
        explicit_bzero(expected_hash, sizeof(expected_hash));
198
500
199
500
        if (SHA256((const unsigned char *)id, strlen(id),
200
500
            expected_hash) != expected_hash) {
201
14
                fido_log_debug("%s: sha256", __func__);
202
14
                return (-1);
203
14
        }
204
486
205
486
        return (timingsafe_bcmp(expected_hash, obtained_hash,
206
486
            SHA256_DIGEST_LENGTH));
207
486
}
208
209
static int
210
get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
211
    size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
212
    const es256_pk_t *pk)
213
24
{
214
24
        const uint8_t           zero = 0;
215
24
        const uint8_t           four = 4; /* uncompressed point */
216
24
        SHA256_CTX              ctx;
217
24
218
24
        if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
219
24
            SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 ||
220
24
            SHA256_Update(&ctx, rp_id, rp_id_len) == 0 ||
221
24
            SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
222
24
            SHA256_Update(&ctx, id->ptr, id->len) == 0 ||
223
24
            SHA256_Update(&ctx, &four, sizeof(four)) == 0 ||
224
24
            SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 ||
225
24
            SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 ||
226
24
            SHA256_Final(dgst->ptr, &ctx) == 0) {
227
10
                fido_log_debug("%s: sha256", __func__);
228
10
                return (-1);
229
10
        }
230
14
231
14
        return (0);
232
14
}
233
234
static int
235
verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
236
    const fido_blob_t *sig)
237
22
{
238
22
        BIO             *rawcert = NULL;
239
22
        X509            *cert = NULL;
240
22
        EVP_PKEY        *pkey = NULL;
241
22
        EC_KEY          *ec;
242
22
        int              ok = -1;
243
22
244
22
        /* openssl needs ints */
245
22
        if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
246
0
                fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
247
0
                    __func__, dgst->len, x5c->len, sig->len);
248
0
                return (-1);
249
0
        }
250
22
251
22
        /* fetch key from x509 */
252
22
        if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
253
22
            (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
254
22
            (pkey = X509_get_pubkey(cert)) == NULL ||
255
22
            (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
256
10
                fido_log_debug("%s: x509 key", __func__);
257
10
                goto fail;
258
10
        }
259
12
260
12
        if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
261
12
            (int)sig->len, ec) != 1) {
262
12
                fido_log_debug("%s: ECDSA_verify", __func__);
263
12
                goto fail;
264
12
        }
265
0
266
0
        ok = 0;
267
22
fail:
268
22
        if (rawcert != NULL)
269
22
                BIO_free(rawcert);
270
22
        if (cert != NULL)
271
22
                X509_free(cert);
272
22
        if (pkey != NULL)
273
22
                EVP_PKEY_free(pkey);
274
22
275
22
        return (ok);
276
0
}
277
278
int
279
fido_cred_verify(const fido_cred_t *cred)
280
1.68k
{
281
1.68k
        unsigned char   buf[SHA256_DIGEST_LENGTH];
282
1.68k
        fido_blob_t     dgst;
283
1.68k
        int             r;
284
1.68k
285
1.68k
        dgst.ptr = buf;
286
1.68k
        dgst.len = sizeof(buf);
287
1.68k
288
1.68k
        /* do we have everything we need? */
289
1.68k
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
290
1.68k
            cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
291
1.68k
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
292
1.68k
            cred->rp.id == NULL) {
293
1.61k
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
294
1.61k
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
295
1.61k
                    (void *)cred->authdata_cbor.ptr,
296
1.61k
                    (void *)cred->attstmt.x5c.ptr,
297
1.61k
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
298
1.61k
                    (void *)cred->attcred.id.ptr, cred->rp.id);
299
1.61k
                r = FIDO_ERR_INVALID_ARGUMENT;
300
1.61k
                goto out;
301
1.61k
        }
302
70
303
70
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
304
35
                fido_log_debug("%s: fido_check_rp_id", __func__);
305
35
                r = FIDO_ERR_INVALID_PARAM;
306
35
                goto out;
307
35
        }
308
35
309
35
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
310
35
            cred->uv) < 0) {
311
2
                fido_log_debug("%s: fido_check_flags", __func__);
312
2
                r = FIDO_ERR_INVALID_PARAM;
313
2
                goto out;
314
2
        }
315
33
316
33
        if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
317
1
                fido_log_debug("%s: check_extensions", __func__);
318
1
                r = FIDO_ERR_INVALID_PARAM;
319
1
                goto out;
320
1
        }
321
32
322
32
        if (!strcmp(cred->fmt, "packed")) {
323
9
                if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh,
324
9
                    &cred->authdata_cbor) < 0) {
325
1
                        fido_log_debug("%s: fido_get_signed_hash", __func__);
326
1
                        r = FIDO_ERR_INTERNAL;
327
1
                        goto out;
328
1
                }
329
23
        } else {
330
23
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
331
23
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
332
23
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
333
9
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
334
9
                        r = FIDO_ERR_INTERNAL;
335
9
                        goto out;
336
9
                }
337
22
        }
338
22
339
22
        if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) {
340
22
                fido_log_debug("%s: verify_sig", __func__);
341
22
                r = FIDO_ERR_INVALID_SIG;
342
22
                goto out;
343
22
        }
344
0
345
0
        r = FIDO_OK;
346
1.68k
out:
347
1.68k
        explicit_bzero(buf, sizeof(buf));
348
1.68k
349
1.68k
        return (r);
350
0
}
351
352
int
353
fido_cred_verify_self(const fido_cred_t *cred)
354
1.68k
{
355
1.68k
        unsigned char   buf[1024]; /* XXX */
356
1.68k
        fido_blob_t     dgst;
357
1.68k
        int             ok = -1;
358
1.68k
        int             r;
359
1.68k
360
1.68k
        dgst.ptr = buf;
361
1.68k
        dgst.len = sizeof(buf);
362
1.68k
363
1.68k
        /* do we have everything we need? */
364
1.68k
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
365
1.68k
            cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
366
1.68k
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
367
1.68k
            cred->rp.id == NULL) {
368
1.60k
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
369
1.60k
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
370
1.60k
                    (void *)cred->authdata_cbor.ptr,
371
1.60k
                    (void *)cred->attstmt.x5c.ptr,
372
1.60k
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
373
1.60k
                    (void *)cred->attcred.id.ptr, cred->rp.id);
374
1.60k
                r = FIDO_ERR_INVALID_ARGUMENT;
375
1.60k
                goto out;
376
1.60k
        }
377
77
378
77
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
379
18
                fido_log_debug("%s: fido_check_rp_id", __func__);
380
18
                r = FIDO_ERR_INVALID_PARAM;
381
18
                goto out;
382
18
        }
383
59
384
59
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
385
59
            cred->uv) < 0) {
386
1
                fido_log_debug("%s: fido_check_flags", __func__);
387
1
                r = FIDO_ERR_INVALID_PARAM;
388
1
                goto out;
389
1
        }
390
58
391
58
        if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
392
1
                fido_log_debug("%s: check_extensions", __func__);
393
1
                r = FIDO_ERR_INVALID_PARAM;
394
1
                goto out;
395
1
        }
396
57
397
57
        if (!strcmp(cred->fmt, "packed")) {
398
56
                if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
399
56
                    &cred->authdata_cbor) < 0) {
400
5
                        fido_log_debug("%s: fido_get_signed_hash", __func__);
401
5
                        r = FIDO_ERR_INTERNAL;
402
5
                        goto out;
403
5
                }
404
1
        } else {
405
1
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
406
1
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
407
1
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
408
1
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
409
1
                        r = FIDO_ERR_INTERNAL;
410
1
                        goto out;
411
1
                }
412
51
        }
413
51
414
51
        switch (cred->attcred.type) {
415
9
        case COSE_ES256:
416
9
                ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256,
417
9
                    &cred->attstmt.sig);
418
9
                break;
419
17
        case COSE_RS256:
420
17
                ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256,
421
17
                    &cred->attstmt.sig);
422
17
                break;
423
25
        case COSE_EDDSA:
424
25
                ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa,
425
25
                    &cred->attstmt.sig);
426
25
                break;
427
0
        default:
428
0
                fido_log_debug("%s: unsupported cose_alg %d", __func__,
429
0
                    cred->attcred.type);
430
0
                r = FIDO_ERR_UNSUPPORTED_OPTION;
431
0
                goto out;
432
51
        }
433
51
434
51
        if (ok < 0)
435
51
                r = FIDO_ERR_INVALID_SIG;
436
51
        else
437
51
                r = FIDO_OK;
438
51
439
1.68k
out:
440
1.68k
        explicit_bzero(buf, sizeof(buf));
441
1.68k
442
1.68k
        return (r);
443
51
}
444
445
fido_cred_t *
446
fido_cred_new(void)
447
3.41k
{
448
3.41k
        return (calloc(1, sizeof(fido_cred_t)));
449
3.41k
}
450
451
static void
452
fido_cred_clean_authdata(fido_cred_t *cred)
453
23.9k
{
454
23.9k
        free(cred->authdata_cbor.ptr);
455
23.9k
        free(cred->authdata_raw.ptr);
456
23.9k
        free(cred->attcred.id.ptr);
457
23.9k
458
23.9k
        memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
459
23.9k
        memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor));
460
23.9k
        memset(&cred->authdata_raw, 0, sizeof(cred->authdata_raw));
461
23.9k
        memset(&cred->authdata, 0, sizeof(cred->authdata));
462
23.9k
        memset(&cred->attcred, 0, sizeof(cred->attcred));
463
23.9k
}
464
465
void
466
fido_cred_reset_tx(fido_cred_t *cred)
467
11.0k
{
468
11.0k
        free(cred->cdh.ptr);
469
11.0k
        free(cred->rp.id);
470
11.0k
        free(cred->rp.name);
471
11.0k
        free(cred->user.id.ptr);
472
11.0k
        free(cred->user.icon);
473
11.0k
        free(cred->user.name);
474
11.0k
        free(cred->user.display_name);
475
11.0k
        fido_free_blob_array(&cred->excl);
476
11.0k
477
11.0k
        memset(&cred->cdh, 0, sizeof(cred->cdh));
478
11.0k
        memset(&cred->rp, 0, sizeof(cred->rp));
479
11.0k
        memset(&cred->user, 0, sizeof(cred->user));
480
11.0k
        memset(&cred->excl, 0, sizeof(cred->excl));
481
11.0k
        memset(&cred->ext, 0, sizeof(cred->ext));
482
11.0k
483
11.0k
        cred->type = 0;
484
11.0k
        cred->rk = FIDO_OPT_OMIT;
485
11.0k
        cred->uv = FIDO_OPT_OMIT;
486
11.0k
}
487
488
static void
489
fido_cred_clean_x509(fido_cred_t *cred)
490
14.9k
{
491
14.9k
        free(cred->attstmt.x5c.ptr);
492
14.9k
        cred->attstmt.x5c.ptr = NULL;
493
14.9k
        cred->attstmt.x5c.len = 0;
494
14.9k
}
495
496
static void
497
fido_cred_clean_sig(fido_cred_t *cred)
498
14.9k
{
499
14.9k
        free(cred->attstmt.sig.ptr);
500
14.9k
        cred->attstmt.sig.ptr = NULL;
501
14.9k
        cred->attstmt.sig.len = 0;
502
14.9k
}
503
504
void
505
fido_cred_reset_rx(fido_cred_t *cred)
506
11.5k
{
507
11.5k
        free(cred->fmt);
508
11.5k
        cred->fmt = NULL;
509
11.5k
510
11.5k
        fido_cred_clean_authdata(cred);
511
11.5k
        fido_cred_clean_x509(cred);
512
11.5k
        fido_cred_clean_sig(cred);
513
11.5k
}
514
515
void
516
fido_cred_free(fido_cred_t **cred_p)
517
3.38k
{
518
3.38k
        fido_cred_t *cred;
519
3.38k
520
3.38k
        if (cred_p == NULL || (cred = *cred_p) == NULL)
521
3.38k
                return;
522
3.38k
523
3.38k
        fido_cred_reset_tx(cred);
524
3.38k
        fido_cred_reset_rx(cred);
525
3.38k
526
3.38k
        free(cred);
527
3.38k
528
3.38k
        *cred_p = NULL;
529
3.38k
}
530
531
int
532
fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
533
3.40k
{
534
3.40k
        cbor_item_t             *item = NULL;
535
3.40k
        struct cbor_load_result  cbor;
536
3.40k
        int                      r = FIDO_ERR_INVALID_ARGUMENT;
537
3.40k
538
3.40k
        fido_cred_clean_authdata(cred);
539
3.40k
540
3.40k
        if (ptr == NULL || len == 0)
541
2.65k
                goto fail;
542
743
543
743
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
544
19
                fido_log_debug("%s: cbor_load", __func__);
545
19
                goto fail;
546
19
        }
547
724
548
724
        if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
549
15
                fido_log_debug("%s: fido_blob_decode", __func__);
550
15
                goto fail;
551
15
        }
552
709
553
709
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
554
709
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
555
298
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
556
298
                goto fail;
557
298
        }
558
411
559
411
        r = FIDO_OK;
560
3.40k
fail:
561
3.40k
        if (item != NULL)
562
3.40k
                cbor_decref(&item);
563
3.40k
564
3.40k
        if (r != FIDO_OK)
565
3.40k
                fido_cred_clean_authdata(cred);
566
3.40k
567
3.40k
        return (r);
568
411
569
411
}
570
571
int
572
fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
573
    size_t len)
574
2.98k
{
575
2.98k
        cbor_item_t     *item = NULL;
576
2.98k
        int              r = FIDO_ERR_INVALID_ARGUMENT;
577
2.98k
578
2.98k
        fido_cred_clean_authdata(cred);
579
2.98k
580
2.98k
        if (ptr == NULL || len == 0)
581
2.64k
                goto fail;
582
343
583
343
        if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
584
7
                fido_log_debug("%s: fido_blob_set", __func__);
585
7
                r = FIDO_ERR_INTERNAL;
586
7
                goto fail;
587
7
        }
588
336
589
336
        if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
590
6
                fido_log_debug("%s: cbor_build_bytestring", __func__);
591
6
                r = FIDO_ERR_INTERNAL;
592
6
                goto fail;
593
6
        }
594
330
595
330
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
596
330
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
597
314
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
598
314
                goto fail;
599
314
        }
600
16
601
16
        r = FIDO_OK;
602
2.98k
fail:
603
2.98k
        if (item != NULL)
604
2.98k
                cbor_decref(&item);
605
2.98k
606
2.98k
        if (r != FIDO_OK)
607
2.98k
                fido_cred_clean_authdata(cred);
608
2.98k
609
2.98k
        return (r);
610
16
611
16
}
612
613
int
614
fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
615
3.39k
{
616
3.39k
        unsigned char *x509;
617
3.39k
618
3.39k
        fido_cred_clean_x509(cred);
619
3.39k
620
3.39k
        if (ptr == NULL || len == 0)
621
3.18k
                return (FIDO_ERR_INVALID_ARGUMENT);
622
211
        if ((x509 = malloc(len)) == NULL)
623
211
                return (FIDO_ERR_INTERNAL);
624
200
625
200
        memcpy(x509, ptr, len);
626
200
        cred->attstmt.x5c.ptr = x509;
627
200
        cred->attstmt.x5c.len = len;
628
200
629
200
        return (FIDO_OK);
630
200
}
631
632
int
633
fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
634
3.39k
{
635
3.39k
        unsigned char *sig;
636
3.39k
637
3.39k
        fido_cred_clean_sig(cred);
638
3.39k
639
3.39k
        if (ptr == NULL || len == 0)
640
3.04k
                return (FIDO_ERR_INVALID_ARGUMENT);
641
354
        if ((sig = malloc(len)) == NULL)
642
354
                return (FIDO_ERR_INTERNAL);
643
349
644
349
        memcpy(sig, ptr, len);
645
349
        cred->attstmt.sig.ptr = sig;
646
349
        cred->attstmt.sig.len = len;
647
349
648
349
        return (FIDO_OK);
649
349
}
650
651
int
652
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
653
65.5k
{
654
65.5k
        fido_blob_t id_blob;
655
65.5k
        fido_blob_t *list_ptr;
656
65.5k
657
65.5k
        memset(&id_blob, 0, sizeof(id_blob));
658
65.5k
659
65.5k
        if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
660
211
                return (FIDO_ERR_INVALID_ARGUMENT);
661
65.3k
662
65.3k
        if (cred->excl.len == SIZE_MAX) {
663
0
                free(id_blob.ptr);
664
0
                return (FIDO_ERR_INVALID_ARGUMENT);
665
0
        }
666
65.3k
667
65.3k
        if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
668
65.3k
            cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
669
188
                free(id_blob.ptr);
670
188
                return (FIDO_ERR_INTERNAL);
671
188
        }
672
65.1k
673
65.1k
        list_ptr[cred->excl.len++] = id_blob;
674
65.1k
        cred->excl.ptr = list_ptr;
675
65.1k
676
65.1k
        return (FIDO_OK);
677
65.1k
}
678
679
int
680
fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
681
    size_t hash_len)
682
4.83k
{
683
4.83k
        if (fido_blob_set(&cred->cdh, hash, hash_len) < 0)
684
142
                return (FIDO_ERR_INVALID_ARGUMENT);
685
4.69k
686
4.69k
        return (FIDO_OK);
687
4.69k
}
688
689
int
690
fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
691
4.83k
{
692
4.83k
        fido_rp_t *rp = &cred->rp;
693
4.83k
694
4.83k
        if (rp->id != NULL) {
695
1.55k
                free(rp->id);
696
1.55k
                rp->id = NULL;
697
1.55k
        }
698
4.83k
        if (rp->name != NULL) {
699
1.55k
                free(rp->name);
700
1.55k
                rp->name = NULL;
701
1.55k
        }
702
4.83k
703
4.83k
        if (id != NULL && (rp->id = strdup(id)) == NULL)
704
4.83k
                goto fail;
705
4.81k
        if (name != NULL && (rp->name = strdup(name)) == NULL)
706
4.81k
                goto fail;
707
4.78k
708
4.78k
        return (FIDO_OK);
709
52
fail:
710
52
        free(rp->id);
711
52
        free(rp->name);
712
52
        rp->id = NULL;
713
52
        rp->name = NULL;
714
52
715
52
        return (FIDO_ERR_INTERNAL);
716
4.78k
}
717
718
int
719
fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
720
    size_t user_id_len, const char *name, const char *display_name,
721
    const char *icon)
722
3.15k
{
723
3.15k
        fido_user_t *up = &cred->user;
724
3.15k
725
3.15k
        if (up->id.ptr != NULL) {
726
1.53k
                free(up->id.ptr);
727
1.53k
                up->id.ptr = NULL;
728
1.53k
                up->id.len = 0;
729
1.53k
        }
730
3.15k
        if (up->name != NULL) {
731
1.53k
                free(up->name);
732
1.53k
                up->name = NULL;
733
1.53k
        }
734
3.15k
        if (up->display_name != NULL) {
735
1.53k
                free(up->display_name);
736
1.53k
                up->display_name = NULL;
737
1.53k
        }
738
3.15k
        if (up->icon != NULL) {
739
1.53k
                free(up->icon);
740
1.53k
                up->icon = NULL;
741
1.53k
        }
742
3.15k
743
3.15k
        if (user_id != NULL) {
744
3.15k
                if ((up->id.ptr = malloc(user_id_len)) == NULL)
745
3.15k
                        goto fail;
746
3.13k
                memcpy(up->id.ptr, user_id, user_id_len);
747
3.13k
                up->id.len = user_id_len;
748
3.13k
        }
749
3.15k
        if (name != NULL && (up->name = strdup(name)) == NULL)
750
3.13k
                goto fail;
751
3.11k
        if (display_name != NULL &&
752
3.11k
            (up->display_name = strdup(display_name)) == NULL)
753
3.11k
                goto fail;
754
3.10k
        if (icon != NULL && (up->icon = strdup(icon)) == NULL)
755
3.10k
                goto fail;
756
3.08k
757
3.08k
        return (FIDO_OK);
758
64
fail:
759
64
        free(up->id.ptr);
760
64
        free(up->name);
761
64
        free(up->display_name);
762
64
        free(up->icon);
763
64
764
64
        up->id.ptr = NULL;
765
64
        up->id.len = 0;
766
64
        up->name = NULL;
767
64
        up->display_name = NULL;
768
64
        up->icon = NULL;
769
64
770
64
        return (FIDO_ERR_INTERNAL);
771
3.08k
}
772
773
int
774
fido_cred_set_extensions(fido_cred_t *cred, int ext)
775
3.25k
{
776
3.25k
        if (ext == 0)
777
184
                cred->ext.mask = 0;
778
3.07k
        else {
779
3.07k
                if (ext != FIDO_EXT_HMAC_SECRET &&
780
3.07k
                    ext != FIDO_EXT_CRED_PROTECT)
781
3.07k
                        return (FIDO_ERR_INVALID_ARGUMENT);
782
32
                cred->ext.mask |= ext;
783
32
        }
784
3.25k
785
3.25k
        return (FIDO_OK);
786
3.25k
}
787
788
int
789
fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
790
0
{
791
0
        cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
792
0
        cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
793
0
794
0
        return (FIDO_OK);
795
0
}
796
797
int
798
fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
799
1.08k
{
800
1.08k
        cred->rk = rk;
801
1.08k
802
1.08k
        return (FIDO_OK);
803
1.08k
}
804
805
int
806
fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
807
1.03k
{
808
1.03k
        cred->uv = uv;
809
1.03k
810
1.03k
        return (FIDO_OK);
811
1.03k
}
812
813
int
814
fido_cred_set_prot(fido_cred_t *cred, int prot)
815
3.81k
{
816
3.81k
        if (prot == 0) {
817
1.66k
                cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT;
818
1.66k
                cred->ext.prot = 0;
819
2.14k
        } else {
820
2.14k
                if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
821
2.14k
                    prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
822
2.14k
                    prot != FIDO_CRED_PROT_UV_REQUIRED)
823
2.14k
                        return (FIDO_ERR_INVALID_ARGUMENT);
824
2.08k
825
2.08k
                cred->ext.mask |= FIDO_EXT_CRED_PROTECT;
826
2.08k
                cred->ext.prot = prot;
827
2.08k
        }
828
3.81k
829
3.81k
        return (FIDO_OK);
830
3.81k
}
831
832
int
833
fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
834
407
{
835
407
        free(cred->fmt);
836
407
        cred->fmt = NULL;
837
407
838
407
        if (fmt == NULL)
839
407
                return (FIDO_ERR_INVALID_ARGUMENT);
840
407
841
407
        if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f"))
842
0
                return (FIDO_ERR_INVALID_ARGUMENT);
843
407
844
407
        if ((cred->fmt = strdup(fmt)) == NULL)
845
407
                return (FIDO_ERR_INTERNAL);
846
404
847
404
        return (FIDO_OK);
848
404
}
849
850
int
851
fido_cred_set_type(fido_cred_t *cred, int cose_alg)
852
4.83k
{
853
4.83k
        if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 &&
854
4.83k
            cose_alg != COSE_EDDSA) || cred->type != 0)
855
1.57k
                return (FIDO_ERR_INVALID_ARGUMENT);
856
3.25k
857
3.25k
        cred->type = cose_alg;
858
3.25k
859
3.25k
        return (FIDO_OK);
860
3.25k
}
861
862
int
863
fido_cred_type(const fido_cred_t *cred)
864
2.93k
{
865
2.93k
        return (cred->type);
866
2.93k
}
867
868
uint8_t
869
fido_cred_flags(const fido_cred_t *cred)
870
1.68k
{
871
1.68k
        return (cred->authdata.flags);
872
1.68k
}
873
874
uint32_t
875
fido_cred_sigcount(const fido_cred_t *cred)
876
1.68k
{
877
1.68k
        return (cred->authdata.sigcount);
878
1.68k
}
879
880
const unsigned char *
881
fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
882
1.70k
{
883
1.70k
        return (cred->cdh.ptr);
884
1.70k
}
885
886
size_t
887
fido_cred_clientdata_hash_len(const fido_cred_t *cred)
888
1.70k
{
889
1.70k
        return (cred->cdh.len);
890
1.70k
}
891
892
const unsigned char *
893
fido_cred_x5c_ptr(const fido_cred_t *cred)
894
1.70k
{
895
1.70k
        return (cred->attstmt.x5c.ptr);
896
1.70k
}
897
898
size_t
899
fido_cred_x5c_len(const fido_cred_t *cred)
900
1.70k
{
901
1.70k
        return (cred->attstmt.x5c.len);
902
1.70k
}
903
904
const unsigned char *
905
fido_cred_sig_ptr(const fido_cred_t *cred)
906
1.70k
{
907
1.70k
        return (cred->attstmt.sig.ptr);
908
1.70k
}
909
910
size_t
911
fido_cred_sig_len(const fido_cred_t *cred)
912
1.70k
{
913
1.70k
        return (cred->attstmt.sig.len);
914
1.70k
}
915
916
const unsigned char *
917
fido_cred_authdata_ptr(const fido_cred_t *cred)
918
1.70k
{
919
1.70k
        return (cred->authdata_cbor.ptr);
920
1.70k
}
921
922
size_t
923
fido_cred_authdata_len(const fido_cred_t *cred)
924
1.70k
{
925
1.70k
        return (cred->authdata_cbor.len);
926
1.70k
}
927
928
const unsigned char *
929
fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
930
1.70k
{
931
1.70k
        return (cred->authdata_raw.ptr);
932
1.70k
}
933
934
size_t
935
fido_cred_authdata_raw_len(const fido_cred_t *cred)
936
1.70k
{
937
1.70k
        return (cred->authdata_raw.len);
938
1.70k
}
939
940
const unsigned char *
941
fido_cred_pubkey_ptr(const fido_cred_t *cred)
942
2.93k
{
943
2.93k
        const void *ptr;
944
2.93k
945
2.93k
        switch (cred->attcred.type) {
946
724
        case COSE_ES256:
947
724
                ptr = &cred->attcred.pubkey.es256;
948
724
                break;
949
21
        case COSE_RS256:
950
21
                ptr = &cred->attcred.pubkey.rs256;
951
21
                break;
952
102
        case COSE_EDDSA:
953
102
                ptr = &cred->attcred.pubkey.eddsa;
954
102
                break;
955
2.09k
        default:
956
2.09k
                ptr = NULL;
957
2.09k
                break;
958
2.93k
        }
959
2.93k
960
2.93k
        return (ptr);
961
2.93k
}
962
963
size_t
964
fido_cred_pubkey_len(const fido_cred_t *cred)
965
2.93k
{
966
2.93k
        size_t len;
967
2.93k
968
2.93k
        switch (cred->attcred.type) {
969
724
        case COSE_ES256:
970
724
                len = sizeof(cred->attcred.pubkey.es256);
971
724
                break;
972
21
        case COSE_RS256:
973
21
                len = sizeof(cred->attcred.pubkey.rs256);
974
21
                break;
975
102
        case COSE_EDDSA:
976
102
                len = sizeof(cred->attcred.pubkey.eddsa);
977
102
                break;
978
2.09k
        default:
979
2.09k
                len = 0;
980
2.09k
                break;
981
2.93k
        }
982
2.93k
983
2.93k
        return (len);
984
2.93k
}
985
986
const unsigned char *
987
fido_cred_id_ptr(const fido_cred_t *cred)
988
2.93k
{
989
2.93k
        return (cred->attcred.id.ptr);
990
2.93k
}
991
992
size_t
993
fido_cred_id_len(const fido_cred_t *cred)
994
2.93k
{
995
2.93k
        return (cred->attcred.id.len);
996
2.93k
}
997
998
const unsigned char *
999
fido_cred_aaguid_ptr(const fido_cred_t *cred)
1000
1.68k
{
1001
1.68k
        return (cred->attcred.aaguid);
1002
1.68k
}
1003
1004
size_t
1005
fido_cred_aaguid_len(const fido_cred_t *cred)
1006
1.68k
{
1007
1.68k
        return (sizeof(cred->attcred.aaguid));
1008
1.68k
}
1009
1010
int
1011
fido_cred_prot(const fido_cred_t *cred)
1012
2.95k
{
1013
2.95k
        return (cred->ext.prot);
1014
2.95k
}
1015
1016
const char *
1017
fido_cred_fmt(const fido_cred_t *cred)
1018
1.70k
{
1019
1.70k
        return (cred->fmt);
1020
1.70k
}
1021
1022
const char *
1023
fido_cred_rp_id(const fido_cred_t *cred)
1024
1.70k
{
1025
1.70k
        return (cred->rp.id);
1026
1.70k
}
1027
1028
const char *
1029
fido_cred_rp_name(const fido_cred_t *cred)
1030
1.70k
{
1031
1.70k
        return (cred->rp.name);
1032
1.70k
}
1033
1034
const char *
1035
fido_cred_user_name(const fido_cred_t *cred)
1036
5.87k
{
1037
5.87k
        return (cred->user.name);
1038
5.87k
}
1039
1040
const char *
1041
fido_cred_display_name(const fido_cred_t *cred)
1042
5.87k
{
1043
5.87k
        return (cred->user.display_name);
1044
5.87k
}
1045
1046
const unsigned char *
1047
fido_cred_user_id_ptr(const fido_cred_t *cred)
1048
2.93k
{
1049
2.93k
        return (cred->user.id.ptr);
1050
2.93k
}
1051
1052
size_t
1053
fido_cred_user_id_len(const fido_cred_t *cred)
1054
2.93k
{
1055
2.93k
        return (cred->user.id.len);
1056
2.93k
}