xref: /freebsd/contrib/libfido2/tools/bio.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*
2  * Copyright (c) 2019 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 <fido.h>
9 #include <fido/bio.h>
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 
18 #include "../openbsd-compat/openbsd-compat.h"
19 #include "extern.h"
20 
21 static int
22 print_template(const fido_bio_template_array_t *ta, size_t idx)
23 {
24 	const fido_bio_template_t *t = NULL;
25 	char *id = NULL;
26 
27 	if ((t = fido_bio_template(ta, idx)) == NULL) {
28 		warnx("fido_bio_template");
29 		return -1;
30 	}
31 	if (base64_encode(fido_bio_template_id_ptr(t),
32 	    fido_bio_template_id_len(t), &id) < 0) {
33 		warnx("output error");
34 		return -1;
35 	}
36 
37 	printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t));
38 	free(id);
39 
40 	return 0;
41 }
42 
43 int
44 bio_list(const char *path)
45 {
46 	fido_bio_template_array_t *ta = NULL;
47 	fido_dev_t *dev = NULL;
48 	char *pin = NULL;
49 	int r, ok = 1;
50 
51 	if ((ta = fido_bio_template_array_new()) == NULL)
52 		errx(1, "fido_bio_template_array_new");
53 	dev = open_dev(path);
54 	if ((pin = get_pin(path)) == NULL)
55 		goto out;
56 	r = fido_bio_dev_get_template_array(dev, ta, pin);
57 	freezero(pin, PINBUF_LEN);
58 	pin = NULL;
59 	if (r != FIDO_OK) {
60 		warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r));
61 		goto out;
62 	}
63 	for (size_t i = 0; i < fido_bio_template_array_count(ta); i++)
64 		if (print_template(ta, i) < 0)
65 			goto out;
66 
67 	ok = 0;
68 out:
69 	fido_bio_template_array_free(&ta);
70 	fido_dev_close(dev);
71 	fido_dev_free(&dev);
72 
73 	exit(ok);
74 }
75 
76 int
77 bio_set_name(const char *path, const char *id, const char *name)
78 {
79 	fido_bio_template_t *t = NULL;
80 	fido_dev_t *dev = NULL;
81 	char *pin = NULL;
82 	void *id_blob_ptr = NULL;
83 	size_t id_blob_len = 0;
84 	int r, ok = 1;
85 
86 	if ((t = fido_bio_template_new()) == NULL)
87 		errx(1, "fido_bio_template_new");
88 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
89 		errx(1, "base64_decode");
90 	if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK)
91 		errx(1, "fido_bio_template_set_name: %s", fido_strerr(r));
92 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
93 	    id_blob_len)) != FIDO_OK)
94 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
95 
96 	dev = open_dev(path);
97 	if ((pin = get_pin(path)) == NULL)
98 		goto out;
99 	r = fido_bio_dev_set_template_name(dev, t, pin);
100 	freezero(pin, PINBUF_LEN);
101 	pin = NULL;
102 	if (r != FIDO_OK) {
103 		warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r));
104 		goto out;
105 	}
106 
107 	ok = 0;
108 out:
109 	free(id_blob_ptr);
110 	fido_bio_template_free(&t);
111 	fido_dev_close(dev);
112 	fido_dev_free(&dev);
113 
114 	exit(ok);
115 }
116 
117 static const char *
118 enroll_strerr(uint8_t n)
119 {
120 	switch (n) {
121 	case FIDO_BIO_ENROLL_FP_GOOD:
122 		return "Sample ok";
123 	case FIDO_BIO_ENROLL_FP_TOO_HIGH:
124 		return "Sample too high";
125 	case FIDO_BIO_ENROLL_FP_TOO_LOW:
126 		return "Sample too low";
127 	case FIDO_BIO_ENROLL_FP_TOO_LEFT:
128 		return "Sample too left";
129 	case FIDO_BIO_ENROLL_FP_TOO_RIGHT:
130 		return "Sample too right";
131 	case FIDO_BIO_ENROLL_FP_TOO_FAST:
132 		return "Sample too fast";
133 	case FIDO_BIO_ENROLL_FP_TOO_SLOW:
134 		return "Sample too slow";
135 	case FIDO_BIO_ENROLL_FP_POOR_QUALITY:
136 		return "Poor quality sample";
137 	case FIDO_BIO_ENROLL_FP_TOO_SKEWED:
138 		return "Sample too skewed";
139 	case FIDO_BIO_ENROLL_FP_TOO_SHORT:
140 		return "Sample too short";
141 	case FIDO_BIO_ENROLL_FP_MERGE_FAILURE:
142 		return "Sample merge failure";
143 	case FIDO_BIO_ENROLL_FP_EXISTS:
144 		return "Sample exists";
145 	case FIDO_BIO_ENROLL_FP_DATABASE_FULL:
146 		return "Fingerprint database full";
147 	case FIDO_BIO_ENROLL_NO_USER_ACTIVITY:
148 		return "No user activity";
149 	case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION:
150 		return "No user presence transition";
151 	default:
152 		return "Unknown error";
153 	}
154 }
155 
156 int
157 bio_enroll(const char *path)
158 {
159 	fido_bio_template_t *t = NULL;
160 	fido_bio_enroll_t *e = NULL;
161 	fido_dev_t *dev = NULL;
162 	char *pin = NULL;
163 	int r, ok = 1;
164 
165 	if ((t = fido_bio_template_new()) == NULL)
166 		errx(1, "fido_bio_template_new");
167 	if ((e = fido_bio_enroll_new()) == NULL)
168 		errx(1, "fido_bio_enroll_new");
169 
170 	dev = open_dev(path);
171 	if ((pin = get_pin(path)) == NULL)
172 		goto out;
173 	printf("Touch your security key.\n");
174 	r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin);
175 	freezero(pin, PINBUF_LEN);
176 	pin = NULL;
177 	if (r != FIDO_OK) {
178 		warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r));
179 		goto out;
180 	}
181 	printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
182 
183 	while (fido_bio_enroll_remaining_samples(e) > 0) {
184 		printf("Touch your security key (%u sample%s left).\n",
185 		    (unsigned)fido_bio_enroll_remaining_samples(e),
186 		    plural(fido_bio_enroll_remaining_samples(e)));
187 		if ((r = fido_bio_dev_enroll_continue(dev, t, e,
188 		    10000)) != FIDO_OK) {
189 			fido_dev_cancel(dev);
190 			warnx("fido_bio_dev_enroll_continue: %s",
191 			    fido_strerr(r));
192 			goto out;
193 		}
194 		printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
195 	}
196 
197 	ok = 0;
198 out:
199 	fido_bio_template_free(&t);
200 	fido_bio_enroll_free(&e);
201 	fido_dev_close(dev);
202 	fido_dev_free(&dev);
203 
204 	exit(ok);
205 }
206 
207 int
208 bio_delete(const char *path, const char *id)
209 {
210 	fido_bio_template_t *t = NULL;
211 	fido_dev_t *dev = NULL;
212 	char *pin = NULL;
213 	void *id_blob_ptr = NULL;
214 	size_t id_blob_len = 0;
215 	int r, ok = 1;
216 
217 	if ((t = fido_bio_template_new()) == NULL)
218 		errx(1, "fido_bio_template_new");
219 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
220 		errx(1, "base64_decode");
221 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
222 	    id_blob_len)) != FIDO_OK)
223 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
224 
225 	dev = open_dev(path);
226 	if ((pin = get_pin(path)) == NULL)
227 		goto out;
228 	r = fido_bio_dev_enroll_remove(dev, t, pin);
229 	freezero(pin, PINBUF_LEN);
230 	pin = NULL;
231 	if (r != FIDO_OK) {
232 		warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r));
233 		goto out;
234 	}
235 
236 	ok = 0;
237 out:
238 	free(id_blob_ptr);
239 	fido_bio_template_free(&t);
240 	fido_dev_close(dev);
241 	fido_dev_free(&dev);
242 
243 	exit(ok);
244 }
245 
246 static const char *
247 type_str(uint8_t t)
248 {
249 	switch (t) {
250 	case 1:
251 		return "touch";
252 	case 2:
253 		return "swipe";
254 	default:
255 		return "unknown";
256 	}
257 }
258 
259 void
260 bio_info(fido_dev_t *dev)
261 {
262 	fido_bio_info_t	*i = NULL;
263 
264 	if ((i = fido_bio_info_new()) == NULL) {
265 		warnx("fido_bio_info_new");
266 		return;
267 	}
268 	if (fido_bio_dev_get_info(dev, i) != FIDO_OK) {
269 		fido_bio_info_free(&i);
270 		return;
271 	}
272 
273 	printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i),
274 	    type_str(fido_bio_info_type(i)));
275 	printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i));
276 
277 	fido_bio_info_free(&i);
278 }
279