mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
WIP: add JWT library
Currently does not compile, pending integration into SDK.
This commit is contained in:
parent
3b81e9e589
commit
cc3b91a3b6
@ -29,6 +29,7 @@ add_subdirectory( thirdparty/curl )
|
||||
add_subdirectory( thirdparty/sdl )
|
||||
add_subdirectory( thirdparty/imgui )
|
||||
add_subdirectory( thirdparty/spdlog )
|
||||
add_subdirectory( thirdparty/jwt )
|
||||
add_subdirectory( thirdparty/lzham )
|
||||
add_subdirectory( thirdparty/fastlz )
|
||||
|
||||
|
27
r5dev/thirdparty/jwt/CMakeLists.txt
vendored
Normal file
27
r5dev/thirdparty/jwt/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
cmake_minimum_required( VERSION 3.16 )
|
||||
add_module( "lib" "libjwt" "" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
|
||||
start_sources()
|
||||
|
||||
add_sources( SOURCE_GROUP "Source"
|
||||
"base64.c"
|
||||
"claim.c"
|
||||
"decode.c"
|
||||
"encode.c"
|
||||
"util.c"
|
||||
"version.c"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Include"
|
||||
"include/algs.h"
|
||||
"include/base64.h"
|
||||
"include/claim.h"
|
||||
"include/decode.h"
|
||||
"include/encode.h"
|
||||
"include/retcodes.h"
|
||||
"include/util.h"
|
||||
"include/version.h"
|
||||
)
|
||||
|
||||
end_sources()
|
||||
thirdparty_suppress_warnings()
|
315
r5dev/thirdparty/jwt/base64.c
vendored
Normal file
315
r5dev/thirdparty/jwt/base64.c
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The above mentioned README can be found under: http://web.mit.edu/freebsd/head/contrib/wpa/
|
||||
|
||||
Here's a full paste of it (18. January 2020), in case the URL goes numb:
|
||||
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
advertisement clause removed).
|
||||
|
||||
If you are submitting changes to the project, please see CONTRIBUTIONS
|
||||
file for more instructions.
|
||||
|
||||
|
||||
This package may include either wpa_supplicant, hostapd, or both. See
|
||||
README file respective subdirectories (wpa_supplicant/README or
|
||||
hostapd/README) for more details.
|
||||
|
||||
Source code files were moved around in v0.6.x releases and compared to
|
||||
earlier releases, the programs are now built by first going to a
|
||||
subdirectory (wpa_supplicant or hostapd) and creating build
|
||||
configuration (.config) and running 'make' there (for Linux/BSD/cygwin
|
||||
builds).
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This software may be distributed, used, and modified under the terms of
|
||||
BSD license:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name(s) of the above-listed copyright holder(s) nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
http://web.mit.edu/freebsd/head/contrib/wpa/COPYING (at the time of writing, 18. January 2020)
|
||||
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
See the README file for the current license terms.
|
||||
|
||||
This software was previously distributed under BSD/GPL v2 dual license
|
||||
terms that allowed either of those license alternatives to be
|
||||
selected. As of February 11, 2012, the project has chosen to use only
|
||||
the BSD license option for future distribution. As such, the GPL v2
|
||||
license option is no longer used. It should be noted that the BSD
|
||||
license option (the one with advertisement clause removed) is compatible
|
||||
with GPL and as such, does not prevent use of this software in projects
|
||||
that use GPL.
|
||||
|
||||
Some of the files may still include pointers to GPL version 2 license
|
||||
terms. However, such copyright and license notifications are maintained
|
||||
only for attribution purposes and any distribution of this software
|
||||
after February 11, 2012 is no longer under the GPL v2 option.
|
||||
|
||||
*/
|
||||
|
||||
/* https://github.com/gaspardpetit/base64 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "include/base64.h"
|
||||
#include "include/version.h"
|
||||
#include "include/retcodes.h"
|
||||
|
||||
static const uint8_t TABLE[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const uint8_t URL_SAFE_TABLE[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
int l8w8jwt_base64_encode(const int url, const uint8_t* data, const size_t data_length, char** out, size_t* out_length)
|
||||
{
|
||||
if (out == NULL || data == NULL || out_length == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
if (data_length == 0)
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t olen = data_length * 4 / 3 + 4;
|
||||
|
||||
olen += olen / 72;
|
||||
olen++;
|
||||
|
||||
if (olen < data_length)
|
||||
{
|
||||
return L8W8JWT_OVERFLOW;
|
||||
}
|
||||
|
||||
*out = malloc(olen);
|
||||
if (*out == NULL)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
uint8_t* pos = (uint8_t*)(*out);
|
||||
uint8_t* in = (uint8_t*)data;
|
||||
uint8_t* end = (uint8_t*)data + data_length;
|
||||
|
||||
int line_length = 0;
|
||||
const uint8_t* table = url ? URL_SAFE_TABLE : TABLE;
|
||||
|
||||
while (end - in >= 3)
|
||||
{
|
||||
*pos++ = table[in[0] >> 2];
|
||||
*pos++ = table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
|
||||
*pos++ = table[in[2] & 0x3f];
|
||||
|
||||
in += 3;
|
||||
|
||||
line_length += 4;
|
||||
if (line_length >= 72 && !url)
|
||||
{
|
||||
*pos++ = '\n';
|
||||
line_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int sub = 0;
|
||||
if (end - in)
|
||||
{
|
||||
*pos++ = table[in[0] >> 2];
|
||||
|
||||
if (end - in == 1)
|
||||
{
|
||||
*pos++ = table[(in[0] & 0x03) << 4];
|
||||
*pos++ = url ? '\0' : '=';
|
||||
if (url)
|
||||
{
|
||||
sub++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pos++ = table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = table[(in[1] & 0x0f) << 2];
|
||||
}
|
||||
|
||||
*pos++ = url ? '\0' : '=';
|
||||
line_length += 4;
|
||||
if (url)
|
||||
{
|
||||
sub++;
|
||||
}
|
||||
}
|
||||
|
||||
if (line_length && !url)
|
||||
{
|
||||
*pos++ = '\n';
|
||||
}
|
||||
|
||||
*pos = '\0';
|
||||
*out_length = (pos - (uint8_t*)*out) - sub;
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
int l8w8jwt_base64_decode(const int url, const char* data, const size_t data_length, uint8_t** out, size_t* out_length)
|
||||
{
|
||||
if (data == NULL || out == NULL || out_length == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
size_t in_length = data_length;
|
||||
|
||||
if (in_length == 0)
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (*(data + in_length - 1) == '\0')
|
||||
{
|
||||
in_length--;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
size_t count = 0;
|
||||
uint8_t dtable[256];
|
||||
const uint8_t* table = url ? URL_SAFE_TABLE : TABLE;
|
||||
|
||||
memset(dtable, 0x80, 256);
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
dtable[table[i]] = (uint8_t)i;
|
||||
}
|
||||
|
||||
dtable['='] = 0;
|
||||
|
||||
for (i = 0; i < in_length; i++)
|
||||
{
|
||||
if (dtable[(unsigned char)data[i]] != 0x80)
|
||||
count++;
|
||||
}
|
||||
|
||||
int r = (int)(count % 4);
|
||||
|
||||
if (count == 0 || r == 1 || (!url && r > 0)) // Invalid input string (format or padding).
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
|
||||
if (r == 3)
|
||||
r = 1;
|
||||
|
||||
*out = calloc(count / 4 * 3 + 16, sizeof(uint8_t));
|
||||
if (*out == NULL)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
int pad = 0;
|
||||
uint8_t tmp;
|
||||
uint8_t block[4];
|
||||
uint8_t* pos = *out;
|
||||
|
||||
for (i = 0; i < in_length + r; i++)
|
||||
{
|
||||
const unsigned char c = i < in_length ? data[i] : '=';
|
||||
|
||||
tmp = dtable[c];
|
||||
|
||||
if (tmp == 0x80)
|
||||
continue;
|
||||
|
||||
if (c == '=')
|
||||
pad++;
|
||||
|
||||
block[count] = tmp;
|
||||
count++;
|
||||
|
||||
if (count == 4)
|
||||
{
|
||||
*pos++ = (block[0] << 2) | (block[1] >> 4);
|
||||
*pos++ = (block[1] << 4) | (block[2] >> 2);
|
||||
*pos++ = (block[2] << 6) | block[3];
|
||||
count = 0;
|
||||
if (pad)
|
||||
{
|
||||
if (pad == 1)
|
||||
{
|
||||
pos--;
|
||||
}
|
||||
else if (pad == 2)
|
||||
{
|
||||
pos -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
l8w8jwt_free(*out);
|
||||
*out = NULL;
|
||||
return L8W8JWT_INVALID_ARG; // Invalid padding...
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_length = pos - *out;
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* All credits for this base-64 encoding/decoding implementation go to Jouni Malinen.
|
||||
* I take no credit for this (not even the modifications I made to it!) whatsoever.
|
||||
* More information at the top of this file.
|
||||
*/
|
147
r5dev/thirdparty/jwt/claim.c
vendored
Normal file
147
r5dev/thirdparty/jwt/claim.c
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "include/claim.h"
|
||||
#include "include/version.h"
|
||||
#include "include/retcodes.h"
|
||||
#include "include/chillbuff.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <mbedtls/md.h> // SChannel???
|
||||
|
||||
void l8w8jwt_free_claims(struct l8w8jwt_claim* claims, const size_t claims_count)
|
||||
{
|
||||
if (claims != NULL && claims_count > 0)
|
||||
{
|
||||
for (struct l8w8jwt_claim* claim = claims; claim < claims + claims_count; ++claim)
|
||||
{
|
||||
if (claim == NULL)
|
||||
continue;
|
||||
|
||||
l8w8jwt_zero(claim->key, claim->key_length);
|
||||
l8w8jwt_zero(claim->value, claim->value_length);
|
||||
|
||||
l8w8jwt_free(claim->key);
|
||||
l8w8jwt_free(claim->value);
|
||||
}
|
||||
|
||||
l8w8jwt_zero(claims, claims_count * sizeof(struct l8w8jwt_claim));
|
||||
l8w8jwt_free(claims);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void l8w8jwt_escape_claim_string(struct chillbuff* stringbuilder, const char* string, const size_t string_length)
|
||||
{
|
||||
for (size_t i = 0; i < string_length; ++i)
|
||||
{
|
||||
const char c = string[i];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
chillbuff_push_back(stringbuilder, "\\\\", 2);
|
||||
break;
|
||||
case '\"':
|
||||
chillbuff_push_back(stringbuilder, "\\\"", 2);
|
||||
break;
|
||||
default:
|
||||
chillbuff_push_back(stringbuilder, &c, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int l8w8jwt_write_claims(struct chillbuff* stringbuilder, struct l8w8jwt_claim* claims, const size_t claims_count)
|
||||
{
|
||||
if (stringbuilder == NULL || claims == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
if (claims_count == 0)
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
struct chillbuff escape_buffer;
|
||||
if (chillbuff_init(&escape_buffer, 256, sizeof(char), CHILLBUFF_GROW_LINEAR) != 0)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
int first = 1;
|
||||
for (struct l8w8jwt_claim* claim = claims; claim < claims + claims_count; ++claim)
|
||||
{
|
||||
if (claim->key == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
chillbuff_push_back(stringbuilder, ",", 1);
|
||||
}
|
||||
|
||||
const size_t key_length = claim->key_length ? claim->key_length : strlen(claim->key);
|
||||
const size_t value_length = claim->value_length ? claim->value_length : strlen(claim->value);
|
||||
|
||||
chillbuff_clear(&escape_buffer);
|
||||
l8w8jwt_escape_claim_string(&escape_buffer, claim->key, key_length);
|
||||
|
||||
chillbuff_push_back(stringbuilder, "\"", 1);
|
||||
chillbuff_push_back(stringbuilder, escape_buffer.array, escape_buffer.length);
|
||||
chillbuff_push_back(stringbuilder, "\":", 2);
|
||||
|
||||
if (claim->type == L8W8JWT_CLAIM_TYPE_STRING)
|
||||
chillbuff_push_back(stringbuilder, "\"", 1);
|
||||
|
||||
chillbuff_clear(&escape_buffer);
|
||||
l8w8jwt_escape_claim_string(&escape_buffer, claim->value, value_length);
|
||||
|
||||
chillbuff_push_back(stringbuilder, escape_buffer.array,escape_buffer.length);
|
||||
|
||||
if (claim->type == L8W8JWT_CLAIM_TYPE_STRING)
|
||||
chillbuff_push_back(stringbuilder, "\"", 1);
|
||||
|
||||
first = 0;
|
||||
}
|
||||
|
||||
chillbuff_free(&escape_buffer);
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
struct l8w8jwt_claim* l8w8jwt_get_claim(struct l8w8jwt_claim* claims, const size_t claims_count, const char* key, const size_t key_length)
|
||||
{
|
||||
if (claims == NULL || key == NULL || claims_count == 0 || key_length == 0)
|
||||
return NULL;
|
||||
|
||||
for (struct l8w8jwt_claim* claim = claims; claim < claims + claims_count; ++claim)
|
||||
{
|
||||
if (strncmp(claim->key, key, key_length) == 0)
|
||||
return claim;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
769
r5dev/thirdparty/jwt/decode.c
vendored
Normal file
769
r5dev/thirdparty/jwt/decode.c
vendored
Normal file
@ -0,0 +1,769 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JSMN_STATIC
|
||||
|
||||
#include "include/util.h"
|
||||
#include "include/decode.h"
|
||||
#include "include/base64.h"
|
||||
#include "include/chillbuff.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>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
|
||||
#if L8W8JWT_ENABLE_EDDSA
|
||||
#include <ed25519.h>
|
||||
#endif
|
||||
|
||||
static inline void md_info_from_alg(const int alg, mbedtls_md_info_t** md_info, mbedtls_md_type_t* md_type, size_t* md_length)
|
||||
{
|
||||
switch (alg)
|
||||
{
|
||||
case L8W8JWT_ALG_HS256:
|
||||
case L8W8JWT_ALG_RS256:
|
||||
case L8W8JWT_ALG_PS256:
|
||||
case L8W8JWT_ALG_ES256:
|
||||
case L8W8JWT_ALG_ES256K:
|
||||
*md_length = 32;
|
||||
*md_type = MBEDTLS_MD_SHA256;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
break;
|
||||
|
||||
case L8W8JWT_ALG_HS384:
|
||||
case L8W8JWT_ALG_RS384:
|
||||
case L8W8JWT_ALG_PS384:
|
||||
case L8W8JWT_ALG_ES384:
|
||||
*md_length = 48;
|
||||
*md_type = MBEDTLS_MD_SHA384;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||
break;
|
||||
|
||||
case L8W8JWT_ALG_HS512:
|
||||
case L8W8JWT_ALG_RS512:
|
||||
case L8W8JWT_ALG_PS512:
|
||||
case L8W8JWT_ALG_ES512:
|
||||
case L8W8JWT_ALG_ED25519:
|
||||
*md_length = 64;
|
||||
*md_type = MBEDTLS_MD_SHA512;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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->value_length = 0;
|
||||
claim->value = calloc(sizeof(char), value_length + 1);
|
||||
|
||||
if (claim->key == NULL || claim->value == NULL)
|
||||
{
|
||||
free(claim->key);
|
||||
free(claim->value);
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
char* out_key = claim->key;
|
||||
char* out_value = claim->value;
|
||||
|
||||
for (size_t i = 0; i < key_length; ++i)
|
||||
{
|
||||
const char c = key[i];
|
||||
*out_key = c;
|
||||
|
||||
if (c == '\\' && i != key_length - 1)
|
||||
{
|
||||
const char nc = key[i + 1];
|
||||
if (nc == '\"')
|
||||
{
|
||||
*out_key = '\"';
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
++out_key;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < value_length; ++i)
|
||||
{
|
||||
const char c = value[i];
|
||||
*out_value = c;
|
||||
|
||||
if (c == '\\' && i != value_length - 1)
|
||||
{
|
||||
const char nc = value[i + 1];
|
||||
|
||||
switch (nc)
|
||||
{
|
||||
case '\"':
|
||||
*out_value = '\"';
|
||||
break;
|
||||
case '/':
|
||||
*out_value = '/';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
++out_value;
|
||||
}
|
||||
|
||||
claim->key_length = (size_t)(out_key - claim->key);
|
||||
claim->value_length = (size_t)(out_value - claim->value);
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
static int l8w8jwt_parse_claims(chillbuff* buffer, char* json, const size_t json_length)
|
||||
{
|
||||
jsmn_parser parser;
|
||||
jsmn_init(&parser);
|
||||
|
||||
int r = jsmn_parse(&parser, json, json_length, NULL, 0);
|
||||
|
||||
if (r == 0)
|
||||
{
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
else if (r < 0)
|
||||
{
|
||||
return L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
}
|
||||
|
||||
jsmntok_t _tokens[64];
|
||||
jsmntok_t* tokens = r <= (sizeof(_tokens) / sizeof(_tokens[0])) ? _tokens : malloc(r * sizeof(jsmntok_t));
|
||||
|
||||
if (tokens == NULL)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
jsmn_init(&parser);
|
||||
r = jsmn_parse(&parser, json, json_length, tokens, r);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
return L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
}
|
||||
|
||||
if (tokens->type != JSMN_OBJECT)
|
||||
{
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < r; ++i)
|
||||
{
|
||||
struct l8w8jwt_claim claim;
|
||||
|
||||
const jsmntok_t key = tokens[i];
|
||||
const jsmntok_t value = tokens[++i];
|
||||
|
||||
if (i >= r || key.type != JSMN_STRING)
|
||||
{
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (value.type)
|
||||
{
|
||||
case JSMN_UNDEFINED: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_OTHER;
|
||||
break;
|
||||
}
|
||||
case JSMN_OBJECT: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_OBJECT;
|
||||
break;
|
||||
}
|
||||
case JSMN_ARRAY: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_ARRAY;
|
||||
break;
|
||||
}
|
||||
case JSMN_STRING: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_STRING;
|
||||
break;
|
||||
}
|
||||
case JSMN_PRIMITIVE: {
|
||||
const int value_length = value.end - value.start;
|
||||
|
||||
if (value_length <= 5 && (strncmp(json + value.start, "true", 4) == 0 || strncmp(json + value.start, "false", 5) == 0))
|
||||
{
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_BOOLEAN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value_length == 4 && strncmp(json + value.start, "null", 4) == 0)
|
||||
{
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (checknum(json + value.start, value_length))
|
||||
{
|
||||
case 1: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_INTEGER;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
claim.type = L8W8JWT_CLAIM_TYPE_NUMBER;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
int ur = l8w8jwt_unescape_claim(&claim, json + key.start, (size_t)key.end - key.start, json + value.start, (size_t)value.end - value.start);
|
||||
if (ur != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = ur;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
chillbuff_push_back(buffer, &claim, 1);
|
||||
}
|
||||
|
||||
r = L8W8JWT_SUCCESS;
|
||||
exit:
|
||||
if (tokens != _tokens)
|
||||
{
|
||||
l8w8jwt_free(tokens);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void l8w8jwt_decoding_params_init(struct l8w8jwt_decoding_params* params)
|
||||
{
|
||||
if (params == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
memset(params, 0x00, sizeof(struct l8w8jwt_decoding_params));
|
||||
params->alg = -2;
|
||||
}
|
||||
|
||||
int l8w8jwt_validate_decoding_params(struct l8w8jwt_decoding_params* params)
|
||||
{
|
||||
if (params == NULL || params->jwt == NULL || params->verification_key == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
if (params->jwt_length == 0 || params->verification_key_length == 0 || params->verification_key_length > L8W8JWT_MAX_KEY_SIZE)
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
#if !L8W8JWT_ENABLE_EDDSA
|
||||
if (params->alg == L8W8JWT_ALG_ED25519)
|
||||
{
|
||||
return L8W8JWT_UNSUPPORTED_ALG;
|
||||
}
|
||||
#endif
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validation_result* out_validation_result, struct l8w8jwt_claim** out_claims, size_t* out_claims_length)
|
||||
{
|
||||
if (params == NULL || (out_claims != NULL && out_claims_length == NULL))
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
const int alg = params->alg;
|
||||
enum l8w8jwt_validation_result validation_res = L8W8JWT_VALID;
|
||||
|
||||
int r = l8w8jwt_validate_decoding_params(params);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
if (out_validation_result == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
*out_validation_result = ~L8W8JWT_VALID;
|
||||
|
||||
char* header = NULL;
|
||||
size_t header_length = 0;
|
||||
|
||||
char* payload = NULL;
|
||||
size_t payload_length = 0;
|
||||
|
||||
uint8_t* signature = NULL;
|
||||
size_t signature_length = 0;
|
||||
|
||||
char* current = params->jwt;
|
||||
char* next = strchr(params->jwt, '.');
|
||||
|
||||
if (next == NULL) /* No payload. */
|
||||
{
|
||||
return L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
}
|
||||
|
||||
int is_cert = 0; // If the validation PEM is a X.509 certificate, this will be set to 1.
|
||||
|
||||
mbedtls_pk_context pk;
|
||||
mbedtls_pk_init(&pk);
|
||||
|
||||
mbedtls_x509_crt crt;
|
||||
mbedtls_x509_crt_init(&crt);
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_entropy_init(&entropy);
|
||||
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
|
||||
#if L8W8JWT_SMALL_STACK
|
||||
unsigned char* key = calloc(sizeof(unsigned char), L8W8JWT_MAX_KEY_SIZE);
|
||||
if (key == NULL)
|
||||
{
|
||||
r = L8W8JWT_OUT_OF_MEM;
|
||||
goto exit;
|
||||
}
|
||||
#else
|
||||
unsigned char key[L8W8JWT_MAX_KEY_SIZE] = { 0x00 };
|
||||
#endif
|
||||
|
||||
size_t key_length = params->verification_key_length;
|
||||
memcpy(key, params->verification_key, key_length);
|
||||
|
||||
key_length += key[key_length - 1] != '\0';
|
||||
|
||||
chillbuff claims;
|
||||
r = chillbuff_init(&claims, 16, sizeof(struct l8w8jwt_claim), CHILLBUFF_GROW_DUPLICATIVE);
|
||||
if (r != CHILLBUFF_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_OUT_OF_MEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
size_t current_length = next - current;
|
||||
|
||||
r = l8w8jwt_base64_decode(true, current, current_length, (uint8_t**)&header, &header_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
if (r != L8W8JWT_OUT_OF_MEM)
|
||||
r = L8W8JWT_BASE64_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
current = next + 1;
|
||||
next = strchr(current, '.');
|
||||
|
||||
if (next == NULL && alg != -1) /* No signature. */
|
||||
{
|
||||
r = L8W8JWT_DECODE_FAILED_MISSING_SIGNATURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
current_length = (next != NULL ? next : params->jwt + params->jwt_length) - current;
|
||||
|
||||
r = l8w8jwt_base64_decode(true, current, current_length, (uint8_t**)&payload, &payload_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
if (r != L8W8JWT_OUT_OF_MEM)
|
||||
r = L8W8JWT_BASE64_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (next != NULL)
|
||||
{
|
||||
current = next + 1;
|
||||
current_length = (params->jwt + params->jwt_length) - current;
|
||||
|
||||
r = l8w8jwt_base64_decode(true, current, current_length, &signature, &signature_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
if (r != L8W8JWT_OUT_OF_MEM)
|
||||
r = L8W8JWT_BASE64_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Signature verification. */
|
||||
if (signature != NULL && signature_length > 0 && alg != -1)
|
||||
{
|
||||
is_cert = strstr((const char*)key, "-----BEGIN CERTIFICATE-----") != NULL;
|
||||
if (is_cert)
|
||||
{
|
||||
r = mbedtls_x509_crt_parse(&crt, key, key_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pk = crt.pk;
|
||||
}
|
||||
|
||||
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_ES256:
|
||||
case L8W8JWT_ALG_ES384:
|
||||
case L8W8JWT_ALG_ES512:
|
||||
case L8W8JWT_ALG_RS256:
|
||||
case L8W8JWT_ALG_RS384:
|
||||
case L8W8JWT_ALG_RS512:
|
||||
case L8W8JWT_ALG_PS256:
|
||||
case L8W8JWT_ALG_PS384:
|
||||
case L8W8JWT_ALG_PS512:
|
||||
case L8W8JWT_ALG_ES256K: {
|
||||
|
||||
r = mbedtls_md(md_info, (const unsigned char*)params->jwt, (current - 1) - params->jwt, hash);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_SHA2_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (alg)
|
||||
{
|
||||
case L8W8JWT_ALG_HS256:
|
||||
case L8W8JWT_ALG_HS384:
|
||||
case L8W8JWT_ALG_HS512: {
|
||||
|
||||
unsigned char signature_cmp[64];
|
||||
memset(signature_cmp, '\0', sizeof(signature_cmp));
|
||||
|
||||
r = mbedtls_md_hmac(md_info, key, key_length - 1, (const unsigned char*)params->jwt, (current - 1) - params->jwt, signature_cmp);
|
||||
if (r != 0)
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
r = memcmp(signature, signature_cmp, 32 + (16 * alg));
|
||||
if (r != 0)
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_RS256:
|
||||
case L8W8JWT_ALG_RS384:
|
||||
case L8W8JWT_ALG_RS512: {
|
||||
|
||||
if (!is_cert)
|
||||
{
|
||||
r = mbedtls_pk_parse_public_key(&pk, key, key_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
r = mbedtls_pk_verify(&pk, md_type, hash, md_length, (const unsigned char*)signature, signature_length);
|
||||
if (r != 0)
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_PS256:
|
||||
case L8W8JWT_ALG_PS384:
|
||||
case L8W8JWT_ALG_PS512: {
|
||||
|
||||
if (!is_cert)
|
||||
{
|
||||
r = mbedtls_pk_parse_public_key(&pk, key, key_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
mbedtls_rsa_context* rsa = mbedtls_pk_rsa(pk);
|
||||
mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, md_type);
|
||||
|
||||
r = mbedtls_rsa_rsassa_pss_verify(rsa, md_type, md_length, hash, signature);
|
||||
if (r != 0)
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ES256:
|
||||
case L8W8JWT_ALG_ES256K:
|
||||
case L8W8JWT_ALG_ES384:
|
||||
case L8W8JWT_ALG_ES512: {
|
||||
|
||||
if (!is_cert)
|
||||
{
|
||||
r = mbedtls_pk_parse_public_key(&pk, key, key_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t half_signature_length = signature_length / 2;
|
||||
|
||||
mbedtls_ecdsa_context ecdsa;
|
||||
mbedtls_ecdsa_init(&ecdsa);
|
||||
|
||||
mbedtls_mpi sig_r, sig_s;
|
||||
mbedtls_mpi_init(&sig_r);
|
||||
mbedtls_mpi_init(&sig_s);
|
||||
|
||||
r = mbedtls_ecdsa_from_keypair(&ecdsa, mbedtls_pk_ec(pk));
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
mbedtls_mpi_free(&sig_r);
|
||||
mbedtls_mpi_free(&sig_s);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_mpi_read_binary(&sig_r, signature, half_signature_length);
|
||||
mbedtls_mpi_read_binary(&sig_s, signature + half_signature_length, half_signature_length);
|
||||
|
||||
r = mbedtls_ecdsa_verify(&ecdsa.MBEDTLS_PRIVATE(grp), hash, md_length, &ecdsa.MBEDTLS_PRIVATE(Q), &sig_r, &sig_s);
|
||||
if (r != 0)
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
}
|
||||
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
mbedtls_mpi_free(&sig_r);
|
||||
mbedtls_mpi_free(&sig_s);
|
||||
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ED25519: {
|
||||
|
||||
#if L8W8JWT_ENABLE_EDDSA
|
||||
if (key_length != 64 && !(key_length == 65 && key[64] == 0x00))
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
unsigned char public_key[32 + 1] = { 0x00 };
|
||||
|
||||
if (l8w8jwt_hexstr2bin((const char*)key, key_length, public_key, sizeof(public_key), NULL) != 0)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!ed25519_verify(signature, (const unsigned char*)params->jwt, (current - 1) - params->jwt, public_key))
|
||||
{
|
||||
validation_res |= (unsigned)L8W8JWT_SIGNATURE_VERIFICATION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
#else
|
||||
r = L8W8JWT_UNSUPPORTED_ALG;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = l8w8jwt_parse_claims(&claims, header, header_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
r = l8w8jwt_parse_claims(&claims, payload, payload_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (params->validate_sub != NULL)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_aud != NULL)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_iss != NULL)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_jti != NULL)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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);
|
||||
|
||||
if (params->validate_exp)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_nbf)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_iat)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
if (params->validate_typ)
|
||||
{
|
||||
struct l8w8jwt_claim* c = l8w8jwt_get_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;
|
||||
}
|
||||
}
|
||||
|
||||
r = L8W8JWT_SUCCESS;
|
||||
*out_validation_result = validation_res;
|
||||
|
||||
if (out_claims != NULL && out_claims_length != NULL)
|
||||
{
|
||||
*out_claims_length = claims.length;
|
||||
*out_claims = (struct l8w8jwt_claim*)claims.array;
|
||||
}
|
||||
|
||||
exit:
|
||||
l8w8jwt_free(header);
|
||||
l8w8jwt_free(payload);
|
||||
l8w8jwt_free(signature);
|
||||
|
||||
if (out_claims == NULL || r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
l8w8jwt_free_claims((struct l8w8jwt_claim*)claims.array, claims.length);
|
||||
}
|
||||
|
||||
mbedtls_platform_zeroize(key, L8W8JWT_MAX_KEY_SIZE);
|
||||
#if L8W8JWT_SMALL_STACK
|
||||
l8w8jwt_free(key);
|
||||
#endif
|
||||
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
|
||||
if (is_cert)
|
||||
{
|
||||
mbedtls_x509_crt_free(&crt);
|
||||
}
|
||||
else
|
||||
{
|
||||
mbedtls_pk_free(&pk);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#undef JSMN_STATIC
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
685
r5dev/thirdparty/jwt/encode.c
vendored
Normal file
685
r5dev/thirdparty/jwt/encode.c
vendored
Normal file
@ -0,0 +1,685 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "include/util.h"
|
||||
#include "include/encode.h"
|
||||
#include "include/base64.h"
|
||||
#include "include/chillbuff.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/platform_util.h>
|
||||
|
||||
#if L8W8JWT_ENABLE_EDDSA
|
||||
#include <ed25519.h>
|
||||
#endif
|
||||
|
||||
static inline void md_info_from_alg(const int alg, mbedtls_md_info_t** md_info, mbedtls_md_type_t* md_type, size_t* md_length)
|
||||
{
|
||||
switch (alg)
|
||||
{
|
||||
case L8W8JWT_ALG_HS256:
|
||||
case L8W8JWT_ALG_RS256:
|
||||
case L8W8JWT_ALG_PS256:
|
||||
case L8W8JWT_ALG_ES256:
|
||||
case L8W8JWT_ALG_ES256K:
|
||||
*md_length = 32;
|
||||
*md_type = MBEDTLS_MD_SHA256;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
break;
|
||||
|
||||
case L8W8JWT_ALG_HS384:
|
||||
case L8W8JWT_ALG_RS384:
|
||||
case L8W8JWT_ALG_PS384:
|
||||
case L8W8JWT_ALG_ES384:
|
||||
*md_length = 48;
|
||||
*md_type = MBEDTLS_MD_SHA384;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||
break;
|
||||
|
||||
case L8W8JWT_ALG_HS512:
|
||||
case L8W8JWT_ALG_RS512:
|
||||
case L8W8JWT_ALG_PS512:
|
||||
case L8W8JWT_ALG_ES512:
|
||||
*md_length = 64;
|
||||
*md_type = MBEDTLS_MD_SHA512;
|
||||
*md_info = (mbedtls_md_info_t*)mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 1: prepare the token by encoding header + payload claims into a stringbuilder, ready to be signed! */
|
||||
static int write_header_and_payload(chillbuff* stringbuilder, struct l8w8jwt_encoding_params* params)
|
||||
{
|
||||
int r;
|
||||
chillbuff buff;
|
||||
|
||||
r = chillbuff_init(&buff, 256, sizeof(char), CHILLBUFF_GROW_DUPLICATIVE);
|
||||
if (r != CHILLBUFF_SUCCESS)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
switch (params->alg)
|
||||
{
|
||||
case L8W8JWT_ALG_HS256:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"HS256\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_HS384:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"HS384\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_HS512:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"HS512\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_RS256:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"RS256\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_RS384:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"RS384\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_RS512:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"RS512\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_PS256:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"PS256\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_PS384:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"PS384\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_PS512:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"PS512\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_ES256:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"ES256\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_ES384:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"ES384\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_ES512:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"ES512\",\"typ\":\"JWT\"", 26);
|
||||
break;
|
||||
case L8W8JWT_ALG_ES256K:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"ES256K\",\"typ\":\"JWT\",\"kty\":\"EC\",\"crv\":\"secp256k1\"", 56);
|
||||
break;
|
||||
case L8W8JWT_ALG_ED25519:
|
||||
chillbuff_push_back(&buff, "{\"alg\":\"EdDSA\",\"typ\":\"JWT\",\"kty\":\"EC\",\"crv\":\"Ed25519\"", 53);
|
||||
break;
|
||||
default:
|
||||
chillbuff_free(&buff);
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (params->additional_header_claims_count > 0)
|
||||
{
|
||||
chillbuff_push_back(&buff, ",", 1);
|
||||
l8w8jwt_write_claims(&buff, params->additional_header_claims, params->additional_header_claims_count);
|
||||
}
|
||||
|
||||
chillbuff_push_back(&buff, "}", 1);
|
||||
|
||||
char* segment;
|
||||
size_t segment_length;
|
||||
|
||||
r = l8w8jwt_base64_encode(1, buff.array, buff.length, &segment, &segment_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
chillbuff_free(&buff);
|
||||
return r;
|
||||
}
|
||||
|
||||
chillbuff_push_back(stringbuilder, segment, segment_length);
|
||||
|
||||
chillbuff_clear(&buff);
|
||||
|
||||
l8w8jwt_free(segment);
|
||||
segment = NULL;
|
||||
|
||||
char iatnbfexp[64] = { 0x00 };
|
||||
|
||||
if (params->iat)
|
||||
{
|
||||
snprintf(iatnbfexp + 00, 21, "%" PRIu64 "", (uint64_t)params->iat);
|
||||
}
|
||||
|
||||
if (params->nbf)
|
||||
{
|
||||
snprintf(iatnbfexp + 21, 21, "%" PRIu64 "", (uint64_t)params->nbf);
|
||||
}
|
||||
|
||||
if (params->exp)
|
||||
{
|
||||
snprintf(iatnbfexp + 42, 21, "%" PRIu64 "", (uint64_t)params->exp);
|
||||
}
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
chillbuff_push_back(&buff, "{", 1);
|
||||
|
||||
l8w8jwt_write_claims(&buff, claims, sizeof(claims) / sizeof(struct l8w8jwt_claim));
|
||||
|
||||
if (params->additional_payload_claims_count > 0)
|
||||
{
|
||||
if (params->iat || params->exp || params->nbf || params->iss_length || params->sub_length || params->jti_length || params->aud_length)
|
||||
chillbuff_push_back(&buff, ",", 1);
|
||||
|
||||
l8w8jwt_write_claims(&buff, params->additional_payload_claims, params->additional_payload_claims_count);
|
||||
}
|
||||
|
||||
chillbuff_push_back(&buff, "}", 1);
|
||||
|
||||
r = l8w8jwt_base64_encode(1, buff.array, buff.length, &segment, &segment_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
chillbuff_free(&buff);
|
||||
return r;
|
||||
}
|
||||
|
||||
chillbuff_push_back(stringbuilder, ".", 1);
|
||||
chillbuff_push_back(stringbuilder, segment, segment_length);
|
||||
|
||||
l8w8jwt_free(segment);
|
||||
chillbuff_free(&buff);
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Step 2: call write_header_and_payload before you call this! */
|
||||
static int write_signature(chillbuff* stringbuilder, struct l8w8jwt_encoding_params* params)
|
||||
{
|
||||
int r;
|
||||
const int alg = params->alg;
|
||||
|
||||
char* signature = NULL;
|
||||
size_t signature_length = 0, signature_bytes_length = 0, key_length = 0;
|
||||
|
||||
mbedtls_pk_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
mbedtls_pk_init(&pk);
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
|
||||
#if L8W8JWT_SMALL_STACK
|
||||
unsigned char* signature_bytes = calloc(sizeof(unsigned char), 4096);
|
||||
unsigned char* key = calloc(sizeof(unsigned char), L8W8JWT_MAX_KEY_SIZE);
|
||||
|
||||
if (signature_bytes == NULL || key == NULL)
|
||||
{
|
||||
r = L8W8JWT_OUT_OF_MEM;
|
||||
goto exit;
|
||||
}
|
||||
#else
|
||||
unsigned char signature_bytes[4096] = { 0x00 };
|
||||
unsigned char key[L8W8JWT_MAX_KEY_SIZE] = { 0x00 };
|
||||
#endif
|
||||
|
||||
key_length = params->secret_key_length;
|
||||
memcpy(key, params->secret_key, key_length);
|
||||
|
||||
/*
|
||||
* MbedTLS requires the NUL-terminator to be included
|
||||
* in the PEM-formatted key string passed to the key parse function.
|
||||
* HMAC-key variants should subtract 1 from key_length again to compensate.
|
||||
*/
|
||||
key_length += key[key_length - 1] != '\0';
|
||||
|
||||
r = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)"l8w8jwt_mbedtls_pers.!#@", 24);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_MBEDTLS_CTR_DRBG_SEED_FAILURE;
|
||||
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:
|
||||
case L8W8JWT_ALG_HS384:
|
||||
case L8W8JWT_ALG_HS512: {
|
||||
|
||||
/*
|
||||
* "key_length - 1" because the MbedTLS implementation of HMAC
|
||||
* does not require its key string to include the NUL-terminator,
|
||||
* unlike the RSA/ECC PEM key parse function "mbedtls_pk_parse_key",
|
||||
* which MUST include the '\0' in the PEM-formatted key string.
|
||||
*/
|
||||
r = mbedtls_md_hmac(md_info, key, key_length - 1, (const unsigned char*)stringbuilder->array, stringbuilder->length, signature_bytes);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = 32 + (16 * params->alg);
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_RS256:
|
||||
case L8W8JWT_ALG_RS384:
|
||||
case L8W8JWT_ALG_RS512: {
|
||||
|
||||
/* Parse & load the key string into the mbedtls pk instance. */
|
||||
|
||||
r = mbedtls_pk_parse_key(&pk, key, key_length, params->secret_key_pw, params->secret_key_pw_length, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Ensure RSA functionality. */
|
||||
if (!mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) && !mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT))
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Weak RSA keys are forbidden! */
|
||||
if (mbedtls_pk_get_bitlen(&pk) < 2048)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Hash the JWT header + payload. */
|
||||
r = mbedtls_md(md_info, (const unsigned char*)stringbuilder->array, stringbuilder->length, hash);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_SHA2_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Sign the hash using the provided private key. */
|
||||
r = mbedtls_pk_sign(&pk, md_type, hash, md_length, signature_bytes, 4096, &signature_bytes_length, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_PS256:
|
||||
case L8W8JWT_ALG_PS384:
|
||||
case L8W8JWT_ALG_PS512: {
|
||||
|
||||
r = mbedtls_pk_parse_key(&pk, key, key_length, params->secret_key_pw, params->secret_key_pw_length, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSASSA_PSS))
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (mbedtls_pk_get_bitlen(&pk) < 2048)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
r = mbedtls_md(md_info, (const unsigned char*)stringbuilder->array, stringbuilder->length, hash);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_SHA2_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_rsa_context* rsa = mbedtls_pk_rsa(pk);
|
||||
mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, md_type);
|
||||
|
||||
r = mbedtls_rsa_rsassa_pss_sign(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, md_type, (unsigned int)md_length, hash, signature_bytes);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = mbedtls_pk_get_bitlen(&pk) / 8;
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ES256:
|
||||
case L8W8JWT_ALG_ES384:
|
||||
case L8W8JWT_ALG_ES512:
|
||||
case L8W8JWT_ALG_ES256K: {
|
||||
|
||||
mbedtls_ecdsa_context ecdsa;
|
||||
mbedtls_ecdsa_init(&ecdsa);
|
||||
|
||||
mbedtls_mpi sig_r, sig_s;
|
||||
mbedtls_mpi_init(&sig_r);
|
||||
mbedtls_mpi_init(&sig_s);
|
||||
|
||||
r = mbedtls_pk_parse_key(&pk, key, key_length, params->secret_key_pw, params->secret_key_pw_length, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
if (!mbedtls_pk_can_do(&pk, MBEDTLS_PK_ECDSA))
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = mbedtls_ecdsa_from_keypair(&ecdsa, mbedtls_pk_ec(pk));
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_KEY_PARSE_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = mbedtls_md(md_info, (const unsigned char*)stringbuilder->array, stringbuilder->length, hash);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_SHA2_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
switch (alg)
|
||||
{
|
||||
case L8W8JWT_ALG_ES256: {
|
||||
|
||||
if (ecdsa.MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_SECP256R1)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = 64;
|
||||
r = mbedtls_pk_get_bitlen(&pk) == 256;
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ES256K: {
|
||||
|
||||
if (ecdsa.MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_SECP256K1)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = 64;
|
||||
r = mbedtls_pk_get_bitlen(&pk) == 256;
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ES384: {
|
||||
|
||||
if (ecdsa.MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_SECP384R1)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = 96;
|
||||
r = mbedtls_pk_get_bitlen(&pk) == 384;
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ES512: {
|
||||
|
||||
if (ecdsa.MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_SECP521R1)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
signature_bytes_length = 132;
|
||||
r = mbedtls_pk_get_bitlen(&pk) == 521;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the passed elliptic-curve cryptography key
|
||||
* has a size that is valid and compatible with the selected JWT alg.
|
||||
*/
|
||||
if (r == 0)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &sig_r, &sig_s, &ecdsa.MBEDTLS_PRIVATE(d), hash, md_length, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
const size_t half_signature_bytes_length = signature_bytes_length / 2;
|
||||
|
||||
r = mbedtls_mpi_write_binary(&sig_r, signature_bytes, half_signature_bytes_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = mbedtls_mpi_write_binary(&sig_s, signature_bytes + half_signature_bytes_length, half_signature_bytes_length);
|
||||
if (r != 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto ecdsa_exit;
|
||||
}
|
||||
|
||||
r = L8W8JWT_SUCCESS;
|
||||
|
||||
ecdsa_exit:
|
||||
mbedtls_mpi_free(&sig_r);
|
||||
mbedtls_mpi_free(&sig_s);
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L8W8JWT_ALG_ED25519: {
|
||||
|
||||
#if L8W8JWT_ENABLE_EDDSA
|
||||
if (params->secret_key_length != 128 && !(params->secret_key_length == 129 && params->secret_key[128] == 0x00))
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
unsigned char private_key_ref10[64 + 1] = { 0x00 };
|
||||
|
||||
if (l8w8jwt_hexstr2bin((const char*)params->secret_key, params->secret_key_length, private_key_ref10, sizeof(private_key_ref10), NULL) != 0)
|
||||
{
|
||||
r = L8W8JWT_WRONG_KEY_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ed25519_sign_ref10(signature_bytes, (const unsigned char*)stringbuilder->array, stringbuilder->length, private_key_ref10);
|
||||
signature_bytes_length = 64;
|
||||
|
||||
l8w8jwt_zero(private_key_ref10, sizeof(private_key_ref10));
|
||||
break;
|
||||
#else
|
||||
r = L8W8JWT_UNSUPPORTED_ALG;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
default: {
|
||||
r = L8W8JWT_INVALID_ARG;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (signature_bytes_length == 0)
|
||||
{
|
||||
r = L8W8JWT_SIGNATURE_CREATION_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this succeeds, it mallocs "signature" and assigns the resulting string length to "signature_length".
|
||||
*/
|
||||
r = l8w8jwt_base64_encode(1, (uint8_t*)signature_bytes, signature_bytes_length, &signature, &signature_length);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
r = L8W8JWT_BASE64_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
chillbuff_push_back(stringbuilder, ".", 1);
|
||||
chillbuff_push_back(stringbuilder, signature, signature_length);
|
||||
|
||||
exit:
|
||||
l8w8jwt_zero(key, L8W8JWT_MAX_KEY_SIZE);
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
mbedtls_pk_free(&pk);
|
||||
l8w8jwt_free(signature);
|
||||
#if L8W8JWT_SMALL_STACK
|
||||
l8w8jwt_free(key);
|
||||
l8w8jwt_free(signature_bytes);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (*(params->out) == NULL)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
*(params->out_length) = stringbuilder->length;
|
||||
(*(params->out))[stringbuilder->length] = '\0';
|
||||
memcpy(*(params->out), stringbuilder->array, stringbuilder->length);
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
void l8w8jwt_encoding_params_init(struct l8w8jwt_encoding_params* params)
|
||||
{
|
||||
if (params == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
memset(params, 0x00, sizeof(struct l8w8jwt_encoding_params));
|
||||
params->alg = -2;
|
||||
}
|
||||
|
||||
int l8w8jwt_validate_encoding_params(struct l8w8jwt_encoding_params* params)
|
||||
{
|
||||
if (params == NULL || params->secret_key == NULL || params->out == NULL || params->out_length == NULL)
|
||||
{
|
||||
return L8W8JWT_NULL_ARG;
|
||||
}
|
||||
|
||||
if (params->secret_key_length == 0 || params->secret_key_length > L8W8JWT_MAX_KEY_SIZE)
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
if ((params->additional_payload_claims != NULL && params->additional_payload_claims_count == 0))
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
if ((params->additional_header_claims != NULL && params->additional_header_claims_count == 0))
|
||||
{
|
||||
return L8W8JWT_INVALID_ARG;
|
||||
}
|
||||
|
||||
return L8W8JWT_SUCCESS;
|
||||
}
|
||||
|
||||
int l8w8jwt_encode(struct l8w8jwt_encoding_params* params)
|
||||
{
|
||||
int r;
|
||||
chillbuff stringbuilder;
|
||||
|
||||
r = l8w8jwt_validate_encoding_params(params);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
r = chillbuff_init(&stringbuilder, 1024, sizeof(char), CHILLBUFF_GROW_DUPLICATIVE);
|
||||
if (r != CHILLBUFF_SUCCESS)
|
||||
{
|
||||
return L8W8JWT_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
r = write_header_and_payload(&stringbuilder, params);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (params->alg != -1)
|
||||
{
|
||||
r = write_signature(&stringbuilder, params);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
r = write_token(&stringbuilder, params);
|
||||
if (r != L8W8JWT_SUCCESS)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
chillbuff_free(&stringbuilder);
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
111
r5dev/thirdparty/jwt/include/algs.h
vendored
Normal file
111
r5dev/thirdparty/jwt/include/algs.h
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 algs.h
|
||||
* @author Raphael Beck
|
||||
* @brief JWT algorithms as defined in https://tools.ietf.org/html/rfc7518#section-3.1
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_ALGS_H
|
||||
#define L8W8JWT_ALGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* HMAC-SHA256 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_HS256 0
|
||||
|
||||
/**
|
||||
* HMAC-SHA384 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_HS384 1
|
||||
|
||||
/**
|
||||
* HMAC-SHA512 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_HS512 2
|
||||
|
||||
/**
|
||||
* RSASSA-PKCS1-v1_5-SHA256 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_RS256 3
|
||||
|
||||
/**
|
||||
* RSASSA-PKCS1-v1_5-SHA384 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_RS384 4
|
||||
|
||||
/**
|
||||
* RSASSA-PKCS1-v1_5-SHA512 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_RS512 5
|
||||
|
||||
/**
|
||||
* RSASSA-PSS MGF1 SHA-256 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_PS256 6
|
||||
|
||||
/**
|
||||
* RSASSA-PSS MGF1 SHA-384 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_PS384 7
|
||||
|
||||
/**
|
||||
* RSASSA-PSS MGF1 SHA-512 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_PS512 8
|
||||
|
||||
/**
|
||||
* ECDSA + P-256 + SHA256 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_ES256 9
|
||||
|
||||
/**
|
||||
* ECDSA + P-384 + SHA384 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_ES384 10
|
||||
|
||||
/**
|
||||
* ECDSA + P-521 + SHA512 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_ES512 11
|
||||
|
||||
/**
|
||||
* ECDSA over secp256k1 + SHA256 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_ES256K 12
|
||||
|
||||
/**
|
||||
* EdDSA over ed25519 + SHA512 signing algorithm.
|
||||
*/
|
||||
#define L8W8JWT_ALG_ED25519 13
|
||||
|
||||
#ifndef L8W8JWT_ENABLE_EDDSA
|
||||
/**
|
||||
* Set this to \c 1 if you want to enable the EdDSA signing algorithm
|
||||
*/
|
||||
#define L8W8JWT_ENABLE_EDDSA 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_ALGS_H
|
77
r5dev/thirdparty/jwt/include/base64.h
vendored
Normal file
77
r5dev/thirdparty/jwt/include/base64.h
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
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 base64.h
|
||||
* @author Raphael Beck
|
||||
* @brief Base-64 encode and decode strings/bytes. <p>
|
||||
* @warning The caller is responsible for freeing the returned buffers! <p>
|
||||
* Pass <code>true</code> as first parameter if you want to use base64url encoding instead of base64.
|
||||
* @see https://en.wikipedia.org/wiki/Base64#URL_applications
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_BASE64_H
|
||||
#define L8W8JWT_BASE64_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "version.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Encodes a byte array to a base-64 string. <p>
|
||||
* If you're encoding a string, don't include the NUL terminator
|
||||
* (pass <code>strlen(data)</code> instead of the array's size to the <code>data_length</code> parameter). <p>
|
||||
*
|
||||
* @note The output buffer is NUL-terminated to make it easier to use as a C string.
|
||||
* @note The NUL terminator is NOT included in the <code>out_length</code>.
|
||||
* @note DO NOT FORGET to free the output buffer once you're done using it!
|
||||
*
|
||||
* @param url base64url encode instead of base64? Set to \c 0 for \c false; anything else for \c true.
|
||||
* @param data The data (array of bytes) to base-64 encode.
|
||||
* @param data_length The length of the input data array (in case of a C string: array size - 1 in order to omit the NUL terminator).
|
||||
* @param out Output where the base-64 encoded string should be written into (will be malloc'ed, so make sure to <code>free()</code> this as soon as you're done using it!).
|
||||
* @param out_length Pointer to a <code>size_t</code> variable containing the length of the output buffer minus the NUL terminator.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Decodes a base-64 encoded string to an array of bytes. <p>
|
||||
*
|
||||
* @note The returned bytes buffer is NUL-terminated to allow usage as a C string.
|
||||
* @note The NUL terminator is NOT included in the <code>out_length</code>.
|
||||
* @note DO NOT FORGET to free the output buffer once you're done using it!
|
||||
*
|
||||
* @param url Decode using base64url instead of base64? Set to \c 0 for \c false; anything else for \c true.
|
||||
* @param data The base-64 encoded string to decode (obtained via {@link #l8w8jwt_base64_encode}).
|
||||
* @param data_length The length of the string to decode.
|
||||
* @param out Output where the decoded bytes should be written into (will be malloc'ed, so make sure to <code>free()</code> this as soon as you're done using it!).
|
||||
* @param out_length Pointer to a <code>size_t</code> variable into which to write the output buffer's length.
|
||||
*
|
||||
* @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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_BASE64_H
|
326
r5dev/thirdparty/jwt/include/chillbuff.h
vendored
Normal file
326
r5dev/thirdparty/jwt/include/chillbuff.h
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
Copyright 2019 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 chillbuff.h
|
||||
* @author Raphael Beck
|
||||
* @date 27. December 2019
|
||||
* @brief Array. Dynamic size. Push back 'n' chill. Buffer stuff. Dynamic stuff that's buff. Dynamically reallocating buff.. Yeah!
|
||||
* @see https://github.com/GlitchedPolygons/chillbuff
|
||||
*/
|
||||
|
||||
#ifndef CHILLBUFF_H
|
||||
#define CHILLBUFF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* The following are the chillbuff exit codes returned from the various chillbuff functions. */
|
||||
|
||||
/**
|
||||
* Returned from a chillbuff function when everything went smooth 'n' chill. Time to get Schwifty!
|
||||
*/
|
||||
#define CHILLBUFF_SUCCESS 0
|
||||
|
||||
/**
|
||||
* Chill time is over, you're out of memory... Time to reconsider memory usage.
|
||||
*/
|
||||
#define CHILLBUFF_OUT_OF_MEM 100
|
||||
|
||||
/**
|
||||
* Error code returned by a chillbuff function if you passed a NULL argument that shouldn't have been NULL.
|
||||
*/
|
||||
#define CHILLBUFF_NULL_ARG 200
|
||||
|
||||
/**
|
||||
* This error code is returned by a chillbuff function if you passed an invalid parameter into it.
|
||||
*/
|
||||
#define CHILLBUFF_INVALID_ARG 300
|
||||
|
||||
/**
|
||||
* Not good...
|
||||
*/
|
||||
#define CHILLBUFF_OVERFLOW 400
|
||||
|
||||
/** @private */
|
||||
static void (*_chillbuff_error_callback)(const char*) = NULL;
|
||||
|
||||
/**
|
||||
* How should the chillbuff's underlying array grow in size
|
||||
* once its maximum capacity is reached during a push_back?
|
||||
*/
|
||||
typedef enum chillbuff_growth_method
|
||||
{
|
||||
/**
|
||||
* Double the capacity.
|
||||
*/
|
||||
CHILLBUFF_GROW_DUPLICATIVE = 0,
|
||||
|
||||
/**
|
||||
* Triple the capacity.
|
||||
*/
|
||||
CHILLBUFF_GROW_TRIPLICATIVE = 1,
|
||||
|
||||
/**
|
||||
* Grow by the same capacity every time the buffer is full.
|
||||
*/
|
||||
CHILLBUFF_GROW_LINEAR = 2,
|
||||
|
||||
/**
|
||||
* Multiplies the capacity by itself. Not the greatest idea... Use carefully!
|
||||
*/
|
||||
CHILLBUFF_GROW_EXPONENTIAL = 3
|
||||
} chillbuff_growth_method;
|
||||
|
||||
/**
|
||||
* Self-reallocating dynamic size array of no strictly defined type.
|
||||
* Easy 'n' "chill" (hope you like segmentation fault errors).
|
||||
*/
|
||||
typedef struct chillbuff
|
||||
{
|
||||
/**
|
||||
* The buffer's underlying array that stores the data.
|
||||
*/
|
||||
void* array;
|
||||
|
||||
/**
|
||||
* The current amount of elements stored in the chillbuff. DO NOT touch this yourself, only read!
|
||||
*/
|
||||
size_t length;
|
||||
|
||||
/**
|
||||
* The current buffer capacity. This grows dynamically according to the specified {@link #chillbuff_growth_method}.
|
||||
*/
|
||||
size_t capacity;
|
||||
|
||||
/**
|
||||
* The size of each stored element. DO NOT CHANGE THIS! Only read (if necessary)...
|
||||
*/
|
||||
size_t element_size;
|
||||
|
||||
/**
|
||||
* The way the buffer's capacity is increased when it's full.
|
||||
*/
|
||||
chillbuff_growth_method growth_method;
|
||||
} chillbuff;
|
||||
|
||||
/** @private */
|
||||
static inline void _chillbuff_printerr(const char* error, const char* origin)
|
||||
{
|
||||
const size_t error_length = 64 + strlen(error) + strlen(origin);
|
||||
char* error_msg = (char*)malloc(error_length * sizeof(char)); // cast malloc because of compat with C++ D:
|
||||
if (error_msg != NULL)
|
||||
{
|
||||
snprintf(error_msg, error_length, "\nCHILLBUFF ERROR: (%s) %s\n", origin, error);
|
||||
if (_chillbuff_error_callback != NULL)
|
||||
{
|
||||
_chillbuff_error_callback(error_msg);
|
||||
}
|
||||
free(error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chillbuff error callback. <p>
|
||||
* If errors occur, they'll be passed as a string into the provided callback function.
|
||||
* @param error_callback The function to call when errors occur.
|
||||
* @return Whether the callback was set up correctly or not (chillbuff exit code, see top of chillbuff.h file for more details).
|
||||
*/
|
||||
static inline int chillbuff_set_error_callback(void (*error_callback)(const char*))
|
||||
{
|
||||
if (error_callback == NULL)
|
||||
{
|
||||
_chillbuff_printerr("The passed error callback is empty; Operation cancelled!", __func__);
|
||||
return CHILLBUFF_NULL_ARG;
|
||||
}
|
||||
|
||||
_chillbuff_error_callback = error_callback;
|
||||
return CHILLBUFF_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the chillbuff error callback (errors won't be printed anymore).
|
||||
*/
|
||||
static inline void chillbuff_unset_error_callback()
|
||||
{
|
||||
_chillbuff_error_callback = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a chillbuff instance and makes it ready to accept data.
|
||||
* @param buff The chillbuff instance to init (or rather, a pointer to it).
|
||||
* @param initial_capacity The initial capacity of the underlying array. If you pass <code>0</code> here, <code>16</code> is used by default.
|
||||
* @param element_size How big should every array element be? E.g. if you're storing <code>int</code> you should pass <code>sizeof(int)</code>.
|
||||
* @param growth_method How should the buffer grow once its maximum capacity is reached? @see chillbuff_growth_method
|
||||
* @return Chillbuff exit code as defined at the top of the chillbuff.h header file. <code>0</code> means success.
|
||||
*/
|
||||
static inline int chillbuff_init(chillbuff* buff, const size_t initial_capacity, const size_t element_size, const chillbuff_growth_method growth_method)
|
||||
{
|
||||
if (buff == NULL)
|
||||
{
|
||||
_chillbuff_printerr("Tried to init a NULL chillbuff instance; wouldn't end well. Cancelled...", __func__);
|
||||
return CHILLBUFF_NULL_ARG;
|
||||
}
|
||||
|
||||
if (element_size == 0)
|
||||
{
|
||||
_chillbuff_printerr("Storing elements of size \"0\" makes no sense...", __func__);
|
||||
return CHILLBUFF_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (growth_method < 0 || growth_method > 3)
|
||||
{
|
||||
_chillbuff_printerr("Invalid grow method! Please use the appropriate chillbuff_growth_method enum!", __func__);
|
||||
return CHILLBUFF_INVALID_ARG;
|
||||
}
|
||||
|
||||
buff->length = 0;
|
||||
buff->element_size = element_size;
|
||||
buff->growth_method = growth_method;
|
||||
buff->capacity = initial_capacity == 0 ? 16 : initial_capacity;
|
||||
buff->array = calloc(buff->capacity, buff->element_size);
|
||||
|
||||
if (buff->array == NULL)
|
||||
{
|
||||
_chillbuff_printerr("OUT OF MEMORY!", __func__);
|
||||
return CHILLBUFF_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
return CHILLBUFF_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a chillbuff instance.
|
||||
* @param buff The chillbuff to deallocate. If this is <code>NULL</code>, nothing happens at all.
|
||||
*/
|
||||
static inline void chillbuff_free(chillbuff* buff)
|
||||
{
|
||||
if (buff == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buff->array, '\0', buff->length);
|
||||
free(buff->array);
|
||||
buff->array = NULL;
|
||||
buff->length = buff->capacity = buff->element_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a chillbuff's data. <p>
|
||||
* Deletes all of the underlying array's elements and resets the length to <code>0</code>. <p>
|
||||
* Leaves the array allocated at the current capacity.
|
||||
* @param buff The chillbuff to clear. If this is <code>NULL</code>, nothing happens at all.
|
||||
*/
|
||||
static inline void chillbuff_clear(chillbuff* buff)
|
||||
{
|
||||
if (buff == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buff->array, '\0', buff->capacity);
|
||||
buff->length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends one or more elements to the buffer.
|
||||
* If the buffer is full, it will be expanded automatically.
|
||||
* @param buff The buffer into which to insert the elements.
|
||||
* @param elements The array of elements to insert (pointer to the first element).
|
||||
* @param elements_count Amount of elements to add (for example: if your buffer stores the type <code>uint32_t</code>, you'd pass <code>sizeof(elements_to_add) / sizeof(uint32_t)</code> here). If you're only adding a single element, pass <code>1</code>.
|
||||
* @return Chillbuff exit code that describes the insertion's outcome.
|
||||
*/
|
||||
static int chillbuff_push_back(chillbuff* buff, const void* elements, const size_t elements_count)
|
||||
{
|
||||
if (buff == NULL)
|
||||
{
|
||||
_chillbuff_printerr("Tried to append to a NULL chillbuff instance!", __func__);
|
||||
return CHILLBUFF_NULL_ARG;
|
||||
}
|
||||
|
||||
if (elements == NULL)
|
||||
{
|
||||
_chillbuff_printerr("Tried to append NULL element(s) to a chillbuff instance!", __func__);
|
||||
return CHILLBUFF_NULL_ARG;
|
||||
}
|
||||
|
||||
if (elements_count == 0)
|
||||
{
|
||||
_chillbuff_printerr("The passed \"elements_count\" argument is zero; nothing to append!", __func__);
|
||||
return CHILLBUFF_INVALID_ARG;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < elements_count; i++)
|
||||
{
|
||||
if (buff->length == buff->capacity)
|
||||
{
|
||||
size_t new_capacity;
|
||||
|
||||
switch (buff->growth_method)
|
||||
{
|
||||
default:
|
||||
_chillbuff_printerr("Invalid grow method! Please use the appropriate chillbuff_growth_method enum!", __func__);
|
||||
return CHILLBUFF_INVALID_ARG;
|
||||
case CHILLBUFF_GROW_DUPLICATIVE:
|
||||
new_capacity = (buff->capacity * 2);
|
||||
break;
|
||||
case CHILLBUFF_GROW_TRIPLICATIVE:
|
||||
new_capacity = (buff->capacity * 3);
|
||||
break;
|
||||
case CHILLBUFF_GROW_LINEAR:
|
||||
new_capacity = (buff->capacity + buff->element_size);
|
||||
break;
|
||||
case CHILLBUFF_GROW_EXPONENTIAL:
|
||||
new_capacity = (buff->capacity * buff->capacity);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_capacity <= buff->capacity || new_capacity >= UINT64_MAX / buff->element_size)
|
||||
{
|
||||
_chillbuff_printerr("Couldn't push back due to buffer OVERFLOW!", __func__);
|
||||
return CHILLBUFF_OVERFLOW;
|
||||
}
|
||||
|
||||
void* new_array = realloc(buff->array, new_capacity * buff->element_size);
|
||||
if (new_array == NULL)
|
||||
{
|
||||
_chillbuff_printerr("Couldn't resize chillbuff underlying array; OUT OF MEMORY!", __func__);
|
||||
return CHILLBUFF_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
memset((char*)new_array + (buff->element_size * buff->length), '\0', (new_capacity - buff->length) * buff->element_size);
|
||||
buff->array = new_array;
|
||||
buff->capacity = new_capacity;
|
||||
}
|
||||
|
||||
memcpy((char*)buff->array + (buff->element_size * buff->length++), (char*)elements + (i * buff->element_size), buff->element_size);
|
||||
}
|
||||
|
||||
return CHILLBUFF_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // CHILLBUFF_H
|
146
r5dev/thirdparty/jwt/include/claim.h
vendored
Normal file
146
r5dev/thirdparty/jwt/include/claim.h
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
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 claim.h
|
||||
* @author Raphael Beck
|
||||
* @brief JWT claims as described in https://auth0.com/docs/tokens/concepts/jwt-claims
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_CLAIM_H
|
||||
#define L8W8JWT_CLAIM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "version.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// Forward declare chillbuff
|
||||
/** @private */
|
||||
struct chillbuff;
|
||||
|
||||
/**
|
||||
* JWT claim value is a string (e.g. <code>"iss": "glitchedpolygons.com"</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_STRING 0
|
||||
|
||||
/**
|
||||
* JWT claim value is an integer (e.g. <code>"exp": 1579610629</code>)
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_INTEGER 1
|
||||
|
||||
/**
|
||||
* JWT claim value type number (e.g. <code>"size": 1.85</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_NUMBER 2
|
||||
|
||||
/**
|
||||
* JWT claim value is a boolean (e.g. <code>"done": true</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_BOOLEAN 3
|
||||
|
||||
/**
|
||||
* JWT claim value is null (e.g. <code>"ref": null</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_NULL 4
|
||||
|
||||
/**
|
||||
* JWT claim value type JSON array (e.g. <code>"ids": [2, 4, 8, 16]</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_ARRAY 5
|
||||
|
||||
/**
|
||||
* JWT claim value type is a JSON object (e.g. <code>"objs": { "name": "GMan", "id": 420 }</code>).
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_OBJECT 6
|
||||
|
||||
/**
|
||||
* JWT claim value is some other type.
|
||||
*/
|
||||
#define L8W8JWT_CLAIM_TYPE_OTHER 7
|
||||
|
||||
/**
|
||||
* Struct containing a jwt claim key-value pair.<p>
|
||||
* If allocated on the heap by the decode function,
|
||||
* remember to call <code>l8w8jwt_claims_free()</code> on it once you're done using it.
|
||||
*/
|
||||
struct l8w8jwt_claim
|
||||
{
|
||||
/**
|
||||
* The token claim key (e.g. "iss", "iat", "sub", etc...). <p>
|
||||
* NUL-terminated C-string!
|
||||
*/
|
||||
char* key;
|
||||
|
||||
/**
|
||||
* key string length. <p>
|
||||
* Set this to <code>0</code> if you want to make the encoder use <code>strlen(key)</code> instead.
|
||||
*/
|
||||
size_t key_length;
|
||||
|
||||
/**
|
||||
* The claim's value as a NUL-terminated C-string.
|
||||
*/
|
||||
char* value;
|
||||
|
||||
/**
|
||||
* value string length. <p>
|
||||
* Set this to <code>0</code> if you want to make the encoder use <code>strlen(value)</code> instead.
|
||||
*/
|
||||
size_t value_length;
|
||||
|
||||
/**
|
||||
* The type of the claim's value. <p>
|
||||
* 0 = string, 1 = integer, 2 = number, 3 = boolean, 4 = null, 5 = array, 6 = object, 7 = other.
|
||||
* @see https://www.w3schools.com/js/js_json_datatypes.asp
|
||||
*/
|
||||
int type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Frees a heap-allocated <code>l8w8jwt_claim</code> array.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Writes a bunch of JWT claims into a chillbuff stringbuilder. <p>
|
||||
* Curly braces and trailing commas won't be written; only the "key":"value" pairs!
|
||||
* @param stringbuilder The buffer into which to write the claims.
|
||||
* @param claims The l8w8jwt_claim array of claims to write.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Gets a claim by key from a l8w8jwt_claim array.
|
||||
* @param claims The array to look in.
|
||||
* @param claims_count The claims array size.
|
||||
* @param key The claim key (e.g. "sub") to look for.
|
||||
* @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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_CLAIM_H
|
274
r5dev/thirdparty/jwt/include/decode.h
vendored
Normal file
274
r5dev/thirdparty/jwt/include/decode.h
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
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 decode.h
|
||||
* @author Raphael Beck
|
||||
* @brief Core DECODE function for l8w8jwt. Use this to decode and validate a JWT!
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_DECODE_H
|
||||
#define L8W8JWT_DECODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "algs.h"
|
||||
#include "claim.h"
|
||||
#include "version.h"
|
||||
#include "retcodes.h"
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef L8W8JWT_MAX_KEY_SIZE
|
||||
#define L8W8JWT_MAX_KEY_SIZE 8192
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Enum containing the validation result flags.
|
||||
*/
|
||||
enum l8w8jwt_validation_result {
|
||||
/**
|
||||
* The JWT is valid (according to the passed validation parameters).
|
||||
*/
|
||||
L8W8JWT_VALID = (unsigned)0,
|
||||
|
||||
/**
|
||||
* The issuer claim is invalid.
|
||||
*/
|
||||
L8W8JWT_ISS_FAILURE = (unsigned)1 << (unsigned)0,
|
||||
|
||||
/**
|
||||
* The subject claim is invalid.
|
||||
*/
|
||||
L8W8JWT_SUB_FAILURE = (unsigned)1 << (unsigned)1,
|
||||
|
||||
/**
|
||||
* The audience claim is invalid.
|
||||
*/
|
||||
L8W8JWT_AUD_FAILURE = (unsigned)1 << (unsigned)2,
|
||||
|
||||
/**
|
||||
* The JWT ID claim is invalid.
|
||||
*/
|
||||
L8W8JWT_JTI_FAILURE = (unsigned)1 << (unsigned)3,
|
||||
|
||||
/**
|
||||
* The token is expired.
|
||||
*/
|
||||
L8W8JWT_EXP_FAILURE = (unsigned)1 << (unsigned)4,
|
||||
|
||||
/**
|
||||
* The token is not yet valid.
|
||||
*/
|
||||
L8W8JWT_NBF_FAILURE = (unsigned)1 << (unsigned)5,
|
||||
|
||||
/**
|
||||
* The token was not issued yet, are you from the future?
|
||||
*/
|
||||
L8W8JWT_IAT_FAILURE = (unsigned)1 << (unsigned)6,
|
||||
|
||||
/**
|
||||
* The token was potentially tampered with: its signature couldn't be verified.
|
||||
*/
|
||||
L8W8JWT_SIGNATURE_VERIFICATION_FAILURE = (unsigned)1 << (unsigned)7,
|
||||
|
||||
/**
|
||||
* The token's "typ" claim validation failed.
|
||||
*/
|
||||
L8W8JWT_TYP_FAILURE = (unsigned)1 << (unsigned)8
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct containing the parameters to use for decoding and validating a JWT.
|
||||
*/
|
||||
struct l8w8jwt_decoding_params
|
||||
{
|
||||
/**
|
||||
* The token to decode and validate.
|
||||
*/
|
||||
char* jwt;
|
||||
|
||||
/**
|
||||
* The jwt string length.
|
||||
*/
|
||||
size_t jwt_length;
|
||||
|
||||
/**
|
||||
* The signature algorithm ID. <p>
|
||||
* [0;2] = HS256/384/512 | [3;5] = RS256/384/512 | [6;8] = PS256/384/512 | [9;11] = ES256/384/512 <p>
|
||||
* This affects what should be the value of {@link #verification_key}
|
||||
*/
|
||||
int alg;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The issuer claim (who issued the JWT?). <p>
|
||||
* Set to <code>NULL</code> if you don't want to validate the issuer. <p>
|
||||
* The JWT will only pass verification if its <code>iss</code> claim matches this string.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.1
|
||||
*/
|
||||
char* validate_iss;
|
||||
|
||||
/**
|
||||
* validate_iss string length.
|
||||
*/
|
||||
size_t validate_iss_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The subject claim (who is the JWT about?). <p>
|
||||
* Set to <code>NULL</code> if you don't want to validate the subject claim. <p>
|
||||
* The JWT will only pass verification if its <code>sub</code> matches this string.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.2
|
||||
*/
|
||||
char* validate_sub;
|
||||
|
||||
/**
|
||||
* validate_sub string length.
|
||||
*/
|
||||
size_t validate_sub_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The audience claim (who is the JWT intended for? Who is the intended JWT's recipient?). <p>
|
||||
* Set to <code>NULL</code> if you don't want to validate the audience. <p>
|
||||
* The JWT will only pass verification if its <code>aud</code> matches this string.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.3
|
||||
*/
|
||||
char* validate_aud;
|
||||
|
||||
/**
|
||||
* validate_aud string length.
|
||||
*/
|
||||
size_t validate_aud_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The JWT ID. Provides a unique identifier for the token. <p>
|
||||
* Set to <code>NULL</code> if you don't want to validate the jti claim. <p>
|
||||
* The JWT will only pass verification if its <code>jti</code> matches this string.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.7
|
||||
*/
|
||||
char* validate_jti;
|
||||
|
||||
/**
|
||||
* validate_jti claim length.
|
||||
*/
|
||||
size_t validate_jti_length;
|
||||
|
||||
/**
|
||||
* Should the expiration claim be verified?
|
||||
* If this is set to <code>1</code>, the <code>exp</code> claim will be compared to the current date and time + {@link #exp_tolerance_seconds}
|
||||
*/
|
||||
int validate_exp;
|
||||
|
||||
/**
|
||||
* Should the "not before" claim be verified?
|
||||
* If this is set to <code>1</code>, the <code>nbf</code> claim will be compared to the current date and time + {@link #nbf_tolerance_seconds}
|
||||
*/
|
||||
int validate_nbf;
|
||||
|
||||
/**
|
||||
* Should the "issued at" claim be verified?
|
||||
* If this is set to <code>1</code>, the <code>iat</code> claim will be compared to the current date and time + {@link #iat_tolerance_seconds}
|
||||
*/
|
||||
int validate_iat;
|
||||
|
||||
/**
|
||||
* Small inconsistencies in time can happen, or also latency between clients and servers.
|
||||
* That's just life. You can forgive a few seconds of expiration, but don't exaggerate this! <p>
|
||||
* Only taken into consideration if {@link #validate_exp} is set to <code>1</code>.
|
||||
*/
|
||||
uint8_t exp_tolerance_seconds;
|
||||
|
||||
/**
|
||||
* The amount of seconds to subtract from the current time when comparing the "not before" claim, to allow for a small tolerance time frame.
|
||||
* Only taken into consideration if {@link #validate_nbf} is set to <code>1</code>.
|
||||
*/
|
||||
uint8_t nbf_tolerance_seconds;
|
||||
|
||||
/**
|
||||
* The amount of seconds to subtract from the current time when comparing the "issued at" claim, to allow for a small tolerance time frame.
|
||||
* Only taken into consideration if {@link #validate_iat} is set to <code>1</code>.
|
||||
*/
|
||||
uint8_t iat_tolerance_seconds;
|
||||
|
||||
/**
|
||||
* The key to use for verifying the token's signature
|
||||
* (e.g. if you chose HS256 as algorithm, this will be the HMAC secret; for RS512 this will be the PEM-formatted public RSA key string, etc...).
|
||||
*/
|
||||
unsigned char* verification_key;
|
||||
|
||||
/**
|
||||
* Length of the {@link #verification_key}
|
||||
*/
|
||||
size_t verification_key_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The typ claim (what type is the token?). <p>
|
||||
* Set to <code>NULL</code> if you don't want to validate the "typ" claim. <p>
|
||||
*/
|
||||
char* validate_typ;
|
||||
|
||||
/**
|
||||
* validate_typ string length.
|
||||
*/
|
||||
size_t validate_typ_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a {@link #l8w8jwt_decoding_params} instance by setting its fields to default values.
|
||||
* @param params The l8w8jwt_decoding_params to initialize (set to default values).
|
||||
*/
|
||||
L8W8JWT_API void l8w8jwt_decoding_params_init(struct l8w8jwt_decoding_params* params);
|
||||
|
||||
/**
|
||||
* Validates a set of l8w8jwt_decoding_params.
|
||||
* @param params The l8w8jwt_decoding_params to validate.
|
||||
* @return Return code as defined in retcodes.h
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_validate_decoding_params(struct l8w8jwt_decoding_params* params);
|
||||
|
||||
/**
|
||||
* Decode (and validate) a JWT using specific parameters. <p>
|
||||
* The resulting {@link #l8w8jwt_validation_result} written into the passed "out_validation_result" pointer
|
||||
* contains validation failure flags (see the {@link #l8w8jwt_validation_result} enum docs for more details). <p>
|
||||
* This only happens if decoding also succeeded: if the token is malformed, nothing will be written into "out_validation_result". <p>
|
||||
* If validation succeeds, the {@link #l8w8jwt_validation_result} receives the value 0 (enum value <code>L8W8JWT_VALID</code>). <p>
|
||||
* The same applies to the "out_claims" argument: it is only allocated and written to if it (obviously) isn't <code>NULL</code> and if the decoding was also successful!
|
||||
*
|
||||
* @param params The parameters to use for decoding and validating the token.
|
||||
*
|
||||
* @param out_validation_result Where to write the validation result flags into (0 means success). In case of a decoding failure this is set to -1 (or <code>~L8W8JWT_VALID</code>)!
|
||||
*
|
||||
* @param out_claims
|
||||
* [OPTIONAL] Where the decoded claims (header + payload claims together) should be written into.
|
||||
* This pointer will be dereferenced + allocated, so make sure to pass a fresh pointer!
|
||||
* If you don't need the claims, set this to <code>NULL</code> (they will only be validated, e.g. signature, exp, etc...).
|
||||
* Check the note down below for more infos!
|
||||
*
|
||||
* @param out_claims_length Where to write the decoded claims count into. This will receive the value of how many claims were written into "out_claims" (0 if you decided to set "out_claims" to <code>NULL</code>).
|
||||
*
|
||||
* @note If you decide to keep the claims stored in the <code>out_claims</code> parameter, REMEMBER to call {@link #l8w8jwt_free_claims()} on it once you're done using them!
|
||||
*
|
||||
* @return Return code as defined in retcodes.h (this is NOT the validation result that's written into the out_validation_result argument; the returned int describes whether the actual parsing/decoding part failed).
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_decode(struct l8w8jwt_decoding_params* params, enum l8w8jwt_validation_result* out_validation_result, struct l8w8jwt_claim** out_claims, size_t* out_claims_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_DECODE_H
|
206
r5dev/thirdparty/jwt/include/encode.h
vendored
Normal file
206
r5dev/thirdparty/jwt/include/encode.h
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
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 encode.h
|
||||
* @author Raphael Beck
|
||||
* @brief Core ENCODE function for l8w8jwt. Use this to encode a JWT header + payload WITHOUT signing.
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_ENCODE_H
|
||||
#define L8W8JWT_ENCODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "algs.h"
|
||||
#include "claim.h"
|
||||
#include "version.h"
|
||||
#include "retcodes.h"
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef L8W8JWT_MAX_KEY_SIZE
|
||||
#define L8W8JWT_MAX_KEY_SIZE 8192
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Struct containing the parameters to use for creating a JWT with l8w8jwt.
|
||||
*/
|
||||
L8W8JWT_API struct l8w8jwt_encoding_params
|
||||
{
|
||||
/**
|
||||
* The signature algorithm ID. <p>
|
||||
* [0;2] = HS256/384/512 | [3;5] = RS256/384/512 | [6;8] = PS256/384/512 | [9;11] = ES256/384/512
|
||||
*/
|
||||
int alg;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The issuer claim (who issued the JWT?). Can be omitted by setting this to <code>NULL</code>.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.1
|
||||
*/
|
||||
char* iss;
|
||||
|
||||
/**
|
||||
* iss claim string length.
|
||||
*/
|
||||
size_t iss_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The subject claim (who is the JWT about?). Set to <code>NULL</code> if you don't want it in your token.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.2
|
||||
*/
|
||||
char* sub;
|
||||
|
||||
/**
|
||||
* sub claim string length.
|
||||
*/
|
||||
size_t sub_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The audience claim (who is the JWT intended for? Who is the intended JWT's recipient?).
|
||||
* Set this to <code>NULL</code> if you don't wish to add this claim to the token.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.3
|
||||
*/
|
||||
char* aud;
|
||||
|
||||
/**
|
||||
* aud claim string length.
|
||||
*/
|
||||
size_t aud_length;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The JWT ID. Provides a unique identifier for the token. Can be omitted by setting this to <code>NULL</code>.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.7
|
||||
*/
|
||||
char* jti;
|
||||
|
||||
/**
|
||||
* jti claim string length.
|
||||
*/
|
||||
size_t jti_length;
|
||||
|
||||
/**
|
||||
* Expiration time claim; specifies when this token should stop being valid (in seconds since Unix epoch). <p>
|
||||
* If you want to omit this, set this to <code>0</code>, but do NOT FORGET to set it to something,
|
||||
* otherwise it will be set to whatever random value was in the memory where this variable resides.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.4
|
||||
*/
|
||||
time_t exp;
|
||||
|
||||
/**
|
||||
* "Not before" time claim; specifies when this token should start being valid (in seconds since Unix epoch). <p>
|
||||
* If you want to omit this, set this to <code>0</code>, but do NOT FORGET to set it to something,
|
||||
* otherwise it will be set to whatever random value was in the memory where this variable resides.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.5
|
||||
*/
|
||||
time_t nbf;
|
||||
|
||||
/**
|
||||
* "Issued at" timestamp claim; specifies when this token was emitted (in seconds since Unix epoch). <p>
|
||||
* If you want to omit this, set this to <code>0</code>, but do NOT FORGET to set it to something,
|
||||
* otherwise it will be set to whatever random value was in the memory where this variable resides.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.6
|
||||
*/
|
||||
time_t iat;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] Array of additional claims to include in the JWT's header like for example "kid" or "cty"; pass <code>NULL</code> if you don't wish to add any! <p>
|
||||
* Avoid header claims such as <code>typ</code> and <code>alg</code>, since those are written by the encoding function itself.
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4.1.7
|
||||
*/
|
||||
struct l8w8jwt_claim* additional_header_claims;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The additional_header_claims array size; pass <code>0</code> if you don't wish to include any custom claims!
|
||||
*/
|
||||
size_t additional_header_claims_count;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] Array of additional claims to include in the JWT's payload; pass <code>NULL</code> if you don't wish to add any! <p>
|
||||
* Registered claim names such as "iss", "exp", etc... have their own dedicated field within this struct: do not include those in this array to prevent uncomfortable duplicates!
|
||||
* @see https://tools.ietf.org/html/rfc7519#section-4
|
||||
*/
|
||||
struct l8w8jwt_claim* additional_payload_claims;
|
||||
|
||||
/**
|
||||
* [OPTIONAL] The additional_payload_claims array size; pass <code>0</code> if you don't wish to include any custom claims!
|
||||
*/
|
||||
size_t additional_payload_claims_count;
|
||||
|
||||
/**
|
||||
* The secret key to use for signing the token
|
||||
* (e.g. if you chose HS256 as algorithm, this will be the HMAC secret; for RS512 this will be the private PEM-formatted RSA key string, and so on...).
|
||||
*/
|
||||
unsigned char* secret_key;
|
||||
|
||||
/**
|
||||
* Length of the secret_key
|
||||
*/
|
||||
size_t secret_key_length;
|
||||
|
||||
/**
|
||||
* If the secret key requires a password for usage, please assign it to this field. <p>
|
||||
* You can only omit this when using JWT algorithms "HS256", "HS384" or "HS512" (it's ignored in that case actually). <p>
|
||||
* Every other algorithm requires you to at least set this to <code>NULL</code> if the {@link #secret_key} isn't password-protected.
|
||||
*/
|
||||
unsigned char* secret_key_pw;
|
||||
|
||||
/**
|
||||
* The secret key's password length (if there is any). If there's none, set this to zero!
|
||||
*/
|
||||
size_t secret_key_pw_length;
|
||||
|
||||
/**
|
||||
* Where the encoded token should be written into
|
||||
* (will be malloc'ed, so make sure to <code>l8w8jwt_free()</code> this as soon as you're done using it!).
|
||||
*/
|
||||
char** out;
|
||||
|
||||
/**
|
||||
* Where the output token string length should be written into.
|
||||
*/
|
||||
size_t* out_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a {@link #l8w8jwt_encoding_params} instance by setting its fields to default values.
|
||||
* @param params The l8w8jwt_encoding_params to initialize (set to default values).
|
||||
*/
|
||||
L8W8JWT_API void l8w8jwt_encoding_params_init(struct l8w8jwt_encoding_params* params);
|
||||
|
||||
/**
|
||||
* Validates a set of l8w8jwt_encoding_params.
|
||||
* @param params The l8w8jwt_encoding_params to validate.
|
||||
* @return Return code as defined in retcodes.h
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_validate_encoding_params(struct l8w8jwt_encoding_params* params);
|
||||
|
||||
/**
|
||||
* Creates, signs and encodes a Json-Web-Token. <p>
|
||||
* An example output could be: <code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNvbWUta2V5LWlkLWhlcmUtMDEyMzQ1NiJ9.eyJpYXQiOjE1Nzk2NDUzNTUsImV4cCI6MTU3OTY0NTk1NSwic3ViIjoiR29yZG9uIEZyZWVtYW4iLCJpc3MiOiJCbGFjayBNZXNhIiwiYXVkIjoiQWRtaW5pc3RyYXRvciJ9.uk4EEoq0ql_SguLto5EWzklakpzO-6GE2U26crB8vUY</code> <p>
|
||||
* @param params The token encoding parameters (e.g. "alg", "iss", "exp", etc...).
|
||||
* @return Return code as defined in retcodes.h
|
||||
* @see l8w8jwt_encoding_params
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_encode(struct l8w8jwt_encoding_params* params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_ENCODE_H
|
107
r5dev/thirdparty/jwt/include/retcodes.h
vendored
Normal file
107
r5dev/thirdparty/jwt/include/retcodes.h
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
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 retcodes.h
|
||||
* @author Raphael Beck
|
||||
* @brief Macros for possible integer codes returned by the various l8w8jwt functions.
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_RETCODES_H
|
||||
#define L8W8JWT_RETCODES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returned from a l8w8jwt function when everything went smooth 'n' chill. Time to get Schwifty, Morteyy!
|
||||
*/
|
||||
#define L8W8JWT_SUCCESS 0
|
||||
|
||||
/**
|
||||
* Error code returned by a l8w8jwt function if you passed a NULL argument that shouldn't have been NULL.
|
||||
*/
|
||||
#define L8W8JWT_NULL_ARG 100
|
||||
|
||||
/**
|
||||
* This error code is returned by a l8w8jwt function if you passed an invalid parameter into it.
|
||||
*/
|
||||
#define L8W8JWT_INVALID_ARG 200
|
||||
|
||||
/**
|
||||
* This is returned if some allocation inside a l8w8jwt function failed: you're out of memory at this point.
|
||||
*/
|
||||
#define L8W8JWT_OUT_OF_MEM 300
|
||||
|
||||
/**
|
||||
* Not good...
|
||||
*/
|
||||
#define L8W8JWT_OVERFLOW 310
|
||||
|
||||
/**
|
||||
* Returned if signing a JWT failed.
|
||||
*/
|
||||
#define L8W8JWT_SIGNATURE_CREATION_FAILURE 400
|
||||
|
||||
/**
|
||||
* If one of the SHA-2 functions fails (e.g. SHA-256).
|
||||
*/
|
||||
#define L8W8JWT_SHA2_FAILURE 410
|
||||
|
||||
/**
|
||||
* Returned if some PEM-formatted key string couldn't be parsed.
|
||||
*/
|
||||
#define L8W8JWT_KEY_PARSE_FAILURE 420
|
||||
|
||||
/**
|
||||
* Base64(URL) encoding or decoding error.
|
||||
*/
|
||||
#define L8W8JWT_BASE64_FAILURE 425
|
||||
|
||||
/**
|
||||
* Returned if you passed the wrong private or public key type (e.g. trying to use an RSA key for ECDSA tokens, etc...). <p>
|
||||
* Especially for the ECDSA algorithms like ES256, ES384 and ES512 double-check that you passed keys of the correct curve! <p>
|
||||
* Only use the P-256 curve for ES256, P-384 (a.k.a. secp384r1) for ES384 and P-521 (a.k.a. secp521r1) for ES512.
|
||||
*/
|
||||
#define L8W8JWT_WRONG_KEY_TYPE 450
|
||||
|
||||
/**
|
||||
* When the <code>mbedtls_ctr_drbg_seed()</code> function fails...
|
||||
*/
|
||||
#define L8W8JWT_MBEDTLS_CTR_DRBG_SEED_FAILURE 500
|
||||
|
||||
/**
|
||||
* Returned if the token is invalid (format-wise).
|
||||
*/
|
||||
#define L8W8JWT_DECODE_FAILED_INVALID_TOKEN_FORMAT 600
|
||||
|
||||
/**
|
||||
* Returned if the token is invalid because it's missing the signature (despite having specified an alg that isn't "none").
|
||||
*/
|
||||
#define L8W8JWT_DECODE_FAILED_MISSING_SIGNATURE 700
|
||||
|
||||
/**
|
||||
* Returned if the JWT signing alg parameter that was passed is not supported (e.g. the used l8w8jwt library was built without support for that algo, e.g. Ed25519).
|
||||
* See the README.md for more details!
|
||||
*/
|
||||
#define L8W8JWT_UNSUPPORTED_ALG 800
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_RETCODES_H
|
58
r5dev/thirdparty/jwt/include/util.h
vendored
Normal file
58
r5dev/thirdparty/jwt/include/util.h
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 util.h
|
||||
* @author Raphael Beck
|
||||
* @brief Useful utility functions.
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_UTIL_H
|
||||
#define L8W8JWT_UTIL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "version.h"
|
||||
|
||||
/**
|
||||
* Converts a hex-encoded string to a binary array. <p>
|
||||
* A NUL-terminator is appended at the end of the output buffer, so make sure to allocate at least <c>(hexstr_length / 2) + 1</c> bytes!
|
||||
* @param hexstr The hex string to convert.
|
||||
* @param hexstr_length Length of the \p hexstr
|
||||
* @param output Where to write the converted binary data into.
|
||||
* @param output_size Size of the output buffer (make sure to allocate at least <c>(hexstr_length / 2) + 1</c> bytes!).
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Compares two strings ignoring UPPER vs. lowercase.
|
||||
* @param str1 String to compare.
|
||||
* @param str2 String to compare to.
|
||||
* @param n How many characters of the string should be compared (starting from index 0)?
|
||||
* @return If the strings are equal, <code>0</code> is returned. Otherwise, something else.
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_strncmpic(const char* str1, const char* str2, size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_UTIL_H
|
87
r5dev/thirdparty/jwt/include/version.h
vendored
Normal file
87
r5dev/thirdparty/jwt/include/version.h
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
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 version.h
|
||||
* @author Raphael Beck
|
||||
* @brief l8w8jwt version checking.
|
||||
*/
|
||||
|
||||
#ifndef L8W8JWT_VERSION_H
|
||||
#define L8W8JWT_VERSION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Current l8w8jwt version number.
|
||||
*/
|
||||
#define L8W8JWT_VERSION 220
|
||||
|
||||
/**
|
||||
* Current l8w8jwt version number (as a human-readable string).
|
||||
*/
|
||||
#define L8W8JWT_VERSION_STR "2.2.0"
|
||||
|
||||
#if defined(_WIN32) && defined(L8W8JWT_DLL)
|
||||
#ifdef L8W8JWT_BUILD_DLL
|
||||
#define L8W8JWT_API __declspec(dllexport)
|
||||
#else
|
||||
#define L8W8JWT_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define L8W8JWT_API
|
||||
#endif
|
||||
|
||||
#ifndef L8W8JWT_SMALL_STACK
|
||||
/**
|
||||
* Set this pre-processor definition to \c 1 if you're using this
|
||||
* on a low-memory device with increased risk of stack overflow.
|
||||
*/
|
||||
#define L8W8JWT_SMALL_STACK 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Free memory that was allocated by L8W8JWT.
|
||||
* @param mem The memory to free.
|
||||
*/
|
||||
L8W8JWT_API void l8w8jwt_free(void* mem);
|
||||
|
||||
/**
|
||||
* Zero memory securely.
|
||||
* @param mem The memory to zero.
|
||||
* @param len The length to zero.
|
||||
*/
|
||||
L8W8JWT_API void l8w8jwt_zero(void* buf, size_t len);
|
||||
|
||||
/**
|
||||
* Gets the l8w8jwt version number as an integer.
|
||||
* @return Version number (e.g. "2.1.4" => 214)
|
||||
*/
|
||||
L8W8JWT_API int l8w8jwt_get_version_number(void);
|
||||
|
||||
/**
|
||||
* Gets the l8w8jwt version number as a nicely formatted string.
|
||||
* @param out A writable \c char buffer of at least 32B where to write the version number string into. The string will be NUL-terminated, no worries! Passing \c NULL here is a very bad idea. Undefined, unpleasant, and just... just don't!
|
||||
*/
|
||||
L8W8JWT_API void l8w8jwt_get_version_string(char out[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // L8W8JWT_VERSION_H
|
87
r5dev/thirdparty/jwt/util.c
vendored
Normal file
87
r5dev/thirdparty/jwt/util.c
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "include/util.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int l8w8jwt_hexstr2bin(const char* hexstr, const size_t hexstr_length, unsigned char* output, const size_t output_size, size_t* output_length)
|
||||
{
|
||||
if (hexstr == NULL || output == NULL || hexstr_length == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const size_t hl = hexstr[hexstr_length - 1] ? hexstr_length : hexstr_length - 1;
|
||||
|
||||
if (hl % 2 != 0)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
const size_t final_length = hl / 2;
|
||||
|
||||
if (output_size < final_length + 1)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
for (size_t i = 0, ii = 0; ii < final_length; i += 2, ii++)
|
||||
{
|
||||
output[ii] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25;
|
||||
}
|
||||
|
||||
output[final_length] = '\0';
|
||||
|
||||
if (output_length != NULL)
|
||||
{
|
||||
*output_length = final_length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l8w8jwt_strncmpic(const char* str1, const char* str2, size_t n)
|
||||
{
|
||||
size_t cmp = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (str1 == NULL || str2 == NULL)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ((*str1 || *str2) && cmp < n)
|
||||
{
|
||||
if ((ret = tolower((int)(*str1)) - tolower((int)(*str2))) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cmp++;
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
73
r5dev/thirdparty/jwt/version.c
vendored
Normal file
73
r5dev/thirdparty/jwt/version.c
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "include/version.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void l8w8jwt_free(void* mem)
|
||||
{
|
||||
free(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)
|
||||
explicit_bzero(buf, len);
|
||||
#if defined(HAVE_MEMORY_SANITIZER)
|
||||
/* You'd think that Msan would recognize explicit_bzero() as
|
||||
* equivalent to bzero(), but it actually doesn't on several
|
||||
* platforms, including Linux (Ubuntu 20.04).
|
||||
* https://github.com/google/sanitizers/issues/1507
|
||||
* https://github.com/openssh/openssh-portable/commit/74433a19bb6f4cef607680fa4d1d7d81ca3826aa
|
||||
*/
|
||||
__msan_unpoison(buf, len);
|
||||
#endif
|
||||
#elif defined(__STDC_LIB_EXT1__)
|
||||
memset_s(buf, len, 0, len);
|
||||
#elif defined(_WIN32)
|
||||
RtlSecureZeroMemory(buf, len);
|
||||
#else
|
||||
memset_func(buf, 0, len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int l8w8jwt_get_version_number()
|
||||
{
|
||||
return (int)L8W8JWT_VERSION;
|
||||
}
|
||||
|
||||
void l8w8jwt_get_version_string(char out[32])
|
||||
{
|
||||
const char version_string[] = L8W8JWT_VERSION_STR;
|
||||
const size_t version_string_length = sizeof(version_string) - 1;
|
||||
|
||||
memcpy(out, version_string, version_string_length);
|
||||
out[version_string_length] = '\0';
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user