1 1.1 christos /* 2 1.4 christos * Copyright (c) 2018-2022 Yubico AB. All rights reserved. 3 1.1 christos * Use of this source code is governed by a BSD-style 4 1.1 christos * license that can be found in the LICENSE file. 5 1.4 christos * SPDX-License-Identifier: BSD-2-Clause 6 1.1 christos */ 7 1.1 christos 8 1.1 christos #include <sys/types.h> 9 1.1 christos #include <sys/stat.h> 10 1.1 christos 11 1.1 christos #include <openssl/ec.h> 12 1.1 christos #include <openssl/evp.h> 13 1.1 christos #include <openssl/pem.h> 14 1.1 christos 15 1.1 christos #include <fido.h> 16 1.1 christos #include <fido/es256.h> 17 1.4 christos #include <fido/es384.h> 18 1.1 christos #include <fido/rs256.h> 19 1.1 christos #include <fido/eddsa.h> 20 1.1 christos 21 1.2 christos #include <errno.h> 22 1.1 christos #include <fcntl.h> 23 1.2 christos #include <limits.h> 24 1.2 christos #include <stdbool.h> 25 1.1 christos #include <stdint.h> 26 1.1 christos #include <stdio.h> 27 1.1 christos #include <stdlib.h> 28 1.1 christos #include <string.h> 29 1.2 christos #include <unistd.h> 30 1.1 christos 31 1.1 christos #include "../openbsd-compat/openbsd-compat.h" 32 1.1 christos #ifdef _MSC_VER 33 1.1 christos #include "../openbsd-compat/posix_win.h" 34 1.1 christos #endif 35 1.1 christos 36 1.1 christos #include "extern.h" 37 1.1 christos 38 1.2 christos char * 39 1.2 christos get_pin(const char *path) 40 1.1 christos { 41 1.2 christos char *pin; 42 1.1 christos char prompt[1024]; 43 1.2 christos int r, ok = -1; 44 1.2 christos 45 1.2 christos if ((pin = calloc(1, PINBUF_LEN)) == NULL) { 46 1.2 christos warn("%s: calloc", __func__); 47 1.2 christos return NULL; 48 1.2 christos } 49 1.2 christos if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 50 1.2 christos path)) < 0 || (size_t)r >= sizeof(prompt)) { 51 1.2 christos warn("%s: snprintf", __func__); 52 1.2 christos goto out; 53 1.2 christos } 54 1.2 christos if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) { 55 1.2 christos warnx("%s: readpassphrase", __func__); 56 1.2 christos goto out; 57 1.2 christos } 58 1.2 christos 59 1.2 christos ok = 0; 60 1.2 christos out: 61 1.2 christos if (ok < 0) { 62 1.2 christos freezero(pin, PINBUF_LEN); 63 1.2 christos pin = NULL; 64 1.2 christos } 65 1.1 christos 66 1.2 christos return pin; 67 1.1 christos } 68 1.1 christos 69 1.1 christos FILE * 70 1.1 christos open_write(const char *file) 71 1.1 christos { 72 1.1 christos int fd; 73 1.1 christos FILE *f; 74 1.1 christos 75 1.1 christos if (file == NULL || strcmp(file, "-") == 0) 76 1.1 christos return (stdout); 77 1.1 christos if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) 78 1.1 christos err(1, "open %s", file); 79 1.1 christos if ((f = fdopen(fd, "w")) == NULL) 80 1.1 christos err(1, "fdopen %s", file); 81 1.1 christos 82 1.1 christos return (f); 83 1.1 christos } 84 1.1 christos 85 1.1 christos FILE * 86 1.1 christos open_read(const char *file) 87 1.1 christos { 88 1.1 christos int fd; 89 1.1 christos FILE *f; 90 1.1 christos 91 1.1 christos if (file == NULL || strcmp(file, "-") == 0) { 92 1.1 christos #ifdef FIDO_FUZZ 93 1.1 christos setvbuf(stdin, NULL, _IONBF, 0); 94 1.1 christos #endif 95 1.1 christos return (stdin); 96 1.1 christos } 97 1.1 christos if ((fd = open(file, O_RDONLY)) < 0) 98 1.1 christos err(1, "open %s", file); 99 1.1 christos if ((f = fdopen(fd, "r")) == NULL) 100 1.1 christos err(1, "fdopen %s", file); 101 1.1 christos 102 1.1 christos return (f); 103 1.1 christos } 104 1.1 christos 105 1.2 christos int 106 1.2 christos base10(const char *str) 107 1.2 christos { 108 1.2 christos char *ep; 109 1.2 christos long long ll; 110 1.2 christos 111 1.2 christos ll = strtoll(str, &ep, 10); 112 1.2 christos if (str == ep || *ep != '\0') 113 1.2 christos return (-1); 114 1.2 christos else if (ll == LLONG_MIN && errno == ERANGE) 115 1.2 christos return (-1); 116 1.2 christos else if (ll == LLONG_MAX && errno == ERANGE) 117 1.2 christos return (-1); 118 1.2 christos else if (ll < 0 || ll > INT_MAX) 119 1.2 christos return (-1); 120 1.2 christos 121 1.2 christos return ((int)ll); 122 1.2 christos } 123 1.2 christos 124 1.1 christos void 125 1.1 christos xxd(const void *buf, size_t count) 126 1.1 christos { 127 1.1 christos const uint8_t *ptr = buf; 128 1.1 christos size_t i; 129 1.1 christos 130 1.1 christos fprintf(stderr, " "); 131 1.1 christos 132 1.1 christos for (i = 0; i < count; i++) { 133 1.1 christos fprintf(stderr, "%02x ", *ptr++); 134 1.1 christos if ((i + 1) % 16 == 0 && i + 1 < count) 135 1.1 christos fprintf(stderr, "\n "); 136 1.1 christos } 137 1.1 christos 138 1.1 christos fprintf(stderr, "\n"); 139 1.1 christos fflush(stderr); 140 1.1 christos } 141 1.1 christos 142 1.1 christos int 143 1.1 christos string_read(FILE *f, char **out) 144 1.1 christos { 145 1.1 christos char *line = NULL; 146 1.1 christos size_t linesize = 0; 147 1.1 christos ssize_t n; 148 1.1 christos 149 1.1 christos *out = NULL; 150 1.1 christos 151 1.1 christos if ((n = getline(&line, &linesize, f)) <= 0 || 152 1.1 christos (size_t)n != strlen(line)) { 153 1.1 christos free(line); 154 1.1 christos return (-1); 155 1.1 christos } 156 1.1 christos 157 1.1 christos line[n - 1] = '\0'; /* trim \n */ 158 1.1 christos *out = line; 159 1.1 christos 160 1.1 christos return (0); 161 1.1 christos } 162 1.1 christos 163 1.1 christos fido_dev_t * 164 1.1 christos open_dev(const char *path) 165 1.1 christos { 166 1.1 christos fido_dev_t *dev; 167 1.1 christos int r; 168 1.1 christos 169 1.1 christos if ((dev = fido_dev_new()) == NULL) 170 1.1 christos errx(1, "fido_dev_new"); 171 1.1 christos 172 1.1 christos r = fido_dev_open(dev, path); 173 1.1 christos if (r != FIDO_OK) 174 1.1 christos errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); 175 1.1 christos 176 1.1 christos return (dev); 177 1.1 christos } 178 1.1 christos 179 1.2 christos int 180 1.2 christos get_devopt(fido_dev_t *dev, const char *name, int *val) 181 1.2 christos { 182 1.2 christos fido_cbor_info_t *cbor_info; 183 1.2 christos char * const *names; 184 1.2 christos const bool *values; 185 1.2 christos int r, ok = -1; 186 1.2 christos 187 1.2 christos if ((cbor_info = fido_cbor_info_new()) == NULL) { 188 1.2 christos warnx("fido_cbor_info_new"); 189 1.2 christos goto out; 190 1.2 christos } 191 1.2 christos 192 1.2 christos if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) { 193 1.2 christos warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); 194 1.2 christos goto out; 195 1.2 christos } 196 1.2 christos 197 1.2 christos if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL || 198 1.2 christos (values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) { 199 1.2 christos warnx("fido_dev_get_cbor_info: NULL name/value pointer"); 200 1.2 christos goto out; 201 1.2 christos } 202 1.2 christos 203 1.2 christos *val = -1; 204 1.2 christos for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++) 205 1.2 christos if (strcmp(names[i], name) == 0) { 206 1.2 christos *val = values[i]; 207 1.2 christos break; 208 1.2 christos } 209 1.2 christos 210 1.2 christos ok = 0; 211 1.2 christos out: 212 1.2 christos fido_cbor_info_free(&cbor_info); 213 1.2 christos 214 1.2 christos return (ok); 215 1.2 christos } 216 1.2 christos 217 1.1 christos EC_KEY * 218 1.1 christos read_ec_pubkey(const char *path) 219 1.1 christos { 220 1.1 christos FILE *fp = NULL; 221 1.1 christos EVP_PKEY *pkey = NULL; 222 1.1 christos EC_KEY *ec = NULL; 223 1.1 christos 224 1.1 christos if ((fp = fopen(path, "r")) == NULL) { 225 1.1 christos warn("fopen"); 226 1.1 christos goto fail; 227 1.1 christos } 228 1.1 christos 229 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 230 1.1 christos warnx("PEM_read_PUBKEY"); 231 1.1 christos goto fail; 232 1.1 christos } 233 1.1 christos if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { 234 1.1 christos warnx("EVP_PKEY_get1_EC_KEY"); 235 1.1 christos goto fail; 236 1.1 christos } 237 1.1 christos 238 1.1 christos fail: 239 1.1 christos if (fp) { 240 1.1 christos fclose(fp); 241 1.1 christos } 242 1.1 christos if (pkey) { 243 1.1 christos EVP_PKEY_free(pkey); 244 1.1 christos } 245 1.1 christos 246 1.1 christos return (ec); 247 1.1 christos } 248 1.1 christos 249 1.1 christos int 250 1.4 christos write_es256_pubkey(FILE *f, const void *ptr, size_t len) 251 1.1 christos { 252 1.1 christos EVP_PKEY *pkey = NULL; 253 1.1 christos es256_pk_t *pk = NULL; 254 1.1 christos int ok = -1; 255 1.1 christos 256 1.1 christos if ((pk = es256_pk_new()) == NULL) { 257 1.1 christos warnx("es256_pk_new"); 258 1.1 christos goto fail; 259 1.1 christos } 260 1.1 christos 261 1.1 christos if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 262 1.1 christos warnx("es256_pk_from_ptr"); 263 1.1 christos goto fail; 264 1.1 christos } 265 1.1 christos 266 1.1 christos if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { 267 1.1 christos warnx("es256_pk_to_EVP_PKEY"); 268 1.1 christos goto fail; 269 1.1 christos } 270 1.1 christos 271 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) { 272 1.1 christos warnx("PEM_write_PUBKEY"); 273 1.1 christos goto fail; 274 1.1 christos } 275 1.1 christos 276 1.1 christos ok = 0; 277 1.1 christos fail: 278 1.1 christos es256_pk_free(&pk); 279 1.1 christos 280 1.1 christos if (pkey != NULL) { 281 1.1 christos EVP_PKEY_free(pkey); 282 1.1 christos } 283 1.1 christos 284 1.1 christos return (ok); 285 1.1 christos } 286 1.1 christos 287 1.4 christos int 288 1.4 christos write_es384_pubkey(FILE *f, const void *ptr, size_t len) 289 1.4 christos { 290 1.4 christos EVP_PKEY *pkey = NULL; 291 1.4 christos es384_pk_t *pk = NULL; 292 1.4 christos int ok = -1; 293 1.4 christos 294 1.4 christos if ((pk = es384_pk_new()) == NULL) { 295 1.4 christos warnx("es384_pk_new"); 296 1.4 christos goto fail; 297 1.4 christos } 298 1.4 christos 299 1.4 christos if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 300 1.4 christos warnx("es384_pk_from_ptr"); 301 1.4 christos goto fail; 302 1.4 christos } 303 1.4 christos 304 1.4 christos if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) { 305 1.4 christos warnx("es384_pk_to_EVP_PKEY"); 306 1.4 christos goto fail; 307 1.4 christos } 308 1.4 christos 309 1.4 christos if (PEM_write_PUBKEY(f, pkey) == 0) { 310 1.4 christos warnx("PEM_write_PUBKEY"); 311 1.4 christos goto fail; 312 1.4 christos } 313 1.4 christos 314 1.4 christos ok = 0; 315 1.4 christos fail: 316 1.4 christos es384_pk_free(&pk); 317 1.4 christos 318 1.4 christos if (pkey != NULL) { 319 1.4 christos EVP_PKEY_free(pkey); 320 1.4 christos } 321 1.4 christos 322 1.4 christos return (ok); 323 1.4 christos } 324 1.4 christos 325 1.1 christos RSA * 326 1.1 christos read_rsa_pubkey(const char *path) 327 1.1 christos { 328 1.1 christos FILE *fp = NULL; 329 1.1 christos EVP_PKEY *pkey = NULL; 330 1.1 christos RSA *rsa = NULL; 331 1.1 christos 332 1.1 christos if ((fp = fopen(path, "r")) == NULL) { 333 1.1 christos warn("fopen"); 334 1.1 christos goto fail; 335 1.1 christos } 336 1.1 christos 337 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 338 1.1 christos warnx("PEM_read_PUBKEY"); 339 1.1 christos goto fail; 340 1.1 christos } 341 1.1 christos if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { 342 1.1 christos warnx("EVP_PKEY_get1_RSA"); 343 1.1 christos goto fail; 344 1.1 christos } 345 1.1 christos 346 1.1 christos fail: 347 1.1 christos if (fp) { 348 1.1 christos fclose(fp); 349 1.1 christos } 350 1.1 christos if (pkey) { 351 1.1 christos EVP_PKEY_free(pkey); 352 1.1 christos } 353 1.1 christos 354 1.1 christos return (rsa); 355 1.1 christos } 356 1.1 christos 357 1.1 christos int 358 1.1 christos write_rsa_pubkey(FILE *f, const void *ptr, size_t len) 359 1.1 christos { 360 1.1 christos EVP_PKEY *pkey = NULL; 361 1.1 christos rs256_pk_t *pk = NULL; 362 1.1 christos int ok = -1; 363 1.1 christos 364 1.1 christos if ((pk = rs256_pk_new()) == NULL) { 365 1.1 christos warnx("rs256_pk_new"); 366 1.1 christos goto fail; 367 1.1 christos } 368 1.1 christos 369 1.1 christos if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 370 1.1 christos warnx("rs256_pk_from_ptr"); 371 1.1 christos goto fail; 372 1.1 christos } 373 1.1 christos 374 1.1 christos if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { 375 1.1 christos warnx("rs256_pk_to_EVP_PKEY"); 376 1.1 christos goto fail; 377 1.1 christos } 378 1.1 christos 379 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) { 380 1.1 christos warnx("PEM_write_PUBKEY"); 381 1.1 christos goto fail; 382 1.1 christos } 383 1.1 christos 384 1.1 christos ok = 0; 385 1.1 christos fail: 386 1.1 christos rs256_pk_free(&pk); 387 1.1 christos 388 1.1 christos if (pkey != NULL) { 389 1.1 christos EVP_PKEY_free(pkey); 390 1.1 christos } 391 1.1 christos 392 1.1 christos return (ok); 393 1.1 christos } 394 1.1 christos 395 1.1 christos EVP_PKEY * 396 1.1 christos read_eddsa_pubkey(const char *path) 397 1.1 christos { 398 1.1 christos FILE *fp = NULL; 399 1.1 christos EVP_PKEY *pkey = NULL; 400 1.1 christos 401 1.1 christos if ((fp = fopen(path, "r")) == NULL) { 402 1.1 christos warn("fopen"); 403 1.1 christos goto fail; 404 1.1 christos } 405 1.1 christos 406 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 407 1.1 christos warnx("PEM_read_PUBKEY"); 408 1.1 christos goto fail; 409 1.1 christos } 410 1.1 christos 411 1.1 christos fail: 412 1.1 christos if (fp) { 413 1.1 christos fclose(fp); 414 1.1 christos } 415 1.1 christos 416 1.1 christos return (pkey); 417 1.1 christos } 418 1.1 christos 419 1.1 christos int 420 1.1 christos write_eddsa_pubkey(FILE *f, const void *ptr, size_t len) 421 1.1 christos { 422 1.1 christos EVP_PKEY *pkey = NULL; 423 1.1 christos eddsa_pk_t *pk = NULL; 424 1.1 christos int ok = -1; 425 1.1 christos 426 1.1 christos if ((pk = eddsa_pk_new()) == NULL) { 427 1.1 christos warnx("eddsa_pk_new"); 428 1.1 christos goto fail; 429 1.1 christos } 430 1.1 christos 431 1.1 christos if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { 432 1.1 christos warnx("eddsa_pk_from_ptr"); 433 1.1 christos goto fail; 434 1.1 christos } 435 1.1 christos 436 1.1 christos if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { 437 1.1 christos warnx("eddsa_pk_to_EVP_PKEY"); 438 1.1 christos goto fail; 439 1.1 christos } 440 1.1 christos 441 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) { 442 1.1 christos warnx("PEM_write_PUBKEY"); 443 1.1 christos goto fail; 444 1.1 christos } 445 1.1 christos 446 1.1 christos ok = 0; 447 1.1 christos fail: 448 1.1 christos eddsa_pk_free(&pk); 449 1.1 christos 450 1.1 christos if (pkey != NULL) { 451 1.1 christos EVP_PKEY_free(pkey); 452 1.1 christos } 453 1.1 christos 454 1.1 christos return (ok); 455 1.1 christos } 456 1.1 christos 457 1.1 christos void 458 1.1 christos print_cred(FILE *out_f, int type, const fido_cred_t *cred) 459 1.1 christos { 460 1.1 christos char *id; 461 1.1 christos int r; 462 1.1 christos 463 1.1 christos r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); 464 1.1 christos if (r < 0) 465 1.1 christos errx(1, "output error"); 466 1.1 christos 467 1.1 christos fprintf(out_f, "%s\n", id); 468 1.1 christos 469 1.4 christos switch (type) { 470 1.4 christos case COSE_ES256: 471 1.4 christos write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred), 472 1.4 christos fido_cred_pubkey_len(cred)); 473 1.4 christos break; 474 1.4 christos case COSE_ES384: 475 1.4 christos write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred), 476 1.1 christos fido_cred_pubkey_len(cred)); 477 1.4 christos break; 478 1.4 christos case COSE_RS256: 479 1.1 christos write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), 480 1.1 christos fido_cred_pubkey_len(cred)); 481 1.4 christos break; 482 1.4 christos case COSE_EDDSA: 483 1.1 christos write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), 484 1.1 christos fido_cred_pubkey_len(cred)); 485 1.4 christos break; 486 1.4 christos default: 487 1.1 christos errx(1, "print_cred: unknown type"); 488 1.1 christos } 489 1.1 christos 490 1.1 christos free(id); 491 1.1 christos } 492 1.2 christos 493 1.2 christos int 494 1.2 christos cose_type(const char *str, int *type) 495 1.2 christos { 496 1.2 christos if (strcmp(str, "es256") == 0) 497 1.2 christos *type = COSE_ES256; 498 1.4 christos else if (strcmp(str, "es384") == 0) 499 1.4 christos *type = COSE_ES384; 500 1.2 christos else if (strcmp(str, "rs256") == 0) 501 1.2 christos *type = COSE_RS256; 502 1.2 christos else if (strcmp(str, "eddsa") == 0) 503 1.2 christos *type = COSE_EDDSA; 504 1.2 christos else { 505 1.2 christos *type = 0; 506 1.2 christos return (-1); 507 1.2 christos } 508 1.2 christos 509 1.2 christos return (0); 510 1.2 christos } 511 1.2 christos 512 1.2 christos const char * 513 1.2 christos cose_string(int type) 514 1.2 christos { 515 1.2 christos switch (type) { 516 1.2 christos case COSE_ES256: 517 1.2 christos return ("es256"); 518 1.4 christos case COSE_ES384: 519 1.4 christos return ("es384"); 520 1.2 christos case COSE_RS256: 521 1.2 christos return ("rs256"); 522 1.4 christos case COSE_EDDSA: 523 1.4 christos return ("eddsa"); 524 1.2 christos default: 525 1.2 christos return ("unknown"); 526 1.2 christos } 527 1.2 christos } 528 1.2 christos 529 1.2 christos const char * 530 1.2 christos prot_string(int prot) 531 1.2 christos { 532 1.2 christos switch (prot) { 533 1.2 christos case FIDO_CRED_PROT_UV_OPTIONAL: 534 1.2 christos return ("uvopt"); 535 1.2 christos case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID: 536 1.2 christos return ("uvopt+id"); 537 1.2 christos case FIDO_CRED_PROT_UV_REQUIRED: 538 1.2 christos return ("uvreq"); 539 1.2 christos default: 540 1.2 christos return ("unknown"); 541 1.2 christos } 542 1.2 christos } 543 1.2 christos 544 1.2 christos int 545 1.2 christos read_file(const char *path, u_char **ptr, size_t *len) 546 1.2 christos { 547 1.2 christos int fd, ok = -1; 548 1.2 christos struct stat st; 549 1.2 christos ssize_t n; 550 1.2 christos 551 1.2 christos *ptr = NULL; 552 1.2 christos *len = 0; 553 1.2 christos 554 1.2 christos if ((fd = open(path, O_RDONLY)) < 0) { 555 1.2 christos warn("%s: open %s", __func__, path); 556 1.2 christos goto fail; 557 1.2 christos } 558 1.2 christos if (fstat(fd, &st) < 0) { 559 1.2 christos warn("%s: stat %s", __func__, path); 560 1.2 christos goto fail; 561 1.2 christos } 562 1.2 christos if (st.st_size < 0) { 563 1.2 christos warnx("%s: stat %s: invalid size", __func__, path); 564 1.2 christos goto fail; 565 1.2 christos } 566 1.2 christos *len = (size_t)st.st_size; 567 1.2 christos if ((*ptr = malloc(*len)) == NULL) { 568 1.2 christos warn("%s: malloc", __func__); 569 1.2 christos goto fail; 570 1.2 christos } 571 1.2 christos if ((n = read(fd, *ptr, *len)) < 0) { 572 1.2 christos warn("%s: read", __func__); 573 1.2 christos goto fail; 574 1.2 christos } 575 1.2 christos if ((size_t)n != *len) { 576 1.2 christos warnx("%s: read", __func__); 577 1.2 christos goto fail; 578 1.2 christos } 579 1.2 christos 580 1.2 christos ok = 0; 581 1.2 christos fail: 582 1.2 christos if (fd != -1) { 583 1.2 christos close(fd); 584 1.2 christos } 585 1.2 christos if (ok < 0) { 586 1.2 christos free(*ptr); 587 1.2 christos *ptr = NULL; 588 1.2 christos *len = 0; 589 1.2 christos } 590 1.2 christos 591 1.2 christos return ok; 592 1.2 christos } 593 1.2 christos 594 1.2 christos int 595 1.2 christos write_file(const char *path, const u_char *ptr, size_t len) 596 1.2 christos { 597 1.2 christos int fd, ok = -1; 598 1.2 christos ssize_t n; 599 1.2 christos 600 1.2 christos if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) { 601 1.2 christos warn("%s: open %s", __func__, path); 602 1.2 christos goto fail; 603 1.2 christos } 604 1.2 christos if ((n = write(fd, ptr, len)) < 0) { 605 1.2 christos warn("%s: write", __func__); 606 1.2 christos goto fail; 607 1.2 christos } 608 1.2 christos if ((size_t)n != len) { 609 1.2 christos warnx("%s: write", __func__); 610 1.2 christos goto fail; 611 1.2 christos } 612 1.2 christos 613 1.2 christos ok = 0; 614 1.2 christos fail: 615 1.2 christos if (fd != -1) { 616 1.2 christos close(fd); 617 1.2 christos } 618 1.2 christos 619 1.2 christos return ok; 620 1.2 christos } 621 1.2 christos 622 1.2 christos const char * 623 1.2 christos plural(size_t x) 624 1.2 christos { 625 1.2 christos return x == 1 ? "" : "s"; 626 1.2 christos } 627 1.2 christos 628 1.2 christos int 629 1.2 christos should_retry_with_pin(const fido_dev_t *dev, int r) 630 1.2 christos { 631 1.3 christos if (fido_dev_has_pin(dev) == false) { 632 1.3 christos return 0; 633 1.3 christos } 634 1.3 christos 635 1.3 christos switch (r) { 636 1.3 christos case FIDO_ERR_PIN_REQUIRED: 637 1.3 christos case FIDO_ERR_UNAUTHORIZED_PERM: 638 1.3 christos case FIDO_ERR_UV_BLOCKED: 639 1.3 christos case FIDO_ERR_UV_INVALID: 640 1.3 christos return 1; 641 1.3 christos } 642 1.3 christos 643 1.3 christos return 0; 644 1.2 christos } 645