1 /*
2  * lws-crypto-jwk
3  *
4  * Written in 2010-2019 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/types.h>
12 #include <fcntl.h>
13 
14 /*
15  * handles escapes and line wrapping suitable for use
16  * defining a C char array ( -c option )
17  */
18 
19 static int
format_c(int fd,const char * key)20 format_c(int fd, const char *key)
21 {
22 	const char *k = key;
23 	int seq = 0;
24 
25 	while (*k) {
26 		if (*k == '{') {
27 			if (write(fd, "\"{\"\n\t\"", 6) < 6)
28 				return -1;
29 			k++;
30 			seq = 0;
31 			continue;
32 		}
33 		if (*k == '}') {
34 			if (write(fd, "\"\n\"}\"\n", 6) < 6)
35 				return -1;
36 			k++;
37 			seq = 0;
38 			continue;
39 		}
40 		if (*k == '\"') {
41 			if (write(fd, "\\\"", 2) < 2)
42 				return -1;
43 			seq += 2;
44 			k++;
45 			continue;
46 		}
47 		if (*k == ',') {
48 			if (write(fd, ",\"\n\t\"", 5) < 5)
49 				return -1;
50 			k++;
51 			seq = 0;
52 			continue;
53 		}
54 		if (write(fd, k, 1) < 1)
55 			return -1;
56 		seq++;
57 		if (seq >= 60) {
58 			if (write(fd, "\"\n\t \"", 5) < 5)
59 				return -1;
60 			seq = 1;
61 		}
62 		k++;
63 	}
64 
65 	return 0;
66 }
67 
main(int argc,const char ** argv)68 int main(int argc, const char **argv)
69 {
70 	int result = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
71 	enum lws_gencrypto_kty kty = LWS_GENCRYPTO_KTY_RSA;
72 	struct lws_context_creation_info info;
73 	const char *curve = "P-256", *p;
74 	struct lws_context *context;
75 	struct lws_jwk jwk;
76 	int bits = 4096;
77 	char key[32768];
78 	int vl = sizeof(key);
79 
80 	if ((p = lws_cmdline_option(argc, argv, "-d")))
81 		logs = atoi(p);
82 
83 	lws_set_log_level(logs, NULL);
84 	lwsl_user("LWS JWK example\n");
85 
86 	if ((p = lws_cmdline_option(argc, argv, "-b")))
87 		bits = atoi(p);
88 
89 	if ((p = lws_cmdline_option(argc, argv, "-t"))) {
90 		if (!strcmp(p, "RSA"))
91 			kty = LWS_GENCRYPTO_KTY_RSA;
92 		else
93 			if (!strcmp(p, "OCT"))
94 				kty = LWS_GENCRYPTO_KTY_OCT;
95 			else
96 				if (!strcmp(p, "EC"))
97 					kty = LWS_GENCRYPTO_KTY_EC;
98 				else {
99 					lwsl_err("Unknown key type (must be "
100 						 "OCT, RSA or EC)\n");
101 
102 					return 1;
103 				}
104 	}
105 
106 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
107 	info.port = CONTEXT_PORT_NO_LISTEN;
108 	info.options = 0;
109 
110 	context = lws_create_context(&info);
111 	if (!context) {
112 		lwsl_err("lws init failed\n");
113 		return 1;
114 	}
115 
116 	if ((p = lws_cmdline_option(argc, argv, "-v")))
117 		curve = p;
118 
119 	if (lws_jwk_generate(context, &jwk, kty, bits, curve)) {
120 		lwsl_err("lws_jwk_generate failed\n");
121 
122 		return 1;
123 	}
124 
125 	if ((p = lws_cmdline_option(argc, argv, "--kid")))
126 		lws_jwk_strdup_meta(&jwk, JWK_META_KID, p, strlen(p));
127 
128 	if ((p = lws_cmdline_option(argc, argv, "--use")))
129 		lws_jwk_strdup_meta(&jwk, JWK_META_USE, p, strlen(p));
130 
131 	if ((p = lws_cmdline_option(argc, argv, "--alg")))
132 		lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, strlen(p));
133 
134 	if ((p = lws_cmdline_option(argc, argv, "--key-ops")))
135 		lws_jwk_strdup_meta(&jwk, JWK_META_KEY_OPS, p, strlen(p));
136 
137 	if ((p = lws_cmdline_option(argc, argv, "--public")) &&
138 	    kty != LWS_GENCRYPTO_KTY_OCT) {
139 
140 		int fd;
141 
142 		/* public version */
143 
144 		if (lws_jwk_export(&jwk, 0, key, &vl) < 0) {
145 			lwsl_err("lws_jwk_export failed\n");
146 
147 			return 1;
148 		}
149 
150 		fd = open(p, LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
151 		if (fd < 0) {
152 			lwsl_err("Can't open public key file %s\n", p);
153 			return 1;
154 		}
155 
156 		if (lws_cmdline_option(argc, argv, "-c"))
157 			format_c(fd, key);
158 		else {
159 			if (write(fd, key, strlen(key)) < 0) {
160 				lwsl_err("Write public failed\n");
161 				return 1;
162 			}
163 		}
164 
165 		close(fd);
166 	}
167 
168 	/* private version */
169 
170 	if (lws_jwk_export(&jwk, LWSJWKF_EXPORT_PRIVATE, key, &vl) < 0) {
171 		lwsl_err("lws_jwk_export failed\n");
172 
173 		return 1;
174 	}
175 
176 	if (lws_cmdline_option(argc, argv, "-c")) {
177 		if (format_c(1, key) < 0)
178 			return 1;
179 	} else
180 		if (write(1, key, strlen(key)) < 0) {
181 			lwsl_err("Write stdout failed\n");
182 			return 1;
183 		}
184 
185 	lws_jwk_destroy(&jwk);
186 
187 	lws_context_destroy(context);
188 
189 	return result;
190 }
191