xref: /freebsd/contrib/libfido2/tools/util.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <sys/types.h>
90afa8e06SEd Maste #include <sys/stat.h>
100afa8e06SEd Maste 
110afa8e06SEd Maste #include <openssl/ec.h>
120afa8e06SEd Maste #include <openssl/evp.h>
130afa8e06SEd Maste #include <openssl/pem.h>
140afa8e06SEd Maste 
150afa8e06SEd Maste #include <fido.h>
160afa8e06SEd Maste #include <fido/es256.h>
17*2ccfa855SEd Maste #include <fido/es384.h>
180afa8e06SEd Maste #include <fido/rs256.h>
190afa8e06SEd Maste #include <fido/eddsa.h>
200afa8e06SEd Maste 
210afa8e06SEd Maste #include <errno.h>
220afa8e06SEd Maste #include <fcntl.h>
230afa8e06SEd Maste #include <limits.h>
240afa8e06SEd Maste #include <stdbool.h>
250afa8e06SEd Maste #include <stdint.h>
260afa8e06SEd Maste #include <stdio.h>
270afa8e06SEd Maste #include <stdlib.h>
280afa8e06SEd Maste #include <string.h>
290afa8e06SEd Maste 
300afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
310afa8e06SEd Maste #ifdef _MSC_VER
320afa8e06SEd Maste #include "../openbsd-compat/posix_win.h"
330afa8e06SEd Maste #endif
340afa8e06SEd Maste 
350afa8e06SEd Maste #include "extern.h"
360afa8e06SEd Maste 
370afa8e06SEd Maste char *
get_pin(const char * path)380afa8e06SEd Maste get_pin(const char *path)
390afa8e06SEd Maste {
400afa8e06SEd Maste 	char *pin;
410afa8e06SEd Maste 	char prompt[1024];
420afa8e06SEd Maste 	int r, ok = -1;
430afa8e06SEd Maste 
440afa8e06SEd Maste 	if ((pin = calloc(1, PINBUF_LEN)) == NULL) {
450afa8e06SEd Maste 		warn("%s: calloc", __func__);
460afa8e06SEd Maste 		return NULL;
470afa8e06SEd Maste 	}
480afa8e06SEd Maste 	if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
490afa8e06SEd Maste 	    path)) < 0 || (size_t)r >= sizeof(prompt)) {
500afa8e06SEd Maste 		warn("%s: snprintf", __func__);
510afa8e06SEd Maste 		goto out;
520afa8e06SEd Maste 	}
530afa8e06SEd Maste 	if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) {
540afa8e06SEd Maste 		warnx("%s: readpassphrase", __func__);
550afa8e06SEd Maste 		goto out;
560afa8e06SEd Maste 	}
570afa8e06SEd Maste 
580afa8e06SEd Maste 	ok = 0;
590afa8e06SEd Maste out:
600afa8e06SEd Maste 	if (ok < 0) {
610afa8e06SEd Maste 		freezero(pin, PINBUF_LEN);
620afa8e06SEd Maste 		pin = NULL;
630afa8e06SEd Maste 	}
640afa8e06SEd Maste 
650afa8e06SEd Maste 	return pin;
660afa8e06SEd Maste }
670afa8e06SEd Maste 
680afa8e06SEd Maste FILE *
open_write(const char * file)690afa8e06SEd Maste open_write(const char *file)
700afa8e06SEd Maste {
710afa8e06SEd Maste 	int fd;
720afa8e06SEd Maste 	FILE *f;
730afa8e06SEd Maste 
740afa8e06SEd Maste 	if (file == NULL || strcmp(file, "-") == 0)
750afa8e06SEd Maste 		return (stdout);
760afa8e06SEd Maste 	if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
770afa8e06SEd Maste 		err(1, "open %s", file);
780afa8e06SEd Maste 	if ((f = fdopen(fd, "w")) == NULL)
790afa8e06SEd Maste 		err(1, "fdopen %s", file);
800afa8e06SEd Maste 
810afa8e06SEd Maste 	return (f);
820afa8e06SEd Maste }
830afa8e06SEd Maste 
840afa8e06SEd Maste FILE *
open_read(const char * file)850afa8e06SEd Maste open_read(const char *file)
860afa8e06SEd Maste {
870afa8e06SEd Maste 	int fd;
880afa8e06SEd Maste 	FILE *f;
890afa8e06SEd Maste 
900afa8e06SEd Maste 	if (file == NULL || strcmp(file, "-") == 0) {
910afa8e06SEd Maste #ifdef FIDO_FUZZ
920afa8e06SEd Maste 		setvbuf(stdin, NULL, _IONBF, 0);
930afa8e06SEd Maste #endif
940afa8e06SEd Maste 		return (stdin);
950afa8e06SEd Maste 	}
960afa8e06SEd Maste 	if ((fd = open(file, O_RDONLY)) < 0)
970afa8e06SEd Maste 		err(1, "open %s", file);
980afa8e06SEd Maste 	if ((f = fdopen(fd, "r")) == NULL)
990afa8e06SEd Maste 		err(1, "fdopen %s", file);
1000afa8e06SEd Maste 
1010afa8e06SEd Maste 	return (f);
1020afa8e06SEd Maste }
1030afa8e06SEd Maste 
1040afa8e06SEd Maste int
base10(const char * str)1050afa8e06SEd Maste base10(const char *str)
1060afa8e06SEd Maste {
1070afa8e06SEd Maste 	char *ep;
1080afa8e06SEd Maste 	long long ll;
1090afa8e06SEd Maste 
1100afa8e06SEd Maste 	ll = strtoll(str, &ep, 10);
1110afa8e06SEd Maste 	if (str == ep || *ep != '\0')
1120afa8e06SEd Maste 		return (-1);
1130afa8e06SEd Maste 	else if (ll == LLONG_MIN && errno == ERANGE)
1140afa8e06SEd Maste 		return (-1);
1150afa8e06SEd Maste 	else if (ll == LLONG_MAX && errno == ERANGE)
1160afa8e06SEd Maste 		return (-1);
1170afa8e06SEd Maste 	else if (ll < 0 || ll > INT_MAX)
1180afa8e06SEd Maste 		return (-1);
1190afa8e06SEd Maste 
1200afa8e06SEd Maste 	return ((int)ll);
1210afa8e06SEd Maste }
1220afa8e06SEd Maste 
1230afa8e06SEd Maste void
xxd(const void * buf,size_t count)1240afa8e06SEd Maste xxd(const void *buf, size_t count)
1250afa8e06SEd Maste {
1260afa8e06SEd Maste 	const uint8_t	*ptr = buf;
1270afa8e06SEd Maste 	size_t		 i;
1280afa8e06SEd Maste 
1290afa8e06SEd Maste 	fprintf(stderr, "  ");
1300afa8e06SEd Maste 
1310afa8e06SEd Maste 	for (i = 0; i < count; i++) {
1320afa8e06SEd Maste 		fprintf(stderr, "%02x ", *ptr++);
1330afa8e06SEd Maste 		if ((i + 1) % 16 == 0 && i + 1 < count)
1340afa8e06SEd Maste 			fprintf(stderr, "\n  ");
1350afa8e06SEd Maste 	}
1360afa8e06SEd Maste 
1370afa8e06SEd Maste 	fprintf(stderr, "\n");
1380afa8e06SEd Maste 	fflush(stderr);
1390afa8e06SEd Maste }
1400afa8e06SEd Maste 
1410afa8e06SEd Maste int
string_read(FILE * f,char ** out)1420afa8e06SEd Maste string_read(FILE *f, char **out)
1430afa8e06SEd Maste {
1440afa8e06SEd Maste 	char *line = NULL;
1450afa8e06SEd Maste 	size_t linesize = 0;
1460afa8e06SEd Maste 	ssize_t n;
1470afa8e06SEd Maste 
1480afa8e06SEd Maste 	*out = NULL;
1490afa8e06SEd Maste 
1500afa8e06SEd Maste 	if ((n = getline(&line, &linesize, f)) <= 0 ||
1510afa8e06SEd Maste 	    (size_t)n != strlen(line)) {
1520afa8e06SEd Maste 		free(line);
1530afa8e06SEd Maste 		return (-1);
1540afa8e06SEd Maste 	}
1550afa8e06SEd Maste 
1560afa8e06SEd Maste 	line[n - 1] = '\0'; /* trim \n */
1570afa8e06SEd Maste 	*out = line;
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	return (0);
1600afa8e06SEd Maste }
1610afa8e06SEd Maste 
1620afa8e06SEd Maste fido_dev_t *
open_dev(const char * path)1630afa8e06SEd Maste open_dev(const char *path)
1640afa8e06SEd Maste {
1650afa8e06SEd Maste 	fido_dev_t *dev;
1660afa8e06SEd Maste 	int r;
1670afa8e06SEd Maste 
1680afa8e06SEd Maste 	if ((dev = fido_dev_new()) == NULL)
1690afa8e06SEd Maste 		errx(1, "fido_dev_new");
1700afa8e06SEd Maste 
1710afa8e06SEd Maste 	r = fido_dev_open(dev, path);
1720afa8e06SEd Maste 	if (r != FIDO_OK)
1730afa8e06SEd Maste 		errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
1740afa8e06SEd Maste 
1750afa8e06SEd Maste 	return (dev);
1760afa8e06SEd Maste }
1770afa8e06SEd Maste 
1780afa8e06SEd Maste int
get_devopt(fido_dev_t * dev,const char * name,int * val)1790afa8e06SEd Maste get_devopt(fido_dev_t *dev, const char *name, int *val)
1800afa8e06SEd Maste {
1810afa8e06SEd Maste 	fido_cbor_info_t *cbor_info;
1820afa8e06SEd Maste 	char * const *names;
1830afa8e06SEd Maste 	const bool *values;
1840afa8e06SEd Maste 	int r, ok = -1;
1850afa8e06SEd Maste 
1860afa8e06SEd Maste 	if ((cbor_info = fido_cbor_info_new()) == NULL) {
1870afa8e06SEd Maste 		warnx("fido_cbor_info_new");
1880afa8e06SEd Maste 		goto out;
1890afa8e06SEd Maste 	}
1900afa8e06SEd Maste 
1910afa8e06SEd Maste 	if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) {
1920afa8e06SEd Maste 		warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
1930afa8e06SEd Maste 		goto out;
1940afa8e06SEd Maste 	}
1950afa8e06SEd Maste 
1960afa8e06SEd Maste 	if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL ||
1970afa8e06SEd Maste 	    (values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) {
1980afa8e06SEd Maste 		warnx("fido_dev_get_cbor_info: NULL name/value pointer");
1990afa8e06SEd Maste 		goto out;
2000afa8e06SEd Maste 	}
2010afa8e06SEd Maste 
2020afa8e06SEd Maste 	*val = -1;
2030afa8e06SEd Maste 	for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++)
2040afa8e06SEd Maste 		if (strcmp(names[i], name) == 0) {
2050afa8e06SEd Maste 			*val = values[i];
2060afa8e06SEd Maste 			break;
2070afa8e06SEd Maste 		}
2080afa8e06SEd Maste 
2090afa8e06SEd Maste 	ok = 0;
2100afa8e06SEd Maste out:
2110afa8e06SEd Maste 	fido_cbor_info_free(&cbor_info);
2120afa8e06SEd Maste 
2130afa8e06SEd Maste 	return (ok);
2140afa8e06SEd Maste }
2150afa8e06SEd Maste 
2160afa8e06SEd Maste EC_KEY *
read_ec_pubkey(const char * path)2170afa8e06SEd Maste read_ec_pubkey(const char *path)
2180afa8e06SEd Maste {
2190afa8e06SEd Maste 	FILE *fp = NULL;
2200afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
2210afa8e06SEd Maste 	EC_KEY *ec = NULL;
2220afa8e06SEd Maste 
2230afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
2240afa8e06SEd Maste 		warn("fopen");
2250afa8e06SEd Maste 		goto fail;
2260afa8e06SEd Maste 	}
2270afa8e06SEd Maste 
2280afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
2290afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
2300afa8e06SEd Maste 		goto fail;
2310afa8e06SEd Maste 	}
2320afa8e06SEd Maste 	if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
2330afa8e06SEd Maste 		warnx("EVP_PKEY_get1_EC_KEY");
2340afa8e06SEd Maste 		goto fail;
2350afa8e06SEd Maste 	}
2360afa8e06SEd Maste 
2370afa8e06SEd Maste fail:
2380afa8e06SEd Maste 	if (fp) {
2390afa8e06SEd Maste 		fclose(fp);
2400afa8e06SEd Maste 	}
2410afa8e06SEd Maste 	if (pkey) {
2420afa8e06SEd Maste 		EVP_PKEY_free(pkey);
2430afa8e06SEd Maste 	}
2440afa8e06SEd Maste 
2450afa8e06SEd Maste 	return (ec);
2460afa8e06SEd Maste }
2470afa8e06SEd Maste 
2480afa8e06SEd Maste int
write_es256_pubkey(FILE * f,const void * ptr,size_t len)249*2ccfa855SEd Maste write_es256_pubkey(FILE *f, const void *ptr, size_t len)
2500afa8e06SEd Maste {
2510afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
2520afa8e06SEd Maste 	es256_pk_t *pk = NULL;
2530afa8e06SEd Maste 	int ok = -1;
2540afa8e06SEd Maste 
2550afa8e06SEd Maste 	if ((pk = es256_pk_new()) == NULL) {
2560afa8e06SEd Maste 		warnx("es256_pk_new");
2570afa8e06SEd Maste 		goto fail;
2580afa8e06SEd Maste 	}
2590afa8e06SEd Maste 
2600afa8e06SEd Maste 	if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
2610afa8e06SEd Maste 		warnx("es256_pk_from_ptr");
2620afa8e06SEd Maste 		goto fail;
2630afa8e06SEd Maste 	}
2640afa8e06SEd Maste 
2650afa8e06SEd Maste 	if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
2660afa8e06SEd Maste 		warnx("es256_pk_to_EVP_PKEY");
2670afa8e06SEd Maste 		goto fail;
2680afa8e06SEd Maste 	}
2690afa8e06SEd Maste 
2700afa8e06SEd Maste 	if (PEM_write_PUBKEY(f, pkey) == 0) {
2710afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
2720afa8e06SEd Maste 		goto fail;
2730afa8e06SEd Maste 	}
2740afa8e06SEd Maste 
2750afa8e06SEd Maste 	ok = 0;
2760afa8e06SEd Maste fail:
2770afa8e06SEd Maste 	es256_pk_free(&pk);
2780afa8e06SEd Maste 
2790afa8e06SEd Maste 	if (pkey != NULL) {
2800afa8e06SEd Maste 		EVP_PKEY_free(pkey);
2810afa8e06SEd Maste 	}
2820afa8e06SEd Maste 
2830afa8e06SEd Maste 	return (ok);
2840afa8e06SEd Maste }
2850afa8e06SEd Maste 
286*2ccfa855SEd Maste int
write_es384_pubkey(FILE * f,const void * ptr,size_t len)287*2ccfa855SEd Maste write_es384_pubkey(FILE *f, const void *ptr, size_t len)
288*2ccfa855SEd Maste {
289*2ccfa855SEd Maste 	EVP_PKEY *pkey = NULL;
290*2ccfa855SEd Maste 	es384_pk_t *pk = NULL;
291*2ccfa855SEd Maste 	int ok = -1;
292*2ccfa855SEd Maste 
293*2ccfa855SEd Maste 	if ((pk = es384_pk_new()) == NULL) {
294*2ccfa855SEd Maste 		warnx("es384_pk_new");
295*2ccfa855SEd Maste 		goto fail;
296*2ccfa855SEd Maste 	}
297*2ccfa855SEd Maste 
298*2ccfa855SEd Maste 	if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
299*2ccfa855SEd Maste 		warnx("es384_pk_from_ptr");
300*2ccfa855SEd Maste 		goto fail;
301*2ccfa855SEd Maste 	}
302*2ccfa855SEd Maste 
303*2ccfa855SEd Maste 	if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
304*2ccfa855SEd Maste 		warnx("es384_pk_to_EVP_PKEY");
305*2ccfa855SEd Maste 		goto fail;
306*2ccfa855SEd Maste 	}
307*2ccfa855SEd Maste 
308*2ccfa855SEd Maste 	if (PEM_write_PUBKEY(f, pkey) == 0) {
309*2ccfa855SEd Maste 		warnx("PEM_write_PUBKEY");
310*2ccfa855SEd Maste 		goto fail;
311*2ccfa855SEd Maste 	}
312*2ccfa855SEd Maste 
313*2ccfa855SEd Maste 	ok = 0;
314*2ccfa855SEd Maste fail:
315*2ccfa855SEd Maste 	es384_pk_free(&pk);
316*2ccfa855SEd Maste 
317*2ccfa855SEd Maste 	if (pkey != NULL) {
318*2ccfa855SEd Maste 		EVP_PKEY_free(pkey);
319*2ccfa855SEd Maste 	}
320*2ccfa855SEd Maste 
321*2ccfa855SEd Maste 	return (ok);
322*2ccfa855SEd Maste }
323*2ccfa855SEd Maste 
3240afa8e06SEd Maste RSA *
read_rsa_pubkey(const char * path)3250afa8e06SEd Maste read_rsa_pubkey(const char *path)
3260afa8e06SEd Maste {
3270afa8e06SEd Maste 	FILE *fp = NULL;
3280afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3290afa8e06SEd Maste 	RSA *rsa = NULL;
3300afa8e06SEd Maste 
3310afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
3320afa8e06SEd Maste 		warn("fopen");
3330afa8e06SEd Maste 		goto fail;
3340afa8e06SEd Maste 	}
3350afa8e06SEd Maste 
3360afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
3370afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
3380afa8e06SEd Maste 		goto fail;
3390afa8e06SEd Maste 	}
3400afa8e06SEd Maste 	if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
3410afa8e06SEd Maste 		warnx("EVP_PKEY_get1_RSA");
3420afa8e06SEd Maste 		goto fail;
3430afa8e06SEd Maste 	}
3440afa8e06SEd Maste 
3450afa8e06SEd Maste fail:
3460afa8e06SEd Maste 	if (fp) {
3470afa8e06SEd Maste 		fclose(fp);
3480afa8e06SEd Maste 	}
3490afa8e06SEd Maste 	if (pkey) {
3500afa8e06SEd Maste 		EVP_PKEY_free(pkey);
3510afa8e06SEd Maste 	}
3520afa8e06SEd Maste 
3530afa8e06SEd Maste 	return (rsa);
3540afa8e06SEd Maste }
3550afa8e06SEd Maste 
3560afa8e06SEd Maste int
write_rsa_pubkey(FILE * f,const void * ptr,size_t len)3570afa8e06SEd Maste write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
3580afa8e06SEd Maste {
3590afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3600afa8e06SEd Maste 	rs256_pk_t *pk = NULL;
3610afa8e06SEd Maste 	int ok = -1;
3620afa8e06SEd Maste 
3630afa8e06SEd Maste 	if ((pk = rs256_pk_new()) == NULL) {
3640afa8e06SEd Maste 		warnx("rs256_pk_new");
3650afa8e06SEd Maste 		goto fail;
3660afa8e06SEd Maste 	}
3670afa8e06SEd Maste 
3680afa8e06SEd Maste 	if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
3690afa8e06SEd Maste 		warnx("rs256_pk_from_ptr");
3700afa8e06SEd Maste 		goto fail;
3710afa8e06SEd Maste 	}
3720afa8e06SEd Maste 
3730afa8e06SEd Maste 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
3740afa8e06SEd Maste 		warnx("rs256_pk_to_EVP_PKEY");
3750afa8e06SEd Maste 		goto fail;
3760afa8e06SEd Maste 	}
3770afa8e06SEd Maste 
3780afa8e06SEd Maste 	if (PEM_write_PUBKEY(f, pkey) == 0) {
3790afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
3800afa8e06SEd Maste 		goto fail;
3810afa8e06SEd Maste 	}
3820afa8e06SEd Maste 
3830afa8e06SEd Maste 	ok = 0;
3840afa8e06SEd Maste fail:
3850afa8e06SEd Maste 	rs256_pk_free(&pk);
3860afa8e06SEd Maste 
3870afa8e06SEd Maste 	if (pkey != NULL) {
3880afa8e06SEd Maste 		EVP_PKEY_free(pkey);
3890afa8e06SEd Maste 	}
3900afa8e06SEd Maste 
3910afa8e06SEd Maste 	return (ok);
3920afa8e06SEd Maste }
3930afa8e06SEd Maste 
3940afa8e06SEd Maste EVP_PKEY *
read_eddsa_pubkey(const char * path)3950afa8e06SEd Maste read_eddsa_pubkey(const char *path)
3960afa8e06SEd Maste {
3970afa8e06SEd Maste 	FILE *fp = NULL;
3980afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3990afa8e06SEd Maste 
4000afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
4010afa8e06SEd Maste 		warn("fopen");
4020afa8e06SEd Maste 		goto fail;
4030afa8e06SEd Maste 	}
4040afa8e06SEd Maste 
4050afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
4060afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
4070afa8e06SEd Maste 		goto fail;
4080afa8e06SEd Maste 	}
4090afa8e06SEd Maste 
4100afa8e06SEd Maste fail:
4110afa8e06SEd Maste 	if (fp) {
4120afa8e06SEd Maste 		fclose(fp);
4130afa8e06SEd Maste 	}
4140afa8e06SEd Maste 
4150afa8e06SEd Maste 	return (pkey);
4160afa8e06SEd Maste }
4170afa8e06SEd Maste 
4180afa8e06SEd Maste int
write_eddsa_pubkey(FILE * f,const void * ptr,size_t len)4190afa8e06SEd Maste write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
4200afa8e06SEd Maste {
4210afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
4220afa8e06SEd Maste 	eddsa_pk_t *pk = NULL;
4230afa8e06SEd Maste 	int ok = -1;
4240afa8e06SEd Maste 
4250afa8e06SEd Maste 	if ((pk = eddsa_pk_new()) == NULL) {
4260afa8e06SEd Maste 		warnx("eddsa_pk_new");
4270afa8e06SEd Maste 		goto fail;
4280afa8e06SEd Maste 	}
4290afa8e06SEd Maste 
4300afa8e06SEd Maste 	if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
4310afa8e06SEd Maste 		warnx("eddsa_pk_from_ptr");
4320afa8e06SEd Maste 		goto fail;
4330afa8e06SEd Maste 	}
4340afa8e06SEd Maste 
4350afa8e06SEd Maste 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
4360afa8e06SEd Maste 		warnx("eddsa_pk_to_EVP_PKEY");
4370afa8e06SEd Maste 		goto fail;
4380afa8e06SEd Maste 	}
4390afa8e06SEd Maste 
4400afa8e06SEd Maste 	if (PEM_write_PUBKEY(f, pkey) == 0) {
4410afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
4420afa8e06SEd Maste 		goto fail;
4430afa8e06SEd Maste 	}
4440afa8e06SEd Maste 
4450afa8e06SEd Maste 	ok = 0;
4460afa8e06SEd Maste fail:
4470afa8e06SEd Maste 	eddsa_pk_free(&pk);
4480afa8e06SEd Maste 
4490afa8e06SEd Maste 	if (pkey != NULL) {
4500afa8e06SEd Maste 		EVP_PKEY_free(pkey);
4510afa8e06SEd Maste 	}
4520afa8e06SEd Maste 
4530afa8e06SEd Maste 	return (ok);
4540afa8e06SEd Maste }
4550afa8e06SEd Maste 
4560afa8e06SEd Maste void
print_cred(FILE * out_f,int type,const fido_cred_t * cred)4570afa8e06SEd Maste print_cred(FILE *out_f, int type, const fido_cred_t *cred)
4580afa8e06SEd Maste {
4590afa8e06SEd Maste 	char *id;
4600afa8e06SEd Maste 	int r;
4610afa8e06SEd Maste 
4620afa8e06SEd Maste 	r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
4630afa8e06SEd Maste 	if (r < 0)
4640afa8e06SEd Maste 		errx(1, "output error");
4650afa8e06SEd Maste 
4660afa8e06SEd Maste 	fprintf(out_f, "%s\n", id);
4670afa8e06SEd Maste 
468*2ccfa855SEd Maste 	switch (type) {
469*2ccfa855SEd Maste 	case COSE_ES256:
470*2ccfa855SEd Maste 		write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred),
4710afa8e06SEd Maste 		    fido_cred_pubkey_len(cred));
472*2ccfa855SEd Maste 		break;
473*2ccfa855SEd Maste 	case COSE_ES384:
474*2ccfa855SEd Maste 		write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred),
475*2ccfa855SEd Maste 		    fido_cred_pubkey_len(cred));
476*2ccfa855SEd Maste 		break;
477*2ccfa855SEd Maste 	case COSE_RS256:
4780afa8e06SEd Maste 		write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
4790afa8e06SEd Maste 		    fido_cred_pubkey_len(cred));
480*2ccfa855SEd Maste 		break;
481*2ccfa855SEd Maste 	case COSE_EDDSA:
4820afa8e06SEd Maste 		write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
4830afa8e06SEd Maste 		    fido_cred_pubkey_len(cred));
484*2ccfa855SEd Maste 		break;
485*2ccfa855SEd Maste 	default:
4860afa8e06SEd Maste 		errx(1, "print_cred: unknown type");
4870afa8e06SEd Maste 	}
4880afa8e06SEd Maste 
4890afa8e06SEd Maste 	free(id);
4900afa8e06SEd Maste }
4910afa8e06SEd Maste 
4920afa8e06SEd Maste int
cose_type(const char * str,int * type)4930afa8e06SEd Maste cose_type(const char *str, int *type)
4940afa8e06SEd Maste {
4950afa8e06SEd Maste 	if (strcmp(str, "es256") == 0)
4960afa8e06SEd Maste 		*type = COSE_ES256;
497*2ccfa855SEd Maste 	else if (strcmp(str, "es384") == 0)
498*2ccfa855SEd Maste 		*type = COSE_ES384;
4990afa8e06SEd Maste 	else if (strcmp(str, "rs256") == 0)
5000afa8e06SEd Maste 		*type = COSE_RS256;
5010afa8e06SEd Maste 	else if (strcmp(str, "eddsa") == 0)
5020afa8e06SEd Maste 		*type = COSE_EDDSA;
5030afa8e06SEd Maste 	else {
5040afa8e06SEd Maste 		*type = 0;
5050afa8e06SEd Maste 		return (-1);
5060afa8e06SEd Maste 	}
5070afa8e06SEd Maste 
5080afa8e06SEd Maste 	return (0);
5090afa8e06SEd Maste }
5100afa8e06SEd Maste 
5110afa8e06SEd Maste const char *
cose_string(int type)5120afa8e06SEd Maste cose_string(int type)
5130afa8e06SEd Maste {
5140afa8e06SEd Maste 	switch (type) {
5150afa8e06SEd Maste 	case COSE_ES256:
5160afa8e06SEd Maste 		return ("es256");
517*2ccfa855SEd Maste 	case COSE_ES384:
518*2ccfa855SEd Maste 		return ("es384");
5190afa8e06SEd Maste 	case COSE_RS256:
5200afa8e06SEd Maste 		return ("rs256");
521*2ccfa855SEd Maste 	case COSE_EDDSA:
522*2ccfa855SEd Maste 		return ("eddsa");
5230afa8e06SEd Maste 	default:
5240afa8e06SEd Maste 		return ("unknown");
5250afa8e06SEd Maste 	}
5260afa8e06SEd Maste }
5270afa8e06SEd Maste 
5280afa8e06SEd Maste const char *
prot_string(int prot)5290afa8e06SEd Maste prot_string(int prot)
5300afa8e06SEd Maste {
5310afa8e06SEd Maste 	switch (prot) {
5320afa8e06SEd Maste 	case FIDO_CRED_PROT_UV_OPTIONAL:
5330afa8e06SEd Maste 		return ("uvopt");
5340afa8e06SEd Maste 	case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
5350afa8e06SEd Maste 		return ("uvopt+id");
5360afa8e06SEd Maste 	case FIDO_CRED_PROT_UV_REQUIRED:
5370afa8e06SEd Maste 		return ("uvreq");
5380afa8e06SEd Maste 	default:
5390afa8e06SEd Maste 		return ("unknown");
5400afa8e06SEd Maste 	}
5410afa8e06SEd Maste }
5420afa8e06SEd Maste 
5430afa8e06SEd Maste int
read_file(const char * path,u_char ** ptr,size_t * len)5440afa8e06SEd Maste read_file(const char *path, u_char **ptr, size_t *len)
5450afa8e06SEd Maste {
5460afa8e06SEd Maste 	int fd, ok = -1;
5470afa8e06SEd Maste 	struct stat st;
5480afa8e06SEd Maste 	ssize_t n;
5490afa8e06SEd Maste 
5500afa8e06SEd Maste 	*ptr = NULL;
5510afa8e06SEd Maste 	*len = 0;
5520afa8e06SEd Maste 
5530afa8e06SEd Maste 	if ((fd = open(path, O_RDONLY)) < 0) {
5540afa8e06SEd Maste 		warn("%s: open %s", __func__, path);
5550afa8e06SEd Maste 		goto fail;
5560afa8e06SEd Maste 	}
5570afa8e06SEd Maste 	if (fstat(fd, &st) < 0) {
5580afa8e06SEd Maste 		warn("%s: stat %s", __func__, path);
5590afa8e06SEd Maste 		goto fail;
5600afa8e06SEd Maste 	}
5610afa8e06SEd Maste 	if (st.st_size < 0) {
5620afa8e06SEd Maste 		warnx("%s: stat %s: invalid size", __func__, path);
5630afa8e06SEd Maste 		goto fail;
5640afa8e06SEd Maste 	}
5650afa8e06SEd Maste 	*len = (size_t)st.st_size;
5660afa8e06SEd Maste 	if ((*ptr = malloc(*len)) == NULL) {
5670afa8e06SEd Maste 		warn("%s: malloc", __func__);
5680afa8e06SEd Maste 		goto fail;
5690afa8e06SEd Maste 	}
5700afa8e06SEd Maste 	if ((n = read(fd, *ptr, *len)) < 0) {
5710afa8e06SEd Maste 		warn("%s: read", __func__);
5720afa8e06SEd Maste 		goto fail;
5730afa8e06SEd Maste 	}
5740afa8e06SEd Maste 	if ((size_t)n != *len) {
5750afa8e06SEd Maste 		warnx("%s: read", __func__);
5760afa8e06SEd Maste 		goto fail;
5770afa8e06SEd Maste 	}
5780afa8e06SEd Maste 
5790afa8e06SEd Maste 	ok = 0;
5800afa8e06SEd Maste fail:
5810afa8e06SEd Maste 	if (fd != -1) {
5820afa8e06SEd Maste 		close(fd);
5830afa8e06SEd Maste 	}
5840afa8e06SEd Maste 	if (ok < 0) {
5850afa8e06SEd Maste 		free(*ptr);
5860afa8e06SEd Maste 		*ptr = NULL;
5870afa8e06SEd Maste 		*len = 0;
5880afa8e06SEd Maste 	}
5890afa8e06SEd Maste 
5900afa8e06SEd Maste 	return ok;
5910afa8e06SEd Maste }
5920afa8e06SEd Maste 
5930afa8e06SEd Maste int
write_file(const char * path,const u_char * ptr,size_t len)5940afa8e06SEd Maste write_file(const char *path, const u_char *ptr, size_t len)
5950afa8e06SEd Maste {
5960afa8e06SEd Maste 	int fd, ok = -1;
5970afa8e06SEd Maste 	ssize_t n;
5980afa8e06SEd Maste 
5990afa8e06SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
6000afa8e06SEd Maste 		warn("%s: open %s", __func__, path);
6010afa8e06SEd Maste 		goto fail;
6020afa8e06SEd Maste 	}
6030afa8e06SEd Maste 	if ((n = write(fd, ptr, len)) < 0) {
6040afa8e06SEd Maste 		warn("%s: write", __func__);
6050afa8e06SEd Maste 		goto fail;
6060afa8e06SEd Maste 	}
6070afa8e06SEd Maste 	if ((size_t)n != len) {
6080afa8e06SEd Maste 		warnx("%s: write", __func__);
6090afa8e06SEd Maste 		goto fail;
6100afa8e06SEd Maste 	}
6110afa8e06SEd Maste 
6120afa8e06SEd Maste 	ok = 0;
6130afa8e06SEd Maste fail:
6140afa8e06SEd Maste 	if (fd != -1) {
6150afa8e06SEd Maste 		close(fd);
6160afa8e06SEd Maste 	}
6170afa8e06SEd Maste 
6180afa8e06SEd Maste 	return ok;
6190afa8e06SEd Maste }
6200afa8e06SEd Maste 
6210afa8e06SEd Maste const char *
plural(size_t x)6220afa8e06SEd Maste plural(size_t x)
6230afa8e06SEd Maste {
6240afa8e06SEd Maste 	return x == 1 ? "" : "s";
6250afa8e06SEd Maste }
6260afa8e06SEd Maste 
6270afa8e06SEd Maste int
should_retry_with_pin(const fido_dev_t * dev,int r)6280afa8e06SEd Maste should_retry_with_pin(const fido_dev_t *dev, int r)
6290afa8e06SEd Maste {
6300afa8e06SEd Maste 	if (fido_dev_has_pin(dev) == false) {
6310afa8e06SEd Maste 		return 0;
6320afa8e06SEd Maste 	}
6330afa8e06SEd Maste 
6340afa8e06SEd Maste 	switch (r) {
6350afa8e06SEd Maste 	case FIDO_ERR_PIN_REQUIRED:
6360afa8e06SEd Maste 	case FIDO_ERR_UNAUTHORIZED_PERM:
6370afa8e06SEd Maste 	case FIDO_ERR_UV_BLOCKED:
6380afa8e06SEd Maste 	case FIDO_ERR_UV_INVALID:
6390afa8e06SEd Maste 		return 1;
6400afa8e06SEd Maste 	}
6410afa8e06SEd Maste 
6420afa8e06SEd Maste 	return 0;
6430afa8e06SEd Maste }
644