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 | /*! \defgroup jws JSON Web Signature |
26 | * ## JSON Web Signature API |
27 | * |
28 | * Lws provides an API to check and create RFC7515 JSON Web Signatures |
29 | * |
30 | * SHA256/384/512 HMAC, and RSA 256/384/512 are supported. |
31 | * |
32 | * The API uses your TLS library crypto, but works exactly the same no matter |
33 | * what your TLS backend is. |
34 | */ |
35 | ///@{ |
36 | |
37 | /* |
38 | * The maps are built to work with both JWS (LJWS_) and JWE (LJWE_), and are |
39 | * sized to the slightly larger JWE case. |
40 | */ |
41 | |
42 | enum enum_jws_sig_elements { |
43 | |
44 | /* JWS block namespace */ |
45 | LJWS_JOSE, |
46 | LJWS_PYLD, |
47 | LJWS_SIG, |
48 | LJWS_UHDR, |
49 | |
50 | /* JWE block namespace */ |
51 | LJWE_JOSE = 0, |
52 | LJWE_EKEY, |
53 | LJWE_IV, |
54 | LJWE_CTXT, |
55 | LJWE_ATAG, |
56 | LJWE_AAD, |
57 | |
58 | LWS_JWS_MAX_COMPACT_BLOCKS |
59 | }; |
60 | |
61 | struct lws_jws_map { |
62 | const char *buf[LWS_JWS_MAX_COMPACT_BLOCKS]; |
63 | uint32_t len[LWS_JWS_MAX_COMPACT_BLOCKS]; |
64 | }; |
65 | |
66 | #define LWS_JWS_MAX_SIGS 3 |
67 | |
68 | struct lws_jws { |
69 | struct lws_jwk *jwk; /* the struct lws_jwk containing the signing key */ |
70 | struct lws_context *context; /* the lws context (used to get random) */ |
71 | struct lws_jws_map map, map_b64; |
72 | }; |
73 | |
74 | /* jws EC signatures do not have ASN.1 in them, meaning they're incompatible |
75 | * with generic signatures. |
76 | */ |
77 | |
78 | /** |
79 | * lws_jws_init() - initialize a jws for use |
80 | * |
81 | * \param jws: pointer to the jws to initialize |
82 | * \param jwk: the jwk to use with this jws |
83 | * \param context: the lws_context to use |
84 | */ |
85 | LWS_VISIBLE LWS_EXTERN void |
86 | lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk, |
87 | struct lws_context *context); |
88 | |
89 | /** |
90 | * lws_jws_destroy() - scrub a jws |
91 | * |
92 | * \param jws: pointer to the jws to destroy |
93 | * |
94 | * Call before the jws goes out of scope. |
95 | * |
96 | * Elements defined in the jws are zeroed. |
97 | */ |
98 | LWS_VISIBLE LWS_EXTERN void |
99 | lws_jws_destroy(struct lws_jws *jws); |
100 | |
101 | /** |
102 | * lws_jws_sig_confirm_compact() - check signature |
103 | * |
104 | * \param map: pointers and lengths for each of the unencoded JWS elements |
105 | * \param jwk: public key |
106 | * \param context: lws_context |
107 | * \param temp: scratchpad |
108 | * \param temp_len: length of scratchpad |
109 | * |
110 | * Confirms the signature on a JWS. Use if you have non-b64 plain JWS elements |
111 | * in a map... it'll make a temp b64 version needed for comparison. See below |
112 | * for other variants. |
113 | * |
114 | * Returns 0 on match, else nonzero. |
115 | */ |
116 | LWS_VISIBLE LWS_EXTERN int |
117 | lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk, |
118 | struct lws_context *context, |
119 | char *temp, int *temp_len); |
120 | |
121 | LWS_VISIBLE LWS_EXTERN int |
122 | lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64, |
123 | struct lws_jwk *jwk, |
124 | struct lws_context *context, |
125 | char *temp, int *temp_len); |
126 | |
127 | /** |
128 | * lws_jws_sig_confirm_compact_b64() - check signature on b64 compact JWS |
129 | * |
130 | * \param in: pointer to b64 jose.payload[.hdr].sig |
131 | * \param len: bytes available at \p in |
132 | * \param map: map to take decoded non-b64 content |
133 | * \param jwk: public key |
134 | * \param context: lws_context |
135 | * \param temp: scratchpad |
136 | * \param temp_len: size of scratchpad |
137 | * |
138 | * Confirms the signature on a JWS. Use if you have you have b64 compact layout |
139 | * (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain |
140 | * version needed for comparison. |
141 | * |
142 | * Returns 0 on match, else nonzero. |
143 | */ |
144 | LWS_VISIBLE LWS_EXTERN int |
145 | lws_jws_sig_confirm_compact_b64(const char *in, size_t len, |
146 | struct lws_jws_map *map, |
147 | struct lws_jwk *jwk, |
148 | struct lws_context *context, |
149 | char *temp, int *temp_len); |
150 | |
151 | /** |
152 | * lws_jws_sig_confirm() - check signature on plain + b64 JWS elements |
153 | * |
154 | * \param map_b64: pointers and lengths for each of the b64-encoded JWS elements |
155 | * \param map: pointers and lengths for each of the unencoded JWS elements |
156 | * \param jwk: public key |
157 | * \param context: lws_context |
158 | * |
159 | * Confirms the signature on a JWS. Use if you have you already have both b64 |
160 | * compact layout (jose.payload.hdr.sig) and decoded JWS elements in maps. |
161 | * |
162 | * If you had the b64 string and called lws_jws_compact_decode() on it, you |
163 | * will end up with both maps, and can use this api version, saving needlessly |
164 | * regenerating any temp map. |
165 | * |
166 | * Returns 0 on match, else nonzero. |
167 | */ |
168 | LWS_VISIBLE LWS_EXTERN int |
169 | lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */ |
170 | struct lws_jws_map *map, /* non-b64 */ |
171 | struct lws_jwk *jwk, struct lws_context *context); |
172 | |
173 | /** |
174 | * lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload |
175 | * |
176 | * \param jose: jose header information |
177 | * \param jws: information to include in the signature |
178 | * \param b64_sig: output buffer for b64 signature |
179 | * \param sig_len: size of \p b64_sig output buffer |
180 | * |
181 | * This adds a b64-coded JWS signature of the b64-encoded protected header |
182 | * and b64-encoded payload, at \p b64_sig. The signature will be as large |
183 | * as the N element of the RSA key when the RSA key is used, eg, 512 bytes for |
184 | * a 4096-bit key, and then b64-encoding on top. |
185 | * |
186 | * In some special cases, there is only payload to sign and no header, in that |
187 | * case \p b64_hdr may be NULL, and only the payload will be hashed before |
188 | * signing. |
189 | * |
190 | * If successful, returns the length of the encoded signature written to |
191 | * \p b64_sig. If the jose signing type is unknown, 0 is returned. Otherwise |
192 | * -1 indicates failure. |
193 | */ |
194 | LWS_VISIBLE LWS_EXTERN int |
195 | lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig, |
196 | size_t sig_len); |
197 | |
198 | /** |
199 | * lws_jws_compact_decode() - converts and maps compact serialization b64 sections |
200 | * |
201 | * \param in: the incoming compact serialized b64 |
202 | * \param len: the length of the incoming compact serialized b64 |
203 | * \param map: pointer to the results structure |
204 | * \param map_b64: NULL, or pointer to a second results structure taking block |
205 | * information about the undecoded b64 |
206 | * \param out: buffer to hold decoded results |
207 | * \param out_len: size of out in bytes |
208 | * |
209 | * Returns number of sections (2 if "none", else 3), or -1 if illegal. |
210 | * |
211 | * map is set to point to the start and hold the length of each decoded block. |
212 | * If map_b64 is non-NULL, then it's set with information about the input b64 |
213 | * blocks. |
214 | */ |
215 | LWS_VISIBLE LWS_EXTERN int |
216 | lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map, |
217 | struct lws_jws_map *map_b64, char *out, int *out_len); |
218 | |
219 | LWS_VISIBLE LWS_EXTERN int |
220 | lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */ |
221 | const struct lws_jws_map *map, /* non-b64 */ |
222 | char *buf, int *out_len); |
223 | |
224 | LWS_VISIBLE LWS_EXTERN int |
225 | lws_jws_sig_confirm_json(const char *in, size_t len, |
226 | struct lws_jws *jws, struct lws_jwk *jwk, |
227 | struct lws_context *context, |
228 | char *temp, int *temp_len); |
229 | |
230 | /** |
231 | * lws_jws_write_flattened_json() - create flattened JSON sig |
232 | * |
233 | * \param jws: information to include in the signature |
234 | * \param flattened: output buffer for JSON |
235 | * \param len: size of \p flattened output buffer |
236 | * |
237 | */ |
238 | LWS_VISIBLE LWS_EXTERN int |
239 | lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len); |
240 | |
241 | /** |
242 | * lws_jws_write_compact() - create flattened JSON sig |
243 | * |
244 | * \param jws: information to include in the signature |
245 | * \param compact: output buffer for compact format |
246 | * \param len: size of \p flattened output buffer |
247 | * |
248 | */ |
249 | LWS_VISIBLE LWS_EXTERN int |
250 | lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len); |
251 | |
252 | |
253 | |
254 | /* |
255 | * below apis are not normally needed if dealing with whole JWS... they're |
256 | * useful for creating from scratch |
257 | */ |
258 | |
259 | |
260 | /** |
261 | * lws_jws_dup_element() - allocate space for an element and copy data into it |
262 | * |
263 | * \param map: map to create the element in |
264 | * \param idx: index of element in the map to create |
265 | * \param temp: space to allocate in |
266 | * \param temp_len: available space at temp |
267 | * \param in: data to duplicate into element |
268 | * \param in_len: length of data to duplicate |
269 | * \param actual_alloc: 0 for same as in_len, else actual allocation size |
270 | * |
271 | * Copies in_len from in to temp, if temp_len is sufficient. |
272 | * |
273 | * Returns 0 or -1 if not enough space in temp / temp_len. |
274 | * |
275 | * Over-allocation can be acheived by setting actual_alloc to the real |
276 | * allocation desired... in_len will be copied into it. |
277 | * |
278 | * *temp_len is reduced by actual_alloc if successful. |
279 | */ |
280 | LWS_VISIBLE LWS_EXTERN int |
281 | lws_jws_dup_element(struct lws_jws_map *map, int idx, |
282 | char *temp, int *temp_len, const void *in, size_t in_len, |
283 | size_t actual_alloc); |
284 | |
285 | /** |
286 | * lws_jws_randomize_element() - create an element and fill with random |
287 | * |
288 | * \param context: lws_context used for random |
289 | * \param map: map to create the element in |
290 | * \param idx: index of element in the map to create |
291 | * \param temp: space to allocate in |
292 | * \param temp_len: available space at temp |
293 | * \param random_len: length of data to fill with random |
294 | * \param actual_alloc: 0 for same as random_len, else actual allocation size |
295 | * |
296 | * Randomize random_len bytes at temp, if temp_len is sufficient. |
297 | * |
298 | * Returns 0 or -1 if not enough space in temp / temp_len. |
299 | * |
300 | * Over-allocation can be acheived by setting actual_alloc to the real |
301 | * allocation desired... the first random_len will be filled with random. |
302 | * |
303 | * *temp_len is reduced by actual_alloc if successful. |
304 | */ |
305 | LWS_VISIBLE LWS_EXTERN int |
306 | lws_jws_randomize_element(struct lws_context *context, |
307 | struct lws_jws_map *map, |
308 | int idx, char *temp, int *temp_len, size_t random_len, |
309 | size_t actual_alloc); |
310 | |
311 | /** |
312 | * lws_jws_alloc_element() - create an element and reserve space for content |
313 | * |
314 | * \param map: map to create the element in |
315 | * \param idx: index of element in the map to create |
316 | * \param temp: space to allocate in |
317 | * \param temp_len: available space at temp |
318 | * \param len: logical length of element |
319 | * \param actual_alloc: 0 for same as len, else actual allocation size |
320 | * |
321 | * Allocate len bytes at temp, if temp_len is sufficient. |
322 | * |
323 | * Returns 0 or -1 if not enough space in temp / temp_len. |
324 | * |
325 | * Over-allocation can be acheived by setting actual_alloc to the real |
326 | * allocation desired... the element logical length will be set to len. |
327 | * |
328 | * *temp_len is reduced by actual_alloc if successful. |
329 | */ |
330 | LWS_VISIBLE LWS_EXTERN int |
331 | lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp, |
332 | int *temp_len, size_t len, size_t actual_alloc); |
333 | |
334 | /** |
335 | * lws_jws_encode_b64_element() - create an b64-encoded element |
336 | * |
337 | * \param map: map to create the element in |
338 | * \param idx: index of element in the map to create |
339 | * \param temp: space to allocate in |
340 | * \param temp_len: available space at temp |
341 | * \param in: pointer to unencoded input |
342 | * \param in_len: length of unencoded input |
343 | * |
344 | * Allocate len bytes at temp, if temp_len is sufficient. |
345 | * |
346 | * Returns 0 or -1 if not enough space in temp / temp_len. |
347 | * |
348 | * Over-allocation can be acheived by setting actual_alloc to the real |
349 | * allocation desired... the element logical length will be set to len. |
350 | * |
351 | * *temp_len is reduced by actual_alloc if successful. |
352 | */ |
353 | LWS_VISIBLE LWS_EXTERN int |
354 | lws_jws_encode_b64_element(struct lws_jws_map *map, int idx, |
355 | char *temp, int *temp_len, const void *in, |
356 | size_t in_len); |
357 | |
358 | |
359 | /** |
360 | * lws_jws_b64_compact_map() - find block starts and lengths in compact b64 |
361 | * |
362 | * \param in: pointer to b64 jose.payload[.hdr].sig |
363 | * \param len: bytes available at \p in |
364 | * \param map: output struct with pointers and lengths for each JWS element |
365 | * |
366 | * Scans a jose.payload[.hdr].sig b64 string and notes where the blocks start |
367 | * and their length into \p map. |
368 | * |
369 | * Returns number of blocks if OK. May return <0 if malformed. |
370 | * May not fill all map entries. |
371 | */ |
372 | |
373 | LWS_VISIBLE LWS_EXTERN int |
374 | lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map); |
375 | |
376 | |
377 | /** |
378 | * lws_jws_base64_enc() - encode input data into b64url data |
379 | * |
380 | * \param in: the incoming plaintext |
381 | * \param in_len: the length of the incoming plaintext in bytes |
382 | * \param out: the buffer to store the b64url encoded data to |
383 | * \param out_max: the length of \p out in bytes |
384 | * |
385 | * Returns either -1 if problems, or the number of bytes written to \p out. |
386 | */ |
387 | LWS_VISIBLE LWS_EXTERN int |
388 | lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max); |
389 | |
390 | /** |
391 | * lws_jws_encode_section() - encode input data into b64url data, |
392 | * prepending . if not first |
393 | * |
394 | * \param in: the incoming plaintext |
395 | * \param in_len: the length of the incoming plaintext in bytes |
396 | * \param first: nonzero if the first section |
397 | * \param p: the buffer to store the b64url encoded data to |
398 | * \param end: just past the end of p |
399 | * |
400 | * Returns either -1 if problems, or the number of bytes written to \p out. |
401 | * If the section is not the first one, '.' is prepended. |
402 | */ |
403 | LWS_VISIBLE LWS_EXTERN int |
404 | lws_jws_encode_section(const char *in, size_t in_len, int first, char **p, |
405 | char *end); |
406 | |
407 | /** |
408 | * lws_jwt_signed_validate() - check a compact JWT against a key and alg |
409 | * |
410 | * \param ctx: the lws_context |
411 | * \param jwk: the key for checking the signature |
412 | * \param alg_list: the expected alg name, like "ES512" |
413 | * \param com: the compact JWT |
414 | * \param len: the length of com |
415 | * \param temp: a temp scratchpad |
416 | * \param tl: available length of temp scratchpad |
417 | * \param out: the output buffer to hold the validated plaintext |
418 | * \param out_len: on entry, max length of out; on exit, used length of out |
419 | * |
420 | * Returns nonzero if the JWT cannot be validated or the plaintext can't fit the |
421 | * provided output buffer, or 0 if it is validated as being signed by the |
422 | * provided jwk. |
423 | * |
424 | * If validated, the plaintext in the JWT is copied into out and out_len set to |
425 | * the used length. |
426 | * |
427 | * temp can be discarded or reused after the call returned, it's used to hold |
428 | * transformations of the B64 JWS in the JWT. |
429 | */ |
430 | LWS_VISIBLE LWS_EXTERN int |
431 | lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk, |
432 | const char *alg_list, const char *com, size_t len, |
433 | char *temp, int tl, char *out, size_t *out_len); |
434 | |
435 | /** |
436 | * lws_jwt_sign_compact() - generate a compact JWT using a key and alg |
437 | * |
438 | * \param ctx: the lws_context |
439 | * \param jwk: the signing key |
440 | * \param alg: the signing alg name, like "ES512" |
441 | * \param out: the output buffer to hold the signed JWT in compact form |
442 | * \param out_len: on entry, the length of out; on exit, the used amount of out |
443 | * \param temp: a temp scratchpad |
444 | * \param tl: available length of temp scratchpad |
445 | * \param format: a printf style format specification |
446 | * \param ...: zero or more args for the format specification |
447 | * |
448 | * Creates a JWT in a single step, from the format string and args through to |
449 | * outputting a well-formed compact JWT representation in out. |
450 | * |
451 | * Returns 0 if all is well and *out_len is the amount of data in out, else |
452 | * nonzero if failed. Temp must be large enough to hold various intermediate |
453 | * representations. |
454 | */ |
455 | LWS_VISIBLE LWS_EXTERN int |
456 | lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk, |
457 | const char *alg, char *out, size_t *out_len, char *temp, |
458 | int tl, const char *format, ...) LWS_FORMAT(8); |
459 | |
460 | struct lws_jwt_sign_info { |
461 | const char *alg; |
462 | /**< entry: signing alg name, like "RS256" */ |
463 | const char *jose_hdr; |
464 | /**< entry: optional JOSE hdr; if present, alg field is ignored; instead the |
465 | * whole claim object has to be provided in this parameter */ |
466 | size_t jose_hdr_len; |
467 | /**< entry: if jose_hdr is not NULL, JOSE header length without terminating '\0' */ |
468 | char *out; |
469 | /**< exit: signed JWT in compact form*/ |
470 | size_t *out_len; |
471 | /**< entry,exit: buffer size of out; actual size of JWT on exit */ |
472 | char *temp; |
473 | /**< exit undefined content, used by the function as a temporary scratchpad; MUST |
474 | * be large enogh to store various intermediate representations */ |
475 | int tl; |
476 | /**< entry: size of temp buffer */ |
477 | }; |
478 | |
479 | /** |
480 | * lws_jwt_sign_compact() - generate a compact JWT using a key and JOSE header |
481 | * |
482 | * \param ctx: the lws_context |
483 | * \param jwk: the signing key |
484 | * \param info: info describing the JWT's content and output/temp buffers |
485 | * \param format: a printf style format specification of the claims object |
486 | * \param ...: zero or more args for the format specification |
487 | * |
488 | * Creates a JWT in a single step, from the format string and args through to |
489 | * outputting a well-formed compact JWT representation in out. The provided |
490 | * JOSE header's syntax is checked before it is added to the JWT. |
491 | * |
492 | * Returns 0 if all is well and *out_len is the amount of data in out, else |
493 | * nonzero if failed. Temp must be large enough to hold various intermediate |
494 | * representations. |
495 | */ |
496 | LWS_VISIBLE LWS_EXTERN int |
497 | lws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk, |
498 | const struct lws_jwt_sign_info *info, const char *format, ...) LWS_FORMAT(4); |
499 | |
500 | /** |
501 | * lws_jwt_token_sanity() - check a validated jwt payload for sanity |
502 | * |
503 | * \param in: the JWT payload |
504 | * \param in_len: the length of the JWT payload |
505 | * \param iss: the expected issuer of the token |
506 | * \param aud: the expected audience of the token |
507 | * \param csrf_in: NULL, or the csrf token that came in on a URL |
508 | * \param sub: a buffer to hold the subject name in the JWT (eg, account name) |
509 | * \param sub_len: the max length of the sub buffer |
510 | * \param secs_left: set to the number of seconds of valid auth left if valid |
511 | * |
512 | * This performs some generic sanity tests on validated JWT payload... |
513 | * |
514 | * - the issuer is as expected |
515 | * - the audience is us |
516 | * - current time is OK for nbf ("not before") in the token |
517 | * - current time is OK for exp ("expiry") in the token |
518 | * - if csrf_in is not NULL, that the JWK has a csrf and it matches it |
519 | * - if sub is not NULL, that the JWK provides a subject (and copies it to sub) |
520 | * |
521 | * If the tests pass, *secs_left is set to the number of remaining seconds the |
522 | * auth is valid. |
523 | * |
524 | * Returns 0 if no inconsistency, else nonzero. |
525 | */ |
526 | LWS_VISIBLE LWS_EXTERN int |
527 | lws_jwt_token_sanity(const char *in, size_t in_len, |
528 | const char *iss, const char *aud, const char *csrf_in, |
529 | char *sub, size_t sub_len, unsigned long *exp_unix_time); |
530 | |
531 | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
532 | |
533 | struct lws_jwt_sign_set_cookie { |
534 | struct lws_jwk *jwk; |
535 | /**< entry: required signing key */ |
536 | const char *alg; |
537 | /**< entry: required signing alg, eg, "ES512" */ |
538 | const char *iss; |
539 | /**< entry: issuer name to use */ |
540 | const char *aud; |
541 | /**< entry: audience */ |
542 | const char *cookie_name; |
543 | /**< entry: the name of the cookie */ |
544 | char sub[33]; |
545 | /**< sign-entry, validate-exit: subject */ |
546 | const char *; |
547 | /**< sign-entry, validate-exit: |
548 | * optional "ext" JSON object contents for the JWT */ |
549 | size_t ; |
550 | /**< validate-exit: |
551 | * length of optional "ext" JSON object contents for the JWT */ |
552 | const char *csrf_in; |
553 | /**< validate-entry: |
554 | * NULL, or an external CSRF token to check against what is in the JWT */ |
555 | unsigned long expiry_unix_time; |
556 | /**< sign-entry: seconds the JWT and cookie may live, |
557 | * validate-exit: expiry unix time */ |
558 | }; |
559 | |
560 | /** |
561 | * lws_jwt_sign_token_set_http_cookie() - creates sets a JWT in a wsi cookie |
562 | * |
563 | * \param wsi: the wsi to create the cookie header on |
564 | * \param i: structure describing what should be in the JWT |
565 | * \param p: wsi headers area |
566 | * \param end: end of wsi headers area |
567 | * |
568 | * Creates a JWT specified \p i, and attaches it to the outgoing headers on |
569 | * wsi. Returns 0 if successful. |
570 | * |
571 | * Best-practice security restrictions are applied to the cookie set action, |
572 | * including forcing httponly, and __Host- prefix. As required by __Host-, the |
573 | * cookie Path is set to /. __Host- is applied by the function, the cookie_name |
574 | * should just be "xyz" for "__Host-xyz". |
575 | * |
576 | * \p extra_json should just be the bare JSON, a { } is provided around it by |
577 | * the function if it's non-NULL. For example, "\"authorization\": 1". |
578 | * |
579 | * It's recommended the secs parameter is kept as small as consistent with one |
580 | * user session on the site if possible, eg, 10 minutes or 20 minutes. At the |
581 | * server, it can determine how much time is left in the auth and inform the |
582 | * client; if the JWT validity expires, the page should reload so the UI always |
583 | * reflects what's possible to do with the authorization state correctly. If |
584 | * the JWT expires, the user can log back in using credentials usually stored in |
585 | * the browser and auto-filled-in, so this is not very inconvenient. |
586 | * |
587 | * This is a helper on top of the other JOSE and JWT apis that somewhat crosses |
588 | * over between JWT and HTTP, since it knows about cookies. So it is only built |
589 | * if both LWS_WITH_JOSE and one of the http-related roles enabled. |
590 | */ |
591 | LWS_VISIBLE LWS_EXTERN int |
592 | lws_jwt_sign_token_set_http_cookie(struct lws *wsi, |
593 | const struct lws_jwt_sign_set_cookie *i, |
594 | uint8_t **p, uint8_t *end); |
595 | LWS_VISIBLE LWS_EXTERN int |
596 | lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi, |
597 | struct lws_jwt_sign_set_cookie *i, |
598 | char *out, size_t *out_len); |
599 | #endif |
600 | |
601 | ///@} |
602 | |