jose.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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. * JOSE is actually specified as part of JWS RFC7515. JWE references RFC7515
  25. * to specify its JOSE JSON object. So it lives in ./lib/jose/jws/jose.c.
  26. */
  27. #include "private-lib-core.h"
  28. #include "jose/private-lib-jose.h"
  29. #include <stdint.h>
  30. static const char * const jws_jose[] = {
  31. "alg", /* REQUIRED */
  32. "jku",
  33. "jwk",
  34. "kid",
  35. "x5u",
  36. "x5c",
  37. "x5t",
  38. "x5t#S256",
  39. "typ",
  40. "cty",
  41. "crit",
  42. /* valid for JWE only below here */
  43. "recipients[].header",
  44. "recipients[].header.alg",
  45. "recipients[].header.kid",
  46. "recipients[].encrypted_key",
  47. "enc",
  48. "zip", /* ("DEF" = deflate) */
  49. "epk", /* valid for JWE ECDH only */
  50. "apu", /* valid for JWE ECDH only */
  51. "apv", /* valid for JWE ECDH only */
  52. "iv", /* valid for JWE AES only */
  53. "tag", /* valid for JWE AES only */
  54. "p2s", /* valid for JWE PBES2 only */
  55. "p2c" /* valid for JWE PBES2 only */
  56. };
  57. struct jose_cb_args {
  58. struct lws_jose *jose;
  59. struct lejp_ctx jwk_jctx; /* fake lejp context used to parse epk */
  60. struct lws_jwk_parse_state jps; /* fake jwk parse state */
  61. char *temp;
  62. int *temp_len;
  63. unsigned int is_jwe;
  64. unsigned int recipients_array;
  65. int recip;
  66. };
  67. /*
  68. * JWE A.4.7 Complete JWE JSON Serialization example
  69. *
  70. * LEJPCB_CONSTRUCTED
  71. * LEJPCB_START
  72. * LEJPCB_OBJECT_START
  73. *
  74. * protected LEJPCB_PAIR_NAME
  75. * protected LEJPCB_VAL_STR_START
  76. * protected LEJPCB_VAL_STR_END
  77. *
  78. * unprotected LEJPCB_PAIR_NAME
  79. * unprotected LEJPCB_OBJECT_START
  80. * unprotected.jku LEJPCB_PAIR_NAME
  81. * unprotected.jku LEJPCB_VAL_STR_START
  82. * unprotected.jku LEJPCB_VAL_STR_END
  83. * unprotected.jku LEJPCB_OBJECT_END
  84. *
  85. * recipients LEJPCB_PAIR_NAME
  86. * recipients[] LEJPCB_ARRAY_START
  87. *
  88. * recipients[] LEJPCB_OBJECT_START
  89. * recipients[].header LEJPCB_PAIR_NAME
  90. * recipients[].header LEJPCB_OBJECT_START
  91. * recipients[].header.alg LEJPCB_PAIR_NAME
  92. * recipients[].header.alg LEJPCB_VAL_STR_START
  93. * recipients[].header.alg LEJPCB_VAL_STR_END
  94. * recipients[].header.kid LEJPCB_PAIR_NAME
  95. * recipients[].header.kid LEJPCB_VAL_STR_START
  96. * recipients[].header.kid LEJPCB_VAL_STR_END
  97. * recipients[] LEJPCB_OBJECT_END
  98. * recipients[].encrypted_key LEJPCB_PAIR_NAME
  99. * recipients[].encrypted_key LEJPCB_VAL_STR_START
  100. * recipients[].encrypted_key LEJPCB_VAL_STR_CHUNK
  101. * recipients[].encrypted_key LEJPCB_VAL_STR_END
  102. * recipients[] LEJPCB_OBJECT_END (ctx->sp = 1)
  103. *
  104. * recipients[] LEJPCB_OBJECT_START
  105. * recipients[].header LEJPCB_PAIR_NAME
  106. * recipients[].header LEJPCB_OBJECT_START
  107. * recipients[].header.alg LEJPCB_PAIR_NAME
  108. * recipients[].header.alg LEJPCB_VAL_STR_START
  109. * recipients[].header.alg LEJPCB_VAL_STR_END
  110. * recipients[].header.kid LEJPCB_PAIR_NAME
  111. * recipients[].header.kid LEJPCB_VAL_STR_START
  112. * recipients[].header.kid LEJPCB_VAL_STR_END
  113. * recipients[] LEJPCB_OBJECT_END
  114. * recipients[].encrypted_key LEJPCB_PAIR_NAME
  115. * recipients[].encrypted_key LEJPCB_VAL_STR_START
  116. * recipients[].encrypted_key LEJPCB_VAL_STR_END
  117. * recipients[] LEJPCB_OBJECT_END (ctx->sp = 1)
  118. *
  119. * recipients[] LEJPCB_ARRAY_END
  120. *
  121. * iv LEJPCB_PAIR_NAME
  122. * iv LEJPCB_VAL_STR_START
  123. * iv LEJPCB_VAL_STR_END
  124. * ciphertext LEJPCB_PAIR_NAME
  125. * ciphertext LEJPCB_VAL_STR_START
  126. * ciphertext LEJPCB_VAL_STR_END
  127. * tag LEJPCB_PAIR_NAME
  128. * tag LEJPCB_VAL_STR_START
  129. * tag LEJPCB_VAL_STR_END
  130. *
  131. * tag LEJPCB_OBJECT_END
  132. * tag LEJPCB_COMPLETE
  133. * tag LEJPCB_DESTRUCTED
  134. *
  135. */
  136. /*
  137. * RFC7516 7.2.2
  138. *
  139. * Note that when using the flattened syntax, just as when using the
  140. * general syntax, any unprotected Header Parameter values can reside in
  141. * either the "unprotected" member or the "header" member, or in both.
  142. */
  143. static signed char
  144. lws_jws_jose_cb(struct lejp_ctx *ctx, char reason)
  145. {
  146. struct jose_cb_args *args = (struct jose_cb_args *)ctx->user;
  147. int n; //, dest;
  148. /*
  149. * In JOSE JSON, the element "epk" contains a fully-formed JWK.
  150. *
  151. * For JOSE paths beginning "epk.", we pass them through to a JWK
  152. * LEJP subcontext to parse using the JWK parser directly.
  153. */
  154. if (args->is_jwe && !strncmp(ctx->path, "epk.", 4)) {
  155. memcpy(args->jwk_jctx.path, ctx->path + 4,
  156. sizeof(ctx->path) - 4);
  157. memcpy(args->jwk_jctx.buf, ctx->buf, ctx->npos);
  158. args->jwk_jctx.npos = ctx->npos;
  159. if (!ctx->path_match)
  160. args->jwk_jctx.path_match = 0;
  161. lejp_check_path_match(&args->jwk_jctx);
  162. if (args->jwk_jctx.path_match)
  163. args->jwk_jctx.pst[args->jwk_jctx.pst_sp].
  164. callback(&args->jwk_jctx, reason);
  165. }
  166. // lwsl_notice("%s: %s %d (%d)\n", __func__, ctx->path, reason, ctx->sp);
  167. /* at the end of each recipients[] entry, bump recipients count */
  168. if (args->is_jwe && reason == LEJPCB_OBJECT_END && ctx->sp == 1 &&
  169. !strcmp(ctx->path, "recipients[]"))
  170. args->jose->recipients++;
  171. if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
  172. return 0;
  173. //dest = ctx->path_match - 1;
  174. switch (ctx->path_match - 1) {
  175. /* strings */
  176. case LJJHI_ALG: /* REQUIRED */
  177. /*
  178. * look up whether we support this alg and point the caller at
  179. * its definition if so
  180. */
  181. if (!args->is_jwe &&
  182. lws_gencrypto_jws_alg_to_definition(ctx->buf,
  183. &args->jose->alg)) {
  184. lwsl_notice("%s: unknown alg '%s'\n", __func__,
  185. ctx->buf);
  186. return -1;
  187. }
  188. if (args->is_jwe &&
  189. lws_gencrypto_jwe_alg_to_definition(ctx->buf,
  190. &args->jose->alg)) {
  191. lwsl_notice("%s: unknown JWE alg '%s'\n", __func__,
  192. ctx->buf);
  193. return -1;
  194. }
  195. return 0;
  196. case LJJHI_TYP: /* Optional: string: media type */
  197. lws_strnncpy(args->jose->typ, ctx->buf, ctx->npos,
  198. sizeof(args->jose->typ));
  199. break;
  200. case LJJHI_JKU: /* Optional: string */
  201. case LJJHI_KID: /* Optional: string */
  202. case LJJHI_X5U: /* Optional: string: url of public key cert / chain */
  203. case LJJHI_CTY: /* Optional: string: content media type */
  204. /* base64 */
  205. case LJJHI_X5C: /* Optional: base64 (NOT -url): actual cert */
  206. /* base64-url */
  207. case LJJHI_X5T: /* Optional: base64url: SHA-1 of actual cert */
  208. case LJJHI_X5T_S256: /* Optional: base64url: SHA-256 of actual cert */
  209. /* array of strings */
  210. case LJJHI_CRIT: /* Optional for send, REQUIRED: array of strings:
  211. * mustn't contain standardized strings or null set */
  212. break;
  213. /* jwk child */
  214. case LJJHI_JWK: /* Optional: jwk JSON object: public key: */
  215. /* past here, JWE only */
  216. case LJJHI_RECIPS_HDR:
  217. if (!args->is_jwe) {
  218. lwsl_info("%s: recipients in jws\n", __func__);
  219. return -1;
  220. }
  221. args->recipients_array = 1;
  222. break;
  223. case LJJHI_RECIPS_HDR_ALG:
  224. case LJJHI_RECIPS_HDR_KID:
  225. break;
  226. case LJJHI_RECIPS_EKEY:
  227. if (!args->is_jwe) {
  228. lwsl_info("%s: recipients in jws\n", __func__);
  229. return -1;
  230. }
  231. args->recipients_array = 1;
  232. //dest = ;
  233. goto append_string;
  234. case LJJHI_ENC: /* JWE only: Mandatory: string */
  235. if (!args->is_jwe) {
  236. lwsl_info("%s: enc in jws\n", __func__);
  237. return -1;
  238. }
  239. if (lws_gencrypto_jwe_enc_to_definition(ctx->buf,
  240. &args->jose->enc_alg)) {
  241. lwsl_notice("%s: unknown enc '%s'\n", __func__,
  242. ctx->buf);
  243. return -1;
  244. }
  245. break;
  246. case LJJHI_ZIP: /* JWE only: Optional: string ("DEF" = deflate) */
  247. if (!args->is_jwe)
  248. return -1;
  249. goto append_string;
  250. case LJJHI_EPK: /* Additional arg for JWE ECDH */
  251. if (!args->is_jwe)
  252. return -1;
  253. /* Ephemeral key... this JSON subsection is actually a JWK */
  254. lwsl_err("LJJHI_EPK\n");
  255. break;
  256. case LJJHI_APU: /* Additional arg for JWE ECDH */
  257. if (!args->is_jwe)
  258. return -1;
  259. /* Agreement Party U */
  260. goto append_string;
  261. case LJJHI_APV: /* Additional arg for JWE ECDH */
  262. if (!args->is_jwe)
  263. return -1;
  264. /* Agreement Party V */
  265. goto append_string;
  266. case LJJHI_IV: /* Additional arg for JWE AES */
  267. if (!args->is_jwe)
  268. return -1;
  269. goto append_string;
  270. case LJJHI_TAG: /* Additional arg for JWE AES */
  271. if (!args->is_jwe)
  272. return -1;
  273. goto append_string;
  274. case LJJHI_P2S: /* Additional arg for JWE PBES2 */
  275. if (!args->is_jwe)
  276. return -1;
  277. goto append_string;
  278. case LJJHI_P2C: /* Additional arg for JWE PBES2 */
  279. if (!args->is_jwe)
  280. return -1;
  281. goto append_string;
  282. /* ignore what we don't understand */
  283. default:
  284. return 0;
  285. }
  286. return 0;
  287. append_string:
  288. if (*args->temp_len < ctx->npos) {
  289. lwsl_err("%s: out of parsing space\n", __func__);
  290. return -1;
  291. }
  292. if (!args->jose->e[ctx->path_match - 1].buf) {
  293. args->jose->e[ctx->path_match - 1].buf = (uint8_t *)args->temp;
  294. args->jose->e[ctx->path_match - 1].len = 0;
  295. }
  296. memcpy(args->temp, ctx->buf, ctx->npos);
  297. args->temp += ctx->npos;
  298. *args->temp_len -= ctx->npos;
  299. args->jose->e[ctx->path_match - 1].len += ctx->npos;
  300. if (reason == LEJPCB_VAL_STR_END) {
  301. n = lws_b64_decode_string_len(
  302. (const char *)args->jose->e[ctx->path_match - 1].buf,
  303. args->jose->e[ctx->path_match - 1].len,
  304. (char *)args->jose->e[ctx->path_match - 1].buf,
  305. args->jose->e[ctx->path_match - 1].len + 1);
  306. if (n < 0) {
  307. lwsl_err("%s: b64 decode failed\n", __func__);
  308. return -1;
  309. }
  310. args->temp -= args->jose->e[ctx->path_match - 1].len - n - 1;
  311. *args->temp_len +=
  312. args->jose->e[ctx->path_match - 1].len - n - 1;
  313. args->jose->e[ctx->path_match - 1].len = n;
  314. }
  315. return 0;
  316. }
  317. void
  318. lws_jose_init(struct lws_jose *jose)
  319. {
  320. memset(jose, 0, sizeof(*jose));
  321. }
  322. static void
  323. lws_jose_recip_destroy(struct lws_jws_recpient *r)
  324. {
  325. lws_jwk_destroy(&r->jwk_ephemeral);
  326. lws_jwk_destroy(&r->jwk);
  327. }
  328. void
  329. lws_jose_destroy(struct lws_jose *jose)
  330. {
  331. int n;
  332. for (n = 0; n < (int)LWS_ARRAY_SIZE(jose->recipient); n++)
  333. lws_jose_recip_destroy(&jose->recipient[n]);
  334. }
  335. static int
  336. lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
  337. char *temp, int *temp_len, int is_jwe)
  338. {
  339. struct lejp_ctx jctx;
  340. struct jose_cb_args args;
  341. int m;
  342. if (is_jwe)
  343. /* prepare a context for JOSE epk ephemeral jwk parsing */
  344. lws_jwk_init_jps(&args.jwk_jctx, &args.jps,
  345. &jose->recipient[jose->recipients].jwk_ephemeral,
  346. NULL, NULL);
  347. args.is_jwe = is_jwe;
  348. args.temp = temp;
  349. args.temp_len = temp_len;
  350. args.jose = jose;
  351. args.recip = 0;
  352. args.recipients_array = 0;
  353. jose->recipients = 0;
  354. lejp_construct(&jctx, lws_jws_jose_cb, &args, jws_jose,
  355. LWS_ARRAY_SIZE(jws_jose));
  356. m = lejp_parse(&jctx, (uint8_t *)buf, n);
  357. lejp_destruct(&jctx);
  358. if (m < 0) {
  359. lwsl_notice("%s: parse returned %d\n", __func__, m);
  360. return -1;
  361. }
  362. if (!args.recipients_array && jose->recipient[0].unprot[LJJHI_ALG].buf)
  363. /* if no explicit recipients[], we got one */
  364. jose->recipients++;
  365. return 0;
  366. }
  367. int
  368. lws_jws_parse_jose(struct lws_jose *jose,
  369. const char *buf, int len, char *temp, int *temp_len)
  370. {
  371. return lws_jose_parse(jose, (const uint8_t *)buf, len,
  372. temp, temp_len, 0);
  373. }
  374. int
  375. lws_jwe_parse_jose(struct lws_jose *jose,
  376. const char *buf, int len, char *temp, int *temp_len)
  377. {
  378. return lws_jose_parse(jose,
  379. (const uint8_t *)buf, len, temp, temp_len, 1);
  380. }
  381. int
  382. lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
  383. char *out, size_t out_len)
  384. {
  385. struct lws_jwk *jwk;
  386. char *end = out + out_len - 1;
  387. int n, m, f, sub = 0, vl;
  388. /* JOSE requires an alg */
  389. if (!jose->alg || !jose->alg->alg)
  390. goto bail;
  391. *out++ = '{';
  392. for (n = 0; n < LWS_COUNT_JOSE_HDR_ELEMENTS; n++) {
  393. switch (n) {
  394. /* strings */
  395. case LJJHI_ALG: /* REQUIRED */
  396. case LJJHI_JKU: /* Optional: string */
  397. case LJJHI_KID: /* Optional: string */
  398. case LJJHI_TYP: /* Optional: string: media type */
  399. case LJJHI_CTY: /* Optional: string: content media type */
  400. case LJJHI_X5U: /* Optional: string: pubkey cert / chain URL */
  401. case LJJHI_ENC: /* JWE only: Optional: string */
  402. case LJJHI_ZIP: /* JWE only: Optional: string ("DEF"=deflate) */
  403. if (jose->e[n].buf) {
  404. out += lws_snprintf(out, end - out,
  405. "%s\"%s\":\"%s\"", sub ? ",\n" : "",
  406. jws_jose[n], jose->e[n].buf);
  407. sub = 1;
  408. }
  409. break;
  410. case LJJHI_X5T: /* Optional: base64url: SHA-1 of actual cert */
  411. case LJJHI_X5T_S256: /* Optional: base64url: SHA-256 of cert */
  412. case LJJHI_APU: /* Additional arg for JWE ECDH: b64url */
  413. case LJJHI_APV: /* Additional arg for JWE ECDH: b64url */
  414. case LJJHI_IV: /* Additional arg for JWE AES: b64url */
  415. case LJJHI_TAG: /* Additional arg for JWE AES: b64url */
  416. case LJJHI_P2S: /* Additional arg for JWE PBES2: b64url: salt */
  417. if (jose->e[n].buf) {
  418. out += lws_snprintf(out, end - out,
  419. "%s\"%s\":\"", sub ? ",\n" : "",
  420. jws_jose[n]);
  421. sub = 1;
  422. m = lws_b64_encode_string_url((const char *)
  423. jose->e[n].buf, jose->e[n].len,
  424. out, lws_ptr_diff(end, out));
  425. if (m < 0)
  426. return -1;
  427. out += m;
  428. out += lws_snprintf(out, end - out, "\"");
  429. }
  430. break;
  431. case LJJHI_P2C: /* Additional arg for JWE PBES2: int: count */
  432. break; /* don't support atm */
  433. case LJJHI_X5C: /* Optional: base64 (NOT -url): actual cert */
  434. if (jose->e[n].buf) {
  435. out += lws_snprintf(out, end - out,
  436. "%s\"%s\":\"", sub ? ",\n" : "",
  437. jws_jose[n]);
  438. sub = 1;
  439. m = lws_b64_encode_string((const char *)
  440. jose->e[n].buf, jose->e[n].len,
  441. out, lws_ptr_diff(end, out));
  442. if (m < 0)
  443. return -1;
  444. out += m;
  445. out += lws_snprintf(out, end - out, "\"");
  446. }
  447. break;
  448. case LJJHI_EPK: /* Additional arg for JWE ECDH: eph pubkey */
  449. case LJJHI_JWK: /* Optional: jwk JSON object: public key: */
  450. jwk = n == LJJHI_EPK ? &jose->recipient[0].jwk_ephemeral : aux_jwk;
  451. if (!jwk || !jwk->kty)
  452. break;
  453. out += lws_snprintf(out, end - out, "%s\"%s\":",
  454. sub ? ",\n" : "", jws_jose[n]);
  455. sub = 1;
  456. vl = lws_ptr_diff(end, out);
  457. m = lws_jwk_export(jwk, 0, out, &vl);
  458. if (m < 0) {
  459. lwsl_notice("%s: failed to export key\n",
  460. __func__);
  461. return -1;
  462. }
  463. out += m;
  464. break;
  465. case LJJHI_CRIT:/* Optional for send, REQUIRED: array of strings:
  466. * mustn't contain standardized strings or null set */
  467. if (!jose->e[n].buf)
  468. break;
  469. out += lws_snprintf(out, end - out,
  470. "%s\"%s\":[", sub ? ",\n" : "", jws_jose[n]);
  471. sub = 1;
  472. m = 0;
  473. f = 1;
  474. while ((unsigned int)m < jose->e[n].len && (end - out) > 1) {
  475. if (jose->e[n].buf[m] == ' ') {
  476. if (!f)
  477. *out++ = '\"';
  478. m++;
  479. f = 1;
  480. continue;
  481. }
  482. if (f) {
  483. if (m)
  484. *out++ = ',';
  485. *out++ = '\"';
  486. f = 0;
  487. }
  488. *out++ = jose->e[n].buf[m];
  489. m++;
  490. }
  491. break;
  492. }
  493. }
  494. *out++ = '}';
  495. if (out > end - 2)
  496. return -1;
  497. return lws_ptr_diff(out_len, (end - out)) - 1;
  498. bail:
  499. return -1;
  500. }