Coverage Report

Created: 2025-03-01 02:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/libfido2/src/u2f.c
Line
Count
Source
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
#ifdef HAVE_UNISTD_H
12
#include <unistd.h>
13
#endif
14
#include <errno.h>
15
16
#include "fido.h"
17
#include "fido/es256.h"
18
#include "fallthrough.h"
19
20
7.64k
#define U2F_PACE_MS (100)
21
22
#if defined(_MSC_VER)
23
static int
24
usleep(unsigned int usec)
25
{
26
        Sleep(usec / 1000);
27
28
        return (0);
29
}
30
#endif
31
32
static int
33
delay_ms(unsigned int ms, int *ms_remain)
34
7.64k
{
35
7.64k
        if (*ms_remain > -1 && (unsigned int)*ms_remain < ms)
36
4.90k
                ms = (unsigned int)*ms_remain;
37
38
7.64k
        if (ms > UINT_MAX / 1000) {
39
0
                fido_log_debug("%s: ms=%u", __func__, ms);
40
0
                return (-1);
41
0
        }
42
43
7.64k
        if (usleep(ms * 1000) < 0) {
44
12
                fido_log_error(errno, "%s: usleep", __func__);
45
12
                return (-1);
46
12
        }
47
48
7.63k
        if (*ms_remain > -1)
49
7.63k
                *ms_remain -= (int)ms;
50
51
7.63k
        return (0);
52
7.64k
}
53
54
static int
55
sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
56
2.74k
{
57
2.74k
        sig->len = *len; /* consume the whole buffer */
58
2.74k
        if ((sig->ptr = calloc(1, sig->len)) == NULL ||
59
2.74k
            fido_buf_read(buf, len, sig->ptr, sig->len) < 0) {
60
4
                fido_log_debug("%s: fido_buf_read", __func__);
61
4
                fido_blob_reset(sig);
62
4
                return (-1);
63
4
        }
64
65
2.73k
        return (0);
66
2.74k
}
67
68
static int
69
x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len)
70
1.92k
{
71
1.92k
        X509    *cert = NULL;
72
1.92k
        int      ok = -1;
73
74
1.92k
        if (*len > LONG_MAX) {
75
0
                fido_log_debug("%s: invalid len %zu", __func__, *len);
76
0
                goto fail;
77
0
        }
78
79
        /* find out the certificate's length */
80
1.92k
        const unsigned char *end = *buf;
81
1.92k
        if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf ||
82
1.92k
            (x5c->len = (size_t)(end - *buf)) >= *len) {
83
1.16k
                fido_log_debug("%s: d2i_X509", __func__);
84
1.16k
                goto fail;
85
1.16k
        }
86
87
        /* read accordingly */
88
756
        if ((x5c->ptr = calloc(1, x5c->len)) == NULL ||
89
756
            fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) {
90
2
                fido_log_debug("%s: fido_buf_read", __func__);
91
2
                goto fail;
92
2
        }
93
94
754
        ok = 0;
95
1.92k
fail:
96
1.92k
        if (cert != NULL)
97
756
                X509_free(cert);
98
99
1.92k
        if (ok < 0)
100
1.16k
                fido_blob_reset(x5c);
101
102
1.92k
        return (ok);
103
754
}
104
105
static int
106
authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
107
    fido_blob_t *fake_cbor_ad)
108
1.98k
{
109
1.98k
        fido_authdata_t  ad;
110
1.98k
        cbor_item_t     *item = NULL;
111
1.98k
        size_t           alloc_len;
112
113
1.98k
        memset(&ad, 0, sizeof(ad));
114
115
1.98k
        if (SHA256((const void *)rp_id, strlen(rp_id),
116
1.98k
            ad.rp_id_hash) != ad.rp_id_hash) {
117
7
                fido_log_debug("%s: sha256", __func__);
118
7
                return (-1);
119
7
        }
120
121
1.97k
        ad.flags = flags; /* XXX translate? */
122
1.97k
        ad.sigcount = sigcount;
123
124
1.97k
        if ((item = cbor_build_bytestring((const unsigned char *)&ad,
125
1.97k
            sizeof(ad))) == NULL) {
126
4
                fido_log_debug("%s: cbor_build_bytestring", __func__);
127
4
                return (-1);
128
4
        }
129
130
1.97k
        if (fake_cbor_ad->ptr != NULL ||
131
1.97k
            (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr,
132
1.97k
            &alloc_len)) == 0) {
133
3
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
134
3
                cbor_decref(&item);
135
3
                return (-1);
136
3
        }
