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 <stdbool.h> 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 void 22 print_template(const fido_bio_template_array_t *ta, size_t idx) 23 { 24 char *id = NULL; 25 const fido_bio_template_t *t = NULL; 26 27 if ((t = fido_bio_template(ta, idx)) == NULL) 28 errx(1, "fido_bio_template"); 29 30 if (base64_encode(fido_bio_template_id_ptr(t), 31 fido_bio_template_id_len(t), &id) < 0) 32 errx(1, "output error"); 33 34 printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); 35 36 free(id); 37 } 38 39 int 40 bio_list(char *path) 41 { 42 char pin[1024]; 43 fido_bio_template_array_t *ta = NULL; 44 fido_dev_t *dev = NULL; 45 int r; 46 47 if (path == NULL) 48 usage(); 49 if ((ta = fido_bio_template_array_new()) == NULL) 50 errx(1, "fido_bio_template_array_new"); 51 52 dev = open_dev(path); 53 read_pin(path, pin, sizeof(pin)); 54 r = fido_bio_dev_get_template_array(dev, ta, pin); 55 explicit_bzero(pin, sizeof(pin)); 56 57 if (r != FIDO_OK) 58 errx(1, "fido_bio_dev_get_template_array: %s", fido_strerr(r)); 59 for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) 60 print_template(ta, i); 61 62 fido_bio_template_array_free(&ta); 63 fido_dev_close(dev); 64 fido_dev_free(&dev); 65 66 exit(0); 67 } 68 69 int 70 bio_set_name(char *path, char *id, char *name) 71 { 72 char pin[1024]; 73 fido_bio_template_t *t = NULL; 74 fido_dev_t *dev = NULL; 75 int r; 76 size_t id_blob_len = 0; 77 void *id_blob_ptr = NULL; 78 79 if (path == NULL) 80 usage(); 81 if ((t = fido_bio_template_new()) == NULL) 82 errx(1, "fido_bio_template_new"); 83 84 if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) 85 errx(1, "base64_decode"); 86 87 if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) 88 errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); 89 if ((r = fido_bio_template_set_id(t, id_blob_ptr, 90 id_blob_len)) != FIDO_OK) 91 errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); 92 93 dev = open_dev(path); 94 read_pin(path, pin, sizeof(pin)); 95 r = fido_bio_dev_set_template_name(dev, t, pin); 96 explicit_bzero(pin, sizeof(pin)); 97 98 if (r != FIDO_OK) 99 errx(1, "fido_bio_dev_set_template_name: %s", fido_strerr(r)); 100 101 free(id_blob_ptr); 102 fido_bio_template_free(&t); 103 fido_dev_close(dev); 104 fido_dev_free(&dev); 105 106 exit(0); 107 } 108 109 static const char * 110 plural(uint8_t n) 111 { 112 if (n == 1) 113 return ""; 114 return "s"; 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(char *path) 158 { 159 char pin[1024]; 160 fido_bio_enroll_t *e = NULL; 161 fido_bio_template_t *t = NULL; 162 fido_dev_t *dev = NULL; 163 int r; 164 165 if (path == NULL) 166 usage(); 167 if ((t = fido_bio_template_new()) == NULL) 168 errx(1, "fido_bio_template_new"); 169 if ((e = fido_bio_enroll_new()) == NULL) 170 errx(1, "fido_bio_enroll_new"); 171 172 dev = open_dev(path); 173 read_pin(path, pin, sizeof(pin)); 174 175 printf("Touch your security key.\n"); 176 177 r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); 178 explicit_bzero(pin, sizeof(pin)); 179 if (r != FIDO_OK) 180 errx(1, "fido_bio_dev_enroll_begin: %s", fido_strerr(r)); 181 182 printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); 183 184 while (fido_bio_enroll_remaining_samples(e) > 0) { 185 printf("Touch your security key (%u sample%s left).\n", 186 (unsigned)fido_bio_enroll_remaining_samples(e), 187 plural(fido_bio_enroll_remaining_samples(e))); 188 if ((r = fido_bio_dev_enroll_continue(dev, t, e, 189 10000)) != FIDO_OK) { 190 errx(1, "fido_bio_dev_enroll_continue: %s", 191 fido_strerr(r)); 192 } 193 printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); 194 } 195 196 fido_bio_template_free(&t); 197 fido_bio_enroll_free(&e); 198 fido_dev_close(dev); 199 fido_dev_free(&dev); 200 201 exit(0); 202 } 203 204 int 205 bio_delete(fido_dev_t *dev, char *path, char *id) 206 { 207 char pin[1024]; 208 fido_bio_template_t *t = NULL; 209 int r; 210 size_t id_blob_len = 0; 211 void *id_blob_ptr = NULL; 212 213 if (path == NULL) 214 usage(); 215 if ((t = fido_bio_template_new()) == NULL) 216 errx(1, "fido_bio_template_new"); 217 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 read_pin(path, pin, sizeof(pin)); 225 r = fido_bio_dev_enroll_remove(dev, t, pin); 226 explicit_bzero(pin, sizeof(pin)); 227 228 if (r != FIDO_OK) 229 errx(1, "fido_bio_dev_enroll_remove: %s", fido_strerr(r)); 230 231 free(id_blob_ptr); 232 fido_bio_template_free(&t); 233 fido_dev_close(dev); 234 fido_dev_free(&dev); 235 236 exit(0); 237 } 238 239 static const char * 240 type_str(uint8_t t) 241 { 242 switch (t) { 243 case 1: 244 return "touch"; 245 case 2: 246 return "swipe"; 247 default: 248 return "unknown"; 249 } 250 } 251 252 void 253 bio_info(fido_dev_t *dev) 254 { 255 fido_bio_info_t *i = NULL; 256 257 if ((i = fido_bio_info_new()) == NULL) 258 errx(1, "fido_bio_info_new"); 259 if (fido_bio_dev_get_info(dev, i) != FIDO_OK) { 260 fido_bio_info_free(&i); 261 return; 262 } 263 264 printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), 265 type_str(fido_bio_info_type(i))); 266 printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); 267 268 fido_bio_info_free(&i); 269 } 270