xref: /netbsd-src/external/bsd/libfido2/dist/examples/util.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
1ba9bdd8bSchristos /*
2*2d40c451Schristos  * 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*2d40c451Schristos  * 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 
1595dbdf32Schristos #include <fido.h>
1695dbdf32Schristos #include <fido/es256.h>
17*2d40c451Schristos #include <fido/es384.h>
1895dbdf32Schristos #include <fido/rs256.h>
1995dbdf32Schristos #include <fido/eddsa.h>
2095dbdf32Schristos 
21ba9bdd8bSchristos #include <errno.h>
22ba9bdd8bSchristos #include <fcntl.h>
23ba9bdd8bSchristos #include <limits.h>
24ba9bdd8bSchristos #include <stdlib.h>
25ba9bdd8bSchristos #include <string.h>
26ba9bdd8bSchristos #ifdef HAVE_UNISTD_H
27ba9bdd8bSchristos #include <unistd.h>
28ba9bdd8bSchristos #endif
29ba9bdd8bSchristos #ifdef _MSC_VER
30ba9bdd8bSchristos #include "../openbsd-compat/posix_win.h"
31ba9bdd8bSchristos #endif
321fc1e710Schristos #include "../openbsd-compat/openbsd-compat.h"
3395dbdf32Schristos #include "extern.h"
34ba9bdd8bSchristos 
35ba9bdd8bSchristos int
base10(const char * str,long long * ll)36ba9bdd8bSchristos base10(const char *str, long long *ll)
37ba9bdd8bSchristos {
38ba9bdd8bSchristos 	char *ep;
39ba9bdd8bSchristos 
40ba9bdd8bSchristos 	*ll = strtoll(str, &ep, 10);
41ba9bdd8bSchristos 	if (str == ep || *ep != '\0')
42ba9bdd8bSchristos 		return (-1);
43ba9bdd8bSchristos 	else if (*ll == LLONG_MIN && errno == ERANGE)
44ba9bdd8bSchristos 		return (-1);
45ba9bdd8bSchristos 	else if (*ll == LLONG_MAX && errno == ERANGE)
46ba9bdd8bSchristos 		return (-1);
47ba9bdd8bSchristos 
48ba9bdd8bSchristos 	return (0);
49ba9bdd8bSchristos }
50ba9bdd8bSchristos 
51ba9bdd8bSchristos int
write_blob(const char * path,const unsigned char * ptr,size_t len)52ba9bdd8bSchristos write_blob(const char *path, const unsigned char *ptr, size_t len)
53ba9bdd8bSchristos {
54ba9bdd8bSchristos 	int fd, ok = -1;
55ba9bdd8bSchristos 	ssize_t n;
56ba9bdd8bSchristos 
5795dbdf32Schristos 	if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
58ba9bdd8bSchristos 		warn("open %s", path);
59ba9bdd8bSchristos 		goto fail;
60ba9bdd8bSchristos 	}
61ba9bdd8bSchristos 
62ba9bdd8bSchristos 	if ((n = write(fd, ptr, len)) < 0) {
63ba9bdd8bSchristos 		warn("write");
64ba9bdd8bSchristos 		goto fail;
65ba9bdd8bSchristos 	}
66ba9bdd8bSchristos 	if ((size_t)n != len) {
67ba9bdd8bSchristos 		warnx("write");
68ba9bdd8bSchristos 		goto fail;
69ba9bdd8bSchristos 	}
70ba9bdd8bSchristos 
71ba9bdd8bSchristos 	ok = 0;
72ba9bdd8bSchristos fail:
73ba9bdd8bSchristos 	if (fd != -1) {
74ba9bdd8bSchristos 		close(fd);
75ba9bdd8bSchristos 	}
76ba9bdd8bSchristos 
77ba9bdd8bSchristos 	return (ok);
78ba9bdd8bSchristos }
79ba9bdd8bSchristos 
80ba9bdd8bSchristos int
read_blob(const char * path,unsigned char ** ptr,size_t * len)81ba9bdd8bSchristos read_blob(const char *path, unsigned char **ptr, size_t *len)
82ba9bdd8bSchristos {
83ba9bdd8bSchristos 	int fd, ok = -1;
84ba9bdd8bSchristos 	struct stat st;
85ba9bdd8bSchristos 	ssize_t n;
86ba9bdd8bSchristos 
87ba9bdd8bSchristos 	*ptr = NULL;
88ba9bdd8bSchristos 	*len = 0;
89ba9bdd8bSchristos 
90ba9bdd8bSchristos 	if ((fd = open(path, O_RDONLY)) < 0) {
91ba9bdd8bSchristos 		warn("open %s", path);
92ba9bdd8bSchristos 		goto fail;
93ba9bdd8bSchristos 	}
94ba9bdd8bSchristos 	if (fstat(fd, &st) < 0) {
95ba9bdd8bSchristos 		warn("stat %s", path);
96ba9bdd8bSchristos 		goto fail;
97ba9bdd8bSchristos 	}
98ba9bdd8bSchristos 	if (st.st_size < 0) {
99ba9bdd8bSchristos 		warnx("stat %s: invalid size", path);
100ba9bdd8bSchristos 		goto fail;
101ba9bdd8bSchristos 	}
102ba9bdd8bSchristos 	*len = (size_t)st.st_size;
103ba9bdd8bSchristos 	if ((*ptr = malloc(*len)) == NULL) {
104ba9bdd8bSchristos 		warn("malloc");
105ba9bdd8bSchristos 		goto fail;
106ba9bdd8bSchristos 	}
107ba9bdd8bSchristos 	if ((n = read(fd, *ptr, *len)) < 0) {
108ba9bdd8bSchristos 		warn("read");
109ba9bdd8bSchristos 		goto fail;
110ba9bdd8bSchristos 	}
111ba9bdd8bSchristos 	if ((size_t)n != *len) {
112ba9bdd8bSchristos 		warnx("read");
113ba9bdd8bSchristos 		goto fail;
114ba9bdd8bSchristos 	}
115ba9bdd8bSchristos 
116ba9bdd8bSchristos 	ok = 0;
117ba9bdd8bSchristos fail:
118ba9bdd8bSchristos 	if (fd != -1) {
119ba9bdd8bSchristos 		close(fd);
120ba9bdd8bSchristos 	}
121ba9bdd8bSchristos 	if (ok < 0) {
122ba9bdd8bSchristos 		free(*ptr);
123ba9bdd8bSchristos 		*ptr = NULL;
124ba9bdd8bSchristos 		*len = 0;
125ba9bdd8bSchristos 	}
126ba9bdd8bSchristos 
127ba9bdd8bSchristos 	return (ok);
128ba9bdd8bSchristos }
129ba9bdd8bSchristos 
130ba9bdd8bSchristos EC_KEY *
read_ec_pubkey(const char * path)131ba9bdd8bSchristos read_ec_pubkey(const char *path)
132ba9bdd8bSchristos {
133ba9bdd8bSchristos 	FILE *fp = NULL;
134ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
135ba9bdd8bSchristos 	EC_KEY *ec = NULL;
136ba9bdd8bSchristos 
137ba9bdd8bSchristos 	if ((fp = fopen(path, "r")) == NULL) {
138ba9bdd8bSchristos 		warn("fopen");
139ba9bdd8bSchristos 		goto fail;
140ba9bdd8bSchristos 	}
141ba9bdd8bSchristos 
142ba9bdd8bSchristos 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
143ba9bdd8bSchristos 		warnx("PEM_read_PUBKEY");
144ba9bdd8bSchristos 		goto fail;
145ba9bdd8bSchristos 	}
146ba9bdd8bSchristos 	if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
147ba9bdd8bSchristos 		warnx("EVP_PKEY_get1_EC_KEY");
148ba9bdd8bSchristos 		goto fail;
149ba9bdd8bSchristos 	}
150ba9bdd8bSchristos 
151ba9bdd8bSchristos fail:
152ba9bdd8bSchristos 	if (fp != NULL) {
153ba9bdd8bSchristos 		fclose(fp);
154ba9bdd8bSchristos 	}
155ba9bdd8bSchristos 	if (pkey != NULL) {
156ba9bdd8bSchristos 		EVP_PKEY_free(pkey);
157ba9bdd8bSchristos 	}
158ba9bdd8bSchristos 
159ba9bdd8bSchristos 	return (ec);
160ba9bdd8bSchristos }
161ba9bdd8bSchristos 
162ba9bdd8bSchristos int
write_es256_pubkey(const char * path,const void * ptr,size_t len)163*2d40c451Schristos write_es256_pubkey(const char *path, const void *ptr, size_t len)
164ba9bdd8bSchristos {
165ba9bdd8bSchristos 	FILE *fp = NULL;
166ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
167ba9bdd8bSchristos 	es256_pk_t *pk = NULL;
168ba9bdd8bSchristos 	int fd = -1;
169ba9bdd8bSchristos 	int ok = -1;
170ba9bdd8bSchristos 
171ba9bdd8bSchristos 	if ((pk = es256_pk_new()) == NULL) {
172ba9bdd8bSchristos 		warnx("es256_pk_new");
173ba9bdd8bSchristos 		goto fail;
174ba9bdd8bSchristos 	}
175ba9bdd8bSchristos 
176ba9bdd8bSchristos 	if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
177ba9bdd8bSchristos 		warnx("es256_pk_from_ptr");
178ba9bdd8bSchristos 		goto fail;
179ba9bdd8bSchristos 	}
180ba9bdd8bSchristos 
181ba9bdd8bSchristos 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
182ba9bdd8bSchristos 		warn("open %s", path);
183ba9bdd8bSchristos 		goto fail;
184ba9bdd8bSchristos 	}
185ba9bdd8bSchristos 
186ba9bdd8bSchristos 	if ((fp = fdopen(fd, "w")) == NULL) {
187ba9bdd8bSchristos 		warn("fdopen");
188ba9bdd8bSchristos 		goto fail;
189ba9bdd8bSchristos 	}
190ba9bdd8bSchristos 	fd = -1; /* owned by fp now */
191ba9bdd8bSchristos 
192ba9bdd8bSchristos 	if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
193ba9bdd8bSchristos 		warnx("es256_pk_to_EVP_PKEY");
194ba9bdd8bSchristos 		goto fail;
195ba9bdd8bSchristos 	}
196ba9bdd8bSchristos 
197ba9bdd8bSchristos 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
198ba9bdd8bSchristos 		warnx("PEM_write_PUBKEY");
199ba9bdd8bSchristos 		goto fail;
200ba9bdd8bSchristos 	}
201ba9bdd8bSchristos 
202ba9bdd8bSchristos 	ok = 0;
203ba9bdd8bSchristos fail:
204ba9bdd8bSchristos 	es256_pk_free(&pk);
205ba9bdd8bSchristos 
206ba9bdd8bSchristos 	if (fp != NULL) {
207ba9bdd8bSchristos 		fclose(fp);
208ba9bdd8bSchristos 	}
209ba9bdd8bSchristos 	if (fd != -1) {
210ba9bdd8bSchristos 		close(fd);
211ba9bdd8bSchristos 	}
212ba9bdd8bSchristos 	if (pkey != NULL) {
213ba9bdd8bSchristos 		EVP_PKEY_free(pkey);
214ba9bdd8bSchristos 	}
215ba9bdd8bSchristos 
216ba9bdd8bSchristos 	return (ok);
217ba9bdd8bSchristos }
218ba9bdd8bSchristos 
219*2d40c451Schristos int
write_es384_pubkey(const char * path,const void * ptr,size_t len)220*2d40c451Schristos write_es384_pubkey(const char *path, const void *ptr, size_t len)
221*2d40c451Schristos {
222*2d40c451Schristos 	FILE *fp = NULL;
223*2d40c451Schristos 	EVP_PKEY *pkey = NULL;
224*2d40c451Schristos 	es384_pk_t *pk = NULL;
225*2d40c451Schristos 	int fd = -1;
226*2d40c451Schristos 	int ok = -1;
227*2d40c451Schristos 
228*2d40c451Schristos 	if ((pk = es384_pk_new()) == NULL) {
229*2d40c451Schristos 		warnx("es384_pk_new");
230*2d40c451Schristos 		goto fail;
231*2d40c451Schristos 	}
232*2d40c451Schristos 
233*2d40c451Schristos 	if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
234*2d40c451Schristos 		warnx("es384_pk_from_ptr");
235*2d40c451Schristos 		goto fail;
236*2d40c451Schristos 	}
237*2d40c451Schristos 
238*2d40c451Schristos 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
239*2d40c451Schristos 		warn("open %s", path);
240*2d40c451Schristos 		goto fail;
241*2d40c451Schristos 	}
242*2d40c451Schristos 
243*2d40c451Schristos 	if ((fp = fdopen(fd, "w")) == NULL) {
244*2d40c451Schristos 		warn("fdopen");
245*2d40c451Schristos 		goto fail;
246*2d40c451Schristos 	}
247*2d40c451Schristos 	fd = -1; /* owned by fp now */
248*2d40c451Schristos 
249*2d40c451Schristos 	if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
250*2d40c451Schristos 		warnx("es384_pk_to_EVP_PKEY");
251*2d40c451Schristos 		goto fail;
252*2d40c451Schristos 	}
253*2d40c451Schristos 
254*2d40c451Schristos 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
255*2d40c451Schristos 		warnx("PEM_write_PUBKEY");
256*2d40c451Schristos 		goto fail;
257*2d40c451Schristos 	}
258*2d40c451Schristos 
259*2d40c451Schristos 	ok = 0;
260*2d40c451Schristos fail:
261*2d40c451Schristos 	es384_pk_free(&pk);
262*2d40c451Schristos 
263*2d40c451Schristos 	if (fp != NULL) {
264*2d40c451Schristos 		fclose(fp);
265*2d40c451Schristos 	}
266*2d40c451Schristos 	if (fd != -1) {
267*2d40c451Schristos 		close(fd);
268*2d40c451Schristos 	}
269*2d40c451Schristos 	if (pkey != NULL) {
270*2d40c451Schristos 		EVP_PKEY_free(pkey);
271*2d40c451Schristos 	}
272*2d40c451Schristos 
273*2d40c451Schristos 	return (ok);
274*2d40c451Schristos }
275*2d40c451Schristos 
276ba9bdd8bSchristos RSA *
read_rsa_pubkey(const char * path)277ba9bdd8bSchristos read_rsa_pubkey(const char *path)
278ba9bdd8bSchristos {
279ba9bdd8bSchristos 	FILE *fp = NULL;
280ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
281ba9bdd8bSchristos 	RSA *rsa = NULL;
282ba9bdd8bSchristos 
283ba9bdd8bSchristos 	if ((fp = fopen(path, "r")) == NULL) {
284ba9bdd8bSchristos 		warn("fopen");
285ba9bdd8bSchristos 		goto fail;
286ba9bdd8bSchristos 	}
287ba9bdd8bSchristos 
288ba9bdd8bSchristos 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
289ba9bdd8bSchristos 		warnx("PEM_read_PUBKEY");
290ba9bdd8bSchristos 		goto fail;
291ba9bdd8bSchristos 	}
292ba9bdd8bSchristos 	if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
293ba9bdd8bSchristos 		warnx("EVP_PKEY_get1_RSA");
294ba9bdd8bSchristos 		goto fail;
295ba9bdd8bSchristos 	}
296ba9bdd8bSchristos 
297ba9bdd8bSchristos fail:
298ba9bdd8bSchristos 	if (fp != NULL) {
299ba9bdd8bSchristos 		fclose(fp);
300ba9bdd8bSchristos 	}
301ba9bdd8bSchristos 	if (pkey != NULL) {
302ba9bdd8bSchristos 		EVP_PKEY_free(pkey);
303ba9bdd8bSchristos 	}
304ba9bdd8bSchristos 
305ba9bdd8bSchristos 	return (rsa);
306ba9bdd8bSchristos }
307ba9bdd8bSchristos 
308ba9bdd8bSchristos int
write_rs256_pubkey(const char * path,const void * ptr,size_t len)309*2d40c451Schristos write_rs256_pubkey(const char *path, const void *ptr, size_t len)
310ba9bdd8bSchristos {
311ba9bdd8bSchristos 	FILE *fp = NULL;
312ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
313ba9bdd8bSchristos 	rs256_pk_t *pk = NULL;
314ba9bdd8bSchristos 	int fd = -1;
315ba9bdd8bSchristos 	int ok = -1;
316ba9bdd8bSchristos 
317ba9bdd8bSchristos 	if ((pk = rs256_pk_new()) == NULL) {
318ba9bdd8bSchristos 		warnx("rs256_pk_new");
319ba9bdd8bSchristos 		goto fail;
320ba9bdd8bSchristos 	}
321ba9bdd8bSchristos 
322ba9bdd8bSchristos 	if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
323ba9bdd8bSchristos 		warnx("rs256_pk_from_ptr");
324ba9bdd8bSchristos 		goto fail;
325ba9bdd8bSchristos 	}
326ba9bdd8bSchristos 
327ba9bdd8bSchristos 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
328ba9bdd8bSchristos 		warn("open %s", path);
329ba9bdd8bSchristos 		goto fail;
330ba9bdd8bSchristos 	}
331ba9bdd8bSchristos 
332ba9bdd8bSchristos 	if ((fp = fdopen(fd, "w")) == NULL) {
333ba9bdd8bSchristos 		warn("fdopen");
334ba9bdd8bSchristos 		goto fail;
335ba9bdd8bSchristos 	}
336ba9bdd8bSchristos 	fd = -1; /* owned by fp now */
337ba9bdd8bSchristos 
338ba9bdd8bSchristos 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
339ba9bdd8bSchristos 		warnx("rs256_pk_to_EVP_PKEY");
340ba9bdd8bSchristos 		goto fail;
341ba9bdd8bSchristos 	}
342ba9bdd8bSchristos 
343ba9bdd8bSchristos 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
344ba9bdd8bSchristos 		warnx("PEM_write_PUBKEY");
345ba9bdd8bSchristos 		goto fail;
346ba9bdd8bSchristos 	}
347ba9bdd8bSchristos 
348ba9bdd8bSchristos 	ok = 0;
349ba9bdd8bSchristos fail:
350ba9bdd8bSchristos 	rs256_pk_free(&pk);
351ba9bdd8bSchristos 
352ba9bdd8bSchristos 	if (fp != NULL) {
353ba9bdd8bSchristos 		fclose(fp);
354ba9bdd8bSchristos 	}
355ba9bdd8bSchristos 	if (fd != -1) {
356ba9bdd8bSchristos 		close(fd);
357ba9bdd8bSchristos 	}
358ba9bdd8bSchristos 	if (pkey != NULL) {
359ba9bdd8bSchristos 		EVP_PKEY_free(pkey);
360ba9bdd8bSchristos 	}
361ba9bdd8bSchristos 
362ba9bdd8bSchristos 	return (ok);
363ba9bdd8bSchristos }
364ba9bdd8bSchristos 
365ba9bdd8bSchristos EVP_PKEY *
read_eddsa_pubkey(const char * path)366ba9bdd8bSchristos read_eddsa_pubkey(const char *path)
367ba9bdd8bSchristos {
368ba9bdd8bSchristos 	FILE *fp = NULL;
369ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
370ba9bdd8bSchristos 
371ba9bdd8bSchristos 	if ((fp = fopen(path, "r")) == NULL) {
372ba9bdd8bSchristos 		warn("fopen");
373ba9bdd8bSchristos 		goto fail;
374ba9bdd8bSchristos 	}
375ba9bdd8bSchristos 
376ba9bdd8bSchristos 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
377ba9bdd8bSchristos 		warnx("PEM_read_PUBKEY");
378ba9bdd8bSchristos 		goto fail;
379ba9bdd8bSchristos 	}
380ba9bdd8bSchristos 
381ba9bdd8bSchristos fail:
382ba9bdd8bSchristos 	if (fp) {
383ba9bdd8bSchristos 		fclose(fp);
384ba9bdd8bSchristos 	}
385ba9bdd8bSchristos 
386ba9bdd8bSchristos 	return (pkey);
387ba9bdd8bSchristos }
388ba9bdd8bSchristos 
389ba9bdd8bSchristos int
write_eddsa_pubkey(const char * path,const void * ptr,size_t len)390ba9bdd8bSchristos write_eddsa_pubkey(const char *path, const void *ptr, size_t len)
391ba9bdd8bSchristos {
392ba9bdd8bSchristos 	FILE *fp = NULL;
393ba9bdd8bSchristos 	EVP_PKEY *pkey = NULL;
394ba9bdd8bSchristos 	eddsa_pk_t *pk = NULL;
395ba9bdd8bSchristos 	int fd = -1;
396ba9bdd8bSchristos 	int ok = -1;
397ba9bdd8bSchristos 
398ba9bdd8bSchristos 	if ((pk = eddsa_pk_new()) == NULL) {
399ba9bdd8bSchristos 		warnx("eddsa_pk_new");
400ba9bdd8bSchristos 		goto fail;
401ba9bdd8bSchristos 	}
402ba9bdd8bSchristos 
403ba9bdd8bSchristos 	if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
404ba9bdd8bSchristos 		warnx("eddsa_pk_from_ptr");
405ba9bdd8bSchristos 		goto fail;
406ba9bdd8bSchristos 	}
407ba9bdd8bSchristos 
408ba9bdd8bSchristos 	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
409ba9bdd8bSchristos 		warn("open %s", path);
410ba9bdd8bSchristos 		goto fail;
411ba9bdd8bSchristos 	}
412ba9bdd8bSchristos 
413ba9bdd8bSchristos 	if ((fp = fdopen(fd, "w")) == NULL) {
414ba9bdd8bSchristos 		warn("fdopen");
415ba9bdd8bSchristos 		goto fail;
416ba9bdd8bSchristos 	}
417ba9bdd8bSchristos 	fd = -1; /* owned by fp now */
418ba9bdd8bSchristos 
419ba9bdd8bSchristos 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
420ba9bdd8bSchristos 		warnx("eddsa_pk_to_EVP_PKEY");
421ba9bdd8bSchristos 		goto fail;
422ba9bdd8bSchristos 	}
423ba9bdd8bSchristos 
424ba9bdd8bSchristos 	if (PEM_write_PUBKEY(fp, pkey) == 0) {
425ba9bdd8bSchristos 		warnx("PEM_write_PUBKEY");
426ba9bdd8bSchristos 		goto fail;
427ba9bdd8bSchristos 	}
428ba9bdd8bSchristos 
429ba9bdd8bSchristos 	ok = 0;
430ba9bdd8bSchristos fail:
431ba9bdd8bSchristos 	eddsa_pk_free(&pk);
432ba9bdd8bSchristos 
433ba9bdd8bSchristos 	if (fp != NULL) {
434ba9bdd8bSchristos 		fclose(fp);
435ba9bdd8bSchristos 	}
436ba9bdd8bSchristos 	if (fd != -1) {
437ba9bdd8bSchristos 		close(fd);
438ba9bdd8bSchristos 	}
439ba9bdd8bSchristos 	if (pkey != NULL) {
440ba9bdd8bSchristos 		EVP_PKEY_free(pkey);
441ba9bdd8bSchristos 	}
442ba9bdd8bSchristos 
443ba9bdd8bSchristos 	return (ok);
444ba9bdd8bSchristos }
445