Coverage Report

Created: 2025-10-04 18:33

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
8.63k
#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
8.63k
{
35
8.63k
        if (*ms_remain > -1 && (unsigned int)*ms_remain < ms)
36
5.94k
                ms = (unsigned int)*ms_remain;
37
38
8.63k
        if (ms > UINT_MAX / 1000) {
39
0
                fido_log_debug("%s: ms=%u", __func__, ms);
40
0
                return (-1);
41
0
        }
42
43
8.63k
        if (usleep(ms * 1000) < 0) {
44
13
                fido_log_error(errno, "%s: usleep", __func__);
45
13
                return (-1);
46
13
        }
47
48
8.62k
        if (*ms_remain > -1)
49
8.62k
                *ms_remain -= (int)ms;
50
51
8.62k
        return (0);
52
8.63k
}
53
54
static int
55
sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
56
3.57k
{
57
3.57k
        sig->len = *len; /* consume the whole buffer */
58
3.57k
        if ((sig->ptr = calloc(1, sig->len)) == NULL ||
59
3.57k
            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
3.56k
        return (0);
66
3.57k
}
67
68
static int
69
x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len)
70
1.94k
{
71
1.94k
        X509    *cert = NULL;
72
1.94k
        int      ok = -1;
73
74
1.94k
        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.94k
        const unsigned char *end = *buf;
81
1.94k
        if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf ||
82
1.94k
            (x5c->len = (size_t)(end - *buf)) >= *len) {
83
1.20k
                fido_log_debug("%s: d2i_X509", __func__);
84
1.20k
                goto fail;
85
1.20k
        }
86
87
        /* read accordingly */
88
740
        if ((x5c->ptr = calloc(1, x5c->len)) == NULL ||
89
740
            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
738
        ok = 0;
95
1.94k
fail:
96
1.94k
        if (cert != NULL)
97
740
                X509_free(cert);
98
99
1.94k
        if (ok < 0)
100
1.20k
                fido_blob_reset(x5c);
101
102
1.94k
        return (ok);
103
738
}
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
2.83k
{
109
2.83k
        fido_authdata_t  ad;
110
2.83k
        cbor_item_t     *item = NULL;
111
2.83k
        size_t           alloc_len;
112
113
2.83k
        memset(&ad, 0, sizeof(ad));
114
115
2.83k
        if (SHA256((const void *)rp_id, strlen(rp_id),
116
2.83k
            ad.rp_id_hash) != ad.rp_id_hash) {
117
8
                fido_log_debug("%s: sha256", __func__);
118
8
                return (-1);
119
8
        }
120
121
2.82k
        ad.flags = flags; /* XXX translate? */
122
2.82k
        ad.sigcount = sigcount;
123
124
2.82k
        if ((item = cbor_build_bytestring((const unsigned char *)&ad,
125
2.82k
            sizeof(ad))) == NULL) {
126
8
                fido_log_debug("%s: cbor_build_bytestring", __func__);
127
8
                return (-1);
128
8
        }
129
130
2.81k
        if (fake_cbor_ad->ptr != NULL ||
131
2.81k
            (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr,
132
2.81k
            &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
2.81k
        cbor_decref(&item);
139
140
2.81k
        return (0);
141
2.81k
}
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
163
{
147
163
        iso7816_apdu_t  *apdu = NULL;
148
163
        unsigned char   *reply = NULL;
149
163
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
150
163
        unsigned char    application[SHA256_DIGEST_LENGTH];
151
163
        int              r;
152
153
        /* dummy challenge & application */
154
163
        memset(&challenge, 0xff, sizeof(challenge));
155
163
        memset(&application, 0xff, sizeof(application));
156
157
163
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
158
163
            SHA256_DIGEST_LENGTH)) == NULL ||
159
163
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
160
163
            iso7816_add(apdu, &application, sizeof(application)) < 0) {
161
5
                fido_log_debug("%s: iso7816", __func__);
162
5
                r = FIDO_ERR_INTERNAL;
163
5
                goto fail;
164
5
        }
