1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

jwt: validate jws helper

Introduce a signed JWT validation helper
This commit is contained in:
Andy Green 2020-07-10 16:38:14 +01:00
parent 44fd4efd88
commit 27bb7ed5a0
2 changed files with 113 additions and 1 deletions

View file

@ -398,8 +398,35 @@ lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
* Returns either -1 if problems, or the number of bytes written to \p out.
* If the section is not the first one, '.' is prepended.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
char *end);
/**
* lws_jwt_signed_validate() - check a compact JWT against a key and alg
*
* \param ctx: the lws_context
* \param alg_list: the expected alg name, like "ES512"
* \param jwk: the key for checking the signature
* \param com: the compact JWT
* \param len: the length of com
* \param temp: a temp scratchpad
* \param tl: available length of temp scratchpad
* \param out: the output buffer to hold the validated plaintext
* \param out_len: on entry, max length of out; on exit, used length of out
*
* Returns nonzero if the JWT cannot be validated or the plaintext can't fit the
* provided output buffer, or 0 if it is validated as being signed by the
* provided jwk.
*
* If validated, the plaintext in the JWT is copied into out and out_len set to
* the used length.
*
* temp can be discarded or reused after the call returned, it's used to hold
* transformations of the B64 JWS in the JWT.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_signed_validate(struct lws_context *ctx, const char *alg_list,
struct lws_jwk *jwk, const char *com, size_t len,
char *temp, int tl, char *out, size_t *out_len);
///@}

View file

@ -949,3 +949,88 @@ lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
return n >= len - 1;
}
int
lws_jwt_signed_validate(struct lws_context *ctx, const char *alg_list,
struct lws_jwk *jwk, const char *com, size_t len,
char *temp, int tl, char *out, size_t *out_len)
{
struct lws_tokenize ts;
struct lws_jose jose;
struct lws_jws jws;
size_t n, r = 1;
memset(&jws, 0, sizeof(jws));
lws_jose_init(&jose);
/*
* Decode the b64.b64[.b64] compact serialization
* blocks
*/
n = lws_jws_compact_decode(com, len, &jws.map, &jws.map_b64, temp, &tl);
if (n != 3) {
lwsl_err("%s: concat_map failed: %d\n", __func__, (int)n);
goto bail;
}
/*
* Parse the JOSE header
*/
if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
jws.map.len[LJWS_JOSE],
lws_concat_temp(temp, tl), &tl) < 0) {
lwsl_err("%s: JOSE parse failed\n", __func__);
goto bail;
}
/*
* Insist to see an alg in there that we list as acceptable
*/
lws_tokenize_init(&ts, alg_list, LWS_TOKENIZE_F_COMMA_SEP_LIST |
LWS_TOKENIZE_F_RFC7230_DELIMS);
n = strlen(jose.alg->alg);
do {
ts.e = lws_tokenize(&ts);
if (ts.e == LWS_TOKZE_TOKEN && ts.token_len == n &&
!strncmp(jose.alg->alg, ts.token, ts.token_len))
break;
} while (ts.e != LWS_TOKZE_ENDED);
if (ts.e != LWS_TOKZE_TOKEN) {
lwsl_err("%s: JOSE using alg %s (accepted: %s)\n", __func__,
jose.alg->alg, alg_list);
goto bail;
}
/* we liked the alg... now how about the crypto? */
if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, jwk, ctx) < 0) {
lwsl_notice("%s: confirm JWT sig failed\n",
__func__);
goto bail;
}
/* yeah, it's validated... see about copying it out */
if (*out_len < jws.map.len[LJWS_PYLD] + 1) {
/* we don't have enough room */
r = 2;
goto bail;
}
memcpy(out, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
*out_len = jws.map.len[LJWS_PYLD];
out[jws.map.len[LJWS_PYLD]] = '\0';
r = 0;
bail:
lws_jws_destroy(&jws);
lws_jose_destroy(&jose);
return r;
}