| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- #include "private-lib-jose.h"
- #if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
- #include <fcntl.h>
- #endif
- static const char * const kty_names[] = {
- "unknown", /* LWS_GENCRYPTO_KTY_UNKNOWN */
- "oct", /* LWS_GENCRYPTO_KTY_OCT */
- "RSA", /* LWS_GENCRYPTO_KTY_RSA */
- "EC" /* LWS_GENCRYPTO_KTY_EC */
- };
- /*
- * These are the entire legal token set for names in jwk.
- *
- * The first version is used to parse a detached single jwk that don't have any
- * parent JSON context. The second version is used to parse full jwk objects
- * that has a "keys": [ ] array containing the keys.
- */
- static const char * const jwk_tok[] = {
- "keys[]", /* dummy */
- "e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
- "kty", /* generic */
- "k", /* symmetric key data */
- "crv", "x", "y", /* EC (also "D") */
- "kid", /* generic */
- "use" /* mutually exclusive with "key_ops" */,
- "key_ops" /* mutually exclusive with "use" */,
- "x5c", /* generic */
- "alg" /* generic */
- }, * const jwk_outer_tok[] = {
- "keys[]",
- "keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
- "keys[].dq", "keys[].qi",
- "keys[].kty", "keys[].k", /* generic */
- "keys[].crv", "keys[].x", "keys[].y", /* EC (also "D") */
- "keys[].kid", "keys[].use" /* mutually exclusive with "key_ops" */,
- "keys[].key_ops", /* mutually exclusive with "use" */
- "keys[].x5c", "keys[].alg"
- };
- /* information about each token declared above */
- #define F_M (1 << 9) /* Mandatory for key type */
- #define F_B64 (1 << 10) /* Base64 coded octets */
- #define F_B64U (1 << 11) /* Base64 Url coded octets */
- #define F_META (1 << 12) /* JWK key metainformation */
- #define F_RSA (1 << 13) /* RSA key */
- #define F_EC (1 << 14) /* Elliptic curve key */
- #define F_OCT (1 << 15) /* octet key */
- static unsigned short tok_map[] = {
- F_RSA | F_EC | F_OCT | F_META | 0xff,
- F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
- F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
- F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D,
- F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P,
- F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q,
- F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP,
- F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ,
- F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI,
- F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY,
- F_OCT | F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
- F_EC | F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
- F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
- F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
- F_RSA | F_EC | F_OCT | F_META | JWK_META_KID,
- F_RSA | F_EC | F_OCT | F_META | JWK_META_USE,
- F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS,
- F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C,
- F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG,
- };
- static const char *meta_names[] = {
- "kty", "kid", "use", "key_ops", "x5c", "alg"
- };
- struct lexico {
- const char *name;
- int idx;
- char meta;
- } lexico_ec[] = {
- { "alg", JWK_META_ALG, 1 },
- { "crv", LWS_GENCRYPTO_EC_KEYEL_CRV, 0 },
- { "d", LWS_GENCRYPTO_EC_KEYEL_D, 2 | 0 },
- { "key_ops", JWK_META_KEY_OPS, 1 },
- { "kid", JWK_META_KID, 1 },
- { "kty", JWK_META_KTY, 1 },
- { "use", JWK_META_USE, 1 },
- { "x", LWS_GENCRYPTO_EC_KEYEL_X, 0 },
- { "x5c", JWK_META_X5C, 1 },
- { "y", LWS_GENCRYPTO_EC_KEYEL_Y, 0 }
- }, lexico_oct[] = {
- { "alg", JWK_META_ALG, 1 },
- { "k", LWS_GENCRYPTO_OCT_KEYEL_K, 0 },
- { "key_ops", JWK_META_KEY_OPS, 1 },
- { "kid", JWK_META_KID, 1 },
- { "kty", JWK_META_KTY, 1 },
- { "use", JWK_META_USE, 1 },
- { "x5c", JWK_META_X5C, 1 }
- }, lexico_rsa[] = {
- { "alg", JWK_META_ALG, 1 },
- { "d", LWS_GENCRYPTO_RSA_KEYEL_D, 2 | 0 },
- { "dp", LWS_GENCRYPTO_RSA_KEYEL_DP, 2 | 0 },
- { "dq", LWS_GENCRYPTO_RSA_KEYEL_DQ, 2 | 0 },
- { "e", LWS_GENCRYPTO_RSA_KEYEL_E, 0 },
- { "key_ops", JWK_META_KEY_OPS, 1 },
- { "kid", JWK_META_KID, 1 },
- { "kty", JWK_META_KTY, 1 },
- { "n", LWS_GENCRYPTO_RSA_KEYEL_N, 0 },
- { "p", LWS_GENCRYPTO_RSA_KEYEL_P, 2 | 0 },
- { "q", LWS_GENCRYPTO_RSA_KEYEL_Q, 2 | 0 },
- { "qi", LWS_GENCRYPTO_RSA_KEYEL_QI, 2 | 0 },
- { "use", JWK_META_USE, 1 },
- { "x5c", JWK_META_X5C, 1 }
- };
- static const char meta_b64[] = { 0, 0, 0, 0, 1, 0 };
- static const char *oct_names[] = {
- "k"
- };
- static const char oct_b64[] = { 1 };
- static const char *rsa_names[] = {
- "e", "n", "d", "p", "q", "dp", "dq", "qi"
- };
- static const char rsa_b64[] = { 1, 1, 1, 1, 1, 1, 1, 1 };
- static const char *ec_names[] = {
- "crv", "x", "d", "y",
- };
- static const char ec_b64[] = { 0, 1, 1, 1 };
- int
- lws_jwk_dump(struct lws_jwk *jwk)
- {
- const char **enames, *b64;
- int elems;
- int n;
- (void)enames;
- (void)meta_names;
- switch (jwk->kty) {
- default:
- case LWS_GENCRYPTO_KTY_UNKNOWN:
- lwsl_err("%s: jwk %p: unknown type\n", __func__, jwk);
- return 1;
- case LWS_GENCRYPTO_KTY_OCT:
- elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
- enames = oct_names;
- b64 = oct_b64;
- break;
- case LWS_GENCRYPTO_KTY_RSA:
- elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
- enames = rsa_names;
- b64 = rsa_b64;
- break;
- case LWS_GENCRYPTO_KTY_EC:
- elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
- enames = ec_names;
- b64 = ec_b64;
- break;
- }
- lwsl_info("%s: jwk %p\n", __func__, jwk);
- for (n = 0; n < LWS_COUNT_JWK_ELEMENTS; n++) {
- if (jwk->meta[n].buf && meta_b64[n]) {
- lwsl_info(" meta: %s\n", meta_names[n]);
- lwsl_hexdump_info(jwk->meta[n].buf, jwk->meta[n].len);
- }
- if (jwk->meta[n].buf && !meta_b64[n])
- lwsl_info(" meta: %s: '%s'\n", meta_names[n],
- jwk->meta[n].buf);
- }
- for (n = 0; n < elems; n++) {
- if (jwk->e[n].buf && b64[n]) {
- lwsl_info(" e: %s\n", enames[n]);
- lwsl_hexdump_info(jwk->e[n].buf, jwk->e[n].len);
- }
- if (jwk->e[n].buf && !b64[n])
- lwsl_info(" e: %s: '%s'\n", enames[n], jwk->e[n].buf);
- }
- return 0;
- }
- static int
- _lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, int len)
- {
- e->buf = lws_malloc(len + 1, "jwk");
- if (!e->buf)
- return -1;
- memcpy(e->buf, in, len);
- e->buf[len] = '\0';
- e->len = len;
- return 0;
- }
- static int
- _lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
- {
- int dec_size = lws_base64_size(len), n;
- e->buf = lws_malloc(dec_size, "jwk");
- if (!e->buf)
- return -1;
- /* same decoder accepts both url or original styles */
- n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1);
- if (n < 0)
- return -1;
- e->len = n;
- return 0;
- }
- static int
- _lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
- {
- int dec_size = lws_base64_size(len), n;
- e->buf = lws_malloc(dec_size, "jwk");
- if (!e->buf)
- return -1;
- /* same decoder accepts both url or original styles */
- n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1);
- if (n < 0)
- return -1;
- e->len = n;
- return 0;
- }
- void
- lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
- {
- int n;
- for (n = 0; n < m; n++)
- if (el[n].buf) {
- /* wipe all key material when it goes out of scope */
- lws_explicit_bzero(el[n].buf, el[n].len);
- lws_free_set_NULL(el[n].buf);
- el[n].len = 0;
- }
- }
- void
- lws_jwk_destroy(struct lws_jwk *jwk)
- {
- lws_jwk_destroy_elements(jwk->e, LWS_ARRAY_SIZE(jwk->e));
- lws_jwk_destroy_elements(jwk->meta, LWS_ARRAY_SIZE(jwk->meta));
- }
- static signed char
- cb_jwk(struct lejp_ctx *ctx, char reason)
- {
- struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
- struct lws_jwk *jwk = jps->jwk;
- unsigned int idx, poss, n;
- char dotstar[64];
- if (reason == LEJPCB_VAL_STR_START)
- jps->pos = 0;
- if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
- /*
- * new keys[] member is starting
- *
- * Until we see some JSON names, it could be anything...
- * there is no requirement for kty to be given first and eg,
- * ACME specifies the keys must be ordered in lexographic
- * order - where kty is not first.
- */
- jps->possible = F_RSA | F_EC | F_OCT;
- if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
- /* we completed parsing a key */
- if (jps->per_key_cb && jps->possible) {
- if (jps->per_key_cb(jps->jwk, jps->user)) {
- lwsl_notice("%s: user cb halts import\n",
- __func__);
- return -2;
- }
- /* clear it down */
- lws_jwk_destroy(jps->jwk);
- jps->possible = 0;
- }
- }
- if (reason == LEJPCB_COMPLETE) {
- /*
- * Now we saw the whole jwk and know the key type, let'jwk insist
- * that as a whole, it must be consistent and complete.
- *
- * The tracking of ->possible bits from even before we know the
- * kty already makes certain we cannot have key element members
- * defined that are inconsistent with the key type.
- */
- for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
- /*
- * All mandataory elements for the key type
- * must be present
- */
- if ((tok_map[n] & jps->possible) && (
- ((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
- !jwk->meta[tok_map[n] & 0xff].buf) ||
- ((tok_map[n] & (F_M | F_META)) == F_M &&
- !jwk->e[tok_map[n] & 0xff].buf))) {
- lwsl_notice("%s: missing %s\n", __func__,
- jwk_tok[n]);
- return -3;
- }
- /*
- * When the key may be public or public + private, ensure the
- * intra-key members related to that are consistent.
- *
- * Only RSA keys need extra care, since EC keys are already
- * confirmed by making CRV, X and Y mandatory and only D
- * (the singular private part) optional. For RSA, N and E are
- * also already known to be present using mandatory checking.
- */
- /*
- * If a private key, it must have all D, P and Q. Public key
- * must have none of them.
- */
- if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
- !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
- (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
- (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
- (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
- ) {
- lwsl_notice("%s: RSA requires D, P and Q for private\n",
- __func__);
- return -3;
- }
- /*
- * If the precomputed private key terms appear, they must all
- * appear together.
- */
- if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
- !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
- (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
- (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
- (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
- ) {
- lwsl_notice("%s: RSA DP, DQ, QI must all appear "
- "or none\n", __func__);
- return -3;
- }
- /*
- * The precomputed private key terms must not appear without
- * the private key itself also appearing.
- */
- if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
- !jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
- lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
- "private key\n", __func__);
- return -3;
- }
- if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
- jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
- jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
- jwk->private_key = 1;
- }
- if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
- return 0;
- if (ctx->path_match == 0 + 1)
- return 0;
- idx = tok_map[ctx->path_match - 1];
- if ((idx & 0xff) == 0xff)
- return 0;
- switch (idx) {
- /* note: kty is not necessarily first... we have to keep track of
- * what could match given which element names have already been
- * seen. Once kty comes, we confirm it'jwk still possible (ie, it'jwk
- * not trying to tell us that it'jwk RSA now when we saw a "crv"
- * earlier) and then reduce the possibilities to just the one that
- * kty told. */
- case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
- if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
- if (!(jps->possible & F_OCT))
- goto elements_mismatch;
- jwk->kty = LWS_GENCRYPTO_KTY_OCT;
- jps->possible = F_OCT;
- goto cont;
- }
- if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
- if (!(jps->possible & F_RSA))
- goto elements_mismatch;
- jwk->kty = LWS_GENCRYPTO_KTY_RSA;
- jps->possible = F_RSA;
- goto cont;
- }
- if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
- if (!(jps->possible & F_EC))
- goto elements_mismatch;
- jwk->kty = LWS_GENCRYPTO_KTY_EC;
- jps->possible = F_EC;
- goto cont;
- }
- lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
- lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
- return -1;
- default:
- cont:
- if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
- goto bail;
- memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
- jps->pos += ctx->npos;
- if (reason == LEJPCB_VAL_STR_CHUNK)
- return 0;
- /* chunking has been collated */
- poss = idx & (F_RSA | F_EC | F_OCT);
- jps->possible &= poss;
- if (!jps->possible)
- goto elements_mismatch;
- if (idx & F_META) {
- if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
- jps->b64, jps->pos) < 0)
- goto bail;
- break;
- }
- if (idx & F_B64U) {
- /* key data... do the base64 decode as needed */
- if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
- jps->b64, jps->pos) < 0)
- goto bail;
- if (jwk->e[idx & 0x7f].len >
- LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
- lwsl_notice("%s: oversize keydata\n", __func__);
- goto bail;
- }
- return 0;
- }
- if (idx & F_B64) {
- /* cert data... do non-urlcoded base64 decode */
- if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
- jps->b64, jps->pos) < 0)
- goto bail;
- return 0;
- }
- if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
- jps->b64, jps->pos) < 0)
- goto bail;
- break;
- }
- return 0;
- elements_mismatch:
- lwsl_err("%s: jwk elements mismatch\n", __func__);
- bail:
- lwsl_err("%s: element failed\n", __func__);
- return -1;
- }
- void
- lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps,
- struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
- void *user)
- {
- if (jwk)
- memset(jwk, 0, sizeof(*jwk));
- jps->jwk = jwk;
- jps->possible = F_RSA | F_EC | F_OCT;
- jps->per_key_cb = cb;
- jps->user = user;
- jps->pos = 0;
- lejp_construct(jctx, cb_jwk, jps, cb ? jwk_outer_tok: jwk_tok,
- LWS_ARRAY_SIZE(jwk_tok));
- }
- int
- lws_jwk_dup_oct(struct lws_jwk *jwk, const void *key, int len)
- {
- jwk->e[LWS_GENCRYPTO_KTY_OCT].buf = lws_malloc(len, __func__);
- if (!jwk->e[LWS_GENCRYPTO_KTY_OCT].buf)
- return -1;
- jwk->kty = LWS_GENCRYPTO_KTY_OCT;
- jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = len;
- memcpy(jwk->e[LWS_GENCRYPTO_KTY_OCT].buf, key, len);
- return 0;
- }
- int
- lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
- enum lws_gencrypto_kty kty, int bits, const char *curve)
- {
- size_t sn;
- int n;
- memset(jwk, 0, sizeof(*jwk));
- jwk->kty = kty;
- jwk->private_key = 1;
- switch (kty) {
- case LWS_GENCRYPTO_KTY_RSA:
- {
- struct lws_genrsa_ctx ctx;
- lwsl_notice("%s: generating %d bit RSA key\n", __func__, bits);
- n = lws_genrsa_new_keypair(context, &ctx, LGRSAM_PKCS1_1_5,
- jwk->e, bits);
- lws_genrsa_destroy(&ctx);
- if (n) {
- lwsl_err("%s: problem generating RSA key\n", __func__);
- return 1;
- }
- }
- break;
- case LWS_GENCRYPTO_KTY_OCT:
- sn = lws_gencrypto_bits_to_bytes(bits);
- jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(sn, "oct");
- jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = (uint32_t)sn;
- if (lws_get_random(context,
- jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, sn) != sn) {
- lwsl_err("%s: problem getting random\n", __func__);
- return 1;
- }
- break;
- case LWS_GENCRYPTO_KTY_EC:
- {
- struct lws_genec_ctx ctx;
- if (!curve) {
- lwsl_err("%s: must have a named curve\n", __func__);
- return 1;
- }
- if (lws_genecdsa_create(&ctx, context, NULL))
- return 1;
- lwsl_notice("%s: generating ECDSA key on curve %s\n", __func__,
- curve);
- n = lws_genecdsa_new_keypair(&ctx, curve, jwk->e);
- lws_genec_destroy(&ctx);
- if (n) {
- lwsl_err("%s: problem generating ECDSA key\n", __func__);
- return 1;
- }
- }
- break;
- case LWS_GENCRYPTO_KTY_UNKNOWN:
- default:
- lwsl_err("%s: unknown kty\n", __func__);
- return 1;
- }
- return 0;
- }
- int
- lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
- const char *in, size_t len)
- {
- struct lejp_ctx jctx;
- struct lws_jwk_parse_state jps;
- int m;
- lws_jwk_init_jps(&jctx, &jps, jwk, cb, user);
- m = lejp_parse(&jctx, (uint8_t *)in, (int)len);
- lejp_destruct(&jctx);
- if (m < 0) {
- lwsl_notice("%s: parse got %d\n", __func__, m);
- lws_jwk_destroy(jwk);
- return -1;
- }
- switch (jwk->kty) {
- case LWS_GENCRYPTO_KTY_UNKNOWN:
- lwsl_notice("%s: missing or unknown kyt\n", __func__);
- lws_jwk_destroy(jwk);
- return -1;
- default:
- break;
- }
- return 0;
- }
- int
- lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
- {
- char *start = p, *end = &p[*len - 1];
- int n, m, limit, first = 1, asym = 0;
- struct lexico *l;
- /* RFC7638 lexicographic order requires
- * RSA: e -> kty -> n
- * oct: k -> kty
- *
- * ie, meta and key data elements appear interleaved in name alpha order
- */
- p += lws_snprintf(p, end - p, "{");
- switch (jwk->kty) {
- case LWS_GENCRYPTO_KTY_OCT:
- l = lexico_oct;
- limit = LWS_ARRAY_SIZE(lexico_oct);
- break;
- case LWS_GENCRYPTO_KTY_RSA:
- l = lexico_rsa;
- limit = LWS_ARRAY_SIZE(lexico_rsa);
- asym = 1;
- break;
- case LWS_GENCRYPTO_KTY_EC:
- l = lexico_ec;
- limit = LWS_ARRAY_SIZE(lexico_ec);
- asym = 1;
- break;
- default:
- return -1;
- }
- for (n = 0; n < limit; n++) {
- const char *q, *q_end;
- char tok[12];
- int pos = 0, f = 1;
- if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
- l->idx == (int)JWK_META_KTY)) {
- switch (l->idx) {
- case JWK_META_KTY:
- if (!first)
- *p++ = ',';
- first = 0;
- p += lws_snprintf(p, end - p, "\"%s\":\"%s\"",
- l->name, kty_names[jwk->kty]);
- break;
- case JWK_META_KEY_OPS:
- if (!first)
- *p++ = ',';
- first = 0;
- q = (const char *)jwk->meta[l->idx].buf;
- q_end = q + jwk->meta[l->idx].len;
- p += lws_snprintf(p, end - p,
- "\"%s\":[", l->name);
- /*
- * For the public version, usages that
- * require the private part must be
- * snipped
- */
- while (q < q_end) {
- if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
- tok[pos++] = *q++;
- if (q != q_end)
- continue;
- }
- tok[pos] = '\0';
- pos = 0;
- if ((flags & LWSJWKF_EXPORT_PRIVATE) ||
- !asym || (strcmp(tok, "sign") &&
- strcmp(tok, "encrypt"))) {
- if (!f)
- *p++ = ',';
- f = 0;
- p += lws_snprintf(p, end - p,
- "\"%s\"", tok);
- }
- q++;
- }
- *p++ = ']';
- break;
- default:
- /* both sig and enc require asym private key */
- if (!(flags & LWSJWKF_EXPORT_PRIVATE) &&
- asym && l->idx == (int)JWK_META_USE)
- break;
- if (!first)
- *p++ = ',';
- first = 0;
- p += lws_snprintf(p, end - p, "\"%s\":\"",
- l->name);
- lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
- jwk->meta[l->idx].len, end - p);
- p += strlen(p);
- p += lws_snprintf(p, end - p, "\"");
- break;
- }
- }
- if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
- ((flags & LWSJWKF_EXPORT_PRIVATE) || !(l->meta & 2))) {
- if (!first)
- *p++ = ',';
- first = 0;
- p += lws_snprintf(p, end - p, "\"%s\":\"", l->name);
- if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
- l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
- lws_strnncpy(p,
- (const char *)jwk->e[l->idx].buf,
- jwk->e[l->idx].len, end - p);
- m = (int)strlen(p);
- } else
- m = lws_jws_base64_enc(
- (const char *)jwk->e[l->idx].buf,
- jwk->e[l->idx].len, p, end - p - 4);
- if (m < 0) {
- lwsl_notice("%s: enc failed\n", __func__);
- return -1;
- }
- p += m;
- p += lws_snprintf(p, end - p, "\"");
- }
- l++;
- }
- p += lws_snprintf(p, end - p,
- (flags & LWSJWKF_EXPORT_NOCRLF) ? "}" : "}\n");
- *len -= lws_ptr_diff(p, start);
- return lws_ptr_diff(p, start);
- }
- int
- lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32)
- {
- struct lws_genhash_ctx hash_ctx;
- int tmpsize = 2536, n;
- char *tmp;
- tmp = lws_malloc(tmpsize, "rfc7638 tmp");
- n = lws_jwk_export(jwk, LWSJWKF_EXPORT_NOCRLF, tmp, &tmpsize);
- if (n < 0)
- goto bail;
- if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
- goto bail;
- if (lws_genhash_update(&hash_ctx, tmp, n)) {
- lws_genhash_destroy(&hash_ctx, NULL);
- goto bail;
- }
- lws_free(tmp);
- if (lws_genhash_destroy(&hash_ctx, digest32))
- return -1;
- return 0;
- bail:
- lws_free(tmp);
- return -1;
- }
- int
- lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx,
- const char *in, int len)
- {
- jwk->meta[idx].buf = lws_malloc(len, __func__);
- if (!jwk->meta[idx].buf)
- return 1;
- jwk->meta[idx].len = len;
- memcpy(jwk->meta[idx].buf, in, len);
- return 0;
- }
- int
- lws_jwk_load(struct lws_jwk *jwk, const char *filename,
- lws_jwk_key_import_callback cb, void *user)
- {
- int buflen = 4096;
- char *buf = lws_malloc(buflen, "jwk-load");
- int n;
- if (!buf)
- return -1;
- n = lws_plat_read_file(filename, buf, buflen);
- if (n < 0)
- goto bail;
- n = lws_jwk_import(jwk, cb, user, buf, n);
- lws_free(buf);
- return n;
- bail:
- lws_free(buf);
- return -1;
- }
- int
- lws_jwk_save(struct lws_jwk *jwk, const char *filename)
- {
- int buflen = 4096;
- char *buf = lws_malloc(buflen, "jwk-save");
- int n, m;
- if (!buf)
- return -1;
- n = lws_jwk_export(jwk, LWSJWKF_EXPORT_PRIVATE, buf, &buflen);
- if (n < 0)
- goto bail;
- m = lws_plat_write_file(filename, buf, n);
- lws_free(buf);
- if (m)
- return -1;
- return 0;
- bail:
- lws_free(buf);
- return -1;
- }
|