assert.c revision 1.1.1.2 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