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