xref: /freebsd-src/contrib/libfido2/tools/bio.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
20afa8e06SEd Maste  * Copyright (c) 2019 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <fido.h>
90afa8e06SEd Maste #include <fido/bio.h>
100afa8e06SEd Maste 
110afa8e06SEd Maste #include <stdio.h>
120afa8e06SEd Maste #include <stdlib.h>
130afa8e06SEd Maste #include <string.h>
140afa8e06SEd Maste #ifdef HAVE_UNISTD_H
150afa8e06SEd Maste #include <unistd.h>
160afa8e06SEd Maste #endif
170afa8e06SEd Maste 
180afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
190afa8e06SEd Maste #include "extern.h"
200afa8e06SEd Maste 
210afa8e06SEd Maste static int
print_template(const fido_bio_template_array_t * ta,size_t idx)220afa8e06SEd Maste print_template(const fido_bio_template_array_t *ta, size_t idx)
230afa8e06SEd Maste {
240afa8e06SEd Maste 	const fido_bio_template_t *t = NULL;
250afa8e06SEd Maste 	char *id = NULL;
260afa8e06SEd Maste 
270afa8e06SEd Maste 	if ((t = fido_bio_template(ta, idx)) == NULL) {
280afa8e06SEd Maste 		warnx("fido_bio_template");
290afa8e06SEd Maste 		return -1;
300afa8e06SEd Maste 	}
310afa8e06SEd Maste 	if (base64_encode(fido_bio_template_id_ptr(t),
320afa8e06SEd Maste 	    fido_bio_template_id_len(t), &id) < 0) {
330afa8e06SEd Maste 		warnx("output error");
340afa8e06SEd Maste 		return -1;
350afa8e06SEd Maste 	}
360afa8e06SEd Maste 
370afa8e06SEd Maste 	printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t));
380afa8e06SEd Maste 	free(id);
390afa8e06SEd Maste 
400afa8e06SEd Maste 	return 0;
410afa8e06SEd Maste }
420afa8e06SEd Maste 
430afa8e06SEd Maste int
bio_list(const char * path)440afa8e06SEd Maste bio_list(const char *path)
450afa8e06SEd Maste {
460afa8e06SEd Maste 	fido_bio_template_array_t *ta = NULL;
470afa8e06SEd Maste 	fido_dev_t *dev = NULL;
480afa8e06SEd Maste 	char *pin = NULL;
490afa8e06SEd Maste 	int r, ok = 1;
500afa8e06SEd Maste 
510afa8e06SEd Maste 	if ((ta = fido_bio_template_array_new()) == NULL)
520afa8e06SEd Maste 		errx(1, "fido_bio_template_array_new");
530afa8e06SEd Maste 	dev = open_dev(path);
540afa8e06SEd Maste 	if ((pin = get_pin(path)) == NULL)
550afa8e06SEd Maste 		goto out;
560afa8e06SEd Maste 	r = fido_bio_dev_get_template_array(dev, ta, pin);
570afa8e06SEd Maste 	freezero(pin, PINBUF_LEN);
580afa8e06SEd Maste 	pin = NULL;
590afa8e06SEd Maste 	if (r != FIDO_OK) {
600afa8e06SEd Maste 		warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r));
610afa8e06SEd Maste 		goto out;
620afa8e06SEd Maste 	}
630afa8e06SEd Maste 	for (size_t i = 0; i < fido_bio_template_array_count(ta); i++)
640afa8e06SEd Maste 		if (print_template(ta, i) < 0)
650afa8e06SEd Maste 			goto out;
660afa8e06SEd Maste 
670afa8e06SEd Maste 	ok = 0;
680afa8e06SEd Maste out:
690afa8e06SEd Maste 	fido_bio_template_array_free(&ta);
700afa8e06SEd Maste 	fido_dev_close(dev);
710afa8e06SEd Maste 	fido_dev_free(&dev);
720afa8e06SEd Maste 
730afa8e06SEd Maste 	exit(ok);
740afa8e06SEd Maste }
750afa8e06SEd Maste 
760afa8e06SEd Maste int
bio_set_name(const char * path,const char * id,const char * name)770afa8e06SEd Maste bio_set_name(const char *path, const char *id, const char *name)
780afa8e06SEd Maste {
790afa8e06SEd Maste 	fido_bio_template_t *t = NULL;
800afa8e06SEd Maste 	fido_dev_t *dev = NULL;
810afa8e06SEd Maste 	char *pin = NULL;
820afa8e06SEd Maste 	void *id_blob_ptr = NULL;
830afa8e06SEd Maste 	size_t id_blob_len = 0;
840afa8e06SEd Maste 	int r, ok = 1;
850afa8e06SEd Maste 
860afa8e06SEd Maste 	if ((t = fido_bio_template_new()) == NULL)
870afa8e06SEd Maste 		errx(1, "fido_bio_template_new");
880afa8e06SEd Maste 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
890afa8e06SEd Maste 		errx(1, "base64_decode");
900afa8e06SEd Maste 	if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK)
910afa8e06SEd Maste 		errx(1, "fido_bio_template_set_name: %s", fido_strerr(r));
920afa8e06SEd Maste 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
930afa8e06SEd Maste 	    id_blob_len)) != FIDO_OK)
940afa8e06SEd Maste 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
950afa8e06SEd Maste 
960afa8e06SEd Maste 	dev = open_dev(path);
970afa8e06SEd Maste 	if ((pin = get_pin(path)) == NULL)
980afa8e06SEd Maste 		goto out;
990afa8e06SEd Maste 	r = fido_bio_dev_set_template_name(dev, t, pin);
1000afa8e06SEd Maste 	freezero(pin, PINBUF_LEN);
1010afa8e06SEd Maste 	pin = NULL;
1020afa8e06SEd Maste 	if (r != FIDO_OK) {
1030afa8e06SEd Maste 		warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r));
1040afa8e06SEd Maste 		goto out;
1050afa8e06SEd Maste 	}
1060afa8e06SEd Maste 
1070afa8e06SEd Maste 	ok = 0;
1080afa8e06SEd Maste out:
1090afa8e06SEd Maste 	free(id_blob_ptr);
1100afa8e06SEd Maste 	fido_bio_template_free(&t);
1110afa8e06SEd Maste 	fido_dev_close(dev);
1120afa8e06SEd Maste 	fido_dev_free(&dev);
1130afa8e06SEd Maste 
1140afa8e06SEd Maste 	exit(ok);
1150afa8e06SEd Maste }
1160afa8e06SEd Maste 
1170afa8e06SEd Maste static const char *
enroll_strerr(uint8_t n)1180afa8e06SEd Maste enroll_strerr(uint8_t n)
1190afa8e06SEd Maste {
1200afa8e06SEd Maste 	switch (n) {
1210afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_GOOD:
1220afa8e06SEd Maste 		return "Sample ok";
1230afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_HIGH:
1240afa8e06SEd Maste 		return "Sample too high";
1250afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_LOW:
1260afa8e06SEd Maste 		return "Sample too low";
1270afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_LEFT:
1280afa8e06SEd Maste 		return "Sample too left";
1290afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_RIGHT:
1300afa8e06SEd Maste 		return "Sample too right";
1310afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_FAST:
1320afa8e06SEd Maste 		return "Sample too fast";
1330afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_SLOW:
1340afa8e06SEd Maste 		return "Sample too slow";
1350afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_POOR_QUALITY:
1360afa8e06SEd Maste 		return "Poor quality sample";
1370afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_SKEWED:
1380afa8e06SEd Maste 		return "Sample too skewed";
1390afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_TOO_SHORT:
1400afa8e06SEd Maste 		return "Sample too short";
1410afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_MERGE_FAILURE:
1420afa8e06SEd Maste 		return "Sample merge failure";
1430afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_EXISTS:
1440afa8e06SEd Maste 		return "Sample exists";
1450afa8e06SEd Maste 	case FIDO_BIO_ENROLL_FP_DATABASE_FULL:
1460afa8e06SEd Maste 		return "Fingerprint database full";
1470afa8e06SEd Maste 	case FIDO_BIO_ENROLL_NO_USER_ACTIVITY:
1480afa8e06SEd Maste 		return "No user activity";
1490afa8e06SEd Maste 	case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION:
1500afa8e06SEd Maste 		return "No user presence transition";
1510afa8e06SEd Maste 	default:
1520afa8e06SEd Maste 		return "Unknown error";
1530afa8e06SEd Maste 	}
1540afa8e06SEd Maste }
1550afa8e06SEd Maste 
1560afa8e06SEd Maste int
bio_enroll(const char * path)1570afa8e06SEd Maste bio_enroll(const char *path)
1580afa8e06SEd Maste {
1590afa8e06SEd Maste 	fido_bio_template_t *t = NULL;
1600afa8e06SEd Maste 	fido_bio_enroll_t *e = NULL;
1610afa8e06SEd Maste 	fido_dev_t *dev = NULL;
1620afa8e06SEd Maste 	char *pin = NULL;
1630afa8e06SEd Maste 	int r, ok = 1;
1640afa8e06SEd Maste 
1650afa8e06SEd Maste 	if ((t = fido_bio_template_new()) == NULL)
1660afa8e06SEd Maste 		errx(1, "fido_bio_template_new");
1670afa8e06SEd Maste 	if ((e = fido_bio_enroll_new()) == NULL)
1680afa8e06SEd Maste 		errx(1, "fido_bio_enroll_new");
1690afa8e06SEd Maste 
1700afa8e06SEd Maste 	dev = open_dev(path);
1710afa8e06SEd Maste 	if ((pin = get_pin(path)) == NULL)
1720afa8e06SEd Maste 		goto out;
1730afa8e06SEd Maste 	printf("Touch your security key.\n");
1740afa8e06SEd Maste 	r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin);
1750afa8e06SEd Maste 	freezero(pin, PINBUF_LEN);
1760afa8e06SEd Maste 	pin = NULL;
1770afa8e06SEd Maste 	if (r != FIDO_OK) {
1780afa8e06SEd Maste 		warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r));
1790afa8e06SEd Maste 		goto out;
1800afa8e06SEd Maste 	}
1810afa8e06SEd Maste 	printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
1820afa8e06SEd Maste 
1830afa8e06SEd Maste 	while (fido_bio_enroll_remaining_samples(e) > 0) {
1840afa8e06SEd Maste 		printf("Touch your security key (%u sample%s left).\n",
1850afa8e06SEd Maste 		    (unsigned)fido_bio_enroll_remaining_samples(e),
1860afa8e06SEd Maste 		    plural(fido_bio_enroll_remaining_samples(e)));
1870afa8e06SEd Maste 		if ((r = fido_bio_dev_enroll_continue(dev, t, e,
1880afa8e06SEd Maste 		    10000)) != FIDO_OK) {
1890afa8e06SEd Maste 			fido_dev_cancel(dev);
1900afa8e06SEd Maste 			warnx("fido_bio_dev_enroll_continue: %s",
1910afa8e06SEd Maste 			    fido_strerr(r));
1920afa8e06SEd Maste 			goto out;
1930afa8e06SEd Maste 		}
1940afa8e06SEd Maste 		printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
1950afa8e06SEd Maste 	}
1960afa8e06SEd Maste 
1970afa8e06SEd Maste 	ok = 0;
1980afa8e06SEd Maste out:
1990afa8e06SEd Maste 	fido_bio_template_free(&t);
2000afa8e06SEd Maste 	fido_bio_enroll_free(&e);
2010afa8e06SEd Maste 	fido_dev_close(dev);
2020afa8e06SEd Maste 	fido_dev_free(&dev);
2030afa8e06SEd Maste 
2040afa8e06SEd Maste 	exit(ok);
2050afa8e06SEd Maste }
2060afa8e06SEd Maste 
2070afa8e06SEd Maste int
bio_delete(const char * path,const char * id)2080afa8e06SEd Maste bio_delete(const char *path, const char *id)
2090afa8e06SEd Maste {
2100afa8e06SEd Maste 	fido_bio_template_t *t = NULL;
2110afa8e06SEd Maste 	fido_dev_t *dev = NULL;
2120afa8e06SEd Maste 	char *pin = NULL;
2130afa8e06SEd Maste 	void *id_blob_ptr = NULL;
2140afa8e06SEd Maste 	size_t id_blob_len = 0;
2150afa8e06SEd Maste 	int r, ok = 1;
2160afa8e06SEd Maste 
2170afa8e06SEd Maste 	if ((t = fido_bio_template_new()) == NULL)
2180afa8e06SEd Maste 		errx(1, "fido_bio_template_new");
2190afa8e06SEd Maste 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
2200afa8e06SEd Maste 		errx(1, "base64_decode");
2210afa8e06SEd Maste 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
2220afa8e06SEd Maste 	    id_blob_len)) != FIDO_OK)
2230afa8e06SEd Maste 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
2240afa8e06SEd Maste 
2250afa8e06SEd Maste 	dev = open_dev(path);
2260afa8e06SEd Maste 	if ((pin = get_pin(path)) == NULL)
2270afa8e06SEd Maste 		goto out;
2280afa8e06SEd Maste 	r = fido_bio_dev_enroll_remove(dev, t, pin);
2290afa8e06SEd Maste 	freezero(pin, PINBUF_LEN);
2300afa8e06SEd Maste 	pin = NULL;
2310afa8e06SEd Maste 	if (r != FIDO_OK) {
2320afa8e06SEd Maste 		warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r));
2330afa8e06SEd Maste 		goto out;
2340afa8e06SEd Maste 	}
2350afa8e06SEd Maste 
2360afa8e06SEd Maste 	ok = 0;
2370afa8e06SEd Maste out:
2380afa8e06SEd Maste 	free(id_blob_ptr);
2390afa8e06SEd Maste 	fido_bio_template_free(&t);
2400afa8e06SEd Maste 	fido_dev_close(dev);
2410afa8e06SEd Maste 	fido_dev_free(&dev);
2420afa8e06SEd Maste 
2430afa8e06SEd Maste 	exit(ok);
2440afa8e06SEd Maste }
2450afa8e06SEd Maste 
2460afa8e06SEd Maste static const char *
type_str(uint8_t t)2470afa8e06SEd Maste type_str(uint8_t t)
2480afa8e06SEd Maste {
2490afa8e06SEd Maste 	switch (t) {
2500afa8e06SEd Maste 	case 1:
2510afa8e06SEd Maste 		return "touch";
2520afa8e06SEd Maste 	case 2:
2530afa8e06SEd Maste 		return "swipe";
2540afa8e06SEd Maste 	default:
2550afa8e06SEd Maste 		return "unknown";
2560afa8e06SEd Maste 	}
2570afa8e06SEd Maste }
2580afa8e06SEd Maste 
2590afa8e06SEd Maste void
bio_info(fido_dev_t * dev)2600afa8e06SEd Maste bio_info(fido_dev_t *dev)
2610afa8e06SEd Maste {
2620afa8e06SEd Maste 	fido_bio_info_t	*i = NULL;
2630afa8e06SEd Maste 
2640afa8e06SEd Maste 	if ((i = fido_bio_info_new()) == NULL) {
2650afa8e06SEd Maste 		warnx("fido_bio_info_new");
2660afa8e06SEd Maste 		return;
2670afa8e06SEd Maste 	}
2680afa8e06SEd Maste 	if (fido_bio_dev_get_info(dev, i) != FIDO_OK) {
2690afa8e06SEd Maste 		fido_bio_info_free(&i);
2700afa8e06SEd Maste 		return;
2710afa8e06SEd Maste 	}
2720afa8e06SEd Maste 
2730afa8e06SEd Maste 	printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i),
2740afa8e06SEd Maste 	    type_str(fido_bio_info_type(i)));
2750afa8e06SEd Maste 	printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i));
2760afa8e06SEd Maste 
2770afa8e06SEd Maste 	fido_bio_info_free(&i);
2780afa8e06SEd Maste }
279