Coverage Report

Created: 2022-01-17 10:46

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