mirror of
https://github.com/arun11299/cpp-jwt.git
synced 2025-05-31 08:57:43 +00:00
Implement verify. Part 1
This commit is contained in:
parent
8277e2cbd3
commit
796abd6e65
10 changed files with 473 additions and 160 deletions
194
include/jwt/impl/algorithm.ipp
Normal file
194
include/jwt/impl/algorithm.ipp
Normal file
|
@ -0,0 +1,194 @@
|
|||
#ifndef CPP_JWT_ALGORITHM_IPP
|
||||
#define CPP_JWT_ALGORITHM_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <typename Hasher>
|
||||
verify_result_t HMACSign<Hasher>::verify(
|
||||
const string_view key,
|
||||
const string_view head,
|
||||
const string_view jwt_sign)
|
||||
{
|
||||
std::error_code ec{};
|
||||
static auto bio_deletor = [](BIO* ptr) {
|
||||
if (ptr) BIO_free_all(ptr);
|
||||
};
|
||||
|
||||
using bio_deletor_t = decltype(bio_deletor);
|
||||
using BIO_unique_ptr = std::unique_ptr<BIO_unique_ptr, bio_deletor_t>;
|
||||
|
||||
BIO_unique_ptr b64{BIO_new(BIO_f_base64())};
|
||||
if (!b64) {
|
||||
//TODO: set error code
|
||||
return {false, ec};
|
||||
}
|
||||
|
||||
BIO* bmem = BIO_new(BIO_s_mem());
|
||||
if (!bmem) {
|
||||
//TODO: set error code
|
||||
return {false, ec};
|
||||
}
|
||||
|
||||
BIO_push(b64, bmem);
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
unsigned char enc_buf[EVP_MAX_MD_SIZE];
|
||||
|
||||
unsigned char* res = HMAC(Hasher{}(),
|
||||
key.data(),
|
||||
key.length(),
|
||||
reinterpret_cast<const unsigned char*>(head.data()),
|
||||
head.length(),
|
||||
enc_buf,
|
||||
&enc_buf_len);
|
||||
|
||||
return {true, ec};
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
sign_result_t PEMSign<Hasher>::load_key(const string_view key)
|
||||
{
|
||||
auto bio_deletor = [](BIO* ptr) {
|
||||
if (ptr) BIO_free(ptr);
|
||||
};
|
||||
|
||||
std::unique_ptr<BIO, decltype(bio_deletor)>
|
||||
bio_ptr{BIO_new_mem_buf((void*)key.data(), key.length()), bio_deletor};
|
||||
|
||||
if (!bio_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio_ptr.get(), nullptr, nullptr, nullptr);
|
||||
if (!pkey) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
std::string PEMSign<Hasher>::evp_digest(
|
||||
EVP_PKEY* pkey,
|
||||
const string_view data,
|
||||
std::error_code& ec)
|
||||
{
|
||||
auto md_deletor = [](EVP_MD_CTX* ptr) {
|
||||
if (ptr) EVP_MD_CTX_destroy(ptr);
|
||||
};
|
||||
|
||||
std::unique_ptr<EVP_MD_CTX, decltype(md_deletor)>
|
||||
mdctx_ptr{EVP_MD_CTX_create(), md_deletor};
|
||||
|
||||
if (!mdctx_ptr) {
|
||||
//TODO: set appropriate error_code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//Initialiaze the digest algorithm
|
||||
if (EVP_DigestSignInit(
|
||||
mdctx_ptr.get(), nullptr, Hasher{}(), nullptr, pkey) != 1) {
|
||||
//TODO: set appropriate error_code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
//Update the digest with the input data
|
||||
if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) {
|
||||
//TODO: set appropriate error_code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
unsigned long len = 0;
|
||||
|
||||
if (EVP_DigestSignFinal(mdctx_ptr.get(), nullptr, &len) != 1) {
|
||||
//TODO: set appropriate error_code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
std::string sign;
|
||||
sign.resize(len);
|
||||
|
||||
//Get the signature
|
||||
if (EVP_DigestSignFinal(mdctx_ptr.get(), (unsigned char*)&sign[0], &len) != 1) {
|
||||
//TODO: set appropriate error_code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
return sign;
|
||||
}
|
||||
|
||||
template <typename Hasher>
|
||||
std::string PEMSign<Hasher>::public_key_ser(
|
||||
EVP_PKEY* pkey,
|
||||
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;
|
||||
|
||||
static auto eckey_deletor = [](EC_KEY* ptr) {
|
||||
if (ptr) EC_KEY_free(ptr);
|
||||
};
|
||||
|
||||
static auto ecsig_deletor = [](ECDSA_SIG* ptr) {
|
||||
if (ptr) ECDSA_SIG_free(ptr);
|
||||
};
|
||||
|
||||
std::unique_ptr<EC_KEY, decltype(eckey_deletor)>
|
||||
ec_key{EVP_PKEY_get1_EC_KEY(pkey), eckey_deletor};
|
||||
|
||||
if (!ec_key) {
|
||||
//TODO set a valid error code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
uint32_t degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key.get()));
|
||||
|
||||
std::unique_ptr<ECDSA_SIG, decltype(ecsig_deletor)>
|
||||
ec_sig{d2i_ECDSA_SIG(nullptr,
|
||||
(const unsigned char**)&sign[0],
|
||||
sign.length()),
|
||||
ecsig_deletor};
|
||||
|
||||
if (!ec_sig) {
|
||||
//TODO set a valid error code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
const BIGNUM* ec_sig_r = nullptr;
|
||||
const BIGNUM* ec_sig_s = nullptr;
|
||||
|
||||
#if 1
|
||||
//Taken from https://github.com/nginnever/zogminer/issues/39
|
||||
auto ECDSA_SIG_get0 = [](const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{
|
||||
if (pr != nullptr) *pr = sig->r;
|
||||
if (ps != nullptr) *ps = sig->s;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
ECDSA_SIG_get0(ec_sig.get(), &ec_sig_r, &ec_sig_s);
|
||||
|
||||
auto r_len = BN_num_bytes(ec_sig_r);
|
||||
auto s_len = BN_num_bytes(ec_sig_s);
|
||||
auto bn_len = (degree + 7) / 8;
|
||||
|
||||
if ((r_len > bn_len) || (s_len > bn_len)) {
|
||||
//TODO set a valid error code
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
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
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef JWT_IPP
|
||||
#define JWT_IPP
|
||||
|
||||
#include "jwt/detail/meta.hpp"
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <typename T>
|
||||
|
@ -23,13 +25,54 @@ std::ostream& write(std::ostream& os, const T& obj, bool pretty)
|
|||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
template <typename T,
|
||||
typename = typename std::enable_if<
|
||||
detail::meta::has_create_json_obj_member<T>{}>::type>
|
||||
std::ostream& operator<< (std::ostream& os, const T& obj)
|
||||
{
|
||||
os << obj.create_json_obj();
|
||||
return os;
|
||||
}
|
||||
|
||||
//========================================================================
|
||||
|
||||
void jwt_header::decode(const string_view enc_str)
|
||||
{
|
||||
std::string json_str = base64_decode(enc_str);
|
||||
json_t obj = json_t::parse(std::move(json_str));
|
||||
|
||||
//Look for the algorithm field
|
||||
auto alg_itr = obj.find("alg");
|
||||
assert (alg_itr != obj.end() && "Algorithm header is missing");
|
||||
std::error_code ec;
|
||||
|
||||
alg_ = str_to_alg(alg_itr.value().get<std::string>());
|
||||
|
||||
if (alg_ != algorithm::NONE) {
|
||||
auto itr = obj.find("typ");
|
||||
if (itr == obj.end()) {
|
||||
//TODO: set error code
|
||||
return;
|
||||
}
|
||||
auto typ = itr.value().get<std::string>();
|
||||
if (strcasecmp(typ.c_str(), "JWT")) {
|
||||
//TODO: set error code
|
||||
return;
|
||||
}
|
||||
typ_ = str_to_type(typ);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void jwt_payload::decode(const string_view enc_str)
|
||||
{
|
||||
std::string json_str = base64_decode(enc_str);
|
||||
payload_ = json_t::parse(std::move(json_str));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string jwt_signature::encode(const jwt_header& header,
|
||||
const jwt_payload& payload)
|
||||
{
|
||||
|
@ -41,9 +84,6 @@ std::string jwt_signature::encode(const jwt_header& header,
|
|||
std::string hdr_sign = header.base64_encode();
|
||||
std::string pld_sign = payload.base64_encode();
|
||||
|
||||
base64_uri_encode(&hdr_sign[0], hdr_sign.length());
|
||||
base64_uri_encode(&pld_sign[0], pld_sign.length());
|
||||
|
||||
std::string data = hdr_sign + '.' + pld_sign;
|
||||
auto res = sign_fn(key_, data);
|
||||
|
||||
|
@ -55,6 +95,15 @@ std::string jwt_signature::encode(const jwt_header& header,
|
|||
return jwt_msg;
|
||||
}
|
||||
|
||||
bool jwt_signature::verify(const jwt_header& header,
|
||||
const string_view hdr_pld_sign,
|
||||
const srting_view jwt_sign)
|
||||
{
|
||||
//TODO: is bool the right choice ?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
sign_func_t
|
||||
jwt_signature::get_algorithm_impl(const jwt_header& hdr) const noexcept
|
||||
|
@ -99,6 +148,33 @@ jwt_signature::get_algorithm_impl(const jwt_header& hdr) const noexcept
|
|||
return ret;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
||||
void jwt_decode(string_view encoded_str, string_view key, bool validate)
|
||||
{
|
||||
//TODO: implement error_code
|
||||
size_t fpos = encoded_str.find_first_of('.');
|
||||
assert (fpos != string_view::npos);
|
||||
|
||||
string_view head{&encoded_str[0], fpos};
|
||||
std::cout << "Head: " << head << std::endl;
|
||||
jwt_header hdr;
|
||||
hdr.decode(head);
|
||||
|
||||
size_t spos = encoded_str.find_first_of('.', fpos + 1);
|
||||
if (spos == string_view::npos) {
|
||||
//TODO: Check for none algorithm
|
||||
}
|
||||
string_view body{&encoded_str[fpos + 1], spos - fpos - 1};
|
||||
std::cout << "Body: " << body << std::endl;
|
||||
|
||||
//Json objects or claims get set in the decode
|
||||
jwt_payload pld;
|
||||
pld.decode(body);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue