diff options
Diffstat (limited to 'tools/assert_get.c')
-rw-r--r-- | tools/assert_get.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/tools/assert_get.c b/tools/assert_get.c new file mode 100644 index 0000000..5e209cd --- /dev/null +++ b/tools/assert_get.c | |||
@@ -0,0 +1,233 @@ | |||
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 <fido.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | static fido_assert_t * | ||
19 | prepare_assert(FILE *in_f, int flags) | ||
20 | { | ||
21 | fido_assert_t *assert = NULL; | ||
22 | struct blob cdh; | ||
23 | struct blob id; | ||
24 | struct blob hmac_salt; | ||
25 | char *rpid = NULL; | ||
26 | int r; | ||
27 | |||
28 | memset(&cdh, 0, sizeof(cdh)); | ||
29 | memset(&id, 0, sizeof(id)); | ||
30 | memset(&hmac_salt, 0, sizeof(hmac_salt)); | ||
31 | |||
32 | r = base64_read(in_f, &cdh); | ||
33 | r |= string_read(in_f, &rpid); | ||
34 | if ((flags & FLAG_RK) == 0) | ||
35 | r |= base64_read(in_f, &id); | ||
36 | if (flags & FLAG_HMAC) | ||
37 | r |= base64_read(in_f, &hmac_salt); | ||
38 | if (r < 0) | ||
39 | errx(1, "input error"); | ||
40 | |||
41 | if (flags & FLAG_DEBUG) { | ||
42 | fprintf(stderr, "client data hash:\n"); | ||
43 | xxd(cdh.ptr, cdh.len); | ||
44 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
45 | if ((flags & FLAG_RK) == 0) { | ||
46 | fprintf(stderr, "credential id:\n"); | ||
47 | xxd(id.ptr, id.len); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if ((assert = fido_assert_new()) == NULL) | ||
52 | errx(1, "fido_assert_new"); | ||
53 | |||
54 | if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, | ||
55 | cdh.len)) != FIDO_OK || | ||
56 | (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) | ||
57 | errx(1, "fido_assert_set: %s", fido_strerr(r)); | ||
58 | |||
59 | if (flags & FLAG_UP) { | ||
60 | if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
61 | errx(1, "fido_assert_set_up: %s", fido_strerr(r)); | ||
62 | } | ||
63 | if (flags & FLAG_UV) { | ||
64 | if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
65 | errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); | ||
66 | } | ||
67 | if (flags & FLAG_HMAC) { | ||
68 | if ((r = fido_assert_set_extensions(assert, | ||
69 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
70 | errx(1, "fido_assert_set_extensions: %s", | ||
71 | fido_strerr(r)); | ||
72 | if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, | ||
73 | hmac_salt.len)) != FIDO_OK) | ||
74 | errx(1, "fido_assert_set_hmac_salt: %s", | ||
75 | fido_strerr(r)); | ||
76 | } | ||
77 | if ((flags & FLAG_RK) == 0) { | ||
78 | if ((r = fido_assert_allow_cred(assert, id.ptr, | ||
79 | id.len)) != FIDO_OK) | ||
80 | errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); | ||
81 | } | ||
82 | |||
83 | free(hmac_salt.ptr); | ||
84 | free(cdh.ptr); | ||
85 | free(id.ptr); | ||
86 | free(rpid); | ||
87 | |||
88 | return (assert); | ||
89 | } | ||
90 | |||
91 | static void | ||
92 | print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) | ||
93 | { | ||
94 | char *cdh = NULL; | ||
95 | char *authdata = NULL; | ||
96 | char *sig = NULL; | ||
97 | char *user_id = NULL; | ||
98 | char *hmac_secret = NULL; | ||
99 | int r; | ||
100 | |||
101 | r = base64_encode(fido_assert_clientdata_hash_ptr(assert), | ||
102 | fido_assert_clientdata_hash_len(assert), &cdh); | ||
103 | r |= base64_encode(fido_assert_authdata_ptr(assert, idx), | ||
104 | fido_assert_authdata_len(assert, 0), &authdata); | ||
105 | r |= base64_encode(fido_assert_sig_ptr(assert, idx), | ||
106 | fido_assert_sig_len(assert, idx), &sig); | ||
107 | if (flags & FLAG_RK) | ||
108 | r |= base64_encode(fido_assert_user_id_ptr(assert, idx), | ||
109 | fido_assert_user_id_len(assert, idx), &user_id); | ||
110 | if (flags & FLAG_HMAC) | ||
111 | r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), | ||
112 | fido_assert_hmac_secret_len(assert, idx), &hmac_secret); | ||
113 | if (r < 0) | ||
114 | errx(1, "output error"); | ||
115 | |||
116 | fprintf(out_f, "%s\n", cdh); | ||
117 | fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); | ||
118 | fprintf(out_f, "%s\n", authdata); | ||
119 | fprintf(out_f, "%s\n", sig); | ||
120 | if (flags & FLAG_RK) | ||
121 | fprintf(out_f, "%s\n", user_id); | ||
122 | if (hmac_secret) { | ||
123 | fprintf(out_f, "%s\n", hmac_secret); | ||
124 | explicit_bzero(hmac_secret, strlen(hmac_secret)); | ||
125 | } | ||
126 | |||
127 | free(hmac_secret); | ||
128 | free(cdh); | ||
129 | free(authdata); | ||
130 | free(sig); | ||
131 | free(user_id); | ||
132 | } | ||
133 | |||
134 | int | ||
135 | assert_get(int argc, char **argv) | ||
136 | { | ||
137 | fido_dev_t *dev = NULL; | ||
138 | fido_assert_t *assert = NULL; | ||
139 | char pin[1024]; | ||
140 | char prompt[1024]; | ||
141 | char *in_path = NULL; | ||
142 | char *out_path = NULL; | ||
143 | FILE *in_f = NULL; | ||
144 | FILE *out_f = NULL; | ||
145 | int flags = 0; | ||
146 | int ch; | ||
147 | int r; | ||
148 | |||
149 | while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { | ||
150 | switch (ch) { | ||
151 | case 'd': | ||
152 | flags |= FLAG_DEBUG; | ||
153 | break; | ||
154 | case 'h': | ||
155 | flags |= FLAG_HMAC; | ||
156 | break; | ||
157 | case 'i': | ||
158 | in_path = optarg; | ||
159 | break; | ||
160 | case 'o': | ||
161 | out_path = optarg; | ||
162 | break; | ||
163 | case 'p': | ||
164 | flags |= FLAG_UP; | ||
165 | break; | ||
166 | case 'r': | ||
167 | flags |= FLAG_RK; | ||
168 | break; | ||
169 | case 'u': | ||
170 | flags |= FLAG_U2F; | ||
171 | break; | ||
172 | case 'v': | ||
173 | flags |= FLAG_UV; | ||
174 | break; | ||
175 | default: | ||
176 | usage(); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | argc -= optind; | ||
181 | argv += optind; | ||
182 | |||
183 | if (argc < 1) | ||
184 | usage(); | ||
185 | |||
186 | in_f = open_read(in_path); | ||
187 | out_f = open_write(out_path); | ||
188 | |||
189 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
190 | |||
191 | assert = prepare_assert(in_f, flags); | ||
192 | |||
193 | dev = open_dev(argv[0]); | ||
194 | if (flags & FLAG_U2F) | ||
195 | fido_dev_force_u2f(dev); | ||
196 | |||
197 | if (flags & FLAG_UV) { | ||
198 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", | ||
199 | argv[0]); | ||
200 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
201 | errx(1, "snprintf"); | ||
202 | if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) | ||
203 | errx(1, "readpassphrase"); | ||
204 | r = fido_dev_get_assert(dev, assert, pin); | ||
205 | } else | ||
206 | r = fido_dev_get_assert(dev, assert, NULL); | ||
207 | |||
208 | explicit_bzero(pin, sizeof(pin)); | ||
209 | |||
210 | if (r != FIDO_OK) | ||
211 | errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); | ||
212 | |||
213 | if (flags & FLAG_RK) { | ||
214 | for (size_t idx = 0; idx < fido_assert_count(assert); idx++) | ||
215 | print_assert(out_f, assert, idx, flags); | ||
216 | } else { | ||
217 | if (fido_assert_count(assert) != 1) | ||
218 | errx(1, "fido_assert_count: %zu", | ||
219 | fido_assert_count(assert)); | ||
220 | print_assert(out_f, assert, 0, flags); | ||
221 | } | ||
222 | |||
223 | fido_dev_close(dev); | ||
224 | fido_dev_free(&dev); | ||
225 | fido_assert_free(&assert); | ||
226 | |||
227 | fclose(in_f); | ||
228 | fclose(out_f); | ||
229 | in_f = NULL; | ||
230 | out_f = NULL; | ||
231 | |||
232 | exit(0); | ||
233 | } | ||