137
138
1.97k
        cbor_decref(&item);
139
140
1.97k
        return (0);
141
1.97k
}
142
143
/* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
144
static int
145
send_dummy_register(fido_dev_t *dev, int *ms)
146
180
{
147
180
        iso7816_apdu_t  *apdu = NULL;
148
180
        unsigned char   *reply = NULL;
149
180
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
150
180
        unsigned char    application[SHA256_DIGEST_LENGTH];
151
180
        int              r;
152
153
        /* dummy challenge & application */
154
180
        memset(&challenge, 0xff, sizeof(challenge));
155
180
        memset(&application, 0xff, sizeof(application));
156
157
180
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
158
180
            SHA256_DIGEST_LENGTH)) == NULL ||
159
180
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
160
180
            iso7816_add(apdu, &application, sizeof(application)) < 0) {
161
4
                fido_log_debug("%s: iso7816", __func__);
162
4
                r = FIDO_ERR_INTERNAL;
163
4
                goto fail;
164
4
        }
165
166
176
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
167
6
                fido_log_debug("%s: malloc", __func__);
168
6
                r = FIDO_ERR_INTERNAL;
169
6
                goto fail;
170
6
        }
171
172
586
        do {
173
586
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
174
586
                    iso7816_len(apdu), ms) < 0) {
175
13
                        fido_log_debug("%s: fido_tx", __func__);
176
13
                        r = FIDO_ERR_TX;
177
13
                        goto fail;
178
13
                }
179
573
                if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) < 2) {
180
76
                        fido_log_debug("%s: fido_rx", __func__);
181
76
                        r = FIDO_ERR_RX;
182
76
                        goto fail;
183
76
                }
184
497
                if (delay_ms(U2F_PACE_MS, ms) != 0) {
185
5
                        fido_log_debug("%s: delay_ms", __func__);
186
5
                        r = FIDO_ERR_RX;
187
5
                        goto fail;
188
5
                }
189
497
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
190
191
76
        r = FIDO_OK;
192
180
fail:
193
180
        iso7816_free(&apdu);
194
180
        freezero(reply, FIDO_MAXMSG);
195
196
180
        return (r);
197
76
}
198
199
static int
200
key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
201
    int *found, int *ms)
202
5.63k
{
203
5.63k
        iso7816_apdu_t  *apdu = NULL;
204
5.63k
        unsigned char   *reply = NULL;
205
5.63k
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
206
5.63k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
207
5.63k
        uint8_t          key_id_len;
208
5.63k
        int              r;
209
210
5.63k
        if (key_id->len > UINT8_MAX || rp_id == NULL) {
211
62
                fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__,
212
62
                    key_id->len, (const void *)rp_id);
213
62
                r = FIDO_ERR_INVALID_ARGUMENT;
214
62
                goto fail;
215
62
        }
216
217
5.57k
        memset(&challenge, 0xff, sizeof(challenge));
218
5.57k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
219
220
5.57k
        if (SHA256((const void *)rp_id, strlen(rp_id),
221
5.57k
            rp_id_hash) != rp_id_hash) {
222
21
                fido_log_debug("%s: sha256", __func__);
223
21
                r = FIDO_ERR_INTERNAL;
224
21
                goto fail;
225
21
        }
226
227
5.55k
        key_id_len = (uint8_t)key_id->len;
228
229
5.55k
        if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
230
5.55k
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
231
5.55k
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
232
5.55k
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
233
5.55k
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
234
5.55k
            iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
235
9
                fido_log_debug("%s: iso7816", __func__);
236
9
                r = FIDO_ERR_INTERNAL;
237
9
                goto fail;
238
9
        }
239
240
5.54k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
241
26
                fido_log_debug("%s: malloc", __func__);
242
26
                r = FIDO_ERR_INTERNAL;
243
26
                goto fail;
244
26
        }
245
246
5.51k
        if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
247
5.51k
            iso7816_len(apdu), ms) < 0) {
248
225
                fido_log_debug("%s: fido_tx", __func__);
249
225
                r = FIDO_ERR_TX;
250
225
                goto fail;
251
225
        }
252
5.29k
        if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) != 2) {
253
1.87k
                fido_log_debug("%s: fido_rx", __func__);
254
1.87k
                r = FIDO_ERR_RX;
255
1.87k
                goto fail;
256
1.87k
        }
