From 7f569b2eba49bbca6d1aa2d9a88df56576f46eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Mon, 4 Mar 2024 13:54:28 +0100 Subject: [PATCH 01/11] implement a jwt parser --- Makefile | 4 +- crypto.c | 67 +++++++++++++++++++++++ crypto.h | 16 ++++++ jwt.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++ jwt.h | 30 +++++++++++ src/main.c | 13 +++++ 6 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 crypto.c create mode 100644 crypto.h create mode 100644 jwt.c create mode 100644 jwt.h diff --git a/Makefile b/Makefile index 3dc38888..b9bdb16b 100644 --- a/Makefile +++ b/Makefile @@ -85,7 +85,9 @@ camblet-objs := third-party/wasm3/source/m3_api_libc.o \ src/sd.o \ src/trace.o \ src/http.o \ - src/spiffe.o + src/spiffe.o \ + src/jwt.o \ + src/crypto.o # Set the path to the Kernel build utils. KBUILD=/lib/modules/$(shell uname -r)/build/ diff --git a/crypto.c b/crypto.c new file mode 100644 index 00000000..55b57734 --- /dev/null +++ b/crypto.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Cisco and/or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: MIT OR GPL-2.0-only + * + * Licensed under the MIT license or the GPLv2 license + * , at your option. This file may not be copied, + * modified, or distributed except according to those terms. + */ + +#include + +static struct shash_desc *init_sdesc(struct crypto_shash *alg) +{ + struct shash_desc *sdesc; + int size; + + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); + sdesc = kmalloc(size, GFP_KERNEL); + if (!sdesc) + return ERR_PTR(-ENOMEM); + sdesc->tfm = alg; + return sdesc; +} + +u8 *hmac_sha256(const u8 *data, unsigned data_len, const char *key, unsigned key_len) +{ + const char *hash_alg_name = "hmac(sha256)"; + struct crypto_shash *shash; + int err; + + shash = crypto_alloc_shash(hash_alg_name, 0, 0); + + if (IS_ERR(shash)) + { + printk(KERN_ERR "can't alloc alg %s\n", hash_alg_name); + return PTR_ERR(shash); + } + + err = crypto_shash_setkey(shash, key, key_len); + if (err < 0) + { + printk(KERN_ERR "can't set key\n"); + crypto_free_shash(shash); + return ERR_PTR(err); + } + + struct shash_desc *desc = init_sdesc(shash); + + u8 *out = kmalloc(crypto_shash_digestsize(shash), GFP_KERNEL); + + err = crypto_shash_digest(desc, data, data_len, out); + + if (err < 0) + { + printk(KERN_ERR "can't digest\n"); + crypto_free_shash(shash); + kfree(out); + kfree(desc); + return ERR_PTR(err); + } + + crypto_free_shash(shash); + kfree(desc); + + return out; +} diff --git a/crypto.h b/crypto.h new file mode 100644 index 00000000..a7ac8e01 --- /dev/null +++ b/crypto.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Cisco and/or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: MIT OR GPL-2.0-only + * + * Licensed under the MIT license or the GPLv2 license + * , at your option. This file may not be copied, + * modified, or distributed except according to those terms. + */ + +#ifndef crypto_h +#define crypto_h + +char *hmac_sha256(const char *data, unsigned data_len, const char *key); + +#endif diff --git a/jwt.c b/jwt.c new file mode 100644 index 00000000..4f87608f --- /dev/null +++ b/jwt.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024 Cisco and/or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: MIT OR GPL-2.0-only + * + * Licensed under the MIT license or the GPLv2 license + * , at your option. This file may not be copied, + * modified, or distributed except according to those terms. + */ + +#include "base64.h" +#include "crypto.h" +#include "jwt.h" +#include "json.h" +#include + +jwt_t *jwt_parse(const char *jwt, const char *secret) +{ + jwt_t *j = kzalloc(sizeof(jwt_t), GFP_KERNEL); + if (!j) + { + return NULL; + } + + char *header_end = strchr(jwt, '.'); + + if (!header_end) + { + kfree(j); + return NULL; + } + + char *header_json = kzalloc(256, GFP_KERNEL); + if (!header_json) + { + kfree(j); + return NULL; + } + + int err = base64_decode(header_json, 256, jwt, header_end - jwt); + if (err < 0) + { + kfree(j); + kfree(header_json); + return NULL; + } + + printk(KERN_INFO "header_json: '%s'\n", header_json); + + JSON_Value *header = json_parse_string(header_json); + if (!header) + { + kfree(j); + kfree(header_json); + return NULL; + } + + JSON_Object *header_obj = json_value_get_object(header); + + j->alg = json_object_get_string(header_obj, "alg"); + j->typ = json_object_get_string(header_obj, "typ"); + + char *payload_end = strchr(header_end + 1, '.'); + if (!payload_end) + { + kfree(j); + kfree(header_json); + json_value_free(header); + return NULL; + } + + char *payload_json = kzalloc(256, GFP_KERNEL); + if (!payload_json) + { + kfree(j); + kfree(header_json); + json_value_free(header); + return NULL; + } + + err = base64_decode(payload_json, 256, header_end + 1, payload_end - header_end - 1); + if (err < 0) + { + kfree(j); + kfree(header_json); + kfree(payload_json); + json_value_free(header); + return NULL; + } + + printk(KERN_INFO "payload_json: '%s'\n", payload_json); + + JSON_Value *payload = json_parse_string(payload_json); + if (!payload) + { + kfree(j); + kfree(header_json); + kfree(payload_json); + json_value_free(header); + return NULL; + } + + JSON_Object *payload_obj = json_value_get_object(payload); + + j->iss = json_object_get_string(payload_obj, "iss"); + j->sub = json_object_get_string(payload_obj, "sub"); + j->aud = json_object_get_string(payload_obj, "aud"); + j->exp = json_object_get_number(payload_obj, "exp"); + + // signature parsing + char *signature = payload_end + 1; + + printk("calculating hash for [%d bytes]: %.*s", payload_end - jwt, payload_end - jwt, jwt); + + char *hash = hmac_sha256(jwt, payload_end - jwt, secret); + if (!hash) + { + printk(KERN_ERR "failed to calculate hmac"); + + kfree(j); + kfree(header_json); + kfree(payload_json); + json_value_free(header); + + return NULL; + } + + char hash_base64[256]; + + int bytes = base64_encode(hash_base64, 256, hash, 32); + + if (bytes < 0) + { + printk(KERN_ERR "failed to base64 encode signature"); + + kfree(j); + kfree(header_json); + kfree(payload_json); + json_value_free(header); + + return NULL; + } + + printk("signature [%d bytes]: %s", strlen(signature), signature); + printk("hash_base64 [%d bytes]: %s", bytes, hash_base64); + + return j; +} + +void jwt_free(jwt_t *jwt) +{ + kfree(jwt); +} diff --git a/jwt.h b/jwt.h new file mode 100644 index 00000000..972a6add --- /dev/null +++ b/jwt.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Cisco and/or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: MIT OR GPL-2.0-only + * + * Licensed under the MIT license or the GPLv2 license + * , at your option. This file may not be copied, + * modified, or distributed except according to those terms. + */ + +#ifndef jwt_h +#define jwt_h + +#include "jwt.h" + +typedef struct jwt { +char *alg; +char *typ; + +char *iss; +char *sub; +char *aud; +u64 exp; + +} jwt_t; + +jwt_t *jwt_parse(const char *jwt, const char *secret); +void jwt_free(jwt_t *jwt); + +#endif diff --git a/src/main.c b/src/main.c index f88f05ac..91ade192 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ #include "config.h" #include "sd.h" #include "string.h" +#include "jwt.h" #include "static/filter_stats.h" #include "static/filter_tcp_metadata.h" @@ -157,6 +158,18 @@ static int __init camblet_init(void) __camblet_init_status.wasm_opa = true; + // test jwt + jwt_t *jwt = jwt_parse("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kGWDzjy0MXc1UiDVSZNAoFQMeVKBievVdGmTE1fOEXg", "no"); + if (jwt) + { + pr_info("jwt: alg=%s, typ=%s, iss=%s, sub=%s, aud=%s, exp=%llu", jwt->alg, jwt->typ, jwt->iss, jwt->sub, jwt->aud, jwt->exp); + jwt_free(jwt); + } + else + { + pr_err("jwt: failed to parse"); + } + out: if (ret < 0) __camblet_exit(); From 4cf9bd7b59549b75beb137febdccca9575ed2711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Mon, 4 Mar 2024 13:58:09 +0100 Subject: [PATCH 02/11] formatting --- jwt.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/jwt.h b/jwt.h index 972a6add..ab62e223 100644 --- a/jwt.h +++ b/jwt.h @@ -13,14 +13,15 @@ #include "jwt.h" -typedef struct jwt { -char *alg; -char *typ; +typedef struct jwt +{ + char *alg; + char *typ; -char *iss; -char *sub; -char *aud; -u64 exp; + char *iss; + char *sub; + char *aud; + u64 exp; } jwt_t; From 89f010ac2332fdab316f82e1f1b3fdd59d3e47aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Tue, 5 Mar 2024 12:23:06 +0100 Subject: [PATCH 03/11] fix --- crypto.c | 4 ++++ crypto.h | 2 +- jwt.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crypto.c b/crypto.c index 55b57734..692ffc99 100644 --- a/crypto.c +++ b/crypto.c @@ -37,6 +37,8 @@ u8 *hmac_sha256(const u8 *data, unsigned data_len, const char *key, unsigned key return PTR_ERR(shash); } + printk("setkey: %.*s\n", key_len, key); + err = crypto_shash_setkey(shash, key, key_len); if (err < 0) { @@ -49,6 +51,8 @@ u8 *hmac_sha256(const u8 *data, unsigned data_len, const char *key, unsigned key u8 *out = kmalloc(crypto_shash_digestsize(shash), GFP_KERNEL); + printk("data: %.*s\n", data_len, data); + err = crypto_shash_digest(desc, data, data_len, out); if (err < 0) diff --git a/crypto.h b/crypto.h index a7ac8e01..5691e3c0 100644 --- a/crypto.h +++ b/crypto.h @@ -11,6 +11,6 @@ #ifndef crypto_h #define crypto_h -char *hmac_sha256(const char *data, unsigned data_len, const char *key); +char *hmac_sha256(const char *data, unsigned data_len, const char *key, unsigned key_len); #endif diff --git a/jwt.c b/jwt.c index 4f87608f..153974f8 100644 --- a/jwt.c +++ b/jwt.c @@ -112,7 +112,7 @@ jwt_t *jwt_parse(const char *jwt, const char *secret) printk("calculating hash for [%d bytes]: %.*s", payload_end - jwt, payload_end - jwt, jwt); - char *hash = hmac_sha256(jwt, payload_end - jwt, secret); + char *hash = hmac_sha256(jwt, payload_end - jwt, secret, strlen(secret)); if (!hash) { printk(KERN_ERR "failed to calculate hmac"); From bee66c4826fdf9c3e7a4a8e176f6eb612e263a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Wed, 6 Mar 2024 13:34:22 +0100 Subject: [PATCH 04/11] add fastjson, implement basic verification --- .gitmodules | 4 ++ .vscode/c_cpp_properties.json.template | 2 + Makefile | 1 + jwt.c | 84 ++++++++++++-------------- jwt.h | 10 ++- src/main.c | 15 ++++- third-party/fastjson | 1 + third-party/parson/json.c | 6 +- 8 files changed, 74 insertions(+), 49 deletions(-) create mode 160000 third-party/fastjson diff --git a/.gitmodules b/.gitmodules index 8024a3a0..16970e0f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = third-party/BearSSL url = https://github.com/bonifaido/BearSSL.git branch = linux-kernel +[submodule "third-party/fastjson"] + path = third-party/fastjson + url = https://github.com/bonifaido/json.c + branch = linux-kernel diff --git a/.vscode/c_cpp_properties.json.template b/.vscode/c_cpp_properties.json.template index dac58d71..7b6b8077 100644 --- a/.vscode/c_cpp_properties.json.template +++ b/.vscode/c_cpp_properties.json.template @@ -23,8 +23,10 @@ "${linux-src}/arch/arm64/include/generated/", "${linux-src}/arch/arm64/include/uapi/", "${linux-src}/arch/arm64/include/generated/uapi/", + "third-party/", "third-party/base64/", "third-party/BearSSL/inc/", + "third-party/fastjson/", "third-party/parson/", "third-party/picohttpparser/", "third-party/wasm3/source/" diff --git a/Makefile b/Makefile index b9bdb16b..cca71bde 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ camblet-objs := third-party/wasm3/source/m3_api_libc.o \ third-party/wasm3/source/m3_module.o \ third-party/wasm3/source/m3_parse.o \ third-party/base64/base64.o \ + third-party/fastjson/json.o \ third-party/parson/json.o \ third-party/picohttpparser/picohttpparser.o \ src/buffer.o \ diff --git a/jwt.c b/jwt.c index 153974f8..27460c4c 100644 --- a/jwt.c +++ b/jwt.c @@ -11,10 +11,11 @@ #include "base64.h" #include "crypto.h" #include "jwt.h" -#include "json.h" +#include "fastjson/json.h" + #include -jwt_t *jwt_parse(const char *jwt, const char *secret) +jwt_t *jwt_parse(const char *jwt, const unsigned len) { jwt_t *j = kzalloc(sizeof(jwt_t), GFP_KERNEL); if (!j) @@ -47,25 +48,22 @@ jwt_t *jwt_parse(const char *jwt, const char *secret) printk(KERN_INFO "header_json: '%s'\n", header_json); - JSON_Value *header = json_parse_string(header_json); - if (!header) + struct json header = json_parse(header_json); + if (!json_exists(header)) { kfree(j); kfree(header_json); return NULL; } - JSON_Object *header_obj = json_value_get_object(header); - - j->alg = json_object_get_string(header_obj, "alg"); - j->typ = json_object_get_string(header_obj, "typ"); + j->alg = json_raw(json_object_get(header, "alg")); + j->typ = json_raw(json_object_get(header, "typ")); char *payload_end = strchr(header_end + 1, '.'); if (!payload_end) { kfree(j); kfree(header_json); - json_value_free(header); return NULL; } @@ -74,7 +72,6 @@ jwt_t *jwt_parse(const char *jwt, const char *secret) { kfree(j); kfree(header_json); - json_value_free(header); return NULL; } @@ -84,70 +81,69 @@ jwt_t *jwt_parse(const char *jwt, const char *secret) kfree(j); kfree(header_json); kfree(payload_json); - json_value_free(header); return NULL; } printk(KERN_INFO "payload_json: '%s'\n", payload_json); - JSON_Value *payload = json_parse_string(payload_json); - if (!payload) + struct json payload = json_parse(payload_json); + if (!json_exists(payload)) { kfree(j); kfree(header_json); kfree(payload_json); - json_value_free(header); return NULL; } - JSON_Object *payload_obj = json_value_get_object(payload); - - j->iss = json_object_get_string(payload_obj, "iss"); - j->sub = json_object_get_string(payload_obj, "sub"); - j->aud = json_object_get_string(payload_obj, "aud"); - j->exp = json_object_get_number(payload_obj, "exp"); + j->iss = json_raw(json_object_get(payload, "iss")); + j->sub = json_raw(json_object_get(payload, "sub")); + j->aud = json_raw(json_object_get(payload, "aud")); + j->exp = json_raw(json_object_get(payload, "exp")); // signature parsing - char *signature = payload_end + 1; + j->signature = payload_end + 1; + j->signature_len = jwt + len - j->signature; + + j->data = jwt; + j->data_len = payload_end - jwt; + + // TODO free all values + + return j; +} - printk("calculating hash for [%d bytes]: %.*s", payload_end - jwt, payload_end - jwt, jwt); +void jwt_free(jwt_t *jwt) +{ + kfree(jwt); +} - char *hash = hmac_sha256(jwt, payload_end - jwt, secret, strlen(secret)); +int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) +{ + printk("calculating hash for [%d bytes]: %.*s", jwt->data_len, jwt->data_len, jwt->data); + + char *hash = hmac_sha256(jwt->data, jwt->data_len, secret, strlen(secret)); if (!hash) { - printk(KERN_ERR "failed to calculate hmac"); - - kfree(j); - kfree(header_json); - kfree(payload_json); - json_value_free(header); + printk(KERN_ERR "failed to calculate hmac for jwt"); - return NULL; + return -1; } char hash_base64[256]; int bytes = base64_encode(hash_base64, 256, hash, 32); - if (bytes < 0) { printk(KERN_ERR "failed to base64 encode signature"); - kfree(j); - kfree(header_json); - kfree(payload_json); - json_value_free(header); - - return NULL; + kfree(hash); + return -1; } - printk("signature [%d bytes]: %s", strlen(signature), signature); - printk("hash_base64 [%d bytes]: %s", bytes, hash_base64); + kfree(hash); - return j; -} + printk("signature [%d bytes]: %s", jwt->signature_len, jwt->signature); + printk("hash_base64 [%d bytes]: %s", bytes, hash_base64); -void jwt_free(jwt_t *jwt) -{ - kfree(jwt); + return strncmp(jwt->signature, hash_base64, bytes); } diff --git a/jwt.h b/jwt.h index ab62e223..b5c362be 100644 --- a/jwt.h +++ b/jwt.h @@ -23,9 +23,17 @@ typedef struct jwt char *aud; u64 exp; + // data is the base64url encoded JSON header.payload part of the JWT + const char *data; + unsigned data_len; + + const char *signature; + unsigned signature_len; + } jwt_t; -jwt_t *jwt_parse(const char *jwt, const char *secret); +jwt_t *jwt_parse(const char *jwt, const unsigned len); +int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len); void jwt_free(jwt_t *jwt); #endif diff --git a/src/main.c b/src/main.c index 91ade192..837200de 100644 --- a/src/main.c +++ b/src/main.c @@ -159,10 +159,23 @@ static int __init camblet_init(void) __camblet_init_status.wasm_opa = true; // test jwt - jwt_t *jwt = jwt_parse("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kGWDzjy0MXc1UiDVSZNAoFQMeVKBievVdGmTE1fOEXg", "no"); + const char *token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.kGWDzjy0MXc1UiDVSZNAoFQMeVKBievVdGmTE1fOEXg"; + jwt_t *jwt = jwt_parse(token, strlen(token)); if (jwt) { pr_info("jwt: alg=%s, typ=%s, iss=%s, sub=%s, aud=%s, exp=%llu", jwt->alg, jwt->typ, jwt->iss, jwt->sub, jwt->aud, jwt->exp); + + const char *secret = "no"; + int ret = jwt_verify(jwt, secret, strlen(secret)); + if (ret == 0) + { + pr_info("jwt: verified"); + } + else + { + pr_err("jwt: failed to verify"); + } + jwt_free(jwt); } else diff --git a/third-party/fastjson b/third-party/fastjson new file mode 160000 index 00000000..4088f37f --- /dev/null +++ b/third-party/fastjson @@ -0,0 +1 @@ +Subproject commit 4088f37f4246b2adb54fb4a850b48fac86c3f721 diff --git a/third-party/parson/json.c b/third-party/parson/json.c index 928be179..f44b2b3a 100644 --- a/third-party/parson/json.c +++ b/third-party/parson/json.c @@ -2306,9 +2306,9 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { } } -JSON_Value_Type json_type(const JSON_Value *value) { - return json_value_get_type(value); -} +// JSON_Value_Type json_type(const JSON_Value *value) { +// return json_value_get_type(value); +// } JSON_Object * json_object (const JSON_Value *value) { return json_value_get_object(value); From 421ce0be1cf75e6154222c3269f9411821419c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Wed, 6 Mar 2024 13:45:50 +0100 Subject: [PATCH 05/11] fix verification --- jwt.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/jwt.c b/jwt.c index 27460c4c..f94170d9 100644 --- a/jwt.c +++ b/jwt.c @@ -129,9 +129,9 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) return -1; } - char hash_base64[256]; + char signature[32]; - int bytes = base64_encode(hash_base64, 256, hash, 32); + int bytes = base64_decode(signature, sizeof(signature), jwt->signature, jwt->signature_len); if (bytes < 0) { printk(KERN_ERR "failed to base64 encode signature"); @@ -140,10 +140,17 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) return -1; } - kfree(hash); + if (bytes != 32) + { + printk(KERN_ERR "signature is not 32 bytes"); - printk("signature [%d bytes]: %s", jwt->signature_len, jwt->signature); - printk("hash_base64 [%d bytes]: %s", bytes, hash_base64); + kfree(hash); + return -1; + } + + int ret = memcmp(hash, signature, bytes); + + kfree(hash); - return strncmp(jwt->signature, hash_base64, bytes); + return ret; } From afabfecbabb90ebfe9e3060f267c4aa5ef70605f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Wed, 6 Mar 2024 16:31:01 +0100 Subject: [PATCH 06/11] fix for memchr --- crypto.c | 2 -- jwt.c | 12 ++++++++---- src/main.c | 2 +- third-party/fastjson | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crypto.c b/crypto.c index 692ffc99..d4e4ad00 100644 --- a/crypto.c +++ b/crypto.c @@ -37,8 +37,6 @@ u8 *hmac_sha256(const u8 *data, unsigned data_len, const char *key, unsigned key return PTR_ERR(shash); } - printk("setkey: %.*s\n", key_len, key); - err = crypto_shash_setkey(shash, key, key_len); if (err < 0) { diff --git a/jwt.c b/jwt.c index f94170d9..3abb6e9d 100644 --- a/jwt.c +++ b/jwt.c @@ -23,8 +23,7 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - char *header_end = strchr(jwt, '.'); - + char *header_end = memchr(jwt, '.', len); if (!header_end) { kfree(j); @@ -59,7 +58,7 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) j->alg = json_raw(json_object_get(header, "alg")); j->typ = json_raw(json_object_get(header, "typ")); - char *payload_end = strchr(header_end + 1, '.'); + char *payload_end = memchr(header_end + 1, '.', len - (header_end - jwt) - 1); if (!payload_end) { kfree(j); @@ -114,6 +113,11 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) void jwt_free(jwt_t *jwt) { + // kfree(jwt->alg); + // kfree(jwt->typ); + // kfree(jwt->iss); + // kfree(jwt->sub); + kfree(jwt); } @@ -129,7 +133,7 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) return -1; } - char signature[32]; + char signature[64]; int bytes = base64_decode(signature, sizeof(signature), jwt->signature, jwt->signature_len); if (bytes < 0) diff --git a/src/main.c b/src/main.c index 837200de..84029b2d 100644 --- a/src/main.c +++ b/src/main.c @@ -173,7 +173,7 @@ static int __init camblet_init(void) } else { - pr_err("jwt: failed to verify"); + pr_err("jwt: failed to verify: %d", ret); } jwt_free(jwt); diff --git a/third-party/fastjson b/third-party/fastjson index 4088f37f..42efb580 160000 --- a/third-party/fastjson +++ b/third-party/fastjson @@ -1 +1 @@ -Subproject commit 4088f37f4246b2adb54fb4a850b48fac86c3f721 +Subproject commit 42efb580d06db27285b3d2be9e72a97a4b66db74 From 911f70e7d1c85c4d74e2bdf0d9c5eb8b706ffc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Thu, 7 Mar 2024 09:53:15 +0100 Subject: [PATCH 07/11] json fixes --- Makefile | 1 - include/socket.h | 4 ---- src/commands.c | 2 +- src/opa.c | 2 +- src/socket.c | 6 +++--- src/trace.c | 2 +- third-party/fastjson | 2 +- 7 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index cca71bde..337e5ea1 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,6 @@ ccflags-y += -foptimize-sibling-calls \ -I$(PWD)/third-party/BearSSL/inc/ \ -I$(PWD)/third-party/wasm3/source/ \ -I$(PWD)/third-party/base64 \ - -I$(PWD)/third-party/parson \ -I$(PWD)/third-party/picohttpparser \ -Wall -g \ #-Dd_m3LogCompile=1 diff --git a/include/socket.h b/include/socket.h index fa7748e5..e7faaf48 100644 --- a/include/socket.h +++ b/include/socket.h @@ -13,8 +13,6 @@ #include -#include "json.h" - int socket_init(void); void socket_exit(void); @@ -37,6 +35,4 @@ typedef struct char *peer_spiffe_id; } tcp_connection_context; -void add_net_conn_info_to_json(const tcp_connection_context *ctx, JSON_Object *json_object); - #endif diff --git a/src/commands.c b/src/commands.c index 0b02468b..a3118768 100644 --- a/src/commands.c +++ b/src/commands.c @@ -15,7 +15,7 @@ #include #include "commands.h" -#include "json.h" +#include "parson/json.h" #include "base64.h" #include "string.h" #include "socket.h" diff --git a/src/opa.c b/src/opa.c index a82292e9..cf5a89cc 100644 --- a/src/opa.c +++ b/src/opa.c @@ -11,7 +11,7 @@ #define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME #include "opa.h" -#include "json.h" +#include "parson/json.h" #include "string.h" #include "config.h" #include "spiffe.h" diff --git a/src/socket.c b/src/socket.c index 66309bc1..f73e8f02 100644 --- a/src/socket.c +++ b/src/socket.c @@ -35,7 +35,7 @@ #include "string.h" #include "cert_tools.h" #include "augmentation.h" -#include "json.h" +#include "parson/json.h" #include "sd.h" #include "camblet.h" #include "trace.h" @@ -1623,7 +1623,7 @@ static void tcp_connection_context_free(tcp_connection_context *ctx) kfree(ctx); } -void add_sd_entry_labels_to_json(service_discovery_entry *sd_entry, JSON_Value *json) +static void add_sd_entry_labels_to_json(service_discovery_entry *sd_entry, JSON_Value *json) { if (!json) { @@ -1653,7 +1653,7 @@ void add_sd_entry_labels_to_json(service_discovery_entry *sd_entry, JSON_Value * json_object_set_value(root, "remote", remote_value); } -void add_net_conn_info_to_json(const tcp_connection_context *conn_ctx, JSON_Object *json_object) +static void add_net_conn_info_to_json(const tcp_connection_context *conn_ctx, JSON_Object *json_object) { if (!json_object) { diff --git a/src/trace.c b/src/trace.c index ad5ad3e4..88066db4 100644 --- a/src/trace.c +++ b/src/trace.c @@ -14,7 +14,7 @@ #include #include "trace.h" #include "task_context.h" -#include "json.h" +#include "parson/json.h" #include "commands.h" #include "socket.h" #include "string.h" diff --git a/third-party/fastjson b/third-party/fastjson index 42efb580..581c0782 160000 --- a/third-party/fastjson +++ b/third-party/fastjson @@ -1 +1 @@ -Subproject commit 42efb580d06db27285b3d2be9e72a97a4b66db74 +Subproject commit 581c0782d7892586ad93608d4fdb317a1a2f9536 From 248600cd455c463ab7bfe95eb1957e93588bb1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Thu, 7 Mar 2024 10:18:28 +0100 Subject: [PATCH 08/11] jwt fixes --- jwt.c | 92 +++++++++++++++++++++++++++++++++++++++++++----------- jwt.h | 4 ++- src/main.c | 2 +- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/jwt.c b/jwt.c index 3abb6e9d..a6967e8a 100644 --- a/jwt.c +++ b/jwt.c @@ -15,6 +15,29 @@ #include +#define JWT_HEADER_MAX_SIZE 64 +#define JWT_PAYLOAD_MAX_SIZE 1024 + +static char *json_string_get(struct json json, const char *key) +{ + struct json value = json_object_get(json, key); + if (!json_exists(value)) + { + return NULL; + } + + size_t length = json_string_length(value); + char *str = kzalloc(length + 1, GFP_KERNEL); + if (!str) + { + return NULL; + } + + json_string_copy(value, str, length + 1); + + return str; +} + jwt_t *jwt_parse(const char *jwt, const unsigned len) { jwt_t *j = kzalloc(sizeof(jwt_t), GFP_KERNEL); @@ -30,14 +53,24 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - char *header_json = kzalloc(256, GFP_KERNEL); + int header_len = header_end - jwt; + // this is base64url encoded header so we can use 4/3 * header_len + header_len = (header_len * 4) / 3 + 1; + + if (header_len > JWT_HEADER_MAX_SIZE) + { + kfree(j); + return NULL; + } + + char *header_json = kzalloc(header_len, GFP_KERNEL); if (!header_json) { kfree(j); return NULL; } - int err = base64_decode(header_json, 256, jwt, header_end - jwt); + int err = base64_decode(header_json, header_len, jwt, header_end - jwt); if (err < 0) { kfree(j); @@ -55,8 +88,7 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - j->alg = json_raw(json_object_get(header, "alg")); - j->typ = json_raw(json_object_get(header, "typ")); + j->alg = json_string_get(header, "alg"); char *payload_end = memchr(header_end + 1, '.', len - (header_end - jwt) - 1); if (!payload_end) @@ -66,7 +98,18 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - char *payload_json = kzalloc(256, GFP_KERNEL); + int payload_len = payload_end - header_end - 1; + // this is base64url encoded payload so we can use 4/3 * payload_len + payload_len = (payload_len * 4) / 3 + 1; + + if (payload_len > JWT_PAYLOAD_MAX_SIZE) + { + kfree(j); + kfree(header_json); + return NULL; + } + + char *payload_json = kzalloc(payload_len, GFP_KERNEL); if (!payload_json) { kfree(j); @@ -74,7 +117,7 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - err = base64_decode(payload_json, 256, header_end + 1, payload_end - header_end - 1); + err = base64_decode(payload_json, payload_len, header_end + 1, payload_end - header_end - 1); if (err < 0) { kfree(j); @@ -94,10 +137,11 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) return NULL; } - j->iss = json_raw(json_object_get(payload, "iss")); - j->sub = json_raw(json_object_get(payload, "sub")); - j->aud = json_raw(json_object_get(payload, "aud")); - j->exp = json_raw(json_object_get(payload, "exp")); + j->iss = json_string_get(payload, "iss"); + j->sub = json_string_get(payload, "sub"); + j->aud = json_string_get(payload, "aud"); + j->exp = json_uint64(json_object_get(payload, "exp")); + j->iat = json_uint64(json_object_get(payload, "iat")); // signature parsing j->signature = payload_end + 1; @@ -106,18 +150,22 @@ jwt_t *jwt_parse(const char *jwt, const unsigned len) j->data = jwt; j->data_len = payload_end - jwt; - // TODO free all values + // free all values + kfree(header_json); + kfree(payload_json); return j; } void jwt_free(jwt_t *jwt) { - // kfree(jwt->alg); - // kfree(jwt->typ); - // kfree(jwt->iss); - // kfree(jwt->sub); + if (!jwt) + return; + kfree(jwt->alg); + kfree(jwt->iss); + kfree(jwt->sub); + kfree(jwt->aud); kfree(jwt); } @@ -125,10 +173,16 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) { printk("calculating hash for [%d bytes]: %.*s", jwt->data_len, jwt->data_len, jwt->data); - char *hash = hmac_sha256(jwt->data, jwt->data_len, secret, strlen(secret)); + if (strcmp(jwt->alg, "HS256") != 0) + { + pr_warn("unsupported jwt alg: %s", jwt->alg); + return -1; + } + + char *hash = hmac_sha256(jwt->data, jwt->data_len, secret, secret_len); if (!hash) { - printk(KERN_ERR "failed to calculate hmac for jwt"); + pr_err("failed to calculate hmac for jwt"); return -1; } @@ -138,7 +192,7 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) int bytes = base64_decode(signature, sizeof(signature), jwt->signature, jwt->signature_len); if (bytes < 0) { - printk(KERN_ERR "failed to base64 encode signature"); + pr_err("failed to base64 decode signature"); kfree(hash); return -1; @@ -153,7 +207,7 @@ int jwt_verify(jwt_t *jwt, const char *secret, const unsigned secret_len) } int ret = memcmp(hash, signature, bytes); - + kfree(hash); return ret; diff --git a/jwt.h b/jwt.h index b5c362be..822162dc 100644 --- a/jwt.h +++ b/jwt.h @@ -16,12 +16,14 @@ typedef struct jwt { char *alg; - char *typ; char *iss; char *sub; char *aud; + u64 exp; + u64 nbf; + u64 iat; // data is the base64url encoded JSON header.payload part of the JWT const char *data; diff --git a/src/main.c b/src/main.c index 84029b2d..c05f09a5 100644 --- a/src/main.c +++ b/src/main.c @@ -163,7 +163,7 @@ static int __init camblet_init(void) jwt_t *jwt = jwt_parse(token, strlen(token)); if (jwt) { - pr_info("jwt: alg=%s, typ=%s, iss=%s, sub=%s, aud=%s, exp=%llu", jwt->alg, jwt->typ, jwt->iss, jwt->sub, jwt->aud, jwt->exp); + pr_info("jwt: alg=%s, iss=%s, sub=%s, aud=%s, iat=%llu, exp=%llu", jwt->alg, jwt->iss, jwt->sub, jwt->aud, jwt->iat, jwt->exp); const char *secret = "no"; int ret = jwt_verify(jwt, secret, strlen(secret)); From 610d74b66b2d07c70a893985f04108451efc785f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Fri, 8 Mar 2024 16:59:54 +0100 Subject: [PATCH 09/11] update fastjson --- third-party/fastjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/fastjson b/third-party/fastjson index 581c0782..27fd20d2 160000 --- a/third-party/fastjson +++ b/third-party/fastjson @@ -1 +1 @@ -Subproject commit 581c0782d7892586ad93608d4fdb317a1a2f9536 +Subproject commit 27fd20d28bc7fc1cfe8f361609e59fe68043a4e1 From 97b5b33f3e1b18d9044a216584e3b3bcc5e339fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Fri, 8 Mar 2024 17:11:06 +0100 Subject: [PATCH 10/11] bump fastjson --- third-party/fastjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/fastjson b/third-party/fastjson index 27fd20d2..62caaa2f 160000 --- a/third-party/fastjson +++ b/third-party/fastjson @@ -1 +1 @@ -Subproject commit 27fd20d28bc7fc1cfe8f361609e59fe68043a4e1 +Subproject commit 62caaa2fca6557ebebb8a9860ceb19b814fdd742 From 0a33bd1c17c45f4c7fc9fb479e37a07783ed4367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Mon, 15 Apr 2024 11:27:56 +0200 Subject: [PATCH 11/11] fixes after rebase --- Makefile | 1 + crypto.h => include/crypto.h | 0 jwt.h => include/jwt.h | 0 crypto.c => src/crypto.c | 0 src/device_driver.c | 2 +- jwt.c => src/jwt.c | 0 6 files changed, 2 insertions(+), 1 deletion(-) rename crypto.h => include/crypto.h (100%) rename jwt.h => include/jwt.h (100%) rename crypto.c => src/crypto.c (100%) rename jwt.c => src/jwt.c (100%) diff --git a/Makefile b/Makefile index 337e5ea1..a0c67ed3 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ ccflags-y += -foptimize-sibling-calls \ -DDEBUG=1 \ -Dd_m3HasFloat=$(EMULATE_FLOATS) \ -I$(PWD)/include \ + -I$(PWD)/third-party/ \ -I$(PWD)/third-party/BearSSL/inc/ \ -I$(PWD)/third-party/wasm3/source/ \ -I$(PWD)/third-party/base64 \ diff --git a/crypto.h b/include/crypto.h similarity index 100% rename from crypto.h rename to include/crypto.h diff --git a/jwt.h b/include/jwt.h similarity index 100% rename from jwt.h rename to include/jwt.h diff --git a/crypto.c b/src/crypto.c similarity index 100% rename from crypto.c rename to src/crypto.c diff --git a/src/device_driver.c b/src/device_driver.c index aa7aafc6..87edb215 100644 --- a/src/device_driver.c +++ b/src/device_driver.c @@ -17,7 +17,7 @@ #include "base64.h" #include "device_driver.h" -#include "json.h" +#include "parson/json.h" #include "opa.h" #include "proxywasm.h" #include "csr.h" diff --git a/jwt.c b/src/jwt.c similarity index 100% rename from jwt.c rename to src/jwt.c