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