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
print_template(const fido_bio_template_array_t * ta,size_t idx)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
bio_list(const char * path)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
bio_set_name(const char * path,const char * id,const char * name)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 *
enroll_strerr(uint8_t n)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
bio_enroll(const char * path)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
bio_delete(const char * path,const char * id)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 *
type_str(uint8_t t)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
bio_info(fido_dev_t * dev)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