• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-crypto-jws
3  *
4  * Written in 2010-2020 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 #define MAX_SIZE (4 * 1024 * 1024)
15 char temp[MAX_SIZE], compact[MAX_SIZE];
16 
main(int argc,const char ** argv)17 int main(int argc, const char **argv)
18 {
19 	int n, sign = 0, result = 0,
20 	    logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
21 	char *in;
22 	struct lws_context_creation_info info;
23 	struct lws_jws_map map;
24 	int temp_len = sizeof(temp);
25 	struct lws_context *context;
26 	struct lws_jose jose;
27 	struct lws_jwk jwk;
28 	struct lws_jws jws;
29 	const char *p;
30 
31 	if ((p = lws_cmdline_option(argc, argv, "-d")))
32 		logs = atoi(p);
33 
34 	lws_set_log_level(logs, NULL);
35 	lwsl_user("LWS JWS example tool\n");
36 
37 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
38 #if defined(LWS_WITH_NETWORK)
39 	info.port = CONTEXT_PORT_NO_LISTEN;
40 #endif
41 	info.options = 0;
42 
43 	context = lws_create_context(&info);
44 	if (!context) {
45 		lwsl_err("lws init failed\n");
46 		return 1;
47 	}
48 
49 	lws_jose_init(&jose);
50 	lws_jws_init(&jws, &jwk, context);
51 
52 	/* if signing, set the ciphers */
53 
54 	if ((p = lws_cmdline_option(argc, argv, "-s"))) {
55 
56 		if (lws_gencrypto_jws_alg_to_definition(p, &jose.alg)) {
57 			lwsl_err("format: -s \"<jws cipher alg>\", eg, "
58 				 "-e \"RS256\"\n");
59 
60 			return 1;
61 		}
62 
63 		/* create JOSE header, also needed for output */
64 
65 		if (lws_jws_alloc_element(&jws.map, LJWS_JOSE,
66 				      lws_concat_temp(temp, temp_len),
67 				      &temp_len, strlen(p) + 10, 0)) {
68 			lwsl_err("%s: temp space too small\n", __func__);
69 			return 1;
70 		}
71 
72 		jws.map.len[LJWS_JOSE] = (uint32_t)
73 				lws_snprintf((char *)jws.map.buf[LJWS_JOSE],
74 					     (unsigned int)temp_len, "{\"alg\":\"%s\"}", p);
75 		sign = 1;
76 	}
77 
78 	in = lws_concat_temp(temp, temp_len);
79 	n = (int)read(0, in, (unsigned int)temp_len);
80 	if (n < 0) {
81 		lwsl_err("Problem reading from stdin\n");
82 		return 1;
83 	}
84 	temp_len -= n;
85 
86 	/* grab the key */
87 
88 	if ((p = lws_cmdline_option(argc, argv, "-k"))) {
89 		if (lws_jwk_load(&jwk, p, NULL, NULL)) {
90 			lwsl_err("%s: problem loading JWK %s\n", __func__, p);
91 
92 			return 1;
93 		}
94 	} else {
95 		lwsl_err("-k <jwk file> is required\n");
96 
97 		return 1;
98 	}
99 	if (sign) {
100 
101 		/* add the plaintext from stdin to the map and a b64 version */
102 
103 		jws.map.buf[LJWS_PYLD] = in;
104 		jws.map.len[LJWS_PYLD] = (unsigned int)n;
105 
106 		if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD,
107 					       lws_concat_temp(temp, temp_len),
108 					       &temp_len, jws.map.buf[LJWS_PYLD],
109 					       jws.map.len[LJWS_PYLD]))
110 			goto bail1;
111 
112 		/* add the b64 JOSE header to the b64 map */
113 
114 		if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE,
115 					       lws_concat_temp(temp, temp_len),
116 					       &temp_len, jws.map.buf[LJWS_JOSE],
117 					       jws.map.len[LJWS_JOSE]))
118 			goto bail1;
119 
120 		/* prepare the space for the b64 signature in the map */
121 
122 		if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG,
123 				      lws_concat_temp(temp, temp_len),
124 				      &temp_len, (unsigned int)lws_base64_size(
125 					 LWS_JWE_LIMIT_KEY_ELEMENT_BYTES), 0)) {
126 			lwsl_err("%s: temp space too small\n", __func__);
127 			goto bail1;
128 		}
129 
130 
131 
132 		/* sign the plaintext */
133 
134 		n = lws_jws_sign_from_b64(&jose, &jws,
135 					  (char *)jws.map_b64.buf[LJWS_SIG],
136 					  jws.map_b64.len[LJWS_SIG]);
137 		if (n < 0) {
138 			lwsl_err("%s: failed signing test packet\n", __func__);
139 			goto bail1;
140 		}
141 		/* set the actual b64 signature size */
142 		jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
143 
144 		if (lws_cmdline_option(argc, argv, "-f"))
145 			/* create the flattened representation */
146 			n = lws_jws_write_flattened_json(&jws, compact, sizeof(compact));
147 		else
148 			/* create the compact JWS representation */
149 			n = lws_jws_write_compact(&jws, compact, sizeof(compact));
150 		if (n < 0) {
151 			lwsl_notice("%s: write_compact failed\n", __func__);
152 			goto bail1;
153 		}
154 
155 		/* dump the compact JWS representation on stdout */
156 
157 		if (write(1, compact,
158 #if defined(WIN32)
159 				(unsigned int)
160 #endif
161 				strlen(compact))  < 0) {
162 			lwsl_err("Write stdout failed\n");
163 			goto bail1;
164 		}
165 
166 	} else {
167 		/* perform the verify directly on the compact representation */
168 
169 		if (lws_cmdline_option(argc, argv, "-f")) {
170 			if (lws_jws_sig_confirm_json(in, (unsigned int)n, &jws, &jwk, context,
171 					lws_concat_temp(temp, temp_len),
172 					&temp_len) < 0) {
173 				lwsl_notice("%s: confirm rsa sig failed\n",
174 					    __func__);
175 				lwsl_hexdump_notice(jws.map.buf[LJWS_JOSE], jws.map.len[LJWS_JOSE]);
176 				lwsl_hexdump_notice(jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
177 				lwsl_hexdump_notice(jws.map.buf[LJWS_SIG], jws.map.len[LJWS_SIG]);
178 
179 				lwsl_hexdump_notice(jws.map_b64.buf[LJWS_JOSE], jws.map_b64.len[LJWS_JOSE]);
180 				lwsl_hexdump_notice(jws.map_b64.buf[LJWS_PYLD], jws.map_b64.len[LJWS_PYLD]);
181 				lwsl_hexdump_notice(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]);
182 				goto bail1;
183 			}
184 		} else {
185 			if (lws_jws_sig_confirm_compact_b64(in,
186 					lws_concat_used(temp, (unsigned int)temp_len),
187 					&map, &jwk, context,
188 					lws_concat_temp(temp, temp_len),
189 					&temp_len) < 0) {
190 				lwsl_notice("%s: confirm rsa sig failed\n",
191 					    __func__);
192 				goto bail1;
193 			}
194 		}
195 
196 		lwsl_notice("VALID\n");
197 
198 		/* dump the verifed plaintext and return 0 */
199 
200 		if (write(1, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]) < 0) {
201 			lwsl_err("Write stdout failed\n");
202 			goto bail1;
203 		}
204 	}
205 
206 	result = 0;
207 
208 bail1:
209 	lws_jws_destroy(&jws);
210 	lws_jwk_destroy(&jwk);
211 
212 	lws_context_destroy(context);
213 
214 	return result;
215 }
216