Home | History | Annotate | Line # | Download | only in tools
      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