Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/src/cred.c
39478 views
1
/*
2
* Copyright (c) 2018-2022 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
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#include <openssl/sha.h>
9
#include <openssl/x509.h>
10
11
#include "fido.h"
12
#include "fido/es256.h"
13
14
#ifndef FIDO_MAXMSG_CRED
15
#define FIDO_MAXMSG_CRED 4096
16
#endif
17
18
static int
19
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
20
{
21
fido_cred_t *cred = arg;
22
23
if (cbor_isa_uint(key) == false ||
24
cbor_int_get_width(key) != CBOR_INT_8) {
25
fido_log_debug("%s: cbor type", __func__);
26
return (0); /* ignore */
27
}
28
29
switch (cbor_get_uint8(key)) {
30
case 1: /* fmt */
31
return (cbor_decode_fmt(val, &cred->fmt));
32
case 2: /* authdata */
33
if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
34
fido_log_debug("%s: fido_blob_decode", __func__);
35
return (-1);
36
}
37
return (cbor_decode_cred_authdata(val, cred->type,
38
&cred->authdata_cbor, &cred->authdata, &cred->attcred,
39
&cred->authdata_ext));
40
case 3: /* attestation statement */
41
return (cbor_decode_attstmt(val, &cred->attstmt));
42
case 5: /* large blob key */
43
return (fido_blob_decode(val, &cred->largeblob_key));
44
default: /* ignore */
45
fido_log_debug("%s: cbor type", __func__);
46
return (0);
47
}
48
}
49
50
static int
51
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
52
int *ms)
53
{
54
fido_blob_t f;
55
fido_blob_t *ecdh = NULL;
56
fido_opt_t uv = cred->uv;
57
es256_pk_t *pk = NULL;
58
cbor_item_t *argv[9];
59
const uint8_t cmd = CTAP_CBOR_MAKECRED;
60
int r;
61
62
memset(&f, 0, sizeof(f));
63
memset(argv, 0, sizeof(argv));
64
65
if (cred->cdh.ptr == NULL || cred->type == 0) {
66
fido_log_debug("%s: cdh=%p, type=%d", __func__,
67
(void *)cred->cdh.ptr, cred->type);
68
r = FIDO_ERR_INVALID_ARGUMENT;
69
goto fail;
70
}
71
72
if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
73
(argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
74
(argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
75
(argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
76
fido_log_debug("%s: cbor encode", __func__);
77
r = FIDO_ERR_INTERNAL;
78
goto fail;
79
}
80
81
/* excluded credentials */
82
if (cred->excl.len)
83
if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
84
fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
85
r = FIDO_ERR_INTERNAL;
86
goto fail;
87
}
88
89
/* extensions */
90
if (cred->ext.mask)
91
if ((argv[5] = cbor_encode_cred_ext(&cred->ext,
92
&cred->blob)) == NULL) {
93
fido_log_debug("%s: cbor_encode_cred_ext", __func__);
94
r = FIDO_ERR_INTERNAL;
95
goto fail;
96
}
97
98
/* user verification */
99
if (pin != NULL || (uv == FIDO_OPT_TRUE &&
100
fido_dev_supports_permissions(dev))) {
101
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
102
fido_log_debug("%s: fido_do_ecdh", __func__);
103
goto fail;
104
}
105
if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
106
pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
107
fido_log_debug("%s: cbor_add_uv_params", __func__);
108
goto fail;
109
}
110
uv = FIDO_OPT_OMIT;
111
}
112
113
/* options */
114
if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
115
if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) {
116
fido_log_debug("%s: cbor_encode_cred_opt", __func__);
117
r = FIDO_ERR_INTERNAL;
118
goto fail;
119
}
120
121
/* framing and transmission */
122
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
123
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
124
fido_log_debug("%s: fido_tx", __func__);
125
r = FIDO_ERR_TX;
126
goto fail;
127
}
128
129
r = FIDO_OK;
130
fail:
131
es256_pk_free(&pk);
132
fido_blob_free(&ecdh);
133
cbor_vector_free(argv, nitems(argv));
134
free(f.ptr);
135
136
return (r);
137
}
138
139
static int
140
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
141
{
142
unsigned char *reply;
143
int reply_len;
144
int r;
145
146
fido_cred_reset_rx(cred);
147
148
if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
149
r = FIDO_ERR_INTERNAL;
150
goto fail;
151
}
152
153
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
154
ms)) < 0) {
155
fido_log_debug("%s: fido_rx", __func__);
156
r = FIDO_ERR_RX;
157
goto fail;
158
}
159
160
if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
161
parse_makecred_reply)) != FIDO_OK) {
162
fido_log_debug("%s: parse_makecred_reply", __func__);
163
goto fail;
164
}
165
166
if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
167
fido_blob_is_empty(&cred->attcred.id)) {
168
r = FIDO_ERR_INVALID_CBOR;
169
goto fail;
170
}
171
172
r = FIDO_OK;
173
fail:
174
free(reply);
175
176
if (r != FIDO_OK)
177
fido_cred_reset_rx(cred);
178
179
return (r);
180
}
181
182
static int
183
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
184
int *ms)
185
{
186
int r;
187
188
if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
189
(r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
190
return (r);
191
192
return (FIDO_OK);
193
}
194
195
int
196
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
197
{
198
int ms = dev->timeout_ms;
199
200
#ifdef USE_WINHELLO
201
if (dev->flags & FIDO_DEV_WINHELLO)
202
return (fido_winhello_make_cred(dev, cred, pin, ms));
203
#endif
204
if (fido_dev_is_fido2(dev) == false) {
205
if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
206
cred->ext.mask != 0)
207
return (FIDO_ERR_UNSUPPORTED_OPTION);
208
return (u2f_register(dev, cred, &ms));
209
}
210
211
return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
212
}
213
214
static int
215
check_extensions(const fido_cred_ext_t *authdata_ext,
216
const fido_cred_ext_t *ext)
217
{
218
fido_cred_ext_t tmp;
219
220
/* XXX: largeBlobKey is not part of the extensions map */
221
memcpy(&tmp, ext, sizeof(tmp));
222
tmp.mask &= ~FIDO_EXT_LARGEBLOB_KEY;
223
224
return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext)));
225
}
226
227
int
228
fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
229
{
230
unsigned char expected_hash[SHA256_DIGEST_LENGTH];
231
232
explicit_bzero(expected_hash, sizeof(expected_hash));
233
234
if (SHA256((const unsigned char *)id, strlen(id),
235
expected_hash) != expected_hash) {
236
fido_log_debug("%s: sha256", __func__);
237
return (-1);
238
}
239
240
return (timingsafe_bcmp(expected_hash, obtained_hash,
241
SHA256_DIGEST_LENGTH));
242
}
243
244
static int
245
get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
246
size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
247
const es256_pk_t *pk)
248
{
249
const uint8_t zero = 0;
250
const uint8_t four = 4; /* uncompressed point */
251
const EVP_MD *md = NULL;
252
EVP_MD_CTX *ctx = NULL;
253
int ok = -1;
254
255
if (dgst->len < SHA256_DIGEST_LENGTH ||
256
(md = EVP_sha256()) == NULL ||
257
(ctx = EVP_MD_CTX_new()) == NULL ||
258
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
259
EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
260
EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
261
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
262
EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
263
EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
264
EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
265
EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
266
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
267
fido_log_debug("%s: sha256", __func__);
268
goto fail;
269
}
270
dgst->len = SHA256_DIGEST_LENGTH;
271
272
ok = 0;
273
fail:
274
EVP_MD_CTX_free(ctx);
275
276
return (ok);
277
}
278
279
static int
280
verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
281
{
282
BIO *rawcert = NULL;
283
X509 *cert = NULL;
284
EVP_PKEY *pkey = NULL;
285
int ok = -1;
286
287
/* openssl needs ints */
288
if (attstmt->x5c.len > INT_MAX) {
289
fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
290
return (-1);
291
}
292
293
/* fetch key from x509 */
294
if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
295
(int)attstmt->x5c.len)) == NULL ||
296
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
297
(pkey = X509_get_pubkey(cert)) == NULL) {
298
fido_log_debug("%s: x509 key", __func__);
299
goto fail;
300
}
301
302
switch (attstmt->alg) {
303
case COSE_UNSPEC:
304
case COSE_ES256:
305
ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
306
break;
307
case COSE_ES384:
308
ok = es384_verify_sig(dgst, pkey, &attstmt->sig);
309
break;
310
case COSE_RS256:
311
ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
312
break;
313
case COSE_RS1:
314
ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
315
break;
316
case COSE_EDDSA:
317
ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
318
break;
319
default:
320
fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
321
break;
322
}
323
324
fail:
325
BIO_free(rawcert);
326
X509_free(cert);
327
EVP_PKEY_free(pkey);
328
329
return (ok);
330
}
331
332
int
333
fido_cred_verify(const fido_cred_t *cred)
334
{
335
unsigned char buf[1024]; /* XXX */
336
fido_blob_t dgst;
337
int cose_alg;
338
int r;
339
340
dgst.ptr = buf;
341
dgst.len = sizeof(buf);
342
343
/* do we have everything we need? */
344
if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
345
cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
346
cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
347
cred->rp.id == NULL) {
348
fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
349
"fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
350
(void *)cred->authdata_cbor.ptr,
351
(void *)cred->attstmt.x5c.ptr,
352
(void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
353
(void *)cred->attcred.id.ptr, cred->rp.id);
354
r = FIDO_ERR_INVALID_ARGUMENT;
355
goto out;
356
}
357
358
if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
359
fido_log_debug("%s: fido_check_rp_id", __func__);
360
r = FIDO_ERR_INVALID_PARAM;
361
goto out;
362
}
363
364
if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
365
cred->uv) < 0) {
366
fido_log_debug("%s: fido_check_flags", __func__);
367
r = FIDO_ERR_INVALID_PARAM;
368
goto out;
369
}
370
371
if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
372
fido_log_debug("%s: check_extensions", __func__);
373
r = FIDO_ERR_INVALID_PARAM;
374
goto out;
375
}
376
377
if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC)
378
cose_alg = COSE_ES256; /* backwards compat */
379
380
if (!strcmp(cred->fmt, "packed")) {
381
if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh,
382
&cred->authdata_cbor) < 0) {
383
fido_log_debug("%s: fido_get_signed_hash", __func__);
384
r = FIDO_ERR_INTERNAL;
385
goto out;
386
}
387
} else if (!strcmp(cred->fmt, "fido-u2f")) {
388
if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
389
sizeof(cred->authdata.rp_id_hash), &cred->cdh,
390
&cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
391
fido_log_debug("%s: get_signed_hash_u2f", __func__);
392
r = FIDO_ERR_INTERNAL;
393
goto out;
394
}
395
} else if (!strcmp(cred->fmt, "tpm")) {
396
if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
397
&cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
398
fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
399
r = FIDO_ERR_INTERNAL;
400
goto out;
401
}
402
} else {
403
fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
404
r = FIDO_ERR_INVALID_ARGUMENT;
405
goto out;
406
}
407
408
if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
409
fido_log_debug("%s: verify_attstmt", __func__);
410
r = FIDO_ERR_INVALID_SIG;
411
goto out;
412
}
413
414
r = FIDO_OK;
415
out:
416
explicit_bzero(buf, sizeof(buf));
417
418
return (r);
419
}
420
421
int
422
fido_cred_verify_self(const fido_cred_t *cred)
423
{
424
unsigned char buf[1024]; /* XXX */
425
fido_blob_t dgst;
426
int ok = -1;
427
int r;
428
429
dgst.ptr = buf;
430
dgst.len = sizeof(buf);
431
432
/* do we have everything we need? */
433
if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
434
cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
435
cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
436
cred->rp.id == NULL) {
437
fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
438
"fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
439
(void *)cred->authdata_cbor.ptr,
440
(void *)cred->attstmt.x5c.ptr,
441
(void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
442
(void *)cred->attcred.id.ptr, cred->rp.id);
443
r = FIDO_ERR_INVALID_ARGUMENT;
444
goto out;
445
}
446
447
if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
448
fido_log_debug("%s: fido_check_rp_id", __func__);
449
r = FIDO_ERR_INVALID_PARAM;
450
goto out;
451
}
452
453
if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
454
cred->uv) < 0) {
455
fido_log_debug("%s: fido_check_flags", __func__);
456
r = FIDO_ERR_INVALID_PARAM;
457
goto out;
458
}
459
460
if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
461
fido_log_debug("%s: check_extensions", __func__);
462
r = FIDO_ERR_INVALID_PARAM;
463
goto out;
464
}
465
466
if (!strcmp(cred->fmt, "packed")) {
467
if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
468
&cred->authdata_cbor) < 0) {
469
fido_log_debug("%s: fido_get_signed_hash", __func__);
470
r = FIDO_ERR_INTERNAL;
471
goto out;
472
}
473
} else if (!strcmp(cred->fmt, "fido-u2f")) {
474
if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
475
sizeof(cred->authdata.rp_id_hash), &cred->cdh,
476
&cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
477
fido_log_debug("%s: get_signed_hash_u2f", __func__);
478
r = FIDO_ERR_INTERNAL;
479
goto out;
480
}
481
} else {
482
fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
483
r = FIDO_ERR_INVALID_ARGUMENT;
484
goto out;
485
}
486
487
switch (cred->attcred.type) {
488
case COSE_ES256:
489
ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
490
&cred->attstmt.sig);
491
break;
492
case COSE_ES384:
493
ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384,
494
&cred->attstmt.sig);
495
break;
496
case COSE_RS256:
497
ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
498
&cred->attstmt.sig);
499
break;
500
case COSE_EDDSA:
501
ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
502
&cred->attstmt.sig);
503
break;
504
default:
505
fido_log_debug("%s: unsupported cose_alg %d", __func__,
506
cred->attcred.type);
507
r = FIDO_ERR_UNSUPPORTED_OPTION;
508
goto out;
509
}
510
511
if (ok < 0)
512
r = FIDO_ERR_INVALID_SIG;
513
else
514
r = FIDO_OK;
515
516
out:
517
explicit_bzero(buf, sizeof(buf));
518
519
return (r);
520
}
521
522
fido_cred_t *
523
fido_cred_new(void)
524
{
525
return (calloc(1, sizeof(fido_cred_t)));
526
}
527
528
static void
529
fido_cred_clean_authdata(fido_cred_t *cred)
530
{
531
fido_blob_reset(&cred->authdata_cbor);
532
fido_blob_reset(&cred->authdata_raw);
533
fido_blob_reset(&cred->attcred.id);
534
535
memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
536
memset(&cred->authdata, 0, sizeof(cred->authdata));
537
memset(&cred->attcred, 0, sizeof(cred->attcred));
538
}
539
540
static void
541
fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
542
{
543
fido_blob_reset(&attstmt->certinfo);
544
fido_blob_reset(&attstmt->pubarea);
545
fido_blob_reset(&attstmt->cbor);
546
fido_blob_reset(&attstmt->x5c);
547
fido_blob_reset(&attstmt->sig);
548
549
memset(attstmt, 0, sizeof(*attstmt));
550
}
551
552
void
553
fido_cred_reset_tx(fido_cred_t *cred)
554
{
555
fido_blob_reset(&cred->cd);
556
fido_blob_reset(&cred->cdh);
557
fido_blob_reset(&cred->user.id);
558
fido_blob_reset(&cred->blob);
559
560
free(cred->rp.id);
561
free(cred->rp.name);
562
free(cred->user.icon);
563
free(cred->user.name);
564
free(cred->user.display_name);
565
fido_cred_empty_exclude_list(cred);
566
567
memset(&cred->rp, 0, sizeof(cred->rp));
568
memset(&cred->user, 0, sizeof(cred->user));
569
memset(&cred->ext, 0, sizeof(cred->ext));
570
571
cred->type = 0;
572
cred->rk = FIDO_OPT_OMIT;
573
cred->uv = FIDO_OPT_OMIT;
574
}
575
576
void
577
fido_cred_reset_rx(fido_cred_t *cred)
578
{
579
free(cred->fmt);
580
cred->fmt = NULL;
581
fido_cred_clean_authdata(cred);
582
fido_cred_clean_attstmt(&cred->attstmt);
583
fido_blob_reset(&cred->largeblob_key);
584
}
585
586
void
587
fido_cred_free(fido_cred_t **cred_p)
588
{
589
fido_cred_t *cred;
590
591
if (cred_p == NULL || (cred = *cred_p) == NULL)
592
return;
593
fido_cred_reset_tx(cred);
594
fido_cred_reset_rx(cred);
595
free(cred);
596
*cred_p = NULL;
597
}
598
599
int
600
fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
601
{
602
cbor_item_t *item = NULL;
603
struct cbor_load_result cbor;
604
int r = FIDO_ERR_INVALID_ARGUMENT;
605
606
fido_cred_clean_authdata(cred);
607
608
if (ptr == NULL || len == 0)
609
goto fail;
610
611
if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
612
fido_log_debug("%s: cbor_load", __func__);
613
goto fail;
614
}
615
616
if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
617
fido_log_debug("%s: fido_blob_decode", __func__);
618
goto fail;
619
}
620
621
if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
622
&cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
623
fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
624
goto fail;
625
}
626
627
r = FIDO_OK;
628
fail:
629
if (item != NULL)
630
cbor_decref(&item);
631
632
if (r != FIDO_OK)
633
fido_cred_clean_authdata(cred);
634
635
return (r);
636
}
637
638
int
639
fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
640
size_t len)
641
{
642
cbor_item_t *item = NULL;
643
int r = FIDO_ERR_INVALID_ARGUMENT;
644
645
fido_cred_clean_authdata(cred);
646
647
if (ptr == NULL || len == 0)
648
goto fail;
649
650
if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
651
fido_log_debug("%s: fido_blob_set", __func__);
652
r = FIDO_ERR_INTERNAL;
653
goto fail;
654
}
655
656
if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
657
fido_log_debug("%s: cbor_build_bytestring", __func__);
658
r = FIDO_ERR_INTERNAL;
659
goto fail;
660
}
661
662
if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
663
&cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
664
fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
665
goto fail;
666
}
667
668
r = FIDO_OK;
669
fail:
670
if (item != NULL)
671
cbor_decref(&item);
672
673
if (r != FIDO_OK)
674
fido_cred_clean_authdata(cred);
675
676
return (r);
677
}
678
679
int
680
fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len)
681
{
682
if (fido_blob_set(&cred->attcred.id, ptr, len) < 0)
683
return (FIDO_ERR_INVALID_ARGUMENT);
684
685
return (FIDO_OK);
686
}
687
688
int
689
fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
690
{
691
if (fido_blob_set(&cred->attstmt.x5c, ptr, len) < 0)
692
return (FIDO_ERR_INVALID_ARGUMENT);
693
694
return (FIDO_OK);
695
}
696
697
int
698
fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
699
{
700
if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0)
701
return (FIDO_ERR_INVALID_ARGUMENT);
702
703
return (FIDO_OK);
704
}
705
706
int
707
fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
708
{
709
cbor_item_t *item = NULL;
710
struct cbor_load_result cbor;
711
int r = FIDO_ERR_INVALID_ARGUMENT;
712
713
fido_cred_clean_attstmt(&cred->attstmt);
714
715
if (ptr == NULL || len == 0)
716
goto fail;
717
718
if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
719
fido_log_debug("%s: cbor_load", __func__);
720
goto fail;
721
}
722
723
if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
724
fido_log_debug("%s: cbor_decode_attstmt", __func__);
725
goto fail;
726
}
727
728
r = FIDO_OK;
729
fail:
730
if (item != NULL)
731
cbor_decref(&item);
732
733
if (r != FIDO_OK)
734
fido_cred_clean_attstmt(&cred->attstmt);
735
736
return (r);
737
}
738
739
int
740
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
741
{
742
fido_blob_t id_blob;
743
fido_blob_t *list_ptr;
744
745
memset(&id_blob, 0, sizeof(id_blob));
746
747
if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
748
return (FIDO_ERR_INVALID_ARGUMENT);
749
750
if (cred->excl.len == SIZE_MAX) {
751
free(id_blob.ptr);
752
return (FIDO_ERR_INVALID_ARGUMENT);
753
}
754
755
if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
756
cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
757
free(id_blob.ptr);
758
return (FIDO_ERR_INTERNAL);
759
}
760
761
list_ptr[cred->excl.len++] = id_blob;
762
cred->excl.ptr = list_ptr;
763
764
return (FIDO_OK);
765
}
766
767
int
768
fido_cred_empty_exclude_list(fido_cred_t *cred)
769
{
770
fido_free_blob_array(&cred->excl);
771
memset(&cred->excl, 0, sizeof(cred->excl));
772
773
return (FIDO_OK);
774
}
775
776
int
777
fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
778
size_t data_len)
779
{
780
if (!fido_blob_is_empty(&cred->cdh) ||
781
fido_blob_set(&cred->cd, data, data_len) < 0) {
782
return (FIDO_ERR_INVALID_ARGUMENT);
783
}
784
if (fido_sha256(&cred->cdh, data, data_len) < 0) {
785
fido_blob_reset(&cred->cd);
786
return (FIDO_ERR_INTERNAL);
787
}
788
789
return (FIDO_OK);
790
}
791
792
int
793
fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
794
size_t hash_len)
795
{
796
if (!fido_blob_is_empty(&cred->cd) ||
797
fido_blob_set(&cred->cdh, hash, hash_len) < 0)
798
return (FIDO_ERR_INVALID_ARGUMENT);
799
800
return (FIDO_OK);
801
}
802
803
int
804
fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
805
{
806
fido_rp_t *rp = &cred->rp;
807
808
if (rp->id != NULL) {
809
free(rp->id);
810
rp->id = NULL;
811
}
812
if (rp->name != NULL) {
813
free(rp->name);
814
rp->name = NULL;
815
}
816
817
if (id != NULL && (rp->id = strdup(id)) == NULL)
818
goto fail;
819
if (name != NULL && (rp->name = strdup(name)) == NULL)
820
goto fail;
821
822
return (FIDO_OK);
823
fail:
824
free(rp->id);
825
free(rp->name);
826
rp->id = NULL;
827
rp->name = NULL;
828
829
return (FIDO_ERR_INTERNAL);
830
}
831
832
int
833
fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
834
size_t user_id_len, const char *name, const char *display_name,
835
const char *icon)
836
{
837
fido_user_t *up = &cred->user;
838
839
if (up->id.ptr != NULL) {
840
free(up->id.ptr);
841
up->id.ptr = NULL;
842
up->id.len = 0;
843
}
844
if (up->name != NULL) {
845
free(up->name);
846
up->name = NULL;
847
}
848
if (up->display_name != NULL) {
849
free(up->display_name);
850
up->display_name = NULL;
851
}
852
if (up->icon != NULL) {
853
free(up->icon);
854
up->icon = NULL;
855
}
856
857
if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0)
858
goto fail;
859
if (name != NULL && (up->name = strdup(name)) == NULL)
860
goto fail;
861
if (display_name != NULL &&
862
(up->display_name = strdup(display_name)) == NULL)
863
goto fail;
864
if (icon != NULL && (up->icon = strdup(icon)) == NULL)
865
goto fail;
866
867
return (FIDO_OK);
868
fail:
869
free(up->id.ptr);
870
free(up->name);
871
free(up->display_name);
872
free(up->icon);
873
874
up->id.ptr = NULL;
875
up->id.len = 0;
876
up->name = NULL;
877
up->display_name = NULL;
878
up->icon = NULL;
879
880
return (FIDO_ERR_INTERNAL);
881
}
882
883
int
884
fido_cred_set_extensions(fido_cred_t *cred, int ext)
885
{
886
if (ext == 0)
887
cred->ext.mask = 0;
888
else {
889
if ((ext & FIDO_EXT_CRED_MASK) != ext)
890
return (FIDO_ERR_INVALID_ARGUMENT);
891
cred->ext.mask |= ext;
892
}
893
894
return (FIDO_OK);
895
}
896
897
int
898
fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
899
{
900
cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
901
cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
902
903
return (FIDO_OK);
904
}
905
906
int
907
fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
908
{
909
cred->rk = rk;
910
911
return (FIDO_OK);
912
}
913
914
int
915
fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
916
{
917
cred->uv = uv;
918
919
return (FIDO_OK);
920
}
921
922
int
923
fido_cred_set_prot(fido_cred_t *cred, int prot)
924
{
925
if (prot == 0) {
926
cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT;
927
cred->ext.prot = 0;
928
} else {
929
if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
930
prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
931
prot != FIDO_CRED_PROT_UV_REQUIRED)
932
return (FIDO_ERR_INVALID_ARGUMENT);
933
934
cred->ext.mask |= FIDO_EXT_CRED_PROTECT;
935
cred->ext.prot = prot;
936
}
937
938
return (FIDO_OK);
939
}
940
941
int
942
fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
943
{
944
if (len == 0)
945
cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
946
else
947
cred->ext.mask |= FIDO_EXT_MINPINLEN;
948
949
cred->ext.minpinlen = len;
950
951
return (FIDO_OK);
952
}
953
954
int
955
fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
956
{
957
if (ptr == NULL || len == 0)
958
return (FIDO_ERR_INVALID_ARGUMENT);
959
if (fido_blob_set(&cred->blob, ptr, len) < 0)
960
return (FIDO_ERR_INTERNAL);
961
962
cred->ext.mask |= FIDO_EXT_CRED_BLOB;
963
964
return (FIDO_OK);
965
}
966
967
int
968
fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
969
{
970
free(cred->fmt);
971
cred->fmt = NULL;
972
973
if (fmt == NULL)
974
return (FIDO_ERR_INVALID_ARGUMENT);
975
976
if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
977
strcmp(fmt, "none") && strcmp(fmt, "tpm"))
978
return (FIDO_ERR_INVALID_ARGUMENT);
979
980
if ((cred->fmt = strdup(fmt)) == NULL)
981
return (FIDO_ERR_INTERNAL);
982
983
return (FIDO_OK);
984
}
985
986
int
987
fido_cred_set_type(fido_cred_t *cred, int cose_alg)
988
{
989
if (cred->type != 0)
990
return (FIDO_ERR_INVALID_ARGUMENT);
991
if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 &&
992
cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA)
993
return (FIDO_ERR_INVALID_ARGUMENT);
994
995
cred->type = cose_alg;
996
997
return (FIDO_OK);
998
}
999
1000
int
1001
fido_cred_type(const fido_cred_t *cred)
1002
{
1003
return (cred->type);
1004
}
1005
1006
uint8_t
1007
fido_cred_flags(const fido_cred_t *cred)
1008
{
1009
return (cred->authdata.flags);
1010
}
1011
1012
uint32_t
1013
fido_cred_sigcount(const fido_cred_t *cred)
1014
{
1015
return (cred->authdata.sigcount);
1016
}
1017
1018
const unsigned char *
1019
fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
1020
{
1021
return (cred->cdh.ptr);
1022
}
1023
1024
size_t
1025
fido_cred_clientdata_hash_len(const fido_cred_t *cred)
1026
{
1027
return (cred->cdh.len);
1028
}
1029
1030
const unsigned char *
1031
fido_cred_x5c_ptr(const fido_cred_t *cred)
1032
{
1033
return (cred->attstmt.x5c.ptr);
1034
}
1035
1036
size_t
1037
fido_cred_x5c_len(const fido_cred_t *cred)
1038
{
1039
return (cred->attstmt.x5c.len);
1040
}
1041
1042
const unsigned char *
1043
fido_cred_sig_ptr(const fido_cred_t *cred)
1044
{
1045
return (cred->attstmt.sig.ptr);
1046
}
1047
1048
size_t
1049
fido_cred_sig_len(const fido_cred_t *cred)
1050
{
1051
return (cred->attstmt.sig.len);
1052
}
1053
1054
const unsigned char *
1055
fido_cred_authdata_ptr(const fido_cred_t *cred)
1056
{
1057
return (cred->authdata_cbor.ptr);
1058
}
1059
1060
size_t
1061
fido_cred_authdata_len(const fido_cred_t *cred)
1062
{
1063
return (cred->authdata_cbor.len);
1064
}
1065
1066
const unsigned char *
1067
fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
1068
{
1069
return (cred->authdata_raw.ptr);
1070
}
1071
1072
size_t
1073
fido_cred_authdata_raw_len(const fido_cred_t *cred)
1074
{
1075
return (cred->authdata_raw.len);
1076
}
1077
1078
const unsigned char *
1079
fido_cred_attstmt_ptr(const fido_cred_t *cred)
1080
{
1081
return (cred->attstmt.cbor.ptr);
1082
}
1083
1084
size_t
1085
fido_cred_attstmt_len(const fido_cred_t *cred)
1086
{
1087
return (cred->attstmt.cbor.len);
1088
}
1089
1090
const unsigned char *
1091
fido_cred_pubkey_ptr(const fido_cred_t *cred)
1092
{
1093
const void *ptr;
1094
1095
switch (cred->attcred.type) {
1096
case COSE_ES256:
1097
ptr = &cred->attcred.pubkey.es256;
1098
break;
1099
case COSE_ES384:
1100
ptr = &cred->attcred.pubkey.es384;
1101
break;
1102
case COSE_RS256:
1103
ptr = &cred->attcred.pubkey.rs256;
1104
break;
1105
case COSE_EDDSA:
1106
ptr = &cred->attcred.pubkey.eddsa;
1107
break;
1108
default:
1109
ptr = NULL;
1110
break;
1111
}
1112
1113
return (ptr);
1114
}
1115
1116
size_t
1117
fido_cred_pubkey_len(const fido_cred_t *cred)
1118
{
1119
size_t len;
1120
1121
switch (cred->attcred.type) {
1122
case COSE_ES256:
1123
len = sizeof(cred->attcred.pubkey.es256);
1124
break;
1125
case COSE_ES384:
1126
len = sizeof(cred->attcred.pubkey.es384);
1127
break;
1128
case COSE_RS256:
1129
len = sizeof(cred->attcred.pubkey.rs256);
1130
break;
1131
case COSE_EDDSA:
1132
len = sizeof(cred->attcred.pubkey.eddsa);
1133
break;
1134
default:
1135
len = 0;
1136
break;
1137
}
1138
1139
return (len);
1140
}
1141
1142
const unsigned char *
1143
fido_cred_id_ptr(const fido_cred_t *cred)
1144
{
1145
return (cred->attcred.id.ptr);
1146
}
1147
1148
size_t
1149
fido_cred_id_len(const fido_cred_t *cred)
1150
{
1151
return (cred->attcred.id.len);
1152
}
1153
1154
const unsigned char *
1155
fido_cred_aaguid_ptr(const fido_cred_t *cred)
1156
{
1157
return (cred->attcred.aaguid);
1158
}
1159
1160
size_t
1161
fido_cred_aaguid_len(const fido_cred_t *cred)
1162
{
1163
return (sizeof(cred->attcred.aaguid));
1164
}
1165
1166
int
1167
fido_cred_prot(const fido_cred_t *cred)
1168
{
1169
return (cred->ext.prot);
1170
}
1171
1172
size_t
1173
fido_cred_pin_minlen(const fido_cred_t *cred)
1174
{
1175
return (cred->ext.minpinlen);
1176
}
1177
1178
const char *
1179
fido_cred_fmt(const fido_cred_t *cred)
1180
{
1181
return (cred->fmt);
1182
}
1183
1184
const char *
1185
fido_cred_rp_id(const fido_cred_t *cred)
1186
{
1187
return (cred->rp.id);
1188
}
1189
1190
const char *
1191
fido_cred_rp_name(const fido_cred_t *cred)
1192
{
1193
return (cred->rp.name);
1194
}
1195
1196
const char *
1197
fido_cred_user_name(const fido_cred_t *cred)
1198
{
1199
return (cred->user.name);
1200
}
1201
1202
const char *
1203
fido_cred_display_name(const fido_cred_t *cred)
1204
{
1205
return (cred->user.display_name);
1206
}
1207
1208
const unsigned char *
1209
fido_cred_user_id_ptr(const fido_cred_t *cred)
1210
{
1211
return (cred->user.id.ptr);
1212
}
1213
1214
size_t
1215
fido_cred_user_id_len(const fido_cred_t *cred)
1216
{
1217
return (cred->user.id.len);
1218
}
1219
1220
const unsigned char *
1221
fido_cred_largeblob_key_ptr(const fido_cred_t *cred)
1222
{
1223
return (cred->largeblob_key.ptr);
1224
}
1225
1226
size_t
1227
fido_cred_largeblob_key_len(const fido_cred_t *cred)
1228
{
1229
return (cred->largeblob_key.len);
1230
}
1231
1232