early-access version 2862
This commit is contained in:
312
externals/cpp-jwt/include/jwt/impl/algorithm.ipp
vendored
Executable file
312
externals/cpp-jwt/include/jwt/impl/algorithm.ipp
vendored
Executable file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
Copyright (c) 2017 Arun Muralidharan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CPP_JWT_ALGORITHM_IPP
|
||||
#define CPP_JWT_ALGORITHM_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <typename Hasher>
|
||||
verify_result_t HMACSign<Hasher>::verify(
|
||||
const jwt::string_view key,
|
||||
const jwt::string_view head,
|
||||
const jwt::string_view jwt_sign)
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
unsigned char enc_buf[EVP_MAX_MD_SIZE];
|
||||
uint32_t enc_buf_len = 0;
|
||||
|
||||
unsigned char* res = HMAC(Hasher{}(),
|
||||
key.data(),
|
||||
static_cast<int>(key.length()),
|
||||
reinterpret_cast<const unsigned char*>(head.data()),
|
||||
head.length(),
|
||||
enc_buf,
|
||||
&enc_buf_len);
|
||||
if (!res) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return {false, ec};
|
||||
}
|
||||
if (enc_buf_len == 0) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return {false, ec};
|
||||
}
|
||||
|
||||
std::string b64_enc_str = jwt::base64_encode((const char*)&enc_buf[0], enc_buf_len);
|
||||
|
||||
if (!b64_enc_str.length()) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return {false, ec};
|
||||
}
|
||||
|
||||
// Make the base64 string url safe
|
||||
auto new_len = jwt::base64_uri_encode(&b64_enc_str[0], b64_enc_str.length());
|
||||
b64_enc_str.resize(new_len);
|
||||
|
||||
bool ret = (jwt::string_view{b64_enc_str} == jwt_sign);
|
||||
|
||||
return { ret, ec };
|
||||
}
|
||||
|
||||
|
||||
template <typename Hasher>
|
||||
verify_result_t PEMSign<Hasher>::verify(
|
||||
const jwt::string_view key,
|
||||
const jwt::string_view head,
|
||||
const jwt::string_view jwt_sign)
|
||||
{
|
||||
std::error_code ec{};
|
||||
std::string dec_sig = base64_uri_decode(jwt_sign.data(), jwt_sign.length());
|
||||
|
||||
BIO_uptr bufkey{
|
||||
BIO_new_mem_buf((void*)key.data(), static_cast<int>(key.length())),
|
||||
bio_deletor};
|
||||
|
||||
if (!bufkey) {
|
||||
throw MemoryAllocationException("BIO_new_mem_buf failed");
|
||||
}
|
||||
|
||||
EC_PKEY_uptr pkey{
|
||||
PEM_read_bio_PUBKEY(bufkey.get(), nullptr, nullptr, nullptr),
|
||||
ev_pkey_deletor};
|
||||
|
||||
if (!pkey) {
|
||||
ec = AlgorithmErrc::InvalidKeyErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
int pkey_type = EVP_PKEY_id(pkey.get());
|
||||
|
||||
if (pkey_type != Hasher::type) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
//Convert EC signature back to ASN1
|
||||
if (Hasher::type == EVP_PKEY_EC) {
|
||||
EC_SIG_uptr ec_sig{ECDSA_SIG_new(), ec_sig_deletor};
|
||||
if (!ec_sig) {
|
||||
throw MemoryAllocationException("ECDSA_SIG_new failed");
|
||||
}
|
||||
|
||||
//Get the actual ec_key
|
||||
EC_KEY_uptr ec_key{EVP_PKEY_get1_EC_KEY(pkey.get()), ec_key_deletor};
|
||||
if (!ec_key) {
|
||||
throw MemoryAllocationException("EVP_PKEY_get1_EC_KEY failed");
|
||||
}
|
||||
|
||||
unsigned int degree = EC_GROUP_get_degree(
|
||||
EC_KEY_get0_group(ec_key.get()));
|
||||
|
||||
unsigned int bn_len = (degree + 7) / 8;
|
||||
|
||||
if ((bn_len * 2) != dec_sig.length()) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
BIGNUM* ec_sig_r = BN_bin2bn((unsigned char*)dec_sig.data(), bn_len, nullptr);
|
||||
BIGNUM* ec_sig_s = BN_bin2bn((unsigned char*)dec_sig.data() + bn_len, bn_len, nullptr);
|
||||
|
||||
if (!ec_sig_r || !ec_sig_s) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
ECDSA_SIG_set0(ec_sig.get(), ec_sig_r, ec_sig_s);
|
||||
|
||||
size_t nlen = i2d_ECDSA_SIG(ec_sig.get(), nullptr);
|
||||
dec_sig.resize(nlen);
|
||||
|
||||
auto data = reinterpret_cast<unsigned char*>(&dec_sig[0]);
|
||||
nlen = i2d_ECDSA_SIG(ec_sig.get(), &data);
|
||||
|
||||
if (nlen == 0) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
}
|
||||
|
||||
EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor};
|
||||
if (!mdctx_ptr) {
|
||||
throw MemoryAllocationException("EVP_MD_CTX_create failed");
|
||||
}
|
||||
|
||||
if (EVP_DigestVerifyInit(
|
||||
mdctx_ptr.get(), nullptr, Hasher{}(), nullptr, pkey.get()) != 1) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
if (EVP_DigestVerifyUpdate(mdctx_ptr.get(), head.data(), head.length()) != 1) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
if (EVP_DigestVerifyFinal(
|
||||
mdctx_ptr.get(), (unsigned char*)&dec_sig[0], dec_sig.length()) != 1) {
|
||||
ec = AlgorithmErrc::VerificationErr;
|
||||
return { false, ec };
|
||||
}
|
||||
|
||||
return { true, ec };
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
EVP_PKEY* PEMSign<Hasher>::load_key(
|
||||
const jwt::string_view key,
|
||||
std::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
BIO_uptr bio_ptr{
|
||||
BIO_new_mem_buf((void*)key.data(), static_cast<int>(key.length())),
|
||||
bio_deletor};
|
||||
|
||||
if (!bio_ptr) {
|
||||
throw MemoryAllocationException("BIO_new_mem_buf failed");
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(
|
||||
bio_ptr.get(), nullptr, nullptr, nullptr);
|
||||
|
||||
if (!pkey) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto pkey_type = EVP_PKEY_id(pkey);
|
||||
if (pkey_type != Hasher::type) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
std::string PEMSign<Hasher>::evp_digest(
|
||||
EVP_PKEY* pkey,
|
||||
const jwt::string_view data,
|
||||
std::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor};
|
||||
|
||||
if (!mdctx_ptr) {
|
||||
throw MemoryAllocationException("EVP_MD_CTX_create failed");
|
||||
}
|
||||
|
||||
//Initialiaze the digest algorithm
|
||||
if (EVP_DigestSignInit(
|
||||
mdctx_ptr.get(), nullptr, Hasher{}(), nullptr, pkey) != 1) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
//Update the digest with the input data
|
||||
if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
if (EVP_DigestSignFinal(mdctx_ptr.get(), nullptr, &len) != 1) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string sign;
|
||||
sign.resize(len);
|
||||
|
||||
//Get the signature
|
||||
if (EVP_DigestSignFinal(mdctx_ptr.get(), (unsigned char*)&sign[0], &len) != 1) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
return sign;
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
std::string PEMSign<Hasher>::public_key_ser(
|
||||
EVP_PKEY* pkey,
|
||||
jwt::string_view sign,
|
||||
std::error_code& ec)
|
||||
{
|
||||
// Get the EC_KEY representing a public key and
|
||||
// (optionaly) an associated private key
|
||||
std::string new_sign;
|
||||
ec.clear();
|
||||
|
||||
EC_KEY_uptr ec_key{EVP_PKEY_get1_EC_KEY(pkey), ec_key_deletor};
|
||||
|
||||
if (!ec_key) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key.get()));
|
||||
|
||||
ec_key.reset(nullptr);
|
||||
|
||||
auto char_ptr = &sign[0];
|
||||
|
||||
EC_SIG_uptr ec_sig{d2i_ECDSA_SIG(nullptr,
|
||||
(const unsigned char**)&char_ptr,
|
||||
static_cast<long>(sign.length())),
|
||||
ec_sig_deletor};
|
||||
|
||||
if (!ec_sig) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
const BIGNUM* ec_sig_r = nullptr;
|
||||
const BIGNUM* ec_sig_s = nullptr;
|
||||
|
||||
ECDSA_SIG_get0(ec_sig.get(), &ec_sig_r, &ec_sig_s);
|
||||
|
||||
int r_len = BN_num_bytes(ec_sig_r);
|
||||
int s_len = BN_num_bytes(ec_sig_s);
|
||||
int bn_len = static_cast<int>((degree + 7) / 8);
|
||||
|
||||
if ((r_len > bn_len) || (s_len > bn_len)) {
|
||||
ec = AlgorithmErrc::SigningErr;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto buf_len = 2 * bn_len;
|
||||
new_sign.resize(buf_len);
|
||||
|
||||
BN_bn2bin(ec_sig_r, (unsigned char*)&new_sign[0] + bn_len - r_len);
|
||||
BN_bn2bin(ec_sig_s, (unsigned char*)&new_sign[0] + buf_len - s_len);
|
||||
|
||||
return new_sign;
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
#endif
|
160
externals/cpp-jwt/include/jwt/impl/error_codes.ipp
vendored
Executable file
160
externals/cpp-jwt/include/jwt/impl/error_codes.ipp
vendored
Executable file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright (c) 2017 Arun Muralidharan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CPP_JWT_ERROR_CODES_IPP
|
||||
#define CPP_JWT_ERROR_CODES_IPP
|
||||
|
||||
namespace jwt {
|
||||
// Anonymous namespace
|
||||
namespace {
|
||||
|
||||
/**
|
||||
*/
|
||||
struct AlgorithmErrCategory: std::error_category
|
||||
{
|
||||
const char* name() const noexcept override
|
||||
{
|
||||
return "algorithms";
|
||||
}
|
||||
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<AlgorithmErrc>(ev))
|
||||
{
|
||||
case AlgorithmErrc::SigningErr:
|
||||
return "signing failed";
|
||||
case AlgorithmErrc::VerificationErr:
|
||||
return "verification failed";
|
||||
case AlgorithmErrc::KeyNotFoundErr:
|
||||
return "key not provided";
|
||||
case AlgorithmErrc::NoneAlgorithmUsed:
|
||||
return "none algorithm used";
|
||||
case AlgorithmErrc::InvalidKeyErr:
|
||||
return "invalid key";
|
||||
};
|
||||
return "unknown algorithm error";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
struct DecodeErrorCategory: std::error_category
|
||||
{
|
||||
const char* name() const noexcept override
|
||||
{
|
||||
return "decode";
|
||||
}
|
||||
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<DecodeErrc>(ev))
|
||||
{
|
||||
case DecodeErrc::EmptyAlgoList:
|
||||
return "empty algorithm list";
|
||||
case DecodeErrc::SignatureFormatError:
|
||||
return "signature format is incorrect";
|
||||
case DecodeErrc::AlgHeaderMiss:
|
||||
return "missing algorithm header";
|
||||
case DecodeErrc::TypHeaderMiss:
|
||||
return "missing type header";
|
||||
case DecodeErrc::TypMismatch:
|
||||
return "type mismatch";
|
||||
case DecodeErrc::JsonParseError:
|
||||
return "json parse failed";
|
||||
case DecodeErrc::DuplClaims:
|
||||
return "duplicate claims";
|
||||
case DecodeErrc::KeyNotPresent:
|
||||
return "key not present";
|
||||
case DecodeErrc::KeyNotRequiredForNoneAlg:
|
||||
return "key not required for NONE algorithm";
|
||||
};
|
||||
return "unknown decode error";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
struct VerificationErrorCategory: std::error_category
|
||||
{
|
||||
const char* name() const noexcept override
|
||||
{
|
||||
return "verification";
|
||||
}
|
||||
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<VerificationErrc>(ev))
|
||||
{
|
||||
case VerificationErrc::InvalidAlgorithm:
|
||||
return "invalid algorithm";
|
||||
case VerificationErrc::TokenExpired:
|
||||
return "token expired";
|
||||
case VerificationErrc::InvalidIssuer:
|
||||
return "invalid issuer";
|
||||
case VerificationErrc::InvalidSubject:
|
||||
return "invalid subject";
|
||||
case VerificationErrc::InvalidAudience:
|
||||
return "invalid audience";
|
||||
case VerificationErrc::InvalidIAT:
|
||||
return "invalid iat";
|
||||
case VerificationErrc::InvalidJTI:
|
||||
return "invalid jti";
|
||||
case VerificationErrc::ImmatureSignature:
|
||||
return "immature signature";
|
||||
case VerificationErrc::InvalidSignature:
|
||||
return "invalid signature";
|
||||
case VerificationErrc::TypeConversionError:
|
||||
return "type conversion error";
|
||||
};
|
||||
return "unknown verification error";
|
||||
}
|
||||
};
|
||||
|
||||
// Create global object for the error categories
|
||||
const AlgorithmErrCategory theAlgorithmErrCategory {};
|
||||
|
||||
const DecodeErrorCategory theDecodeErrorCategory {};
|
||||
|
||||
const VerificationErrorCategory theVerificationErrorCategory {};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Create the AlgorithmErrc error code
|
||||
inline std::error_code make_error_code(AlgorithmErrc err)
|
||||
{
|
||||
return { static_cast<int>(err), theAlgorithmErrCategory };
|
||||
}
|
||||
|
||||
inline std::error_code make_error_code(DecodeErrc err)
|
||||
{
|
||||
return { static_cast<int>(err), theDecodeErrorCategory };
|
||||
}
|
||||
|
||||
inline std::error_code make_error_code(VerificationErrc err)
|
||||
{
|
||||
return { static_cast<int>(err), theVerificationErrorCategory };
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
#endif
|
882
externals/cpp-jwt/include/jwt/impl/jwt.ipp
vendored
Executable file
882
externals/cpp-jwt/include/jwt/impl/jwt.ipp
vendored
Executable file
@@ -0,0 +1,882 @@
|
||||
/*
|
||||
Copyright (c) 2017 Arun Muralidharan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JWT_IPP
|
||||
#define JWT_IPP
|
||||
|
||||
#include "jwt/config.hpp"
|
||||
#include "jwt/detail/meta.hpp"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
namespace jwt {
|
||||
|
||||
/**
|
||||
*/
|
||||
static inline void jwt_throw_exception(const std::error_code& ec);
|
||||
|
||||
template <typename T, typename Cond>
|
||||
std::string to_json_str(const T& obj, bool pretty)
|
||||
{
|
||||
return pretty ? obj.create_json_obj().dump(2)
|
||||
: obj.create_json_obj().dump()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::ostream& write(std::ostream& os, const T& obj, bool pretty)
|
||||
{
|
||||
pretty ? (os << std::setw(2) << obj.create_json_obj())
|
||||
: (os << obj.create_json_obj())
|
||||
;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Cond>
|
||||
std::ostream& operator<< (std::ostream& os, const T& obj)
|
||||
{
|
||||
os << obj.create_json_obj();
|
||||
return os;
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
|
||||
inline void jwt_header::decode(const jwt::string_view enc_str, std::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
std::string json_str = base64_decode(enc_str);
|
||||
|
||||
try {
|
||||
payload_ = json_t::parse(std::move(json_str));
|
||||
} catch(const std::exception&) {
|
||||
ec = DecodeErrc::JsonParseError;
|
||||
return;
|
||||
}
|
||||
|
||||
//Look for the algorithm field
|
||||
auto alg_itr = payload_.find("alg");
|
||||
if (alg_itr == payload_.end()) {
|
||||
ec = DecodeErrc::AlgHeaderMiss;
|
||||
return;
|
||||
}
|
||||
|
||||
alg_ = str_to_alg(alg_itr.value().get<std::string>());
|
||||
|
||||
if (alg_ != algorithm::NONE)
|
||||
{
|
||||
auto itr = payload_.find("typ");
|
||||
|
||||
if (itr != payload_.end()) {
|
||||
const auto& typ = itr.value().get<std::string>();
|
||||
if (strcasecmp(typ.c_str(), "JWT")) {
|
||||
ec = DecodeErrc::TypMismatch;
|
||||
return;
|
||||
}
|
||||
|
||||
typ_ = str_to_type(typ);
|
||||
}
|
||||
} else {
|
||||
//TODO:
|
||||
}
|
||||
|
||||
// Populate header
|
||||
for (auto it = payload_.begin(); it != payload_.end(); ++it) {
|
||||
auto ret = headers_.insert(it.key());
|
||||
if (!ret.second) {
|
||||
ec = DecodeErrc::DuplClaims;
|
||||
//ATTN: Dont stop the decode here
|
||||
//Not a hard error.
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
inline void jwt_header::decode(const jwt::string_view enc_str)
|
||||
{
|
||||
std::error_code ec;
|
||||
decode(enc_str, ec);
|
||||
if (ec) {
|
||||
throw DecodeError(ec.message());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
inline void jwt_payload::decode(const jwt::string_view enc_str, std::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
std::string json_str = base64_decode(enc_str);
|
||||
try {
|
||||
payload_ = json_t::parse(std::move(json_str));
|
||||
} catch(const std::exception&) {
|
||||
ec = DecodeErrc::JsonParseError;
|
||||
return;
|
||||
}
|
||||
//populate the claims set
|
||||
for (auto it = payload_.begin(); it != payload_.end(); ++it) {
|
||||
auto ret = claim_names_.insert(it.key());
|
||||
if (!ret.second) {
|
||||
ec = DecodeErrc::DuplClaims;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
inline void jwt_payload::decode(const jwt::string_view enc_str)
|
||||
{
|
||||
std::error_code ec;
|
||||
decode(enc_str, ec);
|
||||
if (ec) {
|
||||
throw DecodeError(ec.message());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
inline std::string jwt_signature::encode(const jwt_header& header,
|
||||
const jwt_payload& payload,
|
||||
std::error_code& ec)
|
||||
{
|
||||
std::string jwt_msg;
|
||||
ec.clear();
|
||||
//TODO: Optimize allocations
|
||||
|
||||
sign_func_t sign_fn = get_sign_algorithm_impl(header);
|
||||
|
||||
std::string hdr_sign = header.base64_encode();
|
||||
std::string pld_sign = payload.base64_encode();
|
||||
std::string data = hdr_sign + '.' + pld_sign;
|
||||
|
||||
auto res = sign_fn(key_, data);
|
||||
|
||||
if (res.second && res.second != AlgorithmErrc::NoneAlgorithmUsed) {
|
||||
ec = res.second;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string b64hash;
|
||||
|
||||
if (!res.second) {
|
||||
b64hash = base64_encode(res.first.c_str(), res.first.length());
|
||||
}
|
||||
|
||||
auto new_len = base64_uri_encode(&b64hash[0], b64hash.length());
|
||||
b64hash.resize(new_len);
|
||||
|
||||
jwt_msg = data + '.' + b64hash;
|
||||
|
||||
return jwt_msg;
|
||||
}
|
||||
|
||||
inline verify_result_t jwt_signature::verify(const jwt_header& header,
|
||||
const jwt::string_view hdr_pld_sign,
|
||||
const jwt::string_view jwt_sign)
|
||||
{
|
||||
verify_func_t verify_fn = get_verify_algorithm_impl(header);
|
||||
return verify_fn(key_, hdr_pld_sign, jwt_sign);
|
||||
}
|
||||
|
||||
|
||||
inline sign_func_t
|
||||
jwt_signature::get_sign_algorithm_impl(const jwt_header& hdr) const noexcept
|
||||
{
|
||||
sign_func_t ret = nullptr;
|
||||
|
||||
switch (hdr.algo()) {
|
||||
case algorithm::HS256:
|
||||
ret = HMACSign<algo::HS256>::sign;
|
||||
break;
|
||||
case algorithm::HS384:
|
||||
ret = HMACSign<algo::HS384>::sign;
|
||||
break;
|
||||
case algorithm::HS512:
|
||||
ret = HMACSign<algo::HS512>::sign;
|
||||
break;
|
||||
case algorithm::NONE:
|
||||
ret = HMACSign<algo::NONE>::sign;
|
||||
break;
|
||||
case algorithm::RS256:
|
||||
ret = PEMSign<algo::RS256>::sign;
|
||||
break;
|
||||
case algorithm::RS384:
|
||||
ret = PEMSign<algo::RS384>::sign;
|
||||
break;
|
||||
case algorithm::RS512:
|
||||
ret = PEMSign<algo::RS512>::sign;
|
||||
break;
|
||||
case algorithm::ES256:
|
||||
ret = PEMSign<algo::ES256>::sign;
|
||||
break;
|
||||
case algorithm::ES384:
|
||||
ret = PEMSign<algo::ES384>::sign;
|
||||
break;
|
||||
case algorithm::ES512:
|
||||
ret = PEMSign<algo::ES512>::sign;
|
||||
break;
|
||||
default:
|
||||
assert (0 && "Code not reached");
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline verify_func_t
|
||||
jwt_signature::get_verify_algorithm_impl(const jwt_header& hdr) const noexcept
|
||||
{
|
||||
verify_func_t ret = nullptr;
|
||||
|
||||
switch (hdr.algo()) {
|
||||
case algorithm::HS256:
|
||||
ret = HMACSign<algo::HS256>::verify;
|
||||
break;
|
||||
case algorithm::HS384:
|
||||
ret = HMACSign<algo::HS384>::verify;
|
||||
break;
|
||||
case algorithm::HS512:
|
||||
ret = HMACSign<algo::HS512>::verify;
|
||||
break;
|
||||
case algorithm::NONE:
|
||||
ret = HMACSign<algo::NONE>::verify;
|
||||
break;
|
||||
case algorithm::RS256:
|
||||
ret = PEMSign<algo::RS256>::verify;
|
||||
break;
|
||||
case algorithm::RS384:
|
||||
ret = PEMSign<algo::RS384>::verify;
|
||||
break;
|
||||
case algorithm::RS512:
|
||||
ret = PEMSign<algo::RS512>::verify;
|
||||
break;
|
||||
case algorithm::ES256:
|
||||
ret = PEMSign<algo::ES256>::verify;
|
||||
break;
|
||||
case algorithm::ES384:
|
||||
ret = PEMSign<algo::ES384>::verify;
|
||||
break;
|
||||
case algorithm::ES512:
|
||||
ret = PEMSign<algo::ES512>::verify;
|
||||
break;
|
||||
default:
|
||||
assert (0 && "Code not reached");
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
template <typename First, typename... Rest,
|
||||
typename SFINAE_COND>
|
||||
jwt_object::jwt_object(
|
||||
First&& first, Rest&&... rest)
|
||||
{
|
||||
static_assert (detail::meta::is_parameter_concept<First>::value &&
|
||||
detail::meta::are_all_params<Rest...>::value,
|
||||
"All constructor argument types must model ParameterConcept");
|
||||
|
||||
set_parameters(std::forward<First>(first), std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Map, typename... Rest>
|
||||
void jwt_object::set_parameters(
|
||||
params::detail::payload_param<Map>&& payload, Rest&&... rargs)
|
||||
{
|
||||
for (const auto& elem : payload.get()) {
|
||||
payload_.add_claim(std::move(elem.first), std::move(elem.second));
|
||||
}
|
||||
set_parameters(std::forward<Rest>(rargs)...);
|
||||
}
|
||||
|
||||
template <typename... Rest>
|
||||
void jwt_object::set_parameters(
|
||||
params::detail::secret_param secret, Rest&&... rargs)
|
||||
{
|
||||
secret_.assign(secret.get().data(), secret.get().length());
|
||||
set_parameters(std::forward<Rest>(rargs)...);
|
||||
}
|
||||
|
||||
template <typename... Rest>
|
||||
void jwt_object::set_parameters(
|
||||
params::detail::algorithm_param alg, Rest&&... rargs)
|
||||
{
|
||||
header_.algo(alg.get());
|
||||
set_parameters(std::forward<Rest>(rargs)...);
|
||||
}
|
||||
|
||||
template <typename Map, typename... Rest>
|
||||
void jwt_object::set_parameters(
|
||||
params::detail::headers_param<Map>&& header, Rest&&... rargs)
|
||||
{
|
||||
for (const auto& elem : header.get()) {
|
||||
header_.add_header(std::move(elem.first), std::move(elem.second));
|
||||
}
|
||||
|
||||
set_parameters(std::forward<Rest>(rargs)...);
|
||||
}
|
||||
|
||||
inline void jwt_object::set_parameters()
|
||||
{
|
||||
//sentinel call
|
||||
return;
|
||||
}
|
||||
|
||||
inline jwt_object& jwt_object::add_claim(const jwt::string_view name, system_time_t tp)
|
||||
{
|
||||
return add_claim(
|
||||
name,
|
||||
std::chrono::duration_cast<
|
||||
std::chrono::seconds>(tp.time_since_epoch()).count()
|
||||
);
|
||||
}
|
||||
|
||||
inline jwt_object& jwt_object::remove_claim(const jwt::string_view name)
|
||||
{
|
||||
payload_.remove_claim(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline std::string jwt_object::signature(std::error_code& ec) const
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
//key/secret should be set for any algorithm except NONE
|
||||
if (header().algo() != jwt::algorithm::NONE) {
|
||||
if (secret_.length() == 0) {
|
||||
ec = AlgorithmErrc::KeyNotFoundErr;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
jwt_signature jws{secret_};
|
||||
return jws.encode(header_, payload_, ec);
|
||||
}
|
||||
|
||||
inline std::string jwt_object::signature() const
|
||||
{
|
||||
std::error_code ec;
|
||||
std::string res = signature(ec);
|
||||
if (ec) {
|
||||
throw SigningError(ec.message());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Params, typename SequenceT>
|
||||
std::error_code jwt_object::verify(
|
||||
const Params& dparams,
|
||||
const params::detail::algorithms_param<SequenceT>& algos) const
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
//Verify if the algorithm set in the header
|
||||
//is any of the one expected by the client.
|
||||
auto fitr = std::find_if(algos.get().begin(),
|
||||
algos.get().end(),
|
||||
[this](const auto& elem)
|
||||
{
|
||||
return jwt::str_to_alg(elem) == this->header().algo();
|
||||
});
|
||||
|
||||
if (fitr == algos.get().end()) {
|
||||
ec = VerificationErrc::InvalidAlgorithm;
|
||||
return ec;
|
||||
}
|
||||
|
||||
//Check for the expiry timings
|
||||
if (has_claim(registered_claims::expiration)) {
|
||||
auto curr_time =
|
||||
std::chrono::duration_cast<
|
||||
std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
|
||||
auto p_exp = payload()
|
||||
.get_claim_value<uint64_t>(registered_claims::expiration);
|
||||
|
||||
if (static_cast<uint64_t>(curr_time) > static_cast<uint64_t>(p_exp + dparams.leeway)) {
|
||||
ec = VerificationErrc::TokenExpired;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
//Check for issuer
|
||||
if (dparams.has_issuer)
|
||||
{
|
||||
if (has_claim(registered_claims::issuer))
|
||||
{
|
||||
const std::string& p_issuer = payload()
|
||||
.get_claim_value<std::string>(registered_claims::issuer);
|
||||
|
||||
if (p_issuer != dparams.issuer) {
|
||||
ec = VerificationErrc::InvalidIssuer;
|
||||
return ec;
|
||||
}
|
||||
} else {
|
||||
ec = VerificationErrc::InvalidIssuer;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
//Check for audience
|
||||
if (dparams.has_aud)
|
||||
{
|
||||
if (has_claim(registered_claims::audience))
|
||||
{
|
||||
const std::string& p_aud = payload()
|
||||
.get_claim_value<std::string>(registered_claims::audience);
|
||||
|
||||
if (p_aud != dparams.aud) {
|
||||
ec = VerificationErrc::InvalidAudience;
|
||||
return ec;
|
||||
}
|
||||
} else {
|
||||
ec = VerificationErrc::InvalidAudience;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
//Check the subject
|
||||
if (dparams.has_sub)
|
||||
{
|
||||
if (has_claim(registered_claims::subject))
|
||||
{
|
||||
const std::string& p_sub = payload()
|
||||
.get_claim_value<std::string>(registered_claims::subject);
|
||||
if (p_sub != dparams.sub) {
|
||||
ec = VerificationErrc::InvalidSubject;
|
||||
return ec;
|
||||
}
|
||||
} else {
|
||||
ec = VerificationErrc::InvalidSubject;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
//Check for NBF
|
||||
if (has_claim(registered_claims::not_before))
|
||||
{
|
||||
auto curr_time =
|
||||
std::chrono::duration_cast<
|
||||
std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
|
||||
auto p_exp = payload()
|
||||
.get_claim_value<uint64_t>(registered_claims::not_before);
|
||||
|
||||
if (static_cast<uint64_t>(p_exp - dparams.leeway) > static_cast<uint64_t>(curr_time)) {
|
||||
ec = VerificationErrc::ImmatureSignature;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
//Check IAT validation
|
||||
if (dparams.validate_iat) {
|
||||
if (!has_claim(registered_claims::issued_at)) {
|
||||
ec = VerificationErrc::InvalidIAT;
|
||||
return ec;
|
||||
} else {
|
||||
// Will throw type conversion error
|
||||
auto val = payload()
|
||||
.get_claim_value<uint64_t>(registered_claims::issued_at);
|
||||
(void)val;
|
||||
}
|
||||
}
|
||||
|
||||
//Check JTI validation
|
||||
if (dparams.validate_jti) {
|
||||
if (!has_claim("jti")) {
|
||||
ec = VerificationErrc::InvalidJTI;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
|
||||
inline std::array<jwt::string_view, 3>
|
||||
jwt_object::three_parts(const jwt::string_view enc_str)
|
||||
{
|
||||
std::array<jwt::string_view, 3> result;
|
||||
|
||||
size_t fpos = enc_str.find_first_of('.');
|
||||
assert (fpos != jwt::string_view::npos);
|
||||
|
||||
result[0] = jwt::string_view{&enc_str[0], fpos};
|
||||
|
||||
size_t spos = enc_str.find_first_of('.', fpos + 1);
|
||||
|
||||
result[1] = jwt::string_view{&enc_str[fpos + 1], spos - fpos - 1};
|
||||
|
||||
if (spos + 1 != enc_str.length()) {
|
||||
result[2] = jwt::string_view{&enc_str[spos + 1], enc_str.length() - spos - 1};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::secret_param s, Rest&&... args)
|
||||
{
|
||||
dparams.secret.assign(s.get().data(), s.get().length());
|
||||
dparams.has_secret = true;
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename T, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::secret_function_param<T>&& s, Rest&&... args)
|
||||
{
|
||||
dparams.secret = s.get(*dparams.payload_ptr);
|
||||
dparams.has_secret = true;
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::leeway_param l, Rest&&... args)
|
||||
{
|
||||
dparams.leeway = l.get();
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::verify_param v, Rest&&... args)
|
||||
{
|
||||
dparams.verify = v.get();
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::issuer_param i, Rest&&... args)
|
||||
{
|
||||
dparams.issuer = std::move(i).get();
|
||||
dparams.has_issuer = true;
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::audience_param a, Rest&&... args)
|
||||
{
|
||||
dparams.aud = std::move(a).get();
|
||||
dparams.has_aud = true;
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::subject_param s, Rest&&... args)
|
||||
{
|
||||
dparams.sub = std::move(s).get();
|
||||
dparams.has_sub = true;
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::validate_iat_param v, Rest&&... args)
|
||||
{
|
||||
dparams.validate_iat = v.get();
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams, typename... Rest>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams, params::detail::validate_jti_param v, Rest&&... args)
|
||||
{
|
||||
dparams.validate_jti = v.get();
|
||||
jwt_object::set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||
}
|
||||
|
||||
template <typename DecodeParams>
|
||||
void jwt_object::set_decode_params(DecodeParams& dparams)
|
||||
{
|
||||
(void) dparams; // prevent -Wunused-parameter with gcc
|
||||
return;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
|
||||
template <typename SequenceT, typename... Args>
|
||||
jwt_object decode(const jwt::string_view enc_str,
|
||||
const params::detail::algorithms_param<SequenceT>& algos,
|
||||
std::error_code& ec,
|
||||
Args&&... args)
|
||||
{
|
||||
ec.clear();
|
||||
jwt_object obj;
|
||||
|
||||
if (algos.get().size() == 0) {
|
||||
ec = DecodeErrc::EmptyAlgoList;
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct decode_params
|
||||
{
|
||||
/// key to decode the JWS
|
||||
bool has_secret = false;
|
||||
std::string secret;
|
||||
|
||||
/// Verify parameter. Defaulted to true.
|
||||
bool verify = true;
|
||||
|
||||
/// Leeway parameter. Defaulted to zero seconds.
|
||||
uint32_t leeway = 0;
|
||||
|
||||
///The issuer
|
||||
//TODO: optional type
|
||||
bool has_issuer = false;
|
||||
std::string issuer;
|
||||
|
||||
///The audience
|
||||
//TODO: optional type
|
||||
bool has_aud = false;
|
||||
std::string aud;
|
||||
|
||||
//The subject
|
||||
//TODO: optional type
|
||||
bool has_sub = false;
|
||||
std::string sub;
|
||||
|
||||
//Validate IAT
|
||||
bool validate_iat = false;
|
||||
|
||||
//Validate JTI
|
||||
bool validate_jti = false;
|
||||
const jwt_payload* payload_ptr = 0;
|
||||
};
|
||||
|
||||
decode_params dparams{};
|
||||
|
||||
|
||||
//Signature must have atleast 2 dots
|
||||
auto dot_cnt = std::count_if(std::begin(enc_str), std::end(enc_str),
|
||||
[](char ch) { return ch == '.'; });
|
||||
if (dot_cnt < 2) {
|
||||
ec = DecodeErrc::SignatureFormatError;
|
||||
return obj;
|
||||
}
|
||||
|
||||
auto parts = jwt_object::three_parts(enc_str);
|
||||
|
||||
//throws decode error
|
||||
jwt_header hdr{};
|
||||
hdr.decode(parts[0], ec);
|
||||
if (ec) {
|
||||
return obj;
|
||||
}
|
||||
//obj.header(jwt_header{parts[0]});
|
||||
obj.header(std::move(hdr));
|
||||
|
||||
//If the algorithm is not NONE, it must not
|
||||
//have more than two dots ('.') and the split
|
||||
//must result in three strings with some length.
|
||||
if (obj.header().algo() != jwt::algorithm::NONE) {
|
||||
if (dot_cnt > 2) {
|
||||
ec = DecodeErrc::SignatureFormatError;
|
||||
return obj;
|
||||
}
|
||||
if (parts[2].length() == 0) {
|
||||
ec = DecodeErrc::SignatureFormatError;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
//throws decode error
|
||||
jwt_payload payload{};
|
||||
payload.decode(parts[1], ec);
|
||||
if (ec) {
|
||||
return obj;
|
||||
}
|
||||
obj.payload(std::move(payload));
|
||||
dparams.payload_ptr = & obj.payload();
|
||||
jwt_object::set_decode_params(dparams, std::forward<Args>(args)...);
|
||||
if (dparams.verify) {
|
||||
try {
|
||||
ec = obj.verify(dparams, algos);
|
||||
} catch (const json_ns::detail::type_error&) {
|
||||
ec = VerificationErrc::TypeConversionError;
|
||||
}
|
||||
|
||||
if (ec) return obj;
|
||||
|
||||
//Verify the signature only if some algorithm was used
|
||||
if (obj.header().algo() != algorithm::NONE)
|
||||
{
|
||||
if (!dparams.has_secret) {
|
||||
ec = DecodeErrc::KeyNotPresent;
|
||||
return obj;
|
||||
}
|
||||
jwt_signature jsign{dparams.secret};
|
||||
|
||||
// Length of the encoded header and payload only.
|
||||
// Addition of '1' to account for the '.' character.
|
||||
auto l = parts[0].length() + 1 + parts[1].length();
|
||||
|
||||
//MemoryAllocationError is not caught
|
||||
verify_result_t res = jsign.verify(obj.header(), enc_str.substr(0, l), parts[2]);
|
||||
if (res.second) {
|
||||
ec = res.second;
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (!res.first) {
|
||||
ec = VerificationErrc::InvalidSignature;
|
||||
return obj;
|
||||
}
|
||||
} else {
|
||||
ec = AlgorithmErrc::NoneAlgorithmUsed;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename SequenceT, typename... Args>
|
||||
jwt_object decode(const jwt::string_view enc_str,
|
||||
const params::detail::algorithms_param<SequenceT>& algos,
|
||||
Args&&... args)
|
||||
{
|
||||
std::error_code ec{};
|
||||
auto jwt_obj = decode(enc_str,
|
||||
algos,
|
||||
ec,
|
||||
std::forward<Args>(args)...);
|
||||
|
||||
if (ec) {
|
||||
jwt_throw_exception(ec);
|
||||
}
|
||||
|
||||
return jwt_obj;
|
||||
}
|
||||
|
||||
|
||||
void jwt_throw_exception(const std::error_code& ec)
|
||||
{
|
||||
const auto& cat = ec.category();
|
||||
|
||||
if (&cat == &theVerificationErrorCategory ||
|
||||
std::string(cat.name()) == std::string(theVerificationErrorCategory.name()))
|
||||
{
|
||||
switch (static_cast<VerificationErrc>(ec.value()))
|
||||
{
|
||||
case VerificationErrc::InvalidAlgorithm:
|
||||
{
|
||||
throw InvalidAlgorithmError(ec.message());
|
||||
}
|
||||
case VerificationErrc::TokenExpired:
|
||||
{
|
||||
throw TokenExpiredError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidIssuer:
|
||||
{
|
||||
throw InvalidIssuerError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidAudience:
|
||||
{
|
||||
throw InvalidAudienceError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidSubject:
|
||||
{
|
||||
throw InvalidSubjectError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidIAT:
|
||||
{
|
||||
throw InvalidIATError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidJTI:
|
||||
{
|
||||
throw InvalidJTIError(ec.message());
|
||||
}
|
||||
case VerificationErrc::ImmatureSignature:
|
||||
{
|
||||
throw ImmatureSignatureError(ec.message());
|
||||
}
|
||||
case VerificationErrc::InvalidSignature:
|
||||
{
|
||||
throw InvalidSignatureError(ec.message());
|
||||
}
|
||||
case VerificationErrc::TypeConversionError:
|
||||
{
|
||||
throw TypeConversionError(ec.message());
|
||||
}
|
||||
default:
|
||||
assert (0 && "Unknown error code");
|
||||
};
|
||||
}
|
||||
|
||||
if (&cat == &theDecodeErrorCategory ||
|
||||
std::string(cat.name()) == std::string(theDecodeErrorCategory.name()))
|
||||
{
|
||||
switch (static_cast<DecodeErrc>(ec.value()))
|
||||
{
|
||||
case DecodeErrc::SignatureFormatError:
|
||||
{
|
||||
throw SignatureFormatError(ec.message());
|
||||
}
|
||||
case DecodeErrc::KeyNotPresent:
|
||||
{
|
||||
throw KeyNotPresentError(ec.message());
|
||||
}
|
||||
case DecodeErrc::KeyNotRequiredForNoneAlg:
|
||||
{
|
||||
// Not an error. Just to be ignored.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw DecodeError(ec.message());
|
||||
}
|
||||
};
|
||||
|
||||
assert (0 && "Unknown error code");
|
||||
}
|
||||
|
||||
if (&cat == &theAlgorithmErrCategory ||
|
||||
std::string(cat.name()) == std::string(theAlgorithmErrCategory.name()))
|
||||
{
|
||||
switch (static_cast<AlgorithmErrc>(ec.value()))
|
||||
{
|
||||
case AlgorithmErrc::InvalidKeyErr:
|
||||
{
|
||||
throw InvalidKeyError(ec.message());
|
||||
}
|
||||
case AlgorithmErrc::VerificationErr:
|
||||
{
|
||||
throw InvalidSignatureError(ec.message());
|
||||
}
|
||||
case AlgorithmErrc::NoneAlgorithmUsed:
|
||||
{
|
||||
//Not an error actually.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert (0 && "Unknown error code or not to be treated as an error");
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
|
||||
#endif
|
87
externals/cpp-jwt/include/jwt/impl/stack_alloc.ipp
vendored
Executable file
87
externals/cpp-jwt/include/jwt/impl/stack_alloc.ipp
vendored
Executable file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2015 Howard Hinnant
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef STACK_ALLOC_IPP
|
||||
#define STACK_ALLOC_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <size_t N, size_t alignment>
|
||||
template <size_t reqested_alignment>
|
||||
char* Arena<N, alignment>::allocate(size_t n) noexcept
|
||||
{
|
||||
static_assert (reqested_alignment <= alignment,
|
||||
"Requested alignment is too small for this arena");
|
||||
|
||||
assert (pointer_in_storage(ptr_) &&
|
||||
"No more space in the arena or it has outgrown its capacity");
|
||||
|
||||
n = align_up(n);
|
||||
|
||||
if ((ptr_ + n) <= (buf_ + N)) {
|
||||
char* ret = ptr_;
|
||||
ptr_ += n;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
assert (0 && "Code should not reach here");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t N, size_t alignment>
|
||||
void Arena<N, alignment>::deallocate(char* p, size_t n) noexcept
|
||||
{
|
||||
assert (pointer_in_storage(p) &&
|
||||
"The address to de deleted does not lie inside the storage");
|
||||
|
||||
n = align_up(n);
|
||||
|
||||
if ((p + n) == ptr_) {
|
||||
ptr_ = p;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename T, size_t N, size_t alignment>
|
||||
T* stack_alloc<T, N, alignment>::allocate(size_t n) noexcept
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
arena_.template allocate<alignof(T)>(n * sizeof(T))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, size_t N, size_t alignment>
|
||||
void stack_alloc<T, N, alignment>::deallocate(T* p, size_t n) noexcept
|
||||
{
|
||||
arena_.deallocate(reinterpret_cast<char*>(p), n);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
339
externals/cpp-jwt/include/jwt/impl/string_view.ipp
vendored
Executable file
339
externals/cpp-jwt/include/jwt/impl/string_view.ipp
vendored
Executable file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
Copyright (c) 2017 Arun Muralidharan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JWT_STRING_VIEW_IPP
|
||||
#define JWT_STRING_VIEW_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type n) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
assert (n < (len_ - pos) && "Comparison size out of bounds");
|
||||
|
||||
if (n == 0) {
|
||||
return pos <= len_ ? pos : npos;
|
||||
}
|
||||
if (n <= len_) {
|
||||
for (; pos <= (len_ - n); ++pos) {
|
||||
if (traits_type::eq(data_[pos], str[0]) &&
|
||||
traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::rfind(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type n) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
assert (pos < len_ && "Position out of bounds");
|
||||
|
||||
if (n <= len_) {
|
||||
pos = std::min(len_ - n, pos);
|
||||
do {
|
||||
if (traits_type::eq(data_[pos], str[0]) &&
|
||||
traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) {
|
||||
return pos;
|
||||
}
|
||||
} while (pos-- != 0);
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find(
|
||||
const CharT ch,
|
||||
size_type pos) const noexcept -> size_type
|
||||
{
|
||||
if (pos < len_) {
|
||||
for (size_type i = pos; i < len_; ++i) {
|
||||
if (traits_type::eq(data_[i], ch)) return i;
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::rfind(
|
||||
const CharT ch,
|
||||
size_type pos) const noexcept -> size_type
|
||||
{
|
||||
if (pos < len_) {
|
||||
do {
|
||||
if (traits_type::eq(data_[pos], ch)) {
|
||||
return pos;
|
||||
}
|
||||
} while (pos-- != 0);
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_first_of(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type count) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
|
||||
for (size_type i = pos; i < len_; ++i) {
|
||||
auto p = traits_type::find(str, count, data_[i]);
|
||||
if (p) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_last_of(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type count) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
assert (pos < len_ && "Position must be within the bounds of the view");
|
||||
size_type siz = len_;
|
||||
|
||||
if (siz && count) {
|
||||
siz = std::min(pos, siz);
|
||||
|
||||
do {
|
||||
auto p = traits_type::find(str, count, data_[siz]);
|
||||
if (p) {
|
||||
return siz;
|
||||
}
|
||||
} while (siz-- != 0);
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_first_not_of(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type n) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
assert (pos < len_&& "Position must be within the bounds of the view");
|
||||
|
||||
for (size_type i = pos; i < len_; ++i)
|
||||
{
|
||||
auto p = traits_type::find(str, n, data_[i]);
|
||||
if (!p) return i;
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_last_not_of(
|
||||
const CharT* str,
|
||||
size_type pos,
|
||||
size_type n) const noexcept -> size_type
|
||||
{
|
||||
assert (str);
|
||||
assert (pos < len_ && "Position must be within the bounds of the view");
|
||||
|
||||
do {
|
||||
for (size_type i = 0; i < n; ++i) {
|
||||
if (!traits_type::eq(data_[pos], str[i])) return pos;
|
||||
}
|
||||
} while (pos-- != 0);
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_first_not_of(
|
||||
CharT ch,
|
||||
size_type pos) const noexcept -> size_type
|
||||
{
|
||||
assert (pos < len_&& "Position must be within the bounds of the view");
|
||||
|
||||
for (size_type i = pos; i < len_; ++i) {
|
||||
if (!traits_type::eq(data_[i], ch)) return i;
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
auto basic_string_view<CharT, Traits>::find_last_not_of(
|
||||
CharT ch,
|
||||
size_type pos) const noexcept -> size_type
|
||||
{
|
||||
assert (pos < len_ && "Position must be within the bounds of the view");
|
||||
|
||||
do {
|
||||
if (!traits_type::eq(data_[pos], ch)) return pos;
|
||||
} while (pos-- != 0);
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
// Comparison Operators
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator== (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
if (a.length() != b.length()) return false;
|
||||
using traits_type = typename basic_string_view<CharT, Traits>::traits_type;
|
||||
using size_type = typename basic_string_view<CharT, Traits>::size_type;
|
||||
|
||||
for (size_type i = 0; i < a.length(); ++i) {
|
||||
if (!traits_type::eq(a[i], b[i])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator!= (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
return !( a == b );
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator< (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator> (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
return a.compare(b) > 0;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator<= (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
return a.compare(b) <= 0;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
bool operator>= (basic_string_view<CharT, Traits> a,
|
||||
basic_string_view<CharT, Traits> b) noexcept
|
||||
{
|
||||
return a.compare(b) >= 0;
|
||||
}
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
std::ostream& operator<< (std::ostream& os, basic_string_view<CharT, Traits> sv)
|
||||
{
|
||||
os.write(sv.data(), sv.length());
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* Copy of gcc implementation of murmurhash
|
||||
* hash_bytes.cc
|
||||
*/
|
||||
|
||||
inline size_t
|
||||
unaligned_load(const char* p) noexcept
|
||||
{
|
||||
std::size_t result;
|
||||
std::memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
hash_bytes(const void* ptr, size_t len, size_t seed) noexcept
|
||||
{
|
||||
const size_t m = 0x5bd1e995;
|
||||
size_t hash = seed ^ len;
|
||||
const char* buf = static_cast<const char*>(ptr);
|
||||
|
||||
// Mix 4 bytes at a time into the hash.
|
||||
while(len >= 4)
|
||||
{
|
||||
size_t k = unaligned_load(buf);
|
||||
k *= m;
|
||||
k ^= k >> 24;
|
||||
k *= m;
|
||||
hash *= m;
|
||||
hash ^= k;
|
||||
buf += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// Handle the last few bytes of the input array.
|
||||
switch(len)
|
||||
{
|
||||
case 3:
|
||||
hash ^= static_cast<unsigned char>(buf[2]) << 16;
|
||||
//FALLTHROUGH
|
||||
case 2:
|
||||
hash ^= static_cast<unsigned char>(buf[1]) << 8;
|
||||
//FALLTHROUGH
|
||||
case 1:
|
||||
hash ^= static_cast<unsigned char>(buf[0]);
|
||||
hash *= m;
|
||||
};
|
||||
|
||||
// Do a few final mixes of the hash.
|
||||
hash ^= hash >> 13;
|
||||
hash *= m;
|
||||
hash ^= hash >> 15;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
/// Provide a hash specialization
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<jwt::string_view>
|
||||
{
|
||||
size_t operator()(const jwt::string_view& sv) const noexcept
|
||||
{
|
||||
return jwt::hash_bytes((void*)sv.data(), sv.length(), static_cast<size_t>(0xc70f6907UL));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user