257
258
3.41k
        switch ((reply[0] << 8) | reply[1]) {
259
2.95k
        case SW_CONDITIONS_NOT_SATISFIED:
260
2.95k
                *found = 1; /* key exists */
261
2.95k
                break;
262
67
        case SW_WRONG_DATA:
263
72
        case SW_WRONG_LENGTH:
264
72
                *found = 0; /* key does not exist */
265
72
                break;
266
390
        default:
267
                /* unexpected sw */
268
390
                r = FIDO_ERR_INTERNAL;
269
390
                goto fail;
270
3.41k
        }
271
272
3.02k
        r = FIDO_OK;
273
5.63k
fail:
274
5.63k
        iso7816_free(&apdu);
275
5.63k
        freezero(reply, FIDO_MAXMSG);
276
277
5.63k
        return (r);
278
3.02k
}
279
280
static int
281
parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id,
282
    const unsigned char *reply, size_t len)
283
2.13k
{
284
2.13k
        uint8_t         flags;
285
2.13k
        uint32_t        sigcount;
286
287
2.13k
        if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
288
143
                fido_log_debug("%s: unexpected sw", __func__);
289
143
                return (FIDO_ERR_RX);
290
143
        }
291
292
1.99k
        len -= 2;
293
294
1.99k
        if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 ||
295
1.99k
            fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) {
296
8
                fido_log_debug("%s: fido_buf_read", __func__);
297
8
                return (FIDO_ERR_RX);
298
8
        }
299
300
1.98k
        if (sig_get(sig, &reply, &len) < 0) {
301
2
                fido_log_debug("%s: sig_get", __func__);
302
2
                return (FIDO_ERR_RX);
303
2
        }
304
305
1.98k
        if (authdata_fake(rp_id, flags, sigcount, ad) < 0) {
306
14
                fido_log_debug("%s; authdata_fake", __func__);
307
14
                return (FIDO_ERR_RX);
308
14
        }
309
310
1.97k
        return (FIDO_OK);
311
1.98k
}
312
313
static int
314
do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
315
    const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms)
316
2.34k
{
317
2.34k
        iso7816_apdu_t  *apdu = NULL;
318
2.34k
        unsigned char   *reply = NULL;
319
2.34k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
320
2.34k
        int              reply_len;
321
2.34k
        uint8_t          key_id_len;
322
2.34k
        int              r;
323
324
2.34k
#ifdef FIDO_FUZZ
325
2.34k
        *ms = 0; /* XXX */
326
2.34k
#endif
327
328
2.34k
        if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
329
2.34k
            rp_id == NULL) {
330
54
                r = FIDO_ERR_INVALID_ARGUMENT;
331
54
                goto fail;
332
54
        }
333
334
2.29k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
335
336
2.29k
        if (SHA256((const void *)rp_id, strlen(rp_id),
337
2.29k
            rp_id_hash) != rp_id_hash) {
338
3
                fido_log_debug("%s: sha256", __func__);
339
3
                r = FIDO_ERR_INTERNAL;
340
3
                goto fail;
341
3
        }
342
343
2.28k
        key_id_len = (uint8_t)key_id->len;
344
345
2.28k
        if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
346
2.28k
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
347
2.28k
            iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
348
2.28k
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
349
2.28k
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
350
2.28k
            iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
351
3
                fido_log_debug("%s: iso7816", __func__);
352
3
                r = FIDO_ERR_INTERNAL;
353
3
                goto fail;
354
3
        }
355
356
2.28k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
357
3
                fido_log_debug("%s: malloc", __func__);
358
3
                r = FIDO_ERR_INTERNAL;
359
3
                goto fail;
360
3
        }
361
362
3.35k
        do {
363
3.35k
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
364
3.35k
                    iso7816_len(apdu), ms) < 0) {
365
15
                        fido_log_debug("%s: fido_tx", __func__);
366
15
                        r = FIDO_ERR_TX;
367
15
                        goto fail;
368
15
                }
369
3.33k
                if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
370
3.33k
                    FIDO_MAXMSG, ms)) < 2) {
371
125
                        fido_log_debug("%s: fido_rx", __func__);
372
125
                        r = FIDO_ERR_RX;
373
125
                        goto fail;
374
125
                }
