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