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