mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-11-22 00:57:52 +00:00
4db2ff872b
Support for COSE keys and signing / validation - lws_cose_key_t and import / export / generation apis for EC / RSA / SYMMETRIC - cose_sign1 ES256/384/512,RS256/384/512 sign + validate, passes RFC8152 WG tests sign1-tests - cose_sign ES256/384/512,RS256/384/512 sign + validate, passes RFC8152 WG tests sign-tests - cose_mac0 HS256/HS256_64/384/512 sign + validate, passes RFC8152 WG tests hmac-examples - cose_mac HS256/HS256_64/384/512 validate, passes RFC8152 WG tests hmac-examples - lws-crypto-cose-key commandline tool for key / key set dumping and creation - lws-crypro-cose-sign commandline tool for signing / validation - lws-api-test-cose - large number of test vectors and tests from RFC8152
298 lines
6.9 KiB
C
298 lines
6.9 KiB
C
/*
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
*
|
|
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
|
*
|
|
* 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.
|
|
*
|
|
* Shared JWK handling that's the same whether JOSE or COSE
|
|
*/
|
|
|
|
#include "private-lib-core.h"
|
|
#include "private-lib-jose.h"
|
|
|
|
static const char *meta_names[] = {
|
|
"kty", "kid", "use", "key_ops", "x5c", "alg"
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
int
|
|
_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len)
|
|
{
|
|
e->buf = lws_malloc(len + 1, "jwk");
|
|
if (!e->buf)
|
|
return -1;
|
|
|
|
memcpy(e->buf, in, len);
|
|
e->buf[len] = '\0';
|
|
e->len = (uint32_t)len;
|
|
|
|
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));
|
|
}
|
|
|
|
void
|
|
lws_jwk_init_jps(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;
|
|
jps->seen = 0;
|
|
jps->cose_state = 0;
|
|
}
|
|
|
|
int
|
|
lws_jwk_dup_oct(struct lws_jwk *jwk, const void *key, int len)
|
|
{
|
|
unsigned int ulen = (unsigned int)len;
|
|
|
|
jwk->e[LWS_GENCRYPTO_KTY_OCT].buf = lws_malloc(ulen, __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 = ulen;
|
|
|
|
memcpy(jwk->e[LWS_GENCRYPTO_KTY_OCT].buf, key, ulen);
|
|
|
|
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 = (int)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 = (unsigned int)lws_gencrypto_bits_to_bytes(bits);
|
|
jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(sn, "oct");
|
|
if (!jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf)
|
|
return 1;
|
|
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_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32)
|
|
{
|
|
struct lws_genhash_ctx hash_ctx;
|
|
size_t tmpsize = 2536;
|
|
char *tmp;
|
|
int n, m = (int)tmpsize;
|
|
|
|
tmp = lws_malloc(tmpsize, "rfc7638 tmp");
|
|
|
|
n = lws_jwk_export(jwk, LWSJWKF_EXPORT_NOCRLF, tmp, &m);
|
|
if (n < 0)
|
|
goto bail;
|
|
|
|
if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
|
|
goto bail;
|
|
|
|
if (lws_genhash_update(&hash_ctx, tmp, (unsigned int)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((unsigned int)len, __func__);
|
|
if (!jwk->meta[idx].buf)
|
|
return 1;
|
|
jwk->meta[idx].len = (uint32_t)(unsigned int)len;
|
|
memcpy(jwk->meta[idx].buf, in, (unsigned int)len);
|
|
|
|
return 0;
|
|
}
|
|
|