375
3.21k
                if (delay_ms(U2F_PACE_MS, ms) != 0) {
376
3
                        fido_log_debug("%s: delay_ms", __func__);
377
3
                        r = FIDO_ERR_RX;
378
3
                        goto fail;
379
3
                }
380
3.21k
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
381
382
2.13k
        if ((r = parse_auth_reply(sig, ad, rp_id, reply,
383
2.13k
            (size_t)reply_len)) != FIDO_OK) {
384
167
                fido_log_debug("%s: parse_auth_reply", __func__);
385
167
                goto fail;
386
167
        }
387
388
2.34k
fail:
389
2.34k
        iso7816_free(&apdu);
390
2.34k
        freezero(reply, FIDO_MAXMSG);
391
392
2.34k
        return (r);
393
2.13k
}
394
395
static int
396
cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len,
397
    fido_blob_t *cbor_blob)
398
693
{
399
693
        es256_pk_t      *pk = NULL;
400
693
        cbor_item_t     *pk_cbor = NULL;
401
693
        size_t           alloc_len;
402
693
        int              ok = -1;
403
404
        /* only handle uncompressed points */
405
693
        if (ec_point_len != 65 || ec_point[0] != 0x04) {
406
20
                fido_log_debug("%s: unexpected format", __func__);
407
20
                goto fail;
408
20
        }
409
410
673
        if ((pk = es256_pk_new()) == NULL ||
411
673
            es256_pk_set_x(pk, &ec_point[1]) < 0 ||
412
673
            es256_pk_set_y(pk, &ec_point[33]) < 0) {
413
3
                fido_log_debug("%s: es256_pk_set", __func__);
414
3
                goto fail;
415
3
        }
416
417
670
        if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) {
418
7
                fido_log_debug("%s: es256_pk_encode", __func__);
419
7
                goto fail;
420
7
        }
421
422
663
        if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr,
423
663
            &alloc_len)) != 77) {
424
5
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
425
5
                goto fail;
426
5
        }
427
428
658
        ok = 0;
429
693
fail:
430
693
        es256_pk_free(&pk);
431
432
693
        if (pk_cbor)
433
663
                cbor_decref(&pk_cbor);
434
435
693
        return (ok);
436
658
}
437
438
static int
439
encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c,
440
    const fido_blob_t *sig, fido_blob_t *out)
441
752
{
442
752
        cbor_item_t             *item = NULL;
443
752
        cbor_item_t             *x5c_cbor = NULL;
444
752
        const uint8_t            alg_cbor = (uint8_t)(-cose_alg - 1);
445
752
        struct cbor_pair         kv[3];
446
752
        size_t                   alloc_len;
447
752
        int                      ok = -1;
448
449
752
        memset(&kv, 0, sizeof(kv));
450
752
        memset(out, 0, sizeof(*out));
451
452
752
        if ((item = cbor_new_definite_map(3)) == NULL) {
453
4
                fido_log_debug("%s: cbor_new_definite_map", __func__);
454
4
                goto fail;
455
4
        }
456
457
748
        if ((kv[0].key = cbor_build_string("alg")) == NULL ||
458
748
            (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL ||
459
748
            !cbor_map_add(item, kv[0])) {
460
17
                fido_log_debug("%s: alg", __func__);
461
17
                goto fail;
462
17
        }
463
464
731
        if ((kv[1].key = cbor_build_string("sig")) == NULL ||
465
731
            (kv[1].value = fido_blob_encode(sig)) == NULL ||
466
731
            !cbor_map_add(item, kv[1])) {
467
13
                fido_log_debug("%s: sig", __func__);
468
13
                goto fail;
469
13
        }
470
471
718
        if ((kv[2].key = cbor_build_string("x5c")) == NULL ||
472
718
            (kv[2].value = cbor_new_definite_array(1)) == NULL ||
473
718
            (x5c_cbor = fido_blob_encode(x5c)) == NULL ||
474
718
            !cbor_array_push(kv[2].value, x5c_cbor) ||
475
718
            !cbor_map_add(item, kv[2])) {
476
21
                fido_log_debug("%s: x5c", __func__);
477
21
                goto fail;
478
21
        }
479
480
697
        if ((out->len = cbor_serialize_alloc(item, &out->ptr,
481
697
            &alloc_len)) == 0) {
482
4
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
483
4
                goto fail;
484
4
        }
485
486
693
        ok = 0;
487
752
fail:
488
752
        if (item != NULL)
489
748
                cbor_decref(&item);
490
752
        if (x5c_cbor != NULL)
491
706
                cbor_decref(&x5c_cbor);
492
493
3.00k
        for (size_t i = 0; i < nitems(kv); i++) {
494
2.25k
                if (kv[i].key)
495
2.18k
                        cbor_decref(&kv[i].key);
496
2.25k
                if (kv[i].value)
497
2.16k
                        cbor_decref(&kv[i].value);
498
2.25k
        }
499
500
752
        return (ok);
501
693
}
502
503
static int
504
encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
505
    const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out)
