1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
/* Copyright (C) 2015-2025 maClara, LLC <info@maclara-llc.com>
This file is part of the JWT C Library
SPDX-License-Identifier: MPL-2.0
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef JWT_PRIVATE_H
#define JWT_PRIVATE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "jwt-json-ops.h"
#include <time.h>
#include <stdarg.h>
#include <openssl/crypto.h>
#include "ll.h"
#ifndef ARRAY_SIZE
# ifdef __GNUC__
# define ARRAY_SIZE(__arr) (sizeof(__arr) / sizeof((__arr)[0]) + \
__builtin_types_compatible_p(typeof(__arr), typeof(&(__arr)[0])) * 0)
# else
# define ARRAY_SIZE(__arr) (sizeof(__arr) / sizeof((__arr)[0]))
# endif
#endif
#define JWT_CONFIG_DECLARE(__name) \
jwt_config_t __name = { NULL, JWT_ALG_NONE, NULL}
#define JWT_ERR_LEN 256
JWT_NO_EXPORT
extern struct jwt_crypto_ops *jwt_ops;
/* This can be used on anything with an error and error_msg field */
#define jwt_write_error(__obj, __fmt, __args...) \
({ \
if (!strlen((__obj)->error_msg)) \
snprintf((__obj)->error_msg, \
sizeof((__obj)->error_msg), \
__fmt, ##__args); \
(__obj)->error = 1; \
})
#define jwt_copy_error(__dst, __src) \
({ \
strncpy((__dst)->error_msg, (__src)->error_msg, \
sizeof((__dst)->error_msg) - 1); \
(__dst)->error_msg[sizeof((__dst)->error_msg) - 1] = '\0'; \
(__dst)->error = (__src)->error; \
})
/******************************/
struct jwt_common {
jwt_alg_t alg;
const jwk_item_t *key;
jwt_json_t *payload;
jwt_json_t *headers;
jwt_claims_t claims;
jwt_callback_t cb;
void *cb_ctx;
/* For builder, this is offset into the future.
* For checker, this is the leeway.
* Both are in seconds. */
time_t exp;
time_t nbf;
};
struct jwt_builder {
struct jwt_common c;
int error;
char error_msg[JWT_ERR_LEN];
};
struct jwt_checker {
struct jwt_common c;
int error;
char error_msg[JWT_ERR_LEN];
};
/*****************************/
struct jwt {
const jwk_item_t *key;
jwt_json_t *claims;
jwt_json_t *headers;
jwt_alg_t alg;
int error;
char error_msg[JWT_ERR_LEN];
union {
struct jwt_checker *checker;
struct jwt_builder *builder;
};
};
struct jwk_set {
ll_t head;
int error;
char error_msg[JWT_ERR_LEN];
};
/**
* This data structure is produced by importing a JWK or JWKS into a
* @ref jwk_set_t object. Generally, you would not change any values here
* and only use this to probe the internal parser and possibly to
* decide whether a key applies to certain jwt_t for verification
* or signing.
*
* If the jwk_item_t.pem field is not NULL, then it contains a nil terminated
* string of the key. The underlying crypto algorithm may or may not support
* this. It's provided as a convenience.
*/
struct jwk_item {
ll_t node;
char *pem; /**< If not NULL, contains PEM string of this key */
jwt_crypto_provider_t provider; /**< Crypto provider that owns this key */
union {
void *provider_data; /**< Internal data used by the provider */
struct {
void *key; /**< Used for HMAC key material */
size_t len; /**< Length of HMAC key material */
} oct;
};
int is_private_key; /**< Whether this is a public or private key */
char curve[256]; /**< Curve name of an ``"EC"`` or ``"OKP"`` key */
size_t bits; /**< The number of bits in the key (may be 0) */
int error; /**< There was an error parsing this key (unusable) */
char error_msg[JWT_ERR_LEN];/**< Descriptive message for @ref jwk_item_t.error */
jwk_key_type_t kty; /**< @rfc{7517,4.1} The key type of this key */
jwk_pub_key_use_t use; /**< @rfc{7517,4.2} How this key can be used */
jwk_key_op_t key_ops; /**< @rfc{7517,4.3} Key operations supported */
jwt_alg_t alg; /**< @rfc{7517,4.4} JWA Algorithm supported */
char *kid; /**< @rfc{7517,4.5} Key ID */
jwt_json_t *json; /**< The jwt_json_t for this key */
};
/* Crypto operations */
struct jwt_crypto_ops {
const char *name;
jwt_crypto_provider_t provider;
/* Signing/Verifying */
int (*sign_sha_hmac)(jwt_t *jwt, char **out, unsigned int *len,
const char *str, unsigned int str_len);
/* Verifying hmac is basically signing the current token and cmparing
* the signatures. */
int (*sign_sha_pem)(jwt_t *jwt, char **out, unsigned int *len,
const char *str, unsigned int str_len);
int (*verify_sha_pem)(jwt_t *jwt, const char *head,
unsigned int head_len, unsigned char *sig,
int sig_len);
/* Parsing a JWK to prepare it for use */
int jwk_implemented;
int (*process_eddsa)(jwt_json_t *jwk, jwk_item_t *item);
int (*process_rsa)(jwt_json_t *jwk, jwk_item_t *item);
int (*process_ec)(jwt_json_t *jwk, jwk_item_t *item);
void (*process_item_free)(jwk_item_t *item);
};
#ifdef HAVE_OPENSSL
JWT_NO_EXPORT
extern struct jwt_crypto_ops jwt_openssl_ops;
#endif
#ifdef HAVE_GNUTLS
JWT_NO_EXPORT
extern struct jwt_crypto_ops jwt_gnutls_ops;
#endif
#ifdef HAVE_MBEDTLS
JWT_NO_EXPORT
extern struct jwt_crypto_ops jwt_mbedtls_ops;
#endif
/* Memory allocators. */
JWT_NO_EXPORT
void *jwt_malloc(size_t size);
JWT_NO_EXPORT
void __jwt_freemem(void *ptr);
JWT_NO_EXPORT
jwt_t *jwt_new(void);
#define jwt_freemem(__ptr) ({ \
if (__ptr) { \
__jwt_freemem(__ptr); \
__ptr = NULL; \
} \
})
/* Scrub and free sensitive key material. Uses OPENSSL_cleanse which is
* available on all platforms (OpenSSL >= 3.0 is always required). */
#define jwt_scrub_and_free(__ptr, __len) ({ \
if (__ptr) \
OPENSSL_cleanse(__ptr, __len); \
jwt_freemem(__ptr); \
})
static inline void jwt_freememp(char **mem) {
jwt_freemem(*mem);
}
#define char_auto char __attribute__((cleanup(jwt_freememp)))
JWT_NO_EXPORT
void jwt_free(jwt_t *jwt);
static inline void jwt_freep(jwt_t **jwt) {
if (jwt) {
jwt_free(*jwt);
*jwt = NULL;
}
}
#define jwt_auto_t jwt_t __attribute__((cleanup(jwt_freep)))
/* Helper routines to handle base64url encoding without percent padding
* as defined in RFC-4648. */
JWT_NO_EXPORT
int jwt_base64uri_encode(char **_dst, const char *plain, int plain_len);
JWT_NO_EXPORT
void *jwt_base64uri_decode(const char *src, int *ret_len);
JWT_NO_EXPORT
jwt_t *jwt_verify_sig(jwt_t *jwt, const char *head, unsigned int head_len,
const char *sig);
JWT_NO_EXPORT
int jwt_sign(jwt_t *jwt, char **out, unsigned int *len, const char *str,
unsigned int str_len);
JWT_NO_EXPORT
jwt_value_error_t __deleter(jwt_json_t *which, const char *field);
JWT_NO_EXPORT
jwt_value_error_t __setter(jwt_json_t *which, jwt_value_t *value);
JWT_NO_EXPORT
jwt_value_error_t __getter(jwt_json_t *which, jwt_value_t *value);
JWT_NO_EXPORT
int jwt_parse(jwt_t *jwt, const char *token, unsigned int *len);
JWT_NO_EXPORT
jwt_t *jwt_verify_complete(jwt_t *jwt, const jwt_config_t *config,
const char *token, unsigned int payload_len);
JWT_NO_EXPORT
char *jwt_encode_str(jwt_t *jwt);
JWT_NO_EXPORT
int jwt_head_setup(jwt_t *jwt);
#define __trace() fprintf(stderr, "%s:%d\n", __func__, __LINE__)
#endif /* JWT_PRIVATE_H */
|