xref: /netbsd-src/external/bsd/libfido2/dist/tools/bio.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
1ba9bdd8bSchristos /*
2ba9bdd8bSchristos  * Copyright (c) 2019 Yubico AB. All rights reserved.
3ba9bdd8bSchristos  * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos  * license that can be found in the LICENSE file.
5*2d40c451Schristos  * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos  */
7ba9bdd8bSchristos 
8ba9bdd8bSchristos #include <fido.h>
9ba9bdd8bSchristos #include <fido/bio.h>
10ba9bdd8bSchristos 
11ba9bdd8bSchristos #include <stdio.h>
12ba9bdd8bSchristos #include <stdlib.h>
13ba9bdd8bSchristos #include <string.h>
14ba9bdd8bSchristos #ifdef HAVE_UNISTD_H
15ba9bdd8bSchristos #include <unistd.h>
16ba9bdd8bSchristos #endif
17ba9bdd8bSchristos 
18ba9bdd8bSchristos #include "../openbsd-compat/openbsd-compat.h"
19ba9bdd8bSchristos #include "extern.h"
20ba9bdd8bSchristos 
2195dbdf32Schristos static int
print_template(const fido_bio_template_array_t * ta,size_t idx)22ba9bdd8bSchristos print_template(const fido_bio_template_array_t *ta, size_t idx)
23ba9bdd8bSchristos {
24ba9bdd8bSchristos 	const fido_bio_template_t *t = NULL;
2595dbdf32Schristos 	char *id = NULL;
26ba9bdd8bSchristos 
2795dbdf32Schristos 	if ((t = fido_bio_template(ta, idx)) == NULL) {
2895dbdf32Schristos 		warnx("fido_bio_template");
2995dbdf32Schristos 		return -1;
3095dbdf32Schristos 	}
31ba9bdd8bSchristos 	if (base64_encode(fido_bio_template_id_ptr(t),
3295dbdf32Schristos 	    fido_bio_template_id_len(t), &id) < 0) {
3395dbdf32Schristos 		warnx("output error");
3495dbdf32Schristos 		return -1;
3595dbdf32Schristos 	}
36ba9bdd8bSchristos 
37ba9bdd8bSchristos 	printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t));
38ba9bdd8bSchristos 	free(id);
3995dbdf32Schristos 
4095dbdf32Schristos 	return 0;
41ba9bdd8bSchristos }
42ba9bdd8bSchristos 
43ba9bdd8bSchristos int
bio_list(const char * path)4495dbdf32Schristos bio_list(const char *path)
45ba9bdd8bSchristos {
46ba9bdd8bSchristos 	fido_bio_template_array_t *ta = NULL;
47ba9bdd8bSchristos 	fido_dev_t *dev = NULL;
4895dbdf32Schristos 	char *pin = NULL;
4995dbdf32Schristos 	int r, ok = 1;
50ba9bdd8bSchristos 
51ba9bdd8bSchristos 	if ((ta = fido_bio_template_array_new()) == NULL)
52ba9bdd8bSchristos 		errx(1, "fido_bio_template_array_new");
53ba9bdd8bSchristos 	dev = open_dev(path);
5495dbdf32Schristos 	if ((pin = get_pin(path)) == NULL)
5595dbdf32Schristos 		goto out;
56ba9bdd8bSchristos 	r = fido_bio_dev_get_template_array(dev, ta, pin);
5795dbdf32Schristos 	freezero(pin, PINBUF_LEN);
5895dbdf32Schristos 	pin = NULL;
5995dbdf32Schristos 	if (r != FIDO_OK) {
6095dbdf32Schristos 		warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r));
6195dbdf32Schristos 		goto out;
6295dbdf32Schristos 	}
63ba9bdd8bSchristos 	for (size_t i = 0; i < fido_bio_template_array_count(ta); i++)
6495dbdf32Schristos 		if (print_template(ta, i) < 0)
6595dbdf32Schristos 			goto out;
66ba9bdd8bSchristos 
6795dbdf32Schristos 	ok = 0;
6895dbdf32Schristos out:
69ba9bdd8bSchristos 	fido_bio_template_array_free(&ta);
70ba9bdd8bSchristos 	fido_dev_close(dev);
71ba9bdd8bSchristos 	fido_dev_free(&dev);
72ba9bdd8bSchristos 
7395dbdf32Schristos 	exit(ok);
74ba9bdd8bSchristos }
75ba9bdd8bSchristos 
76ba9bdd8bSchristos int
bio_set_name(const char * path,const char * id,const char * name)7795dbdf32Schristos bio_set_name(const char *path, const char *id, const char *name)
78ba9bdd8bSchristos {
79ba9bdd8bSchristos 	fido_bio_template_t *t = NULL;
80ba9bdd8bSchristos 	fido_dev_t *dev = NULL;
8195dbdf32Schristos 	char *pin = NULL;
82ba9bdd8bSchristos 	void *id_blob_ptr = NULL;
8395dbdf32Schristos 	size_t id_blob_len = 0;
8495dbdf32Schristos 	int r, ok = 1;
85ba9bdd8bSchristos 
86ba9bdd8bSchristos 	if ((t = fido_bio_template_new()) == NULL)
87ba9bdd8bSchristos 		errx(1, "fido_bio_template_new");
88ba9bdd8bSchristos 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
89ba9bdd8bSchristos 		errx(1, "base64_decode");
90ba9bdd8bSchristos 	if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK)
91ba9bdd8bSchristos 		errx(1, "fido_bio_template_set_name: %s", fido_strerr(r));
92ba9bdd8bSchristos 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
93ba9bdd8bSchristos 	    id_blob_len)) != FIDO_OK)
94ba9bdd8bSchristos 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
95ba9bdd8bSchristos 
96ba9bdd8bSchristos 	dev = open_dev(path);
9795dbdf32Schristos 	if ((pin = get_pin(path)) == NULL)
9895dbdf32Schristos 		goto out;
99ba9bdd8bSchristos 	r = fido_bio_dev_set_template_name(dev, t, pin);
10095dbdf32Schristos 	freezero(pin, PINBUF_LEN);
10195dbdf32Schristos 	pin = NULL;
10295dbdf32Schristos 	if (r != FIDO_OK) {
10395dbdf32Schristos 		warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r));
10495dbdf32Schristos 		goto out;
10595dbdf32Schristos 	}
106ba9bdd8bSchristos 
10795dbdf32Schristos 	ok = 0;
10895dbdf32Schristos out:
109ba9bdd8bSchristos 	free(id_blob_ptr);
110ba9bdd8bSchristos 	fido_bio_template_free(&t);
111ba9bdd8bSchristos 	fido_dev_close(dev);
112ba9bdd8bSchristos 	fido_dev_free(&dev);
113ba9bdd8bSchristos 
11495dbdf32Schristos 	exit(ok);
115ba9bdd8bSchristos }
116ba9bdd8bSchristos 
117ba9bdd8bSchristos static const char *
enroll_strerr(uint8_t n)118ba9bdd8bSchristos enroll_strerr(uint8_t n)
119ba9bdd8bSchristos {
120ba9bdd8bSchristos 	switch (n) {
121ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_GOOD:
122ba9bdd8bSchristos 		return "Sample ok";
123ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_HIGH:
124ba9bdd8bSchristos 		return "Sample too high";
125ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_LOW:
126ba9bdd8bSchristos 		return "Sample too low";
127ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_LEFT:
128ba9bdd8bSchristos 		return "Sample too left";
129ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_RIGHT:
130ba9bdd8bSchristos 		return "Sample too right";
131ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_FAST:
132ba9bdd8bSchristos 		return "Sample too fast";
133ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_SLOW:
134ba9bdd8bSchristos 		return "Sample too slow";
135ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_POOR_QUALITY:
136ba9bdd8bSchristos 		return "Poor quality sample";
137ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_SKEWED:
138ba9bdd8bSchristos 		return "Sample too skewed";
139ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_TOO_SHORT:
140ba9bdd8bSchristos 		return "Sample too short";
141ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_MERGE_FAILURE:
142ba9bdd8bSchristos 		return "Sample merge failure";
143ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_EXISTS:
144ba9bdd8bSchristos 		return "Sample exists";
145ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_FP_DATABASE_FULL:
146ba9bdd8bSchristos 		return "Fingerprint database full";
147ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_NO_USER_ACTIVITY:
148ba9bdd8bSchristos 		return "No user activity";
149ba9bdd8bSchristos 	case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION:
150ba9bdd8bSchristos 		return "No user presence transition";
151ba9bdd8bSchristos 	default:
152ba9bdd8bSchristos 		return "Unknown error";
153ba9bdd8bSchristos 	}
154ba9bdd8bSchristos }
155ba9bdd8bSchristos 
156ba9bdd8bSchristos int
bio_enroll(const char * path)15795dbdf32Schristos bio_enroll(const char *path)
158ba9bdd8bSchristos {
159ba9bdd8bSchristos 	fido_bio_template_t *t = NULL;
16095dbdf32Schristos 	fido_bio_enroll_t *e = NULL;
161ba9bdd8bSchristos 	fido_dev_t *dev = NULL;
16295dbdf32Schristos 	char *pin = NULL;
16395dbdf32Schristos 	int r, ok = 1;
164ba9bdd8bSchristos 
165ba9bdd8bSchristos 	if ((t = fido_bio_template_new()) == NULL)
166ba9bdd8bSchristos 		errx(1, "fido_bio_template_new");
167ba9bdd8bSchristos 	if ((e = fido_bio_enroll_new()) == NULL)
168ba9bdd8bSchristos 		errx(1, "fido_bio_enroll_new");
169ba9bdd8bSchristos 
170ba9bdd8bSchristos 	dev = open_dev(path);
17195dbdf32Schristos 	if ((pin = get_pin(path)) == NULL)
17295dbdf32Schristos 		goto out;
173ba9bdd8bSchristos 	printf("Touch your security key.\n");
174ba9bdd8bSchristos 	r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin);
17595dbdf32Schristos 	freezero(pin, PINBUF_LEN);
17695dbdf32Schristos 	pin = NULL;
17795dbdf32Schristos 	if (r != FIDO_OK) {
17895dbdf32Schristos 		warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r));
17995dbdf32Schristos 		goto out;
18095dbdf32Schristos 	}
181ba9bdd8bSchristos 	printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
182ba9bdd8bSchristos 
183ba9bdd8bSchristos 	while (fido_bio_enroll_remaining_samples(e) > 0) {
184ba9bdd8bSchristos 		printf("Touch your security key (%u sample%s left).\n",
185ba9bdd8bSchristos 		    (unsigned)fido_bio_enroll_remaining_samples(e),
186ba9bdd8bSchristos 		    plural(fido_bio_enroll_remaining_samples(e)));
187ba9bdd8bSchristos 		if ((r = fido_bio_dev_enroll_continue(dev, t, e,
188ba9bdd8bSchristos 		    10000)) != FIDO_OK) {
18995dbdf32Schristos 			fido_dev_cancel(dev);
19095dbdf32Schristos 			warnx("fido_bio_dev_enroll_continue: %s",
191ba9bdd8bSchristos 			    fido_strerr(r));
19295dbdf32Schristos 			goto out;
193ba9bdd8bSchristos 		}
194ba9bdd8bSchristos 		printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
195ba9bdd8bSchristos 	}
196ba9bdd8bSchristos 
19795dbdf32Schristos 	ok = 0;
19895dbdf32Schristos out:
199ba9bdd8bSchristos 	fido_bio_template_free(&t);
200ba9bdd8bSchristos 	fido_bio_enroll_free(&e);
201ba9bdd8bSchristos 	fido_dev_close(dev);
202ba9bdd8bSchristos 	fido_dev_free(&dev);
203ba9bdd8bSchristos 
20495dbdf32Schristos 	exit(ok);
205ba9bdd8bSchristos }
206ba9bdd8bSchristos 
207ba9bdd8bSchristos int
bio_delete(const char * path,const char * id)20895dbdf32Schristos bio_delete(const char *path, const char *id)
209ba9bdd8bSchristos {
210ba9bdd8bSchristos 	fido_bio_template_t *t = NULL;
21195dbdf32Schristos 	fido_dev_t *dev = NULL;
21295dbdf32Schristos 	char *pin = NULL;
213ba9bdd8bSchristos 	void *id_blob_ptr = NULL;
21495dbdf32Schristos 	size_t id_blob_len = 0;
21595dbdf32Schristos 	int r, ok = 1;
216ba9bdd8bSchristos 
217ba9bdd8bSchristos 	if ((t = fido_bio_template_new()) == NULL)
218ba9bdd8bSchristos 		errx(1, "fido_bio_template_new");
219ba9bdd8bSchristos 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
220ba9bdd8bSchristos 		errx(1, "base64_decode");
221ba9bdd8bSchristos 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
222ba9bdd8bSchristos 	    id_blob_len)) != FIDO_OK)
223ba9bdd8bSchristos 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
224ba9bdd8bSchristos 
22595dbdf32Schristos 	dev = open_dev(path);
22695dbdf32Schristos 	if ((pin = get_pin(path)) == NULL)
22795dbdf32Schristos 		goto out;
228ba9bdd8bSchristos 	r = fido_bio_dev_enroll_remove(dev, t, pin);
22995dbdf32Schristos 	freezero(pin, PINBUF_LEN);
23095dbdf32Schristos 	pin = NULL;
23195dbdf32Schristos 	if (r != FIDO_OK) {
23295dbdf32Schristos 		warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r));
23395dbdf32Schristos 		goto out;
23495dbdf32Schristos 	}
235ba9bdd8bSchristos 
23695dbdf32Schristos 	ok = 0;
23795dbdf32Schristos out:
238ba9bdd8bSchristos 	free(id_blob_ptr);
239ba9bdd8bSchristos 	fido_bio_template_free(&t);
240ba9bdd8bSchristos 	fido_dev_close(dev);
241ba9bdd8bSchristos 	fido_dev_free(&dev);
242ba9bdd8bSchristos 
24395dbdf32Schristos 	exit(ok);
244ba9bdd8bSchristos }
245ba9bdd8bSchristos 
246ba9bdd8bSchristos static const char *
type_str(uint8_t t)247ba9bdd8bSchristos type_str(uint8_t t)
248ba9bdd8bSchristos {
249ba9bdd8bSchristos 	switch (t) {
250ba9bdd8bSchristos 	case 1:
251ba9bdd8bSchristos 		return "touch";
252ba9bdd8bSchristos 	case 2:
253ba9bdd8bSchristos 		return "swipe";
254ba9bdd8bSchristos 	default:
255ba9bdd8bSchristos 		return "unknown";
256ba9bdd8bSchristos 	}
257ba9bdd8bSchristos }
258ba9bdd8bSchristos 
259ba9bdd8bSchristos void
bio_info(fido_dev_t * dev)260ba9bdd8bSchristos bio_info(fido_dev_t *dev)
261ba9bdd8bSchristos {
262ba9bdd8bSchristos 	fido_bio_info_t	*i = NULL;
263ba9bdd8bSchristos 
26495dbdf32Schristos 	if ((i = fido_bio_info_new()) == NULL) {
26595dbdf32Schristos 		warnx("fido_bio_info_new");
26695dbdf32Schristos 		return;
26795dbdf32Schristos 	}
268ba9bdd8bSchristos 	if (fido_bio_dev_get_info(dev, i) != FIDO_OK) {
269ba9bdd8bSchristos 		fido_bio_info_free(&i);
270ba9bdd8bSchristos 		return;
271ba9bdd8bSchristos 	}
272ba9bdd8bSchristos 
273ba9bdd8bSchristos 	printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i),
274ba9bdd8bSchristos 	    type_str(fido_bio_info_type(i)));
275ba9bdd8bSchristos 	printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i));
276ba9bdd8bSchristos 
277ba9bdd8bSchristos 	fido_bio_info_free(&i);
278ba9bdd8bSchristos }
279