xref: /freebsd/contrib/libfido2/examples/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 <stdlib.h>
250afa8e06SEd Maste #include <string.h>
260afa8e06SEd Maste #ifdef HAVE_UNISTD_H
270afa8e06SEd Maste #include <unistd.h>
280afa8e06SEd Maste #endif
290afa8e06SEd Maste #ifdef _MSC_VER
300afa8e06SEd Maste #include "../openbsd-compat/posix_win.h"
310afa8e06SEd Maste #endif
320afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
330afa8e06SEd Maste #include "extern.h"
340afa8e06SEd Maste 
350afa8e06SEd Maste int
base10(const char * str,long long * ll)360afa8e06SEd Maste base10(const char *str, long long *ll)
370afa8e06SEd Maste {
380afa8e06SEd Maste 	char *ep;
390afa8e06SEd Maste 
400afa8e06SEd Maste 	*ll = strtoll(str, &ep, 10);
410afa8e06SEd Maste 	if (str == ep || *ep != '\0')
420afa8e06SEd Maste 		return (-1);
430afa8e06SEd Maste 	else if (*ll == LLONG_MIN && errno == ERANGE)
440afa8e06SEd Maste 		return (-1);
450afa8e06SEd Maste 	else if (*ll == LLONG_MAX && errno == ERANGE)
460afa8e06SEd Maste 		return (-1);
470afa8e06SEd Maste 
480afa8e06SEd Maste 	return (0);
490afa8e06SEd Maste }
500afa8e06SEd Maste 
510afa8e06SEd Maste int
write_blob(const char * path,const unsigned char * ptr,size_t len)520afa8e06SEd Maste write_blob(const char *path, const unsigned char *ptr, size_t len)
530afa8e06SEd Maste {
540afa8e06SEd Maste 	int fd, ok = -1;
550afa8e06SEd Maste 	ssize_t n;
560afa8e06SEd Maste 
570afa8e06SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
580afa8e06SEd Maste 		warn("open %s", path);
590afa8e06SEd Maste 		goto fail;
600afa8e06SEd Maste 	}
610afa8e06SEd Maste 
620afa8e06SEd Maste 	if ((n = write(fd, ptr, len)) < 0) {
630afa8e06SEd Maste 		warn("write");
640afa8e06SEd Maste 		goto fail;
650afa8e06SEd Maste 	}
660afa8e06SEd Maste 	if ((size_t)n != len) {
670afa8e06SEd Maste 		warnx("write");
680afa8e06SEd Maste 		goto fail;
690afa8e06SEd Maste 	}
700afa8e06SEd Maste 
710afa8e06SEd Maste 	ok = 0;
720afa8e06SEd Maste fail:
730afa8e06SEd Maste 	if (fd != -1) {
740afa8e06SEd Maste 		close(fd);
750afa8e06SEd Maste 	}
760afa8e06SEd Maste 
770afa8e06SEd Maste 	return (ok);
780afa8e06SEd Maste }
790afa8e06SEd Maste 
800afa8e06SEd Maste int
read_blob(const char * path,unsigned char ** ptr,size_t * len)810afa8e06SEd Maste read_blob(const char *path, unsigned char **ptr, size_t *len)
820afa8e06SEd Maste {
830afa8e06SEd Maste 	int fd, ok = -1;
840afa8e06SEd Maste 	struct stat st;
850afa8e06SEd Maste 	ssize_t n;
860afa8e06SEd Maste 
870afa8e06SEd Maste 	*ptr = NULL;
880afa8e06SEd Maste 	*len = 0;
890afa8e06SEd Maste 
900afa8e06SEd Maste 	if ((fd = open(path, O_RDONLY)) < 0) {
910afa8e06SEd Maste 		warn("open %s", path);
920afa8e06SEd Maste 		goto fail;
930afa8e06SEd Maste 	}
940afa8e06SEd Maste 	if (fstat(fd, &st) < 0) {
950afa8e06SEd Maste 		warn("stat %s", path);
960afa8e06SEd Maste 		goto fail;
970afa8e06SEd Maste 	}
980afa8e06SEd Maste 	if (st.st_size < 0) {
990afa8e06SEd Maste 		warnx("stat %s: invalid size", path);
1000afa8e06SEd Maste 		goto fail;
1010afa8e06SEd Maste 	}
1020afa8e06SEd Maste 	*len = (size_t)st.st_size;
1030afa8e06SEd Maste 	if ((*ptr = malloc(*len)) == NULL) {
1040afa8e06SEd Maste 		warn("malloc");
1050afa8e06SEd Maste 		goto fail;
1060afa8e06SEd Maste 	}
1070afa8e06SEd Maste 	if ((n = read(fd, *ptr, *len)) < 0) {
1080afa8e06SEd Maste 		warn("read");
1090afa8e06SEd Maste 		goto fail;
1100afa8e06SEd Maste 	}
1110afa8e06SEd Maste 	if ((size_t)n != *len) {
1120afa8e06SEd Maste 		warnx("read");
1130afa8e06SEd Maste 		goto fail;
1140afa8e06SEd Maste 	}
1150afa8e06SEd Maste 
1160afa8e06SEd Maste 	ok = 0;
1170afa8e06SEd Maste fail:
1180afa8e06SEd Maste 	if (fd != -1) {
1190afa8e06SEd Maste 		close(fd);
1200afa8e06SEd Maste 	}
1210afa8e06SEd Maste 	if (ok < 0) {
1220afa8e06SEd Maste 		free(*ptr);
1230afa8e06SEd Maste 		*ptr = NULL;
1240afa8e06SEd Maste 		*len = 0;
1250afa8e06SEd Maste 	}
1260afa8e06SEd Maste 
1270afa8e06SEd Maste 	return (ok);
1280afa8e06SEd Maste }
1290afa8e06SEd Maste 
1300afa8e06SEd Maste EC_KEY *
read_ec_pubkey(const char * path)1310afa8e06SEd Maste read_ec_pubkey(const char *path)
1320afa8e06SEd Maste {
1330afa8e06SEd Maste 	FILE *fp = NULL;
1340afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
1350afa8e06SEd Maste 	EC_KEY *ec = NULL;
1360afa8e06SEd Maste 
1370afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
1380afa8e06SEd Maste 		warn("fopen");
1390afa8e06SEd Maste 		goto fail;
1400afa8e06SEd Maste 	}
1410afa8e06SEd Maste 
1420afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
1430afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
1440afa8e06SEd Maste 		goto fail;
1450afa8e06SEd Maste 	}
1460afa8e06SEd Maste 	if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
1470afa8e06SEd Maste 		warnx("EVP_PKEY_get1_EC_KEY");
1480afa8e06SEd Maste 		goto fail;
1490afa8e06SEd Maste 	}
1500afa8e06SEd Maste 
1510afa8e06SEd Maste fail:
1520afa8e06SEd Maste 	if (fp != NULL) {
1530afa8e06SEd Maste 		fclose(fp);
1540afa8e06SEd Maste 	}
1550afa8e06SEd Maste 	if (pkey != NULL) {
1560afa8e06SEd Maste 		EVP_PKEY_free(pkey);
1570afa8e06SEd Maste 	}
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	return (ec);
1600afa8e06SEd Maste }
1610afa8e06SEd Maste 
1620afa8e06SEd Maste int
write_es256_pubkey(const char * path,const void * ptr,size_t len)163*2ccfa855SEd Maste write_es256_pubkey(const char *path, const void *ptr, size_t len)
1640afa8e06SEd Maste {
1650afa8e06SEd Maste 	FILE *fp = NULL;
1660afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
1670afa8e06SEd Maste 	es256_pk_t *pk = NULL;
1680afa8e06SEd Maste 	int fd = -1;
1690afa8e06SEd Maste 	int ok = -1;
1700afa8e06SEd Maste 
1710afa8e06SEd Maste 	if ((pk = es256_pk_new()) == NULL) {
1720afa8e06SEd Maste 		warnx("es256_pk_new");
1730afa8e06SEd Maste 		goto fail;
1740afa8e06SEd Maste 	}
1750afa8e06SEd Maste 
1760afa8e06SEd Maste 	if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
1770afa8e06SEd Maste 		warnx("es256_pk_from_ptr");
1780afa8e06SEd Maste 		goto fail;
1790afa8e06SEd Maste 	}
1800afa8e06SEd Maste 
1810afa8e06SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
1820afa8e06SEd Maste 		warn("open %s", path);
1830afa8e06SEd Maste 		goto fail;
1840afa8e06SEd Maste 	}
1850afa8e06SEd Maste 
1860afa8e06SEd Maste 	if ((fp = fdopen(fd, "w")) == NULL) {
1870afa8e06SEd Maste 		warn("fdopen");
1880afa8e06SEd Maste 		goto fail;
1890afa8e06SEd Maste 	}
1900afa8e06SEd Maste 	fd = -1; /* owned by fp now */
1910afa8e06SEd Maste 
1920afa8e06SEd Maste 	if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
1930afa8e06SEd Maste 		warnx("es256_pk_to_EVP_PKEY");
1940afa8e06SEd Maste 		goto fail;
1950afa8e06SEd Maste 	}
1960afa8e06SEd Maste 
1970afa8e06SEd Maste 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
1980afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
1990afa8e06SEd Maste 		goto fail;
2000afa8e06SEd Maste 	}
2010afa8e06SEd Maste 
2020afa8e06SEd Maste 	ok = 0;
2030afa8e06SEd Maste fail:
2040afa8e06SEd Maste 	es256_pk_free(&pk);
2050afa8e06SEd Maste 
2060afa8e06SEd Maste 	if (fp != NULL) {
2070afa8e06SEd Maste 		fclose(fp);
2080afa8e06SEd Maste 	}
2090afa8e06SEd Maste 	if (fd != -1) {
2100afa8e06SEd Maste 		close(fd);
2110afa8e06SEd Maste 	}
2120afa8e06SEd Maste 	if (pkey != NULL) {
2130afa8e06SEd Maste 		EVP_PKEY_free(pkey);
2140afa8e06SEd Maste 	}
2150afa8e06SEd Maste 
2160afa8e06SEd Maste 	return (ok);
2170afa8e06SEd Maste }
2180afa8e06SEd Maste 
219*2ccfa855SEd Maste int
write_es384_pubkey(const char * path,const void * ptr,size_t len)220*2ccfa855SEd Maste write_es384_pubkey(const char *path, const void *ptr, size_t len)
221*2ccfa855SEd Maste {
222*2ccfa855SEd Maste 	FILE *fp = NULL;
223*2ccfa855SEd Maste 	EVP_PKEY *pkey = NULL;
224*2ccfa855SEd Maste 	es384_pk_t *pk = NULL;
225*2ccfa855SEd Maste 	int fd = -1;
226*2ccfa855SEd Maste 	int ok = -1;
227*2ccfa855SEd Maste 
228*2ccfa855SEd Maste 	if ((pk = es384_pk_new()) == NULL) {
229*2ccfa855SEd Maste 		warnx("es384_pk_new");
230*2ccfa855SEd Maste 		goto fail;
231*2ccfa855SEd Maste 	}
232*2ccfa855SEd Maste 
233*2ccfa855SEd Maste 	if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
234*2ccfa855SEd Maste 		warnx("es384_pk_from_ptr");
235*2ccfa855SEd Maste 		goto fail;
236*2ccfa855SEd Maste 	}
237*2ccfa855SEd Maste 
238*2ccfa855SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
239*2ccfa855SEd Maste 		warn("open %s", path);
240*2ccfa855SEd Maste 		goto fail;
241*2ccfa855SEd Maste 	}
242*2ccfa855SEd Maste 
243*2ccfa855SEd Maste 	if ((fp = fdopen(fd, "w")) == NULL) {
244*2ccfa855SEd Maste 		warn("fdopen");
245*2ccfa855SEd Maste 		goto fail;
246*2ccfa855SEd Maste 	}
247*2ccfa855SEd Maste 	fd = -1; /* owned by fp now */
248*2ccfa855SEd Maste 
249*2ccfa855SEd Maste 	if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
250*2ccfa855SEd Maste 		warnx("es384_pk_to_EVP_PKEY");
251*2ccfa855SEd Maste 		goto fail;
252*2ccfa855SEd Maste 	}
253*2ccfa855SEd Maste 
254*2ccfa855SEd Maste 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
255*2ccfa855SEd Maste 		warnx("PEM_write_PUBKEY");
256*2ccfa855SEd Maste 		goto fail;
257*2ccfa855SEd Maste 	}
258*2ccfa855SEd Maste 
259*2ccfa855SEd Maste 	ok = 0;
260*2ccfa855SEd Maste fail:
261*2ccfa855SEd Maste 	es384_pk_free(&pk);
262*2ccfa855SEd Maste 
263*2ccfa855SEd Maste 	if (fp != NULL) {
264*2ccfa855SEd Maste 		fclose(fp);
265*2ccfa855SEd Maste 	}
266*2ccfa855SEd Maste 	if (fd != -1) {
267*2ccfa855SEd Maste 		close(fd);
268*2ccfa855SEd Maste 	}
269*2ccfa855SEd Maste 	if (pkey != NULL) {
270*2ccfa855SEd Maste 		EVP_PKEY_free(pkey);
271*2ccfa855SEd Maste 	}
272*2ccfa855SEd Maste 
273*2ccfa855SEd Maste 	return (ok);
274*2ccfa855SEd Maste }
275*2ccfa855SEd Maste 
2760afa8e06SEd Maste RSA *
read_rsa_pubkey(const char * path)2770afa8e06SEd Maste read_rsa_pubkey(const char *path)
2780afa8e06SEd Maste {
2790afa8e06SEd Maste 	FILE *fp = NULL;
2800afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
2810afa8e06SEd Maste 	RSA *rsa = NULL;
2820afa8e06SEd Maste 
2830afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
2840afa8e06SEd Maste 		warn("fopen");
2850afa8e06SEd Maste 		goto fail;
2860afa8e06SEd Maste 	}
2870afa8e06SEd Maste 
2880afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
2890afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
2900afa8e06SEd Maste 		goto fail;
2910afa8e06SEd Maste 	}
2920afa8e06SEd Maste 	if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
2930afa8e06SEd Maste 		warnx("EVP_PKEY_get1_RSA");
2940afa8e06SEd Maste 		goto fail;
2950afa8e06SEd Maste 	}
2960afa8e06SEd Maste 
2970afa8e06SEd Maste fail:
2980afa8e06SEd Maste 	if (fp != NULL) {
2990afa8e06SEd Maste 		fclose(fp);
3000afa8e06SEd Maste 	}
3010afa8e06SEd Maste 	if (pkey != NULL) {
3020afa8e06SEd Maste 		EVP_PKEY_free(pkey);
3030afa8e06SEd Maste 	}
3040afa8e06SEd Maste 
3050afa8e06SEd Maste 	return (rsa);
3060afa8e06SEd Maste }
3070afa8e06SEd Maste 
3080afa8e06SEd Maste int
write_rs256_pubkey(const char * path,const void * ptr,size_t len)309*2ccfa855SEd Maste write_rs256_pubkey(const char *path, const void *ptr, size_t len)
3100afa8e06SEd Maste {
3110afa8e06SEd Maste 	FILE *fp = NULL;
3120afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3130afa8e06SEd Maste 	rs256_pk_t *pk = NULL;
3140afa8e06SEd Maste 	int fd = -1;
3150afa8e06SEd Maste 	int ok = -1;
3160afa8e06SEd Maste 
3170afa8e06SEd Maste 	if ((pk = rs256_pk_new()) == NULL) {
3180afa8e06SEd Maste 		warnx("rs256_pk_new");
3190afa8e06SEd Maste 		goto fail;
3200afa8e06SEd Maste 	}
3210afa8e06SEd Maste 
3220afa8e06SEd Maste 	if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
3230afa8e06SEd Maste 		warnx("rs256_pk_from_ptr");
3240afa8e06SEd Maste 		goto fail;
3250afa8e06SEd Maste 	}
3260afa8e06SEd Maste 
3270afa8e06SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
3280afa8e06SEd Maste 		warn("open %s", path);
3290afa8e06SEd Maste 		goto fail;
3300afa8e06SEd Maste 	}
3310afa8e06SEd Maste 
3320afa8e06SEd Maste 	if ((fp = fdopen(fd, "w")) == NULL) {
3330afa8e06SEd Maste 		warn("fdopen");
3340afa8e06SEd Maste 		goto fail;
3350afa8e06SEd Maste 	}
3360afa8e06SEd Maste 	fd = -1; /* owned by fp now */
3370afa8e06SEd Maste 
3380afa8e06SEd Maste 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
3390afa8e06SEd Maste 		warnx("rs256_pk_to_EVP_PKEY");
3400afa8e06SEd Maste 		goto fail;
3410afa8e06SEd Maste 	}
3420afa8e06SEd Maste 
3430afa8e06SEd Maste 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
3440afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
3450afa8e06SEd Maste 		goto fail;
3460afa8e06SEd Maste 	}
3470afa8e06SEd Maste 
3480afa8e06SEd Maste 	ok = 0;
3490afa8e06SEd Maste fail:
3500afa8e06SEd Maste 	rs256_pk_free(&pk);
3510afa8e06SEd Maste 
3520afa8e06SEd Maste 	if (fp != NULL) {
3530afa8e06SEd Maste 		fclose(fp);
3540afa8e06SEd Maste 	}
3550afa8e06SEd Maste 	if (fd != -1) {
3560afa8e06SEd Maste 		close(fd);
3570afa8e06SEd Maste 	}
3580afa8e06SEd Maste 	if (pkey != NULL) {
3590afa8e06SEd Maste 		EVP_PKEY_free(pkey);
3600afa8e06SEd Maste 	}
3610afa8e06SEd Maste 
3620afa8e06SEd Maste 	return (ok);
3630afa8e06SEd Maste }
3640afa8e06SEd Maste 
3650afa8e06SEd Maste EVP_PKEY *
read_eddsa_pubkey(const char * path)3660afa8e06SEd Maste read_eddsa_pubkey(const char *path)
3670afa8e06SEd Maste {
3680afa8e06SEd Maste 	FILE *fp = NULL;
3690afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3700afa8e06SEd Maste 
3710afa8e06SEd Maste 	if ((fp = fopen(path, "r")) == NULL) {
3720afa8e06SEd Maste 		warn("fopen");
3730afa8e06SEd Maste 		goto fail;
3740afa8e06SEd Maste 	}
3750afa8e06SEd Maste 
3760afa8e06SEd Maste 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
3770afa8e06SEd Maste 		warnx("PEM_read_PUBKEY");
3780afa8e06SEd Maste 		goto fail;
3790afa8e06SEd Maste 	}
3800afa8e06SEd Maste 
3810afa8e06SEd Maste fail:
3820afa8e06SEd Maste 	if (fp) {
3830afa8e06SEd Maste 		fclose(fp);
3840afa8e06SEd Maste 	}
3850afa8e06SEd Maste 
3860afa8e06SEd Maste 	return (pkey);
3870afa8e06SEd Maste }
3880afa8e06SEd Maste 
3890afa8e06SEd Maste int
write_eddsa_pubkey(const char * path,const void * ptr,size_t len)3900afa8e06SEd Maste write_eddsa_pubkey(const char *path, const void *ptr, size_t len)
3910afa8e06SEd Maste {
3920afa8e06SEd Maste 	FILE *fp = NULL;
3930afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
3940afa8e06SEd Maste 	eddsa_pk_t *pk = NULL;
3950afa8e06SEd Maste 	int fd = -1;
3960afa8e06SEd Maste 	int ok = -1;
3970afa8e06SEd Maste 
3980afa8e06SEd Maste 	if ((pk = eddsa_pk_new()) == NULL) {
3990afa8e06SEd Maste 		warnx("eddsa_pk_new");
4000afa8e06SEd Maste 		goto fail;
4010afa8e06SEd Maste 	}
4020afa8e06SEd Maste 
4030afa8e06SEd Maste 	if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
4040afa8e06SEd Maste 		warnx("eddsa_pk_from_ptr");
4050afa8e06SEd Maste 		goto fail;
4060afa8e06SEd Maste 	}
4070afa8e06SEd Maste 
4080afa8e06SEd Maste 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
4090afa8e06SEd Maste 		warn("open %s", path);
4100afa8e06SEd Maste 		goto fail;
4110afa8e06SEd Maste 	}
4120afa8e06SEd Maste 
4130afa8e06SEd Maste 	if ((fp = fdopen(fd, "w")) == NULL) {
4140afa8e06SEd Maste 		warn("fdopen");
4150afa8e06SEd Maste 		goto fail;
4160afa8e06SEd Maste 	}
4170afa8e06SEd Maste 	fd = -1; /* owned by fp now */
4180afa8e06SEd Maste 
4190afa8e06SEd Maste 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
4200afa8e06SEd Maste 		warnx("eddsa_pk_to_EVP_PKEY");
4210afa8e06SEd Maste 		goto fail;
4220afa8e06SEd Maste 	}
4230afa8e06SEd Maste 
4240afa8e06SEd Maste 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
4250afa8e06SEd Maste 		warnx("PEM_write_PUBKEY");
4260afa8e06SEd Maste 		goto fail;
4270afa8e06SEd Maste 	}
4280afa8e06SEd Maste 
4290afa8e06SEd Maste 	ok = 0;
4300afa8e06SEd Maste fail:
4310afa8e06SEd Maste 	eddsa_pk_free(&pk);
4320afa8e06SEd Maste 
4330afa8e06SEd Maste 	if (fp != NULL) {
4340afa8e06SEd Maste 		fclose(fp);
4350afa8e06SEd Maste 	}
4360afa8e06SEd Maste 	if (fd != -1) {
4370afa8e06SEd Maste 		close(fd);
4380afa8e06SEd Maste 	}
4390afa8e06SEd Maste 	if (pkey != NULL) {
4400afa8e06SEd Maste 		EVP_PKEY_free(pkey);
4410afa8e06SEd Maste 	}
4420afa8e06SEd Maste 
4430afa8e06SEd Maste 	return (ok);
4440afa8e06SEd Maste }
445