diff options
Diffstat (limited to 'tools/cred_make.c')
-rw-r--r-- | tools/cred_make.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/tools/cred_make.c b/tools/cred_make.c new file mode 100644 index 0000000..380c67a --- /dev/null +++ b/tools/cred_make.c | |||
@@ -0,0 +1,221 @@ | |||
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 <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | static fido_cred_t * | ||
19 | prepare_cred(FILE *in_f, int type, int flags) | ||
20 | { | ||
21 | fido_cred_t *cred = NULL; | ||
22 | struct blob cdh; | ||
23 | struct blob uid; | ||
24 | char *rpid = NULL; | ||
25 | char *uname = NULL; | ||
26 | int r; | ||
27 | |||
28 | memset(&cdh, 0, sizeof(cdh)); | ||
29 | memset(&uid, 0, sizeof(uid)); | ||
30 | |||
31 | r = base64_read(in_f, &cdh); | ||
32 | r |= string_read(in_f, &rpid); | ||
33 | r |= string_read(in_f, &uname); | ||
34 | r |= base64_read(in_f, &uid); | ||
35 | if (r < 0) | ||
36 | errx(1, "input error"); | ||
37 | |||
38 | if (flags & FLAG_DEBUG) { | ||
39 | fprintf(stderr, "client data hash:\n"); | ||
40 | xxd(cdh.ptr, cdh.len); | ||
41 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
42 | fprintf(stderr, "user name: %s\n", uname); | ||
43 | fprintf(stderr, "user id:\n"); | ||
44 | xxd(uid.ptr, uid.len); | ||
45 | } | ||
46 | |||
47 | if ((cred = fido_cred_new()) == NULL) | ||
48 | errx(1, "fido_cred_new"); | ||
49 | |||
50 | if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || | ||
51 | (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, | ||
52 | cdh.len)) != FIDO_OK || | ||
53 | (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || | ||
54 | (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, | ||
55 | NULL)) != FIDO_OK) | ||
56 | errx(1, "fido_cred_set: %s", fido_strerr(r)); | ||
57 | |||
58 | if (flags & FLAG_RK) { | ||
59 | if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
60 | errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); | ||
61 | } | ||
62 | if (flags & FLAG_UV) { | ||
63 | if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
64 | errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); | ||
65 | } | ||
66 | if (flags & FLAG_HMAC) { | ||
67 | if ((r = fido_cred_set_extensions(cred, | ||
68 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
69 | errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); | ||
70 | } | ||
71 | |||
72 | free(cdh.ptr); | ||
73 | free(uid.ptr); | ||
74 | free(rpid); | ||
75 | free(uname); | ||
76 | |||
77 | return (cred); | ||
78 | } | ||
79 | |||
80 | static void | ||
81 | print_attcred(FILE *out_f, const fido_cred_t *cred) | ||
82 | { | ||
83 | char *cdh = NULL; | ||
84 | char *authdata = NULL; | ||
85 | char *id = NULL; | ||
86 | char *sig = NULL; | ||
87 | char *x5c = NULL; | ||
88 | int r; | ||
89 | |||
90 | r = base64_encode(fido_cred_clientdata_hash_ptr(cred), | ||
91 | fido_cred_clientdata_hash_len(cred), &cdh); | ||
92 | r |= base64_encode(fido_cred_authdata_ptr(cred), | ||
93 | fido_cred_authdata_len(cred), &authdata); | ||
94 | r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), | ||
95 | &id); | ||
96 | r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), | ||
97 | &sig); | ||
98 | if (fido_cred_x5c_ptr(cred) != NULL) | ||
99 | r |= base64_encode(fido_cred_x5c_ptr(cred), | ||
100 | fido_cred_x5c_len(cred), &x5c); | ||
101 | if (r < 0) | ||
102 | errx(1, "output error"); | ||
103 | |||
104 | fprintf(out_f, "%s\n", cdh); | ||
105 | fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); | ||
106 | fprintf(out_f, "%s\n", fido_cred_fmt(cred)); | ||
107 | fprintf(out_f, "%s\n", authdata); | ||
108 | fprintf(out_f, "%s\n", id); | ||
109 | fprintf(out_f, "%s\n", sig); | ||
110 | if (x5c != NULL) | ||
111 | fprintf(out_f, "%s\n", x5c); | ||
112 | |||
113 | free(cdh); | ||
114 | free(authdata); | ||
115 | free(id); | ||
116 | free(sig); | ||
117 | free(x5c); | ||
118 | } | ||
119 | |||
120 | int | ||
121 | cred_make(int argc, char **argv) | ||
122 | { | ||
123 | fido_dev_t *dev = NULL; | ||
124 | fido_cred_t *cred = NULL; | ||
125 | char prompt[1024]; | ||
126 | char pin[1024]; | ||
127 | char *in_path = NULL; | ||
128 | char *out_path = NULL; | ||
129 | FILE *in_f = NULL; | ||
130 | FILE *out_f = NULL; | ||
131 | int type = COSE_ES256; | ||
132 | int flags = 0; | ||
133 | int ch; | ||
134 | int r; | ||
135 | |||
136 | while ((ch = getopt(argc, argv, "dhi:o:qruv")) != -1) { | ||
137 | switch (ch) { | ||
138 | case 'd': | ||
139 | flags |= FLAG_DEBUG; | ||
140 | break; | ||
141 | case 'h': | ||
142 | flags |= FLAG_HMAC; | ||
143 | break; | ||
144 | case 'i': | ||
145 | in_path = optarg; | ||
146 | break; | ||
147 | case 'o': | ||
148 | out_path = optarg; | ||
149 | break; | ||
150 | case 'q': | ||
151 | flags |= FLAG_QUIET; | ||
152 | break; | ||
153 | case 'r': | ||
154 | flags |= FLAG_RK; | ||
155 | break; | ||
156 | case 'u': | ||
157 | flags |= FLAG_U2F; | ||
158 | break; | ||
159 | case 'v': | ||
160 | flags |= FLAG_UV; | ||
161 | break; | ||
162 | default: | ||
163 | usage(); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | argc -= optind; | ||
168 | argv += optind; | ||
169 | |||
170 | if (argc < 1 || argc > 2) | ||
171 | usage(); | ||
172 | |||
173 | in_f = open_read(in_path); | ||
174 | out_f = open_write(out_path); | ||
175 | |||
176 | if (argc > 1) { | ||
177 | if (strcmp(argv[1], "es256") == 0) | ||
178 | type = COSE_ES256; | ||
179 | else if (strcmp(argv[1], "rs256") == 0) | ||
180 | type = COSE_RS256; | ||
181 | else if (strcmp(argv[1], "eddsa") == 0) | ||
182 | type = COSE_EDDSA; | ||
183 | else | ||
184 | errx(1, "unknown type %s", argv[1]); | ||
185 | } | ||
186 | |||
187 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
188 | |||
189 | cred = prepare_cred(in_f, type, flags); | ||
190 | |||
191 | dev = open_dev(argv[0]); | ||
192 | if (flags & FLAG_U2F) | ||
193 | fido_dev_force_u2f(dev); | ||
194 | |||
195 | r = fido_dev_make_cred(dev, cred, NULL); | ||
196 | if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { | ||
197 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", | ||
198 | argv[0]); | ||
199 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
200 | errx(1, "snprintf"); | ||
201 | if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) | ||
202 | errx(1, "readpassphrase"); | ||
203 | r = fido_dev_make_cred(dev, cred, pin); | ||
204 | } | ||
205 | |||
206 | explicit_bzero(pin, sizeof(pin)); | ||
207 | if (r != FIDO_OK) | ||
208 | errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); | ||
209 | print_attcred(out_f, cred); | ||
210 | |||
211 | fido_dev_close(dev); | ||
212 | fido_dev_free(&dev); | ||
213 | fido_cred_free(&cred); | ||
214 | |||
215 | fclose(in_f); | ||
216 | fclose(out_f); | ||
217 | in_f = NULL; | ||
218 | out_f = NULL; | ||
219 | |||
220 | exit(0); | ||
221 | } | ||