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
base10(const char * str,long long * ll)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
write_blob(const char * path,const unsigned char * ptr,size_t len)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
read_blob(const char * path,unsigned char ** ptr,size_t * len)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 *
read_ec_pubkey(const char * path)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
write_es256_pubkey(const char * path,const void * ptr,size_t len)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
write_es384_pubkey(const char * path,const void * ptr,size_t len)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 *
read_rsa_pubkey(const char * path)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
write_rs256_pubkey(const char * path,const void * ptr,size_t len)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 *
read_eddsa_pubkey(const char * path)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
write_eddsa_pubkey(const char * path,const void * ptr,size_t len)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