506
693
{
507
693
        fido_authdata_t          authdata;
508
693
        fido_attcred_raw_t       attcred_raw;
509
693
        fido_blob_t              pk_blob;
510
693
        fido_blob_t              authdata_blob;
511
693
        cbor_item_t             *authdata_cbor = NULL;
512
693
        unsigned char           *ptr;
513
693
        size_t                   len;
514
693
        size_t                   alloc_len;
515
693
        int                      ok = -1;
516
517
693
        memset(&pk_blob, 0, sizeof(pk_blob));
518
693
        memset(&authdata, 0, sizeof(authdata));
519
693
        memset(&authdata_blob, 0, sizeof(authdata_blob));
520
693
        memset(out, 0, sizeof(*out));
521
522
693
        if (rp_id == NULL) {
523
0
                fido_log_debug("%s: NULL rp_id", __func__);
524
0
                goto fail;
525
0
        }
526
527
693
        if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) {
528
35
                fido_log_debug("%s: cbor_blob_from_ec_point", __func__);
529
35
                goto fail;
530
35
        }
531
532
658
        if (SHA256((const void *)rp_id, strlen(rp_id),
533
658
            authdata.rp_id_hash) != authdata.rp_id_hash) {
534
4
                fido_log_debug("%s: sha256", __func__);
535
4
                goto fail;
536
4
        }
537
538
654
        authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT);
539
654
        authdata.sigcount = 0;
540
541
654
        memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
542
654
        attcred_raw.id_len = htobe16(kh_len);
543
544
654
        len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
545
654
            kh_len + pk_blob.len;
546
654
        ptr = authdata_blob.ptr = calloc(1, authdata_blob.len);
547
548
654
        fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len);
549
550
654
        if (authdata_blob.ptr == NULL)
551
4
                goto fail;
552
553
650
        if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 ||
554
650
            fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 ||
555
650
            fido_buf_write(&ptr, &len, kh, kh_len) < 0 ||
556
650
            fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) {
557
0
                fido_log_debug("%s: fido_buf_write", __func__);
558
0
                goto fail;
559
0
        }
560
561
650
        if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) {
562
4
                fido_log_debug("%s: fido_blob_encode", __func__);
563
4
                goto fail;
564
4
        }
565
566
646
        if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr,
567
646
            &alloc_len)) == 0) {
568
4
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
569
4
                goto fail;
570
4
        }
571
572
642
        ok = 0;
573
693
fail:
574
693
        if (authdata_cbor)
575
646
                cbor_decref(&authdata_cbor);
576
577
693
        fido_blob_reset(&pk_blob);
578
693
        fido_blob_reset(&authdata_blob);
579
580
693
        return (ok);
581
642
}
582
583
static int
584
parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
585
2.08k
{
586
2.08k
        fido_blob_t      x5c;
587
2.08k
        fido_blob_t      sig;
588
2.08k
        fido_blob_t      ad;
589
2.08k
        fido_blob_t      stmt;
590
2.08k
        uint8_t          dummy;
591
2.08k
        uint8_t          pubkey[65];
592
2.08k
        uint8_t          kh_len = 0;
593
2.08k
        uint8_t         *kh = NULL;
594
2.08k
        int              r;
595
596
2.08k
        memset(&x5c, 0, sizeof(x5c));
597
2.08k
        memset(&sig, 0, sizeof(sig));
598
2.08k
        memset(&ad, 0, sizeof(ad));
599
2.08k
        memset(&stmt, 0, sizeof(stmt));
600
2.08k
        r = FIDO_ERR_RX;
601
602
        /* status word */
603
2.08k
        if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
604
141
                fido_log_debug("%s: unexpected sw", __func__);
605
141
                goto fail;
606
141
        }
607
608
1.94k
        len -= 2;
609
610
        /* reserved byte */
611
1.94k
        if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 ||
612
1.94k
            dummy != 0x05) {
613
8
                fido_log_debug("%s: reserved byte", __func__);
614
8
                goto fail;
615
8
        }
616
617
        /* pubkey + key handle */
618
1.93k
        if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 ||
619
1.93k
            fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 ||
620
1.93k
            (kh = calloc(1, kh_len)) == NULL ||
621
1.93k
            fido_buf_read(&reply, &len, kh, kh_len) < 0) {
622
13
                fido_log_debug("%s: fido_buf_read", __func__);
623
13
                goto fail;
624
13
        }
625
626
        /* x5c + sig */
627
1.92k
        if (x5c_get(&x5c, &reply, &len) < 0 ||
628
1.92k
            sig_get(&sig, &reply, &len) < 0) {
629
1.17k
                fido_log_debug("%s: x5c || sig", __func__);
630
1.17k
                goto fail;
631
1.17k
        }
632
633
        /* attstmt */
634
752
        if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) {
635
59
                fido_log_debug("%s: encode_cred_attstmt", __func__);
636
59
                goto fail;
637
59
        }
638
639
        /* authdata */
640
693
        if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
641
693
            sizeof(pubkey), &ad) < 0) {
642
51
                fido_log_debug("%s: encode_cred_authdata", __func__);
643
51
                goto fail;
644
51
        }
645
646
642
        if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
647
642
            fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
648
642
            fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) {
649
29
                fido_log_debug("%s: fido_cred_set", __func__);
650
29
                r = FIDO_ERR_INTERNAL;
651
29
                goto fail;
652
29
        }
653
654
613
        r = FIDO_OK;
655
2.08k
fail:
656
2.08k
        freezero(kh, kh_len);
657
2.08k
        fido_blob_reset(&x5c);
658
2.08k
        fido_blob_reset(&sig);
659
2.08k
        fido_blob_reset(&ad);
660
2.08k
        fido_blob_reset(&stmt);
661
662
2.08k
        return (r);
663
613
}
664
665
int
666
u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms)
667
3.08k
{
668
3.08k
        iso7816_apdu_t  *apdu = NULL;
669
3.08k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
670
3.08k
        unsigned char   *reply = NULL;
671
3.08k
        int              reply_len;
672
3.08k
        int              found;
673
3.08k
        int              r;
674
675
3.08k
        if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
676
31
                fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
677
31
                    cred->uv);
678
31
                return (FIDO_ERR_UNSUPPORTED_OPTION);
679
31
        }
680
681
3.05k
        if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL ||
682
3.05k
            cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) {
683
133
                fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__,
684
133
                    cred->type, (void *)cred->cdh.ptr, cred->cdh.len);
685
133
                return (FIDO_ERR_INVALID_ARGUMENT);
686
133
        }
687
688
2.95k
        for (size_t i = 0; i < cred->excl.len; i++) {
689
725
                if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i],
690
725
                    &found, ms)) != FIDO_OK) {
691
511
                        fido_log_debug("%s: key_lookup", __func__);
692
511
                        return (r);
693
511
                }
694
214
                if (found) {
695
180
                        if ((r = send_dummy_register(dev, ms)) != FIDO_OK) {
696
104
                                fido_log_debug("%s: send_dummy_register",
697
104
                                    __func__);
698
104
                                return (r);
699
104
                        }
700
76
                        return (FIDO_ERR_CREDENTIAL_EXCLUDED);
701
180
                }
702
214
        }
703
704
2.22k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
705
706
2.22k
        if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id),
707
2.22k
            rp_id_hash) != rp_id_hash) {
708
4
                fido_log_debug("%s: sha256", __func__);
709
4
                return (FIDO_ERR_INTERNAL);
710
4
        }
711
712
2.22k
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
713
2.22k
            SHA256_DIGEST_LENGTH)) == NULL ||
714
2.22k
            iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 ||
715
2.22k
            iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
716
7
                fido_log_debug("%s: iso7816", __func__);
717
7
                r = FIDO_ERR_INTERNAL;
718
7
                goto fail;
719
7
        }
720
721
2.21k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
722
4
                fido_log_debug("%s: malloc", __func__);
723
4
                r = FIDO_ERR_INTERNAL;
724
4
                goto fail;
725
4
        }
726
727
4.06k
        do {
728
4.06k
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
729
4.06k
                    iso7816_len(apdu), ms) < 0) {
730
22
                        fido_log_debug("%s: fido_tx", __func__);
731
22
                        r = FIDO_ERR_TX;
732
22
                        goto fail;
733
22
                }
734
4.04k
                if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
735
4.04k
                    FIDO_MAXMSG, ms)) < 2) {
736
104
                        fido_log_debug("%s: fido_rx", __func__);
737
104
                        r = FIDO_ERR_RX;
738
104
                        goto fail;
739
104
                }
740
3.94k
                if (delay_ms(U2F_PACE_MS, ms) != 0) {
741
4
                        fido_log_debug("%s: delay_ms", __func__);
742
4
                        r = FIDO_ERR_RX;
743
4
                        goto fail;
744
4
                }
745
3.94k
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
746
747
2.08k
        if ((r = parse_register_reply(cred, reply,
748
2.08k
            (size_t)reply_len)) != FIDO_OK) {
749
1.47k
                fido_log_debug("%s: parse_register_reply", __func__);
750
1.47k
                goto fail;
751
1.47k
        }
752
2.22k
fail:
753
2.22k
        iso7816_free(&apdu);
754
2.22k
        freezero(reply, FIDO_MAXMSG);
755
756
2.22k
        return (r);
757
2.08k
}
758
759
static int
760
u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
761
    fido_assert_t *fa, size_t idx, int *ms)
762
4.91k
{
763
4.91k
        fido_blob_t     sig;
764
4.91k
        fido_blob_t     ad;
765
4.91k
        int             found;
766
4.91k
        int             r;
767
768
4.91k
        memset(&sig, 0, sizeof(sig));
769
4.91k
        memset(&ad, 0, sizeof(ad));
770
771
4.91k
        if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) {
772
2.10k
                fido_log_debug("%s: key_lookup", __func__);
773
2.10k
                goto fail;
774
2.10k
        }
775
776
2.81k
        if (!found) {
777
38
                fido_log_debug("%s: not found", __func__);
778
38
                r = FIDO_ERR_CREDENTIAL_EXCLUDED;
779
38
                goto fail;
780
38
        }
781
782
2.77k
        if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) {
783
4
                fido_log_debug("%s: fido_blob_set", __func__);
784
4
                r = FIDO_ERR_INTERNAL;
785
4
                goto fail;
786
4
        }
787
788
2.76k
        if (fa->up == FIDO_OPT_FALSE) {
789
424
                fido_log_debug("%s: checking for key existence only", __func__);
790
424
                r = FIDO_ERR_USER_PRESENCE_REQUIRED;
791
424
                goto fail;
792
424
        }
793
794
2.34k
        if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad,
795
2.34k
            ms)) != FIDO_OK) {
796
373
                fido_log_debug("%s: do_auth", __func__);
797
373
                goto fail;
798
373
        }
799
800
1.97k
        if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK ||
801
1.97k
            fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) {
802
27
                fido_log_debug("%s: fido_assert_set", __func__);
803
27
                r = FIDO_ERR_INTERNAL;
804
27
                goto fail;
805
27
        }
806
807
1.94k
        r = FIDO_OK;
808
4.91k
fail:
809
4.91k
        fido_blob_reset(&sig);
810
4.91k
        fido_blob_reset(&ad);
811
812
4.91k
        return (r);
813
1.94k
}
814
815
int
816
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms)
817
2.85k
{
818
2.85k
        size_t  nfound = 0;
819
2.85k
        size_t  nauth_ok = 0;
820
2.85k
        int     r;
821
822
2.85k
        if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
823
311
                fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv,
824
311
                    (void *)fa->allow_list.ptr);
825
311
                return (FIDO_ERR_UNSUPPORTED_OPTION);
826
311
        }
827
828
2.54k
        if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) {
829
4
                fido_log_debug("%s: fido_assert_set_count", __func__);
830
4
                return (r);
831
4
        }
832
833
4.94k
        for (size_t i = 0; i < fa->allow_list.len; i++) {
834
4.91k
                switch ((r = u2f_authenticate_single(dev,
835
4.91k
                    &fa->allow_list.ptr[i], fa, nfound, ms))) {
836
1.94k
                case FIDO_OK:
837
1.94k
                        nauth_ok++;
838
1.94k
                        FALLTHROUGH
839
2.36k
                case FIDO_ERR_USER_PRESENCE_REQUIRED:
840
2.36k
                        nfound++;
841
2.36k
                        break;
842
2.54k
                default:
843
2.54k
                        if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) {
844
2.50k
                                fido_log_debug("%s: u2f_authenticate_single",
845
2.50k
                                    __func__);
846
2.50k
                                return (r);
847
2.50k
                        }
848
                        /* ignore credentials that don't exist */
849
4.91k
                }
850
4.91k
        }
851
852
37
        fa->stmt_len = nfound;
853
854
37
        if (nfound == 0)
855
6
                return (FIDO_ERR_NO_CREDENTIALS);
856
31
        if (nauth_ok == 0)
857
4
                return (FIDO_ERR_USER_PRESENCE_REQUIRED);
858
859
27
        return (FIDO_OK);
860
31
}
861
862
int
863
u2f_get_touch_begin(fido_dev_t *dev, int *ms)
864
10.7k
{
865
10.7k
        iso7816_apdu_t  *apdu = NULL;
866
10.7k
        const char      *clientdata = FIDO_DUMMY_CLIENTDATA;
867
10.7k
        const char      *rp_id = FIDO_DUMMY_RP_ID;
868
10.7k
        unsigned char   *reply = NULL;
869
10.7k
        unsigned char    clientdata_hash[SHA256_DIGEST_LENGTH];
870
10.7k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
871
10.7k
        int              r;
872
873
10.7k
        memset(&clientdata_hash, 0, sizeof(clientdata_hash));
874
10.7k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
875
876
10.7k
        if (SHA256((const void *)clientdata, strlen(clientdata),
877
10.7k
            clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
878
10.6k
            strlen(rp_id), rp_id_hash) != rp_id_hash) {
879
72
                fido_log_debug("%s: sha256", __func__);
880
72
                return (FIDO_ERR_INTERNAL);
881
72
        }
882
883
10.6k
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
884
10.6k
            SHA256_DIGEST_LENGTH)) == NULL ||
885
10.6k
            iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
886
10.6k
            iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
887
61
                fido_log_debug("%s: iso7816", __func__);
888
61
                r = FIDO_ERR_INTERNAL;
889
61
                goto fail;
890
61
        }
891
892
10.5k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
893
34
                fido_log_debug("%s: malloc", __func__);
894
34
                r =  FIDO_ERR_INTERNAL;
895
34
                goto fail;
896
34
        }
897
898
10.5k
        if (dev->attr.flags & FIDO_CAP_WINK) {
899
6.27k
                fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms);
900
6.27k
                fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms);
901
6.27k
        }
902
903
10.5k
        if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
904
10.5k
            iso7816_len(apdu), ms) < 0) {
905
895
                fido_log_debug("%s: fido_tx", __func__);
906
895
                r = FIDO_ERR_TX;
907
895
                goto fail;
908
895
        }
909
910
9.66k
        r = FIDO_OK;
911
10.6k
fail:
912
10.6k
        iso7816_free(&apdu);
913
10.6k
        freezero(reply, FIDO_MAXMSG);
914
915
10.6k
        return (r);
916
9.66k
}
917
918
int
919
u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms)
920
10.6k
{
921
10.6k
        unsigned char   *reply;
922
10.6k
        int              reply_len;
923
10.6k
        int              r;
924
925
10.6k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
926
11
                fido_log_debug("%s: malloc", __func__);
927
11
                r =  FIDO_ERR_INTERNAL;
928
11
                goto out;
929
11
        }
930
931
10.6k
        if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG,
932
10.6k
            ms)) < 2) {
933
9.82k
                fido_log_debug("%s: fido_rx", __func__);
934
9.82k
                r = FIDO_OK; /* ignore */
935
9.82k
                goto out;
936
9.82k
        }
937
938
796
        switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
939
98
        case SW_CONDITIONS_NOT_SATISFIED:
940
98
                if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) {
941
45
                        fido_log_debug("%s: u2f_get_touch_begin", __func__);
942
45
                        goto out;
943
45
                }
944
53
                *touched = 0;
945
53
                break;
946
58
        case SW_NO_ERROR:
947
58
                *touched = 1;
948
58
                break;
949
640
        default:
950
640
                fido_log_debug("%s: unexpected sw", __func__);
951
640
                r = FIDO_ERR_RX;
952
640
                goto out;
953
796
        }
954
955
111
        r = FIDO_OK;
956
10.6k
out:
957
10.6k
        freezero(reply, FIDO_MAXMSG);
958
959
10.6k
        return (r);
960
111
}