Coverage Report

Created: 2024-06-03 09:43

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