165
166
158
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
167
5
                fido_log_debug("%s: malloc", __func__);
168
5
                r = FIDO_ERR_INTERNAL;
169
5
                goto fail;
170
5
        }
171
172
534
        do {
173
534
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
174
534
                    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
521
                if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) < 2) {
180
67
                        fido_log_debug("%s: fido_rx", __func__);
181
67
                        r = FIDO_ERR_RX;
182
67
                        goto fail;
183
67
                }
184
454
                if (delay_ms(U2F_PACE_MS, ms) != 0) {
185
6
                        fido_log_debug("%s: delay_ms", __func__);
186
6
                        r = FIDO_ERR_RX;
187
6
                        goto fail;
188
6
                }
189
454
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
190
191
67
        r = FIDO_OK;
192
163
fail:
193
163
        iso7816_free(&apdu);
194
163
        freezero(reply, FIDO_MAXMSG);
195
196
163
        return (r);
197
67
}
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
8.06k
{
203
8.06k
        iso7816_apdu_t  *apdu = NULL;
204
8.06k
        unsigned char   *reply = NULL;
205
8.06k
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
206
8.06k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
207
8.06k
        uint8_t          key_id_len;
208
8.06k
        int              r;
209
210
8.06k
        if (key_id->len > UINT8_MAX || rp_id == NULL) {
211
33
                fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__,
212
33
                    key_id->len, (const void *)rp_id);
213
33
                r = FIDO_ERR_INVALID_ARGUMENT;
214
33
                goto fail;
215
33
        }
216
217
8.03k
        memset(&challenge, 0xff, sizeof(challenge));
218
8.03k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
219
220
8.03k
        if (SHA256((const void *)rp_id, strlen(rp_id),
221
8.03k
            rp_id_hash) != rp_id_hash) {
222
46
                fido_log_debug("%s: sha256", __func__);
223
46
                r = FIDO_ERR_INTERNAL;
224
46
                goto fail;
225
46
        }
226
227
7.98k
        key_id_len = (uint8_t)key_id->len;
228
229
7.98k
        if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
230
7.98k
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
231
7.98k
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
232
7.98k
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
233
7.98k
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
234
7.98k
            iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
235
30
                fido_log_debug("%s: iso7816", __func__);
236
30
                r = FIDO_ERR_INTERNAL;
237
30
                goto fail;
238
30
        }
239
240
7.95k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
241
31
                fido_log_debug("%s: malloc", __func__);
242
31
                r = FIDO_ERR_INTERNAL;
243
31
                goto fail;
244
31
        }
245
246
7.92k
        if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
247
7.92k
            iso7816_len(apdu), ms) < 0) {
248
425
                fido_log_debug("%s: fido_tx", __func__);
249
425
                r = FIDO_ERR_TX;
250
425
                goto fail;
251
425
        }
252
7.50k
        if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) != 2) {
253
2.27k
                fido_log_debug("%s: fido_rx", __func__);
254
2.27k
                r = FIDO_ERR_RX;
255
2.27k
                goto fail;
256
2.27k
        }
257
258
5.22k
        switch ((reply[0] << 8) | reply[1]) {
259
4.23k
        case SW_CONDITIONS_NOT_SATISFIED:
260
4.23k
                *found = 1; /* key exists */
261
4.23k
                break;
262
74
        case SW_WRONG_DATA:
263
94
        case SW_WRONG_LENGTH:
264
94
                *found = 0; /* key does not exist */
265
94
                break;
266
898
        default:
267
                /* unexpected sw */
268
898
                r = FIDO_ERR_INTERNAL;
269
898
                goto fail;
270
5.22k
        }
271
272
4.32k
        r = FIDO_OK;
273
8.06k
fail:
274
8.06k
        iso7816_free(&apdu);
275
8.06k
        freezero(reply, FIDO_MAXMSG);
276
277
8.06k
        return (r);
278
4.32k
}
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.99k
{
284
2.99k
        uint8_t         flags;
285
2.99k
        uint32_t        sigcount;
286
287
2.99k
        if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
288
149
                fido_log_debug("%s: unexpected sw", __func__);
289
149
                return (FIDO_ERR_RX);
290
149
        }
