Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/tools/util.c
39534 views
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 <stdbool.h>
25
#include <stdint.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
30
#include "../openbsd-compat/openbsd-compat.h"
31
#ifdef _MSC_VER
32
#include "../openbsd-compat/posix_win.h"
33
#endif
34
35
#include "extern.h"
36
37
char *
38
get_pin(const char *path)
39
{
40
char *pin;
41
char prompt[1024];
42
int r, ok = -1;
43
44
if ((pin = calloc(1, PINBUF_LEN)) == NULL) {
45
warn("%s: calloc", __func__);
46
return NULL;
47
}
48
if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
49
path)) < 0 || (size_t)r >= sizeof(prompt)) {
50
warn("%s: snprintf", __func__);
51
goto out;
52
}
53
if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) {
54
warnx("%s: readpassphrase", __func__);
55
goto out;
56
}
57
58
ok = 0;
59
out:
60
if (ok < 0) {
61
freezero(pin, PINBUF_LEN);
62
pin = NULL;
63
}
64
65
return pin;
66
}
67
68
FILE *
69
open_write(const char *file)
70
{
71
int fd;
72
FILE *f;
73
74
if (file == NULL || strcmp(file, "-") == 0)
75
return (stdout);
76
if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
77
err(1, "open %s", file);
78
if ((f = fdopen(fd, "w")) == NULL)
79
err(1, "fdopen %s", file);
80
81
return (f);
82
}
83
84
FILE *
85
open_read(const char *file)
86
{
87
int fd;
88
FILE *f;
89
90
if (file == NULL || strcmp(file, "-") == 0) {
91
#ifdef FIDO_FUZZ
92
setvbuf(stdin, NULL, _IONBF, 0);
93
#endif
94
return (stdin);
95
}
96
if ((fd = open(file, O_RDONLY)) < 0)
97
err(1, "open %s", file);
98
if ((f = fdopen(fd, "r")) == NULL)
99
err(1, "fdopen %s", file);
100
101
return (f);
102
}
103
104
int
105
base10(const char *str)
106
{
107
char *ep;
108
long long ll;
109
110
ll = strtoll(str, &ep, 10);
111
if (str == ep || *ep != '\0')
112
return (-1);
113
else if (ll == LLONG_MIN && errno == ERANGE)
114
return (-1);
115
else if (ll == LLONG_MAX && errno == ERANGE)
116
return (-1);
117
else if (ll < 0 || ll > INT_MAX)
118
return (-1);
119
120
return ((int)ll);
121
}
122
123
void
124
xxd(const void *buf, size_t count)
125
{
126
const uint8_t *ptr = buf;
127
size_t i;
128
129
fprintf(stderr, " ");
130
131
for (i = 0; i < count; i++) {
132
fprintf(stderr, "%02x ", *ptr++);
133
if ((i + 1) % 16 == 0 && i + 1 < count)
134
fprintf(stderr, "\n ");
135
}
136
137
fprintf(stderr, "\n");
138
fflush(stderr);
139
}
140
141
int
142
string_read(FILE *f, char **out)
143
{
144
char *line = NULL;
145
size_t linesize = 0;
146
ssize_t n;
147
148
*out = NULL;
149
150
if ((n = getline(&line, &linesize, f)) <= 0 ||
151
(size_t)n != strlen(line)) {
152
free(line);
153
return (-1);
154
}
155
156
line[n - 1] = '\0'; /* trim \n */
157
*out = line;
158
159
return (0);
160
}
161
162
fido_dev_t *
163
open_dev(const char *path)
164
{
165
fido_dev_t *dev;
166
int r;
167
168
if ((dev = fido_dev_new()) == NULL)
169
errx(1, "fido_dev_new");
170
171
r = fido_dev_open(dev, path);
172
if (r != FIDO_OK)
173
errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
174
175
return (dev);
176
}
177
178
int
179
get_devopt(fido_dev_t *dev, const char *name, int *val)
180
{
181
fido_cbor_info_t *cbor_info;
182
char * const *names;
183
const bool *values;
184
int r, ok = -1;
185
186
if ((cbor_info = fido_cbor_info_new()) == NULL) {
187
warnx("fido_cbor_info_new");
188
goto out;
189
}
190
191
if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) {
192
warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
193
goto out;
194
}
195
196
if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL ||
197
(values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) {
198
warnx("fido_dev_get_cbor_info: NULL name/value pointer");
199
goto out;
200
}
201
202
*val = -1;
203
for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++)
204
if (strcmp(names[i], name) == 0) {
205
*val = values[i];
206
break;
207
}
208
209
ok = 0;
210
out:
211
fido_cbor_info_free(&cbor_info);
212
213
return (ok);
214
}
215
216
EC_KEY *
217
read_ec_pubkey(const char *path)
218
{
219
FILE *fp = NULL;
220
EVP_PKEY *pkey = NULL;
221
EC_KEY *ec = NULL;
222
223
if ((fp = fopen(path, "r")) == NULL) {
224
warn("fopen");
225
goto fail;
226
}
227
228
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
229
warnx("PEM_read_PUBKEY");
230
goto fail;
231
}
232
if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
233
warnx("EVP_PKEY_get1_EC_KEY");
234
goto fail;
235
}
236
237
fail:
238
if (fp) {
239
fclose(fp);
240
}
241
if (pkey) {
242
EVP_PKEY_free(pkey);
243
}
244
245
return (ec);
246
}
247
248
int
249
write_es256_pubkey(FILE *f, const void *ptr, size_t len)
250
{
251
EVP_PKEY *pkey = NULL;
252
es256_pk_t *pk = NULL;
253
int ok = -1;
254
255
if ((pk = es256_pk_new()) == NULL) {
256
warnx("es256_pk_new");
257
goto fail;
258
}
259
260
if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
261
warnx("es256_pk_from_ptr");
262
goto fail;
263
}
264
265
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
266
warnx("es256_pk_to_EVP_PKEY");
267
goto fail;
268
}
269
270
if (PEM_write_PUBKEY(f, pkey) == 0) {
271
warnx("PEM_write_PUBKEY");
272
goto fail;
273
}
274
275
ok = 0;
276
fail:
277
es256_pk_free(&pk);
278
279
if (pkey != NULL) {
280
EVP_PKEY_free(pkey);
281
}
282
283
return (ok);
284
}
285
286
int
287
write_es384_pubkey(FILE *f, const void *ptr, size_t len)
288
{
289
EVP_PKEY *pkey = NULL;
290
es384_pk_t *pk = NULL;
291
int ok = -1;
292
293
if ((pk = es384_pk_new()) == NULL) {
294
warnx("es384_pk_new");
295
goto fail;
296
}
297
298
if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
299
warnx("es384_pk_from_ptr");
300
goto fail;
301
}
302
303
if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
304
warnx("es384_pk_to_EVP_PKEY");
305
goto fail;
306
}
307
308
if (PEM_write_PUBKEY(f, pkey) == 0) {
309
warnx("PEM_write_PUBKEY");
310
goto fail;
311
}
312
313
ok = 0;
314
fail:
315
es384_pk_free(&pk);
316
317
if (pkey != NULL) {
318
EVP_PKEY_free(pkey);
319
}
320
321
return (ok);
322
}
323
324
RSA *
325
read_rsa_pubkey(const char *path)
326
{
327
FILE *fp = NULL;
328
EVP_PKEY *pkey = NULL;
329
RSA *rsa = NULL;
330
331
if ((fp = fopen(path, "r")) == NULL) {
332
warn("fopen");
333
goto fail;
334
}
335
336
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
337
warnx("PEM_read_PUBKEY");
338
goto fail;
339
}
340
if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
341
warnx("EVP_PKEY_get1_RSA");
342
goto fail;
343
}
344
345
fail:
346
if (fp) {
347
fclose(fp);
348
}
349
if (pkey) {
350
EVP_PKEY_free(pkey);
351
}
352
353
return (rsa);
354
}
355
356
int
357
write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
358
{
359
EVP_PKEY *pkey = NULL;
360
rs256_pk_t *pk = NULL;
361
int ok = -1;
362
363
if ((pk = rs256_pk_new()) == NULL) {
364
warnx("rs256_pk_new");
365
goto fail;
366
}
367
368
if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
369
warnx("rs256_pk_from_ptr");
370
goto fail;
371
}
372
373
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
374
warnx("rs256_pk_to_EVP_PKEY");
375
goto fail;
376
}
377
378
if (PEM_write_PUBKEY(f, pkey) == 0) {
379
warnx("PEM_write_PUBKEY");
380
goto fail;
381
}
382
383
ok = 0;
384
fail:
385
rs256_pk_free(&pk);
386
387
if (pkey != NULL) {
388
EVP_PKEY_free(pkey);
389
}
390
391
return (ok);
392
}
393
394
EVP_PKEY *
395
read_eddsa_pubkey(const char *path)
396
{
397
FILE *fp = NULL;
398
EVP_PKEY *pkey = NULL;
399
400
if ((fp = fopen(path, "r")) == NULL) {
401
warn("fopen");
402
goto fail;
403
}
404
405
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
406
warnx("PEM_read_PUBKEY");
407
goto fail;
408
}
409
410
fail:
411
if (fp) {
412
fclose(fp);
413
}
414
415
return (pkey);
416
}
417
418
int
419
write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
420
{
421
EVP_PKEY *pkey = NULL;
422
eddsa_pk_t *pk = NULL;
423
int ok = -1;
424
425
if ((pk = eddsa_pk_new()) == NULL) {
426
warnx("eddsa_pk_new");
427
goto fail;
428
}
429
430
if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
431
warnx("eddsa_pk_from_ptr");
432
goto fail;
433
}
434
435
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
436
warnx("eddsa_pk_to_EVP_PKEY");
437
goto fail;
438
}
439
440
if (PEM_write_PUBKEY(f, pkey) == 0) {
441
warnx("PEM_write_PUBKEY");
442
goto fail;
443
}
444
445
ok = 0;
446
fail:
447
eddsa_pk_free(&pk);
448
449
if (pkey != NULL) {
450
EVP_PKEY_free(pkey);
451
}
452
453
return (ok);
454
}
455
456
void
457
print_cred(FILE *out_f, int type, const fido_cred_t *cred)
458
{
459
char *id;
460
int r;
461
462
r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
463
if (r < 0)
464
errx(1, "output error");
465
466
fprintf(out_f, "%s\n", id);
467
468
switch (type) {
469
case COSE_ES256:
470
write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred),
471
fido_cred_pubkey_len(cred));
472
break;
473
case COSE_ES384:
474
write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred),
475
fido_cred_pubkey_len(cred));
476
break;
477
case COSE_RS256:
478
write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
479
fido_cred_pubkey_len(cred));
480
break;
481
case COSE_EDDSA:
482
write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
483
fido_cred_pubkey_len(cred));
484
break;
485
default:
486
errx(1, "print_cred: unknown type");
487
}
488
489
free(id);
490
}
491
492
int
493
cose_type(const char *str, int *type)
494
{
495
if (strcmp(str, "es256") == 0)
496
*type = COSE_ES256;
497
else if (strcmp(str, "es384") == 0)
498
*type = COSE_ES384;
499
else if (strcmp(str, "rs256") == 0)
500
*type = COSE_RS256;
501
else if (strcmp(str, "eddsa") == 0)
502
*type = COSE_EDDSA;
503
else {
504
*type = 0;
505
return (-1);
506
}
507
508
return (0);
509
}
510
511
const char *
512
cose_string(int type)
513
{
514
switch (type) {
515
case COSE_ES256:
516
return ("es256");
517
case COSE_ES384:
518
return ("es384");
519
case COSE_RS256:
520
return ("rs256");
521
case COSE_EDDSA:
522
return ("eddsa");
523
default:
524
return ("unknown");
525
}
526
}
527
528
const char *
529
prot_string(int prot)
530
{
531
switch (prot) {
532
case FIDO_CRED_PROT_UV_OPTIONAL:
533
return ("uvopt");
534
case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
535
return ("uvopt+id");
536
case FIDO_CRED_PROT_UV_REQUIRED:
537
return ("uvreq");
538
default:
539
return ("unknown");
540
}
541
}
542
543
int
544
read_file(const char *path, u_char **ptr, size_t *len)
545
{
546
int fd, ok = -1;
547
struct stat st;
548
ssize_t n;
549
550
*ptr = NULL;
551
*len = 0;
552
553
if ((fd = open(path, O_RDONLY)) < 0) {
554
warn("%s: open %s", __func__, path);
555
goto fail;
556
}
557
if (fstat(fd, &st) < 0) {
558
warn("%s: stat %s", __func__, path);
559
goto fail;
560
}
561
if (st.st_size < 0) {
562
warnx("%s: stat %s: invalid size", __func__, path);
563
goto fail;
564
}
565
*len = (size_t)st.st_size;
566
if ((*ptr = malloc(*len)) == NULL) {
567
warn("%s: malloc", __func__);
568
goto fail;
569
}
570
if ((n = read(fd, *ptr, *len)) < 0) {
571
warn("%s: read", __func__);
572
goto fail;
573
}
574
if ((size_t)n != *len) {
575
warnx("%s: read", __func__);
576
goto fail;
577
}
578
579
ok = 0;
580
fail:
581
if (fd != -1) {
582
close(fd);
583
}
584
if (ok < 0) {
585
free(*ptr);
586
*ptr = NULL;
587
*len = 0;
588
}
589
590
return ok;
591
}
592
593
int
594
write_file(const char *path, const u_char *ptr, size_t len)
595
{
596
int fd, ok = -1;
597
ssize_t n;
598
599
if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
600
warn("%s: open %s", __func__, path);
601
goto fail;
602
}
603
if ((n = write(fd, ptr, len)) < 0) {
604
warn("%s: write", __func__);
605
goto fail;
606
}
607
if ((size_t)n != len) {
608
warnx("%s: write", __func__);
609
goto fail;
610
}
611
612
ok = 0;
613
fail:
614
if (fd != -1) {
615
close(fd);
616
}
617
618
return ok;
619
}
620
621
const char *
622
plural(size_t x)
623
{
624
return x == 1 ? "" : "s";
625
}
626
627
int
628
should_retry_with_pin(const fido_dev_t *dev, int r)
629
{
630
if (fido_dev_has_pin(dev) == false) {
631
return 0;
632
}
633
634
switch (r) {
635
case FIDO_ERR_PIN_REQUIRED:
636
case FIDO_ERR_UNAUTHORIZED_PERM:
637
case FIDO_ERR_UV_BLOCKED:
638
case FIDO_ERR_UV_INVALID:
639
return 1;
640
}
641
642
return 0;
643
}
644
645