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