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