xref: /freebsd/contrib/libfido2/tools/pin.c (revision f126890a)
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  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 
8 #include <fido.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 
17 #include "../openbsd-compat/openbsd-compat.h"
18 #include "extern.h"
19 
20 int
21 pin_set(char *path)
22 {
23 	fido_dev_t *dev = NULL;
24 	char prompt[1024];
25 	char pin1[128];
26 	char pin2[128];
27 	int r;
28 	int status = 1;
29 
30 	dev = open_dev(path);
31 
32 	r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path);
33 	if (r < 0 || (size_t)r >= sizeof(prompt)) {
34 		warnx("snprintf");
35 		goto out;
36 	}
37 
38 	if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) {
39 		warnx("readpassphrase");
40 		goto out;
41 	}
42 
43 	r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: ");
44 	if (r < 0 || (size_t)r >= sizeof(prompt)) {
45 		warnx("snprintf");
46 		goto out;
47 	}
48 
49 	if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) {
50 		warnx("readpassphrase");
51 		goto out;
52 	}
53 
54 	if (strcmp(pin1, pin2) != 0) {
55 		fprintf(stderr, "PINs do not match. Try again.\n");
56 		goto out;
57 	}
58 
59 	if (strlen(pin1) < 4 || strlen(pin1) > 63) {
60 		fprintf(stderr, "invalid PIN length\n");
61 		goto out;
62 	}
63 
64 	if ((r = fido_dev_set_pin(dev, pin1, NULL)) != FIDO_OK) {
65 		warnx("fido_dev_set_pin: %s", fido_strerr(r));
66 		goto out;
67 	}
68 
69 	fido_dev_close(dev);
70 	fido_dev_free(&dev);
71 
72 	status = 0;
73 out:
74 	explicit_bzero(pin1, sizeof(pin1));
75 	explicit_bzero(pin2, sizeof(pin2));
76 
77 	exit(status);
78 }
79 
80 int
81 pin_change(char *path)
82 {
83 	fido_dev_t *dev = NULL;
84 	char prompt[1024];
85 	char pin0[128];
86 	char pin1[128];
87 	char pin2[128];
88 	int r;
89 	int status = 1;
90 
91 	if (path == NULL)
92 		usage();
93 
94 	dev = open_dev(path);
95 
96 	r = snprintf(prompt, sizeof(prompt), "Enter current PIN for %s: ", path);
97 	if (r < 0 || (size_t)r >= sizeof(prompt)) {
98 		warnx("snprintf");
99 		goto out;
100 	}
101 
102 	if (!readpassphrase(prompt, pin0, sizeof(pin0), RPP_ECHO_OFF)) {
103 		warnx("readpassphrase");
104 		goto out;
105 	}
106 
107 	if (strlen(pin0) < 4 || strlen(pin0) > 63) {
108 		warnx("invalid PIN length");
109 		goto out;
110 	}
111 
112 	r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path);
113 	if (r < 0 || (size_t)r >= sizeof(prompt)) {
114 		warnx("snprintf");
115 		goto out;
116 	}
117 
118 	if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) {
119 		warnx("readpassphrase");
120 		goto out;
121 	}
122 
123 	r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: ");
124 	if (r < 0 || (size_t)r >= sizeof(prompt)) {
125 		warnx("snprintf");
126 		goto out;
127 	}
128 
129 	if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) {
130 		warnx("readpassphrase");
131 		goto out;
132 	}
133 
134 	if (strcmp(pin1, pin2) != 0) {
135 		fprintf(stderr, "PINs do not match. Try again.\n");
136 		goto out;
137 	}
138 
139 	if (strlen(pin1) < 4 || strlen(pin1) > 63) {
140 		fprintf(stderr, "invalid PIN length\n");
141 		goto out;
142 	}
143 
144 	if ((r = fido_dev_set_pin(dev, pin1, pin0)) != FIDO_OK) {
145 		warnx("fido_dev_set_pin: %s", fido_strerr(r));
146 		goto out;
147 	}
148 
149 	fido_dev_close(dev);
150 	fido_dev_free(&dev);
151 
152 	status = 0;
153 out:
154 	explicit_bzero(pin0, sizeof(pin0));
155 	explicit_bzero(pin1, sizeof(pin1));
156 	explicit_bzero(pin2, sizeof(pin2));
157 
158 	exit(status);
159 }
160