291
292
2.84k
        len -= 2;
293
294
2.84k
        if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 ||
295
2.84k
            fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) {
296
9
                fido_log_debug("%s: fido_buf_read", __func__);
297
9
                return (FIDO_ERR_RX);
298
9
        }
299
300
2.83k
        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
2.83k
        if (authdata_fake(rp_id, flags, sigcount, ad) < 0) {
306
19
                fido_log_debug("%s; authdata_fake", __func__);
307
19
                return (FIDO_ERR_RX);
308
19
        }
309
310
2.81k
        return (FIDO_OK);
311
2.83k
}
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
3.39k
{
317
3.39k
        iso7816_apdu_t  *apdu = NULL;
318
3.39k
        unsigned char   *reply = NULL;
319
3.39k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
320
3.39k
        int              reply_len;
321
3.39k
        uint8_t          key_id_len;
322
3.39k
        int              r;
323
324
3.39k
#ifdef FIDO_FUZZ
325
3.39k
        *ms = 0; /* XXX */
326
3.39k
#endif
327
328
3.39k
        if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
329
3.39k
            rp_id == NULL) {
330
123
                r = FIDO_ERR_INVALID_ARGUMENT;
331
123
                goto fail;
332
123
        }
333
334
3.27k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
335
336
3.27k
        if (SHA256((const void *)rp_id, strlen(rp_id),
337
3.27k
            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
3.26k
        key_id_len = (uint8_t)key_id->len;
344
345
3.26k
        if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
346
3.26k
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
347
3.26k
            iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
348
3.26k
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
349
3.26k
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
350
3.26k
            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
3.26k
        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
4.53k
        do {
363
4.53k
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
364
4.53k
                    iso7816_len(apdu), ms) < 0) {
365
14
                        fido_log_debug("%s: fido_tx", __func__);
366
14
                        r = FIDO_ERR_TX;
367
14
                        goto fail;
368
14
                }
369
4.52k
                if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
370
4.52k
                    FIDO_MAXMSG, ms)) < 2) {
371
253
                        fido_log_debug("%s: fido_rx", __func__);
372
253
                        r = FIDO_ERR_RX;
373
253
                        goto fail;
374
253
                }
375
4.27k
                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
4.27k
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
381
382
2.99k
        if ((r = parse_auth_reply(sig, ad, rp_id, reply,
383
2.99k
            (size_t)reply_len)) != FIDO_OK) {
384
179
                fido_log_debug("%s: parse_auth_reply", __func__);
385
179
                goto fail;
386
179
        }
387
388
3.39k
fail:
389
3.39k
        iso7816_free(&apdu);
390
3.39k
        freezero(reply, FIDO_MAXMSG);
391
392
3.39k
        return (r);
393
2.99k
}
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
681
{
399
681
        es256_pk_t      *pk = NULL;
400
681
        cbor_item_t     *pk_cbor = NULL;
401
681
        size_t           alloc_len;
402
681
        int              ok = -1;
403
404
        /* only handle uncompressed points */
405
681
        if (ec_point_len != 65 || ec_point[0] != 0x04) {
406
16
                fido_log_debug("%s: unexpected format", __func__);
407
16
                goto fail;
408
16
        }
409
410
665
        if ((pk = es256_pk_new()) == NULL ||
411
665
            es256_pk_set_x(pk, &ec_point[1]) < 0 ||
412
665
            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
662
        if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) {
418
5
                fido_log_debug("%s: es256_pk_encode", __func__);
419
5
                goto fail;
420
5
        }
421
422
657
        if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr,
423
657
            &alloc_len)) != 77) {
424
5
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
425
5
                goto fail;
426
5
        }
427
428
652
        ok = 0;
429
681
fail:
430
681
        es256_pk_free(&pk);
431
432
681
        if (pk_cbor)
433
657
                cbor_decref(&pk_cbor);
434
435
681
        return (ok);
