Coverage Report

Created: 2021-07-20 18:14

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