util.c revision 1.1.1.2 1 1.1 christos /*
2 1.1 christos * Copyright (c) 2018 Yubico AB. All rights reserved.
3 1.1 christos * Use of this source code is governed by a BSD-style
4 1.1 christos * license that can be found in the LICENSE file.
5 1.1 christos */
6 1.1 christos
7 1.1 christos #include <sys/types.h>
8 1.1 christos #include <sys/stat.h>
9 1.1 christos
10 1.1 christos #include <openssl/ec.h>
11 1.1 christos #include <openssl/evp.h>
12 1.1 christos #include <openssl/pem.h>
13 1.1 christos
14 1.1 christos #include <fido.h>
15 1.1 christos #include <fido/es256.h>
16 1.1 christos #include <fido/rs256.h>
17 1.1 christos #include <fido/eddsa.h>
18 1.1 christos
19 1.1.1.2 christos #include <errno.h>
20 1.1 christos #include <fcntl.h>
21 1.1.1.2 christos #include <limits.h>
22 1.1 christos #include <stdint.h>
23 1.1 christos #include <stdio.h>
24 1.1 christos #include <stdlib.h>
25 1.1 christos #include <string.h>
26 1.1 christos
27 1.1 christos #include "../openbsd-compat/openbsd-compat.h"
28 1.1 christos #ifdef _MSC_VER
29 1.1 christos #include "../openbsd-compat/posix_win.h"
30 1.1 christos #endif
31 1.1 christos
32 1.1 christos #include "extern.h"
33 1.1 christos
34 1.1 christos void
35 1.1 christos read_pin(const char *path, char *buf, size_t len)
36 1.1 christos {
37 1.1 christos char prompt[1024];
38 1.1 christos int r;
39 1.1 christos
40 1.1 christos r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path);
41 1.1 christos if (r < 0 || (size_t)r >= sizeof(prompt))
42 1.1 christos errx(1, "snprintf");
43 1.1 christos if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF))
44 1.1 christos errx(1, "readpassphrase");
45 1.1 christos }
46 1.1 christos
47 1.1 christos FILE *
48 1.1 christos open_write(const char *file)
49 1.1 christos {
50 1.1 christos int fd;
51 1.1 christos FILE *f;
52 1.1 christos
53 1.1 christos if (file == NULL || strcmp(file, "-") == 0)
54 1.1 christos return (stdout);
55 1.1 christos if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
56 1.1 christos err(1, "open %s", file);
57 1.1 christos if ((f = fdopen(fd, "w")) == NULL)
58 1.1 christos err(1, "fdopen %s", file);
59 1.1 christos
60 1.1 christos return (f);
61 1.1 christos }
62 1.1 christos
63 1.1 christos FILE *
64 1.1 christos open_read(const char *file)
65 1.1 christos {
66 1.1 christos int fd;
67 1.1 christos FILE *f;
68 1.1 christos
69 1.1 christos if (file == NULL || strcmp(file, "-") == 0) {
70 1.1 christos #ifdef FIDO_FUZZ
71 1.1 christos setvbuf(stdin, NULL, _IONBF, 0);
72 1.1 christos #endif
73 1.1 christos return (stdin);
74 1.1 christos }
75 1.1 christos if ((fd = open(file, O_RDONLY)) < 0)
76 1.1 christos err(1, "open %s", file);
77 1.1 christos if ((f = fdopen(fd, "r")) == NULL)
78 1.1 christos err(1, "fdopen %s", file);
79 1.1 christos
80 1.1 christos return (f);
81 1.1 christos }
82 1.1 christos
83 1.1.1.2 christos int
84 1.1.1.2 christos base10(const char *str)
85 1.1.1.2 christos {
86 1.1.1.2 christos char *ep;
87 1.1.1.2 christos long long ll;
88 1.1.1.2 christos
89 1.1.1.2 christos ll = strtoll(str, &ep, 10);
90 1.1.1.2 christos if (str == ep || *ep != '\0')
91 1.1.1.2 christos return (-1);
92 1.1.1.2 christos else if (ll == LLONG_MIN && errno == ERANGE)
93 1.1.1.2 christos return (-1);
94 1.1.1.2 christos else if (ll == LLONG_MAX && errno == ERANGE)
95 1.1.1.2 christos return (-1);
96 1.1.1.2 christos else if (ll < 0 || ll > INT_MAX)
97 1.1.1.2 christos return (-1);
98 1.1.1.2 christos
99 1.1.1.2 christos return ((int)ll);
100 1.1.1.2 christos }
101 1.1.1.2 christos
102 1.1 christos void
103 1.1 christos xxd(const void *buf, size_t count)
104 1.1 christos {
105 1.1 christos const uint8_t *ptr = buf;
106 1.1 christos size_t i;
107 1.1 christos
108 1.1 christos fprintf(stderr, " ");
109 1.1 christos
110 1.1 christos for (i = 0; i < count; i++) {
111 1.1 christos fprintf(stderr, "%02x ", *ptr++);
112 1.1 christos if ((i + 1) % 16 == 0 && i + 1 < count)
113 1.1 christos fprintf(stderr, "\n ");
114 1.1 christos }
115 1.1 christos
116 1.1 christos fprintf(stderr, "\n");
117 1.1 christos fflush(stderr);
118 1.1 christos }
119 1.1 christos
120 1.1 christos int
121 1.1 christos string_read(FILE *f, char **out)
122 1.1 christos {
123 1.1 christos char *line = NULL;
124 1.1 christos size_t linesize = 0;
125 1.1 christos ssize_t n;
126 1.1 christos
127 1.1 christos *out = NULL;
128 1.1 christos
129 1.1 christos if ((n = getline(&line, &linesize, f)) <= 0 ||
130 1.1 christos (size_t)n != strlen(line)) {
131 1.1 christos free(line);
132 1.1 christos return (-1);
133 1.1 christos }
134 1.1 christos
135 1.1 christos line[n - 1] = '\0'; /* trim \n */
136 1.1 christos *out = line;
137 1.1 christos
138 1.1 christos return (0);
139 1.1 christos }
140 1.1 christos
141 1.1 christos fido_dev_t *
142 1.1 christos open_dev(const char *path)
143 1.1 christos {
144 1.1 christos fido_dev_t *dev;
145 1.1 christos int r;
146 1.1 christos
147 1.1 christos if ((dev = fido_dev_new()) == NULL)
148 1.1 christos errx(1, "fido_dev_new");
149 1.1 christos
150 1.1 christos r = fido_dev_open(dev, path);
151 1.1 christos if (r != FIDO_OK)
152 1.1 christos errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
153 1.1 christos
154 1.1 christos return (dev);
155 1.1 christos }
156 1.1 christos
157 1.1 christos EC_KEY *
158 1.1 christos read_ec_pubkey(const char *path)
159 1.1 christos {
160 1.1 christos FILE *fp = NULL;
161 1.1 christos EVP_PKEY *pkey = NULL;
162 1.1 christos EC_KEY *ec = NULL;
163 1.1 christos
164 1.1 christos if ((fp = fopen(path, "r")) == NULL) {
165 1.1 christos warn("fopen");
166 1.1 christos goto fail;
167 1.1 christos }
168 1.1 christos
169 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
170 1.1 christos warnx("PEM_read_PUBKEY");
171 1.1 christos goto fail;
172 1.1 christos }
173 1.1 christos if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
174 1.1 christos warnx("EVP_PKEY_get1_EC_KEY");
175 1.1 christos goto fail;
176 1.1 christos }
177 1.1 christos
178 1.1 christos fail:
179 1.1 christos if (fp) {
180 1.1 christos fclose(fp);
181 1.1 christos }
182 1.1 christos if (pkey) {
183 1.1 christos EVP_PKEY_free(pkey);
184 1.1 christos }
185 1.1 christos
186 1.1 christos return (ec);
187 1.1 christos }
188 1.1 christos
189 1.1 christos int
190 1.1 christos write_ec_pubkey(FILE *f, const void *ptr, size_t len)
191 1.1 christos {
192 1.1 christos EVP_PKEY *pkey = NULL;
193 1.1 christos es256_pk_t *pk = NULL;
194 1.1 christos int ok = -1;
195 1.1 christos
196 1.1 christos if ((pk = es256_pk_new()) == NULL) {
197 1.1 christos warnx("es256_pk_new");
198 1.1 christos goto fail;
199 1.1 christos }
200 1.1 christos
201 1.1 christos if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
202 1.1 christos warnx("es256_pk_from_ptr");
203 1.1 christos goto fail;
204 1.1 christos }
205 1.1 christos
206 1.1 christos if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
207 1.1 christos warnx("es256_pk_to_EVP_PKEY");
208 1.1 christos goto fail;
209 1.1 christos }
210 1.1 christos
211 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) {
212 1.1 christos warnx("PEM_write_PUBKEY");
213 1.1 christos goto fail;
214 1.1 christos }
215 1.1 christos
216 1.1 christos ok = 0;
217 1.1 christos fail:
218 1.1 christos es256_pk_free(&pk);
219 1.1 christos
220 1.1 christos if (pkey != NULL) {
221 1.1 christos EVP_PKEY_free(pkey);
222 1.1 christos }
223 1.1 christos
224 1.1 christos return (ok);
225 1.1 christos }
226 1.1 christos
227 1.1 christos RSA *
228 1.1 christos read_rsa_pubkey(const char *path)
229 1.1 christos {
230 1.1 christos FILE *fp = NULL;
231 1.1 christos EVP_PKEY *pkey = NULL;
232 1.1 christos RSA *rsa = NULL;
233 1.1 christos
234 1.1 christos if ((fp = fopen(path, "r")) == NULL) {
235 1.1 christos warn("fopen");
236 1.1 christos goto fail;
237 1.1 christos }
238 1.1 christos
239 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
240 1.1 christos warnx("PEM_read_PUBKEY");
241 1.1 christos goto fail;
242 1.1 christos }
243 1.1 christos if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
244 1.1 christos warnx("EVP_PKEY_get1_RSA");
245 1.1 christos goto fail;
246 1.1 christos }
247 1.1 christos
248 1.1 christos fail:
249 1.1 christos if (fp) {
250 1.1 christos fclose(fp);
251 1.1 christos }
252 1.1 christos if (pkey) {
253 1.1 christos EVP_PKEY_free(pkey);
254 1.1 christos }
255 1.1 christos
256 1.1 christos return (rsa);
257 1.1 christos }
258 1.1 christos
259 1.1 christos int
260 1.1 christos write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
261 1.1 christos {
262 1.1 christos EVP_PKEY *pkey = NULL;
263 1.1 christos rs256_pk_t *pk = NULL;
264 1.1 christos int ok = -1;
265 1.1 christos
266 1.1 christos if ((pk = rs256_pk_new()) == NULL) {
267 1.1 christos warnx("rs256_pk_new");
268 1.1 christos goto fail;
269 1.1 christos }
270 1.1 christos
271 1.1 christos if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
272 1.1 christos warnx("rs256_pk_from_ptr");
273 1.1 christos goto fail;
274 1.1 christos }
275 1.1 christos
276 1.1 christos if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
277 1.1 christos warnx("rs256_pk_to_EVP_PKEY");
278 1.1 christos goto fail;
279 1.1 christos }
280 1.1 christos
281 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) {
282 1.1 christos warnx("PEM_write_PUBKEY");
283 1.1 christos goto fail;
284 1.1 christos }
285 1.1 christos
286 1.1 christos ok = 0;
287 1.1 christos fail:
288 1.1 christos rs256_pk_free(&pk);
289 1.1 christos
290 1.1 christos if (pkey != NULL) {
291 1.1 christos EVP_PKEY_free(pkey);
292 1.1 christos }
293 1.1 christos
294 1.1 christos return (ok);
295 1.1 christos }
296 1.1 christos
297 1.1 christos EVP_PKEY *
298 1.1 christos read_eddsa_pubkey(const char *path)
299 1.1 christos {
300 1.1 christos FILE *fp = NULL;
301 1.1 christos EVP_PKEY *pkey = NULL;
302 1.1 christos
303 1.1 christos if ((fp = fopen(path, "r")) == NULL) {
304 1.1 christos warn("fopen");
305 1.1 christos goto fail;
306 1.1 christos }
307 1.1 christos
308 1.1 christos if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
309 1.1 christos warnx("PEM_read_PUBKEY");
310 1.1 christos goto fail;
311 1.1 christos }
312 1.1 christos
313 1.1 christos fail:
314 1.1 christos if (fp) {
315 1.1 christos fclose(fp);
316 1.1 christos }
317 1.1 christos
318 1.1 christos return (pkey);
319 1.1 christos }
320 1.1 christos
321 1.1 christos int
322 1.1 christos write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
323 1.1 christos {
324 1.1 christos EVP_PKEY *pkey = NULL;
325 1.1 christos eddsa_pk_t *pk = NULL;
326 1.1 christos int ok = -1;
327 1.1 christos
328 1.1 christos if ((pk = eddsa_pk_new()) == NULL) {
329 1.1 christos warnx("eddsa_pk_new");
330 1.1 christos goto fail;
331 1.1 christos }
332 1.1 christos
333 1.1 christos if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
334 1.1 christos warnx("eddsa_pk_from_ptr");
335 1.1 christos goto fail;
336 1.1 christos }
337 1.1 christos
338 1.1 christos if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
339 1.1 christos warnx("eddsa_pk_to_EVP_PKEY");
340 1.1 christos goto fail;
341 1.1 christos }
342 1.1 christos
343 1.1 christos if (PEM_write_PUBKEY(f, pkey) == 0) {
344 1.1 christos warnx("PEM_write_PUBKEY");
345 1.1 christos goto fail;
346 1.1 christos }
347 1.1 christos
348 1.1 christos ok = 0;
349 1.1 christos fail:
350 1.1 christos eddsa_pk_free(&pk);
351 1.1 christos
352 1.1 christos if (pkey != NULL) {
353 1.1 christos EVP_PKEY_free(pkey);
354 1.1 christos }
355 1.1 christos
356 1.1 christos return (ok);
357 1.1 christos }
358 1.1 christos
359 1.1 christos void
360 1.1 christos print_cred(FILE *out_f, int type, const fido_cred_t *cred)
361 1.1 christos {
362 1.1 christos char *id;
363 1.1 christos int r;
364 1.1 christos
365 1.1 christos r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
366 1.1 christos if (r < 0)
367 1.1 christos errx(1, "output error");
368 1.1 christos
369 1.1 christos fprintf(out_f, "%s\n", id);
370 1.1 christos
371 1.1 christos if (type == COSE_ES256) {
372 1.1 christos write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred),
373 1.1 christos fido_cred_pubkey_len(cred));
374 1.1 christos } else if (type == COSE_RS256) {
375 1.1 christos write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
376 1.1 christos fido_cred_pubkey_len(cred));
377 1.1 christos } else if (type == COSE_EDDSA) {
378 1.1 christos write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
379 1.1 christos fido_cred_pubkey_len(cred));
380 1.1 christos } else {
381 1.1 christos errx(1, "print_cred: unknown type");
382 1.1 christos }
383 1.1 christos
384 1.1 christos free(id);
385 1.1 christos }
386 1.1.1.2 christos
387 1.1.1.2 christos int
388 1.1.1.2 christos cose_type(const char *str, int *type)
389 1.1.1.2 christos {
390 1.1.1.2 christos if (strcmp(str, "es256") == 0)
391 1.1.1.2 christos *type = COSE_ES256;
392 1.1.1.2 christos else if (strcmp(str, "rs256") == 0)
393 1.1.1.2 christos *type = COSE_RS256;
394 1.1.1.2 christos else if (strcmp(str, "eddsa") == 0)
395 1.1.1.2 christos *type = COSE_EDDSA;
396 1.1.1.2 christos else {
397 1.1.1.2 christos *type = 0;
398 1.1.1.2 christos return (-1);
399 1.1.1.2 christos }
400 1.1.1.2 christos
401 1.1.1.2 christos return (0);
402 1.1.1.2 christos }
403 1.1.1.2 christos
404 1.1.1.2 christos const char *
405 1.1.1.2 christos cose_string(int type)
406 1.1.1.2 christos {
407 1.1.1.2 christos switch (type) {
408 1.1.1.2 christos case COSE_EDDSA:
409 1.1.1.2 christos return ("eddsa");
410 1.1.1.2 christos case COSE_ES256:
411 1.1.1.2 christos return ("es256");
412 1.1.1.2 christos case COSE_RS256:
413 1.1.1.2 christos return ("rs256");
414 1.1.1.2 christos default:
415 1.1.1.2 christos return ("unknown");
416 1.1.1.2 christos }
417 1.1.1.2 christos }
418 1.1.1.2 christos
419 1.1.1.2 christos const char *
420 1.1.1.2 christos prot_string(int prot)
421 1.1.1.2 christos {
422 1.1.1.2 christos switch (prot) {
423 1.1.1.2 christos case FIDO_CRED_PROT_UV_OPTIONAL:
424 1.1.1.2 christos return ("uvopt");
425 1.1.1.2 christos case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
426 1.1.1.2 christos return ("uvopt+id");
427 1.1.1.2 christos case FIDO_CRED_PROT_UV_REQUIRED:
428 1.1.1.2 christos return ("uvreq");
429 1.1.1.2 christos default:
430 1.1.1.2 christos return ("unknown");
431 1.1.1.2 christos }
432 1.1.1.2 christos }
433