mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-12-25 23:00:12 +00:00
314 lines
6.6 KiB
C
314 lines
6.6 KiB
C
/*
|
|
* lws-minimal-crypto-cose-key
|
|
*
|
|
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*/
|
|
|
|
#include <libwebsockets.h>
|
|
#include <sys/select.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
|
|
static int fdin = 0, fdout = 1;
|
|
|
|
static const char *meta_names[] = {
|
|
"kty", "kid", "use", "key_ops", "base_iv", "alg"
|
|
};
|
|
|
|
static const char *oct_names[] = {
|
|
"k"
|
|
};
|
|
|
|
static const char *rsa_names[] = {
|
|
"e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
|
|
};
|
|
|
|
static const char *ec_names[] = {
|
|
"crv", "x", "d", "y",
|
|
};
|
|
|
|
static void
|
|
cose_key_dump(const struct lws_cose_key *ck)
|
|
{
|
|
const char **enames;
|
|
char hex[2048], dump[3072];
|
|
int elems;
|
|
size_t l;
|
|
int n;
|
|
|
|
(void)enames;
|
|
(void)meta_names;
|
|
|
|
switch (ck->gencrypto_kty) {
|
|
|
|
case LWS_GENCRYPTO_KTY_OCT:
|
|
elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
|
|
enames = oct_names;
|
|
break;
|
|
case LWS_GENCRYPTO_KTY_RSA:
|
|
elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
|
|
enames = rsa_names;
|
|
break;
|
|
case LWS_GENCRYPTO_KTY_EC:
|
|
elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
|
|
enames = ec_names;
|
|
break;
|
|
|
|
default:
|
|
lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
|
|
|
|
return;
|
|
}
|
|
|
|
for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
|
|
if (ck->meta[n].buf) {
|
|
if (n < 2) {
|
|
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
|
" %s: %.*s\n", meta_names[n],
|
|
(int)ck->meta[n].len,
|
|
ck->meta[n].buf);
|
|
write(fdout, dump, l);
|
|
} else {
|
|
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
|
" %s: ", meta_names[n]);
|
|
write(fdout, dump, l);
|
|
lws_hex_from_byte_array(ck->meta[n].buf,
|
|
ck->meta[n].len,
|
|
hex, sizeof(hex));
|
|
write(fdout, hex, strlen(hex));
|
|
write(fdout, "\n", 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (n = 0; n < elems; n++) {
|
|
if (ck->e[n].buf) {
|
|
if (!n && ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
|
|
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
|
" %s: %.*s\n", enames[n],
|
|
(int)ck->e[n].len,
|
|
ck->e[n].buf);
|
|
write(fdout, dump, l);
|
|
} else {
|
|
l = (size_t)lws_snprintf(dump, sizeof(dump),
|
|
" %s: ", enames[n]);
|
|
write(fdout, dump, l);
|
|
lws_hex_from_byte_array(ck->e[n].buf,
|
|
ck->e[n].len,
|
|
hex, sizeof(hex));
|
|
write(fdout, hex, strlen(hex));
|
|
write(fdout, "\n", 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
uint8_t *kid = NULL, ktmp[4096], set_temp[32 * 1024], temp[256];
|
|
int result = 1, bits = 0,
|
|
logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
|
struct lws_context_creation_info info;
|
|
size_t kid_len = 0, stp = 0;
|
|
struct lws_context *context;
|
|
lws_cose_key_t *ck = NULL;
|
|
cose_param_t cose_kty = 0;
|
|
lws_dll2_owner_t set;
|
|
const char *p, *crv;
|
|
lws_lec_pctx_t lec;
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
|
logs = atoi(p);
|
|
|
|
lws_set_log_level(logs, NULL);
|
|
|
|
lwsl_user("LWS cose-key example tool -k keyset [-s alg-name kid ]\n");
|
|
|
|
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
|
#if defined(LWS_WITH_NETWORK)
|
|
info.port = CONTEXT_PORT_NO_LISTEN;
|
|
#endif
|
|
|
|
context = lws_create_context(&info);
|
|
if (!context) {
|
|
lwsl_err("lws init failed\n");
|
|
return 1;
|
|
}
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
|
|
fdin = open(p, LWS_O_RDONLY, 0);
|
|
if (fdin < 0) {
|
|
lwsl_err("%s: unable to open stdin file\n", __func__);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
|
|
fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
|
|
if (fdout < 0) {
|
|
lwsl_err("%s: unable to open stdout file\n", __func__);
|
|
goto bail_early;
|
|
}
|
|
}
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
|
|
kid = (uint8_t *)p;
|
|
kid_len = strlen(p);
|
|
//lwsl_hexdump_notice(kid, kid_len);
|
|
}
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
|
|
kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
|
|
kid = (uint8_t *)ktmp;
|
|
}
|
|
|
|
/*
|
|
* If we have some stdin queued up, we understand we are dumping
|
|
* an existing cose_key or key_set from stdin
|
|
*/
|
|
|
|
if (!fdin) {
|
|
struct timeval timeout;
|
|
fd_set fds;
|
|
|
|
FD_ZERO(&fds);
|
|
FD_SET(0, &fds);
|
|
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 1000;
|
|
|
|
if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0)
|
|
goto no_stdin;
|
|
|
|
if (!FD_ISSET(0, &fds))
|
|
goto no_stdin;
|
|
}
|
|
|
|
do {
|
|
int n = (int)read(fdin, temp, sizeof(temp));
|
|
|
|
if (n < 0)
|
|
goto bail;
|
|
if (!n) {
|
|
int kc = 0;
|
|
|
|
if (!stp)
|
|
/* there was no stdin */
|
|
break;
|
|
|
|
lwsl_notice("%s: importing\n", __func__);
|
|
|
|
lws_dll2_owner_clear(&set);
|
|
ck = lws_cose_key_import(&set, NULL, NULL, set_temp, stp);
|
|
if (!ck) {
|
|
lwsl_err("%s: import failed\n", __func__);
|
|
goto bail;
|
|
}
|
|
|
|
lws_start_foreach_dll(struct lws_dll2 *, p,
|
|
lws_dll2_get_head(&set)) {
|
|
lws_cose_key_t *ck = lws_container_of(p,
|
|
lws_cose_key_t, list);
|
|
struct lws_gencrypto_keyelem *ke =
|
|
&ck->meta[COSEKEY_META_KID];
|
|
|
|
kc++;
|
|
|
|
if (!kid_len || (ke->len &&
|
|
ke->len == (uint32_t)kid_len &&
|
|
!memcmp(ke->buf, kid, kid_len))) {
|
|
printf("Cose key #%d\n", kc);
|
|
cose_key_dump(ck);
|
|
}
|
|
|
|
} lws_end_foreach_dll(p);
|
|
|
|
lws_cose_key_set_destroy(&set);
|
|
result = 0;
|
|
goto bail;
|
|
|
|
}
|
|
|
|
if (stp + (size_t)n > sizeof(set_temp)) {
|
|
lwsl_err("%s: stdin bigger than our buffer\n", __func__);
|
|
goto bail;
|
|
}
|
|
memcpy(set_temp + stp, temp, (size_t)n);
|
|
stp += (size_t)n;
|
|
} while (1);
|
|
|
|
no_stdin:
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
p = lws_cmdline_option(argc, argv, "--kty");
|
|
if (!p) {
|
|
lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
|
|
__func__);
|
|
goto bail;
|
|
}
|
|
|
|
if (!strcmp(p, "OKP"))
|
|
cose_kty = LWSCOSE_WKKTV_OKP;
|
|
if (!strcmp(p, "EC2"))
|
|
cose_kty = LWSCOSE_WKKTV_EC2;
|
|
if (!strcmp(p, "RSA"))
|
|
cose_kty = LWSCOSE_WKKTV_RSA;
|
|
if (!strcmp(p, "SYMMETRIC") || !strcmp(p, "SYM"))
|
|
cose_kty = LWSCOSE_WKKTV_SYMMETRIC;
|
|
|
|
if (!cose_kty) {
|
|
lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
|
|
__func__);
|
|
goto bail;
|
|
}
|
|
|
|
crv = NULL;
|
|
if (cose_kty == LWSCOSE_WKKTV_OKP ||
|
|
cose_kty == LWSCOSE_WKKTV_EC2) {
|
|
crv = lws_cmdline_option(argc, argv, "--curve");
|
|
if (!crv) {
|
|
lwsl_err("%s: use --curve P-256 etc\n", __func__);
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
p = lws_cmdline_option(argc, argv, "--bits");
|
|
if (p)
|
|
bits = atoi(p);
|
|
|
|
ck = lws_cose_key_generate(context, cose_kty, 0, bits, crv,
|
|
kid, kid_len);
|
|
if (!ck)
|
|
goto bail;
|
|
|
|
lws_lec_init(&lec, ktmp, sizeof(ktmp));
|
|
lws_cose_key_export(ck, &lec, LWSJWKF_EXPORT_PRIVATE);
|
|
write(fdout, ktmp, lec.used);
|
|
|
|
lws_cose_key_destroy(&ck);
|
|
result = 0;
|
|
|
|
bail:
|
|
lws_context_destroy(context);
|
|
|
|
if (result)
|
|
lwsl_err("%s: FAIL: %d\n", __func__, result);
|
|
else
|
|
lwsl_notice("%s: PASS\n", __func__);
|
|
|
|
bail_early:
|
|
if (fdin > 0)
|
|
close(fdin);
|
|
if (fdout != 1 && fdout >= 0)
|
|
close(fdout);
|
|
|
|
return result;
|
|
}
|