xref: /freebsd/contrib/libfido2/examples/assert.c (revision 4f8f43b06ed07e96a250855488cc531799d5b78f)
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
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
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
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