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