/* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static int print_template(const fido_bio_template_array_t *ta, size_t idx) { const fido_bio_template_t *t = NULL; char *id = NULL; if ((t = fido_bio_template(ta, idx)) == NULL) { warnx("fido_bio_template"); return -1; } if (base64_encode(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t), &id) < 0) { warnx("output error"); return -1; } printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); free(id); return 0; } int bio_list(const char *path) { fido_bio_template_array_t *ta = NULL; fido_dev_t *dev = NULL; char *pin = NULL; int r, ok = 1; if ((ta = fido_bio_template_array_new()) == NULL) errx(1, "fido_bio_template_array_new"); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_get_template_array(dev, ta, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r)); goto out; } for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) if (print_template(ta, i) < 0) goto out; ok = 0; out: fido_bio_template_array_free(&ta); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int bio_set_name(const char *path, const char *id, const char *name) { fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; char *pin = NULL; void *id_blob_ptr = NULL; size_t id_blob_len = 0; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_set_template_name(dev, t, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r)); goto out; } ok = 0; out: free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static const char * enroll_strerr(uint8_t n) { switch (n) { case FIDO_BIO_ENROLL_FP_GOOD: return "Sample ok"; case FIDO_BIO_ENROLL_FP_TOO_HIGH: return "Sample too high"; case FIDO_BIO_ENROLL_FP_TOO_LOW: return "Sample too low"; case FIDO_BIO_ENROLL_FP_TOO_LEFT: return "Sample too left"; case FIDO_BIO_ENROLL_FP_TOO_RIGHT: return "Sample too right"; case FIDO_BIO_ENROLL_FP_TOO_FAST: return "Sample too fast"; case FIDO_BIO_ENROLL_FP_TOO_SLOW: return "Sample too slow"; case FIDO_BIO_ENROLL_FP_POOR_QUALITY: return "Poor quality sample"; case FIDO_BIO_ENROLL_FP_TOO_SKEWED: return "Sample too skewed"; case FIDO_BIO_ENROLL_FP_TOO_SHORT: return "Sample too short"; case FIDO_BIO_ENROLL_FP_MERGE_FAILURE: return "Sample merge failure"; case FIDO_BIO_ENROLL_FP_EXISTS: return "Sample exists"; case FIDO_BIO_ENROLL_FP_DATABASE_FULL: return "Fingerprint database full"; case FIDO_BIO_ENROLL_NO_USER_ACTIVITY: return "No user activity"; case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION: return "No user presence transition"; default: return "Unknown error"; } } int bio_enroll(const char *path) { fido_bio_template_t *t = NULL; fido_bio_enroll_t *e = NULL; fido_dev_t *dev = NULL; char *pin = NULL; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if ((e = fido_bio_enroll_new()) == NULL) errx(1, "fido_bio_enroll_new"); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; printf("Touch your security key.\n"); r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r)); goto out; } printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); while (fido_bio_enroll_remaining_samples(e) > 0) { printf("Touch your security key (%u sample%s left).\n", (unsigned)fido_bio_enroll_remaining_samples(e), plural(fido_bio_enroll_remaining_samples(e))); if ((r = fido_bio_dev_enroll_continue(dev, t, e, 10000)) != FIDO_OK) { fido_dev_cancel(dev); warnx("fido_bio_dev_enroll_continue: %s", fido_strerr(r)); goto out; } printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); } ok = 0; out: fido_bio_template_free(&t); fido_bio_enroll_free(&e); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int bio_delete(const char *path, const char *id) { fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; char *pin = NULL; void *id_blob_ptr = NULL; size_t id_blob_len = 0; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_enroll_remove(dev, t, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r)); goto out; } ok = 0; out: free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static const char * type_str(uint8_t t) { switch (t) { case 1: return "touch"; case 2: return "swipe"; default: return "unknown"; } } void bio_info(fido_dev_t *dev) { fido_bio_info_t *i = NULL; if ((i = fido_bio_info_new()) == NULL) { warnx("fido_bio_info_new"); return; } if (fido_bio_dev_get_info(dev, i) != FIDO_OK) { fido_bio_info_free(&i); return; } printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), type_str(fido_bio_info_type(i))); printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); fido_bio_info_free(&i); }