diff --git a/r5dev/thirdparty/jwt/CMakeLists.txt b/r5dev/thirdparty/jwt/CMakeLists.txt index a4bde888..3f257f5c 100644 --- a/r5dev/thirdparty/jwt/CMakeLists.txt +++ b/r5dev/thirdparty/jwt/CMakeLists.txt @@ -25,3 +25,7 @@ add_sources( SOURCE_GROUP "Include" end_sources() thirdparty_suppress_warnings() + +target_include_directories( ${PROJECT_NAME} PRIVATE + "${THIRDPARTY_SOURCE_DIR}/mbedtls/include/" +) diff --git a/r5dev/thirdparty/jwt/base64.c b/r5dev/thirdparty/jwt/base64.c index ea27386a..2d7fe85b 100644 --- a/r5dev/thirdparty/jwt/base64.c +++ b/r5dev/thirdparty/jwt/base64.c @@ -133,7 +133,7 @@ int l8w8jwt_base64_encode(const int url, const uint8_t* data, const size_t data_ return L8W8JWT_OVERFLOW; } - *out = malloc(olen); + *out = (char*)malloc(olen); if (*out == NULL) { return L8W8JWT_OUT_OF_MEM; @@ -249,7 +249,7 @@ int l8w8jwt_base64_decode(const int url, const char* data, const size_t data_len if (r == 3) r = 1; - *out = calloc(count / 4 * 3 + 16, sizeof(uint8_t)); + *out = (uint8_t*)calloc(count / 4 * 3 + 16, sizeof(uint8_t)); if (*out == NULL) { return L8W8JWT_OUT_OF_MEM; diff --git a/r5dev/thirdparty/jwt/claim.c b/r5dev/thirdparty/jwt/claim.c index 089baff1..8918f0bc 100644 --- a/r5dev/thirdparty/jwt/claim.c +++ b/r5dev/thirdparty/jwt/claim.c @@ -24,8 +24,7 @@ extern "C" { #include "include/chillbuff.h" #include <string.h> - -#include <mbedtls/md.h> // SChannel??? +#include <mbedtls/md.h> void l8w8jwt_free_claims(struct l8w8jwt_claim* claims, const size_t claims_count) { diff --git a/r5dev/thirdparty/jwt/decode.c b/r5dev/thirdparty/jwt/decode.c index 65ecfa25..121a2cab 100644 --- a/r5dev/thirdparty/jwt/decode.c +++ b/r5dev/thirdparty/jwt/decode.c @@ -24,11 +24,12 @@ extern "C" { #include "include/decode.h" #include "include/base64.h" #include "include/chillbuff.h" +#include "include/jsmn.h" +#include "include/checknum.h" -#include <jsmn.h> // RapidJSON? #include <string.h> #include <inttypes.h> -#include <checknum.h> + #include <mbedtls/pk.h> #include <mbedtls/md.h> #include <mbedtls/platform_util.h> @@ -82,14 +83,14 @@ static inline void md_info_from_alg(const int alg, mbedtls_md_info_t** md_info, static int l8w8jwt_unescape_claim(struct l8w8jwt_claim* claim, const char* key, const size_t key_length, const char* value, const size_t value_length) { claim->key_length = 0; - claim->key = calloc(sizeof(char), key_length + 1); + claim->key = (char*)calloc(sizeof(char), key_length + 1); claim->value_length = 0; - claim->value = calloc(sizeof(char), value_length + 1); + claim->value = (char*)calloc(sizeof(char), value_length + 1); if (claim->key == NULL || claim->value == NULL) { - free(claim->key); + free((void*)claim->key); free(claim->value); return L8W8JWT_OUT_OF_MEM; } @@ -165,7 +166,7 @@ static int l8w8jwt_parse_claims(chillbuff* buffer, char* json, const size_t json } jsmntok_t _tokens[64]; - jsmntok_t* tokens = r <= (sizeof(_tokens) / sizeof(_tokens[0])) ? _tokens : malloc(r * sizeof(jsmntok_t)); + jsmntok_t* tokens = r <= (sizeof(_tokens) / sizeof(_tokens[0])) ? _tokens : (jsmntok_t*)malloc(r * sizeof(jsmntok_t)); if (tokens == NULL) { @@ -315,7 +316,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati } const int alg = params->alg; - enum l8w8jwt_validation_result validation_res = L8W8JWT_VALID; + unsigned validation_res = L8W8JWT_VALID; int r = l8w8jwt_validate_decoding_params(params); if (r != L8W8JWT_SUCCESS) @@ -328,7 +329,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati return L8W8JWT_NULL_ARG; } - *out_validation_result = ~L8W8JWT_VALID; + *out_validation_result = (enum l8w8jwt_validation_result)~L8W8JWT_VALID; char* header = NULL; size_t header_length = 0; @@ -342,6 +343,9 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati char* current = params->jwt; char* next = strchr(params->jwt, '.'); + size_t current_length; + time_t ct; + if (next == NULL) /* No payload. */ { return L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT; @@ -385,7 +389,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati goto exit; } - size_t current_length = next - current; + current_length = next - current; r = l8w8jwt_base64_decode(true, current, current_length, (uint8_t**)&header, &header_length); if (r != L8W8JWT_SUCCESS) @@ -651,7 +655,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_sub != NULL) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "sub", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "sub", 3); if (c == NULL || strncmp(c->value, params->validate_sub, params->validate_sub_length ? params->validate_sub_length : strlen(params->validate_sub)) != 0) { validation_res |= (unsigned)L8W8JWT_SUB_FAILURE; @@ -660,7 +664,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_aud != NULL) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "aud", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "aud", 3); if (c == NULL || strncmp(c->value, params->validate_aud, params->validate_aud_length ? params->validate_aud_length : strlen(params->validate_aud)) != 0) { validation_res |= (unsigned)L8W8JWT_AUD_FAILURE; @@ -669,7 +673,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_iss != NULL) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "iss", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "iss", 3); if (c == NULL || strncmp(c->value, params->validate_iss, params->validate_iss_length ? params->validate_iss_length : strlen(params->validate_iss)) != 0) { validation_res |= (unsigned)L8W8JWT_ISS_FAILURE; @@ -678,18 +682,18 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_jti != NULL) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "jti", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "jti", 3); if (c == NULL || strncmp(c->value, params->validate_jti, params->validate_jti_length ? params->validate_jti_length : strlen(params->validate_jti)) != 0) { validation_res |= (unsigned)L8W8JWT_JTI_FAILURE; } } - const time_t ct = time(NULL); + ct = time(NULL); if (params->validate_exp) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "exp", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "exp", 3); if (c == NULL || ct - params->exp_tolerance_seconds > strtoll(c->value, NULL, 10)) { validation_res |= (unsigned)L8W8JWT_EXP_FAILURE; @@ -698,7 +702,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_nbf) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "nbf", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "nbf", 3); if (c == NULL || ct + params->nbf_tolerance_seconds < strtoll(c->value, NULL, 10)) { validation_res |= (unsigned)L8W8JWT_NBF_FAILURE; @@ -707,7 +711,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_iat) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "iat", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "iat", 3); if (c == NULL || ct + params->iat_tolerance_seconds < strtoll(c->value, NULL, 10)) { validation_res |= (unsigned)L8W8JWT_IAT_FAILURE; @@ -716,7 +720,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati if (params->validate_typ) { - struct l8w8jwt_claim* c = l8w8jwt_get_claim(claims.array, claims.length, "typ", 3); + struct l8w8jwt_claim* c = l8w8jwt_get_claim((struct l8w8jwt_claim*)claims.array, claims.length, "typ", 3); if (c == NULL || l8w8jwt_strncmpic(c->value, params->validate_typ, params->validate_typ_length) != 0) { validation_res |= (unsigned)L8W8JWT_TYP_FAILURE; @@ -724,7 +728,7 @@ int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validati } r = L8W8JWT_SUCCESS; - *out_validation_result = validation_res; + *out_validation_result = (enum l8w8jwt_validation_result)validation_res; if (out_claims != NULL && out_claims_length != NULL) { diff --git a/r5dev/thirdparty/jwt/encode.c b/r5dev/thirdparty/jwt/encode.c index 081901e2..8abc0962 100644 --- a/r5dev/thirdparty/jwt/encode.c +++ b/r5dev/thirdparty/jwt/encode.c @@ -24,6 +24,7 @@ extern "C" { #include "include/chillbuff.h" #include <inttypes.h> + #include <mbedtls/pk.h> #include <mbedtls/entropy.h> #include <mbedtls/ctr_drbg.h> @@ -143,7 +144,7 @@ static int write_header_and_payload(chillbuff* stringbuilder, struct l8w8jwt_enc char* segment; size_t segment_length; - r = l8w8jwt_base64_encode(1, buff.array, buff.length, &segment, &segment_length); + r = l8w8jwt_base64_encode(1, (const uint8_t*)buff.array, buff.length, &segment, &segment_length); if (r != L8W8JWT_SUCCESS) { chillbuff_free(&buff); @@ -176,13 +177,13 @@ static int write_header_and_payload(chillbuff* stringbuilder, struct l8w8jwt_enc struct l8w8jwt_claim claims[] = { // Setting l8w8jwt_claim::value_length to 0 makes the encoder use strlen, which in this case is fine. - { .key = *(iatnbfexp + 00) ? "iat" : NULL, .key_length = 3, .value = iatnbfexp + 00, .value_length = 0, .type = L8W8JWT_CLAIM_TYPE_INTEGER }, - { .key = *(iatnbfexp + 21) ? "nbf" : NULL, .key_length = 3, .value = iatnbfexp + 21, .value_length = 0, .type = L8W8JWT_CLAIM_TYPE_INTEGER }, - { .key = *(iatnbfexp + 42) ? "exp" : NULL, .key_length = 3, .value = iatnbfexp + 42, .value_length = 0, .type = L8W8JWT_CLAIM_TYPE_INTEGER }, - { .key = params->sub ? "sub" : NULL, .key_length = 3, .value = params->sub, .value_length = params->sub_length, .type = L8W8JWT_CLAIM_TYPE_STRING }, - { .key = params->iss ? "iss" : NULL, .key_length = 3, .value = params->iss, .value_length = params->iss_length, .type = L8W8JWT_CLAIM_TYPE_STRING }, - { .key = params->aud ? "aud" : NULL, .key_length = 3, .value = params->aud, .value_length = params->aud_length, .type = L8W8JWT_CLAIM_TYPE_STRING }, - { .key = params->jti ? "jti" : NULL, .key_length = 3, .value = params->jti, .value_length = params->jti_length, .type = L8W8JWT_CLAIM_TYPE_STRING }, + { *(iatnbfexp + 00) ? (char*)"iat" : NULL, 3, iatnbfexp + 00, 0, L8W8JWT_CLAIM_TYPE_INTEGER }, + { *(iatnbfexp + 21) ? (char*)"nbf" : NULL, 3, iatnbfexp + 21, 0, L8W8JWT_CLAIM_TYPE_INTEGER }, + { *(iatnbfexp + 42) ? (char*)"exp" : NULL, 3, iatnbfexp + 42, 0, L8W8JWT_CLAIM_TYPE_INTEGER }, + { params->sub ? (char*)"sub" : NULL, 3, params->sub, params->sub_length, L8W8JWT_CLAIM_TYPE_STRING }, + { params->iss ? (char*)"iss" : NULL, 3, params->iss, params->iss_length, L8W8JWT_CLAIM_TYPE_STRING }, + { params->aud ? (char*)"aud" : NULL, 3, params->aud, params->aud_length, L8W8JWT_CLAIM_TYPE_STRING }, + { params->jti ? (char*)"jti" : NULL, 3, params->jti, params->jti_length, L8W8JWT_CLAIM_TYPE_STRING }, }; chillbuff_push_back(&buff, "{", 1); @@ -199,7 +200,7 @@ static int write_header_and_payload(chillbuff* stringbuilder, struct l8w8jwt_enc chillbuff_push_back(&buff, "}", 1); - r = l8w8jwt_base64_encode(1, buff.array, buff.length, &segment, &segment_length); + r = l8w8jwt_base64_encode(1, (const uint8_t*)buff.array, buff.length, &segment, &segment_length); if (r != L8W8JWT_SUCCESS) { chillbuff_free(&buff); @@ -221,6 +222,8 @@ static int write_signature(chillbuff* stringbuilder, struct l8w8jwt_encoding_par int r; const int alg = params->alg; + unsigned char hash[64] = { 0x00 }; + char* signature = NULL; size_t signature_length = 0, signature_bytes_length = 0, key_length = 0; @@ -228,6 +231,12 @@ static int write_signature(chillbuff* stringbuilder, struct l8w8jwt_encoding_par mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; + size_t md_length; + mbedtls_md_type_t md_type; + mbedtls_md_info_t* md_info; + + size_t half_signature_bytes_length; + mbedtls_pk_init(&pk); mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); @@ -263,14 +272,8 @@ static int write_signature(chillbuff* stringbuilder, struct l8w8jwt_encoding_par goto exit; } - size_t md_length; - mbedtls_md_type_t md_type; - mbedtls_md_info_t* md_info; - md_info_from_alg(alg, &md_info, &md_type, &md_length); - unsigned char hash[64] = { 0x00 }; - switch (alg) { case L8W8JWT_ALG_HS256: @@ -492,7 +495,7 @@ static int write_signature(chillbuff* stringbuilder, struct l8w8jwt_encoding_par goto ecdsa_exit; } - const size_t half_signature_bytes_length = signature_bytes_length / 2; + half_signature_bytes_length = signature_bytes_length / 2; r = mbedtls_mpi_write_binary(&sig_r, signature_bytes, half_signature_bytes_length); if (r != 0) @@ -589,7 +592,7 @@ exit: /* Step 3: finalize the token by writing it into the "out" string defined in the l8w8jwt_encoding_params argument. */ static int write_token(chillbuff* stringbuilder, struct l8w8jwt_encoding_params* params) { - *(params->out) = malloc(stringbuilder->length + 1); + *(params->out) = (char*)malloc(stringbuilder->length + 1); if (*(params->out) == NULL) { return L8W8JWT_OUT_OF_MEM; diff --git a/r5dev/thirdparty/jwt/include/base64.h b/r5dev/thirdparty/jwt/include/base64.h index f3124fc8..2fa71771 100644 --- a/r5dev/thirdparty/jwt/include/base64.h +++ b/r5dev/thirdparty/jwt/include/base64.h @@ -51,7 +51,7 @@ extern "C" { * * @return Return code as defined in retcodes.h */ -L8W8JWT_API int l8w8jwt_base64_encode(int url, const uint8_t* data, size_t data_length, char** out, size_t* out_length); +L8W8JWT_API int l8w8jwt_base64_encode(const int url, const uint8_t* data, const size_t data_length, char** out, size_t* out_length); /** * Decodes a base-64 encoded string to an array of bytes. <p> @@ -68,7 +68,7 @@ L8W8JWT_API int l8w8jwt_base64_encode(int url, const uint8_t* data, size_t data_ * * @return Return code as defined in retcodes.h */ -L8W8JWT_API int l8w8jwt_base64_decode(int url, const char* data, size_t data_length, uint8_t** out, size_t* out_length); +L8W8JWT_API int l8w8jwt_base64_decode(const int url, const char* data, const size_t data_length, uint8_t** out, size_t* out_length); #ifdef __cplusplus } // extern "C" diff --git a/r5dev/thirdparty/jwt/include/checknum.h b/r5dev/thirdparty/jwt/include/checknum.h new file mode 100644 index 00000000..c84a32fa --- /dev/null +++ b/r5dev/thirdparty/jwt/include/checknum.h @@ -0,0 +1,141 @@ +/* + Copyright 2020 Raphael Beck + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file checknum.h + * @author Raphael Beck + * @brief Check whether a given string contains an integer or floating point number. + */ + +/* https://github.com/GlitchedPolygons/checknum */ + +#ifndef CHECKNUM_H +#define CHECKNUM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CHECKNUM_STATIC + #define CHECKNUM_API static +#else + #define CHECKNUM_API extern +#endif + +#include <string.h> +#include <stddef.h> +#include <stdbool.h> +#include <inttypes.h> + +/** + * Checks whether a given string contains a valid integer or floating point number. <p> + * If it's an integer, 1 is returned. <P> + * If it's a float or a double, 2 is returned. <p> + * If the string doesn't contain a valid number at all, 0 is returned. + */ +CHECKNUM_API int checknum(char* string, size_t string_length) +{ + if (string == NULL) + return 0; + + if (string_length == 0) + string_length = strlen(string); + + char* c = string; + + while (*c == ' ' && c < string + string_length) + c++; + + while (*(string + string_length - 1) == ' ' && c < string + string_length) + string_length--; + + switch (*c) + { + case '+': + case '-': + if (++c >= string + string_length) + return 0; + default: + break; + } + + unsigned int type = 0; + + if (*c == '0') + { + type |= 1 << 0; + if (*++c != '.' && c < string + string_length) + return 0; + } + + for (; c < string + string_length; c++) + { + switch (*c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + type |= 1 << 0; + continue; + case '-': + if (type & 1 << 1 || (*(c - 1) != 'E' && *(c - 1) != 'e')) + return 0; + type |= 1 << 1; + continue; + case '.': + if (type & 1 << 2 || type & 1 << 3) + return 0; + type |= 1 << 2; + continue; + case 'E': + case 'e': + if (!(type & 1 << 0) || type & 1 << 3 || c + 1 >= string + string_length) + return 0; + type |= 1 << 3; + continue; + case '+': + if (type & 1 << 4 || (*(c - 1) != 'E' && *(c - 1) != 'e')) + return 0; + type |= 1 << 4; + continue; + default: + return 0; + } + } + + switch (type) + { + case 0: + return 0; + case 1 << 0: + return 1; + default: + return type & 1 << 0 ? 2 : 0; + } +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // CHECKNUM_H diff --git a/r5dev/thirdparty/jwt/include/claim.h b/r5dev/thirdparty/jwt/include/claim.h index 0b55acad..b9bf18d2 100644 --- a/r5dev/thirdparty/jwt/include/claim.h +++ b/r5dev/thirdparty/jwt/include/claim.h @@ -117,7 +117,7 @@ struct l8w8jwt_claim * @param claims The claims to free. * @param claims_count The size of the passed claims array. */ -L8W8JWT_API void l8w8jwt_free_claims(struct l8w8jwt_claim* claims, size_t claims_count); +L8W8JWT_API void l8w8jwt_free_claims(struct l8w8jwt_claim* claims, const size_t claims_count); /** * Writes a bunch of JWT claims into a chillbuff stringbuilder. <p> @@ -127,7 +127,7 @@ L8W8JWT_API void l8w8jwt_free_claims(struct l8w8jwt_claim* claims, size_t claims * @param claims_count The claims array size. * @return Return code as specified inside retcodes.h */ -L8W8JWT_API int l8w8jwt_write_claims(struct chillbuff* stringbuilder, struct l8w8jwt_claim* claims, size_t claims_count); +L8W8JWT_API int l8w8jwt_write_claims(struct chillbuff* stringbuilder, struct l8w8jwt_claim* claims, const size_t claims_count); /** * Gets a claim by key from a l8w8jwt_claim array. @@ -137,7 +137,7 @@ L8W8JWT_API int l8w8jwt_write_claims(struct chillbuff* stringbuilder, struct l8w * @param key_length The claim key's string length. * @return The found claim; <code>NULL</code> if no such claim was found in the array. */ -L8W8JWT_API struct l8w8jwt_claim* l8w8jwt_get_claim(struct l8w8jwt_claim* claims, size_t claims_count, const char* key, size_t key_length); +L8W8JWT_API struct l8w8jwt_claim* l8w8jwt_get_claim(struct l8w8jwt_claim* claims, const size_t claims_count, const char* key, const size_t key_length); #ifdef __cplusplus } // extern "C" diff --git a/r5dev/thirdparty/jwt/include/decode.h b/r5dev/thirdparty/jwt/include/decode.h index a8a31cb4..dd9ac563 100644 --- a/r5dev/thirdparty/jwt/include/decode.h +++ b/r5dev/thirdparty/jwt/include/decode.h @@ -34,6 +34,7 @@ extern "C" { #include <time.h> #include <stddef.h> #include <stdint.h> +#include <stdio.h> #ifndef L8W8JWT_MAX_KEY_SIZE #define L8W8JWT_MAX_KEY_SIZE 8192 @@ -94,6 +95,31 @@ enum l8w8jwt_validation_result { L8W8JWT_TYP_FAILURE = (unsigned)1 << (unsigned)8 }; +static void l8w8jwt_get_validation_result_desc(enum l8w8jwt_validation_result res, char* out_buffer, size_t buffer_size) +{ +#define JWT_OUTPUT_MSG(msg) snprintf(out_buffer, buffer_size, "%s", msg) +#define JWT_FLAG_STATUS(flag, msg) if(res & flag) { JWT_OUTPUT_MSG(msg); return; } + + if (res == L8W8JWT_VALID) + { + JWT_OUTPUT_MSG("Success"); + return; + } + + JWT_FLAG_STATUS(L8W8JWT_ISS_FAILURE, "Issuer claim is invalid"); + JWT_FLAG_STATUS(L8W8JWT_SUB_FAILURE, "Subject claim is invalid"); + JWT_FLAG_STATUS(L8W8JWT_AUD_FAILURE, "Audience claim is invalid"); + JWT_FLAG_STATUS(L8W8JWT_JTI_FAILURE, "JWT ID claim is invalid"); + JWT_FLAG_STATUS(L8W8JWT_EXP_FAILURE, "Token has expired"); + JWT_FLAG_STATUS(L8W8JWT_NBF_FAILURE, "Token is not yet valid"); + JWT_FLAG_STATUS(L8W8JWT_IAT_FAILURE, "Token has not been issued yet"); + JWT_FLAG_STATUS(L8W8JWT_SIGNATURE_VERIFICATION_FAILURE, "Token signature is invalid"); + JWT_FLAG_STATUS(L8W8JWT_TYP_FAILURE, "Token type is invalid"); + +#undef JWT_OUTPUT_MSG +#undef JWT_FLAG_STATUS +} + /** * Struct containing the parameters to use for decoding and validating a JWT. */ diff --git a/r5dev/thirdparty/jwt/include/jsmn.h b/r5dev/thirdparty/jwt/include/jsmn.h new file mode 100644 index 00000000..8ac14c1b --- /dev/null +++ b/r5dev/thirdparty/jwt/include/jsmn.h @@ -0,0 +1,471 @@ +/* + * MIT License + * + * Copyright (c) 2010 Serge Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef JSMN_H +#define JSMN_H + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef JSMN_STATIC +#define JSMN_API static +#else +#define JSMN_API extern +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1 << 0, + JSMN_ARRAY = 1 << 1, + JSMN_STRING = 1 << 2, + JSMN_PRIMITIVE = 1 << 3 +} jsmntype_t; + +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; + +/** + * JSON token description. + * type type (object, array, string etc.) + * start start position in JSON data string + * end end position in JSON data string + */ +typedef struct jsmntok { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string. + */ +typedef struct jsmn_parser { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g. parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +JSMN_API void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each + * describing + * a single JSON object. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens); + +#ifndef JSMN_HEADER +/** + * Allocates a fresh unused token from the token pool. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, + const int start, const int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t': + case '\r': + case '\n': + case ' ': + case ',': + case ']': + case '}': + goto found; + default: + /* to quiet a warning from gcc*/ + break; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + const size_t len, jsmntok_t *tokens, + const size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + /* Skip starting quote */ + parser->pos++; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': + case '/': + case '\\': + case 'b': + case 'f': + case 'r': + case 'n': + case 't': + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; + i++) { + /* If it isn't a hex character we have an error */ + if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, + jsmntok_t *tokens, const unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': + case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + return JSMN_ERROR_NOMEM; + } + if (parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; +#ifdef JSMN_STRICT + /* In strict mode an object or array can't become a key */ + if (t->type == JSMN_OBJECT) { + return JSMN_ERROR_INVAL; + } +#endif + t->size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': + case ']': + if (tokens == NULL) { + break; + } + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if (token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) { + return JSMN_ERROR_INVAL; + } + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + case '\t': + case '\r': + case '\n': + case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 't': + case 'f': + case 'n': + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + const jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) { + return r; + } + count++; + if (parser->toksuper != -1 && tokens != NULL) { + tokens[parser->toksuper].size++; + } + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +JSMN_API void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} + +#endif /* JSMN_HEADER */ + +#ifdef __cplusplus +} +#endif + +#endif /* JSMN_H */ diff --git a/r5dev/thirdparty/jwt/include/util.h b/r5dev/thirdparty/jwt/include/util.h index 7bd4d479..ef986795 100644 --- a/r5dev/thirdparty/jwt/include/util.h +++ b/r5dev/thirdparty/jwt/include/util.h @@ -40,7 +40,7 @@ extern "C" { * @param output_length [OPTIONAL] Where to write the output array length into. This is always gonna be <c>hexstr_length / 2</c>, but you can still choose to write it out just to be sure. If you want to omit this: no problem.. just pass <c>NULL</c>! * @return <c>0</c> if conversion succeeded. <c>1</c> if one or more required arguments were <c>NULL</c> or invalid. <c>2</c> if the hexadecimal string is in an invalid format (e.g. not divisible by 2). <c>3</c> if output buffer size was insufficient (needs to be at least <c>(hexstr_length / 2) + 1</c> bytes). */ -L8W8JWT_API int l8w8jwt_hexstr2bin(const char* hexstr, size_t hexstr_length, unsigned char* output, size_t output_size, size_t* output_length); +L8W8JWT_API int l8w8jwt_hexstr2bin(const char* hexstr, const size_t hexstr_length, unsigned char* output, const size_t output_size, size_t* output_length); /** * Compares two strings ignoring UPPER vs. lowercase. diff --git a/r5dev/thirdparty/jwt/version.c b/r5dev/thirdparty/jwt/version.c index 2484b772..62604c3a 100644 --- a/r5dev/thirdparty/jwt/version.c +++ b/r5dev/thirdparty/jwt/version.c @@ -18,6 +18,10 @@ #include <stdlib.h> #include <string.h> +#if defined(_WIN32) +#include <windows.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -29,8 +33,6 @@ void l8w8jwt_free(void* mem) void l8w8jwt_zero(void* buf, size_t len) { - MBEDTLS_INTERNAL_VALIDATE(len == 0 || buf != NULL); - if (len > 0) { #if defined(MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO)