Coverage Report

Created: 2020-09-01 07:05

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