xref: /netbsd-src/external/bsd/libfido2/dist/tools/util.c (revision 0b4509d2c94d0dbe3be5de7df91101c4f0e235d6)
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