diff --git a/include/jwt/algorithm.hpp b/include/jwt/algorithm.hpp index 7dd0f08..becbd98 100644 --- a/include/jwt/algorithm.hpp +++ b/include/jwt/algorithm.hpp @@ -483,6 +483,31 @@ private: /*! */ static std::string public_key_ser(EVP_PKEY* pkey, string_view sign, std::error_code& ec); + + //ATTN: Below 2 functions + //are Taken from https://github.com/nginnever/zogminer/issues/39 + + /** + */ + static void 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; + }; + + /** + */ + static int ECDSA_SIG_set0(ECDSA_SIG* sig, BIGNUM* r, BIGNUM* s) + { + if (r == nullptr || s == nullptr) return 0; + + BN_clear_free(sig->r); + BN_clear_free(sig->s); + + sig->r = r; + sig->s = s; + return 1; + } }; } // END namespace jwt diff --git a/include/jwt/impl/algorithm.ipp b/include/jwt/impl/algorithm.ipp index 6352388..ce29e34 100644 --- a/include/jwt/impl/algorithm.ipp +++ b/include/jwt/impl/algorithm.ipp @@ -77,21 +77,100 @@ verify_result_t PEMSign<Hasher>::verify( const string_view head, const string_view jwt_sign) { - /* - * unsigned char *sig = NULL; - * EVP_MD_CTX *mdctx = NULL; - * ECDSA_SIG *ec_sig = NULL; - * BIGNUM *ec_sig_r = NULL; - * BIGNUM *ec_sig_s = NULL; - * EVP_PKEY *pkey = NULL; - * const EVP_MD *alg; - * int type; - * int pkey_type; - * BIO *bufkey = NULL; - * int ret = 0; - * int slen; - */ 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(), 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::VerificationErr; + 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 }; } @@ -199,16 +278,6 @@ std::string PEMSign<Hasher>::public_key_ser( const BIGNUM* ec_sig_r = nullptr; const BIGNUM* ec_sig_s = nullptr; -#if 1 - //Taken from https://github.com/nginnever/zogminer/issues/39 - static 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); diff --git a/include/jwt/test/test_jwt_object b/include/jwt/test/test_jwt_object index 696b3a1..849029f 100755 Binary files a/include/jwt/test/test_jwt_object and b/include/jwt/test/test_jwt_object differ