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 <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 cdh[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
usage(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
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)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_hash(assert, cdh, sizeof(cdh));
110 if (r != FIDO_OK)
111 errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
112 fido_strerr(r), r);
113
114 /* relying party */
115 r = fido_assert_set_rp(assert, "localhost");
116 if (r != FIDO_OK)
117 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
118
119 /* authdata */
120 r = fido_assert_set_count(assert, 1);
121 if (r != FIDO_OK)
122 errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r);
123 r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len);
124 if (r != FIDO_OK)
125 errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r);
126
127 /* extension */
128 r = fido_assert_set_extensions(assert, ext);
129 if (r != FIDO_OK)
130 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
131 r);
132
133 /* user presence */
134 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
135 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
136
137 /* user verification */
138 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
139 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
140
141 /* sig */
142 r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
143 if (r != FIDO_OK)
144 errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r);
145
146 r = fido_assert_verify(assert, 0, type, pk);
147 if (r != FIDO_OK)
148 errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r);
149
150 es256_pk_free(&es256_pk);
151 rs256_pk_free(&rs256_pk);
152 eddsa_pk_free(&eddsa_pk);
153
154 fido_assert_free(&assert);
155 }
156
157 int
main(int argc,char ** argv)158 main(int argc, char **argv)
159 {
160 bool up = false;
161 bool uv = false;
162 bool u2f = false;
163 fido_dev_t *dev = NULL;
164 fido_assert_t *assert = NULL;
165 const char *pin = NULL;
166 const char *blobkey_out = 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:b: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 'b':
206 ext |= FIDO_EXT_LARGEBLOB_KEY;
207 blobkey_out = optarg;
208 break;
209 case 'h':
210 hmac_out = optarg;
211 break;
212 case 'p':
213 up = true;
214 break;
215 case 's':
216 ext |= FIDO_EXT_HMAC_SECRET;
217 if (read_blob(optarg, &body, &len) < 0)
218 errx(1, "read_blob: %s", optarg);
219 if ((r = fido_assert_set_hmac_salt(assert, body,
220 len)) != FIDO_OK)
221 errx(1, "fido_assert_set_hmac_salt: %s (0x%x)",
222 fido_strerr(r), r);
223 free(body);
224 body = NULL;
225 break;
226 case 't':
227 if (strcmp(optarg, "ecdsa") == 0)
228 type = COSE_ES256;
229 else if (strcmp(optarg, "rsa") == 0)
230 type = COSE_RS256;
231 else if (strcmp(optarg, "eddsa") == 0)
232 type = COSE_EDDSA;
233 else
234 errx(1, "unknown type %s", optarg);
235 break;
236 case 'u':
237 u2f = true;
238 break;
239 case 'v':
240 uv = true;
241 break;
242 default:
243 usage();
244 }
245 }
246
247 argc -= optind;
248 argv += optind;
249
250 if (argc != 2)
251 usage();
252
253 fido_init(0);
254
255 if ((dev = fido_dev_new()) == NULL)
256 errx(1, "fido_dev_new");
257
258 r = fido_dev_open(dev, argv[1]);
259 if (r != FIDO_OK)
260 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
261 if (u2f)
262 fido_dev_force_u2f(dev);
263
264 /* client data hash */
265 r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh));
266 if (r != FIDO_OK)
267 errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
268 fido_strerr(r), r);
269
270 /* relying party */
271 r = fido_assert_set_rp(assert, "localhost");
272 if (r != FIDO_OK)
273 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
274
275 /* extensions */
276 r = fido_assert_set_extensions(assert, ext);
277 if (r != FIDO_OK)
278 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
279 r);
280
281 /* user presence */
282 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
283 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
284
285 /* user verification */
286 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
287 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
288
289 #ifdef SIGNAL_EXAMPLE
290 prepare_signal_handler(SIGINT);
291 if (seconds) {
292 prepare_signal_handler(SIGALRM);
293 alarm((unsigned)seconds);
294 }
295 #endif
296
297 r = fido_dev_get_assert(dev, assert, pin);
298 if (r != FIDO_OK) {
299 #ifdef SIGNAL_EXAMPLE
300 if (got_signal)
301 fido_dev_cancel(dev);
302 #endif
303 errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
304 }
305
306 r = fido_dev_close(dev);
307 if (r != FIDO_OK)
308 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
309
310 fido_dev_free(&dev);
311
312 if (fido_assert_count(assert) != 1)
313 errx(1, "fido_assert_count: %d signatures returned",
314 (int)fido_assert_count(assert));
315
316 /* when verifying, pin implies uv */
317 if (pin)
318 uv = true;
319
320 verify_assert(type, fido_assert_authdata_ptr(assert, 0),
321 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
322 fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]);
323
324 if (hmac_out != NULL) {
325 /* extract the hmac secret */
326 if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0),
327 fido_assert_hmac_secret_len(assert, 0)) < 0)
328 errx(1, "write_blob");
329 }
330
331 if (blobkey_out != NULL) {
332 /* extract the hmac secret */
333 if (write_blob(blobkey_out,
334 fido_assert_largeblob_key_ptr(assert, 0),
335 fido_assert_largeblob_key_len(assert, 0)) < 0)
336 errx(1, "write_blob");
337 }
338
339 fido_assert_free(&assert);
340
341 exit(0);
342 }
343