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