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