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