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