6#include <cjson/cJSON.h>
8#if defined(CWIST_TLS_MBEDTLS)
12#include <mbedtls/pk.h>
13#include <mbedtls/ecp.h>
14#include <mbedtls/ecdsa.h>
15#include <mbedtls/md.h>
16#include <mbedtls/bignum.h>
21#include <openssl/sha.h>
23#include <openssl/pem.h>
24#include <openssl/bio.h>
25#include <openssl/ec.h>
26#include <openssl/ecdsa.h>
27#include <openssl/bn.h>
28#include <openssl/obj.h>
46static size_t b64url_encoded_len(
size_t input_len) {
51static void b64url_encode(
const unsigned char *src,
size_t src_len,
char *
dst) {
52 static const char tbl[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
85static unsigned char *b64url_decode(
const char *src,
size_t src_len,
size_t *out_len) {
87 static const signed char lut[256] = {
88 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
89 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62,
91 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
92 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
93 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
94 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
95 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
97 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
98 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
99 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
101 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
112 if (!out)
return NULL;
116 signed char a =
lut[(
unsigned char)src[
i]];
117 signed char b =
lut[(
unsigned char)src[
i + 1]];
118 signed char c =
lut[(
unsigned char)src[
i + 2]];
119 signed char d =
lut[(
unsigned char)src[
i + 3]];
120 if (
a < 0 || b < 0 ||
c < 0 ||
d < 0) {
124 out[
j++] = (
unsigned char)((
a << 2) | (b >> 4));
125 out[
j++] = (
unsigned char)((b << 4) | (
c >> 2));
126 out[
j++] = (
unsigned char)((
c << 6) |
d);
132 signed char a =
lut[(
unsigned char)src[
i]];
133 signed char b =
lut[(
unsigned char)src[
i + 1]];
134 if (
a < 0 || b < 0) {
138 out[
j++] = (
unsigned char)((
a << 2) | (b >> 4));
139 }
else if (
rem == 3) {
140 signed char a =
lut[(
unsigned char)src[
i]];
141 signed char b =
lut[(
unsigned char)src[
i + 1]];
142 signed char c =
lut[(
unsigned char)src[
i + 2]];
143 if (
a < 0 || b < 0 ||
c < 0) {
147 out[
j++] = (
unsigned char)((
a << 2) | (b >> 4));
148 out[
j++] = (
unsigned char)((b << 4) | (
c >> 2));
149 }
else if (
rem == 1) {
181static bool hmac_sha256(
const char *key,
size_t key_len,
const char *
msg,
size_t msg_len,
182 unsigned char out[32]) {
183#if defined(CWIST_TLS_MBEDTLS)
185 (
const unsigned char *)key,
key_len,
186 (
const unsigned char *)
msg,
msg_len, out) == 0;
188 unsigned int out_len = 0;
191 return r !=
NULL && out_len == 32;
195#if defined(CWIST_TLS_MBEDTLS)
238 if (!jwt_load_private_key(&
pk, key))
return NULL;
239 if (!jwt_key_is_p256(&
pk)) {
256 if (
sig) *out_len = 64;
267 if (
sig_len != 64)
return false;
269 if (!jwt_load_public_key(&
pk, key))
return false;
270 if (!jwt_key_is_p256(&
pk)) {
291static EVP_PKEY *jwt_load_private_key(
const char *
pem) {
300static EVP_PKEY *jwt_load_public_key(
const char *
pem) {
314static bool jwt_key_is_p256(
EVP_PKEY *key) {
317 if (!
ec)
return false;
329static unsigned char *jwt_sign_bytes(
jwt_alg_t alg,
const char *key,
const char *
msg,
330 size_t msg_len,
size_t *out_len) {
342#if defined(CWIST_TLS_MBEDTLS)
344 unsigned char hash[32];
352 EVP_PKEY *pkey = jwt_load_private_key(key);
353 if (!pkey)
return NULL;
434 if (
sig_len != 32)
return false;
437 for (
int i = 0;
i < 32;
i++) {
443#if defined(CWIST_TLS_MBEDTLS)
445 unsigned char hash[32];
454 EVP_PKEY *pkey = jwt_load_public_key(key);
455 if (!pkey)
return false;
522 if (!header)
return NULL;
716 if (!json)
return NULL;
719#define CWIST_JWT_TIME_LEEWAY 300
767 if (!claims || !key)
return NULL;
820 for (
size_t i = 0;
i <
msg.count;
i++) {
858 for (
size_t i = 0;
i <
count;
i++) {
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
char * cwist_strdup(const char *src)
Duplicate a string using libttak-backed storage.
#define CWIST_DEFER_FREE
Attach to a pointer variable's declaration to cwist_free() it automatically when that variable's encl...
void * cwist_alloc_array(size_t count, size_t elem_size)
Allocate zeroed memory for count elements.
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Safe string type with helper methods.
cwist_sstring * cwist_sstring_create(void)
Create a new sstring instance.
cwist_error_t cwist_sstring_append(cwist_sstring *str, const char *data)
Append a C string.
void cwist_sstring_destroy(cwist_sstring *str)
Destroy an sstring instance.
mbedTLS TLS backend: EVP subset (HMAC digest tags, AES-256-CBC).
struct cwist_mtls_evp_md EVP_MD
mbedTLS TLS backend: HMAC subset (HMAC-SHA256, one-shot + streaming).
const char * cwist_jwt_claims_get(const cwist_jwt_claims *claims, const char *key)
Retrieve one string-valued claim from a verified JWT payload.
void cwist_jwt_claims_destroy(cwist_jwt_claims *claims)
Destroy a verified claims object and its parsed JSON payload.
cwist_jwt_chunk_t * cwist_jwt_split_chunks(const char *token, uint16_t chunk_payload_size, size_t *out_count)
Split a JWT token into sequenced transport chunks.
char * cwist_jwt_join_chunks(const cwist_jwt_chunk_t *chunks, size_t count)
Reassemble a JWT token from sequenced transport chunks.
cwist_jwt_claims * cwist_jwt_verify_es256(const char *token, const char *pem_key)
Verify an ES256-signed JWT token and return the decoded claims.
char * cwist_jwt_sign(const char *payload_json, const char *secret, long exp_seconds)
Sign a JWT token with HMAC-SHA256.
cwist_jwt_claims * cwist_jwt_verify(const char *token, const char *secret)
Verify a JWT token and return the decoded claims.
cwist_jwt_chunk_t * cwist_jwt_sign_chunks(const char *payload_json, const char *secret, long exp_seconds, uint16_t chunk_payload_size, size_t *out_count)
Sign a payload as an HS256 JWT and split it into sequenced transport chunks.
char * cwist_jwt_sign_es256(const char *payload_json, const char *pem_private_key, const char *kid, long exp_seconds)
Sign a JWT token with ES256 (ECDSA over P-256 with SHA-256).
#define CWIST_JWT_TIME_LEEWAY
cwist_jwt_claims * cwist_jwt_verify_chunks(const cwist_jwt_chunk_t *chunks, size_t count, const char *secret)
Reassemble sequenced chunks into a token, verify it, and return its claims.
void cwist_jwt_chunks_free(cwist_jwt_chunk_t *chunks, size_t count)
Free a chunk array produced by cwist_jwt_split_chunks() or cwist_jwt_sign_chunks().
cwist_jwt_claims * cwist_jwt_verify_ed25519(const char *token, const char *pem_key)
Verify an Ed25519-signed JWT token and return the decoded claims.
char * cwist_jwt_sign_ed25519(const char *payload_json, const char *pem_private_key, const char *kid, long exp_seconds)
Sign a JWT token with EdDSA (Ed25519, RFC 8037).
JWT (JSON Web Token) generation and verification.
struct cwist_jwt_claims cwist_jwt_claims
Opaque JWT claims object returned after successful verification.
mbedTLS TLS backend: RAND_bytes over mbedTLS CTR-DRBG.
TCP-like sequenced message fragmentation and reassembly.
bool cwist_seq_chunk_parse(const uint8_t *data, size_t len, cwist_seq_chunk_t *out)
Parse a sequence chunk from raw bytes.
cwist_seq_assembler_t * cwist_seq_assembler_create(void)
Create an empty assembler.
void cwist_seq_assembler_destroy(cwist_seq_assembler_t *a)
Destroy an assembler and its internal buffer.
void cwist_seq_message_free(cwist_seq_message_t *msg)
Free all buffers allocated by cwist_seq_split().
bool cwist_seq_assembler_get_data(cwist_seq_assembler_t *a, const uint8_t **out_data, size_t *out_len)
Borrow the assembled message when complete.
bool cwist_seq_assembler_feed(cwist_seq_assembler_t *a, const cwist_seq_chunk_t *chunk)
Feed one parsed chunk into the assembler.
struct cwist_seq_assembler cwist_seq_assembler_t
Opaque stateful assembler that reorders chunks and detects duplicates.
bool cwist_seq_split(const uint8_t *data, size_t len, uint16_t chunk_payload_size, cwist_seq_message_t *out)
Split data into sequenced chunks.
One sequenced JWT chunk produced by cwist_jwt_split_chunks().
size_t len
Length of data.
uint8_t * data
Chunk bytes (header + payload).
Parsed view of one sequenced chunk.
Split a message into sequenced chunks.