Coverage Report

Created: 2020-03-07 10:10

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