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