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