1 /* 2 * Copyright (c) 2018 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 <sys/types.h> 8 #include <sys/stat.h> 9 10 #include <openssl/ec.h> 11 #include <openssl/evp.h> 12 #include <openssl/pem.h> 13 14 #include <fido.h> 15 #include <fido/es256.h> 16 #include <fido/rs256.h> 17 #include <fido/eddsa.h> 18 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <limits.h> 22 #include <stdint.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "../openbsd-compat/openbsd-compat.h" 28 #ifdef _MSC_VER 29 #include "../openbsd-compat/posix_win.h" 30 #endif 31 32 #include "extern.h" 33 34 void 35 read_pin(const char *path, char *buf, size_t len) 36 { 37 char prompt[1024]; 38 int r; 39 40 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path); 41 if (r < 0 || (size_t)r >= sizeof(prompt)) 42 errx(1, "snprintf"); 43 if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF)) 44 errx(1, "readpassphrase"); 45 } 46 47 FILE * 48 open_write(const char *file) 49 { 50 int fd; 51 FILE *f; 52 53 if (file == NULL || strcmp(file, "-") == 0) 54 return (stdout); 55 if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) 56 err(1, "open %s", file); 57 if ((f = fdopen(fd, "w")) == NULL) 58 err(1, "fdopen %s", file); 59 60 return (f); 61 } 62 63 FILE * 64 open_read(const char *file) 65 { 66 int fd; 67 FILE *f; 68 69 if (file == NULL || strcmp(file, "-") == 0) { 70 #ifdef FIDO_FUZZ 71 setvbuf(stdin, NULL, _IONBF, 0); 72 #endif 73 return (stdin); 74 } 75 if ((fd = open(file, O_RDONLY)) < 0) 76 err(1, "open %s", file); 77 if ((f = fdopen(fd, "r")) == NULL) 78 err(1, "fdopen %s", file); 79 80 return (f); 81 } 82 83 int 84 base10(const char *str) 85 { 86 char *ep; 87 long long ll; 88 89 ll = strtoll(str, &ep, 10); 90 if (str == ep || *ep != '\0') 91 return (-1); 92 else if (ll == LLONG_MIN && errno == ERANGE) 93 return (-1); 94 else if (ll == LLONG_MAX && errno == ERANGE) 95 return (-1); 96 else if (ll < 0 || ll > INT_MAX) 97 return (-1); 98 99 return ((int)ll); 100 } 101 102 void 103 xxd(const void *buf, size_t count) 104 { 105 const uint8_t *ptr = buf; 106 size_t i; 107 108 fprintf(stderr, " "); 109 110 for (i = 0; i < count; i++) { 111 fprintf(stderr, "%02x ", *ptr++); 112 if ((i + 1) % 16 == 0 && i + 1 < count) 113 fprintf(stderr, "\n "); 114 } 115 116 fprintf(stderr, "\n"); 117 fflush(stderr); 118 } 119 120 int 121 string_read(FILE *f, char **out) 122 { 123 char *line = NULL; 124 size_t linesize = 0; 125 ssize_t n; 126 127 *out = NULL; 128 129 if ((n = getline(&line, &linesize, f)) <= 0 || 130 (size_t)n != strlen(line)) { 131 free(line); 132 return (-1); 133 } 134 135 line[n - 1] = '\0'; /* trim \n */ 136 *out = line; 137 138 return (0); 139 } 140 141 fido_dev_t * 142 open_dev(const char *path) 143 { 144 fido_dev_t *dev; 145 int r; 146 147 if ((dev = fido_dev_new()) == NULL) 148 errx(1, "fido_dev_new"); 149 150 r = fido_dev_open(dev, path); 151 if (r != FIDO_OK) 152 errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); 153 154 return (dev); 155 } 156 157 EC_KEY * 158 read_ec_pubkey(const char *path) 159 { 160 FILE *fp = NULL; 161 EVP_PKEY *pkey = NULL; 162 EC_KEY *ec = NULL; 163 164 if ((fp = fopen(path, "r")) == NULL) { 165 warn("fopen"); 166 goto fail; 167 } 168 169 if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 170 warnx("PEM_read_PUBKEY"); 171 goto fail; 172 } 173 if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { 174 warnx("EVP_PKEY_get1_EC_KEY"); 175 goto fail; 176 } 177 178 fail: 179 if (fp) { 180 fclose(fp); 181 } 182 if (pkey) { 183 EVP_PKEY_free(pkey); 184 } 185 186 return (ec); 187 } 188 189 int 190 write_ec_pubkey(FILE *f, const void *ptr, size_t len) 191 { 192 EVP_PKEY *pkey = NULL; 193 es256_pk_t *pk = NULL; 194 int ok = -1; 195 196 if ((pk = es256_pk_new()) == NULL) { 197 warnx("es256_pk_new"); 198 goto fail; 199 } 200 201 if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 202 warnx("es256_pk_from_ptr"); 203 goto fail; 204 } 205 206 if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { 207 warnx("es256_pk_to_EVP_PKEY"); 208 goto fail; 209 } 210 211 if (PEM_write_PUBKEY(f, pkey) == 0) { 212 warnx("PEM_write_PUBKEY"); 213 goto fail; 214 } 215 216 ok = 0; 217 fail: 218 es256_pk_free(&pk); 219 220 if (pkey != NULL) { 221 EVP_PKEY_free(pkey); 222 } 223 224 return (ok); 225 } 226 227 RSA * 228 read_rsa_pubkey(const char *path) 229 { 230 FILE *fp = NULL; 231 EVP_PKEY *pkey = NULL; 232 RSA *rsa = NULL; 233 234 if ((fp = fopen(path, "r")) == NULL) { 235 warn("fopen"); 236 goto fail; 237 } 238 239 if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 240 warnx("PEM_read_PUBKEY"); 241 goto fail; 242 } 243 if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { 244 warnx("EVP_PKEY_get1_RSA"); 245 goto fail; 246 } 247 248 fail: 249 if (fp) { 250 fclose(fp); 251 } 252 if (pkey) { 253 EVP_PKEY_free(pkey); 254 } 255 256 return (rsa); 257 } 258 259 int 260 write_rsa_pubkey(FILE *f, const void *ptr, size_t len) 261 { 262 EVP_PKEY *pkey = NULL; 263 rs256_pk_t *pk = NULL; 264 int ok = -1; 265 266 if ((pk = rs256_pk_new()) == NULL) { 267 warnx("rs256_pk_new"); 268 goto fail; 269 } 270 271 if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 272 warnx("rs256_pk_from_ptr"); 273 goto fail; 274 } 275 276 if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { 277 warnx("rs256_pk_to_EVP_PKEY"); 278 goto fail; 279 } 280 281 if (PEM_write_PUBKEY(f, pkey) == 0) { 282 warnx("PEM_write_PUBKEY"); 283 goto fail; 284 } 285 286 ok = 0; 287 fail: 288 rs256_pk_free(&pk); 289 290 if (pkey != NULL) { 291 EVP_PKEY_free(pkey); 292 } 293 294 return (ok); 295 } 296 297 EVP_PKEY * 298 read_eddsa_pubkey(const char *path) 299 { 300 FILE *fp = NULL; 301 EVP_PKEY *pkey = NULL; 302 303 if ((fp = fopen(path, "r")) == NULL) { 304 warn("fopen"); 305 goto fail; 306 } 307 308 if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 309 warnx("PEM_read_PUBKEY"); 310 goto fail; 311 } 312 313 fail: 314 if (fp) { 315 fclose(fp); 316 } 317 318 return (pkey); 319 } 320 321 int 322 write_eddsa_pubkey(FILE *f, const void *ptr, size_t len) 323 { 324 EVP_PKEY *pkey = NULL; 325 eddsa_pk_t *pk = NULL; 326 int ok = -1; 327 328 if ((pk = eddsa_pk_new()) == NULL) { 329 warnx("eddsa_pk_new"); 330 goto fail; 331 } 332 333 if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 334 warnx("eddsa_pk_from_ptr"); 335 goto fail; 336 } 337 338 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { 339 warnx("eddsa_pk_to_EVP_PKEY"); 340 goto fail; 341 } 342 343 if (PEM_write_PUBKEY(f, pkey) == 0) { 344 warnx("PEM_write_PUBKEY"); 345 goto fail; 346 } 347 348 ok = 0; 349 fail: 350 eddsa_pk_free(&pk); 351 352 if (pkey != NULL) { 353 EVP_PKEY_free(pkey); 354 } 355 356 return (ok); 357 } 358 359 void 360 print_cred(FILE *out_f, int type, const fido_cred_t *cred) 361 { 362 char *id; 363 int r; 364 365 r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); 366 if (r < 0) 367 errx(1, "output error"); 368 369 fprintf(out_f, "%s\n", id); 370 371 if (type == COSE_ES256) { 372 write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), 373 fido_cred_pubkey_len(cred)); 374 } else if (type == COSE_RS256) { 375 write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), 376 fido_cred_pubkey_len(cred)); 377 } else if (type == COSE_EDDSA) { 378 write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), 379 fido_cred_pubkey_len(cred)); 380 } else { 381 errx(1, "print_cred: unknown type"); 382 } 383 384 free(id); 385 } 386 387 int 388 cose_type(const char *str, int *type) 389 { 390 if (strcmp(str, "es256") == 0) 391 *type = COSE_ES256; 392 else if (strcmp(str, "rs256") == 0) 393 *type = COSE_RS256; 394 else if (strcmp(str, "eddsa") == 0) 395 *type = COSE_EDDSA; 396 else { 397 *type = 0; 398 return (-1); 399 } 400 401 return (0); 402 } 403 404 const char * 405 cose_string(int type) 406 { 407 switch (type) { 408 case COSE_EDDSA: 409 return ("eddsa"); 410 case COSE_ES256: 411 return ("es256"); 412 case COSE_RS256: 413 return ("rs256"); 414 default: 415 return ("unknown"); 416 } 417 } 418 419 const char * 420 prot_string(int prot) 421 { 422 switch (prot) { 423 case FIDO_CRED_PROT_UV_OPTIONAL: 424 return ("uvopt"); 425 case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID: 426 return ("uvopt+id"); 427 case FIDO_CRED_PROT_UV_REQUIRED: 428 return ("uvreq"); 429 default: 430 return ("unknown"); 431 } 432 } 433