diff options
Diffstat (limited to 'tools/util.c')
-rw-r--r-- | tools/util.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/tools/util.c b/tools/util.c new file mode 100644 index 0000000..de70388 --- /dev/null +++ b/tools/util.c | |||
@@ -0,0 +1,364 @@ | |||
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 <fcntl.h> | ||
20 | #include <stdint.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "../openbsd-compat/openbsd-compat.h" | ||
26 | #ifdef _MSC_VER | ||
27 | #include "../openbsd-compat/posix_win.h" | ||
28 | #endif | ||
29 | |||
30 | #include "extern.h" | ||
31 | |||
32 | void | ||
33 | read_pin(const char *path, char *buf, size_t len) | ||
34 | { | ||
35 | char prompt[1024]; | ||
36 | int r; | ||
37 | |||
38 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path); | ||
39 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
40 | errx(1, "snprintf"); | ||
41 | if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF)) | ||
42 | errx(1, "readpassphrase"); | ||
43 | } | ||
44 | |||
45 | FILE * | ||
46 | open_write(const char *file) | ||
47 | { | ||
48 | int fd; | ||
49 | FILE *f; | ||
50 | |||
51 | if (file == NULL || strcmp(file, "-") == 0) | ||
52 | return (stdout); | ||
53 | if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) | ||
54 | err(1, "open %s", file); | ||
55 | if ((f = fdopen(fd, "w")) == NULL) | ||
56 | err(1, "fdopen %s", file); | ||
57 | |||
58 | return (f); | ||
59 | } | ||
60 | |||
61 | FILE * | ||
62 | open_read(const char *file) | ||
63 | { | ||
64 | int fd; | ||
65 | FILE *f; | ||
66 | |||
67 | if (file == NULL || strcmp(file, "-") == 0) { | ||
68 | #ifdef FIDO_FUZZ | ||
69 | setvbuf(stdin, NULL, _IONBF, 0); | ||
70 | #endif | ||
71 | return (stdin); | ||
72 | } | ||
73 | if ((fd = open(file, O_RDONLY)) < 0) | ||
74 | err(1, "open %s", file); | ||
75 | if ((f = fdopen(fd, "r")) == NULL) | ||
76 | err(1, "fdopen %s", file); | ||
77 | |||
78 | return (f); | ||
79 | } | ||
80 | |||
81 | void | ||
82 | xxd(const void *buf, size_t count) | ||
83 | { | ||
84 | const uint8_t *ptr = buf; | ||
85 | size_t i; | ||
86 | |||
87 | fprintf(stderr, " "); | ||
88 | |||
89 | for (i = 0; i < count; i++) { | ||
90 | fprintf(stderr, "%02x ", *ptr++); | ||
91 | if ((i + 1) % 16 == 0 && i + 1 < count) | ||
92 | fprintf(stderr, "\n "); | ||
93 | } | ||
94 | |||
95 | fprintf(stderr, "\n"); | ||
96 | fflush(stderr); | ||
97 | } | ||
98 | |||
99 | int | ||
100 | string_read(FILE *f, char **out) | ||
101 | { | ||
102 | char *line = NULL; | ||
103 | size_t linesize = 0; | ||
104 | ssize_t n; | ||
105 | |||
106 | *out = NULL; | ||
107 | |||
108 | if ((n = getline(&line, &linesize, f)) <= 0 || | ||
109 | (size_t)n != strlen(line)) { | ||
110 | free(line); | ||
111 | return (-1); | ||
112 | } | ||
113 | |||
114 | line[n - 1] = '\0'; /* trim \n */ | ||
115 | *out = line; | ||
116 | |||
117 | return (0); | ||
118 | } | ||
119 | |||
120 | fido_dev_t * | ||
121 | open_dev(const char *path) | ||
122 | { | ||
123 | fido_dev_t *dev; | ||
124 | int r; | ||
125 | |||
126 | if ((dev = fido_dev_new()) == NULL) | ||
127 | errx(1, "fido_dev_new"); | ||
128 | |||
129 | r = fido_dev_open(dev, path); | ||
130 | if (r != FIDO_OK) | ||
131 | errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); | ||
132 | |||
133 | return (dev); | ||
134 | } | ||
135 | |||
136 | EC_KEY * | ||
137 | read_ec_pubkey(const char *path) | ||
138 | { | ||
139 | FILE *fp = NULL; | ||
140 | EVP_PKEY *pkey = NULL; | ||
141 | EC_KEY *ec = NULL; | ||
142 | |||
143 | if ((fp = fopen(path, "r")) == NULL) { | ||
144 | warn("fopen"); | ||
145 | goto fail; | ||
146 | } | ||
147 | |||
148 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
149 | warnx("PEM_read_PUBKEY"); | ||
150 | goto fail; | ||
151 | } | ||
152 | if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { | ||
153 | warnx("EVP_PKEY_get1_EC_KEY"); | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | fail: | ||
158 | if (fp) { | ||
159 | fclose(fp); | ||
160 | } | ||
161 | if (pkey) { | ||
162 | EVP_PKEY_free(pkey); | ||
163 | } | ||
164 | |||
165 | return (ec); | ||
166 | } | ||
167 | |||
168 | int | ||
169 | write_ec_pubkey(FILE *f, const void *ptr, size_t len) | ||
170 | { | ||
171 | EVP_PKEY *pkey = NULL; | ||
172 | es256_pk_t *pk = NULL; | ||
173 | int ok = -1; | ||
174 | |||
175 | if ((pk = es256_pk_new()) == NULL) { | ||
176 | warnx("es256_pk_new"); | ||
177 | goto fail; | ||
178 | } | ||
179 | |||
180 | if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
181 | warnx("es256_pk_from_ptr"); | ||
182 | goto fail; | ||
183 | } | ||
184 | |||
185 | if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
186 | warnx("es256_pk_to_EVP_PKEY"); | ||
187 | goto fail; | ||
188 | } | ||
189 | |||
190 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
191 | warnx("PEM_write_PUBKEY"); | ||
192 | goto fail; | ||
193 | } | ||
194 | |||
195 | ok = 0; | ||
196 | fail: | ||
197 | es256_pk_free(&pk); | ||
198 | |||
199 | if (pkey != NULL) { | ||
200 | EVP_PKEY_free(pkey); | ||
201 | } | ||
202 | |||
203 | return (ok); | ||
204 | } | ||
205 | |||
206 | RSA * | ||
207 | read_rsa_pubkey(const char *path) | ||
208 | { | ||
209 | FILE *fp = NULL; | ||
210 | EVP_PKEY *pkey = NULL; | ||
211 | RSA *rsa = NULL; | ||
212 | |||
213 | if ((fp = fopen(path, "r")) == NULL) { | ||
214 | warn("fopen"); | ||
215 | goto fail; | ||
216 | } | ||
217 | |||
218 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
219 | warnx("PEM_read_PUBKEY"); | ||
220 | goto fail; | ||
221 | } | ||
222 | if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { | ||
223 | warnx("EVP_PKEY_get1_RSA"); | ||
224 | goto fail; | ||
225 | } | ||
226 | |||
227 | fail: | ||
228 | if (fp) { | ||
229 | fclose(fp); | ||
230 | } | ||
231 | if (pkey) { | ||
232 | EVP_PKEY_free(pkey); | ||
233 | } | ||
234 | |||
235 | return (rsa); | ||
236 | } | ||
237 | |||
238 | int | ||
239 | write_rsa_pubkey(FILE *f, const void *ptr, size_t len) | ||
240 | { | ||
241 | EVP_PKEY *pkey = NULL; | ||
242 | rs256_pk_t *pk = NULL; | ||
243 | int ok = -1; | ||
244 | |||
245 | if ((pk = rs256_pk_new()) == NULL) { | ||
246 | warnx("rs256_pk_new"); | ||
247 | goto fail; | ||
248 | } | ||
249 | |||
250 | if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
251 | warnx("rs256_pk_from_ptr"); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
256 | warnx("rs256_pk_to_EVP_PKEY"); | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
261 | warnx("PEM_write_PUBKEY"); | ||
262 | goto fail; | ||
263 | } | ||
264 | |||
265 | ok = 0; | ||
266 | fail: | ||
267 | rs256_pk_free(&pk); | ||
268 | |||
269 | if (pkey != NULL) { | ||
270 | EVP_PKEY_free(pkey); | ||
271 | } | ||
272 | |||
273 | return (ok); | ||
274 | } | ||
275 | |||
276 | EVP_PKEY * | ||
277 | read_eddsa_pubkey(const char *path) | ||
278 | { | ||
279 | FILE *fp = NULL; | ||
280 | EVP_PKEY *pkey = NULL; | ||
281 | |||
282 | if ((fp = fopen(path, "r")) == NULL) { | ||
283 | warn("fopen"); | ||
284 | goto fail; | ||
285 | } | ||
286 | |||
287 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
288 | warnx("PEM_read_PUBKEY"); | ||
289 | goto fail; | ||
290 | } | ||
291 | |||
292 | fail: | ||
293 | if (fp) { | ||
294 | fclose(fp); | ||
295 | } | ||
296 | |||
297 | return (pkey); | ||
298 | } | ||
299 | |||
300 | int | ||
301 | write_eddsa_pubkey(FILE *f, const void *ptr, size_t len) | ||
302 | { | ||
303 | EVP_PKEY *pkey = NULL; | ||
304 | eddsa_pk_t *pk = NULL; | ||
305 | int ok = -1; | ||
306 | |||
307 | if ((pk = eddsa_pk_new()) == NULL) { | ||
308 | warnx("eddsa_pk_new"); | ||
309 | goto fail; | ||
310 | } | ||
311 | |||
312 | if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
313 | warnx("eddsa_pk_from_ptr"); | ||
314 | goto fail; | ||
315 | } | ||
316 | |||
317 | if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { | ||
318 | warnx("eddsa_pk_to_EVP_PKEY"); | ||
319 | goto fail; | ||
320 | } | ||
321 | |||
322 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
323 | warnx("PEM_write_PUBKEY"); | ||
324 | goto fail; | ||
325 | } | ||
326 | |||
327 | ok = 0; | ||
328 | fail: | ||
329 | eddsa_pk_free(&pk); | ||
330 | |||
331 | if (pkey != NULL) { | ||
332 | EVP_PKEY_free(pkey); | ||
333 | } | ||
334 | |||
335 | return (ok); | ||
336 | } | ||
337 | |||
338 | void | ||
339 | print_cred(FILE *out_f, int type, const fido_cred_t *cred) | ||
340 | { | ||
341 | char *id; | ||
342 | int r; | ||
343 | |||
344 | r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); | ||
345 | if (r < 0) | ||
346 | errx(1, "output error"); | ||
347 | |||
348 | fprintf(out_f, "%s\n", id); | ||
349 | |||
350 | if (type == COSE_ES256) { | ||
351 | write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
352 | fido_cred_pubkey_len(cred)); | ||
353 | } else if (type == COSE_RS256) { | ||
354 | write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
355 | fido_cred_pubkey_len(cred)); | ||
356 | } else if (type == COSE_EDDSA) { | ||
357 | write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
358 | fido_cred_pubkey_len(cred)); | ||
359 | } else { | ||
360 | errx(1, "print_cred: unknown type"); | ||
361 | } | ||
362 | |||
363 | free(id); | ||
364 | } | ||