mirror of
https://github.com/arun11299/cpp-jwt.git
synced 2025-05-15 09:18:33 +00:00
PEM signing now works...silly double pointergit add -A Test code still needs to be removed
This commit is contained in:
parent
5a150780cf
commit
aaf5c9bb46
8 changed files with 233 additions and 9 deletions
|
@ -451,6 +451,11 @@ public:
|
||||||
{
|
{
|
||||||
std::error_code ec{};
|
std::error_code ec{};
|
||||||
|
|
||||||
|
char* out;
|
||||||
|
unsigned int l;
|
||||||
|
std::string ii{data.data(), data.length()};
|
||||||
|
libjwt_sign(&out, &l, ii.c_str(), key.data(), key.length());
|
||||||
|
|
||||||
EC_PKEY_uptr pkey{load_key(key, ec), ev_pkey_deletor};
|
EC_PKEY_uptr pkey{load_key(key, ec), ev_pkey_deletor};
|
||||||
if (ec) return { std::string{}, ec };
|
if (ec) return { std::string{}, ec };
|
||||||
|
|
||||||
|
@ -472,6 +477,9 @@ public:
|
||||||
verify(const string_view key, const string_view head, const string_view sign);
|
verify(const string_view key, const string_view head, const string_view sign);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static void libjwt_sign(char** out, unsigned int *len, const char* str, const char* key, size_t klen);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*/
|
*/
|
||||||
static EVP_PKEY* load_key(const string_view key, std::error_code& ec);
|
static EVP_PKEY* load_key(const string_view key, std::error_code& ec);
|
||||||
|
|
|
@ -174,6 +174,125 @@ verify_result_t PEMSign<Hasher>::verify(
|
||||||
return { true, ec };
|
return { true, ec };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
#define SIGN_ERROR(__err) ({ ret = __err; goto jwt_sign_sha_pem_done; })
|
||||||
|
|
||||||
|
template <typename Hasher>
|
||||||
|
void PEMSign<Hasher>::libjwt_sign(char** out, unsigned int *len, const char* str, const char* key, size_t klen)
|
||||||
|
{
|
||||||
|
ECDSA_SIG *ec_sig = NULL;
|
||||||
|
const BIGNUM *ec_sig_r = NULL;
|
||||||
|
const BIGNUM *ec_sig_s = NULL;
|
||||||
|
const EVP_MD *alg;
|
||||||
|
int type;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
int pkey_type;
|
||||||
|
unsigned char *sig;
|
||||||
|
int ret = 0;
|
||||||
|
size_t slen;
|
||||||
|
|
||||||
|
alg = EVP_sha256();
|
||||||
|
type = EVP_PKEY_EC;
|
||||||
|
|
||||||
|
BIO_uptr bufkey{
|
||||||
|
BIO_new_mem_buf(key, klen),
|
||||||
|
bio_deletor};
|
||||||
|
|
||||||
|
if (!bufkey) {
|
||||||
|
throw MemoryAllocationException("BIO_new_mem_buf failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = PEM_read_bio_PrivateKey(bufkey.get(), NULL, NULL, NULL);
|
||||||
|
if (!pkey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey_type = EVP_PKEY_id(pkey);
|
||||||
|
if (pkey_type != type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_MDCTX_uptr mdctx{EVP_MD_CTX_create(), evp_md_ctx_deletor};
|
||||||
|
if (!mdctx) return;
|
||||||
|
|
||||||
|
EVP_DigestSignInit(mdctx.get(), NULL, alg, NULL, pkey);
|
||||||
|
EVP_DigestSignUpdate(mdctx.get(), str, strlen(str));
|
||||||
|
EVP_DigestSignFinal(mdctx.get(), NULL, &slen);
|
||||||
|
|
||||||
|
sig = (unsigned char*)alloca(slen);
|
||||||
|
|
||||||
|
EVP_DigestSignFinal(mdctx.get(), sig, &slen);
|
||||||
|
|
||||||
|
|
||||||
|
if (pkey_type != EVP_PKEY_EC) {
|
||||||
|
*out = (char*)malloc(slen);
|
||||||
|
if (*out == NULL)
|
||||||
|
SIGN_ERROR(ENOMEM);
|
||||||
|
|
||||||
|
memcpy(*out, sig, slen);
|
||||||
|
*len = slen;
|
||||||
|
} else {
|
||||||
|
unsigned int degree, bn_len, r_len, s_len, buf_len;
|
||||||
|
unsigned char *raw_buf;
|
||||||
|
EC_KEY *ec_key;
|
||||||
|
|
||||||
|
/* For EC we need to convert to a raw format of R/S. */
|
||||||
|
|
||||||
|
/* Get the actual ec_key */
|
||||||
|
ec_key = EVP_PKEY_get1_EC_KEY(pkey);
|
||||||
|
if (ec_key == NULL)
|
||||||
|
SIGN_ERROR(ENOMEM);
|
||||||
|
|
||||||
|
degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key));
|
||||||
|
|
||||||
|
EC_KEY_free(ec_key);
|
||||||
|
|
||||||
|
std::cout << "AAA: " << sig << std::endl;
|
||||||
|
|
||||||
|
/* Get the sig from the DER encoded version. */
|
||||||
|
ec_sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig, slen);
|
||||||
|
if (ec_sig == NULL)
|
||||||
|
SIGN_ERROR(ENOMEM);
|
||||||
|
|
||||||
|
std::cout << "ON YOUR FACE!!" << std::endl;
|
||||||
|
|
||||||
|
ECDSA_SIG_get0(ec_sig, &ec_sig_r, &ec_sig_s);
|
||||||
|
|
||||||
|
r_len = BN_num_bytes(ec_sig_r);
|
||||||
|
s_len = BN_num_bytes(ec_sig_s);
|
||||||
|
bn_len = (degree + 7) / 8;
|
||||||
|
if ((r_len > bn_len) || (s_len > bn_len))
|
||||||
|
SIGN_ERROR(EINVAL);
|
||||||
|
|
||||||
|
buf_len = 2 * bn_len;
|
||||||
|
raw_buf = (unsigned char*)alloca(buf_len);
|
||||||
|
if (raw_buf == NULL)
|
||||||
|
SIGN_ERROR(ENOMEM);
|
||||||
|
|
||||||
|
/* Pad the bignums with leading zeroes. */
|
||||||
|
memset(raw_buf, 0, buf_len);
|
||||||
|
BN_bn2bin(ec_sig_r, raw_buf + bn_len - r_len);
|
||||||
|
BN_bn2bin(ec_sig_s, raw_buf + buf_len - s_len);
|
||||||
|
|
||||||
|
*out = (char*)malloc(buf_len);
|
||||||
|
if (*out == NULL)
|
||||||
|
SIGN_ERROR(ENOMEM);
|
||||||
|
memcpy(*out, raw_buf, buf_len);
|
||||||
|
*len = buf_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt_sign_sha_pem_done:
|
||||||
|
if (pkey)
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
if (ec_sig)
|
||||||
|
ECDSA_SIG_free(ec_sig);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
template <typename Hasher>
|
template <typename Hasher>
|
||||||
EVP_PKEY* PEMSign<Hasher>::load_key(
|
EVP_PKEY* PEMSign<Hasher>::load_key(
|
||||||
const string_view key,
|
const string_view key,
|
||||||
|
@ -189,13 +308,20 @@ EVP_PKEY* PEMSign<Hasher>::load_key(
|
||||||
throw MemoryAllocationException("BIO_new_mem_buf failed");
|
throw MemoryAllocationException("BIO_new_mem_buf failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio_ptr.get(), nullptr, nullptr, nullptr);
|
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(
|
||||||
|
bio_ptr.get(), nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
if (!pkey) {
|
if (!pkey) {
|
||||||
ec = AlgorithmErrc::SigningErr;
|
ec = AlgorithmErrc::SigningErr;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto pkey_type = EVP_PKEY_id(pkey);
|
||||||
|
if (pkey_type != Hasher::type) {
|
||||||
|
ec = AlgorithmErrc::SigningErr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return pkey;
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +334,8 @@ std::string PEMSign<Hasher>::evp_digest(
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
|
||||||
EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor};
|
EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor};
|
||||||
|
std::cout << data << std::endl;
|
||||||
|
std::cout << data.length() << std::endl;
|
||||||
|
|
||||||
if (!mdctx_ptr) {
|
if (!mdctx_ptr) {
|
||||||
throw MemoryAllocationException("EVP_MD_CTX_create failed");
|
throw MemoryAllocationException("EVP_MD_CTX_create failed");
|
||||||
|
@ -223,7 +351,7 @@ std::string PEMSign<Hasher>::evp_digest(
|
||||||
//Update the digest with the input data
|
//Update the digest with the input data
|
||||||
if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) {
|
if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) {
|
||||||
ec = AlgorithmErrc::SigningErr;
|
ec = AlgorithmErrc::SigningErr;
|
||||||
return std::string{};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long len = 0;
|
unsigned long len = 0;
|
||||||
|
@ -265,13 +393,20 @@ std::string PEMSign<Hasher>::public_key_ser(
|
||||||
|
|
||||||
uint32_t degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key.get()));
|
uint32_t degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key.get()));
|
||||||
|
|
||||||
|
ec_key.reset(nullptr);
|
||||||
|
|
||||||
|
auto char_ptr = &sign[0];
|
||||||
|
|
||||||
|
std::cout << "AAA: " << char_ptr << std::endl;
|
||||||
|
|
||||||
EC_SIG_uptr ec_sig{d2i_ECDSA_SIG(nullptr,
|
EC_SIG_uptr ec_sig{d2i_ECDSA_SIG(nullptr,
|
||||||
(const unsigned char**)&sign[0],
|
(const unsigned char**)&char_ptr,
|
||||||
sign.length()),
|
sign.length()),
|
||||||
ec_sig_deletor};
|
ec_sig_deletor};
|
||||||
|
|
||||||
if (!ec_sig) {
|
if (!ec_sig) {
|
||||||
ec = AlgorithmErrc::SigningErr;
|
ec = AlgorithmErrc::SigningErr;
|
||||||
|
std::cout << "1\n";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +421,7 @@ std::string PEMSign<Hasher>::public_key_ser(
|
||||||
|
|
||||||
if ((r_len > bn_len) || (s_len > bn_len)) {
|
if ((r_len > bn_len) || (s_len > bn_len)) {
|
||||||
ec = AlgorithmErrc::SigningErr;
|
ec = AlgorithmErrc::SigningErr;
|
||||||
|
std::cout << "2\n";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,10 @@ std::string jwt_signature::encode(const jwt_header& header,
|
||||||
|
|
||||||
std::string data = hdr_sign + '.' + pld_sign;
|
std::string data = hdr_sign + '.' + pld_sign;
|
||||||
auto res = sign_fn(key_, data);
|
auto res = sign_fn(key_, data);
|
||||||
|
if (res.second) {
|
||||||
|
std::cout << res.second.message() << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::string b64hash = base64_encode(res.first.c_str(), res.first.length());
|
std::string b64hash = base64_encode(res.first.c_str(), res.first.length());
|
||||||
auto new_len = base64_uri_encode(&b64hash[0], b64hash.length());
|
auto new_len = base64_uri_encode(&b64hash[0], b64hash.length());
|
||||||
|
@ -248,16 +252,16 @@ void jwt_object::set_parameters()
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
jwt_payload& jwt_object::add_claim(const string_view name, T&& value)
|
jwt_object& jwt_object::add_claim(const string_view name, T&& value)
|
||||||
{
|
{
|
||||||
payload_.add_claim(name, std::forward<T>(value));
|
payload_.add_claim(name, std::forward<T>(value));
|
||||||
return payload_;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt_payload& jwt_object::remove_claim(const string_view name)
|
jwt_object& jwt_object::remove_claim(const string_view name)
|
||||||
{
|
{
|
||||||
payload_.remove_claim(name);
|
payload_.remove_claim(name);
|
||||||
return payload_;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string jwt_object::signature() const
|
std::string jwt_object::signature() const
|
||||||
|
|
|
@ -541,11 +541,11 @@ public: // Exposed APIs
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
jwt_payload& add_claim(const string_view name, T&& value);
|
jwt_object& add_claim(const string_view name, T&& value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
jwt_payload& remove_claim(const string_view name);
|
jwt_object& remove_claim(const string_view name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
|
BIN
include/jwt/test/test_evp
Executable file
BIN
include/jwt/test/test_evp
Executable file
Binary file not shown.
45
include/jwt/test/test_evp.c
Normal file
45
include/jwt/test/test_evp.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
EVP_MD_CTX *mdctx;
|
||||||
|
const EVP_MD *md;
|
||||||
|
char mess1[] = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaXNzIjoiYXJ1bi5jb20iLCJ0aW1lX3N0ciI6Ijg6MThwbSAyNCBOb3YgMjAxNyIsIndoZXJlIjoiYWlycG9ydCJ9";
|
||||||
|
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||||
|
int md_len, i;
|
||||||
|
|
||||||
|
//OpenSSL_add_all_digests();
|
||||||
|
|
||||||
|
if(!argv[1]) {
|
||||||
|
printf("Usage: mdtest digestname\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
md = EVP_sha256();
|
||||||
|
|
||||||
|
if(!md) {
|
||||||
|
printf("Unknown message digest %s\n", argv[1]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdctx = EVP_MD_CTX_create();
|
||||||
|
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||||
|
EVP_DigestUpdate(mdctx, mess1, strlen(mess1));
|
||||||
|
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
|
||||||
|
EVP_MD_CTX_destroy(mdctx);
|
||||||
|
|
||||||
|
printf("Dig: %s\n", md_value);
|
||||||
|
printf("Dig: %d\n", md_len);
|
||||||
|
|
||||||
|
printf("Digest is: ");
|
||||||
|
for(i = 0; i < md_len; i++)
|
||||||
|
printf("%02x", md_value[i]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
d2i_ECDSA_SIG(NULL, (const unsigned char **)&md_value[0], md_len);
|
||||||
|
|
||||||
|
/* Call this once before exit. */
|
||||||
|
EVP_cleanup();
|
||||||
|
exit(0);
|
||||||
|
}
|
Binary file not shown.
|
@ -44,7 +44,38 @@ void basic_jwt_object_test()
|
||||||
auto dec_obj = jwt::jwt_decode(obj3.signature(), "secret");
|
auto dec_obj = jwt::jwt_decode(obj3.signature(), "secret");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void jwt_object_pem_test()
|
||||||
|
{
|
||||||
|
std::string pub_key =
|
||||||
|
R"(-----BEGIN PUBLIC KEY-----
|
||||||
|
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEomxC9ycc8AkXSwWQpu1kN5Fmgy/sD/KJ
|
||||||
|
qN3tlSZmUEZ3w3c6KYJfK97PMOSZQaUdeydBoq/IOglQQOj8zLqubq5IpaaUiDQ5
|
||||||
|
0eJg79PvXuLiVUH98cBL/o8sDVB/sGzz
|
||||||
|
-----END PUBLIC KEY-----)";
|
||||||
|
|
||||||
|
std::string priv_key =
|
||||||
|
R"(-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT
|
||||||
|
13edeU8YdDugBwYFK4EEACKhZANiAASibEL3JxzwCRdLBZCm7WQ3kWaDL+wP8omo
|
||||||
|
3e2VJmZQRnfDdzopgl8r3s8w5JlBpR17J0Gir8g6CVBA6PzMuq5urkilppSINDnR
|
||||||
|
4mDv0+9e4uJVQf3xwEv+jywNUH+wbPM=
|
||||||
|
-----END EC PRIVATE KEY-----)";
|
||||||
|
|
||||||
|
jwt::jwt_object obj;
|
||||||
|
obj.secret(priv_key);
|
||||||
|
obj.header().algo(jwt::algorithm::ES256);
|
||||||
|
|
||||||
|
obj.add_claim("iss", "arun.com")
|
||||||
|
.add_claim("where", "airport")
|
||||||
|
.add_claim("time_str", "8:18pm 24 Nov 2017")
|
||||||
|
.add_claim("id", 1)
|
||||||
|
;
|
||||||
|
|
||||||
|
std::cout << "pem sign " << obj.signature() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
basic_jwt_object_test();
|
basic_jwt_object_test();
|
||||||
|
jwt_object_pem_test();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue