diff --git a/include/jwt/algorithm.hpp b/include/jwt/algorithm.hpp index becbd98..bacccb1 100644 --- a/include/jwt/algorithm.hpp +++ b/include/jwt/algorithm.hpp @@ -451,6 +451,11 @@ public: { 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}; if (ec) return { std::string{}, ec }; @@ -472,6 +477,9 @@ public: verify(const string_view key, const string_view head, const string_view sign); 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); diff --git a/include/jwt/impl/algorithm.ipp b/include/jwt/impl/algorithm.ipp index ce29e34..0d6c3ef 100644 --- a/include/jwt/impl/algorithm.ipp +++ b/include/jwt/impl/algorithm.ipp @@ -174,6 +174,125 @@ verify_result_t PEMSign::verify( return { true, ec }; } +/////////////////////// + +#define SIGN_ERROR(__err) ({ ret = __err; goto jwt_sign_sha_pem_done; }) + +template +void PEMSign::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 EVP_PKEY* PEMSign::load_key( const string_view key, @@ -189,13 +308,20 @@ EVP_PKEY* PEMSign::load_key( 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) { ec = AlgorithmErrc::SigningErr; return nullptr; } + auto pkey_type = EVP_PKEY_id(pkey); + if (pkey_type != Hasher::type) { + ec = AlgorithmErrc::SigningErr; + return nullptr; + } + return pkey; } @@ -208,6 +334,8 @@ std::string PEMSign::evp_digest( ec.clear(); 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) { throw MemoryAllocationException("EVP_MD_CTX_create failed"); @@ -223,7 +351,7 @@ std::string PEMSign::evp_digest( //Update the digest with the input data if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) { ec = AlgorithmErrc::SigningErr; - return std::string{}; + return {}; } unsigned long len = 0; @@ -265,13 +393,20 @@ std::string PEMSign::public_key_ser( 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, - (const unsigned char**)&sign[0], + (const unsigned char**)&char_ptr, sign.length()), ec_sig_deletor}; if (!ec_sig) { ec = AlgorithmErrc::SigningErr; + std::cout << "1\n"; return {}; } @@ -286,6 +421,7 @@ std::string PEMSign::public_key_ser( if ((r_len > bn_len) || (s_len > bn_len)) { ec = AlgorithmErrc::SigningErr; + std::cout << "2\n"; return {}; } diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index 88b3d67..f34e62d 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -86,6 +86,10 @@ std::string jwt_signature::encode(const jwt_header& header, std::string data = hdr_sign + '.' + pld_sign; 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()); auto new_len = base64_uri_encode(&b64hash[0], b64hash.length()); @@ -248,16 +252,16 @@ void jwt_object::set_parameters() } template -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(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); - return payload_; + return *this; } std::string jwt_object::signature() const diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index 1f2cc3c..8f7ab6c 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -541,11 +541,11 @@ public: // Exposed APIs /** */ template - 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); /** */ diff --git a/include/jwt/test/test_evp b/include/jwt/test/test_evp new file mode 100755 index 0000000..818c82e Binary files /dev/null and b/include/jwt/test/test_evp differ diff --git a/include/jwt/test/test_evp.c b/include/jwt/test/test_evp.c new file mode 100644 index 0000000..7affbc8 --- /dev/null +++ b/include/jwt/test/test_evp.c @@ -0,0 +1,45 @@ +#include + #include + + 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); + } diff --git a/include/jwt/test/test_jwt_object b/include/jwt/test/test_jwt_object index 849029f..c6cd967 100755 Binary files a/include/jwt/test/test_jwt_object and b/include/jwt/test/test_jwt_object differ diff --git a/include/jwt/test/test_jwt_object.cc b/include/jwt/test/test_jwt_object.cc index 7612bfb..e1e14fb 100644 --- a/include/jwt/test/test_jwt_object.cc +++ b/include/jwt/test/test_jwt_object.cc @@ -44,7 +44,38 @@ void basic_jwt_object_test() 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() { basic_jwt_object_test(); + jwt_object_pem_test(); return 0; }