1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * lws-crypto-jwe
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Written in 2010-2020 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker */
9*1c60b9acSAndroid Build Coastguard Worker
10*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
11*1c60b9acSAndroid Build Coastguard Worker #include <sys/types.h>
12*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
13*1c60b9acSAndroid Build Coastguard Worker
14*1c60b9acSAndroid Build Coastguard Worker /*
15*1c60b9acSAndroid Build Coastguard Worker * handles escapes and line wrapping suitable for use
16*1c60b9acSAndroid Build Coastguard Worker * defining a C char array ( -c option )
17*1c60b9acSAndroid Build Coastguard Worker */
18*1c60b9acSAndroid Build Coastguard Worker
19*1c60b9acSAndroid Build Coastguard Worker static void
format_c(const char * key)20*1c60b9acSAndroid Build Coastguard Worker format_c(const char *key)
21*1c60b9acSAndroid Build Coastguard Worker {
22*1c60b9acSAndroid Build Coastguard Worker const char *k = key;
23*1c60b9acSAndroid Build Coastguard Worker int seq = 0;
24*1c60b9acSAndroid Build Coastguard Worker
25*1c60b9acSAndroid Build Coastguard Worker while (*k) {
26*1c60b9acSAndroid Build Coastguard Worker if (*k == '{') {
27*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
28*1c60b9acSAndroid Build Coastguard Worker putchar('{');
29*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
30*1c60b9acSAndroid Build Coastguard Worker putchar('\n');
31*1c60b9acSAndroid Build Coastguard Worker putchar('\t');
32*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
33*1c60b9acSAndroid Build Coastguard Worker k++;
34*1c60b9acSAndroid Build Coastguard Worker seq = 0;
35*1c60b9acSAndroid Build Coastguard Worker continue;
36*1c60b9acSAndroid Build Coastguard Worker }
37*1c60b9acSAndroid Build Coastguard Worker if (*k == '}') {
38*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
39*1c60b9acSAndroid Build Coastguard Worker putchar('\n');
40*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
41*1c60b9acSAndroid Build Coastguard Worker putchar('}');
42*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
43*1c60b9acSAndroid Build Coastguard Worker putchar('\n');
44*1c60b9acSAndroid Build Coastguard Worker k++;
45*1c60b9acSAndroid Build Coastguard Worker seq = 0;
46*1c60b9acSAndroid Build Coastguard Worker continue;
47*1c60b9acSAndroid Build Coastguard Worker }
48*1c60b9acSAndroid Build Coastguard Worker if (*k == '\"') {
49*1c60b9acSAndroid Build Coastguard Worker putchar('\\');
50*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
51*1c60b9acSAndroid Build Coastguard Worker seq += 2;
52*1c60b9acSAndroid Build Coastguard Worker k++;
53*1c60b9acSAndroid Build Coastguard Worker continue;
54*1c60b9acSAndroid Build Coastguard Worker }
55*1c60b9acSAndroid Build Coastguard Worker if (*k == ',') {
56*1c60b9acSAndroid Build Coastguard Worker putchar(',');
57*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
58*1c60b9acSAndroid Build Coastguard Worker putchar('\n');
59*1c60b9acSAndroid Build Coastguard Worker putchar('\t');
60*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
61*1c60b9acSAndroid Build Coastguard Worker k++;
62*1c60b9acSAndroid Build Coastguard Worker seq = 0;
63*1c60b9acSAndroid Build Coastguard Worker continue;
64*1c60b9acSAndroid Build Coastguard Worker }
65*1c60b9acSAndroid Build Coastguard Worker putchar(*k);
66*1c60b9acSAndroid Build Coastguard Worker seq++;
67*1c60b9acSAndroid Build Coastguard Worker if (seq >= 60) {
68*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
69*1c60b9acSAndroid Build Coastguard Worker putchar('\n');
70*1c60b9acSAndroid Build Coastguard Worker putchar('\t');
71*1c60b9acSAndroid Build Coastguard Worker putchar(' ');
72*1c60b9acSAndroid Build Coastguard Worker putchar('\"');
73*1c60b9acSAndroid Build Coastguard Worker seq = 1;
74*1c60b9acSAndroid Build Coastguard Worker }
75*1c60b9acSAndroid Build Coastguard Worker k++;
76*1c60b9acSAndroid Build Coastguard Worker }
77*1c60b9acSAndroid Build Coastguard Worker }
78*1c60b9acSAndroid Build Coastguard Worker
79*1c60b9acSAndroid Build Coastguard Worker #define MAX_SIZE (4 * 1024 * 1024)
80*1c60b9acSAndroid Build Coastguard Worker char temp[MAX_SIZE], compact[MAX_SIZE];
81*1c60b9acSAndroid Build Coastguard Worker
main(int argc,const char ** argv)82*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
83*1c60b9acSAndroid Build Coastguard Worker {
84*1c60b9acSAndroid Build Coastguard Worker int n, enc = 0, result = 0,
85*1c60b9acSAndroid Build Coastguard Worker logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
86*1c60b9acSAndroid Build Coastguard Worker char *in;
87*1c60b9acSAndroid Build Coastguard Worker struct lws_context_creation_info info;
88*1c60b9acSAndroid Build Coastguard Worker int temp_len = sizeof(temp);
89*1c60b9acSAndroid Build Coastguard Worker struct lws_context *context;
90*1c60b9acSAndroid Build Coastguard Worker struct lws_jwe jwe;
91*1c60b9acSAndroid Build Coastguard Worker const char *p;
92*1c60b9acSAndroid Build Coastguard Worker
93*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "-d")))
94*1c60b9acSAndroid Build Coastguard Worker logs = atoi(p);
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker lws_set_log_level(logs, NULL);
97*1c60b9acSAndroid Build Coastguard Worker lwsl_user("LWS JWE example tool\n");
98*1c60b9acSAndroid Build Coastguard Worker
99*1c60b9acSAndroid Build Coastguard Worker memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
100*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_NETWORK)
101*1c60b9acSAndroid Build Coastguard Worker info.port = CONTEXT_PORT_NO_LISTEN;
102*1c60b9acSAndroid Build Coastguard Worker #endif
103*1c60b9acSAndroid Build Coastguard Worker info.options = 0;
104*1c60b9acSAndroid Build Coastguard Worker
105*1c60b9acSAndroid Build Coastguard Worker context = lws_create_context(&info);
106*1c60b9acSAndroid Build Coastguard Worker if (!context) {
107*1c60b9acSAndroid Build Coastguard Worker lwsl_err("lws init failed\n");
108*1c60b9acSAndroid Build Coastguard Worker return 1;
109*1c60b9acSAndroid Build Coastguard Worker }
110*1c60b9acSAndroid Build Coastguard Worker
111*1c60b9acSAndroid Build Coastguard Worker lws_jwe_init(&jwe, context);
112*1c60b9acSAndroid Build Coastguard Worker
113*1c60b9acSAndroid Build Coastguard Worker /* if encrypting, set the ciphers */
114*1c60b9acSAndroid Build Coastguard Worker
115*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "-e"))) {
116*1c60b9acSAndroid Build Coastguard Worker char *sp = strchr(p, ' ');
117*1c60b9acSAndroid Build Coastguard Worker
118*1c60b9acSAndroid Build Coastguard Worker if (!sp) {
119*1c60b9acSAndroid Build Coastguard Worker lwsl_err("format: -e \"<cek cipher alg> "
120*1c60b9acSAndroid Build Coastguard Worker "<payload enc alg>\", eg, "
121*1c60b9acSAndroid Build Coastguard Worker "-e \"RSA1_5 A128CBC-HS256\"\n");
122*1c60b9acSAndroid Build Coastguard Worker
123*1c60b9acSAndroid Build Coastguard Worker return 1;
124*1c60b9acSAndroid Build Coastguard Worker }
125*1c60b9acSAndroid Build Coastguard Worker *sp = '\0';
126*1c60b9acSAndroid Build Coastguard Worker if (lws_gencrypto_jwe_alg_to_definition(p, &jwe.jose.alg)) {
127*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Unknown cipher alg %s\n", p);
128*1c60b9acSAndroid Build Coastguard Worker return 1;
129*1c60b9acSAndroid Build Coastguard Worker }
130*1c60b9acSAndroid Build Coastguard Worker if (lws_gencrypto_jwe_enc_to_definition(sp + 1, &jwe.jose.enc_alg)) {
131*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Unknown payload enc alg %s\n", sp + 1);
132*1c60b9acSAndroid Build Coastguard Worker return 1;
133*1c60b9acSAndroid Build Coastguard Worker }
134*1c60b9acSAndroid Build Coastguard Worker
135*1c60b9acSAndroid Build Coastguard Worker /* create JOSE header, also needed for output */
136*1c60b9acSAndroid Build Coastguard Worker
137*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_alloc_element(&jwe.jws.map, LJWS_JOSE,
138*1c60b9acSAndroid Build Coastguard Worker lws_concat_temp(temp, temp_len),
139*1c60b9acSAndroid Build Coastguard Worker &temp_len, strlen(p) +
140*1c60b9acSAndroid Build Coastguard Worker strlen(sp + 1) + 32, 0)) {
141*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: temp space too small\n", __func__);
142*1c60b9acSAndroid Build Coastguard Worker return 1;
143*1c60b9acSAndroid Build Coastguard Worker }
144*1c60b9acSAndroid Build Coastguard Worker
145*1c60b9acSAndroid Build Coastguard Worker jwe.jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(
146*1c60b9acSAndroid Build Coastguard Worker (char *)jwe.jws.map.buf[LJWS_JOSE], (unsigned int)temp_len,
147*1c60b9acSAndroid Build Coastguard Worker "{\"alg\":\"%s\",\"enc\":\"%s\"}", p, sp + 1);
148*1c60b9acSAndroid Build Coastguard Worker
149*1c60b9acSAndroid Build Coastguard Worker enc = 1;
150*1c60b9acSAndroid Build Coastguard Worker }
151*1c60b9acSAndroid Build Coastguard Worker
152*1c60b9acSAndroid Build Coastguard Worker in = lws_concat_temp(temp, temp_len);
153*1c60b9acSAndroid Build Coastguard Worker n = (int)read(0, in, (unsigned int)temp_len);
154*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
155*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Problem reading from stdin\n");
156*1c60b9acSAndroid Build Coastguard Worker return 1;
157*1c60b9acSAndroid Build Coastguard Worker }
158*1c60b9acSAndroid Build Coastguard Worker
159*1c60b9acSAndroid Build Coastguard Worker /* account for padding as well */
160*1c60b9acSAndroid Build Coastguard Worker
161*1c60b9acSAndroid Build Coastguard Worker temp_len -= (int)lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN, (unsigned int)n);
162*1c60b9acSAndroid Build Coastguard Worker
163*1c60b9acSAndroid Build Coastguard Worker /* grab the key */
164*1c60b9acSAndroid Build Coastguard Worker
165*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "-k"))) {
166*1c60b9acSAndroid Build Coastguard Worker if (lws_jwk_load(&jwe.jwk, p, NULL, NULL)) {
167*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: problem loading JWK %s\n", __func__, p);
168*1c60b9acSAndroid Build Coastguard Worker
169*1c60b9acSAndroid Build Coastguard Worker return 1;
170*1c60b9acSAndroid Build Coastguard Worker }
171*1c60b9acSAndroid Build Coastguard Worker } else {
172*1c60b9acSAndroid Build Coastguard Worker lwsl_err("-k <jwk file> is required\n");
173*1c60b9acSAndroid Build Coastguard Worker
174*1c60b9acSAndroid Build Coastguard Worker return 1;
175*1c60b9acSAndroid Build Coastguard Worker }
176*1c60b9acSAndroid Build Coastguard Worker
177*1c60b9acSAndroid Build Coastguard Worker if (enc) {
178*1c60b9acSAndroid Build Coastguard Worker
179*1c60b9acSAndroid Build Coastguard Worker /* point CTXT to the plaintext we read from stdin */
180*1c60b9acSAndroid Build Coastguard Worker
181*1c60b9acSAndroid Build Coastguard Worker jwe.jws.map.buf[LJWE_CTXT] = in;
182*1c60b9acSAndroid Build Coastguard Worker jwe.jws.map.len[LJWE_CTXT] = (uint32_t)n;
183*1c60b9acSAndroid Build Coastguard Worker
184*1c60b9acSAndroid Build Coastguard Worker /*
185*1c60b9acSAndroid Build Coastguard Worker * Create a random CEK and set EKEY to it
186*1c60b9acSAndroid Build Coastguard Worker * CEK size is determined by hash / hmac size
187*1c60b9acSAndroid Build Coastguard Worker */
188*1c60b9acSAndroid Build Coastguard Worker
189*1c60b9acSAndroid Build Coastguard Worker n = lws_gencrypto_bits_to_bytes(jwe.jose.enc_alg->keybits_fixed);
190*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_randomize_element(context, &jwe.jws.map, LJWE_EKEY,
191*1c60b9acSAndroid Build Coastguard Worker lws_concat_temp(temp, temp_len),
192*1c60b9acSAndroid Build Coastguard Worker &temp_len, (unsigned int)n,
193*1c60b9acSAndroid Build Coastguard Worker LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) {
194*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Problem getting random\n");
195*1c60b9acSAndroid Build Coastguard Worker goto bail1;
196*1c60b9acSAndroid Build Coastguard Worker }
197*1c60b9acSAndroid Build Coastguard Worker
198*1c60b9acSAndroid Build Coastguard Worker /* perform the encryption of the CEK and the plaintext */
199*1c60b9acSAndroid Build Coastguard Worker
200*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_encrypt(&jwe, lws_concat_temp(temp, temp_len),
201*1c60b9acSAndroid Build Coastguard Worker &temp_len);
202*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
203*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_encrypt failed\n", __func__);
204*1c60b9acSAndroid Build Coastguard Worker goto bail1;
205*1c60b9acSAndroid Build Coastguard Worker }
206*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-f"))
207*1c60b9acSAndroid Build Coastguard Worker /* output the JWE in flattened form */
208*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_render_flattened(&jwe, compact,
209*1c60b9acSAndroid Build Coastguard Worker sizeof(compact));
210*1c60b9acSAndroid Build Coastguard Worker else
211*1c60b9acSAndroid Build Coastguard Worker /* output the JWE in compact form */
212*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_render_compact(&jwe, compact,
213*1c60b9acSAndroid Build Coastguard Worker sizeof(compact));
214*1c60b9acSAndroid Build Coastguard Worker
215*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
216*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_render failed: %d\n",
217*1c60b9acSAndroid Build Coastguard Worker __func__, n);
218*1c60b9acSAndroid Build Coastguard Worker goto bail1;
219*1c60b9acSAndroid Build Coastguard Worker }
220*1c60b9acSAndroid Build Coastguard Worker
221*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-c"))
222*1c60b9acSAndroid Build Coastguard Worker format_c(compact);
223*1c60b9acSAndroid Build Coastguard Worker else
224*1c60b9acSAndroid Build Coastguard Worker if (write(1, compact,
225*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
226*1c60b9acSAndroid Build Coastguard Worker (unsigned int)
227*1c60b9acSAndroid Build Coastguard Worker #endif
228*1c60b9acSAndroid Build Coastguard Worker strlen(compact)) < 0) {
229*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Write stdout failed\n");
230*1c60b9acSAndroid Build Coastguard Worker goto bail1;
231*1c60b9acSAndroid Build Coastguard Worker }
232*1c60b9acSAndroid Build Coastguard Worker } else {
233*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-f")) {
234*1c60b9acSAndroid Build Coastguard Worker if (lws_jwe_json_parse(&jwe, (uint8_t *)in, n,
235*1c60b9acSAndroid Build Coastguard Worker lws_concat_temp(temp, temp_len),
236*1c60b9acSAndroid Build Coastguard Worker &temp_len)) {
237*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_json_parse failed\n",
238*1c60b9acSAndroid Build Coastguard Worker __func__);
239*1c60b9acSAndroid Build Coastguard Worker goto bail1;
240*1c60b9acSAndroid Build Coastguard Worker }
241*1c60b9acSAndroid Build Coastguard Worker } else
242*1c60b9acSAndroid Build Coastguard Worker /*
243*1c60b9acSAndroid Build Coastguard Worker * converts a compact serialization to b64 + decoded maps
244*1c60b9acSAndroid Build Coastguard Worker * held in jws
245*1c60b9acSAndroid Build Coastguard Worker */
246*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_compact_decode(in, n, &jwe.jws.map,
247*1c60b9acSAndroid Build Coastguard Worker &jwe.jws.map_b64,
248*1c60b9acSAndroid Build Coastguard Worker lws_concat_temp(temp, temp_len),
249*1c60b9acSAndroid Build Coastguard Worker &temp_len) != 5) {
250*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jws_compact_decode failed\n",
251*1c60b9acSAndroid Build Coastguard Worker __func__);
252*1c60b9acSAndroid Build Coastguard Worker goto bail1;
253*1c60b9acSAndroid Build Coastguard Worker }
254*1c60b9acSAndroid Build Coastguard Worker
255*1c60b9acSAndroid Build Coastguard Worker /*
256*1c60b9acSAndroid Build Coastguard Worker * Do the crypto according to what we parsed into the jose
257*1c60b9acSAndroid Build Coastguard Worker * (information on the ciphers) and the jws (plaintext and
258*1c60b9acSAndroid Build Coastguard Worker * signature info)
259*1c60b9acSAndroid Build Coastguard Worker */
260*1c60b9acSAndroid Build Coastguard Worker
261*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_auth_and_decrypt(&jwe,
262*1c60b9acSAndroid Build Coastguard Worker lws_concat_temp(temp, temp_len),
263*1c60b9acSAndroid Build Coastguard Worker &temp_len);
264*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
265*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n",
266*1c60b9acSAndroid Build Coastguard Worker __func__);
267*1c60b9acSAndroid Build Coastguard Worker goto bail1;
268*1c60b9acSAndroid Build Coastguard Worker }
269*1c60b9acSAndroid Build Coastguard Worker
270*1c60b9acSAndroid Build Coastguard Worker /* if it's valid, dump the plaintext and return 0 */
271*1c60b9acSAndroid Build Coastguard Worker
272*1c60b9acSAndroid Build Coastguard Worker if (write(1, jwe.jws.map.buf[LJWE_CTXT],
273*1c60b9acSAndroid Build Coastguard Worker jwe.jws.map.len[LJWE_CTXT]) < 0) {
274*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Write stdout failed\n");
275*1c60b9acSAndroid Build Coastguard Worker goto bail1;
276*1c60b9acSAndroid Build Coastguard Worker }
277*1c60b9acSAndroid Build Coastguard Worker }
278*1c60b9acSAndroid Build Coastguard Worker
279*1c60b9acSAndroid Build Coastguard Worker result = 0;
280*1c60b9acSAndroid Build Coastguard Worker
281*1c60b9acSAndroid Build Coastguard Worker bail1:
282*1c60b9acSAndroid Build Coastguard Worker
283*1c60b9acSAndroid Build Coastguard Worker lws_jwe_destroy(&jwe);
284*1c60b9acSAndroid Build Coastguard Worker
285*1c60b9acSAndroid Build Coastguard Worker lws_context_destroy(context);
286*1c60b9acSAndroid Build Coastguard Worker
287*1c60b9acSAndroid Build Coastguard Worker return result;
288*1c60b9acSAndroid Build Coastguard Worker }
289