• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-minimal-crypto-cose-key
3  *
4  * Written in 2010-2021 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  */
9 
10 #include <libwebsockets.h>
11 #include <sys/select.h>
12 #include <sys/types.h>
13 #include <stdlib.h>
14 #include <fcntl.h>
15 
16 static int fdin = 0, fdout = 1;
17 
18 static const char *meta_names[] = {
19 	"kty", "kid", "use", "key_ops", "base_iv", "alg"
20 };
21 
22 static const char *oct_names[] = {
23 	"k"
24 };
25 
26 static const char *rsa_names[] = {
27 	"e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
28 };
29 
30 static const char *ec_names[] = {
31 	"crv", "x", "d", "y",
32 };
33 
34 static void
cose_key_dump(const struct lws_cose_key * ck)35 cose_key_dump(const struct lws_cose_key *ck)
36 {
37 	const char **enames;
38 	char hex[2048], dump[3072];
39 	int elems;
40 	size_t l;
41 	int n;
42 
43 	(void)enames;
44 	(void)meta_names;
45 
46 	switch (ck->gencrypto_kty) {
47 
48 	case LWS_GENCRYPTO_KTY_OCT:
49 		elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
50 		enames = oct_names;
51 		break;
52 	case LWS_GENCRYPTO_KTY_RSA:
53 		elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
54 		enames = rsa_names;
55 		break;
56 	case LWS_GENCRYPTO_KTY_EC:
57 		elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
58 		enames = ec_names;
59 		break;
60 
61 	default:
62 		lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
63 
64 		return;
65 	}
66 
67 	for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
68 		if (ck->meta[n].buf) {
69 			if (n < 2) {
70 				l = (size_t)lws_snprintf(dump, sizeof(dump),
71 						 "  %s: %.*s\n", meta_names[n],
72 						 (int)ck->meta[n].len,
73 						 ck->meta[n].buf);
74 				write(fdout, dump, l);
75 			} else {
76 				l = (size_t)lws_snprintf(dump, sizeof(dump),
77 						 "  %s: ", meta_names[n]);
78 				write(fdout, dump, l);
79 				lws_hex_from_byte_array(ck->meta[n].buf,
80 							ck->meta[n].len,
81 							hex, sizeof(hex));
82 				write(fdout, hex, strlen(hex));
83 				write(fdout, "\n", 1);
84 			}
85 		}
86 	}
87 
88 	for (n = 0; n < elems; n++) {
89 		if (ck->e[n].buf) {
90 			if (!n && ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
91 				l = (size_t)lws_snprintf(dump, sizeof(dump),
92 						 "  %s: %.*s\n", enames[n],
93 						 (int)ck->e[n].len,
94 						 ck->e[n].buf);
95 				write(fdout, dump, l);
96 			} else {
97 				l = (size_t)lws_snprintf(dump, sizeof(dump),
98 						 "  %s: ", enames[n]);
99 				write(fdout, dump, l);
100 				lws_hex_from_byte_array(ck->e[n].buf,
101 							ck->e[n].len,
102 							hex, sizeof(hex));
103 				write(fdout, hex, strlen(hex));
104 				write(fdout, "\n", 1);
105 			}
106 		}
107 	}
108 }
109 
main(int argc,const char ** argv)110 int main(int argc, const char **argv)
111 {
112 	uint8_t *kid = NULL, ktmp[4096], set_temp[32 * 1024], temp[256];
113 	int result = 1, bits = 0,
114 	    logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
115 	struct lws_context_creation_info info;
116 	size_t kid_len = 0, stp = 0;
117 	struct lws_context *context;
118 	lws_cose_key_t *ck = NULL;
119 	cose_param_t cose_kty = 0;
120 	lws_dll2_owner_t set;
121 	const char *p, *crv;
122 	lws_lec_pctx_t lec;
123 
124 	if ((p = lws_cmdline_option(argc, argv, "-d")))
125 		logs = atoi(p);
126 
127 	lws_set_log_level(logs, NULL);
128 
129 	lwsl_user("LWS cose-key example tool -k keyset [-s alg-name kid ]\n");
130 
131 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
132 #if defined(LWS_WITH_NETWORK)
133 	info.port = CONTEXT_PORT_NO_LISTEN;
134 #endif
135 
136 	context = lws_create_context(&info);
137 	if (!context) {
138 		lwsl_err("lws init failed\n");
139 		return 1;
140 	}
141 
142 	if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
143 		fdin = open(p, LWS_O_RDONLY, 0);
144 		if (fdin < 0) {
145 			lwsl_err("%s: unable to open stdin file\n", __func__);
146 			return 1;
147 		}
148 	}
149 
150 	if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
151 		fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
152 		if (fdout < 0) {
153 			lwsl_err("%s: unable to open stdout file\n", __func__);
154 			goto bail_early;
155 		}
156 	}
157 
158 	if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
159 		kid = (uint8_t *)p;
160 		kid_len = strlen(p);
161 		//lwsl_hexdump_notice(kid, kid_len);
162 	}
163 
164 	if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
165 		kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
166 		kid = (uint8_t *)ktmp;
167 	}
168 
169 	/*
170 	 * If we have some stdin queued up, we understand we are dumping
171 	 * an existing cose_key or key_set from stdin
172 	 */
173 
174 	if (!fdin) {
175 		struct timeval	timeout;
176 		fd_set	fds;
177 
178 		FD_ZERO(&fds);
179 		FD_SET(0, &fds);
180 
181 		timeout.tv_sec  = 0;
182 		timeout.tv_usec = 1000;
183 
184 		if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0)
185 			goto no_stdin;
186 
187 		if (!FD_ISSET(0, &fds))
188 			goto no_stdin;
189 	}
190 
191 	do {
192 		int n = (int)read(fdin, temp, sizeof(temp));
193 
194 		if (n < 0)
195 			goto bail;
196 		if (!n) {
197 			int kc = 0;
198 
199 			if (!stp)
200 				/* there was no stdin */
201 				break;
202 
203 			lwsl_notice("%s: importing\n", __func__);
204 
205 			lws_dll2_owner_clear(&set);
206 			ck = lws_cose_key_import(&set, NULL, NULL, set_temp, stp);
207 			if (!ck) {
208 				lwsl_err("%s: import failed\n", __func__);
209 				goto bail;
210 			}
211 
212 			lws_start_foreach_dll(struct lws_dll2 *, p,
213 						lws_dll2_get_head(&set)) {
214 				lws_cose_key_t *ck = lws_container_of(p,
215 							lws_cose_key_t, list);
216 				struct lws_gencrypto_keyelem *ke =
217 						&ck->meta[COSEKEY_META_KID];
218 
219 				kc++;
220 
221 				if (!kid_len || (ke->len &&
222 				    ke->len == (uint32_t)kid_len &&
223 				    !memcmp(ke->buf, kid, kid_len))) {
224 					    printf("Cose key #%d\n", kc);
225 					    cose_key_dump(ck);
226 				}
227 
228 			} lws_end_foreach_dll(p);
229 
230 			lws_cose_key_set_destroy(&set);
231 			result = 0;
232 			goto bail;
233 
234 		}
235 
236 		if (stp + (size_t)n > sizeof(set_temp)) {
237 			lwsl_err("%s: stdin bigger than our buffer\n", __func__);
238 			goto bail;
239 		}
240 		memcpy(set_temp + stp, temp, (size_t)n);
241 		stp += (size_t)n;
242 	} while (1);
243 
244 no_stdin:
245 
246 	/*
247 	 *
248 	 */
249 
250 	p = lws_cmdline_option(argc, argv, "--kty");
251 	if (!p) {
252 		lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
253 					__func__);
254 		goto bail;
255 	}
256 
257 	if (!strcmp(p, "OKP"))
258 		cose_kty = LWSCOSE_WKKTV_OKP;
259 	if (!strcmp(p, "EC2"))
260 		cose_kty = LWSCOSE_WKKTV_EC2;
261 	if (!strcmp(p, "RSA"))
262 		cose_kty = LWSCOSE_WKKTV_RSA;
263 	if (!strcmp(p, "SYMMETRIC") || !strcmp(p, "SYM"))
264 		cose_kty = LWSCOSE_WKKTV_SYMMETRIC;
265 
266 	if (!cose_kty) {
267 		lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
268 			 __func__);
269 		goto bail;
270 	}
271 
272 	crv = NULL;
273 	if (cose_kty == LWSCOSE_WKKTV_OKP ||
274 	    cose_kty == LWSCOSE_WKKTV_EC2) {
275 		crv = lws_cmdline_option(argc, argv, "--curve");
276 		if (!crv) {
277 			lwsl_err("%s: use --curve P-256 etc\n", __func__);
278 			goto bail;
279 		}
280 	}
281 
282 	p = lws_cmdline_option(argc, argv, "--bits");
283 	if (p)
284 		bits = atoi(p);
285 
286 	ck = lws_cose_key_generate(context, cose_kty, 0, bits, crv,
287 				   kid, kid_len);
288 	if (!ck)
289 		goto bail;
290 
291 	lws_lec_init(&lec, ktmp, sizeof(ktmp));
292 	lws_cose_key_export(ck, &lec, LWSJWKF_EXPORT_PRIVATE);
293 	write(fdout, ktmp, lec.used);
294 
295 	lws_cose_key_destroy(&ck);
296 	result = 0;
297 
298 bail:
299 	lws_context_destroy(context);
300 
301 	if (result)
302 		lwsl_err("%s: FAIL: %d\n", __func__, result);
303 	else
304 		lwsl_notice("%s: PASS\n", __func__);
305 
306 bail_early:
307 	if (fdin > 0)
308 		close(fdin);
309 	if (fdout != 1 && fdout >= 0)
310 		close(fdout);
311 
312 	return result;
313 }
314