436
652
}
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
736
{
442
736
        cbor_item_t             *item = NULL;
443
736
        cbor_item_t             *x5c_cbor = NULL;
444
736
        const uint8_t            alg_cbor = (uint8_t)(-cose_alg - 1);
445
736
        struct cbor_pair         kv[3];
446
736
        size_t                   alloc_len;
447
736
        int                      ok = -1;
448
449
736
        memset(&kv, 0, sizeof(kv));
450
736
        memset(out, 0, sizeof(*out));
451
452
736
        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
732
        if ((kv[0].key = cbor_build_string("alg")) == NULL ||
458
732
            (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL ||
459
732
            !cbor_map_add(item, kv[0])) {
460
15
                fido_log_debug("%s: alg", __func__);
461
15
                goto fail;
462
15
        }
463
464
717
        if ((kv[1].key = cbor_build_string("sig")) == NULL ||
465
717
            (kv[1].value = fido_blob_encode(sig)) == NULL ||
466
717
            !cbor_map_add(item, kv[1])) {
467
12
                fido_log_debug("%s: sig", __func__);
468
12
                goto fail;
469
12
        }
470
471
705
        if ((kv[2].key = cbor_build_string("x5c")) == NULL ||
472
705
            (kv[2].value = cbor_new_definite_array(1)) == NULL ||
473
705
            (x5c_cbor = fido_blob_encode(x5c)) == NULL ||
474
705
            !cbor_array_push(kv[2].value, x5c_cbor) ||
475
705
            !cbor_map_add(item, kv[2])) {
476
20
                fido_log_debug("%s: x5c", __func__);
477
20
                goto fail;
478
20
        }
479
480
685
        if ((out->len = cbor_serialize_alloc(item, &out->ptr,
481
685
            &alloc_len)) == 0) {
482
4
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
483
4
                goto fail;
484
4
        }
485
486
681
        ok = 0;
487
736
fail:
488
736
        if (item != NULL)
489
732
                cbor_decref(&item);
490
736
        if (x5c_cbor != NULL)
491
692
                cbor_decref(&x5c_cbor);
492
493
2.94k
        for (size_t i = 0; i < nitems(kv); i++) {
494
2.20k
                if (kv[i].key)
495
2.14k
                        cbor_decref(&kv[i].key);
496
2.20k
                if (kv[i].value)
497
2.12k
                        cbor_decref(&kv[i].value);
498
2.20k
        }
499
500
736
        return (ok);
501
681
}
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
681
{
507
681
        fido_authdata_t          authdata;
508
681
        fido_attcred_raw_t       attcred_raw;
509
681
        fido_blob_t              pk_blob;
510
681
        fido_blob_t              authdata_blob;
511
681
        cbor_item_t             *authdata_cbor = NULL;
512
681
        unsigned char           *ptr;
513
681
        size_t                   len;
514
681
        size_t                   alloc_len;
515
681
        int                      ok = -1;
516
517
681
        memset(&pk_blob, 0, sizeof(pk_blob));
518
681
        memset(&authdata, 0, sizeof(authdata));
519
681
        memset(&authdata_blob, 0, sizeof(authdata_blob));
520
681
        memset(out, 0, sizeof(*out));
521
522
681
        if (rp_id == NULL) {
523
0
                fido_log_debug("%s: NULL rp_id", __func__);
524
0
                goto fail;
525
0
        }
526
527
681
        if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) {
528
29
                fido_log_debug("%s: cbor_blob_from_ec_point", __func__);
529
29
                goto fail;
530
29
        }
531
532
652
        if (SHA256((const void *)rp_id, strlen(rp_id),
533
652
            authdata.rp_id_hash) != authdata.rp_id_hash) {
534
4
                fido_log_debug("%s: sha256", __func__);
535
4
                goto fail;
536
4
        }
537
538
648
        authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT);
539
648
        authdata.sigcount = 0;
540
541
648
        memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
542
648
        attcred_raw.id_len = htobe16(kh_len);
543
544
648
        len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
545
648
            kh_len + pk_blob.len;
546
648
        ptr = authdata_blob.ptr = calloc(1, authdata_blob.len);
547
548
648
        fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len);
549
550
648
        if (authdata_blob.ptr == NULL)
551
4
                goto fail;
552
553
644
        if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 ||
554
644
            fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 ||
555
644
            fido_buf_write(&ptr, &len, kh, kh_len) < 0 ||
556
644
            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
644
        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
640
        if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr,
567
640
            &alloc_len)) == 0) {
568
4
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
569
4
                goto fail;
570
4
        }
571
572
636
        ok = 0;
573
681
fail:
574
681
        if (authdata_cbor)
575
640
                cbor_decref(&authdata_cbor);
576
577
681
        fido_blob_reset(&pk_blob);
578
681
        fido_blob_reset(&authdata_blob);
579
580
681
        return (ok);
581
636
}
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
119
                fido_log_debug("%s: unexpected sw", __func__);
605
119
                goto fail;
606
119
        }
607
608
1.96k
        len -= 2;
609
610
        /* reserved byte */
611
1.96k
        if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 ||
612
1.96k
            dummy != 0x05) {
613
8
                fido_log_debug("%s: reserved byte", __func__);
614
8
                goto fail;
615
8
        }
616
617
        /* pubkey + key handle */
618
1.96k
        if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 ||
619
1.96k
            fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 ||
620
1.96k
            (kh = calloc(1, kh_len)) == NULL ||
621
1.96k
            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.94k
        if (x5c_get(&x5c, &reply, &len) < 0 ||
628
1.94k
            sig_get(&sig, &reply, &len) < 0) {
629
1.21k
                fido_log_debug("%s: x5c || sig", __func__);
630
1.21k
                goto fail;
631
1.21k
        }
632
633
        /* attstmt */
634
736
        if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) {
635
55
                fido_log_debug("%s: encode_cred_attstmt", __func__);
636
55
                goto fail;
637
55
        }
638
639
        /* authdata */
640
681
        if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
641
681
            sizeof(pubkey), &ad) < 0) {
642
45
                fido_log_debug("%s: encode_cred_authdata", __func__);
643
45
                goto fail;
644
45
        }
645
646
636
        if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
647
636
            fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
648
636
            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
607
        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
607
}
664
665
int
666
u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms)
667
3.32k
{
668
3.32k
        iso7816_apdu_t  *apdu = NULL;
669
3.32k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
670
3.32k
        unsigned char   *reply = NULL;
671
3.32k
        int              reply_len;
672
3.32k
        int              found;
673
3.32k
        int              r;
674
675
3.32k
        if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
676
82
                fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
677
82
                    cred->uv);
678
82
                return (FIDO_ERR_UNSUPPORTED_OPTION);
679
82
        }
680
681
3.24k
        if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL ||
682
3.24k
            cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) {
683
238
                fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__,
684
238
                    cred->type, (void *)cred->cdh.ptr, cred->cdh.len);
685
238
                return (FIDO_ERR_INVALID_ARGUMENT);
686
238
        }
687
688
3.03k
        for (size_t i = 0; i < cred->excl.len; i++) {
689
846
                if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i],
690
846
                    &found, ms)) != FIDO_OK) {
691
650
                        fido_log_debug("%s: key_lookup", __func__);
692
650
                        return (r);
693
650
                }
694
196
                if (found) {
695
163
                        if ((r = send_dummy_register(dev, ms)) != FIDO_OK) {
696
96
                                fido_log_debug("%s: send_dummy_register",
697
96
                                    __func__);
698
96
                                return (r);
699
96
                        }
700
67
                        return (FIDO_ERR_CREDENTIAL_EXCLUDED);
701
163
                }
702
196
        }
703
704
2.18k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
705
706
2.18k
        if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id),
707
2.18k
            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.18k
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
713
2.18k
            SHA256_DIGEST_LENGTH)) == NULL ||
714
2.18k
            iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 ||
715
2.18k
            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.17k
        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
