1ba9bdd8bSchristos /*
2*0b4509d2Schristos * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
3ba9bdd8bSchristos * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos * license that can be found in the LICENSE file.
5*0b4509d2Schristos * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos */
7ba9bdd8bSchristos
8ba9bdd8bSchristos #include <sys/types.h>
9ba9bdd8bSchristos #include <sys/stat.h>
10ba9bdd8bSchristos
11ba9bdd8bSchristos #include <openssl/ec.h>
12ba9bdd8bSchristos #include <openssl/evp.h>
13ba9bdd8bSchristos #include <openssl/pem.h>
14ba9bdd8bSchristos
15ba9bdd8bSchristos #include <fido.h>
16ba9bdd8bSchristos #include <fido/es256.h>
17*0b4509d2Schristos #include <fido/es384.h>
18ba9bdd8bSchristos #include <fido/rs256.h>
19ba9bdd8bSchristos #include <fido/eddsa.h>
20ba9bdd8bSchristos
211fc1e710Schristos #include <errno.h>
22ba9bdd8bSchristos #include <fcntl.h>
231fc1e710Schristos #include <limits.h>
2495dbdf32Schristos #include <stdbool.h>
25ba9bdd8bSchristos #include <stdint.h>
26ba9bdd8bSchristos #include <stdio.h>
27ba9bdd8bSchristos #include <stdlib.h>
28ba9bdd8bSchristos #include <string.h>
2907d9d566Schristos #include <unistd.h>
30ba9bdd8bSchristos
31ba9bdd8bSchristos #include "../openbsd-compat/openbsd-compat.h"
32ba9bdd8bSchristos #ifdef _MSC_VER
33ba9bdd8bSchristos #include "../openbsd-compat/posix_win.h"
34ba9bdd8bSchristos #endif
35ba9bdd8bSchristos
36ba9bdd8bSchristos #include "extern.h"
37ba9bdd8bSchristos
3895dbdf32Schristos char *
get_pin(const char * path)3995dbdf32Schristos get_pin(const char *path)
40ba9bdd8bSchristos {
4195dbdf32Schristos char *pin;
42ba9bdd8bSchristos char prompt[1024];
4395dbdf32Schristos int r, ok = -1;
44ba9bdd8bSchristos
4595dbdf32Schristos if ((pin = calloc(1, PINBUF_LEN)) == NULL) {
4695dbdf32Schristos warn("%s: calloc", __func__);
4795dbdf32Schristos return NULL;
4895dbdf32Schristos }
4995dbdf32Schristos if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
5095dbdf32Schristos path)) < 0 || (size_t)r >= sizeof(prompt)) {
5195dbdf32Schristos warn("%s: snprintf", __func__);
5295dbdf32Schristos goto out;
5395dbdf32Schristos }
5495dbdf32Schristos if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) {
5595dbdf32Schristos warnx("%s: readpassphrase", __func__);
5695dbdf32Schristos goto out;
5795dbdf32Schristos }
5895dbdf32Schristos
5995dbdf32Schristos ok = 0;
6095dbdf32Schristos out:
6195dbdf32Schristos if (ok < 0) {
6295dbdf32Schristos freezero(pin, PINBUF_LEN);
6395dbdf32Schristos pin = NULL;
6495dbdf32Schristos }
6595dbdf32Schristos
6695dbdf32Schristos return pin;
67ba9bdd8bSchristos }
68ba9bdd8bSchristos
69ba9bdd8bSchristos FILE *
open_write(const char * file)70ba9bdd8bSchristos open_write(const char *file)
71ba9bdd8bSchristos {
72ba9bdd8bSchristos int fd;
73ba9bdd8bSchristos FILE *f;
74ba9bdd8bSchristos
75ba9bdd8bSchristos if (file == NULL || strcmp(file, "-") == 0)
76ba9bdd8bSchristos return (stdout);
77ba9bdd8bSchristos if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
78ba9bdd8bSchristos err(1, "open %s", file);
79ba9bdd8bSchristos if ((f = fdopen(fd, "w")) == NULL)
80ba9bdd8bSchristos err(1, "fdopen %s", file);
81ba9bdd8bSchristos
82ba9bdd8bSchristos return (f);
83ba9bdd8bSchristos }
84ba9bdd8bSchristos
85ba9bdd8bSchristos FILE *
open_read(const char * file)86ba9bdd8bSchristos open_read(const char *file)
87ba9bdd8bSchristos {
88ba9bdd8bSchristos int fd;
89ba9bdd8bSchristos FILE *f;
90ba9bdd8bSchristos
91ba9bdd8bSchristos if (file == NULL || strcmp(file, "-") == 0) {
92ba9bdd8bSchristos #ifdef FIDO_FUZZ
93ba9bdd8bSchristos setvbuf(stdin, NULL, _IONBF, 0);
94ba9bdd8bSchristos #endif
95ba9bdd8bSchristos return (stdin);
96ba9bdd8bSchristos }
97ba9bdd8bSchristos if ((fd = open(file, O_RDONLY)) < 0)
98ba9bdd8bSchristos err(1, "open %s", file);
99ba9bdd8bSchristos if ((f = fdopen(fd, "r")) == NULL)
100ba9bdd8bSchristos err(1, "fdopen %s", file);
101ba9bdd8bSchristos
102ba9bdd8bSchristos return (f);
103ba9bdd8bSchristos }
104ba9bdd8bSchristos
1051fc1e710Schristos int
base10(const char * str)1061fc1e710Schristos base10(const char *str)
1071fc1e710Schristos {
1081fc1e710Schristos char *ep;
1091fc1e710Schristos long long ll;
1101fc1e710Schristos
1111fc1e710Schristos ll = strtoll(str, &ep, 10);
1121fc1e710Schristos if (str == ep || *ep != '\0')
1131fc1e710Schristos return (-1);
1141fc1e710Schristos else if (ll == LLONG_MIN && errno == ERANGE)
1151fc1e710Schristos return (-1);
1161fc1e710Schristos else if (ll == LLONG_MAX && errno == ERANGE)
1171fc1e710Schristos return (-1);
1181fc1e710Schristos else if (ll < 0 || ll > INT_MAX)
1191fc1e710Schristos return (-1);
1201fc1e710Schristos
1211fc1e710Schristos return ((int)ll);
1221fc1e710Schristos }
1231fc1e710Schristos
124ba9bdd8bSchristos void
xxd(const void * buf,size_t count)125ba9bdd8bSchristos xxd(const void *buf, size_t count)
126ba9bdd8bSchristos {
127ba9bdd8bSchristos const uint8_t *ptr = buf;
128ba9bdd8bSchristos size_t i;
129ba9bdd8bSchristos
130ba9bdd8bSchristos fprintf(stderr, " ");
131ba9bdd8bSchristos
132ba9bdd8bSchristos for (i = 0; i < count; i++) {
133ba9bdd8bSchristos fprintf(stderr, "%02x ", *ptr++);
134ba9bdd8bSchristos if ((i + 1) % 16 == 0 && i + 1 < count)
135ba9bdd8bSchristos fprintf(stderr, "\n ");
136ba9bdd8bSchristos }
137ba9bdd8bSchristos
138ba9bdd8bSchristos fprintf(stderr, "\n");
139ba9bdd8bSchristos fflush(stderr);
140ba9bdd8bSchristos }
141ba9bdd8bSchristos
142ba9bdd8bSchristos int
string_read(FILE * f,char ** out)143ba9bdd8bSchristos string_read(FILE *f, char **out)
144ba9bdd8bSchristos {
145ba9bdd8bSchristos char *line = NULL;
146ba9bdd8bSchristos size_t linesize = 0;
147ba9bdd8bSchristos ssize_t n;
148ba9bdd8bSchristos
149ba9bdd8bSchristos *out = NULL;
150ba9bdd8bSchristos
151ba9bdd8bSchristos if ((n = getline(&line, &linesize, f)) <= 0 ||
152ba9bdd8bSchristos (size_t)n != strlen(line)) {
153ba9bdd8bSchristos free(line);
154ba9bdd8bSchristos return (-1);
155ba9bdd8bSchristos }
156ba9bdd8bSchristos
157ba9bdd8bSchristos line[n - 1] = '\0'; /* trim \n */
158ba9bdd8bSchristos *out = line;
159ba9bdd8bSchristos
160ba9bdd8bSchristos return (0);
161ba9bdd8bSchristos }
162ba9bdd8bSchristos
163ba9bdd8bSchristos fido_dev_t *
open_dev(const char * path)164ba9bdd8bSchristos open_dev(const char *path)
165ba9bdd8bSchristos {
166ba9bdd8bSchristos fido_dev_t *dev;
167ba9bdd8bSchristos int r;
168ba9bdd8bSchristos
169ba9bdd8bSchristos if ((dev = fido_dev_new()) == NULL)
170ba9bdd8bSchristos errx(1, "fido_dev_new");
171ba9bdd8bSchristos
172ba9bdd8bSchristos r = fido_dev_open(dev, path);
173ba9bdd8bSchristos if (r != FIDO_OK)
174ba9bdd8bSchristos errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
175ba9bdd8bSchristos
176ba9bdd8bSchristos return (dev);
177ba9bdd8bSchristos }
178ba9bdd8bSchristos
17995dbdf32Schristos int
get_devopt(fido_dev_t * dev,const char * name,int * val)18095dbdf32Schristos get_devopt(fido_dev_t *dev, const char *name, int *val)
18195dbdf32Schristos {
18295dbdf32Schristos fido_cbor_info_t *cbor_info;
18395dbdf32Schristos char * const *names;
18495dbdf32Schristos const bool *values;
18595dbdf32Schristos int r, ok = -1;
18695dbdf32Schristos
18795dbdf32Schristos if ((cbor_info = fido_cbor_info_new()) == NULL) {
18895dbdf32Schristos warnx("fido_cbor_info_new");
18995dbdf32Schristos goto out;
19095dbdf32Schristos }
19195dbdf32Schristos
19295dbdf32Schristos if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) {
19395dbdf32Schristos warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
19495dbdf32Schristos goto out;
19595dbdf32Schristos }
19695dbdf32Schristos
19795dbdf32Schristos if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL ||
19895dbdf32Schristos (values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) {
19995dbdf32Schristos warnx("fido_dev_get_cbor_info: NULL name/value pointer");
20095dbdf32Schristos goto out;
20195dbdf32Schristos }
20295dbdf32Schristos
20395dbdf32Schristos *val = -1;
20495dbdf32Schristos for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++)
20595dbdf32Schristos if (strcmp(names[i], name) == 0) {
20695dbdf32Schristos *val = values[i];
20795dbdf32Schristos break;
20895dbdf32Schristos }
20995dbdf32Schristos
21095dbdf32Schristos ok = 0;
21195dbdf32Schristos out:
21295dbdf32Schristos fido_cbor_info_free(&cbor_info);
21395dbdf32Schristos
21495dbdf32Schristos return (ok);
21595dbdf32Schristos }
21695dbdf32Schristos
217ba9bdd8bSchristos EC_KEY *
read_ec_pubkey(const char * path)218ba9bdd8bSchristos read_ec_pubkey(const char *path)
219ba9bdd8bSchristos {
220ba9bdd8bSchristos FILE *fp = NULL;
221ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
222ba9bdd8bSchristos EC_KEY *ec = NULL;
223ba9bdd8bSchristos
224ba9bdd8bSchristos if ((fp = fopen(path, "r")) == NULL) {
225ba9bdd8bSchristos warn("fopen");
226ba9bdd8bSchristos goto fail;
227ba9bdd8bSchristos }
228ba9bdd8bSchristos
229ba9bdd8bSchristos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
230ba9bdd8bSchristos warnx("PEM_read_PUBKEY");
231ba9bdd8bSchristos goto fail;
232ba9bdd8bSchristos }
233ba9bdd8bSchristos if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
234ba9bdd8bSchristos warnx("EVP_PKEY_get1_EC_KEY");
235ba9bdd8bSchristos goto fail;
236ba9bdd8bSchristos }
237ba9bdd8bSchristos
238ba9bdd8bSchristos fail:
239ba9bdd8bSchristos if (fp) {
240ba9bdd8bSchristos fclose(fp);
241ba9bdd8bSchristos }
242ba9bdd8bSchristos if (pkey) {
243ba9bdd8bSchristos EVP_PKEY_free(pkey);
244ba9bdd8bSchristos }
245ba9bdd8bSchristos
246ba9bdd8bSchristos return (ec);
247ba9bdd8bSchristos }
248ba9bdd8bSchristos
249ba9bdd8bSchristos int
write_es256_pubkey(FILE * f,const void * ptr,size_t len)250*0b4509d2Schristos write_es256_pubkey(FILE *f, const void *ptr, size_t len)
251ba9bdd8bSchristos {
252ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
253ba9bdd8bSchristos es256_pk_t *pk = NULL;
254ba9bdd8bSchristos int ok = -1;
255ba9bdd8bSchristos
256ba9bdd8bSchristos if ((pk = es256_pk_new()) == NULL) {
257ba9bdd8bSchristos warnx("es256_pk_new");
258ba9bdd8bSchristos goto fail;
259ba9bdd8bSchristos }
260ba9bdd8bSchristos
261ba9bdd8bSchristos if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
262ba9bdd8bSchristos warnx("es256_pk_from_ptr");
263ba9bdd8bSchristos goto fail;
264ba9bdd8bSchristos }
265ba9bdd8bSchristos
266ba9bdd8bSchristos if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
267ba9bdd8bSchristos warnx("es256_pk_to_EVP_PKEY");
268ba9bdd8bSchristos goto fail;
269ba9bdd8bSchristos }
270ba9bdd8bSchristos
271ba9bdd8bSchristos if (PEM_write_PUBKEY(f, pkey) == 0) {
272ba9bdd8bSchristos warnx("PEM_write_PUBKEY");
273ba9bdd8bSchristos goto fail;
274ba9bdd8bSchristos }
275ba9bdd8bSchristos
276ba9bdd8bSchristos ok = 0;
277ba9bdd8bSchristos fail:
278ba9bdd8bSchristos es256_pk_free(&pk);
279ba9bdd8bSchristos
280ba9bdd8bSchristos if (pkey != NULL) {
281ba9bdd8bSchristos EVP_PKEY_free(pkey);
282ba9bdd8bSchristos }
283ba9bdd8bSchristos
284ba9bdd8bSchristos return (ok);
285ba9bdd8bSchristos }
286ba9bdd8bSchristos
287*0b4509d2Schristos int
write_es384_pubkey(FILE * f,const void * ptr,size_t len)288*0b4509d2Schristos write_es384_pubkey(FILE *f, const void *ptr, size_t len)
289*0b4509d2Schristos {
290*0b4509d2Schristos EVP_PKEY *pkey = NULL;
291*0b4509d2Schristos es384_pk_t *pk = NULL;
292*0b4509d2Schristos int ok = -1;
293*0b4509d2Schristos
294*0b4509d2Schristos if ((pk = es384_pk_new()) == NULL) {
295*0b4509d2Schristos warnx("es384_pk_new");
296*0b4509d2Schristos goto fail;
297*0b4509d2Schristos }
298*0b4509d2Schristos
299*0b4509d2Schristos if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
300*0b4509d2Schristos warnx("es384_pk_from_ptr");
301*0b4509d2Schristos goto fail;
302*0b4509d2Schristos }
303*0b4509d2Schristos
304*0b4509d2Schristos if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
305*0b4509d2Schristos warnx("es384_pk_to_EVP_PKEY");
306*0b4509d2Schristos goto fail;
307*0b4509d2Schristos }
308*0b4509d2Schristos
309*0b4509d2Schristos if (PEM_write_PUBKEY(f, pkey) == 0) {
310*0b4509d2Schristos warnx("PEM_write_PUBKEY");
311*0b4509d2Schristos goto fail;
312*0b4509d2Schristos }
313*0b4509d2Schristos
314*0b4509d2Schristos ok = 0;
315*0b4509d2Schristos fail:
316*0b4509d2Schristos es384_pk_free(&pk);
317*0b4509d2Schristos
318*0b4509d2Schristos if (pkey != NULL) {
319*0b4509d2Schristos EVP_PKEY_free(pkey);
320*0b4509d2Schristos }
321*0b4509d2Schristos
322*0b4509d2Schristos return (ok);
323*0b4509d2Schristos }
324*0b4509d2Schristos
325ba9bdd8bSchristos RSA *
read_rsa_pubkey(const char * path)326ba9bdd8bSchristos read_rsa_pubkey(const char *path)
327ba9bdd8bSchristos {
328ba9bdd8bSchristos FILE *fp = NULL;
329ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
330ba9bdd8bSchristos RSA *rsa = NULL;
331ba9bdd8bSchristos
332ba9bdd8bSchristos if ((fp = fopen(path, "r")) == NULL) {
333ba9bdd8bSchristos warn("fopen");
334ba9bdd8bSchristos goto fail;
335ba9bdd8bSchristos }
336ba9bdd8bSchristos
337ba9bdd8bSchristos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
338ba9bdd8bSchristos warnx("PEM_read_PUBKEY");
339ba9bdd8bSchristos goto fail;
340ba9bdd8bSchristos }
341ba9bdd8bSchristos if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
342ba9bdd8bSchristos warnx("EVP_PKEY_get1_RSA");
343ba9bdd8bSchristos goto fail;
344ba9bdd8bSchristos }
345ba9bdd8bSchristos
346ba9bdd8bSchristos fail:
347ba9bdd8bSchristos if (fp) {
348ba9bdd8bSchristos fclose(fp);
349ba9bdd8bSchristos }
350ba9bdd8bSchristos if (pkey) {
351ba9bdd8bSchristos EVP_PKEY_free(pkey);
352ba9bdd8bSchristos }
353ba9bdd8bSchristos
354ba9bdd8bSchristos return (rsa);
355ba9bdd8bSchristos }
356ba9bdd8bSchristos
357ba9bdd8bSchristos int
write_rsa_pubkey(FILE * f,const void * ptr,size_t len)358ba9bdd8bSchristos write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
359ba9bdd8bSchristos {
360ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
361ba9bdd8bSchristos rs256_pk_t *pk = NULL;
362ba9bdd8bSchristos int ok = -1;
363ba9bdd8bSchristos
364ba9bdd8bSchristos if ((pk = rs256_pk_new()) == NULL) {
365ba9bdd8bSchristos warnx("rs256_pk_new");
366ba9bdd8bSchristos goto fail;
367ba9bdd8bSchristos }
368ba9bdd8bSchristos
369ba9bdd8bSchristos if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
370ba9bdd8bSchristos warnx("rs256_pk_from_ptr");
371ba9bdd8bSchristos goto fail;
372ba9bdd8bSchristos }
373ba9bdd8bSchristos
374ba9bdd8bSchristos if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
375ba9bdd8bSchristos warnx("rs256_pk_to_EVP_PKEY");
376ba9bdd8bSchristos goto fail;
377ba9bdd8bSchristos }
378ba9bdd8bSchristos
379ba9bdd8bSchristos if (PEM_write_PUBKEY(f, pkey) == 0) {
380ba9bdd8bSchristos warnx("PEM_write_PUBKEY");
381ba9bdd8bSchristos goto fail;
382ba9bdd8bSchristos }
383ba9bdd8bSchristos
384ba9bdd8bSchristos ok = 0;
385ba9bdd8bSchristos fail:
386ba9bdd8bSchristos rs256_pk_free(&pk);
387ba9bdd8bSchristos
388ba9bdd8bSchristos if (pkey != NULL) {
389ba9bdd8bSchristos EVP_PKEY_free(pkey);
390ba9bdd8bSchristos }
391ba9bdd8bSchristos
392ba9bdd8bSchristos return (ok);
393ba9bdd8bSchristos }
394ba9bdd8bSchristos
395ba9bdd8bSchristos EVP_PKEY *
read_eddsa_pubkey(const char * path)396ba9bdd8bSchristos read_eddsa_pubkey(const char *path)
397ba9bdd8bSchristos {
398ba9bdd8bSchristos FILE *fp = NULL;
399ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
400ba9bdd8bSchristos
401ba9bdd8bSchristos if ((fp = fopen(path, "r")) == NULL) {
402ba9bdd8bSchristos warn("fopen");
403ba9bdd8bSchristos goto fail;
404ba9bdd8bSchristos }
405ba9bdd8bSchristos
406ba9bdd8bSchristos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
407ba9bdd8bSchristos warnx("PEM_read_PUBKEY");
408ba9bdd8bSchristos goto fail;
409ba9bdd8bSchristos }
410ba9bdd8bSchristos
411ba9bdd8bSchristos fail:
412ba9bdd8bSchristos if (fp) {
413ba9bdd8bSchristos fclose(fp);
414ba9bdd8bSchristos }
415ba9bdd8bSchristos
416ba9bdd8bSchristos return (pkey);
417ba9bdd8bSchristos }
418ba9bdd8bSchristos
419ba9bdd8bSchristos int
write_eddsa_pubkey(FILE * f,const void * ptr,size_t len)420ba9bdd8bSchristos write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
421ba9bdd8bSchristos {
422ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
423ba9bdd8bSchristos eddsa_pk_t *pk = NULL;
424ba9bdd8bSchristos int ok = -1;
425ba9bdd8bSchristos
426ba9bdd8bSchristos if ((pk = eddsa_pk_new()) == NULL) {
427ba9bdd8bSchristos warnx("eddsa_pk_new");
428ba9bdd8bSchristos goto fail;
429ba9bdd8bSchristos }
430ba9bdd8bSchristos
431ba9bdd8bSchristos if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
432ba9bdd8bSchristos warnx("eddsa_pk_from_ptr");
433ba9bdd8bSchristos goto fail;
434ba9bdd8bSchristos }
435ba9bdd8bSchristos
436ba9bdd8bSchristos if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
437ba9bdd8bSchristos warnx("eddsa_pk_to_EVP_PKEY");
438ba9bdd8bSchristos goto fail;
439ba9bdd8bSchristos }
440ba9bdd8bSchristos
441ba9bdd8bSchristos if (PEM_write_PUBKEY(f, pkey) == 0) {
442ba9bdd8bSchristos warnx("PEM_write_PUBKEY");
443ba9bdd8bSchristos goto fail;
444ba9bdd8bSchristos }
445ba9bdd8bSchristos
446ba9bdd8bSchristos ok = 0;
447ba9bdd8bSchristos fail:
448ba9bdd8bSchristos eddsa_pk_free(&pk);
449ba9bdd8bSchristos
450ba9bdd8bSchristos if (pkey != NULL) {
451ba9bdd8bSchristos EVP_PKEY_free(pkey);
452ba9bdd8bSchristos }
453ba9bdd8bSchristos
454ba9bdd8bSchristos return (ok);
455ba9bdd8bSchristos }
456ba9bdd8bSchristos
457ba9bdd8bSchristos void
print_cred(FILE * out_f,int type,const fido_cred_t * cred)458ba9bdd8bSchristos print_cred(FILE *out_f, int type, const fido_cred_t *cred)
459ba9bdd8bSchristos {
460ba9bdd8bSchristos char *id;
461ba9bdd8bSchristos int r;
462ba9bdd8bSchristos
463ba9bdd8bSchristos r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
464ba9bdd8bSchristos if (r < 0)
465ba9bdd8bSchristos errx(1, "output error");
466ba9bdd8bSchristos
467ba9bdd8bSchristos fprintf(out_f, "%s\n", id);
468ba9bdd8bSchristos
469*0b4509d2Schristos switch (type) {
470*0b4509d2Schristos case COSE_ES256:
471*0b4509d2Schristos write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred),
472ba9bdd8bSchristos fido_cred_pubkey_len(cred));
473*0b4509d2Schristos break;
474*0b4509d2Schristos case COSE_ES384:
475*0b4509d2Schristos write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred),
476*0b4509d2Schristos fido_cred_pubkey_len(cred));
477*0b4509d2Schristos break;
478*0b4509d2Schristos case COSE_RS256:
479ba9bdd8bSchristos write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
480ba9bdd8bSchristos fido_cred_pubkey_len(cred));
481*0b4509d2Schristos break;
482*0b4509d2Schristos case COSE_EDDSA:
483ba9bdd8bSchristos write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
484ba9bdd8bSchristos fido_cred_pubkey_len(cred));
485*0b4509d2Schristos break;
486*0b4509d2Schristos default:
487ba9bdd8bSchristos errx(1, "print_cred: unknown type");
488ba9bdd8bSchristos }
489ba9bdd8bSchristos
490ba9bdd8bSchristos free(id);
491ba9bdd8bSchristos }
4921fc1e710Schristos
4931fc1e710Schristos int
cose_type(const char * str,int * type)4941fc1e710Schristos cose_type(const char *str, int *type)
4951fc1e710Schristos {
4961fc1e710Schristos if (strcmp(str, "es256") == 0)
4971fc1e710Schristos *type = COSE_ES256;
498*0b4509d2Schristos else if (strcmp(str, "es384") == 0)
499*0b4509d2Schristos *type = COSE_ES384;
5001fc1e710Schristos else if (strcmp(str, "rs256") == 0)
5011fc1e710Schristos *type = COSE_RS256;
5021fc1e710Schristos else if (strcmp(str, "eddsa") == 0)
5031fc1e710Schristos *type = COSE_EDDSA;
5041fc1e710Schristos else {
5051fc1e710Schristos *type = 0;
5061fc1e710Schristos return (-1);
5071fc1e710Schristos }
5081fc1e710Schristos
5091fc1e710Schristos return (0);
5101fc1e710Schristos }
5111fc1e710Schristos
5121fc1e710Schristos const char *
cose_string(int type)5131fc1e710Schristos cose_string(int type)
5141fc1e710Schristos {
5151fc1e710Schristos switch (type) {
5161fc1e710Schristos case COSE_ES256:
5171fc1e710Schristos return ("es256");
518*0b4509d2Schristos case COSE_ES384:
519*0b4509d2Schristos return ("es384");
5201fc1e710Schristos case COSE_RS256:
5211fc1e710Schristos return ("rs256");
522*0b4509d2Schristos case COSE_EDDSA:
523*0b4509d2Schristos return ("eddsa");
5241fc1e710Schristos default:
5251fc1e710Schristos return ("unknown");
5261fc1e710Schristos }
5271fc1e710Schristos }
5281fc1e710Schristos
5291fc1e710Schristos const char *
prot_string(int prot)5301fc1e710Schristos prot_string(int prot)
5311fc1e710Schristos {
5321fc1e710Schristos switch (prot) {
5331fc1e710Schristos case FIDO_CRED_PROT_UV_OPTIONAL:
5341fc1e710Schristos return ("uvopt");
5351fc1e710Schristos case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
5361fc1e710Schristos return ("uvopt+id");
5371fc1e710Schristos case FIDO_CRED_PROT_UV_REQUIRED:
5381fc1e710Schristos return ("uvreq");
5391fc1e710Schristos default:
5401fc1e710Schristos return ("unknown");
5411fc1e710Schristos }
5421fc1e710Schristos }
54395dbdf32Schristos
54495dbdf32Schristos int
read_file(const char * path,u_char ** ptr,size_t * len)54595dbdf32Schristos read_file(const char *path, u_char **ptr, size_t *len)
54695dbdf32Schristos {
54795dbdf32Schristos int fd, ok = -1;
54895dbdf32Schristos struct stat st;
54995dbdf32Schristos ssize_t n;
55095dbdf32Schristos
55195dbdf32Schristos *ptr = NULL;
55295dbdf32Schristos *len = 0;
55395dbdf32Schristos
55495dbdf32Schristos if ((fd = open(path, O_RDONLY)) < 0) {
55595dbdf32Schristos warn("%s: open %s", __func__, path);
55695dbdf32Schristos goto fail;
55795dbdf32Schristos }
55895dbdf32Schristos if (fstat(fd, &st) < 0) {
55995dbdf32Schristos warn("%s: stat %s", __func__, path);
56095dbdf32Schristos goto fail;
56195dbdf32Schristos }
56295dbdf32Schristos if (st.st_size < 0) {
56395dbdf32Schristos warnx("%s: stat %s: invalid size", __func__, path);
56495dbdf32Schristos goto fail;
56595dbdf32Schristos }
56695dbdf32Schristos *len = (size_t)st.st_size;
56795dbdf32Schristos if ((*ptr = malloc(*len)) == NULL) {
56895dbdf32Schristos warn("%s: malloc", __func__);
56995dbdf32Schristos goto fail;
57095dbdf32Schristos }
57195dbdf32Schristos if ((n = read(fd, *ptr, *len)) < 0) {
57295dbdf32Schristos warn("%s: read", __func__);
57395dbdf32Schristos goto fail;
57495dbdf32Schristos }
57595dbdf32Schristos if ((size_t)n != *len) {
57695dbdf32Schristos warnx("%s: read", __func__);
57795dbdf32Schristos goto fail;
57895dbdf32Schristos }
57995dbdf32Schristos
58095dbdf32Schristos ok = 0;
58195dbdf32Schristos fail:
58295dbdf32Schristos if (fd != -1) {
58395dbdf32Schristos close(fd);
58495dbdf32Schristos }
58595dbdf32Schristos if (ok < 0) {
58695dbdf32Schristos free(*ptr);
58795dbdf32Schristos *ptr = NULL;
58895dbdf32Schristos *len = 0;
58995dbdf32Schristos }
59095dbdf32Schristos
59195dbdf32Schristos return ok;
59295dbdf32Schristos }
59395dbdf32Schristos
59495dbdf32Schristos int
write_file(const char * path,const u_char * ptr,size_t len)59595dbdf32Schristos write_file(const char *path, const u_char *ptr, size_t len)
59695dbdf32Schristos {
59795dbdf32Schristos int fd, ok = -1;
59895dbdf32Schristos ssize_t n;
59995dbdf32Schristos
60095dbdf32Schristos if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
60195dbdf32Schristos warn("%s: open %s", __func__, path);
60295dbdf32Schristos goto fail;
60395dbdf32Schristos }
60495dbdf32Schristos if ((n = write(fd, ptr, len)) < 0) {
60595dbdf32Schristos warn("%s: write", __func__);
60695dbdf32Schristos goto fail;
60795dbdf32Schristos }
60895dbdf32Schristos if ((size_t)n != len) {
60995dbdf32Schristos warnx("%s: write", __func__);
61095dbdf32Schristos goto fail;
61195dbdf32Schristos }
61295dbdf32Schristos
61395dbdf32Schristos ok = 0;
61495dbdf32Schristos fail:
61595dbdf32Schristos if (fd != -1) {
61695dbdf32Schristos close(fd);
61795dbdf32Schristos }
61895dbdf32Schristos
61995dbdf32Schristos return ok;
62095dbdf32Schristos }
62195dbdf32Schristos
62295dbdf32Schristos const char *
plural(size_t x)62395dbdf32Schristos plural(size_t x)
62495dbdf32Schristos {
62595dbdf32Schristos return x == 1 ? "" : "s";
62695dbdf32Schristos }
62795dbdf32Schristos
62895dbdf32Schristos int
should_retry_with_pin(const fido_dev_t * dev,int r)62995dbdf32Schristos should_retry_with_pin(const fido_dev_t *dev, int r)
63095dbdf32Schristos {
6314bc1579dSchristos if (fido_dev_has_pin(dev) == false) {
6324bc1579dSchristos return 0;
6334bc1579dSchristos }
6344bc1579dSchristos
6354bc1579dSchristos switch (r) {
6364bc1579dSchristos case FIDO_ERR_PIN_REQUIRED:
6374bc1579dSchristos case FIDO_ERR_UNAUTHORIZED_PERM:
6384bc1579dSchristos case FIDO_ERR_UV_BLOCKED:
6394bc1579dSchristos case FIDO_ERR_UV_INVALID:
6404bc1579dSchristos return 1;
6414bc1579dSchristos }
6424bc1579dSchristos
6434bc1579dSchristos return 0;
64495dbdf32Schristos }
645