• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-api-test-jose - RFC7515 jws tests
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 
12 /*
13  * JSON Web Signature is defined in RFC7515
14  *
15  * https://tools.ietf.org/html/rfc7515
16  *
17  * It's basically a way to wrap some JSON with a JSON "header" describing the
18  * crypto, and a signature, all in a BASE64 wrapper with elided terminating '='.
19  *
20  * The signature stays with the content, it serves a different purpose than eg
21  * a TLS tunnel to transfer it.
22  *
23  */
24 
25 /* for none, the compact serialization format is b64u(jose hdr).b64u(payload) */
26 
27 static const char *none_cser =
28 	  "eyJhbGciOiJub25lIn0"
29 	  "."
30 	  "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
31 	  "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
32 	  *none_jose = "{\"alg\":\"none\"}",
33 	  *none_payload	= "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n"
34 			  " \"http://example.com/is_root\":true}";
35 
36 int
test_jws_none(struct lws_context * context)37 test_jws_none(struct lws_context *context)
38 {
39 	struct lws_jws_map map;
40 	struct lws_jose jose;
41 	char temp[2048];
42 	int n, temp_len = sizeof(temp), ret = -1;
43 
44 	lws_jose_init(&jose);
45 
46 	/* A.5 Unsecured JSON "none" RFC7515 worked example */
47 
48 	/* decode the b64.b64[.b64] compact serialization blocks */
49 	n = lws_jws_compact_decode(none_cser, (int)strlen(none_cser), &map, NULL,
50 				   temp, &temp_len);
51 	if (n != 2) {
52 		lwsl_err("%s: concat_map failed\n", __func__);
53 		goto bail;
54 	}
55 
56 		/* confirm the decoded JOSE header is exactly what we expect */
57 		if (strncmp(none_jose, map.buf[LJWS_JOSE], map.len[LJWS_JOSE])) {
58 			lwsl_err("%s: jose b64 decode wrong\n", __func__);
59 			goto bail;
60 		}
61 
62 	/* parse the JOSE header */
63 	if (lws_jws_parse_jose(&jose, map.buf[LJWS_JOSE],
64 			       (int)map.len[LJWS_JOSE],
65 			       (char *)lws_concat_temp(temp, temp_len),
66 			       &temp_len) < 0 || !jose.alg) {
67 		lwsl_err("%s: JOSE parse failed\n", __func__);
68 		goto bail;
69 	}
70 
71 		/* confirm we used the "none" alg as expected from JOSE hdr */
72 		if (strcmp(jose.alg->alg, "none")) {
73 			lwsl_err("%s: JOSE header has wrong alg\n", __func__);
74 			goto bail;
75 		}
76 
77 		/* confirm the payload is literally what we expect */
78 		if (strncmp(none_payload, map.buf[LJWS_PYLD],
79 					  map.len[LJWS_PYLD])) {
80 			lwsl_err("%s: payload b64 decode wrong\n", __func__);
81 			goto bail;
82 		}
83 
84 	/* end */
85 
86 	ret = 0;
87 
88 bail:
89 	lws_jose_destroy(&jose);
90 
91 	if (ret)
92 		lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__);
93 	else
94 		lwsl_notice("%s: selftest OK\n", __func__);
95 
96 	return ret;
97 }
98 
99 
100 
101 static const char
102 	   *test1	= "{\"typ\":\"JWT\",\r\n \"alg\":\"HS256\"}",
103 	   *test1_enc	= "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9",
104 	   *test2	= "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n"
105 			  " \"http://example.com/is_root\":true}",
106 	   *test2_enc	= "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQ"
107 			  "ogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
108 	   *key_jwk	= "{\"kty\":\"oct\",\r\n"
109 			  " \"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQ"
110 			  "Lr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"}",
111 	   *hash_enc	= "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
112 ;
113 
114 int
test_jws_HS256(struct lws_context * context)115 test_jws_HS256(struct lws_context *context)
116 {
117 	char buf[2048], temp[256], *p = buf, *end = buf + sizeof(buf) - 1, *enc_ptr;
118 	uint8_t digest[LWS_GENHASH_LARGEST];
119 	struct lws_jws_map map;
120 	int temp_len = sizeof(temp);
121 	struct lws_genhmac_ctx ctx;
122 	struct lws_jose jose;
123 	struct lws_jwk jwk;
124 	struct lws_jws jws;
125 	int n;
126 
127 	lws_jose_init(&jose);
128 	lws_jws_init(&jws, &jwk, context);
129 
130 	/* Test 1: SHA256 on RFC7515 worked example */
131 
132 	/* parse the JOSE header */
133 
134 	if (lws_jws_parse_jose(&jose, test1, (int)strlen(test1), temp,
135 			       &temp_len) < 0 || !jose.alg) {
136 		lwsl_err("%s: JOSE parse failed\n", __func__);
137 		goto bail;
138 	}
139 
140 		/* confirm we used the "none" alg as expected from JOSE hdr */
141 		if (strcmp(jose.alg->alg, "HS256")) {
142 			lwsl_err("%s: JOSE header has wrong alg\n", __func__);
143 			goto bail;
144 		}
145 
146 	/* 1.1: import the JWK oct key */
147 
148 	if (lws_jwk_import(&jwk, NULL, NULL, key_jwk, strlen(key_jwk)) < 0) {
149 		lwsl_notice("Failed to decode JWK test key\n");
150 		return -1;
151 	}
152 		if (jwk.kty != LWS_GENCRYPTO_KTY_OCT) {
153 			lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty);
154 
155 			return -1;
156 		}
157 
158 	/* 1.2: create JWS known hdr + known payload */
159 
160 	n = lws_jws_encode_section(test1, strlen(test1), 1, &p, end);
161 	if (n < 0) {
162 		goto bail;
163 	}
164 
165 		if (strcmp(buf, test1_enc))
166 			goto bail;
167 
168 	enc_ptr = p + 1; /* + 1 skips the . */
169 	n = lws_jws_encode_section(test2, strlen(test2), 0, &p, end);
170 	if (n < 0) {
171 		goto bail;
172 	}
173 
174 		if (strcmp(enc_ptr, test2_enc))
175 			goto bail;
176 
177 	/* 1.3: use HMAC SHA-256 with known key on the hdr . payload */
178 
179 	if (lws_genhmac_init(&ctx, jose.alg->hmac_type,
180 			     jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf,
181 			     jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len))
182 		goto bail;
183 	if (lws_genhmac_update(&ctx, (uint8_t *)buf, lws_ptr_diff_size_t(p, buf)))
184 		goto bail_destroy_hmac;
185 	lws_genhmac_destroy(&ctx, digest);
186 
187 	/* 1.4: append a base64 encode of the computed HMAC digest */
188 
189 	enc_ptr = p + 1; /* + 1 skips the . */
190 	n = lws_jws_encode_section((const char *)digest, 32, 0, &p, end);
191 	if (n < 0)
192 		goto bail;
193 	if (strcmp(enc_ptr, hash_enc)) { /* check against known B64URL hash */
194 		lwsl_err("%s: b64 enc of computed HMAC mismatches '%s' '%s'\n",
195 			 __func__, enc_ptr, hash_enc);
196 		goto bail;
197 	}
198 
199 	/* 1.5: Check we can agree the signature matches the payload */
200 
201 	if (lws_jws_sig_confirm_compact_b64(buf, lws_ptr_diff_size_t(p, buf), &map, &jwk, context,
202 			lws_concat_temp(temp, temp_len), &temp_len) < 0) {
203 		lwsl_notice("%s: confirm sig failed\n", __func__);
204 		goto bail;
205 	}
206 
207 	lws_jws_destroy(&jws);
208 	lws_jwk_destroy(&jwk);
209 	lws_jose_destroy(&jose);
210 
211 	/* end */
212 
213 	lwsl_notice("%s: selftest OK\n", __func__);
214 
215 	return 0;
216 
217 bail_destroy_hmac:
218 	lws_genhmac_destroy(&ctx, NULL);
219 
220 bail:
221 	lws_jws_destroy(&jws);
222 	lws_jwk_destroy(&jwk);
223 	lws_jose_destroy(&jose);
224 	lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__);
225 
226 	return 1;
227 }
228 
229 
230 static const char
231 	/* the key from worked example in RFC7515 A-2, as a JWK */
232 	*rfc7515_rsa_key =
233 	"{\"kty\":\"RSA\","
234 	" \"n\":\"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx"
235 		 "HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs"
236 		 "D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH"
237 		 "SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV"
238 		 "MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8"
239 		 "NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ\","
240 	"\"e\":\"AQAB\","
241 	"\"d\":\"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I"
242 		"jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0"
243 		"BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn"
244 		"439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT"
245 		"CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh"
246 		"BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ\","
247 	"\"p\":\"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdi"
248 		"YrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPG"
249 		"BY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc\","
250 	"\"q\":\"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxa"
251 		"ewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA"
252 		"-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc\","
253 	"\"dp\":\"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3Q"
254 		"CLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb"
255 		"34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0\","
256 	"\"dq\":\"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa"
257 		"7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-ky"
258 		"NlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU\","
259 	"\"qi\":\"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2o"
260 		"y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU"
261 		"W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U\""
262 	"}",
263 	*rfc7515_rsa_a1 = /* the signed worked example in RFC7515 A-1 */
264 	"eyJhbGciOiJSUzI1NiJ9"
265 	".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
266 	"cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
267 	".cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7"
268 	"AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4"
269 	"BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K"
270 	"0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv"
271 	"hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB"
272 	"p0igcN_IoypGlUPQGe77Rw"
273 ;
274 
275 int
test_jws_RS256(struct lws_context * context)276 test_jws_RS256(struct lws_context *context)
277 {
278 	struct lws_jws_map map;
279 	struct lws_jose jose;
280 	struct lws_jwk jwk;
281 	struct lws_jws jws;
282 	char temp[2048], *in;
283 	int n, l, temp_len = sizeof(temp);
284 
285 	lws_jose_init(&jose);
286 	lws_jws_init(&jws, &jwk, context);
287 
288 	/* Test 2: RS256 on RFC7515 worked example */
289 
290 	if (lws_gencrypto_jws_alg_to_definition("RS256", &jose.alg)) {
291 		lwsl_err("%s: RS256 not supported\n", __func__);
292 		goto bail;
293 	}
294 
295 	/* 2.1: import the jwk */
296 
297 	if (lws_jwk_import(&jwk, NULL, NULL,
298 			   rfc7515_rsa_key, strlen(rfc7515_rsa_key))) {
299 		lwsl_notice("%s: 2.2: Failed to read JWK key\n", __func__);
300 		goto bail2;
301 	}
302 
303 	if (jwk.kty != LWS_GENCRYPTO_KTY_RSA) {
304 		lwsl_err("%s: 2.2: kty: %d instead of RSA\n", __func__, jwk.kty);
305 		goto bail;
306 	}
307 
308 	/* 2.2: check the signature on the test packet from RFC7515 A-1 */
309 
310 	if (lws_jws_sig_confirm_compact_b64(rfc7515_rsa_a1,
311 					    strlen(rfc7515_rsa_a1), &map,
312 					    &jwk, context, temp, &temp_len) < 0) {
313 		lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__);
314 		goto bail;
315 	}
316 
317 	if (lws_jws_b64_compact_map(rfc7515_rsa_a1, (int)strlen(rfc7515_rsa_a1),
318 				   &jws.map_b64) != 3) {
319 		lwsl_notice("%s: lws_jws_b64_compact_map failed\n", __func__);
320 		goto bail;
321 	}
322 
323 	/* 2.3: generate our own signature for a copy of the test packet */
324 
325 	in = lws_concat_temp(temp, temp_len);
326 	l = (int)strlen(rfc7515_rsa_a1);
327 	if (temp_len < l + 1)
328 		goto bail;
329 	memcpy(in, rfc7515_rsa_a1, (unsigned int)l + 1);
330 	temp_len -= l + 1;
331 
332 	if (lws_jws_b64_compact_map(in, l, &jws.map_b64) != 3) {
333 		lwsl_notice("%s: lws_jws_b64_compact_map failed\n", __func__);
334 		goto bail;
335 	}
336 
337 	/* overwrite the copy of the known b64 sig (it's all placed inside temp) */
338 	n = lws_jws_sign_from_b64(&jose, &jws,
339 				  (char *)jws.map_b64.buf[LJWS_SIG],
340 				  jws.map_b64.len[LJWS_SIG] + 8);
341 	if (n < 0) {
342 		lwsl_err("%s: failed signing test packet\n", __func__);
343 		goto bail;
344 	}
345 	jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
346 
347 	/* 2.4: confirm our signature can be verified */
348 
349 	in[l] = '\0';
350 	if (lws_jws_sig_confirm_compact_b64(in, (unsigned int)l, &map, &jwk,
351 			context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
352 		lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__);
353 		goto bail;
354 	}
355 
356 	lws_jwk_destroy(&jwk);
357 
358 	/* end */
359 
360 	lwsl_notice("%s: selftest OK\n", __func__);
361 
362 	return 0;
363 
364 bail:
365 	lws_jwk_destroy(&jwk);
366 bail2:
367 	lws_jws_destroy(&jws);
368 	lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__);
369 
370 	return 1;
371 }
372 
373 static const char
374 	*es256_jose = "{\"alg\":\"ES256\"}",
375 	*es256_payload	= "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n"
376 			  " \"http://example.com/is_root\":true}",
377 	*es256_cser =
378 	    "eyJhbGciOiJFUzI1NiJ9"
379 	    "."
380 	    "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
381 	    "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
382 	    "."
383 	    "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA"
384 	    "pmWQxfKTUJqPP3-Kg6NU1Q",
385 	*es256_jwk =
386 	"{"
387 		"\"kty\":\"EC\","
388 		"\"crv\":\"P-256\","
389 		"\"x\":\"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\","
390 		"\"y\":\"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\","
391 		"\"d\":\"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI\""
392 	"}"
393 #if 0
394 			,
395 	rfc7515_ec_a3_R[] = {
396 		 14, 209,  33,  83, 121,  99, 108,  72,  60,  47, 127,  21,  88,
397 		  7, 212,   2, 163, 178,  40,   3,  58, 249, 124, 126,  23, 129,
398 		154, 195,  22, 158, 166, 101
399 	},
400 	rfc7515_ec_a3_S[] = {
401 		197,  10,   7, 211, 140,  60, 112, 229, 216, 241,  45, 175,
402 		  8,  74,  84, 128, 166, 101, 144, 197, 242, 147,  80, 154,
403 		143,  63, 127, 138, 131, 163,  84, 213
404 	}
405 #endif
406 ;
407 
408 int
test_jws_ES256(struct lws_context * context)409 test_jws_ES256(struct lws_context *context)
410 {
411 	uint8_t digest[LWS_GENHASH_LARGEST];
412 	struct lws_genhash_ctx hash_ctx;
413 	struct lws_jws_map map;
414 	struct lws_jose jose;
415 	struct lws_jwk jwk;
416 	struct lws_jws jws;
417 	char temp[2048], *p;
418 	int ret = -1, l, n, temp_len = sizeof(temp);
419 
420 	/* A.3 "ES256" RFC7515 worked example - verify */
421 
422 	lws_jose_init(&jose);
423 
424 	/* decode the b64.b64[.b64] compact serialization blocks */
425 	if (lws_jws_compact_decode(es256_cser, (int)strlen(es256_cser),
426 				   &jws.map, &jws.map_b64,
427 				   temp, &temp_len) != 3) {
428 		lwsl_err("%s: concat_map failed\n", __func__);
429 		goto bail;
430 	}
431 
432 		/* confirm the decoded JOSE header is exactly what we expect */
433 		if (jws.map.len[LJWS_JOSE] != strlen(es256_jose) ||
434 		    strncmp(es256_jose, jws.map.buf[LJWS_JOSE],
435 				    jws.map.len[LJWS_JOSE])) {
436 			lwsl_err("%s: jose b64 decode wrong\n", __func__);
437 			goto bail;
438 		}
439 
440 		/* confirm the decoded payload is exactly what we expect */
441 		if (jws.map.len[LJWS_PYLD] != strlen(es256_payload) ||
442 		    strncmp(es256_payload, jws.map.buf[LJWS_PYLD],
443 					    jws.map.len[LJWS_PYLD])) {
444 			lwsl_err("%s: payload b64 decode wrong\n", __func__);
445 			goto bail;
446 		}
447 
448 	/* parse the JOSE header */
449 	if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
450 			       (int)jws.map.len[LJWS_JOSE],
451 			       (char *)lws_concat_temp(temp, temp_len), &temp_len) < 0) {
452 		lwsl_err("%s: JOSE parse failed\n", __func__);
453 		goto bail;
454 	}
455 
456 		/* confirm we used "ES256" alg we expect from the JOSE hdr */
457 		if (strcmp(jose.alg->alg, "ES256")) {
458 			lwsl_err("%s: JOSE header has wrong alg\n", __func__);
459 			goto bail;
460 		}
461 
462 	jws.jwk = &jwk;
463 	jws.context = context;
464 
465 	/* import the ES256 jwk */
466 	if (lws_jwk_import(&jwk, NULL, NULL, es256_jwk, strlen(es256_jwk))) {
467 		lwsl_notice("%s: Failed to read JWK key\n", __func__);
468 		goto bail;
469 	}
470 
471 		/* sanity */
472 		if (jwk.kty != LWS_GENCRYPTO_KTY_EC) {
473 			lwsl_err("%s: kty: %d instead of EC\n",
474 					__func__, jwk.kty);
475 			goto bail1;
476 		}
477 
478 	if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, &jwk, context) < 0) {
479 		lwsl_notice("%s: confirm EC sig failed\n", __func__);
480 		goto bail1;
481 	}
482 
483 	/* A.3 "ES256" RFC7515 worked example - sign */
484 
485 	l = (int)strlen(es256_cser);
486 	if (temp_len < l + 1)
487 		goto bail1;
488 	p = lws_concat_temp(temp, temp_len);
489 	memcpy(p, es256_cser, (unsigned int)l + 1);
490 	temp_len -= l + 1;
491 
492 	/* scan the b64 compact serialization string to map the blocks */
493 	if (lws_jws_b64_compact_map(p, l, &jws.map_b64) != 3)
494 		goto bail1;
495 
496 	/* create the hash of the protected b64 part */
497 	if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
498 	    lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_JOSE],
499 			    jws.map_b64.len[LJWS_JOSE]) ||
500 	    lws_genhash_update(&hash_ctx, ".", 1) ||
501 	    lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_PYLD],
502 			    jws.map_b64.len[LJWS_PYLD]) ||
503 	    lws_genhash_destroy(&hash_ctx, digest)) {
504 		lws_genhash_destroy(&hash_ctx, NULL);
505 
506 		goto bail1;
507 	}
508 
509 	lwsl_hexdump(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]);
510 
511 	/* overwrite the copy of the known b64 sig (it's placed inside buf) */
512 	n = lws_jws_sign_from_b64(&jose, &jws,
513 				  (char *)jws.map_b64.buf[LJWS_SIG],
514 				  jws.map_b64.len[LJWS_SIG] + 8);
515 	if (n < 0) {
516 		lwsl_err("%s: failed signing test packet\n", __func__);
517 		goto bail1;
518 	}
519 	jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
520 
521 	lwsl_hexdump(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]);
522 
523 	/* 2.4: confirm our generated signature can be verified */
524 
525 //	lwsl_err("p %p, l %d\n", p, (int)l);
526 	p[l] = '\0';
527 	if (lws_jws_sig_confirm_compact_b64(p, (unsigned int)l, &map, &jwk,
528 			context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
529 		lwsl_notice("%s: confirm our EC sig failed\n", __func__);
530 		goto bail1;
531 	}
532 
533 	/* end */
534 	ret =  0;
535 
536 bail1:
537 	lws_jwk_destroy(&jwk);
538 	lws_jose_destroy(&jose);
539 
540 bail:
541 	lwsl_notice("%s: selftest %s\n", __func__, ret ? "FAIL" : "OK");
542 
543 	return ret;
544 }
545 
546 static const char
547 	*es512_jose = "{\"alg\":\"ES512\"}",
548 	*es512_payload	= "Payload",
549 	*es512_cser =
550 	     "eyJhbGciOiJFUzUxMiJ9"
551 	     "."
552 	     "UGF5bG9hZA"
553 	     "."
554 	     "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq"
555 	     "wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp"
556 	     "EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn",
557 	*es512_jwk =
558 	   "{"
559 	      "\"kty\":\"EC\","
560 	      "\"crv\":\"P-521\","
561 	      "\"x\":\"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_"
562 	           "NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk\","
563 	      "\"y\":\"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDl"
564 	           "y79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2\","
565 	      "\"d\":\"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPA"
566 	           "xerEzgdRhajnu0ferB0d53vM9mE15j2C\""
567 	   "}"
568 ;
569 
570 int
test_jws_ES512(struct lws_context * context)571 test_jws_ES512(struct lws_context *context)
572 {
573 	uint8_t digest[LWS_GENHASH_LARGEST];
574 	struct lws_genhash_ctx hash_ctx;
575 	struct lws_jws_map map;
576 	struct lws_jose jose;
577 	struct lws_jwk jwk;
578 	struct lws_jws jws;
579 	char temp[2048], *p;
580 	int ret = -1, l, n, temp_len = sizeof(temp);
581 
582 	/* A.4 "ES512" RFC7515 worked example - verify */
583 
584 	lws_jose_init(&jose);
585 
586 	/* decode the b64.b64[.b64] compact serialization blocks */
587 	if (lws_jws_compact_decode(es512_cser, (int)strlen(es512_cser),
588 				   &jws.map, &jws.map_b64, temp,
589 				   &temp_len) != 3) {
590 		lwsl_err("%s: concat_map failed\n", __func__);
591 		goto bail;
592 	}
593 
594 		/* confirm the decoded JOSE header is exactly what we expect */
595 		if (jws.map.len[LJWS_JOSE] != strlen(es512_jose) ||
596 		    strncmp(es512_jose, jws.map.buf[LJWS_JOSE],
597 				        jws.map.len[LJWS_JOSE])) {
598 			lwsl_err("%s: jose b64 decode wrong\n", __func__);
599 			goto bail;
600 		}
601 
602 		/* confirm the decoded payload is exactly what we expect */
603 		if (jws.map.len[LJWS_PYLD] != strlen(es512_payload) ||
604 		    strncmp(es512_payload, jws.map.buf[LJWS_PYLD],
605 					   jws.map.len[LJWS_PYLD])) {
606 			lwsl_err("%s: payload b64 decode wrong\n", __func__);
607 			goto bail;
608 		}
609 
610 	/* parse the JOSE header */
611 	if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
612 			      (int)jws.map.len[LJWS_JOSE],
613 			      lws_concat_temp(temp, temp_len), &temp_len) < 0) {
614 		lwsl_err("%s: JOSE parse failed\n", __func__);
615 		goto bail;
616 	}
617 
618 		/* confirm we used "es512" alg we expect from the JOSE hdr */
619 		if (strcmp(jose.alg->alg, "ES512")) {
620 			lwsl_err("%s: JOSE header has wrong alg\n", __func__);
621 			goto bail;
622 		}
623 
624 	jws.jwk = &jwk;
625 	jws.context = context;
626 
627 	/* import the es512 jwk */
628 	if (lws_jwk_import(&jwk, NULL, NULL, es512_jwk, strlen(es512_jwk))) {
629 		lwsl_notice("%s: Failed to read JWK key\n", __func__);
630 		goto bail;
631 	}
632 
633 		/* sanity */
634 		if (jwk.kty != LWS_GENCRYPTO_KTY_EC) {
635 			lwsl_err("%s: kty: %d instead of EC\n",
636 					__func__, jwk.kty);
637 			goto bail1;
638 		}
639 
640 	if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, &jwk, context) < 0) {
641 		lwsl_notice("%s: confirm EC sig failed\n", __func__);
642 		goto bail1;
643 	}
644 
645 	/* A.3 "es512" RFC7515 worked example - sign */
646 
647 	l = (int)strlen(es512_cser);
648 	if (temp_len < l)
649 		goto bail1;
650 	p = lws_concat_temp(temp, temp_len);
651 	memcpy(p, es512_cser, (unsigned int)l + 1);
652 	temp_len -= (l + 1);
653 
654 	/* scan the b64 compact serialization string to map the blocks */
655 	if (lws_jws_b64_compact_map(p, l, &jws.map_b64) != 3)
656 		goto bail1;
657 
658 	/* create the hash of the protected b64 part */
659 	if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
660 	    lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_JOSE],
661 			       jws.map_b64.len[LJWS_JOSE]) ||
662 	    lws_genhash_update(&hash_ctx, ".", 1) ||
663 	    lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_PYLD],
664 			       jws.map_b64.len[LJWS_PYLD]) ||
665 	    lws_genhash_destroy(&hash_ctx, digest)) {
666 		lws_genhash_destroy(&hash_ctx, NULL);
667 
668 		goto bail1;
669 	}
670 
671 	/* overwrite the copy of the known b64 sig (it's placed inside buf) */
672 	n = lws_jws_sign_from_b64(&jose, &jws,
673 				  (char *)jws.map_b64.buf[LJWS_SIG], 1024);
674 	if (n < 0) {
675 		lwsl_err("%s: failed signing test packet\n", __func__);
676 		goto bail1;
677 	}
678 	jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
679 
680 	/* 2.4: confirm our generated signature can be verified */
681 
682 	p[l] = '\0';
683 
684 	if (lws_jws_sig_confirm_compact_b64(p, (unsigned int)l, &map, &jwk, context,
685 			lws_concat_temp(temp, temp_len), &temp_len) < 0) {
686 		lwsl_notice("%s: confirm our ECDSA sig failed\n", __func__);
687 		goto bail1;
688 	}
689 
690 	/* jwt test */
691 
692 	{
693 		unsigned long long ull = lws_now_secs();
694 		char buf[8192];
695 		size_t cml = 2048, cml2 = 2048;
696 
697 		if (lws_jwt_sign_compact(context, &jwk, "ES512",
698 					(char *)buf, &cml2,
699 					(char *)buf + 2048, 4096,
700 					"{\"iss\":\"warmcat.com\",\"aud\":"
701 					"\"https://libwebsockets.org/sai\","
702 					"\"iat\":%llu,"
703 					"\"nbf\":%llu,"
704 					"\"exp\":%llu,"
705 					"\"sub\":\"manage\"}", ull,
706 					ull - 60, ull + (30 * 24 * 3600)
707 				     )) {
708 			lwsl_err("%s: failed to create JWT\n", __func__);
709 			goto bail1;
710 		}
711 
712 		lwsl_notice("%s: jwt test '%s'\n", __func__, buf);
713 
714 		if (lws_jwt_signed_validate(context, &jwk, "ES512",
715 					     (const char *)buf, cml2,
716 					     (char *)buf + 2048, 2048,
717 					     (char *)buf + 4096, &cml)) {
718 			lwsl_err("%s: failed to parse JWT\n", __func__);
719 
720 			goto bail1;
721 		}
722 
723 		lwsl_notice("%s: jwt valid, payload '%s'\n",
724 				__func__, buf + 4096);
725 	}
726 
727 	/* end */
728 	ret =  0;
729 
730 bail1:
731 	lws_jwk_destroy(&jwk);
732 	lws_jose_destroy(&jose);
733 
734 bail:
735 	lwsl_notice("%s: selftest %s\n", __func__, ret ? "FAIL" : "OK");
736 
737 	return ret;
738 }
739 
740 static char
741 	rsa_cert[] = "-----BEGIN CERTIFICATE-----\n"
742 	     "MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD\n"
743 	     "VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb\n"
744 	     "MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx\n"
745 	     "HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3\n"
746 	     "WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl\n"
747 	     "d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0\n"
748 	     "cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA\n"
749 	     "aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW\n"
750 	     "aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8\n"
751 	     "Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek\n"
752 	     "LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH\n"
753 	     "KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6\n"
754 	     "jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ\n"
755 	     "Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz\n"
756 	     "TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK\n"
757 	     "Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0\n"
758 	     "nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo\n"
759 	     "GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p\n"
760 	     "sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU\n"
761 	     "9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar\n"
762 	     "jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow\n"
763 	     "YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA\n"
764 	     "xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P\n"
765 	     "wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34\n"
766 	     "H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv\n"
767 	     "xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk\n"
768 	     "ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g\n"
769 	     "1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA\n"
770 	     "AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg\n"
771 	     "mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s\n"
772 	     "8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX\n"
773 	     "e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=\n"
774 	     "-----END CERTIFICATE-----\n",
775 	rsa_key[] = "-----BEGIN PRIVATE KEY-----\n"
776 	    "MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJ\n"
777 	    "PubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHK\n"
778 	    "nSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZ\n"
779 	    "toGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU\n"
780 	    "0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBT\n"
781 	    "J1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pS\n"
782 	    "Np7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHN\n"
783 	    "uC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9\n"
784 	    "fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSn\n"
785 	    "zXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/Au\n"
786 	    "ehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaB\n"
787 	    "QLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8f\n"
788 	    "qokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+\n"
789 	    "vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9\n"
790 	    "fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5A\n"
791 	    "Kqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMT\n"
792 	    "G+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/\n"
793 	    "HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8\n"
794 	    "YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXgl\n"
795 	    "xBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvs\n"
796 	    "esnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqw\n"
797 	    "zFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVz\n"
798 	    "mgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCw\n"
799 	    "au9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN77\n"
800 	    "40QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5\n"
801 	    "YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFH\n"
802 	    "PgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXj\n"
803 	    "W7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuR\n"
804 	    "naVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr6\n"
805 	    "2ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m\n"
806 	    "39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79\n"
807 	    "J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDC\n"
808 	    "R1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMp\n"
809 	    "Y+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaCh\n"
810 	    "BVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCE\n"
811 	    "fXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQ\n"
812 	    "x1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHI\n"
813 	    "UlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RM\n"
814 	    "OMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L\n"
815 	    "65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/A\n"
816 	    "aJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5\n"
817 	    "SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6S\n"
818 	    "me/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+I\n"
819 	    "G4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iK\n"
820 	    "TncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY\n"
821 	    "56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2\n"
822 	    "gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMr\n"
823 	    "Ziw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3E\n"
824 	    "NqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrs\n"
825 	    "fBrpEY1IATtPq1taBZZogRqI3rOkkPk=\n"
826 	    "-----END PRIVATE KEY-----\n";
827 
828 int
test_jwt_RS256(struct lws_context * context)829 test_jwt_RS256(struct lws_context *context)
830 {
831 	struct lws_jwk jwk;
832 	struct lws_x509_cert *pub = NULL;
833 	int ret = -1;
834 	int ret_encode;
835 	char sha1_fingerprint[30];
836 	uint8_t sha1sum[20];
837 	char der_buf[LWS_ARRAY_SIZE(rsa_cert)];
838 	union lws_tls_cert_info_results *der_info =
839 			(union lws_tls_cert_info_results *)der_buf;
840 
841 	if (lws_x509_create(&pub)) {
842 		lwsl_err("%s: failed to create x509 public key\n", __func__);
843 		goto bail;
844 	}
845 
846 	if (lws_x509_parse_from_pem(pub, rsa_cert, LWS_ARRAY_SIZE(rsa_cert))) {
847 		lwsl_err("%s: failed to parse x509 public key\n", __func__);
848 		goto bail;
849 	}
850 
851 	if (lws_x509_public_to_jwk(&jwk, pub, NULL, 2048)) {
852 		lwsl_err("%s: failed to copy public key to jwk\n", __func__);
853 		goto bail;
854 	}
855 
856 	if (lws_x509_jwk_privkey_pem(context, &jwk, (char *)rsa_key,
857 				     LWS_ARRAY_SIZE(rsa_key), NULL)) {
858 		lwsl_err("%s: failed to copy private key to jwk\n", __func__);
859 		goto bail;
860 	}
861 
862 	if (lws_x509_info(pub, LWS_TLS_CERT_INFO_DER_RAW, der_info,
863 			  LWS_ARRAY_SIZE(der_buf) - sizeof(*der_info) +
864 			  sizeof(der_info->ns.name)) ||
865 	    der_info->ns.len <= 0) {
866 		lwsl_err("%s: failed to parse x509 public key\n", __func__);
867 		goto bail;
868 	}
869 
870 	if (!lws_SHA1((unsigned char *)der_info->ns.name,
871 		      (size_t)der_info->ns.len, sha1sum)) {
872 		lwsl_err("%s: sha1sum of public key failed\n", __func__);
873 		goto bail;
874 	}
875 
876 	ret_encode = lws_b64_encode_string_url((char *)sha1sum,
877 				LWS_ARRAY_SIZE(sha1sum), sha1_fingerprint,
878 				LWS_ARRAY_SIZE(sha1_fingerprint));
879 	if (ret_encode < 0) {
880 		lwsl_err("%s: failed to encode sha1sum to base64url\n", __func__);
881 		goto bail;
882 	}
883 
884 	while (sha1_fingerprint[--ret_encode] == '=')
885 		sha1_fingerprint[ret_encode] = '\0';
886 
887 	lwsl_notice("%s: cert fingerprint '%s'\n", __func__, sha1_fingerprint);
888 
889 	/* now produce jwt with some additional header fields */
890 	{
891 		unsigned long long ull = lws_now_secs();
892 		char buf[8192];
893 		size_t cml = 2048, cml2 = 2048;
894 		const char hdr_fmt[] = "{\"alg\":\"RS256\", \"typ\":\"JWT\", \"x5t\":\"%s\"}";
895 		char jose_hdr[LWS_ARRAY_SIZE(hdr_fmt) + LWS_ARRAY_SIZE(sha1_fingerprint)];
896 
897 		struct lws_jwt_sign_info info = {
898 			.alg = NULL,
899 			.jose_hdr = jose_hdr,
900 			.jose_hdr_len = (size_t)lws_snprintf(jose_hdr, LWS_ARRAY_SIZE(jose_hdr), hdr_fmt, sha1_fingerprint),
901 			.out = buf,
902 			.out_len = &cml2,
903 			.temp = buf + cml2,
904 			.tl = 4096
905 		};
906 
907 		lwsl_notice("%s: jose_hdr of len %zu: '%s'\n", __func__, info.jose_hdr_len, info.jose_hdr);
908 		if (lws_jwt_sign_via_info(context, &jwk, &info,
909 					"{\"iss\":\"warmcat.com\",\"aud\":"
910 					"\"https://libwebsockets.org/sai\","
911 					"\"iat\":%llu,"
912 					"\"nbf\":%llu,"
913 					"\"exp\":%llu,"
914 					"\"sub\":\"manage\"}", ull,
915 					ull - 60, ull + (30 * 24 * 3600)
916 						 )) {
917 			lwsl_err("%s: failed to create JWT\n", __func__);
918 			goto bail1;
919 		}
920 
921 		lwsl_notice("%s: jwt test '%s'\n", __func__, buf);
922 
923 		if (lws_jwt_signed_validate(context, &jwk, "RS256",
924 							 (const char *)buf, cml2,
925 							 (char *)buf + 2048, 2048,
926 							 (char *)buf + 4096, &cml)) {
927 			lwsl_err("%s: failed to parse JWT\n", __func__);
928 
929 			goto bail1;
930 		}
931 
932 		lwsl_notice("%s: jwt valid, payload '%s'\n",
933 				__func__, buf + 4096);
934 	}
935 
936 	/* end */
937 	ret =	0;
938 
939 bail1:
940 	lws_jwk_destroy(&jwk);
941 	lws_x509_destroy(&pub);
942 
943 bail:
944 	lwsl_notice("%s: selftest %s\n", __func__, ret ? "FAIL" : "OK");
945 
946 	return ret;
947 }
948 
949 int
test_jws(struct lws_context * context)950 test_jws(struct lws_context *context)
951 {
952 	int n = 0;
953 
954 	n |= test_jws_none(context);
955 	n |= test_jws_HS256(context);
956 	n |= test_jws_RS256(context);
957 	n |= test_jws_ES256(context);
958 	n |= test_jws_ES512(context);
959 	n |= test_jwt_RS256(context);
960 
961 	return n;
962 }
963