diff --git a/include/jwt/.algorithm.hpp.swp b/include/jwt/.algorithm.hpp.swp deleted file mode 100644 index 914ea7d..0000000 Binary files a/include/jwt/.algorithm.hpp.swp and /dev/null differ diff --git a/include/jwt/algorithm.hpp b/include/jwt/algorithm.hpp index f0ed116..6615bbf 100644 --- a/include/jwt/algorithm.hpp +++ b/include/jwt/algorithm.hpp @@ -25,7 +25,7 @@ using sign_func_t = sign_result_t (*) (const string_view key, const string_view data); /// using verify_func_t = verify_result_t (*) (const string_view key, - const string_view header, + const string_view head, const string_view jwt_sign); namespace algo { @@ -215,7 +215,7 @@ struct HMACSign static verify_result_t verify(const string_view key, const string_view head, const string_view sign) { - int compare_res = 0; + bool compare_res = 0; std::error_code ec{}; //TODO: Set the appropriate error code for none @@ -268,6 +268,18 @@ public: return {std::move(sign), ec}; } + /*! + */ + static verify_result_t + verify(const string_view key, const string_view head, const string_view sign) + { + bool compare_res = 0; + std::error_code ec{}; + + //TODO: Set the appropriate error code for none + return {compare_res, ec}; + } + private: /*! */ @@ -284,5 +296,7 @@ private: } // END namespace jwt +#include "jwt/impl/algorithm.ipp" + #endif diff --git a/include/jwt/base64.hpp b/include/jwt/base64.hpp index 77833ba..74fe49c 100644 --- a/include/jwt/base64.hpp +++ b/include/jwt/base64.hpp @@ -189,7 +189,7 @@ std::string base64_decode(const char* in, size_t len) /*! */ -void base64_uri_encode(char* data, size_t len) noexcept +size_t base64_uri_encode(char* data, size_t len) noexcept { size_t i = 0; size_t j = 0; @@ -209,7 +209,7 @@ void base64_uri_encode(char* data, size_t len) noexcept }; } - return; + return j; } /*! @@ -219,7 +219,9 @@ std::string base64_uri_decode(const char* data, size_t len) std::string uri_dec; uri_dec.resize(len + 4); - for (size_t i = 0; i < len; ++i) { + size_t i = 0; + + for (; i < len; ++i) { switch (data[i]) { case '-': uri_dec[i] = '+'; diff --git a/include/jwt/detail/meta.hpp b/include/jwt/detail/meta.hpp index c02642b..752a66d 100644 --- a/include/jwt/detail/meta.hpp +++ b/include/jwt/detail/meta.hpp @@ -26,7 +26,7 @@ template struct has_create_json_obj_member.create_json_obj(), + std::declval().create_json_obj(), (void)0 ) > diff --git a/include/jwt/impl/algorithm.ipp b/include/jwt/impl/algorithm.ipp index b6ec42b..0eb4480 100644 --- a/include/jwt/impl/algorithm.ipp +++ b/include/jwt/impl/algorithm.ipp @@ -1,6 +1,8 @@ #ifndef CPP_JWT_ALGORITHM_IPP #define CPP_JWT_ALGORITHM_IPP +#include + namespace jwt { template @@ -14,10 +16,14 @@ verify_result_t HMACSign::verify( if (ptr) BIO_free_all(ptr); }; - using bio_deletor_t = decltype(bio_deletor); - using BIO_unique_ptr = std::unique_ptr; + std::cout << "Key: " << key << std::endl; + std::cout << "Head: " << head << std::endl; + std::cout << "JWT: " << jwt_sign << std::endl; - BIO_unique_ptr b64{BIO_new(BIO_f_base64())}; + using bio_deletor_t = decltype(bio_deletor); + using BIO_unique_ptr = std::unique_ptr; + + BIO_unique_ptr b64{BIO_new(BIO_f_base64()), bio_deletor}; if (!b64) { //TODO: set error code return {false, ec}; @@ -29,10 +35,11 @@ verify_result_t HMACSign::verify( return {false, ec}; } - BIO_push(b64, bmem); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO_push(b64.get(), bmem); + BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); unsigned char enc_buf[EVP_MAX_MD_SIZE]; + uint32_t enc_buf_len = 0; unsigned char* res = HMAC(Hasher{}(), key.data(), @@ -41,12 +48,36 @@ verify_result_t HMACSign::verify( head.length(), enc_buf, &enc_buf_len); + if (!res) { + //TODO: set error code + return {false, ec}; + } - return {true, ec}; + BIO_write(b64.get(), enc_buf, enc_buf_len); + (void)BIO_flush(b64.get()); + + int len = BIO_pending(bmem); + if (len < 0) { + //TODO: set error code + return {false, ec}; + } + + std::string cbuf; + cbuf.resize(len + 1); + + len = BIO_read(bmem, &cbuf[0], len); + cbuf.resize(len); + + //Make the base64 string url safe + auto new_len = jwt::base64_uri_encode(&cbuf[0], cbuf.length()); + cbuf.resize(new_len); + std::cout << "cbuf: " << cbuf << std::endl; + + return {string_view{cbuf} == jwt_sign, ec}; } template -sign_result_t PEMSign::load_key(const string_view key) +EVP_PKEY* PEMSign::load_key(const string_view key) { auto bio_deletor = [](BIO* ptr) { if (ptr) BIO_free(ptr); diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index fb4c27a..730f8a5 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -79,7 +79,7 @@ std::string jwt_signature::encode(const jwt_header& header, std::string jwt_msg; //TODO: Optimize allocations - sign_func_t sign_fn = get_algorithm_impl(header); + sign_func_t sign_fn = get_sign_algorithm_impl(header); std::string hdr_sign = header.base64_encode(); std::string pld_sign = payload.base64_encode(); @@ -88,7 +88,8 @@ std::string jwt_signature::encode(const jwt_header& header, auto res = sign_fn(key_, data); std::string b64hash = base64_encode(res.first.c_str(), res.first.length()); - base64_uri_encode(&b64hash[0], b64hash.length()); + auto new_len = base64_uri_encode(&b64hash[0], b64hash.length()); + b64hash.resize(new_len); jwt_msg = data + '.' + b64hash; @@ -97,16 +98,18 @@ std::string jwt_signature::encode(const jwt_header& header, bool jwt_signature::verify(const jwt_header& header, const string_view hdr_pld_sign, - const srting_view jwt_sign) + const string_view jwt_sign) { //TODO: is bool the right choice ? + verify_func_t verify_fn = get_verify_algorithm_impl(header); + verify_fn(key_, hdr_pld_sign, jwt_sign); return true; } sign_func_t -jwt_signature::get_algorithm_impl(const jwt_header& hdr) const noexcept +jwt_signature::get_sign_algorithm_impl(const jwt_header& hdr) const noexcept { sign_func_t ret = nullptr; @@ -148,16 +151,61 @@ jwt_signature::get_algorithm_impl(const jwt_header& hdr) const noexcept return ret; } + + +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::verify; + break; + case algorithm::HS384: + ret = HMACSign::verify; + break; + case algorithm::HS512: + ret = HMACSign::verify; + break; + case algorithm::NONE: + ret = HMACSign::verify; + break; + case algorithm::RS256: + ret = PEMSign::verify; + break; + case algorithm::RS384: + ret = PEMSign::verify; + break; + case algorithm::RS512: + ret = PEMSign::verify; + break; + case algorithm::ES256: + ret = PEMSign::verify; + break; + case algorithm::ES384: + ret = PEMSign::verify; + break; + case algorithm::ES512: + ret = PEMSign::verify; + break; + default: + assert (0 && "Code not reached"); + }; + + return ret; +} + + //==================================================================== -void jwt_decode(string_view encoded_str, string_view key, bool validate) +void jwt_decode(const string_view encoded_str, const 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); @@ -166,13 +214,13 @@ void jwt_decode(string_view encoded_str, string_view key, bool validate) //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); - + jwt_signature jsign{key}; + jsign.verify(hdr, encoded_str.substr(0, spos), encoded_str); } } // END namespace jwt diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index ae76d40..0886fd7 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -176,7 +176,7 @@ struct write_interface /*! */ - template + template friend std::ostream& operator<< (std::ostream& os, const T& obj); }; @@ -195,12 +195,9 @@ struct base64_enc_dec { std::string jstr = to_json_str(*static_cast(this), with_pretty); std::string b64_str = jwt::base64_encode(jstr.c_str(), jstr.length()); - size_t rpos = b64_str.length(); - while(b64_str[rpos-1] == '=') rpos--; - // Remove the '=' characters - b64_str.resize(rpos); // Do the URI safe encoding - jwt::base64_uri_encode(&b64_str[0], b64_str.length()); + auto new_len = jwt::base64_uri_encode(&b64_str[0], b64_str.length()); + b64_str.resize(new_len); return b64_str; } @@ -438,7 +435,11 @@ public: // Exposed APIs private: // Private implementation /*! */ - sign_func_t get_algorithm_impl(const jwt_header& hdr) const noexcept; + sign_func_t get_sign_algorithm_impl(const jwt_header& hdr) const noexcept; + + /*! + */ + verify_func_t get_verify_algorithm_impl(const jwt_header& hdr) const noexcept; private: // Data members; /// The key for creating the JWS @@ -461,12 +462,11 @@ private: // Data Members jwt_header header_; /// JWT payload section jwt_payload payload_; - }; /*! */ -void jwt_decode(string_view encoded_str, string_view key, bool validate=true); +void jwt_decode(const string_view encoded_str, const string_view key, bool validate=true); } // END namespace jwt diff --git a/include/jwt/test/test_jwt_decode b/include/jwt/test/test_jwt_decode index 0949716..f6a8bd6 100755 Binary files a/include/jwt/test/test_jwt_decode and b/include/jwt/test/test_jwt_decode differ