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