xref: /netbsd-src/external/bsd/libfido2/dist/tools/token.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*
2  * Copyright (c) 2018 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 <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 
16 #include "../openbsd-compat/openbsd-compat.h"
17 #include "extern.h"
18 
19 static void
20 format_flags(char *ret, size_t retlen, uint8_t flags)
21 {
22 	memset(ret, 0, retlen);
23 
24 	if (flags & FIDO_CAP_WINK) {
25 		if (strlcat(ret, "wink,", retlen) >= retlen)
26 			goto toolong;
27 	} else {
28 		if (strlcat(ret, "nowink,", retlen) >= retlen)
29 			goto toolong;
30 	}
31 
32 	if (flags & FIDO_CAP_CBOR) {
33 		if (strlcat(ret, " cbor,", retlen) >= retlen)
34 			goto toolong;
35 	} else {
36 		if (strlcat(ret, " nocbor,", retlen) >= retlen)
37 			goto toolong;
38 	}
39 
40 	if (flags & FIDO_CAP_NMSG) {
41 		if (strlcat(ret, " nomsg", retlen) >= retlen)
42 			goto toolong;
43 	} else {
44 		if (strlcat(ret, " msg", retlen) >= retlen)
45 			goto toolong;
46 	}
47 
48 	return;
49 toolong:
50 	strlcpy(ret, "toolong", retlen);
51 }
52 
53 static void
54 print_attr(const fido_dev_t *dev)
55 {
56 	char flags_txt[128];
57 
58 	printf("proto: 0x%02x\n", fido_dev_protocol(dev));
59 	printf("major: 0x%02x\n", fido_dev_major(dev));
60 	printf("minor: 0x%02x\n", fido_dev_minor(dev));
61 	printf("build: 0x%02x\n", fido_dev_build(dev));
62 
63 	format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
64 	printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
65 }
66 
67 static void
68 print_str_array(const char *label, char * const *sa, size_t len)
69 {
70 	if (len == 0)
71 		return;
72 
73 	printf("%s strings: ", label);
74 
75 	for (size_t i = 0; i < len; i++)
76 		printf("%s%s", i > 0 ? ", " : "", sa[i]);
77 
78 	printf("\n");
79 }
80 
81 static void
82 print_opt_array(const char *label, char * const *name, const bool *value,
83     size_t len)
84 {
85 	if (len == 0)
86 		return;
87 
88 	printf("%s: ", label);
89 
90 	for (size_t i = 0; i < len; i++)
91 		printf("%s%s%s", i > 0 ? ", " : "",
92 		    value[i] ? "" : "no", name[i]);
93 
94 	printf("\n");
95 }
96 
97 static void
98 print_aaguid(const unsigned char *buf, size_t buflen)
99 {
100 	printf("aaguid: ");
101 
102 	while (buflen--)
103 		printf("%02x", *buf++);
104 
105 	printf("\n");
106 }
107 
108 static void
109 print_maxmsgsiz(uint64_t maxmsgsiz)
110 {
111 	printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
112 }
113 
114 static void
115 print_maxcredcntlst(uint64_t maxcredcntlst)
116 {
117 	printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
118 }
119 
120 static void
121 print_maxcredidlen(uint64_t maxcredidlen)
122 {
123 	printf("maxcredlen: %d\n", (int)maxcredidlen);
124 }
125 
126 static void
127 print_fwversion(uint64_t fwversion)
128 {
129 	printf("fwversion: 0x%x\n", (int)fwversion);
130 }
131 
132 static void
133 print_byte_array(const char *label, const uint8_t *ba, size_t len)
134 {
135 	if (len == 0)
136 		return;
137 
138 	printf("%s: ", label);
139 
140 	for (size_t i = 0; i < len; i++)
141 		printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
142 
143 	printf("\n");
144 }
145 
146 int
147 token_info(int argc, char **argv, char *path)
148 {
149 	char			*cred_id = NULL;
150 	char			*rp_id = NULL;
151 	fido_cbor_info_t	*ci = NULL;
152 	fido_dev_t		*dev = NULL;
153 	int			 ch;
154 	int			 credman = 0;
155 	int			 r;
156 	int			 retrycnt;
157 
158 	optind = 1;
159 
160 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
161 		switch (ch) {
162 		case 'c':
163 			credman = 1;
164 			break;
165 		case 'i':
166 			cred_id = optarg;
167 			break;
168 		case 'k':
169 			rp_id = optarg;
170 			break;
171 		default:
172 			break; /* ignore */
173 		}
174 	}
175 
176 	if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL)))
177 		usage();
178 
179 	dev = open_dev(path);
180 
181 	if (credman)
182 		return (credman_get_metadata(dev, path));
183 	if (cred_id && rp_id)
184 		return (credman_print_rk(dev, path, rp_id, cred_id));
185 	if (cred_id || rp_id)
186 		usage();
187 
188 	print_attr(dev);
189 
190 	if (fido_dev_is_fido2(dev) == false)
191 		goto end;
192 	if ((ci = fido_cbor_info_new()) == NULL)
193 		errx(1, "fido_cbor_info_new");
194 	if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
195 		errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
196 
197 	/* print supported protocol versions */
198 	print_str_array("version", fido_cbor_info_versions_ptr(ci),
199 	    fido_cbor_info_versions_len(ci));
200 
201 	/* print supported extensions */
202 	print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
203 	    fido_cbor_info_extensions_len(ci));
204 
205 	/* print aaguid */
206 	print_aaguid(fido_cbor_info_aaguid_ptr(ci),
207 	    fido_cbor_info_aaguid_len(ci));
208 
209 	/* print supported options */
210 	print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
211 	    fido_cbor_info_options_value_ptr(ci),
212 	    fido_cbor_info_options_len(ci));
213 
214 	/* print maximum message size */
215 	print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
216 
217 	/* print maximum number of credentials allowed in credential lists */
218 	print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
219 
220 	/* print maximum length of a credential ID */
221 	print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
222 
223 	/* print firmware version */
224 	print_fwversion(fido_cbor_info_fwversion(ci));
225 
226 	/* print supported pin protocols */
227 	print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
228 	    fido_cbor_info_protocols_len(ci));
229 
230 	if (fido_dev_get_retry_count(dev, &retrycnt) != FIDO_OK)
231 		printf("pin retries: undefined\n");
232 	else
233 		printf("pin retries: %d\n", retrycnt);
234 
235 	bio_info(dev);
236 
237 	fido_cbor_info_free(&ci);
238 end:
239 	fido_dev_close(dev);
240 	fido_dev_free(&dev);
241 
242 	exit(0);
243 }
244 
245 int
246 token_reset(char *path)
247 {
248 	fido_dev_t *dev = NULL;
249 	int r;
250 
251 	if (path == NULL)
252 		usage();
253 
254 	dev = open_dev(path);
255 	if ((r = fido_dev_reset(dev)) != FIDO_OK)
256 		errx(1, "fido_dev_reset: %s", fido_strerr(r));
257 
258 	fido_dev_close(dev);
259 	fido_dev_free(&dev);
260 
261 	exit(0);
262 }
263 
264 int
265 token_set(int argc, char **argv, char *path)
266 {
267 	char	*id = NULL;
268 	char	*name = NULL;
269 	int	 ch;
270 	int	 enroll = 0;
271 
272 	optind = 1;
273 
274 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
275 		switch (ch) {
276 		case 'e':
277 			enroll = 1;
278 			break;
279 		case 'i':
280 			id = optarg;
281 			break;
282 		case 'n':
283 			name = optarg;
284 			break;
285 		default:
286 			break; /* ignore */
287 		}
288 	}
289 
290 	if (enroll) {
291 		if (id && name)
292 			return (bio_set_name(path, id, name));
293 		if (!id && !name)
294 			return (bio_enroll(path));
295 		usage();
296 	}
297 
298 	return (pin_set(path));
299 }
300 
301 int
302 token_list(int argc, char **argv, char *path)
303 {
304 	fido_dev_info_t *devlist;
305 	size_t ndevs;
306 	const char *rp_id = NULL;
307 	int enrolls = 0;
308 	int keys = 0;
309 	int rplist = 0;
310 	int ch;
311 	int r;
312 
313 	optind = 1;
314 
315 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
316 		switch (ch) {
317 		case 'e':
318 			enrolls = 1;
319 			break;
320 		case 'k':
321 			keys = 1;
322 			rp_id = optarg;
323 			break;
324 		case 'r':
325 			rplist = 1;
326 			break;
327 		default:
328 			break; /* ignore */
329 		}
330 	}
331 
332 	if (enrolls)
333 		return (bio_list(path));
334 	if (keys)
335 		return (credman_list_rk(path, rp_id));
336 	if (rplist)
337 		return (credman_list_rp(path));
338 
339 	if ((devlist = fido_dev_info_new(64)) == NULL)
340 		errx(1, "fido_dev_info_new");
341 	if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
342 		errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
343 
344 	for (size_t i = 0; i < ndevs; i++) {
345 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
346 		printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n",
347 		    fido_dev_info_path(di),
348 		    (uint16_t)fido_dev_info_vendor(di),
349 		    (uint16_t)fido_dev_info_product(di),
350 		    fido_dev_info_manufacturer_string(di),
351 		    fido_dev_info_product_string(di));
352 	}
353 
354 	fido_dev_info_free(&devlist, ndevs);
355 
356 	exit(0);
357 }
358 
359 int
360 token_delete(int argc, char **argv, char *path)
361 {
362 	char		*id = NULL;
363 	fido_dev_t	*dev = NULL;
364 	int		 ch;
365 	int		 enroll = 0;
366 
367 	optind = 1;
368 
369 	while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
370 		switch (ch) {
371 		case 'e':
372 			enroll = 1;
373 			break;
374 		case 'i':
375 			id = optarg;
376 			break;
377 		default:
378 			break; /* ignore */
379 		}
380 	}
381 
382 	if (path == NULL || id == NULL)
383 		usage();
384 
385 	dev = open_dev(path);
386 
387 	if (id && !enroll)
388 		return (credman_delete_rk(dev, path, id));
389 
390 	return (bio_delete(dev, path, id));
391 }
392