diff options
Diffstat (limited to 'examples/cred.c')
-rw-r--r-- | examples/cred.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/examples/cred.c b/examples/cred.c new file mode 100644 index 0000000..e471f7e --- /dev/null +++ b/examples/cred.c | |||
@@ -0,0 +1,303 @@ | |||
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 | #include <openssl/pem.h> | ||
9 | |||
10 | #include <errno.h> | ||
11 | #include <stdbool.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #ifdef HAVE_UNISTD_H | ||
16 | #include <unistd.h> | ||
17 | #endif | ||
18 | |||
19 | #include "../openbsd-compat/openbsd-compat.h" | ||
20 | |||
21 | #include "fido.h" | ||
22 | #include "extern.h" | ||
23 | |||
24 | #ifdef SIGNAL_EXAMPLE | ||
25 | extern volatile sig_atomic_t got_signal; | ||
26 | #endif | ||
27 | |||
28 | static const unsigned char cdh[32] = { | ||
29 | 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, | ||
30 | 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, | ||
31 | 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, | ||
32 | 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, | ||
33 | }; | ||
34 | |||
35 | static const unsigned char user_id[32] = { | ||
36 | 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, | ||
37 | 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, | ||
38 | 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, | ||
39 | 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, | ||
40 | }; | ||
41 | |||
42 | static void | ||
43 | usage(void) | ||
44 | { | ||
45 | fprintf(stderr, "usage: cred [-t ecdsa|rsa|eddsa] [-k pubkey] " | ||
46 | "[-ei cred_id] [-P pin] [-T seconds] [-hruv] <device>\n"); | ||
47 | exit(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | static void | ||
51 | verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr, | ||
52 | size_t authdata_len, const unsigned char *x509_ptr, size_t x509_len, | ||
53 | const unsigned char *sig_ptr, size_t sig_len, bool rk, bool uv, int ext, | ||
54 | const char *key_out, const char *id_out) | ||
55 | { | ||
56 | fido_cred_t *cred; | ||
57 | int r; | ||
58 | |||
59 | if ((cred = fido_cred_new()) == NULL) | ||
60 | errx(1, "fido_cred_new"); | ||
61 | |||
62 | /* type */ | ||
63 | r = fido_cred_set_type(cred, type); | ||
64 | if (r != FIDO_OK) | ||
65 | errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); | ||
66 | |||
67 | /* client data hash */ | ||
68 | r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); | ||
69 | if (r != FIDO_OK) | ||
70 | errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", | ||
71 | fido_strerr(r), r); | ||
72 | |||
73 | /* relying party */ | ||
74 | r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); | ||
75 | if (r != FIDO_OK) | ||
76 | errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
77 | |||
78 | /* authdata */ | ||
79 | r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len); | ||
80 | if (r != FIDO_OK) | ||
81 | errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r); | ||
82 | |||
83 | /* extensions */ | ||
84 | r = fido_cred_set_extensions(cred, ext); | ||
85 | if (r != FIDO_OK) | ||
86 | errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); | ||
87 | |||
88 | /* resident key */ | ||
89 | if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
90 | errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); | ||
91 | |||
92 | /* user verification */ | ||
93 | if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
94 | errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
95 | |||
96 | /* x509 */ | ||
97 | r = fido_cred_set_x509(cred, x509_ptr, x509_len); | ||
98 | if (r != FIDO_OK) | ||
99 | errx(1, "fido_cred_set_x509: %s (0x%x)", fido_strerr(r), r); | ||
100 | |||
101 | /* sig */ | ||
102 | r = fido_cred_set_sig(cred, sig_ptr, sig_len); | ||
103 | if (r != FIDO_OK) | ||
104 | errx(1, "fido_cred_set_sig: %s (0x%x)", fido_strerr(r), r); | ||
105 | |||
106 | /* fmt */ | ||
107 | r = fido_cred_set_fmt(cred, fmt); | ||
108 | if (r != FIDO_OK) | ||
109 | errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r); | ||
110 | |||
111 | r = fido_cred_verify(cred); | ||
112 | if (r != FIDO_OK) | ||
113 | errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r); | ||
114 | |||
115 | if (key_out != NULL) { | ||
116 | /* extract the credential pubkey */ | ||
117 | if (type == COSE_ES256) { | ||
118 | if (write_ec_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
119 | fido_cred_pubkey_len(cred)) < 0) | ||
120 | errx(1, "write_ec_pubkey"); | ||
121 | } else if (type == COSE_RS256) { | ||
122 | if (write_rsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
123 | fido_cred_pubkey_len(cred)) < 0) | ||
124 | errx(1, "write_rsa_pubkey"); | ||
125 | } else if (type == COSE_EDDSA) { | ||
126 | if (write_eddsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
127 | fido_cred_pubkey_len(cred)) < 0) | ||
128 | errx(1, "write_eddsa_pubkey"); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (id_out != NULL) { | ||
133 | /* extract the credential id */ | ||
134 | if (write_blob(id_out, fido_cred_id_ptr(cred), | ||
135 | fido_cred_id_len(cred)) < 0) | ||
136 | errx(1, "write_blob"); | ||
137 | } | ||
138 | |||
139 | fido_cred_free(&cred); | ||
140 | } | ||
141 | |||
142 | int | ||
143 | main(int argc, char **argv) | ||
144 | { | ||
145 | bool rk = false; | ||
146 | bool uv = false; | ||
147 | bool u2f = false; | ||
148 | fido_dev_t *dev; | ||
149 | fido_cred_t *cred = NULL; | ||
150 | const char *pin = NULL; | ||
151 | const char *key_out = NULL; | ||
152 | const char *id_out = NULL; | ||
153 | unsigned char *body = NULL; | ||
154 | long long seconds = 0; | ||
155 | size_t len; | ||
156 | int type = COSE_ES256; | ||
157 | int ext = 0; | ||
158 | int ch; | ||
159 | int r; | ||
160 | |||
161 | if ((cred = fido_cred_new()) == NULL) | ||
162 | errx(1, "fido_cred_new"); | ||
163 | |||
164 | while ((ch = getopt(argc, argv, "P:T:e:hi:k:rt:uv")) != -1) { | ||
165 | switch (ch) { | ||
166 | case 'P': | ||
167 | pin = optarg; | ||
168 | break; | ||
169 | case 'T': | ||
170 | #ifndef SIGNAL_EXAMPLE | ||
171 | errx(1, "-T not supported"); | ||
172 | #endif | ||
173 | if (base10(optarg, &seconds) < 0) | ||
174 | errx(1, "base10: %s", optarg); | ||
175 | if (seconds <= 0 || seconds > 30) | ||
176 | errx(1, "-T: %s must be in (0,30]", optarg); | ||
177 | break; | ||
178 | case 'e': | ||
179 | if (read_blob(optarg, &body, &len) < 0) | ||
180 | errx(1, "read_blob: %s", optarg); | ||
181 | r = fido_cred_exclude(cred, body, len); | ||
182 | if (r != FIDO_OK) | ||
183 | errx(1, "fido_cred_exclude: %s (0x%x)", | ||
184 | fido_strerr(r), r); | ||
185 | free(body); | ||
186 | body = NULL; | ||
187 | break; | ||
188 | case 'h': | ||
189 | ext = FIDO_EXT_HMAC_SECRET; | ||
190 | break; | ||
191 | case 'i': | ||
192 | id_out = optarg; | ||
193 | break; | ||
194 | case 'k': | ||
195 | key_out = optarg; | ||
196 | break; | ||
197 | case 'r': | ||
198 | rk = true; | ||
199 | break; | ||
200 | case 't': | ||
201 | if (strcmp(optarg, "ecdsa") == 0) | ||
202 | type = COSE_ES256; | ||
203 | else if (strcmp(optarg, "rsa") == 0) | ||
204 | type = COSE_RS256; | ||
205 | else if (strcmp(optarg, "eddsa") == 0) | ||
206 | type = COSE_EDDSA; | ||
207 | else | ||
208 | errx(1, "unknown type %s", optarg); | ||
209 | break; | ||
210 | case 'u': | ||
211 | u2f = true; | ||
212 | break; | ||
213 | case 'v': | ||
214 | uv = true; | ||
215 | break; | ||
216 | default: | ||
217 | usage(); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | argc -= optind; | ||
222 | argv += optind; | ||
223 | |||
224 | if (argc != 1) | ||
225 | usage(); | ||
226 | |||
227 | fido_init(0); | ||
228 | |||
229 | if ((dev = fido_dev_new()) == NULL) | ||
230 | errx(1, "fido_dev_new"); | ||
231 | |||
232 | if ((r = fido_dev_open(dev, argv[0])) != FIDO_OK) | ||
233 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
234 | if (u2f) | ||
235 | fido_dev_force_u2f(dev); | ||
236 | |||
237 | /* type */ | ||
238 | r = fido_cred_set_type(cred, type); | ||
239 | if (r != FIDO_OK) | ||
240 | errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); | ||
241 | |||
242 | /* client data hash */ | ||
243 | r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); | ||
244 | if (r != FIDO_OK) | ||
245 | errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", | ||
246 | fido_strerr(r), r); | ||
247 | |||
248 | /* relying party */ | ||
249 | r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); | ||
250 | if (r != FIDO_OK) | ||
251 | errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
252 | |||
253 | /* user */ | ||
254 | r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith", | ||
255 | "jsmith", NULL); | ||
256 | if (r != FIDO_OK) | ||
257 | errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r); | ||
258 | |||
259 | /* extensions */ | ||
260 | r = fido_cred_set_extensions(cred, ext); | ||
261 | if (r != FIDO_OK) | ||
262 | errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); | ||
263 | |||
264 | /* resident key */ | ||
265 | if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
266 | errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); | ||
267 | |||
268 | /* user verification */ | ||
269 | if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
270 | errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
271 | |||
272 | #ifdef SIGNAL_EXAMPLE | ||
273 | prepare_signal_handler(SIGINT); | ||
274 | if (seconds) { | ||
275 | prepare_signal_handler(SIGALRM); | ||
276 | alarm((unsigned)seconds); | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | r = fido_dev_make_cred(dev, cred, pin); | ||
281 | if (r != FIDO_OK) { | ||
282 | #ifdef SIGNAL_EXAMPLE | ||
283 | if (got_signal) | ||
284 | fido_dev_cancel(dev); | ||
285 | #endif | ||
286 | errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r); | ||
287 | } | ||
288 | |||
289 | r = fido_dev_close(dev); | ||
290 | if (r != FIDO_OK) | ||
291 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
292 | |||
293 | fido_dev_free(&dev); | ||
294 | |||
295 | verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), | ||
296 | fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), | ||
297 | fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), | ||
298 | fido_cred_sig_len(cred), rk, uv, ext, key_out, id_out); | ||
299 | |||
300 | fido_cred_free(&cred); | ||
301 | |||
302 | exit(0); | ||
303 | } | ||