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