Coverage Report

Created: 2024-02-05 19:20

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