lws-jws.h (21789B)
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 42enum 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 61struct 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 68struct 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 */ 85LWS_VISIBLE LWS_EXTERN void 86lws_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 */ 98LWS_VISIBLE LWS_EXTERN void 99lws_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 */ 116LWS_VISIBLE LWS_EXTERN int 117lws_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 121LWS_VISIBLE LWS_EXTERN int 122lws_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 */ 144LWS_VISIBLE LWS_EXTERN int 145lws_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 */ 168LWS_VISIBLE LWS_EXTERN int 169lws_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 */ 194LWS_VISIBLE LWS_EXTERN int 195lws_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 */ 215LWS_VISIBLE LWS_EXTERN int 216lws_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 219LWS_VISIBLE LWS_EXTERN int 220lws_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 224LWS_VISIBLE LWS_EXTERN int 225lws_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 */ 238LWS_VISIBLE LWS_EXTERN int 239lws_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 */ 249LWS_VISIBLE LWS_EXTERN int 250lws_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 */ 280LWS_VISIBLE LWS_EXTERN int 281lws_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 */ 305LWS_VISIBLE LWS_EXTERN int 306lws_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 */ 330LWS_VISIBLE LWS_EXTERN int 331lws_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 */ 353LWS_VISIBLE LWS_EXTERN int 354lws_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 373LWS_VISIBLE LWS_EXTERN int 374lws_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 */ 387LWS_VISIBLE LWS_EXTERN int 388lws_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 */ 403LWS_VISIBLE LWS_EXTERN int 404lws_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 */ 430LWS_VISIBLE LWS_EXTERN int 431lws_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 */ 455LWS_VISIBLE LWS_EXTERN int 456lws_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 460struct 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 */ 496LWS_VISIBLE LWS_EXTERN int 497lws_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 */ 526LWS_VISIBLE LWS_EXTERN int 527lws_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 533struct 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 *extra_json; 547 /**< sign-entry, validate-exit: 548 * optional "ext" JSON object contents for the JWT */ 549 size_t extra_json_len; 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 */ 591LWS_VISIBLE LWS_EXTERN int 592lws_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); 595LWS_VISIBLE LWS_EXTERN int 596lws_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///@}