xref: /netbsd-src/external/bsd/libfido2/dist/tools/util.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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 }
365