mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
jwt: sign and create jws helper
This commit is contained in:
parent
27bb7ed5a0
commit
865f2e4a6c
3 changed files with 181 additions and 7 deletions
|
@ -406,8 +406,8 @@ lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
|
|||
* 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 alg_list: the expected alg name, like "ES512"
|
||||
* \param com: the compact JWT
|
||||
* \param len: the length of com
|
||||
* \param temp: a temp scratchpad
|
||||
|
@ -426,7 +426,32 @@ lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
|
|||
* 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,
|
||||
lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
|
||||
const char *alg_list, const char *com, size_t len,
|
||||
char *temp, int tl, char *out, size_t *out_len);
|
||||
|
||||
/**
|
||||
* lws_jwt_sign_compact() - generate a compact JWT using a key and alg
|
||||
*
|
||||
* \param ctx: the lws_context
|
||||
* \param jwk: the signing key
|
||||
* \param alg: the signing alg name, like "ES512"
|
||||
* \param out: the output buffer to hold the signed JWT in compact form
|
||||
* \param out_len: on entry, the length of out; on exit, the used amount of out
|
||||
* \param temp: a temp scratchpad
|
||||
* \param tl: available length of temp scratchpad
|
||||
* \param format: a printf style format specification
|
||||
* \param ...: zero or more args for the format specification
|
||||
*
|
||||
* Creates a JWT in a single step, from the format string and args through to
|
||||
* outputting a well-formed compact JWT representation in out.
|
||||
*
|
||||
* Returns 0 if all is well and *out_len is the amount of data in out, else
|
||||
* nonzero if failed. Temp must be large enough to hold various intermediate
|
||||
* representations.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
|
||||
const char *alg, char *out, size_t *out_len, char *temp,
|
||||
int tl, const char *format, ...) LWS_FORMAT(8);
|
||||
///@}
|
||||
|
|
|
@ -951,14 +951,15 @@ lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
|
|||
}
|
||||
|
||||
int
|
||||
lws_jwt_signed_validate(struct lws_context *ctx, const char *alg_list,
|
||||
struct lws_jwk *jwk, const char *com, size_t len,
|
||||
lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
|
||||
const char *alg_list, 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;
|
||||
int otl = tl;
|
||||
|
||||
memset(&jws, 0, sizeof(jws));
|
||||
lws_jose_init(&jose);
|
||||
|
@ -974,13 +975,15 @@ lws_jwt_signed_validate(struct lws_context *ctx, const char *alg_list,
|
|||
goto bail;
|
||||
}
|
||||
|
||||
temp += otl - tl;
|
||||
otl = tl;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
jws.map.len[LJWS_JOSE], temp, &tl) < 0) {
|
||||
lwsl_err("%s: JOSE parse failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
@ -1034,3 +1037,112 @@ bail:
|
|||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
|
||||
const char *alg, char *out, size_t *out_len, char *temp,
|
||||
int tl, const char *format, ...)
|
||||
{
|
||||
int n, r = 1, otl = tl;
|
||||
struct lws_jose jose;
|
||||
struct lws_jws jws;
|
||||
va_list ap;
|
||||
char *q;
|
||||
|
||||
lws_jws_init(&jws, jwk, ctx);
|
||||
lws_jose_init(&jose);
|
||||
|
||||
if (lws_gencrypto_jws_alg_to_definition(alg, &jose.alg)) {
|
||||
lwsl_err("%s: unknown alg %s\n", __func__, alg);
|
||||
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* create JOSE header, also needed for output */
|
||||
|
||||
if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, temp, &tl,
|
||||
strlen(alg) + 10, 0)) {
|
||||
lwsl_err("%s: temp space too small\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
jws.map.len[LJWS_JOSE] = lws_snprintf((char *)jws.map.buf[LJWS_JOSE],
|
||||
tl, "{\"alg\":\"%s\"}", alg);
|
||||
|
||||
temp += otl - tl;
|
||||
otl = tl;
|
||||
|
||||
va_start(ap, format);
|
||||
n = vsnprintf(NULL, 0, format, ap);
|
||||
va_end(ap);
|
||||
if (n + 2 >= tl)
|
||||
goto bail;
|
||||
|
||||
q = lws_malloc(n + 2, __func__);
|
||||
if (!q)
|
||||
goto bail;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(q, n + 2, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* add the plaintext from stdin to the map and a b64 version */
|
||||
|
||||
jws.map.buf[LJWS_PYLD] = q;
|
||||
jws.map.len[LJWS_PYLD] = n;
|
||||
|
||||
if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, temp, &tl,
|
||||
jws.map.buf[LJWS_PYLD],
|
||||
jws.map.len[LJWS_PYLD]))
|
||||
goto bail1;
|
||||
|
||||
temp += otl - tl;
|
||||
otl = tl;
|
||||
|
||||
/* add the b64 JOSE header to the b64 map */
|
||||
|
||||
if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, temp, &tl,
|
||||
jws.map.buf[LJWS_JOSE],
|
||||
jws.map.len[LJWS_JOSE]))
|
||||
goto bail1;
|
||||
|
||||
temp += otl - tl;
|
||||
otl = tl;
|
||||
|
||||
/* prepare the space for the b64 signature in the map */
|
||||
|
||||
if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, temp, &tl,
|
||||
lws_base64_size(LWS_JWE_LIMIT_KEY_ELEMENT_BYTES),
|
||||
0))
|
||||
goto bail1;
|
||||
|
||||
/* sign the plaintext */
|
||||
|
||||
n = lws_jws_sign_from_b64(&jose, &jws,
|
||||
(char *)jws.map_b64.buf[LJWS_SIG],
|
||||
jws.map_b64.len[LJWS_SIG]);
|
||||
if (n < 0)
|
||||
goto bail1;
|
||||
|
||||
/* set the actual b64 signature size */
|
||||
jws.map_b64.len[LJWS_SIG] = n;
|
||||
|
||||
/* create the compact JWS representation */
|
||||
if (lws_jws_write_compact(&jws, out, *out_len))
|
||||
goto bail1;
|
||||
|
||||
*out_len = strlen(out);
|
||||
|
||||
r = 0;
|
||||
|
||||
bail1:
|
||||
lws_free(q);
|
||||
|
||||
bail:
|
||||
jws.map.buf[LJWS_PYLD] = NULL;
|
||||
jws.map.len[LJWS_PYLD] = 0;
|
||||
lws_jws_destroy(&jws);
|
||||
lws_jose_destroy(&jose);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -685,6 +685,43 @@ test_jws_ES512(struct lws_context *context)
|
|||
goto bail1;
|
||||
}
|
||||
|
||||
/* jwt test */
|
||||
|
||||
{
|
||||
unsigned long long ull = lws_now_secs();
|
||||
char buf[8192];
|
||||
size_t cml = 2048, cml2 = 2048;
|
||||
|
||||
if (lws_jwt_sign_compact(context, &jwk, "ES512",
|
||||
(char *)buf, &cml2,
|
||||
(char *)buf + 2048, 4096,
|
||||
"{\"iss\":\"warmcat.com\",\"aud\":"
|
||||
"\"https://libwebsockets.org/sai\","
|
||||
"\"iat\":%llu,"
|
||||
"\"nbf\":%llu,"
|
||||
"\"exp\":%llu,"
|
||||
"\"sub\":\"manage\"}", ull,
|
||||
ull - 60, ull + (30 * 24 * 3600)
|
||||
)) {
|
||||
lwsl_err("%s: failed to create JWT\n", __func__);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
lwsl_notice("%s: jwt test '%s'\n", __func__, buf);
|
||||
|
||||
if (lws_jwt_signed_validate(context, &jwk, "ES512",
|
||||
(const char *)buf, cml2,
|
||||
(char *)buf + 2048, 2048,
|
||||
(char *)buf + 4096, &cml)) {
|
||||
lwsl_err("%s: failed to parse JWT\n", __func__);
|
||||
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
lwsl_notice("%s: jwt valid, payload '%s'\n",
|
||||
__func__, buf + 4096);
|
||||
}
|
||||
|
||||
/* end */
|
||||
ret = 0;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue