• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 #include "private-lib-jose-jws.h"
27 
28 /*
29  * Currently only support flattened or compact (implicitly single signature)
30  */
31 
32 static const char * const jws_json[] = {
33 	"protected", /* base64u */
34 	"header", /* JSON */
35 	"payload", /* base64u payload */
36 	"signature", /* base64u signature */
37 
38 	//"signatures[].protected",
39 	//"signatures[].header",
40 	//"signatures[].signature"
41 };
42 
43 enum lws_jws_json_tok {
44 	LJWSJT_PROTECTED,
45 	LJWSJT_HEADER,
46 	LJWSJT_PAYLOAD,
47 	LJWSJT_SIGNATURE,
48 
49 	// LJWSJT_SIGNATURES_PROTECTED,
50 	// LJWSJT_SIGNATURES_HEADER,
51 	// LJWSJT_SIGNATURES_SIGNATURE,
52 };
53 
54 /* parse a JWS complete or flattened JSON object */
55 
56 struct jws_cb_args {
57 	struct lws_jws *jws;
58 
59 	char *temp;
60 	int *temp_len;
61 };
62 
63 static signed char
lws_jws_json_cb(struct lejp_ctx * ctx,char reason)64 lws_jws_json_cb(struct lejp_ctx *ctx, char reason)
65 {
66 	struct jws_cb_args *args = (struct jws_cb_args *)ctx->user;
67 	int n, m;
68 
69 	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
70 		return 0;
71 
72 	switch (ctx->path_match - 1) {
73 
74 	/* strings */
75 
76 	case LJWSJT_PROTECTED:  /* base64u: JOSE: must contain 'alg' */
77 		m = LJWS_JOSE;
78 		goto append_string;
79 	case LJWSJT_PAYLOAD:	/* base64u */
80 		m = LJWS_PYLD;
81 		goto append_string;
82 	case LJWSJT_SIGNATURE:  /* base64u */
83 		m = LJWS_SIG;
84 		goto append_string;
85 
86 	case LJWSJT_HEADER:	/* unprotected freeform JSON */
87 		break;
88 
89 	default:
90 		return -1;
91 	}
92 
93 	return 0;
94 
95 append_string:
96 
97 	if (*args->temp_len < ctx->npos) {
98 		lwsl_err("%s: out of parsing space\n", __func__);
99 		return -1;
100 	}
101 
102 	/*
103 	 * We keep both b64u and decoded in temp mapped using map / map_b64,
104 	 * the jws signature is actually over the b64 content not the plaintext,
105 	 * and we can't do it until we see the protected alg.
106 	 */
107 
108 	if (!args->jws->map_b64.buf[m]) {
109 		args->jws->map_b64.buf[m] = args->temp;
110 		args->jws->map_b64.len[m] = 0;
111 	}
112 
113 	memcpy(args->temp, ctx->buf, ctx->npos);
114 	args->temp += ctx->npos;
115 	*args->temp_len -= ctx->npos;
116 	args->jws->map_b64.len[m] += ctx->npos;
117 
118 	if (reason == LEJPCB_VAL_STR_END) {
119 		args->jws->map.buf[m] = args->temp;
120 
121 		n = lws_b64_decode_string_len(
122 			(const char *)args->jws->map_b64.buf[m],
123 			(int)args->jws->map_b64.len[m],
124 			(char *)args->temp, *args->temp_len);
125 		if (n < 0) {
126 			lwsl_err("%s: b64 decode failed: in len %d, m %d\n", __func__, (int)args->jws->map_b64.len[m], m);
127 			return -1;
128 		}
129 
130 		args->temp += n;
131 		*args->temp_len -= n;
132 		args->jws->map.len[m] = (unsigned int)n;
133 	}
134 
135 	return 0;
136 }
137 
138 static int
lws_jws_json_parse(struct lws_jws * jws,const uint8_t * buf,int len,char * temp,int * temp_len)139 lws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
140 		   char *temp, int *temp_len)
141 {
142 	struct jws_cb_args args;
143 	struct lejp_ctx jctx;
144 	int m = 0;
145 
146 	args.jws = jws;
147 	args.temp = temp;
148 	args.temp_len = temp_len;
149 
150 	lejp_construct(&jctx, lws_jws_json_cb, &args, jws_json,
151 		       LWS_ARRAY_SIZE(jws_json));
152 
153 	m = lejp_parse(&jctx, (uint8_t *)buf, len);
154 	lejp_destruct(&jctx);
155 	if (m < 0) {
156 		lwsl_notice("%s: parse returned %d\n", __func__, m);
157 		return -1;
158 	}
159 
160 	return 0;
161 }
162 
163 void
lws_jws_init(struct lws_jws * jws,struct lws_jwk * jwk,struct lws_context * context)164 lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
165 	     struct lws_context *context)
166 {
167 	memset(jws, 0, sizeof(*jws));
168 	jws->context = context;
169 	jws->jwk = jwk;
170 }
171 
172 static void
lws_jws_map_bzero(struct lws_jws_map * map)173 lws_jws_map_bzero(struct lws_jws_map *map)
174 {
175 	int n;
176 
177 	/* no need to scrub first jose header element (it can be canned then) */
178 
179 	for (n = 1; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++)
180 		if (map->buf[n])
181 			lws_explicit_bzero((void *)map->buf[n], map->len[n]);
182 }
183 
184 void
lws_jws_destroy(struct lws_jws * jws)185 lws_jws_destroy(struct lws_jws *jws)
186 {
187 	lws_jws_map_bzero(&jws->map);
188 	jws->jwk = NULL;
189 }
190 
191 int
lws_jws_dup_element(struct lws_jws_map * map,int idx,char * temp,int * temp_len,const void * in,size_t in_len,size_t actual_alloc)192 lws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
193 		    const void *in, size_t in_len, size_t actual_alloc)
194 {
195 	if (!actual_alloc)
196 		actual_alloc = in_len;
197 
198 	if ((size_t)*temp_len < actual_alloc)
199 		return -1;
200 
201 	memcpy(temp, in, in_len);
202 
203 	map->len[idx] = (uint32_t)in_len;
204 	map->buf[idx] = temp;
205 
206 	*temp_len -= (int)actual_alloc;
207 
208 	return 0;
209 }
210 
211 int
lws_jws_encode_b64_element(struct lws_jws_map * map,int idx,char * temp,int * temp_len,const void * in,size_t in_len)212 lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
213 			   char *temp, int *temp_len, const void *in,
214 			   size_t in_len)
215 {
216 	int n;
217 
218 	if (*temp_len < lws_base64_size((int)in_len))
219 		return -1;
220 
221 	n = lws_jws_base64_enc(in, in_len, temp, (size_t)*temp_len);
222 	if (n < 0)
223 		return -1;
224 
225 	map->len[idx] = (unsigned int)n;
226 	map->buf[idx] = temp;
227 
228 	*temp_len -= n;
229 
230 	return 0;
231 }
232 
233 int
lws_jws_randomize_element(struct lws_context * context,struct lws_jws_map * map,int idx,char * temp,int * temp_len,size_t random_len,size_t actual_alloc)234 lws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
235 			  int idx, char *temp, int *temp_len, size_t random_len,
236 			  size_t actual_alloc)
237 {
238 	if (!actual_alloc)
239 		actual_alloc = random_len;
240 
241 	if ((size_t)*temp_len < actual_alloc)
242 		return -1;
243 
244 	map->len[idx] = (uint32_t)random_len;
245 	map->buf[idx] = temp;
246 
247 	if (lws_get_random(context, temp, random_len) != random_len) {
248 		lwsl_err("Problem getting random\n");
249 		return -1;
250 	}
251 
252 	*temp_len -= (int)actual_alloc;
253 
254 	return 0;
255 }
256 
257 int
lws_jws_alloc_element(struct lws_jws_map * map,int idx,char * temp,int * temp_len,size_t len,size_t actual_alloc)258 lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
259 		      int *temp_len, size_t len, size_t actual_alloc)
260 {
261 	if (!actual_alloc)
262 		actual_alloc = len;
263 
264 	if ((size_t)*temp_len < actual_alloc)
265 		return -1;
266 
267 	map->len[idx] = (uint32_t)len;
268 	map->buf[idx] = temp;
269 	*temp_len -= (int)actual_alloc;
270 
271 	return 0;
272 }
273 
274 int
lws_jws_base64_enc(const char * in,size_t in_len,char * out,size_t out_max)275 lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
276 {
277 	int n;
278 
279 	n = lws_b64_encode_string_url(in, (int)in_len, out, (int)out_max - 1);
280 	if (n < 0) {
281 		lwsl_notice("%s: in len %d too large for %d out buf\n",
282 				__func__, (int)in_len, (int)out_max);
283 		return n; /* too large for output buffer */
284 	}
285 
286 	/* trim the terminal = */
287 	while (n && out[n - 1] == '=')
288 		n--;
289 
290 	out[n] = '\0';
291 
292 	return n;
293 }
294 
295 int
lws_jws_b64_compact_map(const char * in,int len,struct lws_jws_map * map)296 lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
297 {
298 	int me = 0;
299 
300 	memset(map, 0, sizeof(*map));
301 
302 	map->buf[me] = (char *)in;
303 	map->len[me] = 0;
304 
305 	while (len--) {
306 		if (*in++ == '.') {
307 			if (++me == LWS_JWS_MAX_COMPACT_BLOCKS)
308 				return -1;
309 			map->buf[me] = (char *)in;
310 			map->len[me] = 0;
311 			continue;
312 		}
313 		map->len[me]++;
314 	}
315 
316 	return me + 1;
317 }
318 
319 /* b64 in, map contains decoded elements, if non-NULL,
320  * map_b64 set to b64 elements
321  */
322 
323 int
lws_jws_compact_decode(const char * in,int len,struct lws_jws_map * map,struct lws_jws_map * map_b64,char * out,int * out_len)324 lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
325 		       struct lws_jws_map *map_b64, char *out,
326 		       int *out_len)
327 {
328 	int blocks, n, m = 0;
329 
330 	if (!map_b64)
331 		map_b64 = map;
332 
333 	memset(map_b64, 0, sizeof(*map_b64));
334 	memset(map, 0, sizeof(*map));
335 
336 	blocks = lws_jws_b64_compact_map(in, len, map_b64);
337 
338 	if (blocks > LWS_JWS_MAX_COMPACT_BLOCKS)
339 		return -1;
340 
341 	while (m < blocks) {
342 		n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
343 					      out, *out_len);
344 		if (n < 0) {
345 			lwsl_err("%s: b64 decode failed\n", __func__);
346 			return -1;
347 		}
348 		/* replace the map entry with the decoded content */
349 		if (n)
350 			map->buf[m] = out;
351 		else
352 			map->buf[m] = NULL;
353 		map->len[m++] = (unsigned int)n;
354 		out += n;
355 		*out_len -= n;
356 
357 		if (*out_len < 1)
358 			return -1;
359 	}
360 
361 	return blocks;
362 }
363 
364 static int
lws_jws_compact_decode_map(struct lws_jws_map * map_b64,struct lws_jws_map * map,char * out,int * out_len)365 lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
366 			   char *out, int *out_len)
367 {
368 	int n, m = 0;
369 
370 	for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
371 		n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
372 					      out, *out_len);
373 		if (n < 0) {
374 			lwsl_err("%s: b64 decode failed\n", __func__);
375 			return -1;
376 		}
377 		/* replace the map entry with the decoded content */
378 		map->buf[m] = out;
379 		map->len[m++] = (unsigned int)n;
380 		out += n;
381 		*out_len -= n;
382 
383 		if (*out_len < 1)
384 			return -1;
385 	}
386 
387 	return 0;
388 }
389 
390 int
lws_jws_encode_section(const char * in,size_t in_len,int first,char ** p,char * end)391 lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
392 		       char *end)
393 {
394 	int n, len = lws_ptr_diff(end, (*p)) - 1;
395 	char *p_entry = *p;
396 
397 	if (len < 3)
398 		return -1;
399 
400 	if (!first)
401 		*(*p)++ = '.';
402 
403 	n = lws_jws_base64_enc(in, in_len, *p, (unsigned int)len - 1);
404 	if (n < 0)
405 		return -1;
406 
407 	*p += n;
408 
409 	return lws_ptr_diff((*p), p_entry);
410 }
411 
412 int
lws_jws_compact_encode(struct lws_jws_map * map_b64,const struct lws_jws_map * map,char * buf,int * len)413 lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
414 		       const struct lws_jws_map *map,	/* non-b64 */
415 		       char *buf, int *len)
416 {
417 	int n, m;
418 
419 	for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
420 		if (!map->buf[n]) {
421 			map_b64->buf[n] = NULL;
422 			map_b64->len[n] = 0;
423 			continue;
424 		}
425 		m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, (size_t)*len);
426 		if (m < 0)
427 			return -1;
428 		buf += m;
429 		*len -= m;
430 		if (*len < 1)
431 			return -1;
432 	}
433 
434 	return 0;
435 }
436 
437 /*
438  * This takes both a base64 -encoded map and a plaintext map.
439  *
440  * JWS demands base-64 encoded elements for hash computation and at least for
441  * the JOSE header and signature, decoded versions too.
442  */
443 
444 int
lws_jws_sig_confirm(struct lws_jws_map * map_b64,struct lws_jws_map * map,struct lws_jwk * jwk,struct lws_context * context)445 lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
446 		    struct lws_jwk *jwk, struct lws_context *context)
447 {
448 	enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5;
449 	char temp[256];
450 	int n, h_len, b = 3, temp_len = sizeof(temp);
451 	uint8_t digest[LWS_GENHASH_LARGEST];
452 	struct lws_genhash_ctx hash_ctx;
453 	struct lws_genec_ctx ecdsactx;
454 	struct lws_genrsa_ctx rsactx;
455 	struct lws_genhmac_ctx ctx;
456 	struct lws_jose jose;
457 
458 	lws_jose_init(&jose);
459 
460 	/* only valid if no signature or key */
461 	if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR])
462 		b = 2;
463 
464 	if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], (int)map->len[LJWS_JOSE],
465 			       temp, &temp_len) < 0 || !jose.alg) {
466 		lwsl_notice("%s: parse failed\n", __func__);
467 		return -1;
468 	}
469 
470 	if (!strcmp(jose.alg->alg, "none")) {
471 		/* "none" compact serialization has 2 blocks: jose.payload */
472 		if (b != 2 || jwk)
473 			return -1;
474 
475 		/* the lack of a key matches the lack of a signature */
476 		return 0;
477 	}
478 
479 	/* all other have 3 blocks: jose.payload.sig */
480 	if (b != 3 || !jwk) {
481 		lwsl_notice("%s: %d blocks\n", __func__, b);
482 		return -1;
483 	}
484 
485 	switch (jose.alg->algtype_signing) {
486 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
487 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
488 		padding = LGRSAM_PKCS1_OAEP_PSS;
489 		/* fallthru */
490 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
491 
492 		/* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */
493 
494 		if (jwk->kty != LWS_GENCRYPTO_KTY_RSA)
495 			return -1;
496 
497 		/* 6(RSA): compute the hash of the payload into "digest" */
498 
499 		if (lws_genhash_init(&hash_ctx, jose.alg->hash_type))
500 			return -1;
501 
502 		/*
503 		 * JWS Signing Input value:
504 		 *
505 		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
506 		 * 	BASE64URL(JWS Payload)
507 		 */
508 
509 		if (lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
510 						  map_b64->len[LJWS_JOSE]) ||
511 		    lws_genhash_update(&hash_ctx, ".", 1) ||
512 		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
513 						  map_b64->len[LJWS_PYLD]) ||
514 		    lws_genhash_destroy(&hash_ctx, digest)) {
515 			lws_genhash_destroy(&hash_ctx, NULL);
516 
517 			return -1;
518 		}
519 		// h_len = lws_genhash_size(jose.alg->hash_type);
520 
521 		if (lws_genrsa_create(&rsactx, jwk->e, context, padding,
522 				LWS_GENHASH_TYPE_UNKNOWN)) {
523 			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
524 				    __func__);
525 			return -1;
526 		}
527 
528 		n = lws_genrsa_hash_sig_verify(&rsactx, digest,
529 					       jose.alg->hash_type,
530 					       (uint8_t *)map->buf[LJWS_SIG],
531 					       map->len[LJWS_SIG]);
532 
533 		lws_genrsa_destroy(&rsactx);
534 		if (n < 0) {
535 			lwsl_notice("%s: decrypt fail\n", __func__);
536 			return -1;
537 		}
538 
539 		break;
540 
541 	case LWS_JOSE_ENCTYPE_NONE: /* HSxxx */
542 
543 		/* SHA256/384/512 HMAC */
544 
545 		h_len = (int)lws_genhmac_size(jose.alg->hmac_type);
546 
547 		/* 6) compute HMAC over payload */
548 
549 		if (lws_genhmac_init(&ctx, jose.alg->hmac_type,
550 				     jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
551 				     jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len))
552 			return -1;
553 
554 		/*
555 		 * JWS Signing Input value:
556 		 *
557 		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
558 		 *   BASE64URL(JWS Payload)
559 		 */
560 
561 		if (lws_genhmac_update(&ctx, map_b64->buf[LJWS_JOSE],
562 					     map_b64->len[LJWS_JOSE]) ||
563 		    lws_genhmac_update(&ctx, ".", 1) ||
564 		    lws_genhmac_update(&ctx, map_b64->buf[LJWS_PYLD],
565 					     map_b64->len[LJWS_PYLD]) ||
566 		    lws_genhmac_destroy(&ctx, digest)) {
567 			lws_genhmac_destroy(&ctx, NULL);
568 
569 			return -1;
570 		}
571 
572 		/* 7) Compare the computed and decoded hashes */
573 
574 		if (lws_timingsafe_bcmp(digest, map->buf[2], (uint32_t)h_len)) {
575 			lwsl_notice("digest mismatch\n");
576 
577 			return -1;
578 		}
579 
580 		break;
581 
582 	case LWS_JOSE_ENCTYPE_ECDSA:
583 
584 		/* ECDSA using SHA-256/384/512 */
585 
586 		/* Confirm the key coming in with this makes sense */
587 
588 		/* has to be an EC key :-) */
589 		if (jwk->kty != LWS_GENCRYPTO_KTY_EC)
590 			return -1;
591 
592 		/* key must state its curve */
593 		if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
594 			return -1;
595 
596 		/* key must match the selected alg curve */
597 		if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
598 				jose.alg->curve_name))
599 			return -1;
600 
601 		/*
602 		 * JWS Signing Input value:
603 		 *
604 		 * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
605 		 * 	BASE64URL(JWS Payload)
606 		 *
607 		 * Validating the JWS Signature is a bit different from the
608 		 * previous examples.  We need to split the 64 member octet
609 		 * sequence of the JWS Signature (which is base64url decoded
610 		 * from the value encoded in the JWS representation) into two
611 		 * 32 octet sequences, the first representing R and the second
612 		 * S.  We then pass the public key (x, y), the signature (R, S),
613 		 * and the JWS Signing Input (which is the initial substring of
614 		 * the JWS Compact Serialization representation up until but not
615 		 * including the second period character) to an ECDSA signature
616 		 * verifier that has been configured to use the P-256 curve with
617 		 * the SHA-256 hash function.
618 		 */
619 
620 		if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
621 		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
622 						  map_b64->len[LJWS_JOSE]) ||
623 		    lws_genhash_update(&hash_ctx, ".", 1) ||
624 		    lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
625 						  map_b64->len[LJWS_PYLD]) ||
626 		    lws_genhash_destroy(&hash_ctx, digest)) {
627 			lws_genhash_destroy(&hash_ctx, NULL);
628 
629 			return -1;
630 		}
631 
632 		h_len = (int)lws_genhash_size(jose.alg->hash_type);
633 
634 		if (lws_genecdsa_create(&ecdsactx, context, NULL)) {
635 			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
636 				    __func__);
637 			return -1;
638 		}
639 
640 		if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) {
641 			lws_genec_destroy(&ecdsactx);
642 			lwsl_notice("%s: ec key import fail\n", __func__);
643 			return -1;
644 		}
645 
646 		n = lws_genecdsa_hash_sig_verify_jws(&ecdsactx, digest,
647 						     jose.alg->hash_type,
648 						     jose.alg->keybits_fixed,
649 						  (uint8_t *)map->buf[LJWS_SIG],
650 						     map->len[LJWS_SIG]);
651 		lws_genec_destroy(&ecdsactx);
652 		if (n < 0) {
653 			lwsl_notice("%s: verify fail\n", __func__);
654 			return -1;
655 		}
656 
657 		break;
658 
659 	default:
660 		lwsl_err("%s: unknown alg from jose\n", __func__);
661 		return -1;
662 	}
663 
664 	return 0;
665 }
666 
667 /* it's already a b64 map, we will make a temp plain version */
668 
669 int
lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map * map_b64,struct lws_jwk * jwk,struct lws_context * context,char * temp,int * temp_len)670 lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
671 				    struct lws_jwk *jwk,
672 			            struct lws_context *context,
673 			            char *temp, int *temp_len)
674 {
675 	struct lws_jws_map map;
676 	int n;
677 
678 	n = lws_jws_compact_decode_map(map_b64, &map, temp, temp_len);
679 	if (n > 3 || n < 0)
680 		return -1;
681 
682 	return lws_jws_sig_confirm(map_b64, &map, jwk, context);
683 }
684 
685 /*
686  * it's already a compact / concatenated b64 string, we will make a temp
687  * plain version
688  */
689 
690 int
lws_jws_sig_confirm_compact_b64(const char * in,size_t len,struct lws_jws_map * map,struct lws_jwk * jwk,struct lws_context * context,char * temp,int * temp_len)691 lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
692 				struct lws_jws_map *map, struct lws_jwk *jwk,
693 				struct lws_context *context,
694 				char *temp, int *temp_len)
695 {
696 	struct lws_jws_map map_b64;
697 	int n;
698 
699 	if (lws_jws_b64_compact_map(in, (int)len, &map_b64) < 0)
700 		return -1;
701 
702 	n = lws_jws_compact_decode(in, (int)len, map, &map_b64, temp, temp_len);
703 	if (n > 3 || n < 0)
704 		return -1;
705 
706 	return lws_jws_sig_confirm(&map_b64, map, jwk, context);
707 }
708 
709 /* it's already plain, we will make a temp b64 version */
710 
711 int
lws_jws_sig_confirm_compact(struct lws_jws_map * map,struct lws_jwk * jwk,struct lws_context * context,char * temp,int * temp_len)712 lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
713 			    struct lws_context *context, char *temp,
714 			    int *temp_len)
715 {
716 	struct lws_jws_map map_b64;
717 
718 	if (lws_jws_compact_encode(&map_b64, map, temp, temp_len) < 0)
719 		return -1;
720 
721 	return lws_jws_sig_confirm(&map_b64, map, jwk, context);
722 }
723 
724 int
lws_jws_sig_confirm_json(const char * in,size_t len,struct lws_jws * jws,struct lws_jwk * jwk,struct lws_context * context,char * temp,int * temp_len)725 lws_jws_sig_confirm_json(const char *in, size_t len,
726 			 struct lws_jws *jws, struct lws_jwk *jwk,
727 			 struct lws_context *context,
728 			 char *temp, int *temp_len)
729 {
730 	if (lws_jws_json_parse(jws, (const uint8_t *)in,
731 			       (int)len, temp, temp_len)) {
732 		lwsl_err("%s: lws_jws_json_parse failed\n", __func__);
733 
734 		return -1;
735 	}
736 	return lws_jws_sig_confirm(&jws->map_b64, &jws->map, jwk, context);
737 }
738 
739 
740 int
lws_jws_sign_from_b64(struct lws_jose * jose,struct lws_jws * jws,char * b64_sig,size_t sig_len)741 lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
742 		      char *b64_sig, size_t sig_len)
743 {
744 	enum enum_genrsa_mode pad = LGRSAM_PKCS1_1_5;
745 	uint8_t digest[LWS_GENHASH_LARGEST];
746 	struct lws_genhash_ctx hash_ctx;
747 	struct lws_genec_ctx ecdsactx;
748 	struct lws_genrsa_ctx rsactx;
749 	uint8_t *buf;
750 	int n, m;
751 
752 	if (jose->alg->hash_type == LWS_GENHASH_TYPE_UNKNOWN &&
753 	    jose->alg->hmac_type == LWS_GENHMAC_TYPE_UNKNOWN &&
754 	    !strcmp(jose->alg->alg, "none"))
755 		return 0;
756 
757 	if (lws_genhash_init(&hash_ctx, jose->alg->hash_type) ||
758 	    lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_JOSE],
759 					  jws->map_b64.len[LJWS_JOSE]) ||
760 	    lws_genhash_update(&hash_ctx, ".", 1) ||
761 	    lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_PYLD],
762 					  jws->map_b64.len[LJWS_PYLD]) ||
763 	    lws_genhash_destroy(&hash_ctx, digest)) {
764 		lws_genhash_destroy(&hash_ctx, NULL);
765 
766 		return -1;
767 	}
768 
769 	switch (jose->alg->algtype_signing) {
770 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
771 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
772 		pad = LGRSAM_PKCS1_OAEP_PSS;
773 		/* fallthru */
774 	case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
775 
776 		if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA)
777 			return -1;
778 
779 		if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context,
780 				      pad, LWS_GENHASH_TYPE_UNKNOWN)) {
781 			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
782 				    __func__);
783 			return -1;
784 		}
785 
786 		n = (int)jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
787 		buf = lws_malloc((unsigned int)lws_base64_size(n), "jws sign");
788 		if (!buf)
789 			return -1;
790 
791 		n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type,
792 					 buf, (unsigned int)n);
793 		lws_genrsa_destroy(&rsactx);
794 		if (n < 0) {
795 			lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__);
796 			lws_free(buf);
797 
798 			return -1;
799 		}
800 
801 		n = lws_jws_base64_enc((char *)buf, (unsigned int)n, b64_sig, sig_len);
802 		lws_free(buf);
803 		if (n < 0) {
804 			lwsl_err("%s: lws_jws_base64_enc failed\n", __func__);
805 		}
806 
807 		return n;
808 
809 	case LWS_JOSE_ENCTYPE_NONE:
810 		return lws_jws_base64_enc((char *)digest,
811 					 lws_genhash_size(jose->alg->hash_type),
812 					  b64_sig, sig_len);
813 	case LWS_JOSE_ENCTYPE_ECDSA:
814 		/* ECDSA using SHA-256/384/512 */
815 
816 		/* the key coming in with this makes sense, right? */
817 
818 		/* has to be an EC key :-) */
819 		if (jws->jwk->kty != LWS_GENCRYPTO_KTY_EC)
820 			return -1;
821 
822 		/* key must state its curve */
823 		if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
824 			return -1;
825 
826 		/* must have all his pieces for a private key */
827 		if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf ||
828 		    !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf ||
829 		    !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
830 			return -1;
831 
832 		/* key must match the selected alg curve */
833 		if (strcmp((const char *)
834 				jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
835 			    jose->alg->curve_name))
836 			return -1;
837 
838 		if (lws_genecdsa_create(&ecdsactx, jws->context, NULL)) {
839 			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
840 				    __func__);
841 			return -1;
842 		}
843 
844 		if (lws_genecdsa_set_key(&ecdsactx, jws->jwk->e)) {
845 			lws_genec_destroy(&ecdsactx);
846 			lwsl_notice("%s: ec key import fail\n", __func__);
847 			return -1;
848 		}
849 		m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2;
850 		buf = lws_malloc((unsigned int)m, "jws sign");
851 		if (!buf)
852 			return -1;
853 
854 		n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest,
855 					       jose->alg->hash_type,
856 					       jose->alg->keybits_fixed,
857 					       (uint8_t *)buf, (unsigned int)m);
858 		lws_genec_destroy(&ecdsactx);
859 		if (n < 0) {
860 			lws_free(buf);
861 			lwsl_notice("%s: lws_genecdsa_hash_sign_jws fail\n",
862 					__func__);
863 			return -1;
864 		}
865 
866 		n = lws_jws_base64_enc((char *)buf, (unsigned int)m, b64_sig, sig_len);
867 		lws_free(buf);
868 
869 		return n;
870 
871 	default:
872 		break;
873 	}
874 
875 	/* unknown key type */
876 
877 	return -1;
878 }
879 
880 /*
881  * Flattened JWS JSON:
882  *
883  *  {
884  *    "payload":   "<payload contents>",
885  *    "protected": "<integrity-protected header contents>",
886  *    "header":    <non-integrity-protected header contents>,
887  *    "signature": "<signature contents>"
888  *   }
889  */
890 
891 int
lws_jws_write_flattened_json(struct lws_jws * jws,char * flattened,size_t len)892 lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
893 {
894 	size_t n = 0;
895 
896 	if (len < 1)
897 		return 1;
898 
899 	n += (unsigned int)lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
900 	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
901 			jws->map_b64.len[LJWS_PYLD], len - n);
902 	n = n + strlen(flattened + n);
903 
904 	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
905 	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
906 			jws->map_b64.len[LJWS_JOSE], len - n);
907 	n = n + strlen(flattened + n);
908 
909 	if (jws->map_b64.buf[LJWS_UHDR]) {
910 		n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
911 		lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
912 				jws->map_b64.len[LJWS_UHDR], len - n);
913 		n = n + strlen(flattened + n);
914 	}
915 
916 	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
917 	lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
918 			jws->map_b64.len[LJWS_SIG], len - n);
919 	n = n + strlen(flattened + n);
920 
921 	n += (unsigned int)lws_snprintf(flattened + n, len - n , "\"}\n");
922 
923 	return (n >= len - 1);
924 }
925 
926 int
lws_jws_write_compact(struct lws_jws * jws,char * compact,size_t len)927 lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
928 {
929 	size_t n = 0;
930 
931 	if (len < 1)
932 		return 1;
933 
934 	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
935 		     jws->map_b64.len[LJWS_JOSE], len - n);
936 	n += strlen(compact + n);
937 	if (n >= len - 1)
938 		return 1;
939 	compact[n++] = '.';
940 	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
941 		     jws->map_b64.len[LJWS_PYLD], len - n);
942 	n += strlen(compact + n);
943 	if (n >= len - 1)
944 		return 1;
945 	compact[n++] = '.';
946 	lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
947 		     jws->map_b64.len[LJWS_SIG], len - n);
948 	n += strlen(compact + n);
949 
950 	return n >= len - 1;
951 }
952 
953 int
lws_jwt_signed_validate(struct lws_context * ctx,struct lws_jwk * jwk,const char * alg_list,const char * com,size_t len,char * temp,int tl,char * out,size_t * out_len)954 lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
955 			const char *alg_list, const char *com, size_t len,
956 			char *temp, int tl, char *out, size_t *out_len)
957 {
958 	struct lws_tokenize ts;
959 	struct lws_jose jose;
960 	int otl = tl, r = 1;
961 	struct lws_jws jws;
962 	size_t n;
963 
964 	memset(&jws, 0, sizeof(jws));
965 	lws_jose_init(&jose);
966 
967 	/*
968 	 * Decode the b64.b64[.b64] compact serialization
969 	 * blocks
970 	 */
971 
972 	n = (size_t)lws_jws_compact_decode(com, (int)len, &jws.map, &jws.map_b64,
973 				   temp, &tl);
974 	if (n != 3) {
975 		lwsl_err("%s: concat_map failed: %d\n", __func__, (int)n);
976 		goto bail;
977 	}
978 
979 	temp += otl - tl;
980 	otl = tl;
981 
982 	/*
983 	 * Parse the JOSE header
984 	 */
985 
986 	if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
987 			       (int)jws.map.len[LJWS_JOSE], temp, &tl) < 0) {
988 		lwsl_err("%s: JOSE parse failed\n", __func__);
989 		goto bail;
990 	}
991 
992 	/*
993 	 * Insist to see an alg in there that we list as acceptable
994 	 */
995 
996 	lws_tokenize_init(&ts, alg_list, LWS_TOKENIZE_F_COMMA_SEP_LIST |
997 					 LWS_TOKENIZE_F_RFC7230_DELIMS);
998 	n = strlen(jose.alg->alg);
999 
1000 	do {
1001 		ts.e = (int8_t)lws_tokenize(&ts);
1002 		if (ts.e == LWS_TOKZE_TOKEN && ts.token_len == n &&
1003 		    !strncmp(jose.alg->alg, ts.token, ts.token_len))
1004 			break;
1005 	} while (ts.e != LWS_TOKZE_ENDED);
1006 
1007 	if (ts.e != LWS_TOKZE_TOKEN) {
1008 		lwsl_err("%s: JOSE using alg %s (accepted: %s)\n", __func__,
1009 			 jose.alg->alg, alg_list);
1010 		goto bail;
1011 	}
1012 
1013 	/* we liked the alg... now how about the crypto? */
1014 
1015 	if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, jwk, ctx) < 0) {
1016 		lwsl_notice("%s: confirm JWT sig failed\n",
1017 			    __func__);
1018 		goto bail;
1019 	}
1020 
1021 	/* yeah, it's validated... see about copying it out */
1022 
1023 	if (*out_len < jws.map.len[LJWS_PYLD] + 1) {
1024 		/* we don't have enough room */
1025 		r = 2;
1026 		goto bail;
1027 	}
1028 
1029 	memcpy(out, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
1030 	*out_len = jws.map.len[LJWS_PYLD];
1031 	out[jws.map.len[LJWS_PYLD]] = '\0';
1032 
1033 	r = 0;
1034 
1035 bail:
1036 	lws_jws_destroy(&jws);
1037 	lws_jose_destroy(&jose);
1038 
1039 	return r;
1040 }
1041 
lws_jwt_vsign_via_info(struct lws_context * ctx,struct lws_jwk * jwk,const struct lws_jwt_sign_info * info,const char * format,va_list ap)1042 static int lws_jwt_vsign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
1043     const struct lws_jwt_sign_info *info, const char *format, va_list ap)
1044 {
1045 	size_t actual_hdr_len;
1046 	struct lws_jose jose;
1047 	struct lws_jws jws;
1048 	va_list ap_cpy;
1049 	int n, r = 1;
1050 	int otl, tlr;
1051 	char *p, *q;
1052 
1053 	lws_jws_init(&jws, jwk, ctx);
1054 	lws_jose_init(&jose);
1055 
1056 	otl = tlr = info->tl;
1057 	p = info->temp;
1058 
1059 	/*
1060 	 * We either just use the provided info->jose_hdr, or build a
1061 	 * minimal header from info->alg
1062 	 */
1063 	actual_hdr_len = info->jose_hdr ? info->jose_hdr_len :
1064 					  10 + strlen(info->alg);
1065 
1066 	if (actual_hdr_len > INT_MAX) {
1067 	  goto bail;
1068 	}
1069 
1070 	if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, info->temp, &tlr,
1071 				  actual_hdr_len, 0)) {
1072 		lwsl_err("%s: temp space too small\n", __func__);
1073 		goto bail;
1074 	}
1075 
1076 	if (!info->jose_hdr) {
1077 
1078 		/* get algorithm from 'alg' string and write minimal JOSE header */
1079 		if (lws_gencrypto_jws_alg_to_definition(info->alg, &jose.alg)) {
1080 			lwsl_err("%s: unknown alg %s\n", __func__, info->alg);
1081 
1082 			goto bail;
1083 		}
1084 		jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(
1085 				(char *)jws.map.buf[LJWS_JOSE], (size_t)otl,
1086 						"{\"alg\":\"%s\"}", info->alg);
1087 	} else {
1088 
1089 		/*
1090 		 * Get algorithm by parsing the given JOSE header and copy it,
1091 		 * if it's ok
1092 		 */
1093 		if (lws_jws_parse_jose(&jose, info->jose_hdr,
1094 				       (int)actual_hdr_len, info->temp, &tlr)) {
1095 			lwsl_err("%s: invalid jose header\n", __func__);
1096 			goto bail;
1097 		}
1098 		tlr = otl;
1099 		memcpy((char *)jws.map.buf[LJWS_JOSE], info->jose_hdr,
1100 								actual_hdr_len);
1101 		jws.map.len[LJWS_JOSE] = (uint32_t)actual_hdr_len;
1102 		tlr -= (int)actual_hdr_len;
1103 	}
1104 
1105 	p += otl - tlr;
1106 	otl = tlr;
1107 
1108 	va_copy(ap_cpy, ap);
1109 	n = vsnprintf(NULL, 0, format, ap_cpy);
1110 	va_end(ap_cpy);
1111 	if (n + 2 >= tlr)
1112 		goto bail;
1113 
1114 	q = lws_malloc((unsigned int)n + 2, __func__);
1115 	if (!q)
1116 		goto bail;
1117 
1118 	vsnprintf(q, (unsigned int)n + 2, format, ap);
1119 
1120 	/* add the plaintext from stdin to the map and a b64 version */
1121 
1122 	jws.map.buf[LJWS_PYLD] = q;
1123 	jws.map.len[LJWS_PYLD] = (uint32_t)n;
1124 
1125 	if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, p, &tlr,
1126 				       jws.map.buf[LJWS_PYLD],
1127 				       jws.map.len[LJWS_PYLD]))
1128 		goto bail1;
1129 
1130 	p += otl - tlr;
1131 	otl = tlr;
1132 
1133 	/* add the b64 JOSE header to the b64 map */
1134 
1135 	if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, p, &tlr,
1136 				       jws.map.buf[LJWS_JOSE],
1137 				       jws.map.len[LJWS_JOSE]))
1138 		goto bail1;
1139 
1140 	p += otl - tlr;
1141 	otl = tlr;
1142 
1143 	/* prepare the space for the b64 signature in the map */
1144 
1145 	if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, p, &tlr,
1146 				  (size_t)lws_base64_size(LWS_JWE_LIMIT_KEY_ELEMENT_BYTES),
1147 				  0))
1148 		goto bail1;
1149 
1150 	/* sign the plaintext */
1151 
1152 	n = lws_jws_sign_from_b64(&jose, &jws,
1153 				  (char *)jws.map_b64.buf[LJWS_SIG],
1154 				  jws.map_b64.len[LJWS_SIG]);
1155 	if (n < 0)
1156 		goto bail1;
1157 
1158 	/* set the actual b64 signature size */
1159 	jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
1160 
1161 	/* create the compact JWS representation */
1162 	if (lws_jws_write_compact(&jws, info->out, *info->out_len))
1163 		goto bail1;
1164 
1165 	*info->out_len = strlen(info->out);
1166 
1167 	r = 0;
1168 
1169 bail1:
1170 	lws_free(q);
1171 
1172 bail:
1173 	jws.map.buf[LJWS_PYLD] = NULL;
1174 	jws.map.len[LJWS_PYLD] = 0;
1175 	lws_jws_destroy(&jws);
1176 	lws_jose_destroy(&jose);
1177 
1178 	return r;
1179 }
1180 
1181 int
lws_jwt_sign_via_info(struct lws_context * ctx,struct lws_jwk * jwk,const struct lws_jwt_sign_info * info,const char * format,...)1182 lws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
1183 		     const struct lws_jwt_sign_info *info, const char *format,
1184 		     ...)
1185 {
1186 	int ret;
1187 	va_list ap;
1188 
1189 	va_start(ap, format);
1190 	ret = lws_jwt_vsign_via_info(ctx, jwk, info, format, ap);
1191 	va_end(ap);
1192 
1193 	return ret;
1194 }
1195 
1196 int
lws_jwt_sign_compact(struct lws_context * ctx,struct lws_jwk * jwk,const char * alg,char * out,size_t * out_len,char * temp,int tl,const char * format,...)1197 lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
1198 		     const char *alg, char *out, size_t *out_len, char *temp,
1199 		     int tl, const char *format, ...)
1200 {
1201 	struct lws_jwt_sign_info info = {
1202 		.alg		= alg,
1203 		.jose_hdr	= NULL,
1204 		.out		= out,
1205 		.out_len	= out_len,
1206 		.temp		= temp,
1207 		.tl		= tl
1208 	};
1209 	int r = 1;
1210 	va_list ap;
1211 
1212 	va_start(ap, format);
1213 
1214 	r = lws_jwt_vsign_via_info(ctx, jwk, &info, format, ap);
1215 
1216 	va_end(ap);
1217 	return r;
1218 }
1219 
1220 int
lws_jwt_token_sanity(const char * in,size_t in_len,const char * iss,const char * aud,const char * csrf_in,char * sub,size_t sub_len,unsigned long * expiry_unix_time)1221 lws_jwt_token_sanity(const char *in, size_t in_len,
1222 		     const char *iss, const char *aud,
1223 		     const char *csrf_in,
1224 		     char *sub, size_t sub_len, unsigned long *expiry_unix_time)
1225 {
1226 	unsigned long now = lws_now_secs(), exp;
1227 	const char *cp;
1228 	size_t len;
1229 
1230 	/*
1231 	 * It has our issuer?
1232 	 */
1233 
1234 	if (lws_json_simple_strcmp(in, in_len, "\"iss\":", iss)) {
1235 		lwsl_notice("%s: iss mismatch\n", __func__);
1236 		return 1;
1237 	}
1238 
1239 	/*
1240 	 * ... it is indended for us to consume? (this is set
1241 	 * to the public base url for this sai instance)
1242 	 */
1243 	if (lws_json_simple_strcmp(in, in_len, "\"aud\":", aud)) {
1244 		lwsl_notice("%s: aud mismatch\n", __func__);
1245 		return 1;
1246 	}
1247 
1248 	/*
1249 	 * ...it's not too early for it?
1250 	 */
1251 	cp = lws_json_simple_find(in, in_len, "\"nbf\":", &len);
1252 	if (!cp || (unsigned long)atol(cp) > now) {
1253 		lwsl_notice("%s: nbf fail\n", __func__);
1254 		return 1;
1255 	}
1256 
1257 	/*
1258 	 * ... and not too late for it?
1259 	 */
1260 	cp = lws_json_simple_find(in, in_len, "\"exp\":", &len);
1261 	exp = (unsigned long)atol(cp);
1262 	if (!cp || (unsigned long)atol(cp) < now) {
1263 		lwsl_notice("%s: exp fail %lu vs %lu\n", __func__,
1264 				cp ? (unsigned long)atol(cp) : 0, now);
1265 		return 1;
1266 	}
1267 
1268 	/*
1269 	 * Caller cares about subject?  Then we must have it, and it can't be
1270 	 * empty.
1271 	 */
1272 
1273 	if (sub) {
1274 		cp = lws_json_simple_find(in, in_len, "\"sub\":", &len);
1275 		if (!cp || !len) {
1276 			lwsl_notice("%s: missing subject\n", __func__);
1277 			return 1;
1278 		}
1279 		lws_strnncpy(sub, cp, len, sub_len);
1280 	}
1281 
1282 	/*
1283 	 * If caller has been told a Cross Site Request Forgery (CSRF) nonce,
1284 	 * require this JWT to express the same CSRF... this makes generated
1285 	 * links for dangerous privileged auth'd actions expire with the JWT
1286 	 * that was accessing the site when the links were generated.  And it
1287 	 * leaves an attacker not knowing what links to synthesize unless he
1288 	 * can read the token or pages generated with it.
1289 	 *
1290 	 * Using this is very good for security, but it implies you must refresh
1291 	 * generated pages still when the auth token is expiring (and the user
1292 	 * must log in again).
1293 	 */
1294 
1295 	if (csrf_in &&
1296 	    lws_json_simple_strcmp(in, in_len, "\"csrf\":", csrf_in)) {
1297 		lwsl_notice("%s: csrf mismatch\n", __func__);
1298 		return 1;
1299 	}
1300 
1301 	if (expiry_unix_time)
1302 		*expiry_unix_time = exp;
1303 
1304 	return 0;
1305 }
1306