diff --git a/include/jwt/error_codes.hpp b/include/jwt/error_codes.hpp index 13af452..742eeff 100644 --- a/include/jwt/error_codes.hpp +++ b/include/jwt/error_codes.hpp @@ -28,6 +28,7 @@ enum class AlgorithmFailureSource enum class DecodeErrc { EmptyAlgoList = 1, + SignatureFormatError, JsonParseError, AlgHeaderMiss, TypHeaderMiss, diff --git a/include/jwt/exceptions.hpp b/include/jwt/exceptions.hpp index 534cc58..509ef84 100644 --- a/include/jwt/exceptions.hpp +++ b/include/jwt/exceptions.hpp @@ -45,7 +45,7 @@ public: /** */ -class DecodeError final: public std::runtime_error +class DecodeError: public std::runtime_error { public: /** @@ -56,6 +56,19 @@ public: } }; +/** + */ +class SignatureFormatError final : public std::runtime_error +{ +public: + /** + */ + SignatureFormatError(std::string msg) + : std::runtime_error(std::move(msg)) + { + } +}; + /** */ class VerificationError : public std::runtime_error diff --git a/include/jwt/impl/error_codes.ipp b/include/jwt/impl/error_codes.ipp index a1ad64a..2862917 100644 --- a/include/jwt/impl/error_codes.ipp +++ b/include/jwt/impl/error_codes.ipp @@ -47,6 +47,8 @@ struct DecodeErrorCategory: std::error_category { case DecodeErrc::EmptyAlgoList: return "empty algorithm list"; + case DecodeErrc::SignatureFormatError: + return "signature format is incorrect"; case DecodeErrc::AlgHeaderMiss: return "missing algorithm header"; case DecodeErrc::TypHeaderMiss: diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index f85f8f5..c132b02 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -544,11 +544,33 @@ jwt_object decode(const string_view enc_str, decode_params dparams{}; set_decode_params(dparams, std::forward(args)...); + //Signature must have atleast 2 dots + auto dot_cnt = std::count_if(std::begin(enc_str), std::end(enc_str), + [](char ch) { return ch == '.'; }); + if (dot_cnt < 2) { + ec = DecodeErrc::SignatureFormatError; + return obj; + } + auto parts = jwt_object::three_parts(enc_str); //throws decode error obj.header(jwt_header{parts[0]}); + //If the algorithm is not NONE, it must not + //have more than two dots ('.') and the split + //must result in three strings with some length. + if (obj.header().algo() != jwt::algorithm::NONE) { + if (dot_cnt > 2) { + ec = DecodeErrc::SignatureFormatError; + return obj; + } + if (parts[2].length() == 0) { + ec = DecodeErrc::SignatureFormatError; + return obj; + } + } + //throws decode error obj.payload(jwt_payload{parts[1]}); @@ -646,7 +668,19 @@ void jwt_throw_exception(const std::error_code& ec) if (&cat == &theDecodeErrorCategory) { - throw DecodeError(ec.message()); + switch (static_cast(ec.value())) + { + case DecodeErrc::SignatureFormatError: + { + throw SignatureFormatError(ec.message()); + } + default: + { + throw DecodeError(ec.message()); + } + }; + + assert (0 && "Unknown error code"); } if (&cat == &theAlgorithmErrCategory) diff --git a/tests/test_jwt_decode b/tests/test_jwt_decode new file mode 100755 index 0000000..07fe1bd Binary files /dev/null and b/tests/test_jwt_decode differ diff --git a/tests/test_jwt_decode.cc b/tests/test_jwt_decode.cc new file mode 100644 index 0000000..95f0af1 --- /dev/null +++ b/tests/test_jwt_decode.cc @@ -0,0 +1,23 @@ +#include +#include "gtest/gtest.h" +#include "jwt/jwt.hpp" + +TEST (DecodeTest, InvalidFinalDotForNoneAlg) +{ + using namespace jwt::params; + const char* inv_enc_str = + "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ"; + + std::error_code ec; + auto obj = jwt::decode(inv_enc_str, "", algorithms({"none", "hs256"}), ec); + + ASSERT_TRUE (ec); + EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::SignatureFormatError)); +} + + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + return 0; +}