3.99k
        do {
728
3.99k
                if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
729
3.99k
                    iso7816_len(apdu), ms) < 0) {
730
15
                        fido_log_debug("%s: fido_tx", __func__);
731
15
                        r = FIDO_ERR_TX;
732
15
                        goto fail;
733
15
                }
734
3.98k
                if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
735
3.98k
                    FIDO_MAXMSG, ms)) < 2) {
736
68
                        fido_log_debug("%s: fido_rx", __func__);
737
68
                        r = FIDO_ERR_RX;
738
68
                        goto fail;
739
68
                }
740
3.91k
                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.91k
        } 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.48k
                fido_log_debug("%s: parse_register_reply", __func__);
750
1.48k
                goto fail;
751
1.48k
        }
752
2.18k
fail:
753
2.18k
        iso7816_free(&apdu);
754
2.18k
        freezero(reply, FIDO_MAXMSG);
755
756
2.18k
        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
7.21k
{
763
7.21k
        fido_blob_t     sig;
764
7.21k
        fido_blob_t     ad;
765
7.21k
        int             found;
766
7.21k
        int             r;
767
768
7.21k
        memset(&sig, 0, sizeof(sig));
769
7.21k
        memset(&ad, 0, sizeof(ad));
770
771
7.21k
        if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) {
772
3.08k
                fido_log_debug("%s: key_lookup", __func__);
773
3.08k
                goto fail;
774
3.08k
        }
775
776
4.13k
        if (!found) {
777
61
                fido_log_debug("%s: not found", __func__);
778
61
                r = FIDO_ERR_CREDENTIAL_EXCLUDED;
779
61
                goto fail;
780
61
        }
781
782
4.06k
        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
4.06k
        if (fa->up == FIDO_OPT_FALSE) {
789
670
                fido_log_debug("%s: checking for key existence only", __func__);
790
670
                r = FIDO_ERR_USER_PRESENCE_REQUIRED;
791
670
                goto fail;
792
670
        }
793
794
3.39k
        if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad,
795
3.39k
            ms)) != FIDO_OK) {
796
581
                fido_log_debug("%s: do_auth", __func__);
797
581
                goto fail;
798
581
        }
799
800
2.81k
        if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK ||
801
2.81k
            fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) {
802
28
                fido_log_debug("%s: fido_assert_set", __func__);
803
28
                r = FIDO_ERR_INTERNAL;
804
28
                goto fail;
805
28
        }
806
807
2.78k
        r = FIDO_OK;
808
7.21k
fail:
809
7.21k
        fido_blob_reset(&sig);
810
7.21k
        fido_blob_reset(&ad);
811
812
7.21k
        return (r);
813
2.78k
}
814
815
int
816
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms)
817
4.15k
{
818
4.15k
        size_t  nfound = 0;
819
4.15k
        size_t  nauth_ok = 0;
820
4.15k
        int     r;
821
822
4.15k
        if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
823
384
                fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv,
824
384
                    (void *)fa->allow_list.ptr);
825
384
                return (FIDO_ERR_UNSUPPORTED_OPTION);
826
384
        }
827
828
3.76k
        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
7.28k
        for (size_t i = 0; i < fa->allow_list.len; i++) {
834
7.21k
                switch ((r = u2f_authenticate_single(dev,
835
7.21k
                    &fa->allow_list.ptr[i], fa, nfound, ms))) {
836
2.78k
                case FIDO_OK:
837
2.78k
                        nauth_ok++;
838
2.78k
                        FALLTHROUGH
839
3.45k
                case FIDO_ERR_USER_PRESENCE_REQUIRED:
840
3.45k
                        nfound++;
841
3.45k
                        break;
842
3.76k
                default:
843
3.76k
                        if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) {
844
3.70k
                                fido_log_debug("%s: u2f_authenticate_single",
845
3.70k
                                    __func__);
846
3.70k
                                return (r);
847
3.70k
                        }
848
                        /* ignore credentials that don't exist */
849
7.21k
                }
850
7.21k
        }
851
852
61
        fa->stmt_len = nfound;
853
854
61
        if (nfound == 0)
855
23
                return (FIDO_ERR_NO_CREDENTIALS);
