xref: /netbsd-src/external/bsd/libfido2/dist/tools/bio.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
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 <stdbool.h>
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 void
22 print_template(const fido_bio_template_array_t *ta, size_t idx)
23 {
24 	char				*id = NULL;
25 	const fido_bio_template_t	*t = NULL;
26 
27 	if ((t = fido_bio_template(ta, idx)) == NULL)
28 		errx(1, "fido_bio_template");
29 
30 	if (base64_encode(fido_bio_template_id_ptr(t),
31 	    fido_bio_template_id_len(t), &id) < 0)
32 		errx(1, "output error");
33 
34 	printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t));
35 
36 	free(id);
37 }
38 
39 int
40 bio_list(char *path)
41 {
42 	char				 pin[1024];
43 	fido_bio_template_array_t	*ta = NULL;
44 	fido_dev_t			*dev = NULL;
45 	int				 r;
46 
47 	if (path == NULL)
48 		usage();
49 	if ((ta = fido_bio_template_array_new()) == NULL)
50 		errx(1, "fido_bio_template_array_new");
51 
52 	dev = open_dev(path);
53 	read_pin(path, pin, sizeof(pin));
54 	r = fido_bio_dev_get_template_array(dev, ta, pin);
55 	explicit_bzero(pin, sizeof(pin));
56 
57 	if (r != FIDO_OK)
58 		errx(1, "fido_bio_dev_get_template_array: %s", fido_strerr(r));
59 	for (size_t i = 0; i < fido_bio_template_array_count(ta); i++)
60 		print_template(ta, i);
61 
62 	fido_bio_template_array_free(&ta);
63 	fido_dev_close(dev);
64 	fido_dev_free(&dev);
65 
66 	exit(0);
67 }
68 
69 int
70 bio_set_name(char *path, char *id, char *name)
71 {
72 	char			 pin[1024];
73 	fido_bio_template_t	*t = NULL;
74 	fido_dev_t		*dev = NULL;
75 	int			 r;
76 	size_t			 id_blob_len = 0;
77 	void			*id_blob_ptr = NULL;
78 
79 	if (path == NULL)
80 		usage();
81 	if ((t = fido_bio_template_new()) == NULL)
82 		errx(1, "fido_bio_template_new");
83 
84 	if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
85 		errx(1, "base64_decode");
86 
87 	if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK)
88 		errx(1, "fido_bio_template_set_name: %s", fido_strerr(r));
89 	if ((r = fido_bio_template_set_id(t, id_blob_ptr,
90 	    id_blob_len)) != FIDO_OK)
91 		errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
92 
93 	dev = open_dev(path);
94 	read_pin(path, pin, sizeof(pin));
95 	r = fido_bio_dev_set_template_name(dev, t, pin);
96 	explicit_bzero(pin, sizeof(pin));
97 
98 	if (r != FIDO_OK)
99 		errx(1, "fido_bio_dev_set_template_name: %s", fido_strerr(r));
100 
101 	free(id_blob_ptr);
102 	fido_bio_template_free(&t);
103 	fido_dev_close(dev);
104 	fido_dev_free(&dev);
105 
106 	exit(0);
107 }
108 
109 static const char *
110 plural(uint8_t n)
111 {
112 	if (n == 1)
113 		return "";
114 	return "s";
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(char *path)
158 {
159 	char			 pin[1024];
160 	fido_bio_enroll_t	*e = NULL;
161 	fido_bio_template_t	*t = NULL;
162 	fido_dev_t		*dev = NULL;
163 	int			 r;
164 
165 	if (path == NULL)
166 		usage();
167 	if ((t = fido_bio_template_new()) == NULL)
168 		errx(1, "fido_bio_template_new");
169 	if ((e = fido_bio_enroll_new()) == NULL)
170 		errx(1, "fido_bio_enroll_new");
171 
172 	dev = open_dev(path);
173 	read_pin(path, pin, sizeof(pin));
174 
175 	printf("Touch your security key.\n");
176 
177 	r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin);
178 	explicit_bzero(pin, sizeof(pin));
179 	if (r != FIDO_OK)
180 		errx(1, "fido_bio_dev_enroll_begin: %s", fido_strerr(r));
181 
182 	printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
183 
184 	while (fido_bio_enroll_remaining_samples(e) > 0) {
185 		printf("Touch your security key (%u sample%s left).\n",
186 		    (unsigned)fido_bio_enroll_remaining_samples(e),
187 		    plural(fido_bio_enroll_remaining_samples(e)));
188 		if ((r = fido_bio_dev_enroll_continue(dev, t, e,
189 		    10000)) != FIDO_OK) {
190 			errx(1, "fido_bio_dev_enroll_continue: %s",
191 			    fido_strerr(r));
192 		}
193 		printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
194 	}
195 
196 	fido_bio_template_free(&t);
197 	fido_bio_enroll_free(&e);
198 	fido_dev_close(dev);
199 	fido_dev_free(&dev);
200 
201 	exit(0);
202 }
203 
204 int
205 bio_delete(fido_dev_t *dev, char *path, char *id)
206 {
207 	char			 pin[1024];
208 	fido_bio_template_t	*t = NULL;
209 	int			 r;
210 	size_t			 id_blob_len = 0;
211 	void			*id_blob_ptr = NULL;
212 
213 	if (path == NULL)
214 		usage();
215 	if ((t = fido_bio_template_new()) == NULL)
216 		errx(1, "fido_bio_template_new");
217 
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 	read_pin(path, pin, sizeof(pin));
225 	r = fido_bio_dev_enroll_remove(dev, t, pin);
226 	explicit_bzero(pin, sizeof(pin));
227 
228 	if (r != FIDO_OK)
229 		errx(1, "fido_bio_dev_enroll_remove: %s", fido_strerr(r));
230 
231 	free(id_blob_ptr);
232 	fido_bio_template_free(&t);
233 	fido_dev_close(dev);
234 	fido_dev_free(&dev);
235 
236 	exit(0);
237 }
238 
239 static const char *
240 type_str(uint8_t t)
241 {
242 	switch (t) {
243 	case 1:
244 		return "touch";
245 	case 2:
246 		return "swipe";
247 	default:
248 		return "unknown";
249 	}
250 }
251 
252 void
253 bio_info(fido_dev_t *dev)
254 {
255 	fido_bio_info_t	*i = NULL;
256 
257 	if ((i = fido_bio_info_new()) == NULL)
258 		errx(1, "fido_bio_info_new");
259 	if (fido_bio_dev_get_info(dev, i) != FIDO_OK) {
260 		fido_bio_info_free(&i);
261 		return;
262 	}
263 
264 	printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i),
265 	    type_str(fido_bio_info_type(i)));
266 	printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i));
267 
268 	fido_bio_info_free(&i);
269 }
270