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