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