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