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 */ 6 7 #include <fido.h> 8 #include <fido/bio.h> 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #ifdef HAVE_UNISTD_H 14 #include <unistd.h> 15 #endif 16 17 #include "../openbsd-compat/openbsd-compat.h" 18 #include "extern.h" 19 20 static int 21 print_template(const fido_bio_template_array_t *ta, size_t idx) 22 { 23 const fido_bio_template_t *t = NULL; 24 char *id = NULL; 25 26 if ((t = fido_bio_template(ta, idx)) == NULL) { 27 warnx("fido_bio_template"); 28 return -1; 29 } 30 if (base64_encode(fido_bio_template_id_ptr(t), 31 fido_bio_template_id_len(t), &id) < 0) { 32 warnx("output error"); 33 return -1; 34 } 35 36 printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); 37 free(id); 38 39 return 0; 40 } 41 42 int 43 bio_list(const char *path) 44 { 45 fido_bio_template_array_t *ta = NULL; 46 fido_dev_t *dev = NULL; 47 char *pin = NULL; 48 int r, ok = 1; 49 50 if ((ta = fido_bio_template_array_new()) == NULL) 51 errx(1, "fido_bio_template_array_new"); 52 dev = open_dev(path); 53 if ((pin = get_pin(path)) == NULL) 54 goto out; 55 r = fido_bio_dev_get_template_array(dev, ta, pin); 56 freezero(pin, PINBUF_LEN); 57 pin = NULL; 58 if (r != FIDO_OK) { 59 warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r)); 60 goto out; 61 } 62 for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) 63 if (print_template(ta, i) < 0) 64 goto out; 65 66 ok = 0; 67 out: 68 fido_bio_template_array_free(&ta); 69 fido_dev_close(dev); 70 fido_dev_free(&dev); 71 72 exit(ok); 73 } 74 75 int 76 bio_set_name(const char *path, const char *id, const char *name) 77 { 78 fido_bio_template_t *t = NULL; 79 fido_dev_t *dev = NULL; 80 char *pin = NULL; 81 void *id_blob_ptr = NULL; 82 size_t id_blob_len = 0; 83 int r, ok = 1; 84 85 if ((t = fido_bio_template_new()) == NULL) 86 errx(1, "fido_bio_template_new"); 87 if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) 88 errx(1, "base64_decode"); 89 if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) 90 errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); 91 if ((r = fido_bio_template_set_id(t, id_blob_ptr, 92 id_blob_len)) != FIDO_OK) 93 errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); 94 95 dev = open_dev(path); 96 if ((pin = get_pin(path)) == NULL) 97 goto out; 98 r = fido_bio_dev_set_template_name(dev, t, pin); 99 freezero(pin, PINBUF_LEN); 100 pin = NULL; 101 if (r != FIDO_OK) { 102 warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r)); 103 goto out; 104 } 105 106 ok = 0; 107 out: 108 free(id_blob_ptr); 109 fido_bio_template_free(&t); 110 fido_dev_close(dev); 111 fido_dev_free(&dev); 112 113 exit(ok); 114 } 115 116 static const char * 117 enroll_strerr(uint8_t n) 118 { 119 switch (n) { 120 case FIDO_BIO_ENROLL_FP_GOOD: 121 return "Sample ok"; 122 case FIDO_BIO_ENROLL_FP_TOO_HIGH: 123 return "Sample too high"; 124 case FIDO_BIO_ENROLL_FP_TOO_LOW: 125 return "Sample too low"; 126 case FIDO_BIO_ENROLL_FP_TOO_LEFT: 127 return "Sample too left"; 128 case FIDO_BIO_ENROLL_FP_TOO_RIGHT: 129 return "Sample too right"; 130 case FIDO_BIO_ENROLL_FP_TOO_FAST: 131 return "Sample too fast"; 132 case FIDO_BIO_ENROLL_FP_TOO_SLOW: 133 return "Sample too slow"; 134 case FIDO_BIO_ENROLL_FP_POOR_QUALITY: 135 return "Poor quality sample"; 136 case FIDO_BIO_ENROLL_FP_TOO_SKEWED: 137 return "Sample too skewed"; 138 case FIDO_BIO_ENROLL_FP_TOO_SHORT: 139 return "Sample too short"; 140 case FIDO_BIO_ENROLL_FP_MERGE_FAILURE: 141 return "Sample merge failure"; 142 case FIDO_BIO_ENROLL_FP_EXISTS: 143 return "Sample exists"; 144 case FIDO_BIO_ENROLL_FP_DATABASE_FULL: 145 return "Fingerprint database full"; 146 case FIDO_BIO_ENROLL_NO_USER_ACTIVITY: 147 return "No user activity"; 148 case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION: 149 return "No user presence transition"; 150 default: 151 return "Unknown error"; 152 } 153 } 154 155 int 156 bio_enroll(const char *path) 157 { 158 fido_bio_template_t *t = NULL; 159 fido_bio_enroll_t *e = NULL; 160 fido_dev_t *dev = NULL; 161 char *pin = NULL; 162 int r, ok = 1; 163 164 if ((t = fido_bio_template_new()) == NULL) 165 errx(1, "fido_bio_template_new"); 166 if ((e = fido_bio_enroll_new()) == NULL) 167 errx(1, "fido_bio_enroll_new"); 168 169 dev = open_dev(path); 170 if ((pin = get_pin(path)) == NULL) 171 goto out; 172 printf("Touch your security key.\n"); 173 r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); 174 freezero(pin, PINBUF_LEN); 175 pin = NULL; 176 if (r != FIDO_OK) { 177 warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r)); 178 goto out; 179 } 180 printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); 181 182 while (fido_bio_enroll_remaining_samples(e) > 0) { 183 printf("Touch your security key (%u sample%s left).\n", 184 (unsigned)fido_bio_enroll_remaining_samples(e), 185 plural(fido_bio_enroll_remaining_samples(e))); 186 if ((r = fido_bio_dev_enroll_continue(dev, t, e, 187 10000)) != FIDO_OK) { 188 fido_dev_cancel(dev); 189 warnx("fido_bio_dev_enroll_continue: %s", 190 fido_strerr(r)); 191 goto out; 192 } 193 printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); 194 } 195 196 ok = 0; 197 out: 198 fido_bio_template_free(&t); 199 fido_bio_enroll_free(&e); 200 fido_dev_close(dev); 201 fido_dev_free(&dev); 202 203 exit(ok); 204 } 205 206 int 207 bio_delete(const char *path, const char *id) 208 { 209 fido_bio_template_t *t = NULL; 210 fido_dev_t *dev = NULL; 211 char *pin = NULL; 212 void *id_blob_ptr = NULL; 213 size_t id_blob_len = 0; 214 int r, ok = 1; 215 216 if ((t = fido_bio_template_new()) == NULL) 217 errx(1, "fido_bio_template_new"); 218 if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) 219 errx(1, "base64_decode"); 220 if ((r = fido_bio_template_set_id(t, id_blob_ptr, 221 id_blob_len)) != FIDO_OK) 222 errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); 223 224 dev = open_dev(path); 225 if ((pin = get_pin(path)) == NULL) 226 goto out; 227 r = fido_bio_dev_enroll_remove(dev, t, pin); 228 freezero(pin, PINBUF_LEN); 229 pin = NULL; 230 if (r != FIDO_OK) { 231 warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r)); 232 goto out; 233 } 234 235 ok = 0; 236 out: 237 free(id_blob_ptr); 238 fido_bio_template_free(&t); 239 fido_dev_close(dev); 240 fido_dev_free(&dev); 241 242 exit(ok); 243 } 244 245 static const char * 246 type_str(uint8_t t) 247 { 248 switch (t) { 249 case 1: 250 return "touch"; 251 case 2: 252 return "swipe"; 253 default: 254 return "unknown"; 255 } 256 } 257 258 void 259 bio_info(fido_dev_t *dev) 260 { 261 fido_bio_info_t *i = NULL; 262 263 if ((i = fido_bio_info_new()) == NULL) { 264 warnx("fido_bio_info_new"); 265 return; 266 } 267 if (fido_bio_dev_get_info(dev, i) != FIDO_OK) { 268 fido_bio_info_free(&i); 269 return; 270 } 271 272 printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), 273 type_str(fido_bio_info_type(i))); 274 printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); 275 276 fido_bio_info_free(&i); 277 } 278