jws.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  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. #include "private-lib-core.h"
  25. #include "private-lib-jose-jws.h"
  26. /*
  27. * Currently only support flattened or compact (implicitly single signature)
  28. */
  29. static const char * const jws_json[] = {
  30. "protected", /* base64u */
  31. "header", /* JSON */
  32. "payload", /* base64u payload */
  33. "signature", /* base64u signature */
  34. //"signatures[].protected",
  35. //"signatures[].header",
  36. //"signatures[].signature"
  37. };
  38. enum lws_jws_json_tok {
  39. LJWSJT_PROTECTED,
  40. LJWSJT_HEADER,
  41. LJWSJT_PAYLOAD,
  42. LJWSJT_SIGNATURE,
  43. // LJWSJT_SIGNATURES_PROTECTED,
  44. // LJWSJT_SIGNATURES_HEADER,
  45. // LJWSJT_SIGNATURES_SIGNATURE,
  46. };
  47. /* parse a JWS complete or flattened JSON object */
  48. struct jws_cb_args {
  49. struct lws_jws *jws;
  50. char *temp;
  51. int *temp_len;
  52. };
  53. static signed char
  54. lws_jws_json_cb(struct lejp_ctx *ctx, char reason)
  55. {
  56. struct jws_cb_args *args = (struct jws_cb_args *)ctx->user;
  57. int n, m;
  58. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  59. return 0;
  60. switch (ctx->path_match - 1) {
  61. /* strings */
  62. case LJWSJT_PROTECTED: /* base64u: JOSE: must contain 'alg' */
  63. m = LJWS_JOSE;
  64. goto append_string;
  65. case LJWSJT_PAYLOAD: /* base64u */
  66. m = LJWS_PYLD;
  67. goto append_string;
  68. case LJWSJT_SIGNATURE: /* base64u */
  69. m = LJWS_SIG;
  70. goto append_string;
  71. case LJWSJT_HEADER: /* unprotected freeform JSON */
  72. break;
  73. default:
  74. return -1;
  75. }
  76. return 0;
  77. append_string:
  78. if (*args->temp_len < ctx->npos) {
  79. lwsl_err("%s: out of parsing space\n", __func__);
  80. return -1;
  81. }
  82. /*
  83. * We keep both b64u and decoded in temp mapped using map / map_b64,
  84. * the jws signature is actually over the b64 content not the plaintext,
  85. * and we can't do it until we see the protected alg.
  86. */
  87. if (!args->jws->map_b64.buf[m]) {
  88. args->jws->map_b64.buf[m] = args->temp;
  89. args->jws->map_b64.len[m] = 0;
  90. }
  91. memcpy(args->temp, ctx->buf, ctx->npos);
  92. args->temp += ctx->npos;
  93. *args->temp_len -= ctx->npos;
  94. args->jws->map_b64.len[m] += ctx->npos;
  95. if (reason == LEJPCB_VAL_STR_END) {
  96. args->jws->map.buf[m] = args->temp;
  97. n = lws_b64_decode_string_len(
  98. (const char *)args->jws->map_b64.buf[m],
  99. args->jws->map_b64.len[m],
  100. (char *)args->temp, *args->temp_len);
  101. if (n < 0) {
  102. lwsl_err("%s: b64 decode failed: in len %d, m %d\n", __func__, (int)args->jws->map_b64.len[m], m);
  103. return -1;
  104. }
  105. args->temp += n;
  106. *args->temp_len -= n;
  107. args->jws->map.len[m] = n;
  108. }
  109. return 0;
  110. }
  111. static int
  112. lws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
  113. char *temp, int *temp_len)
  114. {
  115. struct jws_cb_args args;
  116. struct lejp_ctx jctx;
  117. int m = 0;
  118. args.jws = jws;
  119. args.temp = temp;
  120. args.temp_len = temp_len;
  121. lejp_construct(&jctx, lws_jws_json_cb, &args, jws_json,
  122. LWS_ARRAY_SIZE(jws_json));
  123. m = lejp_parse(&jctx, (uint8_t *)buf, len);
  124. lejp_destruct(&jctx);
  125. if (m < 0) {
  126. lwsl_notice("%s: parse returned %d\n", __func__, m);
  127. return -1;
  128. }
  129. return 0;
  130. }
  131. void
  132. lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
  133. struct lws_context *context)
  134. {
  135. memset(jws, 0, sizeof(*jws));
  136. jws->context = context;
  137. jws->jwk = jwk;
  138. }
  139. static void
  140. lws_jws_map_bzero(struct lws_jws_map *map)
  141. {
  142. int n;
  143. /* no need to scrub first jose header element (it can be canned then) */
  144. for (n = 1; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++)
  145. if (map->buf[n])
  146. lws_explicit_bzero((void *)map->buf[n], map->len[n]);
  147. }
  148. void
  149. lws_jws_destroy(struct lws_jws *jws)
  150. {
  151. lws_jws_map_bzero(&jws->map);
  152. jws->jwk = NULL;
  153. }
  154. int
  155. lws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
  156. const void *in, size_t in_len, size_t actual_alloc)
  157. {
  158. if (!actual_alloc)
  159. actual_alloc = in_len;
  160. if ((size_t)*temp_len < actual_alloc)
  161. return -1;
  162. memcpy(temp, in, in_len);
  163. map->len[idx] = (uint32_t)in_len;
  164. map->buf[idx] = temp;
  165. *temp_len -= (int)actual_alloc;
  166. return 0;
  167. }
  168. int
  169. lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
  170. char *temp, int *temp_len, const void *in,
  171. size_t in_len)
  172. {
  173. int n;
  174. if (*temp_len < lws_base64_size((int)in_len))
  175. return -1;
  176. n = lws_jws_base64_enc(in, in_len, temp, *temp_len);
  177. if (n < 0)
  178. return -1;
  179. map->len[idx] = n;
  180. map->buf[idx] = temp;
  181. *temp_len -= n;
  182. return 0;
  183. }
  184. int
  185. lws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
  186. int idx, char *temp, int *temp_len, size_t random_len,
  187. size_t actual_alloc)
  188. {
  189. if (!actual_alloc)
  190. actual_alloc = random_len;
  191. if ((size_t)*temp_len < actual_alloc)
  192. return -1;
  193. map->len[idx] = (uint32_t)random_len;
  194. map->buf[idx] = temp;
  195. if (lws_get_random(context, temp, random_len) != random_len) {
  196. lwsl_err("Problem getting random\n");
  197. return -1;
  198. }
  199. *temp_len -= (int)actual_alloc;
  200. return 0;
  201. }
  202. int
  203. lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
  204. int *temp_len, size_t len, size_t actual_alloc)
  205. {
  206. if (!actual_alloc)
  207. actual_alloc = len;
  208. if ((size_t)*temp_len < actual_alloc)
  209. return -1;
  210. map->len[idx] = (uint32_t)len;
  211. map->buf[idx] = temp;
  212. *temp_len -= (int)actual_alloc;
  213. return 0;
  214. }
  215. int
  216. lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
  217. {
  218. int n;
  219. n = lws_b64_encode_string_url(in, (int)in_len, out, (int)out_max - 1);
  220. if (n < 0) {
  221. lwsl_notice("%s: in len %d too large for %d out buf\n",
  222. __func__, (int)in_len, (int)out_max);
  223. return n; /* too large for output buffer */
  224. }
  225. /* trim the terminal = */
  226. while (n && out[n - 1] == '=')
  227. n--;
  228. out[n] = '\0';
  229. return n;
  230. }
  231. int
  232. lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
  233. {
  234. int me = 0;
  235. memset(map, 0, sizeof(*map));
  236. map->buf[me] = (char *)in;
  237. map->len[me] = 0;
  238. while (len--) {
  239. if (*in++ == '.') {
  240. if (++me == LWS_JWS_MAX_COMPACT_BLOCKS)
  241. return -1;
  242. map->buf[me] = (char *)in;
  243. map->len[me] = 0;
  244. continue;
  245. }
  246. map->len[me]++;
  247. }
  248. return me + 1;
  249. }
  250. /* b64 in, map contains decoded elements, if non-NULL,
  251. * map_b64 set to b64 elements
  252. */
  253. int
  254. lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
  255. struct lws_jws_map *map_b64, char *out,
  256. int *out_len)
  257. {
  258. int blocks, n, m = 0;
  259. if (!map_b64)
  260. map_b64 = map;
  261. memset(map_b64, 0, sizeof(*map_b64));
  262. memset(map, 0, sizeof(*map));
  263. blocks = lws_jws_b64_compact_map(in, len, map_b64);
  264. if (blocks > LWS_JWS_MAX_COMPACT_BLOCKS)
  265. return -1;
  266. while (m < blocks) {
  267. n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
  268. out, *out_len);
  269. if (n < 0) {
  270. lwsl_err("%s: b64 decode failed\n", __func__);
  271. return -1;
  272. }
  273. /* replace the map entry with the decoded content */
  274. if (n)
  275. map->buf[m] = out;
  276. else
  277. map->buf[m] = NULL;
  278. map->len[m++] = n;
  279. out += n;
  280. *out_len -= n;
  281. if (*out_len < 1)
  282. return -1;
  283. }
  284. return blocks;
  285. }
  286. static int
  287. lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
  288. char *out, int *out_len)
  289. {
  290. int n, m = 0;
  291. for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
  292. n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
  293. out, *out_len);
  294. if (n < 0) {
  295. lwsl_err("%s: b64 decode failed\n", __func__);
  296. return -1;
  297. }
  298. /* replace the map entry with the decoded content */
  299. map->buf[m] = out;
  300. map->len[m++] = n;
  301. out += n;
  302. *out_len -= n;
  303. if (*out_len < 1)
  304. return -1;
  305. }
  306. return 0;
  307. }
  308. int
  309. lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
  310. char *end)
  311. {
  312. int n, len = lws_ptr_diff(end, (*p)) - 1;
  313. char *p_entry = *p;
  314. if (len < 3)
  315. return -1;
  316. if (!first)
  317. *(*p)++ = '.';
  318. n = lws_jws_base64_enc(in, in_len, *p, len - 1);
  319. if (n < 0)
  320. return -1;
  321. *p += n;
  322. return lws_ptr_diff((*p), p_entry);
  323. }
  324. int
  325. lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
  326. const struct lws_jws_map *map, /* non-b64 */
  327. char *buf, int *len)
  328. {
  329. int n, m;
  330. for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
  331. if (!map->buf[n]) {
  332. map_b64->buf[n] = NULL;
  333. map_b64->len[n] = 0;
  334. continue;
  335. }
  336. m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, *len);
  337. if (m < 0)
  338. return -1;
  339. buf += m;
  340. *len -= m;
  341. if (*len < 1)
  342. return -1;
  343. }
  344. return 0;
  345. }
  346. /*
  347. * This takes both a base64 -encoded map and a plaintext map.
  348. *
  349. * JWS demands base-64 encoded elements for hash computation and at least for
  350. * the JOSE header and signature, decoded versions too.
  351. */
  352. int
  353. lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
  354. struct lws_jwk *jwk, struct lws_context *context)
  355. {
  356. enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5;
  357. char temp[256];
  358. int n, h_len, b = 3, temp_len = sizeof(temp);
  359. uint8_t digest[LWS_GENHASH_LARGEST];
  360. struct lws_genhash_ctx hash_ctx;
  361. struct lws_genec_ctx ecdsactx;
  362. struct lws_genrsa_ctx rsactx;
  363. struct lws_genhmac_ctx ctx;
  364. struct lws_jose jose;
  365. lws_jose_init(&jose);
  366. /* only valid if no signature or key */
  367. if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR])
  368. b = 2;
  369. if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], map->len[LJWS_JOSE],
  370. temp, &temp_len) < 0 || !jose.alg) {
  371. lwsl_notice("%s: parse failed\n", __func__);
  372. return -1;
  373. }
  374. if (!strcmp(jose.alg->alg, "none")) {
  375. /* "none" compact serialization has 2 blocks: jose.payload */
  376. if (b != 2 || jwk)
  377. return -1;
  378. /* the lack of a key matches the lack of a signature */
  379. return 0;
  380. }
  381. /* all other have 3 blocks: jose.payload.sig */
  382. if (b != 3 || !jwk) {
  383. lwsl_notice("%s: %d blocks\n", __func__, b);
  384. return -1;
  385. }
  386. switch (jose.alg->algtype_signing) {
  387. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
  388. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
  389. padding = LGRSAM_PKCS1_OAEP_PSS;
  390. /* fallthru */
  391. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
  392. /* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */
  393. if (jwk->kty != LWS_GENCRYPTO_KTY_RSA)
  394. return -1;
  395. /* 6(RSA): compute the hash of the payload into "digest" */
  396. if (lws_genhash_init(&hash_ctx, jose.alg->hash_type))
  397. return -1;
  398. /*
  399. * JWS Signing Input value:
  400. *
  401. * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
  402. * BASE64URL(JWS Payload)
  403. */
  404. if (lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
  405. map_b64->len[LJWS_JOSE]) ||
  406. lws_genhash_update(&hash_ctx, ".", 1) ||
  407. lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
  408. map_b64->len[LJWS_PYLD]) ||
  409. lws_genhash_destroy(&hash_ctx, digest)) {
  410. lws_genhash_destroy(&hash_ctx, NULL);
  411. return -1;
  412. }
  413. // h_len = lws_genhash_size(jose.alg->hash_type);
  414. if (lws_genrsa_create(&rsactx, jwk->e, context, padding,
  415. LWS_GENHASH_TYPE_UNKNOWN)) {
  416. lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
  417. __func__);
  418. return -1;
  419. }
  420. n = lws_genrsa_hash_sig_verify(&rsactx, digest,
  421. jose.alg->hash_type,
  422. (uint8_t *)map->buf[LJWS_SIG],
  423. map->len[LJWS_SIG]);
  424. lws_genrsa_destroy(&rsactx);
  425. if (n < 0) {
  426. lwsl_notice("%s: decrypt fail\n", __func__);
  427. return -1;
  428. }
  429. break;
  430. case LWS_JOSE_ENCTYPE_NONE: /* HSxxx */
  431. /* SHA256/384/512 HMAC */
  432. h_len = (int)lws_genhmac_size(jose.alg->hmac_type);
  433. /* 6) compute HMAC over payload */
  434. if (lws_genhmac_init(&ctx, jose.alg->hmac_type,
  435. jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
  436. jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len))
  437. return -1;
  438. /*
  439. * JWS Signing Input value:
  440. *
  441. * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
  442. * BASE64URL(JWS Payload)
  443. */
  444. if (lws_genhmac_update(&ctx, map_b64->buf[LJWS_JOSE],
  445. map_b64->len[LJWS_JOSE]) ||
  446. lws_genhmac_update(&ctx, ".", 1) ||
  447. lws_genhmac_update(&ctx, map_b64->buf[LJWS_PYLD],
  448. map_b64->len[LJWS_PYLD]) ||
  449. lws_genhmac_destroy(&ctx, digest)) {
  450. lws_genhmac_destroy(&ctx, NULL);
  451. return -1;
  452. }
  453. /* 7) Compare the computed and decoded hashes */
  454. if (lws_timingsafe_bcmp(digest, map->buf[2], h_len)) {
  455. lwsl_notice("digest mismatch\n");
  456. return -1;
  457. }
  458. break;
  459. case LWS_JOSE_ENCTYPE_ECDSA:
  460. /* ECDSA using SHA-256/384/512 */
  461. /* Confirm the key coming in with this makes sense */
  462. /* has to be an EC key :-) */
  463. if (jwk->kty != LWS_GENCRYPTO_KTY_EC)
  464. return -1;
  465. /* key must state its curve */
  466. if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
  467. return -1;
  468. /* key must match the selected alg curve */
  469. if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
  470. jose.alg->curve_name))
  471. return -1;
  472. /*
  473. * JWS Signing Input value:
  474. *
  475. * BASE64URL(UTF8(JWS Protected Header)) || '.' ||
  476. * BASE64URL(JWS Payload)
  477. *
  478. * Validating the JWS Signature is a bit different from the
  479. * previous examples. We need to split the 64 member octet
  480. * sequence of the JWS Signature (which is base64url decoded
  481. * from the value encoded in the JWS representation) into two
  482. * 32 octet sequences, the first representing R and the second
  483. * S. We then pass the public key (x, y), the signature (R, S),
  484. * and the JWS Signing Input (which is the initial substring of
  485. * the JWS Compact Serialization representation up until but not
  486. * including the second period character) to an ECDSA signature
  487. * verifier that has been configured to use the P-256 curve with
  488. * the SHA-256 hash function.
  489. */
  490. if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) ||
  491. lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE],
  492. map_b64->len[LJWS_JOSE]) ||
  493. lws_genhash_update(&hash_ctx, ".", 1) ||
  494. lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD],
  495. map_b64->len[LJWS_PYLD]) ||
  496. lws_genhash_destroy(&hash_ctx, digest)) {
  497. lws_genhash_destroy(&hash_ctx, NULL);
  498. return -1;
  499. }
  500. h_len = (int)lws_genhash_size(jose.alg->hash_type);
  501. if (lws_genecdsa_create(&ecdsactx, context, NULL)) {
  502. lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
  503. __func__);
  504. return -1;
  505. }
  506. if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) {
  507. lws_genec_destroy(&ecdsactx);
  508. lwsl_notice("%s: ec key import fail\n", __func__);
  509. return -1;
  510. }
  511. n = lws_genecdsa_hash_sig_verify_jws(&ecdsactx, digest,
  512. jose.alg->hash_type,
  513. jose.alg->keybits_fixed,
  514. (uint8_t *)map->buf[LJWS_SIG],
  515. map->len[LJWS_SIG]);
  516. lws_genec_destroy(&ecdsactx);
  517. if (n < 0) {
  518. lwsl_notice("%s: verify fail\n", __func__);
  519. return -1;
  520. }
  521. break;
  522. default:
  523. lwsl_err("%s: unknown alg from jose\n", __func__);
  524. return -1;
  525. }
  526. return 0;
  527. }
  528. /* it's already a b64 map, we will make a temp plain version */
  529. int
  530. lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
  531. struct lws_jwk *jwk,
  532. struct lws_context *context,
  533. char *temp, int *temp_len)
  534. {
  535. struct lws_jws_map map;
  536. int n;
  537. n = lws_jws_compact_decode_map(map_b64, &map, temp, temp_len);
  538. if (n > 3 || n < 0)
  539. return -1;
  540. return lws_jws_sig_confirm(map_b64, &map, jwk, context);
  541. }
  542. /*
  543. * it's already a compact / concatenated b64 string, we will make a temp
  544. * plain version
  545. */
  546. int
  547. lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
  548. struct lws_jws_map *map, struct lws_jwk *jwk,
  549. struct lws_context *context,
  550. char *temp, int *temp_len)
  551. {
  552. struct lws_jws_map map_b64;
  553. int n;
  554. if (lws_jws_b64_compact_map(in, (int)len, &map_b64) < 0)
  555. return -1;
  556. n = lws_jws_compact_decode(in, (int)len, map, &map_b64, temp, temp_len);
  557. if (n > 3 || n < 0)
  558. return -1;
  559. return lws_jws_sig_confirm(&map_b64, map, jwk, context);
  560. }
  561. /* it's already plain, we will make a temp b64 version */
  562. int
  563. lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
  564. struct lws_context *context, char *temp,
  565. int *temp_len)
  566. {
  567. struct lws_jws_map map_b64;
  568. if (lws_jws_compact_encode(&map_b64, map, temp, temp_len) < 0)
  569. return -1;
  570. return lws_jws_sig_confirm(&map_b64, map, jwk, context);
  571. }
  572. int
  573. lws_jws_sig_confirm_json(const char *in, size_t len,
  574. struct lws_jws *jws, struct lws_jwk *jwk,
  575. struct lws_context *context,
  576. char *temp, int *temp_len)
  577. {
  578. if (lws_jws_json_parse(jws, (const uint8_t *)in,
  579. (int)len, temp, temp_len)) {
  580. lwsl_err("%s: lws_jws_json_parse failed\n", __func__);
  581. return -1;
  582. }
  583. return lws_jws_sig_confirm(&jws->map_b64, &jws->map, jwk, context);
  584. }
  585. int
  586. lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
  587. char *b64_sig, size_t sig_len)
  588. {
  589. enum enum_genrsa_mode pad = LGRSAM_PKCS1_1_5;
  590. uint8_t digest[LWS_GENHASH_LARGEST];
  591. struct lws_genhash_ctx hash_ctx;
  592. struct lws_genec_ctx ecdsactx;
  593. struct lws_genrsa_ctx rsactx;
  594. uint8_t *buf;
  595. int n, m;
  596. if (jose->alg->hash_type == LWS_GENHASH_TYPE_UNKNOWN &&
  597. jose->alg->hmac_type == LWS_GENHMAC_TYPE_UNKNOWN &&
  598. !strcmp(jose->alg->alg, "none"))
  599. return 0;
  600. if (lws_genhash_init(&hash_ctx, jose->alg->hash_type) ||
  601. lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_JOSE],
  602. jws->map_b64.len[LJWS_JOSE]) ||
  603. lws_genhash_update(&hash_ctx, ".", 1) ||
  604. lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_PYLD],
  605. jws->map_b64.len[LJWS_PYLD]) ||
  606. lws_genhash_destroy(&hash_ctx, digest)) {
  607. lws_genhash_destroy(&hash_ctx, NULL);
  608. return -1;
  609. }
  610. switch (jose->alg->algtype_signing) {
  611. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS:
  612. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP:
  613. pad = LGRSAM_PKCS1_OAEP_PSS;
  614. /* fallthru */
  615. case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5:
  616. if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA)
  617. return -1;
  618. if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context,
  619. pad, LWS_GENHASH_TYPE_UNKNOWN)) {
  620. lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
  621. __func__);
  622. return -1;
  623. }
  624. n = jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
  625. buf = lws_malloc(lws_base64_size(n), "jws sign");
  626. if (!buf)
  627. return -1;
  628. n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type,
  629. buf, n);
  630. lws_genrsa_destroy(&rsactx);
  631. if (n < 0) {
  632. lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__);
  633. lws_free(buf);
  634. return -1;
  635. }
  636. n = lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len);
  637. lws_free(buf);
  638. if (n < 0) {
  639. lwsl_err("%s: lws_jws_base64_enc failed\n", __func__);
  640. }
  641. return n;
  642. case LWS_JOSE_ENCTYPE_NONE:
  643. return lws_jws_base64_enc((char *)digest,
  644. lws_genhash_size(jose->alg->hash_type),
  645. b64_sig, sig_len);
  646. case LWS_JOSE_ENCTYPE_ECDSA:
  647. /* ECDSA using SHA-256/384/512 */
  648. /* the key coming in with this makes sense, right? */
  649. /* has to be an EC key :-) */
  650. if (jws->jwk->kty != LWS_GENCRYPTO_KTY_EC)
  651. return -1;
  652. /* key must state its curve */
  653. if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
  654. return -1;
  655. /* must have all his pieces for a private key */
  656. if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf ||
  657. !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf ||
  658. !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
  659. return -1;
  660. /* key must match the selected alg curve */
  661. if (strcmp((const char *)
  662. jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
  663. jose->alg->curve_name))
  664. return -1;
  665. if (lws_genecdsa_create(&ecdsactx, jws->context, NULL)) {
  666. lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
  667. __func__);
  668. return -1;
  669. }
  670. if (lws_genecdsa_set_key(&ecdsactx, jws->jwk->e)) {
  671. lws_genec_destroy(&ecdsactx);
  672. lwsl_notice("%s: ec key import fail\n", __func__);
  673. return -1;
  674. }
  675. m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2;
  676. buf = lws_malloc(m, "jws sign");
  677. if (!buf)
  678. return -1;
  679. n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest,
  680. jose->alg->hash_type,
  681. jose->alg->keybits_fixed,
  682. (uint8_t *)buf, m);
  683. lws_genec_destroy(&ecdsactx);
  684. if (n < 0) {
  685. lws_free(buf);
  686. lwsl_notice("%s: lws_genecdsa_hash_sign_jws fail\n",
  687. __func__);
  688. return -1;
  689. }
  690. n = lws_jws_base64_enc((char *)buf, m, b64_sig, sig_len);
  691. lws_free(buf);
  692. return n;
  693. default:
  694. break;
  695. }
  696. /* unknown key type */
  697. return -1;
  698. }
  699. /*
  700. * Flattened JWS JSON:
  701. *
  702. * {
  703. * "payload": "<payload contents>",
  704. * "protected": "<integrity-protected header contents>",
  705. * "header": <non-integrity-protected header contents>,
  706. * "signature": "<signature contents>"
  707. * }
  708. */
  709. int
  710. lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
  711. {
  712. size_t n = 0;
  713. if (len < 1)
  714. return 1;
  715. n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
  716. lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
  717. jws->map_b64.len[LJWS_PYLD], len - n);
  718. n += strlen(flattened + n);
  719. n += lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
  720. lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
  721. jws->map_b64.len[LJWS_JOSE], len - n);
  722. n += strlen(flattened + n);
  723. if (jws->map_b64.buf[LJWS_UHDR]) {
  724. n += lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
  725. lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
  726. jws->map_b64.len[LJWS_UHDR], len - n);
  727. n += strlen(flattened + n);
  728. }
  729. n += lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
  730. lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
  731. jws->map_b64.len[LJWS_SIG], len - n);
  732. n += strlen(flattened + n);
  733. n += lws_snprintf(flattened + n, len - n , "\"}\n");
  734. return (n >= len - 1);
  735. }
  736. int
  737. lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
  738. {
  739. size_t n = 0;
  740. if (len < 1)
  741. return 1;
  742. lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
  743. jws->map_b64.len[LJWS_JOSE], len - n);
  744. n += strlen(compact + n);
  745. if (n >= len - 1)
  746. return 1;
  747. compact[n++] = '.';
  748. lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
  749. jws->map_b64.len[LJWS_PYLD], len - n);
  750. n += strlen(compact + n);
  751. if (n >= len - 1)
  752. return 1;
  753. compact[n++] = '.';
  754. lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
  755. jws->map_b64.len[LJWS_SIG], len - n);
  756. n += strlen(compact + n);
  757. return n >= len - 1;
  758. }
  759. int
  760. lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
  761. const char *alg_list, const char *com, size_t len,
  762. char *temp, int tl, char *out, size_t *out_len)
  763. {
  764. struct lws_tokenize ts;
  765. struct lws_jose jose;
  766. int otl = tl, r = 1;
  767. struct lws_jws jws;
  768. size_t n;
  769. memset(&jws, 0, sizeof(jws));
  770. lws_jose_init(&jose);
  771. /*
  772. * Decode the b64.b64[.b64] compact serialization
  773. * blocks
  774. */
  775. n = lws_jws_compact_decode(com, (int)len, &jws.map, &jws.map_b64,
  776. temp, &tl);
  777. if (n != 3) {
  778. lwsl_err("%s: concat_map failed: %d\n", __func__, (int)n);
  779. goto bail;
  780. }
  781. temp += otl - tl;
  782. otl = tl;
  783. /*
  784. * Parse the JOSE header
  785. */
  786. if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
  787. jws.map.len[LJWS_JOSE], temp, &tl) < 0) {
  788. lwsl_err("%s: JOSE parse failed\n", __func__);
  789. goto bail;
  790. }
  791. /*
  792. * Insist to see an alg in there that we list as acceptable
  793. */
  794. lws_tokenize_init(&ts, alg_list, LWS_TOKENIZE_F_COMMA_SEP_LIST |
  795. LWS_TOKENIZE_F_RFC7230_DELIMS);
  796. n = strlen(jose.alg->alg);
  797. do {
  798. ts.e = lws_tokenize(&ts);
  799. if (ts.e == LWS_TOKZE_TOKEN && ts.token_len == n &&
  800. !strncmp(jose.alg->alg, ts.token, ts.token_len))
  801. break;
  802. } while (ts.e != LWS_TOKZE_ENDED);
  803. if (ts.e != LWS_TOKZE_TOKEN) {
  804. lwsl_err("%s: JOSE using alg %s (accepted: %s)\n", __func__,
  805. jose.alg->alg, alg_list);
  806. goto bail;
  807. }
  808. /* we liked the alg... now how about the crypto? */
  809. if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, jwk, ctx) < 0) {
  810. lwsl_notice("%s: confirm JWT sig failed\n",
  811. __func__);
  812. goto bail;
  813. }
  814. /* yeah, it's validated... see about copying it out */
  815. if (*out_len < jws.map.len[LJWS_PYLD] + 1) {
  816. /* we don't have enough room */
  817. r = 2;
  818. goto bail;
  819. }
  820. memcpy(out, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
  821. *out_len = jws.map.len[LJWS_PYLD];
  822. out[jws.map.len[LJWS_PYLD]] = '\0';
  823. r = 0;
  824. bail:
  825. lws_jws_destroy(&jws);
  826. lws_jose_destroy(&jose);
  827. return r;
  828. }
  829. int
  830. lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
  831. const char *alg, char *out, size_t *out_len, char *temp,
  832. int tl, const char *format, ...)
  833. {
  834. int n, r = 1, otl = tl;
  835. struct lws_jose jose;
  836. struct lws_jws jws;
  837. va_list ap;
  838. char *q;
  839. lws_jws_init(&jws, jwk, ctx);
  840. lws_jose_init(&jose);
  841. if (lws_gencrypto_jws_alg_to_definition(alg, &jose.alg)) {
  842. lwsl_err("%s: unknown alg %s\n", __func__, alg);
  843. goto bail;
  844. }
  845. /* create JOSE header, also needed for output */
  846. if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, temp, &tl,
  847. strlen(alg) + 10, 0)) {
  848. lwsl_err("%s: temp space too small\n", __func__);
  849. return 1;
  850. }
  851. jws.map.len[LJWS_JOSE] = lws_snprintf((char *)jws.map.buf[LJWS_JOSE],
  852. tl, "{\"alg\":\"%s\"}", alg);
  853. temp += otl - tl;
  854. otl = tl;
  855. va_start(ap, format);
  856. n = vsnprintf(NULL, 0, format, ap);
  857. va_end(ap);
  858. if (n + 2 >= tl)
  859. goto bail;
  860. q = lws_malloc(n + 2, __func__);
  861. if (!q)
  862. goto bail;
  863. va_start(ap, format);
  864. vsnprintf(q, n + 2, format, ap);
  865. va_end(ap);
  866. /* add the plaintext from stdin to the map and a b64 version */
  867. jws.map.buf[LJWS_PYLD] = q;
  868. jws.map.len[LJWS_PYLD] = n;
  869. if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, temp, &tl,
  870. jws.map.buf[LJWS_PYLD],
  871. jws.map.len[LJWS_PYLD]))
  872. goto bail1;
  873. temp += otl - tl;
  874. otl = tl;
  875. /* add the b64 JOSE header to the b64 map */
  876. if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, temp, &tl,
  877. jws.map.buf[LJWS_JOSE],
  878. jws.map.len[LJWS_JOSE]))
  879. goto bail1;
  880. temp += otl - tl;
  881. otl = tl;
  882. /* prepare the space for the b64 signature in the map */
  883. if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, temp, &tl,
  884. lws_base64_size(LWS_JWE_LIMIT_KEY_ELEMENT_BYTES),
  885. 0))
  886. goto bail1;
  887. /* sign the plaintext */
  888. n = lws_jws_sign_from_b64(&jose, &jws,
  889. (char *)jws.map_b64.buf[LJWS_SIG],
  890. jws.map_b64.len[LJWS_SIG]);
  891. if (n < 0)
  892. goto bail1;
  893. /* set the actual b64 signature size */
  894. jws.map_b64.len[LJWS_SIG] = n;
  895. /* create the compact JWS representation */
  896. if (lws_jws_write_compact(&jws, out, *out_len))
  897. goto bail1;
  898. *out_len = strlen(out);
  899. r = 0;
  900. bail1:
  901. lws_free(q);
  902. bail:
  903. jws.map.buf[LJWS_PYLD] = NULL;
  904. jws.map.len[LJWS_PYLD] = 0;
  905. lws_jws_destroy(&jws);
  906. lws_jose_destroy(&jose);
  907. return r;
  908. }
  909. int
  910. lws_jwt_token_sanity(const char *in, size_t in_len,
  911. const char *iss, const char *aud,
  912. const char *csrf_in,
  913. char *sub, size_t sub_len, unsigned long *expiry_unix_time)
  914. {
  915. unsigned long now = lws_now_secs(), exp;
  916. const char *cp;
  917. size_t len;
  918. /*
  919. * It has our issuer?
  920. */
  921. if (lws_json_simple_strcmp(in, in_len, "\"iss\":", iss)) {
  922. lwsl_notice("%s: iss mismatch\n", __func__);
  923. return 1;
  924. }
  925. /*
  926. * ... it is indended for us to consume? (this is set
  927. * to the public base url for this sai instance)
  928. */
  929. if (lws_json_simple_strcmp(in, in_len, "\"aud\":", aud)) {
  930. lwsl_notice("%s: aud mismatch\n", __func__);
  931. return 1;
  932. }
  933. /*
  934. * ...it's not too early for it?
  935. */
  936. cp = lws_json_simple_find(in, in_len, "\"nbf\":", &len);
  937. if (!cp || (unsigned long)atol(cp) > now) {
  938. lwsl_notice("%s: nbf fail\n", __func__);
  939. return 1;
  940. }
  941. /*
  942. * ... and not too late for it?
  943. */
  944. cp = lws_json_simple_find(in, in_len, "\"exp\":", &len);
  945. exp = (unsigned long)atol(cp);
  946. if (!cp || (unsigned long)atol(cp) < now) {
  947. lwsl_notice("%s: exp fail %lu vs %lu\n", __func__,
  948. cp ? (unsigned long)atol(cp) : 0, now);
  949. return 1;
  950. }
  951. /*
  952. * Caller cares about subject? Then we must have it, and it can't be
  953. * empty.
  954. */
  955. if (sub) {
  956. cp = lws_json_simple_find(in, in_len, "\"sub\":", &len);
  957. if (!cp || !len) {
  958. lwsl_notice("%s: missing subject\n", __func__);
  959. return 1;
  960. }
  961. lws_strnncpy(sub, cp, len, sub_len);
  962. }
  963. /*
  964. * If caller has been told a Cross Site Request Forgery (CSRF) nonce,
  965. * require this JWT to express the same CSRF... this makes generated
  966. * links for dangerous privileged auth'd actions expire with the JWT
  967. * that was accessing the site when the links were generated. And it
  968. * leaves an attacker not knowing what links to synthesize unless he
  969. * can read the token or pages generated with it.
  970. *
  971. * Using this is very good for security, but it implies you must refresh
  972. * generated pages still when the auth token is expiring (and the user
  973. * must log in again).
  974. */
  975. if (csrf_in &&
  976. lws_json_simple_strcmp(in, in_len, "\"csrf\":", csrf_in)) {
  977. lwsl_notice("%s: csrf mismatch\n", __func__);
  978. return 1;
  979. }
  980. if (expiry_unix_time)
  981. *expiry_unix_time = exp;
  982. return 0;
  983. }