Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Commit

Permalink
implement a jwt parser
Browse files Browse the repository at this point in the history
  • Loading branch information
bonifaido committed Mar 6, 2024
1 parent d9e8420 commit cb8b51e
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 1 deletion.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ camblet-objs := third-party/wasm3/source/m3_api_libc.o \
config.o \
sd.o \
trace.o \
http.o
http.o \
jwt.o \
crypto.o

# Set the path to the Kernel build utils.
KBUILD=/lib/modules/$(shell uname -r)/build/
Expand Down
67 changes: 67 additions & 0 deletions crypto.c
Original file line number Diff line number Diff line change
@@ -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 <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, at your option. This file may not be copied,
* modified, or distributed except according to those terms.
*/

#include <crypto/hash.h>

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;
}
16 changes: 16 additions & 0 deletions crypto.h
Original file line number Diff line number Diff line change
@@ -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 <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, 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
153 changes: 153 additions & 0 deletions jwt.c
Original file line number Diff line number Diff line change
@@ -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 <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, 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 <linux/slab.h>

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);
}
30 changes: 30 additions & 0 deletions jwt.h
Original file line number Diff line number Diff line change
@@ -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 <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, 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
13 changes: 13 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "config.h"
#include "sd.h"
#include "string.h"
#include "jwt.h"

#include "static/filter_stats.h"
#include "static/filter_tcp_metadata.h"
Expand Down Expand Up @@ -89,6 +90,18 @@ static int __init camblet_init(void)
return -1;
}

// 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");
}

return ret;
}

Expand Down

0 comments on commit cb8b51e

Please sign in to comment.