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 <fido.h>
9 #include <fido/es256.h>
10 #include <fido/es384.h>
11 #include <fido/rs256.h>
12 #include <fido/eddsa.h>
13
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
21
22 #include "../openbsd-compat/openbsd-compat.h"
23 #include "extern.h"
24
25 static const unsigned char cd[32] = {
26 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
27 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
28 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52,
29 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76,
30 };
31
32 static void
usage(void)33 usage(void)
34 {
35 fprintf(stderr, "usage: assert [-t es256|es384|rs256|eddsa] "
36 "[-a cred_id] [-h hmac_secret] [-s hmac_salt] [-P pin] "
37 "[-T seconds] [-b blobkey] [-puv] <pubkey> <device>\n");
38 exit(EXIT_FAILURE);
39 }
40
41 static void
verify_assert(int type,const unsigned char * authdata_ptr,size_t authdata_len,const unsigned char * sig_ptr,size_t sig_len,bool up,bool uv,int ext,const char * key)42 verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len,
43 const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext,
44 const char *key)
45 {
46 fido_assert_t *assert = NULL;
47 EC_KEY *ec = NULL;
48 RSA *rsa = NULL;
49 EVP_PKEY *eddsa = NULL;
50 es256_pk_t *es256_pk = NULL;
51 es384_pk_t *es384_pk = NULL;
52 rs256_pk_t *rs256_pk = NULL;
53 eddsa_pk_t *eddsa_pk = NULL;
54 void *pk;
55 int r;
56
57 /* credential pubkey */
58 switch (type) {
59 case COSE_ES256:
60 if ((ec = read_ec_pubkey(key)) == NULL)
61 errx(1, "read_ec_pubkey");
62
63 if ((es256_pk = es256_pk_new()) == NULL)
64 errx(1, "es256_pk_new");
65
66 if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK)
67 errx(1, "es256_pk_from_EC_KEY");
68
69 pk = es256_pk;
70 EC_KEY_free(ec);
71 ec = NULL;
72
73 break;
74 case COSE_ES384:
75 if ((ec = read_ec_pubkey(key)) == NULL)
76 errx(1, "read_ec_pubkey");
77
78 if ((es384_pk = es384_pk_new()) == NULL)
79 errx(1, "es384_pk_new");
80
81 if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK)
82 errx(1, "es384_pk_from_EC_KEY");
83
84 pk = es384_pk;
85 EC_KEY_free(ec);
86 ec = NULL;
87
88 break;
89 case COSE_RS256:
90 if ((rsa = read_rsa_pubkey(key)) == NULL)
91 errx(1, "read_rsa_pubkey");
92
93 if ((rs256_pk = rs256_pk_new()) == NULL)
94 errx(1, "rs256_pk_new");
95
96 if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK)
97 errx(1, "rs256_pk_from_RSA");
98
99 pk = rs256_pk;
100 RSA_free(rsa);
101 rsa = NULL;
102
103 break;
104 case COSE_EDDSA:
105 if ((eddsa = read_eddsa_pubkey(key)) == NULL)
106 errx(1, "read_eddsa_pubkey");
107
108 if ((eddsa_pk = eddsa_pk_new()) == NULL)
109 errx(1, "eddsa_pk_new");
110
111 if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK)
112 errx(1, "eddsa_pk_from_EVP_PKEY");
113
114 pk = eddsa_pk;
115 EVP_PKEY_free(eddsa);
116 eddsa = NULL;
117
118 break;
119 default:
120 errx(1, "unknown credential type %d", type);
121 }
122
123 if ((assert = fido_assert_new()) == NULL)
124 errx(1, "fido_assert_new");
125
126 /* client data hash */
127 r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
128 if (r != FIDO_OK)
129 errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
130
131 /* relying party */
132 r = fido_assert_set_rp(assert, "localhost");
133 if (r != FIDO_OK)
134 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
135
136 /* authdata */
137 r = fido_assert_set_count(assert, 1);
138 if (r != FIDO_OK)
139 errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r);
140 r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len);
141 if (r != FIDO_OK)
142 errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r);
143
144 /* extension */
145 r = fido_assert_set_extensions(assert, ext);
146 if (r != FIDO_OK)
147 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
148 r);
149
150 /* user presence */
151 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
152 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
153
154 /* user verification */
155 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
156 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
157
158 /* sig */
159 r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
160 if (r != FIDO_OK)
161 errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r);
162
163 r = fido_assert_verify(assert, 0, type, pk);
164 if (r != FIDO_OK)
165 errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r);
166
167 es256_pk_free(&es256_pk);
168 es384_pk_free(&es384_pk);
169 rs256_pk_free(&rs256_pk);
170 eddsa_pk_free(&eddsa_pk);
171
172 fido_assert_free(&assert);
173 }
174
175 int
main(int argc,char ** argv)176 main(int argc, char **argv)
177 {
178 bool up = false;
179 bool uv = false;
180 bool u2f = false;
181 fido_dev_t *dev = NULL;
182 fido_assert_t *assert = NULL;
183 const char *pin = NULL;
184 const char *blobkey_out = NULL;
185 const char *hmac_out = NULL;
186 unsigned char *body = NULL;
187 long long ms = 0;
188 size_t len;
189 int type = COSE_ES256;
190 int ext = 0;
191 int ch;
192 int r;
193
194 if ((assert = fido_assert_new()) == NULL)
195 errx(1, "fido_assert_new");
196
197 while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) {
198 switch (ch) {
199 case 'P':
200 pin = optarg;
201 break;
202 case 'T':
203 if (base10(optarg, &ms) < 0)
204 errx(1, "base10: %s", optarg);
205 if (ms <= 0 || ms > 30)
206 errx(1, "-T: %s must be in (0,30]", optarg);
207 ms *= 1000; /* seconds to milliseconds */
208 break;
209 case 'a':
210 if (read_blob(optarg, &body, &len) < 0)
211 errx(1, "read_blob: %s", optarg);
212 if ((r = fido_assert_allow_cred(assert, body,
213 len)) != FIDO_OK)
214 errx(1, "fido_assert_allow_cred: %s (0x%x)",
215 fido_strerr(r), r);
216 free(body);
217 body = NULL;
218 break;
219 case 'b':
220 ext |= FIDO_EXT_LARGEBLOB_KEY;
221 blobkey_out = optarg;
222 break;
223 case 'h':
224 hmac_out = optarg;
225 break;
226 case 'p':
227 up = true;
228 break;
229 case 's':
230 ext |= FIDO_EXT_HMAC_SECRET;
231 if (read_blob(optarg, &body, &len) < 0)
232 errx(1, "read_blob: %s", optarg);
233 if ((r = fido_assert_set_hmac_salt(assert, body,
234 len)) != FIDO_OK)
235 errx(1, "fido_assert_set_hmac_salt: %s (0x%x)",
236 fido_strerr(r), r);
237 free(body);
238 body = NULL;
239 break;
240 case 't':
241 if (strcmp(optarg, "es256") == 0)
242 type = COSE_ES256;
243 else if (strcmp(optarg, "es384") == 0)
244 type = COSE_ES384;
245 else if (strcmp(optarg, "rs256") == 0)
246 type = COSE_RS256;
247 else if (strcmp(optarg, "eddsa") == 0)
248 type = COSE_EDDSA;
249 else
250 errx(1, "unknown type %s", optarg);
251 break;
252 case 'u':
253 u2f = true;
254 break;
255 case 'v':
256 uv = true;
257 break;
258 default:
259 usage();
260 }
261 }
262
263 argc -= optind;
264 argv += optind;
265
266 if (argc != 2)
267 usage();
268
269 fido_init(0);
270
271 if ((dev = fido_dev_new()) == NULL)
272 errx(1, "fido_dev_new");
273
274 r = fido_dev_open(dev, argv[1]);
275 if (r != FIDO_OK)
276 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
277 if (u2f)
278 fido_dev_force_u2f(dev);
279
280 /* client data hash */
281 r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
282 if (r != FIDO_OK)
283 errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
284
285 /* relying party */
286 r = fido_assert_set_rp(assert, "localhost");
287 if (r != FIDO_OK)
288 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
289
290 /* extensions */
291 r = fido_assert_set_extensions(assert, ext);
292 if (r != FIDO_OK)
293 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
294 r);
295
296 /* user presence */
297 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
298 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
299
300 /* user verification */
301 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
302 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
303
304 /* timeout */
305 if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
306 errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
307
308 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
309 fido_dev_cancel(dev);
310 errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
311 }
312
313 r = fido_dev_close(dev);
314 if (r != FIDO_OK)
315 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
316
317 fido_dev_free(&dev);
318
319 if (fido_assert_count(assert) != 1)
320 errx(1, "fido_assert_count: %d signatures returned",
321 (int)fido_assert_count(assert));
322
323 /* when verifying, pin implies uv */
324 if (pin)
325 uv = true;
326
327 verify_assert(type, fido_assert_authdata_ptr(assert, 0),
328 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
329 fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]);
330
331 if (hmac_out != NULL) {
332 /* extract the hmac secret */
333 if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0),
334 fido_assert_hmac_secret_len(assert, 0)) < 0)
335 errx(1, "write_blob");
336 }
337
338 if (blobkey_out != NULL) {
339 /* extract the hmac secret */
340 if (write_blob(blobkey_out,
341 fido_assert_largeblob_key_ptr(assert, 0),
342 fido_assert_largeblob_key_len(assert, 0)) < 0)
343 errx(1, "write_blob");
344 }
345
346 fido_assert_free(&assert);
347
348 exit(0);
349 }
350