856
38
        if (nauth_ok == 0)
857
10
                return (FIDO_ERR_USER_PRESENCE_REQUIRED);
858
859
28
        return (FIDO_OK);
860
38
}
861
862
int
863
u2f_get_touch_begin(fido_dev_t *dev, int *ms)
864
15.8k
{
865
15.8k
        iso7816_apdu_t  *apdu = NULL;
866
15.8k
        const char      *clientdata = FIDO_DUMMY_CLIENTDATA;
867
15.8k
        const char      *rp_id = FIDO_DUMMY_RP_ID;
868
15.8k
        unsigned char   *reply = NULL;
869
15.8k
        unsigned char    clientdata_hash[SHA256_DIGEST_LENGTH];
870
15.8k
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
871
15.8k
        int              r;
872
873
15.8k
        memset(&clientdata_hash, 0, sizeof(clientdata_hash));
874
15.8k
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
875
876
15.8k
        if (SHA256((const void *)clientdata, strlen(clientdata),
877
15.8k
            clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
878
15.7k
            strlen(rp_id), rp_id_hash) != rp_id_hash) {
879
258
                fido_log_debug("%s: sha256", __func__);
880
258
                return (FIDO_ERR_INTERNAL);
881
258
        }
882
883
15.5k
        if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
884
15.5k
            SHA256_DIGEST_LENGTH)) == NULL ||
885
15.5k
            iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
886
15.5k
            iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
887
161
                fido_log_debug("%s: iso7816", __func__);
888
161
                r = FIDO_ERR_INTERNAL;
889
161
                goto fail;
890
161
        }
891
892
15.4k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
893
70
                fido_log_debug("%s: malloc", __func__);
894
70
                r =  FIDO_ERR_INTERNAL;
895
70
                goto fail;
896
70
        }
897
898
15.3k
        if (dev->attr.flags & FIDO_CAP_WINK) {
899
9.58k
                fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms);
900
9.58k
                fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms);
901
9.58k
        }
902
903
15.3k
        if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
904
15.3k
            iso7816_len(apdu), ms) < 0) {
905
1.14k
                fido_log_debug("%s: fido_tx", __func__);
906
1.14k
                r = FIDO_ERR_TX;
907
1.14k
                goto fail;
908
1.14k
        }
909
910
14.2k
        r = FIDO_OK;
911
15.5k
fail:
912
15.5k
        iso7816_free(&apdu);
913
15.5k
        freezero(reply, FIDO_MAXMSG);
914
915
15.5k
        return (r);
916
14.2k
}
917
918
int
919
u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms)
920
15.5k
{
921
15.5k
        unsigned char   *reply;
922
15.5k
        int              reply_len;
923
15.5k
        int              r;
924
925
15.5k
        if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
926
48
                fido_log_debug("%s: malloc", __func__);
927
48
                r =  FIDO_ERR_INTERNAL;
928
48
                goto out;
929
48
        }
930
931
15.5k
        if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG,
932
15.5k
            ms)) < 2) {
933
13.9k
                fido_log_debug("%s: fido_rx", __func__);
934
13.9k
                r = FIDO_OK; /* ignore */
935
13.9k
                goto out;
936
13.9k
        }
937
938
1.59k
        switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
939
264
        case SW_CONDITIONS_NOT_SATISFIED:
940
264
                if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) {
941
161
                        fido_log_debug("%s: u2f_get_touch_begin", __func__);
942
161
                        goto out;
943
161
                }
944
103
                *touched = 0;
945
103
                break;
946
77
        case SW_NO_ERROR:
947
77
                *touched = 1;
948
77
                break;
949
1.24k
        default:
950
1.24k
                fido_log_debug("%s: unexpected sw", __func__);
951
1.24k
                r = FIDO_ERR_RX;
952
1.24k
                goto out;
953
1.59k
        }
954
955
180
        r = FIDO_OK;
956
15.5k
out:
957
15.5k
        freezero(reply, FIDO_MAXMSG);
958
959
15.5k
        return (r);
960
180
}