├── .github └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── Config.cmake.in ├── cmake_command ├── conanfile.txt ├── examples ├── CMakeFiles │ └── simple_ex1.dir │ │ ├── DependInfo.cmake │ │ ├── cmake_clean.cmake │ │ └── progress.make ├── CMakeLists.txt ├── rsa_256 │ ├── jwtRS256.key │ └── jwtRS256.key.pub ├── simple_ex1.cc ├── simple_ex2.cc └── simple_ex3_rsa.cc ├── include └── jwt │ ├── algorithm.hpp │ ├── assertions.hpp │ ├── base64.hpp │ ├── config.hpp │ ├── detail │ └── meta.hpp │ ├── error_codes.hpp │ ├── exceptions.hpp │ ├── impl │ ├── algorithm.ipp │ ├── error_codes.ipp │ ├── jwt.ipp │ ├── stack_alloc.ipp │ └── string_view.ipp │ ├── json │ ├── json.hpp │ └── test_json.cc │ ├── jwt.hpp │ ├── parameters.hpp │ ├── short_string.hpp │ ├── stack_alloc.hpp │ ├── string_view.hpp │ └── test │ ├── compile.txt │ ├── test_base64 │ ├── test_base64.cc │ ├── test_evp.c │ ├── test_hmac │ ├── test_hmac.cc │ ├── test_jwt_decode │ ├── test_jwt_decode.cc │ ├── test_jwt_header │ ├── test_jwt_header.cc │ ├── test_jwt_object │ ├── test_jwt_object.cc │ ├── test_jwt_payload │ ├── test_jwt_payload.cc │ ├── test_jwt_signature │ ├── test_jwt_signature.cc │ ├── test_rsa │ ├── test_rsa.cc │ ├── test_stack_alloc │ ├── test_stack_alloc.cc │ ├── test_sv │ └── test_sv.cc ├── tests ├── CMakeLists.txt ├── certs │ ├── ec_certs │ │ ├── ec384_priv.pem │ │ └── ec384_pub.pem │ └── rsa_certs │ │ ├── rsa256_priv.pem │ │ ├── rsa256_pub.pem │ │ ├── rsa384_priv.pem │ │ ├── rsa384_pub.pem │ │ ├── rsa512_priv.pem │ │ └── rsa512_pub.pem ├── compile.txt ├── test_jwt_decode.cc ├── test_jwt_decode_verifiy.cc ├── test_jwt_decode_verifiy_with_exception.cc ├── test_jwt_encode.cc ├── test_jwt_es.cc ├── test_jwt_object.cc └── test_jwt_rsa.cc └── vcpkg.json /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | BUILD_TYPE: Debug 7 | CMAKE_ARGS: '-DCMAKE_BUILD_TYPE=Debug -DCPP_JWT_USE_VENDORED_NLOHMANN_JSON=off' 8 | VCPKG_ARGUMENTS: 'nlohmann-json openssl gtest' 9 | VCPKG_VERSION: '6be82cfac67649a31d4c3eba56d2fafa9dc6736a' # May 13, 2022 10 | 11 | jobs: 12 | build: 13 | runs-on: ${{ matrix.config.os }} 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | config: 18 | - { 19 | name: 'Windows/2019/MSVC-19.30.30528.0', 20 | os: windows-2019, 21 | triplet: x64-windows, 22 | parallel: 2, 23 | } 24 | - { 25 | name: 'MacOSX/11/AppleClang-12.0.5.12050022', 26 | os: macos-11, 27 | triplet: x64-osx, 28 | parallel: 3, 29 | } 30 | - { 31 | name: 'Ubuntu/20.04/GCC-9.3.0', 32 | os: ubuntu-20.04, 33 | triplet: x64-linux, 34 | parallel: 2, 35 | } 36 | 37 | steps: 38 | - uses: actions/checkout@v1 39 | 40 | - name: Install vcpkg 41 | uses: lukka/run-vcpkg@v7 42 | with: 43 | vcpkgDirectory: ${{ runner.workspace }}/vcpkg 44 | vcpkgArguments: ${{ env.VCPKG_ARGUMENTS }} 45 | vcpkgGitCommitId: ${{ env.VCPKG_VERSION }} 46 | vcpkgTriplet: ${{ matrix.config.triplet }} 47 | 48 | - name: Configure CMake 49 | run: cmake -B ${{ github.workspace }}/build -DCMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake ${{ env.CMAKE_ARGS }} 50 | 51 | - name: Build 52 | run: cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} --parallel ${{ matrix.config.parallel }} 53 | 54 | - name: Test 55 | working-directory: ${{ github.workspace }}/build 56 | run: ctest -C ${{ env.BUILD_TYPE }} -T test --parallel ${{ matrix.config.parallel }} --output-on-failure --timeout 200 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14.0) 2 | project(cpp-jwt VERSION 1.5.0) 3 | 4 | option(CPP_JWT_BUILD_EXAMPLES "build examples" ON) 5 | option(CPP_JWT_BUILD_TESTS "build tests" ON) 6 | option(CPP_JWT_USE_VENDORED_NLOHMANN_JSON "use vendored json header" ON) 7 | 8 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) 9 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_BINARY_DIR}) 10 | 11 | # only set compiler flags if we are the main project, otherwise let the main 12 | # project decide on the flags 13 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 14 | set(CMAKE_CXX_STANDARD 14) 15 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 16 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" 17 | MATCHES "Clang") 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 19 | endif() 20 | 21 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 23 | endif() 24 | 25 | endif() 26 | 27 | find_package(OpenSSL REQUIRED SSL) 28 | 29 | if(NOT CPP_JWT_USE_VENDORED_NLOHMANN_JSON) 30 | find_package(nlohmann_json REQUIRED) 31 | endif() 32 | 33 | # ############################################################################## 34 | # LIBRARY 35 | # ############################################################################## 36 | 37 | add_library(${PROJECT_NAME} INTERFACE) 38 | target_include_directories( 39 | ${PROJECT_NAME} 40 | INTERFACE $ 41 | $) 42 | target_link_libraries(${PROJECT_NAME} INTERFACE OpenSSL::SSL) 43 | if(NOT CPP_JWT_USE_VENDORED_NLOHMANN_JSON) 44 | target_link_libraries(${PROJECT_NAME} INTERFACE nlohmann_json::nlohmann_json) 45 | else() 46 | target_compile_definitions(${PROJECT_NAME} INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) 47 | endif() 48 | target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_14) 49 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 50 | 51 | # ############################################################################## 52 | # TESTS 53 | # ############################################################################## 54 | 55 | if(CPP_JWT_BUILD_TESTS) 56 | find_package(GTest REQUIRED) 57 | include_directories(${GTEST_INCLUDE_DIRS}) 58 | enable_testing() 59 | # Recurse into the "Hello" and "Demo" subdirectories. This does not actually 60 | # cause another cmake executable to run. The same process will walk through 61 | # the project's entire directory structure. 62 | add_subdirectory(tests) 63 | endif() 64 | 65 | # ############################################################################## 66 | # EXAMPLES 67 | # ############################################################################## 68 | 69 | if(CPP_JWT_BUILD_EXAMPLES) 70 | add_subdirectory(examples) 71 | endif() 72 | 73 | # ############################################################################## 74 | # INSTALL 75 | # ############################################################################## 76 | 77 | include(GNUInstallDirs) 78 | include(CMakePackageConfigHelpers) 79 | set(CPP_JWT_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}) 80 | 81 | install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets) 82 | install( 83 | EXPORT ${PROJECT_NAME}Targets 84 | DESTINATION ${CPP_JWT_CONFIG_INSTALL_DIR} 85 | NAMESPACE ${PROJECT_NAME}:: 86 | COMPONENT dev) 87 | configure_package_config_file(cmake/Config.cmake.in ${PROJECT_NAME}Config.cmake 88 | INSTALL_DESTINATION ${CPP_JWT_CONFIG_INSTALL_DIR} 89 | NO_SET_AND_CHECK_MACRO) 90 | write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake 91 | COMPATIBILITY SameMajorVersion 92 | ARCH_INDEPENDENT) 93 | install( 94 | FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 95 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 96 | DESTINATION ${CPP_JWT_CONFIG_INSTALL_DIR} 97 | COMPONENT dev) 98 | 99 | if(NOT CPP_JWT_USE_VENDORED_NLOHMANN_JSON) 100 | set(CPP_JWT_VENDORED_NLOHMANN_JSON_INSTALL_PATTERN PATTERN "json" EXCLUDE) 101 | endif() 102 | install( 103 | DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/jwt/ 104 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/jwt 105 | COMPONENT dev 106 | FILES_MATCHING 107 | PATTERN "*.hpp" 108 | PATTERN "*.ipp" 109 | PATTERN "test" EXCLUDE 110 | ${CPP_JWT_VENDORED_NLOHMANN_JSON_INSTALL_PATTERN}) 111 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Arun Muralidharan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | 5 | if(NOT @CPP_JWT_USE_VENDORED_NLOHMANN_JSON@) 6 | find_dependency(nlohmann_json) 7 | endif() 8 | 9 | find_dependency(OpenSSL COMPONENTS SSL) 10 | 11 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 12 | check_required_components("@PROJECT_NAME@") 13 | -------------------------------------------------------------------------------- /cmake_command: -------------------------------------------------------------------------------- 1 | cmake -DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2j -DGTEST_ROOT=$HOME/googletest -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | gtest/1.10.0 3 | nlohmann_json/3.7.0 4 | openssl/1.1.1d 5 | 6 | [generators] 7 | cmake_find_package 8 | cmake_paths 9 | 10 | [options] 11 | -------------------------------------------------------------------------------- /examples/CMakeFiles/simple_ex1.dir/DependInfo.cmake: -------------------------------------------------------------------------------- 1 | # The set of languages for which implicit dependencies are needed: 2 | set(CMAKE_DEPENDS_LANGUAGES 3 | "CXX" 4 | ) 5 | # The set of files for implicit dependencies of each language: 6 | set(CMAKE_DEPENDS_CHECK_CXX 7 | "/Users/amuralid/dev_test/cpp-jwt/examples/simple_ex1.cc" "/Users/amuralid/dev_test/cpp-jwt/examples/CMakeFiles/simple_ex1.dir/simple_ex1.cc.o" 8 | ) 9 | set(CMAKE_CXX_COMPILER_ID "Clang") 10 | 11 | # The include file search paths: 12 | set(CMAKE_CXX_TARGET_INCLUDE_PATH 13 | "include" 14 | "/usr/local/Cellar/openssl/1.0.2j/include" 15 | ) 16 | 17 | # Targets to which this target links. 18 | set(CMAKE_TARGET_LINKED_INFO_FILES 19 | ) 20 | 21 | # Fortran module output directory. 22 | set(CMAKE_Fortran_TARGET_MODULE_DIR "") 23 | -------------------------------------------------------------------------------- /examples/CMakeFiles/simple_ex1.dir/cmake_clean.cmake: -------------------------------------------------------------------------------- 1 | file(REMOVE_RECURSE 2 | "CMakeFiles/simple_ex1.dir/simple_ex1.cc.o" 3 | "simple_ex1.pdb" 4 | "simple_ex1" 5 | ) 6 | 7 | # Per-language clean rules from dependency scanning. 8 | foreach(lang CXX) 9 | include(CMakeFiles/simple_ex1.dir/cmake_clean_${lang}.cmake OPTIONAL) 10 | endforeach() 11 | -------------------------------------------------------------------------------- /examples/CMakeFiles/simple_ex1.dir/progress.make: -------------------------------------------------------------------------------- 1 | CMAKE_PROGRESS_1 = 1 2 | CMAKE_PROGRESS_2 = 2 3 | 4 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CERT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rsa_256") 2 | set(CMAKE_CXX_FLAGS 3 | "${CMAKE_CXX_FLAGS} -DCERT_ROOT_DIR=\"\\\"${CERT_ROOT_DIR}\\\"\"") 4 | 5 | add_executable(simple_ex1 simple_ex1.cc) 6 | target_link_libraries(simple_ex1 ${PROJECT_NAME}) 7 | add_test( 8 | NAME simple_ex1 9 | COMMAND ./simple_ex1 10 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 11 | 12 | add_executable(simple_ex2 simple_ex2.cc) 13 | target_link_libraries(simple_ex2 ${PROJECT_NAME}) 14 | add_test( 15 | NAME simple_ex2 16 | COMMAND ./simple_ex2 17 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 18 | 19 | add_executable(simple_ex3_rsa simple_ex3_rsa.cc) 20 | target_link_libraries(simple_ex3_rsa ${PROJECT_NAME}) 21 | add_test( 22 | NAME simple_ex3_rsa 23 | COMMAND ./simple_ex3_rsa 24 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 25 | -------------------------------------------------------------------------------- /examples/rsa_256/jwtRS256.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQC4fkg/JYyN3Skr6RYLiAd/Yhl02TE3/HzHSNPnCaRdUakGp9og 3 | 7oXBMcoadFDjnoSq1sz+gUHnpoO7s2fwkD5Q4OnCBGD3oKP2A4PlOOWD2B2cVmMq 4 | X/vf1nAA/343496jsbfgkh1Q7LTzR0IXfdii0o1UCbvrVCuaBoyiv4TxWQIDAQAB 5 | AoGAWA5uDTWu0Ecuz3aAvyA9896up8bCZyZrp/JqsWs4uBGxyytyQSWXUY6iF95M 6 | fVe7mo7LaO3ottgTKBOJGJjAJKnfwXRn8/NV/Q5oHx48sPGDoUUtyMrRbZpeLM1L 7 | gpFX715XWrtALInWPlVG1OfkQQLv4K7mwveM0cez0bWPUsECQQDuPK9IL7WuO2WR 8 | s6pGEHBc3/MMk6I+vqJ+rJMgJjCC/Wjeyo6U3xTNipJRJL5L/Y8iMqpWCrYOjpo8 9 | +1p4FXqDAkEAxj/FcVhXl3NMco6D9u0LxTAmqavMzmXDmODVW2m1K3+rQWQDqXqr 10 | FQ9WQq0LSsqiwRul6hrd0EmCkNJqpCMN8wJBAIz06uDTGbPVAOuMWhrKbzEEcFHo 11 | p/5n3M0GXqaO8fUO6pWnU2VR+IUEkD3id5WOmLmrMI1oGP/T7/5U2dpjGvECQEBq 12 | 0k4tJXEJvupuUoT2q19scPOq5kaenHrde5ZTd9HljxEVXXdBa7vRGvdZYRTxWQck 13 | Y7n49uBKMom6RXqGBW8CQQCrnub4stg6dwdpnmZmEtAE4VqNSZeV5UWz7+l7+R+B 14 | ENtNlIgyQfE6NpOc3Fr/uy3IQjaHcOOwIKI0GMJww9sC 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /examples/rsa_256/jwtRS256.key.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4fkg/JYyN3Skr6RYLiAd/Yhl0 3 | 2TE3/HzHSNPnCaRdUakGp9og7oXBMcoadFDjnoSq1sz+gUHnpoO7s2fwkD5Q4OnC 4 | BGD3oKP2A4PlOOWD2B2cVmMqX/vf1nAA/343496jsbfgkh1Q7LTzR0IXfdii0o1U 5 | CbvrVCuaBoyiv4TxWQIDAQAB 6 | -----END PUBLIC KEY----- 7 | -------------------------------------------------------------------------------- /examples/simple_ex1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/jwt.hpp" 3 | 4 | int main() { 5 | using namespace jwt::params; 6 | 7 | auto key = "secret"; //Secret to use for the algorithm 8 | //Create JWT object 9 | jwt::jwt_object obj{algorithm("HS256"), payload({{"some", "payload"}}), secret(key)}; 10 | 11 | //Get the encoded string/assertion 12 | auto enc_str = obj.signature(); 13 | std::cout << enc_str << std::endl; 14 | 15 | //Decode 16 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret(key)); 17 | std::cout << dec_obj.header() << std::endl; 18 | std::cout << dec_obj.payload() << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/simple_ex2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "jwt/jwt.hpp" 5 | 6 | int main() { 7 | using namespace jwt::params; 8 | 9 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"user", "admin"}})}; 10 | 11 | //Use add_claim API to add claim values which are 12 | // _not_ strings. 13 | // For eg: `iat` and `exp` claims below. 14 | // Other claims could have been added in the payload 15 | // function above as they are just stringy things. 16 | obj.add_claim("iss", "arun.muralidharan") 17 | .add_claim("sub", "test") 18 | .add_claim("id", "a-b-c-d-e-f-1-2-3") 19 | .add_claim("iat", 1513862371) 20 | .add_claim("exp", std::chrono::system_clock::now() + std::chrono::seconds{10}) 21 | ; 22 | 23 | //Use `has_claim` to check if the claim exists or not 24 | assert (obj.has_claim("iss")); 25 | assert (obj.has_claim("exp")); 26 | 27 | //Use `has_claim_with_value` to check if the claim exists 28 | //with a specific value or not. 29 | assert (obj.payload().has_claim_with_value("id", "a-b-c-d-e-f-1-2-3")); 30 | assert (obj.payload().has_claim_with_value("iat", 1513862371)); 31 | 32 | //Remove a claim using `remove_claim` API. 33 | //Most APIs have an overload which takes enum class type as well 34 | //It can be used interchangeably with strings. 35 | obj.remove_claim(jwt::registered_claims::expiration); 36 | assert (!obj.has_claim("exp")); 37 | 38 | //Using `add_claim` with extra features. 39 | //Check return status and overwrite 40 | assert (!obj.payload().add_claim("sub", "new test", false/*overwrite*/)); 41 | 42 | // Overwrite an existing claim 43 | assert (obj.payload().add_claim("sub", "new test", true/*overwrite*/)); 44 | 45 | assert (obj.payload().has_claim_with_value("sub", "new test")); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/simple_ex3_rsa.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "jwt/jwt.hpp" 7 | 8 | /*** 9 | * STEPS TO GENERATE RSA PRIVATE PUBLIC KEYPAIR. 10 | * 11 | * 1. openssl genrsa -out jwtRS256.key 1024 12 | * 2. openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub 13 | */ 14 | 15 | std::string read_from_file(const std::string& path) 16 | { 17 | std::string contents; 18 | std::ifstream is{path, std::ifstream::binary}; 19 | 20 | if (is) { 21 | // get length of file: 22 | is.seekg (0, is.end); 23 | auto length = is.tellg(); 24 | is.seekg (0, is.beg); 25 | contents.resize(length); 26 | 27 | is.read(&contents[0], length); 28 | if (!is) { 29 | is.close(); 30 | return {}; 31 | } 32 | } else { 33 | std::cerr << "FILE not FOUND!!" << std::endl; 34 | } 35 | 36 | is.close(); 37 | return contents; 38 | } 39 | 40 | int main() { 41 | using namespace jwt::params; 42 | const std::string priv_key_path = std::string{CERT_ROOT_DIR} + "/jwtRS256.key"; 43 | const std::string pub_key_path = std::string{CERT_ROOT_DIR} + "/jwtRS256.key.pub"; 44 | 45 | auto priv_key = read_from_file(priv_key_path); 46 | 47 | jwt::jwt_object obj{algorithm("RS256"), secret(priv_key), payload({{"user", "admin"}})}; 48 | 49 | //Use add_claim API to add claim values which are 50 | // _not_ strings. 51 | // For eg: `iat` and `exp` claims below. 52 | // Other claims could have been added in the payload 53 | // function above as they are just stringy things. 54 | obj.add_claim("iss", "arun.muralidharan") 55 | .add_claim("sub", "test") 56 | .add_claim("id", "a-b-c-d-e-f-1-2-3") 57 | .add_claim("iat", 1513862371) 58 | .add_claim("exp", std::chrono::system_clock::now() + std::chrono::seconds{10}) 59 | ; 60 | 61 | //Use `has_claim` to check if the claim exists or not 62 | assert (obj.has_claim("iss")); 63 | assert (obj.has_claim("exp")); 64 | 65 | //Use `has_claim_with_value` to check if the claim exists 66 | //with a specific value or not. 67 | assert (obj.payload().has_claim_with_value("id", "a-b-c-d-e-f-1-2-3")); 68 | assert (obj.payload().has_claim_with_value("iat", 1513862371)); 69 | 70 | auto pub_key = read_from_file(pub_key_path); 71 | 72 | std::error_code ec{}; 73 | auto sign = obj.signature(ec); 74 | if (ec) { 75 | std::cerr << ec.message() << std::endl; 76 | return 1; 77 | } 78 | 79 | auto dec_obj = jwt::decode(sign, algorithms({"RS256"}), verify(false), secret(pub_key)); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /include/jwt/algorithm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_ALGORITHM_HPP 24 | #define CPP_JWT_ALGORITHM_HPP 25 | 26 | /*! 27 | * Most of the signing and verification code has been taken 28 | * and modified for C++ specific use from the C implementation 29 | * JWT library, libjwt. 30 | * https://github.com/benmcollins/libjwt/tree/master/libjwt 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "jwt/assertions.hpp" 47 | #include "jwt/exceptions.hpp" 48 | #include "jwt/string_view.hpp" 49 | #include "jwt/error_codes.hpp" 50 | #include "jwt/base64.hpp" 51 | #include "jwt/config.hpp" 52 | 53 | namespace jwt { 54 | 55 | /// The result type of the signing function 56 | using sign_result_t = std::pair; 57 | /// The result type of verification function 58 | using verify_result_t = std::pair; 59 | /// The function pointer type for the signing function 60 | using sign_func_t = sign_result_t (*) (const jwt::string_view key, 61 | const jwt::string_view data); 62 | /// The function pointer type for the verifying function 63 | using verify_func_t = verify_result_t (*) (const jwt::string_view key, 64 | const jwt::string_view head, 65 | const jwt::string_view jwt_sign); 66 | 67 | namespace algo { 68 | 69 | //Me: TODO: All these can be done using code generaion. 70 | //Me: NO. NEVER. I hate Macros. 71 | //Me: You can use templates too. 72 | //Me: No. I would rather prefer explicit. 73 | //Me: Ok. You win. 74 | //Me: Same to you. 75 | 76 | /** 77 | * HS256 algorithm. 78 | */ 79 | struct HS256 80 | { 81 | const EVP_MD* operator()() noexcept 82 | { 83 | return EVP_sha256(); 84 | } 85 | }; 86 | 87 | /** 88 | * HS384 algorithm. 89 | */ 90 | struct HS384 91 | { 92 | const EVP_MD* operator()() noexcept 93 | { 94 | return EVP_sha384(); 95 | } 96 | }; 97 | 98 | /** 99 | * HS512 algorithm. 100 | */ 101 | struct HS512 102 | { 103 | const EVP_MD* operator()() noexcept 104 | { 105 | return EVP_sha512(); 106 | } 107 | }; 108 | 109 | /** 110 | * NONE algorithm. 111 | */ 112 | struct NONE 113 | { 114 | void operator()() noexcept 115 | { 116 | return; 117 | } 118 | }; 119 | 120 | /** 121 | * RS256 algorithm. 122 | */ 123 | struct RS256 124 | { 125 | static const int type = EVP_PKEY_RSA; 126 | 127 | const EVP_MD* operator()() noexcept 128 | { 129 | return EVP_sha256(); 130 | } 131 | }; 132 | 133 | /** 134 | * RS384 algorithm. 135 | */ 136 | struct RS384 137 | { 138 | static const int type = EVP_PKEY_RSA; 139 | 140 | const EVP_MD* operator()() noexcept 141 | { 142 | return EVP_sha384(); 143 | } 144 | }; 145 | 146 | /** 147 | * RS512 algorithm. 148 | */ 149 | struct RS512 150 | { 151 | static const int type = EVP_PKEY_RSA; 152 | 153 | const EVP_MD* operator()() noexcept 154 | { 155 | return EVP_sha512(); 156 | } 157 | }; 158 | 159 | /** 160 | * ES256 algorithm. 161 | */ 162 | struct ES256 163 | { 164 | static const int type = EVP_PKEY_EC; 165 | 166 | const EVP_MD* operator()() noexcept 167 | { 168 | return EVP_sha256(); 169 | } 170 | }; 171 | 172 | /** 173 | * ES384 algorithm. 174 | */ 175 | struct ES384 176 | { 177 | static const int type = EVP_PKEY_EC; 178 | 179 | const EVP_MD* operator()() noexcept 180 | { 181 | return EVP_sha384(); 182 | } 183 | }; 184 | 185 | /** 186 | * ES512 algorithm. 187 | */ 188 | struct ES512 189 | { 190 | static const int type = EVP_PKEY_EC; 191 | 192 | const EVP_MD* operator()() noexcept 193 | { 194 | return EVP_sha512(); 195 | } 196 | }; 197 | 198 | } //END Namespace algo 199 | 200 | 201 | /** 202 | * JWT signing algorithm types. 203 | */ 204 | enum class algorithm 205 | { 206 | NONE = 0, 207 | HS256, 208 | HS384, 209 | HS512, 210 | RS256, 211 | RS384, 212 | RS512, 213 | ES256, 214 | ES384, 215 | ES512, 216 | UNKN, 217 | TERM, 218 | }; 219 | 220 | 221 | /** 222 | * Convert the algorithm enum class type to 223 | * its stringified form. 224 | */ 225 | inline jwt::string_view alg_to_str(SCOPED_ENUM algorithm alg) noexcept 226 | { 227 | switch (alg) { 228 | case algorithm::HS256: return "HS256"; 229 | case algorithm::HS384: return "HS384"; 230 | case algorithm::HS512: return "HS512"; 231 | case algorithm::RS256: return "RS256"; 232 | case algorithm::RS384: return "RS384"; 233 | case algorithm::RS512: return "RS512"; 234 | case algorithm::ES256: return "ES256"; 235 | case algorithm::ES384: return "ES384"; 236 | case algorithm::ES512: return "ES512"; 237 | case algorithm::TERM: return "TERM"; 238 | case algorithm::NONE: return "NONE"; 239 | case algorithm::UNKN: return "UNKN"; 240 | default: assert (0 && "Unknown Algorithm"); 241 | }; 242 | return "UNKN"; 243 | JWT_NOT_REACHED("Code not reached"); 244 | } 245 | 246 | /** 247 | * Convert stringified algorithm to enum class. 248 | * The string comparison is case insesitive. 249 | */ 250 | inline SCOPED_ENUM algorithm str_to_alg(const jwt::string_view alg) noexcept 251 | { 252 | if (!alg.length()) return algorithm::UNKN; 253 | 254 | if (!strcasecmp(alg.data(), "NONE")) return algorithm::NONE; 255 | if (!strcasecmp(alg.data(), "HS256")) return algorithm::HS256; 256 | if (!strcasecmp(alg.data(), "HS384")) return algorithm::HS384; 257 | if (!strcasecmp(alg.data(), "HS512")) return algorithm::HS512; 258 | if (!strcasecmp(alg.data(), "RS256")) return algorithm::RS256; 259 | if (!strcasecmp(alg.data(), "RS384")) return algorithm::RS384; 260 | if (!strcasecmp(alg.data(), "RS512")) return algorithm::RS512; 261 | if (!strcasecmp(alg.data(), "ES256")) return algorithm::ES256; 262 | if (!strcasecmp(alg.data(), "ES384")) return algorithm::ES384; 263 | if (!strcasecmp(alg.data(), "ES512")) return algorithm::ES512; 264 | 265 | return algorithm::UNKN; 266 | 267 | JWT_NOT_REACHED("Code not reached"); 268 | } 269 | 270 | /** 271 | */ 272 | inline void bio_deletor(BIO* ptr) 273 | { 274 | if (ptr) BIO_free_all(ptr); 275 | } 276 | 277 | /** 278 | */ 279 | inline void evp_md_ctx_deletor(EVP_MD_CTX* ptr) 280 | { 281 | if (ptr) EVP_MD_CTX_destroy(ptr); 282 | } 283 | 284 | /** 285 | */ 286 | inline void ec_key_deletor(EC_KEY* ptr) 287 | { 288 | if (ptr) EC_KEY_free(ptr); 289 | } 290 | 291 | /** 292 | */ 293 | inline void ec_sig_deletor(ECDSA_SIG* ptr) 294 | { 295 | if (ptr) ECDSA_SIG_free(ptr); 296 | } 297 | 298 | /** 299 | */ 300 | inline void ev_pkey_deletor(EVP_PKEY* ptr) 301 | { 302 | if (ptr) EVP_PKEY_free(ptr); 303 | } 304 | 305 | /// Useful typedefs 306 | using bio_deletor_t = decltype(&bio_deletor); 307 | using BIO_uptr = std::unique_ptr; 308 | 309 | using evp_mdctx_deletor_t = decltype(&evp_md_ctx_deletor); 310 | using EVP_MDCTX_uptr = std::unique_ptr; 311 | 312 | using eckey_deletor_t = decltype(&ec_key_deletor); 313 | using EC_KEY_uptr = std::unique_ptr; 314 | 315 | using ecsig_deletor_t = decltype(&ec_sig_deletor); 316 | using EC_SIG_uptr = std::unique_ptr; 317 | 318 | using evpkey_deletor_t = decltype(&ev_pkey_deletor); 319 | using EC_PKEY_uptr = std::unique_ptr; 320 | 321 | 322 | 323 | /** 324 | * OpenSSL HMAC based signature and verfication. 325 | * 326 | * The template type `Hasher` takes the type representing 327 | * the HMAC algorithm type from the `jwt::algo` namespace. 328 | * 329 | * The struct is specialized for NONE algorithm. See the 330 | * details of that class as well. 331 | */ 332 | template 333 | struct HMACSign 334 | { 335 | /// The type of Hashing algorithm 336 | using hasher_type = Hasher; 337 | 338 | /** 339 | * Signs the input using the HMAC algorithm using the 340 | * provided key. 341 | * 342 | * Arguments: 343 | * @key : The secret/key to use for the signing. 344 | * Cannot be empty string. 345 | * @data : The data to be signed. 346 | * 347 | * Exceptions: 348 | * Any allocation failure will result in jwt::MemoryAllocationException 349 | * being thrown. 350 | */ 351 | static sign_result_t sign(const jwt::string_view key, const jwt::string_view data) 352 | { 353 | std::string sign; 354 | sign.resize(EVP_MAX_MD_SIZE); 355 | std::error_code ec{}; 356 | 357 | uint32_t len = 0; 358 | 359 | unsigned char* res = HMAC(Hasher{}(), 360 | key.data(), 361 | static_cast(key.length()), 362 | reinterpret_cast(data.data()), 363 | data.length(), 364 | reinterpret_cast(&sign[0]), 365 | &len); 366 | if (!res) { 367 | ec = AlgorithmErrc::SigningErr; 368 | } 369 | 370 | sign.resize(len); 371 | return { std::move(sign), ec }; 372 | } 373 | 374 | /** 375 | * Verifies the JWT string against the signature using 376 | * the provided key. 377 | * 378 | * Arguments: 379 | * @key : The secret/key to use for the signing. 380 | * Cannot be empty string. 381 | * @head : The part of JWT encoded string representing header 382 | * and the payload claims. 383 | * @sign : The signature part of the JWT encoded string. 384 | * 385 | * Returns: 386 | * verify_result_t 387 | * verify_result_t::first set to true if verification succeeds. 388 | * false otherwise. 389 | * verify_result_t::second set to relevant error if verification fails. 390 | * 391 | * Exceptions: 392 | * Any allocation failure will result in jwt::MemoryAllocationException 393 | * being thrown. 394 | */ 395 | static verify_result_t 396 | verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign); 397 | 398 | }; 399 | 400 | /** 401 | * Specialization of `HMACSign` class 402 | * for NONE algorithm. 403 | * 404 | * This specialization is selected for even 405 | * PEM based algorithms. 406 | * 407 | * The signing and verification APIs are 408 | * basically no-op except that they would 409 | * set the relevant error code. 410 | * 411 | * NOTE: error_code would be set in the case 412 | * of usage of NONE algorithm. 413 | * Users of this API are expected to check for 414 | * the case explicitly. 415 | */ 416 | template <> 417 | struct HMACSign 418 | { 419 | using hasher_type = algo::NONE; 420 | 421 | /** 422 | * Basically a no-op. Sets the error code to NoneAlgorithmUsed. 423 | */ 424 | static sign_result_t sign(const jwt::string_view key, const jwt::string_view data) 425 | { 426 | (void)key; 427 | (void)data; 428 | std::error_code ec{}; 429 | ec = AlgorithmErrc::NoneAlgorithmUsed; 430 | 431 | return { std::string{}, ec }; 432 | } 433 | 434 | /** 435 | * Basically a no-op. Sets the error code to NoneAlgorithmUsed. 436 | */ 437 | static verify_result_t 438 | verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign) 439 | { 440 | (void)key; 441 | (void)head; 442 | (void)sign; 443 | std::error_code ec{}; 444 | ec = AlgorithmErrc::NoneAlgorithmUsed; 445 | 446 | return { true, ec }; 447 | } 448 | 449 | }; 450 | 451 | 452 | 453 | /** 454 | * OpenSSL PEM based signature and verfication. 455 | * 456 | * The template type `Hasher` takes the type representing 457 | * the PEM algorithm type from the `jwt::algo` namespace. 458 | * 459 | * For NONE algorithm, HMACSign<> specialization is used. 460 | * See that for more details. 461 | */ 462 | template 463 | struct PEMSign 464 | { 465 | public: 466 | /// The type of Hashing algorithm 467 | using hasher_type = Hasher; 468 | 469 | /** 470 | * Signs the input data using PEM encryption algorithm. 471 | * 472 | * Arguments: 473 | * @key : The key/secret to be used for signing. 474 | * Cannot be an empty string. 475 | * @data: The data to be signed. 476 | * 477 | * Exceptions: 478 | * Any allocation failure would be thrown out as 479 | * jwt::MemoryAllocationException. 480 | */ 481 | static sign_result_t sign(const jwt::string_view key, const jwt::string_view data) 482 | { 483 | std::error_code ec{}; 484 | 485 | std::string ii{data.data(), data.length()}; 486 | 487 | EC_PKEY_uptr pkey{load_key(key, ec), ev_pkey_deletor}; 488 | if (ec) return { std::string{}, ec }; 489 | 490 | //TODO: Use stack string here ? 491 | std::string sign = evp_digest(pkey.get(), data, ec); 492 | 493 | if (ec) return { std::string{}, ec }; 494 | 495 | if (Hasher::type == EVP_PKEY_EC) { 496 | sign = public_key_ser(pkey.get(), sign, ec); 497 | } 498 | 499 | return { std::move(sign), ec }; 500 | } 501 | 502 | /** 503 | */ 504 | static verify_result_t 505 | verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign); 506 | 507 | private: 508 | 509 | /*! 510 | */ 511 | static EVP_PKEY* load_key(const jwt::string_view key, std::error_code& ec); 512 | 513 | /*! 514 | */ 515 | static std::string evp_digest(EVP_PKEY* pkey, const jwt::string_view data, std::error_code& ec); 516 | 517 | /*! 518 | */ 519 | static std::string public_key_ser(EVP_PKEY* pkey, jwt::string_view sign, std::error_code& ec); 520 | 521 | #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L 522 | 523 | 524 | //ATTN: Below 2 functions 525 | //are Taken from https://github.com/nginnever/zogminer/issues/39 526 | 527 | /** 528 | */ 529 | static void ECDSA_SIG_get0(const ECDSA_SIG* sig, const BIGNUM** pr, const BIGNUM** ps) 530 | { 531 | if (pr != nullptr) *pr = sig->r; 532 | if (ps != nullptr) *ps = sig->s; 533 | }; 534 | 535 | /** 536 | */ 537 | static int ECDSA_SIG_set0(ECDSA_SIG* sig, BIGNUM* r, BIGNUM* s) 538 | { 539 | if (r == nullptr || s == nullptr) return 0; 540 | 541 | BN_clear_free(sig->r); 542 | BN_clear_free(sig->s); 543 | 544 | sig->r = r; 545 | sig->s = s; 546 | return 1; 547 | } 548 | 549 | #endif 550 | }; 551 | 552 | } // END namespace jwt 553 | 554 | #include "jwt/impl/algorithm.ipp" 555 | 556 | 557 | #endif 558 | -------------------------------------------------------------------------------- /include/jwt/assertions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_ASSERTIONS_HPP 24 | #define CPP_JWT_ASSERTIONS_HPP 25 | 26 | #include 27 | 28 | namespace jwt { 29 | 30 | #if defined(__clang__) 31 | # define JWT_NOT_REACHED_MARKER() __builtin_unreachable() 32 | #elif defined(__GNUC__) 33 | # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 34 | # define JWT_NOT_REACHED_MARKER() __builtin_unreachable() 35 | # endif 36 | #elif defined(_MSC_VER) 37 | # define JWT_NOT_REACHED_MARKER() __assume(0) 38 | #endif 39 | 40 | #if defined(DEBUG) 41 | # define JWT_NOT_REACHED(reason) do { \ 42 | assert (0 && reason); \ 43 | JWT_NOT_REACHED_MARKER(); \ 44 | } while (0) 45 | #else 46 | # define JWT_NOT_REACHED(reason) JWT_NOT_REACHED_MARKER() 47 | #endif 48 | 49 | } // END namespace jwt 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/jwt/base64.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_BASE64_HPP 24 | #define CPP_JWT_BASE64_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "jwt/config.hpp" 31 | #include "jwt/string_view.hpp" 32 | 33 | namespace jwt { 34 | 35 | // Returns the maximum number of bytes required to 36 | // encode an input byte string of length `n` to base64. 37 | inline constexpr 38 | size_t encoding_size(size_t n) 39 | { 40 | return 4 * ((n + 2) / 3); 41 | } 42 | 43 | 44 | // Returns the maximum number of bytes required 45 | // to store a decoded base64 byte string. 46 | inline constexpr 47 | size_t decoding_size(size_t n) 48 | { 49 | return n / 4 * 3; 50 | } 51 | 52 | /** 53 | * Encoding map. 54 | * A constexpr helper class for performing base64 55 | * encoding on the input byte string. 56 | */ 57 | class EMap 58 | { 59 | public: 60 | constexpr EMap() = default; 61 | 62 | public: 63 | constexpr char at(size_t pos) const noexcept 64 | { 65 | return X_ASSERT(pos < chars_.size()), chars_.at(pos); 66 | } 67 | 68 | private: 69 | std::array chars_ = {{ 70 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 71 | 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 72 | '0','1','2','3','4','5','6','7','8','9', 73 | '+','/', 74 | }}; 75 | }; 76 | 77 | /** 78 | * Encodes a sequence of octet into base64 string. 79 | * Returns std::string resized to contain only the 80 | * encoded data (as usual without null terminator). 81 | * 82 | * The encoded string is atleast `encoding_size(input len)` 83 | * in size. 84 | * 85 | * Arguments: 86 | * @in : Input byte string to be encoded. 87 | * @len : Length of the input byte string. 88 | */ 89 | inline std::string base64_encode(const char* in, size_t len) 90 | { 91 | std::string result; 92 | const auto encoded_siz = encoding_size(len); 93 | result.resize(encoded_siz); 94 | 95 | constexpr static const EMap emap{}; 96 | 97 | int i = 0; 98 | int j = 0; 99 | for (; i < static_cast(len) - 2; i += 3) { 100 | const auto first = in[i]; 101 | const auto second = in[i+1]; 102 | const auto third = in[i+2]; 103 | 104 | result[j++] = emap.at( (first >> 2) & 0x3F ); 105 | result[j++] = emap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4)); 106 | result[j++] = emap.at(((second & 0x0F) << 2) | ((third & 0xC0) >> 6)); 107 | result[j++] = emap.at( (third & 0x3F) ); 108 | } 109 | 110 | switch (len % 3) { 111 | case 2: 112 | { 113 | const auto first = in[i]; 114 | const auto second = in[i+1]; 115 | 116 | result[j++] = emap.at( (first >> 2) & 0x3F ); 117 | result[j++] = emap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4)); 118 | result[j++] = emap.at( (second & 0x0F) << 2 ); 119 | result[j++] = '='; 120 | break; 121 | } 122 | case 1: 123 | { 124 | const auto first = in[i]; 125 | 126 | result[j++] = emap.at((first >> 2) & 0x3F); 127 | result[j++] = emap.at((first & 0x03) << 4); 128 | result[j++] = '='; 129 | result[j++] = '='; 130 | break; 131 | } 132 | case 0: 133 | break; 134 | }; 135 | 136 | result.resize(j); 137 | 138 | return result; 139 | } 140 | 141 | 142 | 143 | //======================= Decoder ========================== 144 | 145 | /** 146 | * Decoding map. 147 | * A helper constexpr class for providing interface 148 | * to the decoding map for base64. 149 | */ 150 | class DMap 151 | { 152 | public: 153 | constexpr DMap() = default; 154 | 155 | public: 156 | constexpr signed char at(size_t pos) const noexcept 157 | { 158 | return X_ASSERT(pos < map_.size()), map_[pos]; 159 | } 160 | 161 | private: 162 | std::array map_ = {{ 163 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15 164 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31 165 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47 166 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63 167 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79 168 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95 169 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111 170 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127 171 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143 172 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159 173 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175 174 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191 175 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207 176 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223 177 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239 178 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255 179 | }}; 180 | }; 181 | 182 | /** 183 | * Decodes octet of base64 encoded byte string. 184 | * 185 | * Returns a std::string with the decoded byte string. 186 | * 187 | * Arguments: 188 | * @in : Encoded base64 byte string. 189 | * @len : Length of the encoded input byte string. 190 | */ 191 | inline std::string base64_decode(const char* in, size_t len) 192 | { 193 | std::string result; 194 | const auto decoded_siz = decoding_size(len); 195 | result.resize(decoded_siz); 196 | 197 | int i = 0; 198 | size_t bytes_rem = len; 199 | size_t bytes_wr = 0; 200 | 201 | constexpr static const DMap dmap{}; 202 | 203 | while (bytes_rem > 0 && dmap.at(in[bytes_rem - 1]) == -1) { bytes_rem--; } 204 | 205 | while (bytes_rem > 4) 206 | { 207 | // Error case in input 208 | if (dmap.at(*in) == -1) return result; 209 | 210 | const auto first = dmap.at(in[0]); 211 | const auto second = dmap.at(in[1]); 212 | const auto third = dmap.at(in[2]); 213 | const auto fourth = dmap.at(in[3]); 214 | 215 | result[i] = (first << 2) | (second >> 4); 216 | result[i + 1] = (second << 4) | (third >> 2); 217 | result[i + 2] = (third << 6) | fourth; 218 | 219 | bytes_rem -= 4; 220 | i += 3; 221 | in += 4; 222 | } 223 | bytes_wr = i; 224 | 225 | switch(bytes_rem) { 226 | case 4: 227 | { 228 | const auto third = dmap.at(in[2]); 229 | const auto fourth = dmap.at(in[3]); 230 | result[i + 2] = (third << 6) | fourth; 231 | bytes_wr++; 232 | } 233 | //FALLTHROUGH 234 | case 3: 235 | { 236 | const auto second = dmap.at(in[1]); 237 | const auto third = dmap.at(in[2]); 238 | result[i + 1] = (second << 4) | (third >> 2); 239 | bytes_wr++; 240 | } 241 | //FALLTHROUGH 242 | case 2: 243 | { 244 | const auto first = dmap.at(in[0]); 245 | const auto second = dmap.at(in[1]); 246 | result[i] = (first << 2) | (second >> 4); 247 | bytes_wr++; 248 | } 249 | }; 250 | 251 | result.resize(bytes_wr); 252 | 253 | return result; 254 | } 255 | 256 | /** 257 | * Makes the base64 encoded byte string URL safe. 258 | * Overwrites/skips few URL unsafe characters 259 | * from the input sequence. 260 | * 261 | * Arguments: 262 | * @data : Base64 encoded byte string. 263 | * @len : Length of the base64 byte string. 264 | * 265 | * Returns: 266 | * Length of the URL safe base64 encoded byte string. 267 | */ 268 | inline size_t base64_uri_encode(char* data, size_t len) noexcept 269 | { 270 | size_t i = 0; 271 | size_t j = 0; 272 | 273 | for (; i < len; ++i) { 274 | switch (data[i]) { 275 | case '+': 276 | data[j++] = '-'; 277 | break; 278 | case '/': 279 | data[j++] = '_'; 280 | break; 281 | case '=': 282 | break; 283 | default: 284 | data[j++] = data[i]; 285 | }; 286 | } 287 | 288 | return j; 289 | } 290 | 291 | /** 292 | * Decodes an input URL safe base64 encoded byte string. 293 | * 294 | * NOTE: To be used only for decoding URL safe base64 encoded 295 | * byte string. 296 | * 297 | * Arguments: 298 | * @data : URL safe base64 encoded byte string. 299 | * @len : Length of the input byte string. 300 | */ 301 | inline std::string base64_uri_decode(const char* data, size_t len) 302 | { 303 | std::string uri_dec; 304 | uri_dec.resize(len + 4); 305 | 306 | size_t i = 0; 307 | 308 | for (; i < len; ++i) 309 | { 310 | switch (data[i]) { 311 | case '-': 312 | uri_dec[i] = '+'; 313 | break; 314 | case '_': 315 | uri_dec[i] = '/'; 316 | break; 317 | default: 318 | uri_dec[i] = data[i]; 319 | }; 320 | } 321 | 322 | size_t trailer = 4 - (i % 4); 323 | if (trailer && trailer < 4) { 324 | while (trailer--) { 325 | uri_dec[i++] = '='; 326 | } 327 | } 328 | 329 | return base64_decode(uri_dec.c_str(), uri_dec.length()); 330 | } 331 | 332 | } // END namespace jwt 333 | 334 | 335 | #endif 336 | -------------------------------------------------------------------------------- /include/jwt/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | #ifndef CPP_JWT_CONFIG_HPP 23 | #define CPP_JWT_CONFIG_HPP 24 | 25 | #ifdef _MSC_VER 26 | #define strncasecmp _strnicmp 27 | #define strcasecmp _stricmp 28 | #endif 29 | 30 | // To hack around Visual Studio error: 31 | // error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 32 | #if defined(_MSC_VER) && !defined(__clang__) 33 | #define SCOPED_ENUM enum class 34 | #else 35 | #define SCOPED_ENUM enum 36 | #endif 37 | 38 | // To hack around Visual Studio error 39 | // error C3249: illegal statement or sub-expression for 'constexpr' function 40 | // Doesn't allow assert to be part of constexpr functions. 41 | // Copied the solution as described in: 42 | // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/ 43 | #if defined NDEBUG 44 | # define X_ASSERT(CHECK) void(0) 45 | #else 46 | # define X_ASSERT(CHECK) \ 47 | ( (CHECK) ? void(0) : []{assert(!#CHECK);}() ) 48 | #endif 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/jwt/detail/meta.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | #ifndef CPP_JWT_META_HPP 23 | #define CPP_JWT_META_HPP 24 | 25 | #include 26 | #include 27 | #include "jwt/string_view.hpp" 28 | 29 | namespace jwt { 30 | namespace detail { 31 | namespace meta { 32 | 33 | /** 34 | * The famous void_t trick. 35 | */ 36 | template 37 | struct make_void 38 | { 39 | using type = void; 40 | }; 41 | 42 | template 43 | using void_t = typename make_void::type; 44 | 45 | /** 46 | * A type tag representing an empty tag. 47 | * To be used to represent a `result-not-found` 48 | * situation. 49 | */ 50 | struct empty_type {}; 51 | 52 | /** 53 | * A type list. 54 | */ 55 | template struct list{}; 56 | 57 | 58 | /** 59 | */ 60 | template 61 | struct has_create_json_obj_member: std::false_type 62 | { 63 | }; 64 | 65 | template 66 | struct has_create_json_obj_member().create_json_obj(), 70 | (void)0 71 | ) 72 | > 73 | >: std::true_type 74 | { 75 | }; 76 | 77 | /** 78 | * Checks if the type `T` models MappingConcept. 79 | * 80 | * Requirements on type `T` for matching the requirements: 81 | * a. Must be able to construct jwt::string_view from the 82 | * `key_type` of the map. 83 | * b. Must be able to construct jwt::string_view from the 84 | * `mapped_type` of the map. 85 | * c. The type `T` must have an access operator i.e. operator[]. 86 | * d. The type `T` must have `begin` and `end` member functions 87 | * for iteration. 88 | * 89 | * NOTE: Requirements `a` and `b` means that the concept 90 | * type can only hold values that are string or constructible 91 | * to form a string_view (basically C strings and std::string) 92 | */ 93 | template 94 | struct is_mapping_concept: std::false_type 95 | { 96 | }; 97 | 98 | template 99 | struct is_mapping_concept::key_type>::value, 103 | void 104 | >::type, 105 | 106 | typename std::enable_if< 107 | std::is_constructible::mapped_type>::value, 108 | void 109 | >::type, 110 | 111 | decltype( 112 | std::declval().operator[](std::declval::key_type>()), 113 | std::declval().begin(), 114 | std::declval().end(), 115 | (void)0 116 | ) 117 | > 118 | >: std::true_type 119 | { 120 | }; 121 | 122 | 123 | /** 124 | * Checks if the type `T` models the ParameterConcept. 125 | * 126 | * Requirements on type `T` for matching the requirements: 127 | * a. The type must have a `get` method. 128 | */ 129 | template 130 | struct is_parameter_concept: std::false_type 131 | { 132 | }; 133 | 134 | template 135 | struct is_parameter_concept().get(), 139 | (void)0 140 | ) 141 | > 142 | >: std::true_type 143 | { 144 | }; 145 | 146 | /** 147 | * Models SequenceConcept 148 | */ 149 | template 150 | struct is_sequence_concept: std::false_type 151 | { 152 | }; 153 | 154 | /// For array types 155 | template 156 | struct is_sequence_concept>::value>, 159 | 160 | std::enable_if_t< 161 | std::is_constructible()))>>::value 163 | > 164 | > 165 | >: std::true_type 166 | { 167 | }; 168 | 169 | template 170 | struct is_sequence_concept::iterator::iterator_category 176 | >::value>, 177 | 178 | std::enable_if_t< 179 | std::is_constructible::value_type>::value 180 | >, 181 | 182 | decltype( 183 | std::declval().begin(), 184 | std::declval().end(), 185 | (void)0 186 | ) 187 | > 188 | >: std::true_type 189 | { 190 | }; 191 | 192 | 193 | /** 194 | * Find if a type is present in the typelist. 195 | * Eg: has_type>{} == true 196 | * has_type>{} == false 197 | */ 198 | template struct has_type; 199 | 200 | template 201 | struct has_type>: std::false_type 202 | { 203 | }; 204 | 205 | template 206 | struct has_type>: std::true_type 207 | { 208 | }; 209 | 210 | template 211 | struct has_type>: has_type> 212 | { 213 | }; 214 | 215 | /** 216 | * A pack of bools for the bool trick. 217 | */ 218 | template 219 | struct bool_pack {}; 220 | 221 | /** 222 | */ 223 | template 224 | using all_true = std::is_same, bool_pack>; 225 | 226 | /** 227 | */ 228 | template 229 | using are_all_params = all_true::value...>; 230 | 231 | 232 | } // END namespace meta 233 | } // END namespace detail 234 | } // END namespace jwt 235 | 236 | #endif 237 | -------------------------------------------------------------------------------- /include/jwt/error_codes.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_ERROR_CODES_HPP 24 | #define CPP_JWT_ERROR_CODES_HPP 25 | 26 | #include 27 | 28 | namespace jwt { 29 | /** 30 | * All the algorithm errors 31 | */ 32 | enum class AlgorithmErrc 33 | { 34 | SigningErr = 1, 35 | VerificationErr, 36 | KeyNotFoundErr, 37 | InvalidKeyErr, 38 | NoneAlgorithmUsed, // Not an actual error! 39 | }; 40 | 41 | /** 42 | * Algorithm error conditions 43 | * TODO: Remove it or use it! 44 | */ 45 | enum class AlgorithmFailureSource 46 | { 47 | }; 48 | 49 | /** 50 | * Decode error conditions 51 | */ 52 | enum class DecodeErrc 53 | { 54 | // No algorithms provided in decode API 55 | EmptyAlgoList = 1, 56 | // The JWT signature has incorrect format 57 | SignatureFormatError, 58 | // The JSON library failed to parse 59 | JsonParseError, 60 | // Algorithm field in header is missing 61 | AlgHeaderMiss, 62 | // Type field in header is missing 63 | TypHeaderMiss, 64 | // Unexpected type field value 65 | TypMismatch, 66 | // Found duplicate claims 67 | DuplClaims, 68 | // Key/Secret not passed as decode argument 69 | KeyNotPresent, 70 | // Key/secret passed as argument for NONE algorithm. 71 | // Not a hard error. 72 | KeyNotRequiredForNoneAlg, 73 | }; 74 | 75 | /** 76 | * Errors handled during verification process. 77 | */ 78 | enum class VerificationErrc 79 | { 80 | //Algorithms provided does not match with header 81 | InvalidAlgorithm = 1, 82 | //Token is expired at the time of decoding 83 | TokenExpired, 84 | //The issuer specified does not match with payload 85 | InvalidIssuer, 86 | //The subject specified does not match with payload 87 | InvalidSubject, 88 | //The field IAT is not present or is of invalid type 89 | InvalidIAT, 90 | //Checks for the existence of JTI 91 | //if validate_jti is passed in decode 92 | InvalidJTI, 93 | //The audience specified does not match with payload 94 | InvalidAudience, 95 | //Decoded before nbf time 96 | ImmatureSignature, 97 | //Signature match error 98 | InvalidSignature, 99 | // Invalid value type used for known claims 100 | TypeConversionError, 101 | // Algorithm confusion attack detected 102 | AlgoConfusionAttack, 103 | }; 104 | 105 | /** 106 | */ 107 | std::error_code make_error_code(AlgorithmErrc err); 108 | 109 | /** 110 | */ 111 | std::error_code make_error_code(DecodeErrc err); 112 | 113 | /** 114 | */ 115 | std::error_code make_error_code(VerificationErrc err); 116 | 117 | } // END namespace jwt 118 | 119 | 120 | /** 121 | * Make the custom enum classes as error code 122 | * adaptable. 123 | */ 124 | namespace std 125 | { 126 | template <> 127 | struct is_error_code_enum : true_type {}; 128 | 129 | template <> 130 | struct is_error_code_enum: true_type {}; 131 | 132 | template <> 133 | struct is_error_code_enum: true_type {}; 134 | } 135 | 136 | #include "jwt/impl/error_codes.ipp" 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /include/jwt/exceptions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_EXCEPTIONS_HPP 24 | #define CPP_JWT_EXCEPTIONS_HPP 25 | 26 | #include 27 | #include 28 | 29 | namespace jwt { 30 | 31 | /** 32 | * Exception for allocation related failures in the 33 | * OpenSSL C APIs. 34 | */ 35 | class MemoryAllocationException final: public std::bad_alloc 36 | { 37 | public: 38 | /** 39 | * Construct MemoryAllocationException from a 40 | * string literal. 41 | */ 42 | template 43 | MemoryAllocationException(const char(&msg)[N]) 44 | : msg_(&msg[0]) 45 | { 46 | } 47 | 48 | virtual const char* what() const noexcept override 49 | { 50 | return msg_; 51 | } 52 | 53 | private: 54 | const char* msg_ = nullptr; 55 | }; 56 | 57 | /** 58 | * Exception thrown for failures in OpenSSL 59 | * APIs while signing. 60 | */ 61 | class SigningError : public std::runtime_error 62 | { 63 | public: 64 | /** 65 | */ 66 | SigningError(std::string msg) 67 | : std::runtime_error(std::move(msg)) 68 | { 69 | } 70 | }; 71 | 72 | /** 73 | * Exception thrown for decode related errors. 74 | */ 75 | class DecodeError: public std::runtime_error 76 | { 77 | public: 78 | /** 79 | */ 80 | DecodeError(std::string msg) 81 | : std::runtime_error(std::move(msg)) 82 | { 83 | } 84 | }; 85 | 86 | /** 87 | * A derived decode error for signature format 88 | * error. 89 | */ 90 | class SignatureFormatError final : public DecodeError 91 | { 92 | public: 93 | /** 94 | */ 95 | SignatureFormatError(std::string msg) 96 | : DecodeError(std::move(msg)) 97 | { 98 | } 99 | }; 100 | 101 | /** 102 | * A derived decode error for Key argument not present 103 | * error. Only thrown if the algorithm set is not NONE. 104 | */ 105 | class KeyNotPresentError final : public DecodeError 106 | { 107 | public: 108 | /** 109 | */ 110 | KeyNotPresentError(std::string msg) 111 | : DecodeError(std::move(msg)) 112 | { 113 | } 114 | }; 115 | 116 | 117 | /** 118 | * Base class exception for all kinds of verification errors. 119 | * Verification errors are thrown only when the verify 120 | * decode parameter is set to true. 121 | */ 122 | class VerificationError : public std::runtime_error 123 | { 124 | public: 125 | /** 126 | */ 127 | VerificationError(std::string msg) 128 | : std::runtime_error(std::move(msg)) 129 | { 130 | } 131 | }; 132 | 133 | /** 134 | * Derived from VerificationError. 135 | * Thrown when the algorithm decoded in the header 136 | * is incorrect. 137 | */ 138 | class InvalidAlgorithmError final: public VerificationError 139 | { 140 | public: 141 | /** 142 | */ 143 | InvalidAlgorithmError(std::string msg) 144 | : VerificationError(std::move(msg)) 145 | { 146 | } 147 | }; 148 | 149 | /** 150 | * Derived from VerificationError. 151 | * Thrown when the token is expired at the 152 | * time of decoding. 153 | */ 154 | class TokenExpiredError final: public VerificationError 155 | { 156 | public: 157 | /** 158 | */ 159 | TokenExpiredError(std::string msg) 160 | : VerificationError(std::move(msg)) 161 | { 162 | } 163 | }; 164 | 165 | /** 166 | * Derived from VerificationError. 167 | * Thrown when the issuer claim does not match 168 | * with the one provided as part of decode argument. 169 | */ 170 | class InvalidIssuerError final: public VerificationError 171 | { 172 | public: 173 | /** 174 | */ 175 | InvalidIssuerError(std::string msg) 176 | : VerificationError(std::move(msg)) 177 | { 178 | } 179 | }; 180 | 181 | /** 182 | * Derived from VerificationError. 183 | * Thrown when the audience claim does not match 184 | * with the one provided as part of decode argument. 185 | */ 186 | class InvalidAudienceError final: public VerificationError 187 | { 188 | public: 189 | /** 190 | */ 191 | InvalidAudienceError(std::string msg) 192 | : VerificationError(std::move(msg)) 193 | { 194 | } 195 | }; 196 | 197 | /** 198 | * Derived from VerificationError. 199 | * Thrown when the subject claim does not match 200 | * with the one provided as part of decode argument. 201 | */ 202 | class InvalidSubjectError final: public VerificationError 203 | { 204 | public: 205 | /** 206 | */ 207 | InvalidSubjectError(std::string msg) 208 | : VerificationError(std::move(msg)) 209 | { 210 | } 211 | }; 212 | 213 | /** 214 | * Derived from VerificationError. 215 | * Thrown when verify_iat parameter is passed to 216 | * decode and IAT is not present. 217 | */ 218 | class InvalidIATError final: public VerificationError 219 | { 220 | public: 221 | /** 222 | */ 223 | InvalidIATError(std::string msg) 224 | : VerificationError(std::move(msg)) 225 | { 226 | } 227 | }; 228 | 229 | /** 230 | * Derived from VerificationError. 231 | * Thrown when validate_jti is asked for 232 | * in decode and jti claim is not present. 233 | */ 234 | class InvalidJTIError final: public VerificationError 235 | { 236 | public: 237 | /** 238 | */ 239 | InvalidJTIError(std::string msg) 240 | : VerificationError(std::move(msg)) 241 | { 242 | } 243 | }; 244 | 245 | /** 246 | * Derived from VerificationError. 247 | * Thrown when the token is decoded at a time before 248 | * as specified in the `nbf` claim. 249 | */ 250 | class ImmatureSignatureError final: public VerificationError 251 | { 252 | public: 253 | /** 254 | */ 255 | ImmatureSignatureError(std::string msg) 256 | : VerificationError(std::move(msg)) 257 | { 258 | } 259 | }; 260 | 261 | /** 262 | * Derived from VerificationError. 263 | * Thrown when the signature does not match in the verification process. 264 | */ 265 | class InvalidSignatureError final: public VerificationError 266 | { 267 | public: 268 | /** 269 | */ 270 | InvalidSignatureError(std::string msg) 271 | : VerificationError(std::move(msg)) 272 | { 273 | } 274 | }; 275 | 276 | class InvalidKeyError final: public VerificationError 277 | { 278 | public: 279 | /** 280 | */ 281 | InvalidKeyError(std::string msg) 282 | : VerificationError(std::move(msg)) 283 | { 284 | } 285 | }; 286 | 287 | /** 288 | * Derived from VerificationError. 289 | * Thrown when there type expectation mismatch 290 | * while verifying the values of registered claim names. 291 | */ 292 | class TypeConversionError final: public VerificationError 293 | { 294 | public: 295 | /** 296 | */ 297 | TypeConversionError(std::string msg) 298 | : VerificationError(std::move(msg)) 299 | { 300 | } 301 | }; 302 | 303 | } // END namespace jwt 304 | 305 | #endif 306 | -------------------------------------------------------------------------------- /include/jwt/impl/algorithm.ipp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_ALGORITHM_IPP 24 | #define CPP_JWT_ALGORITHM_IPP 25 | 26 | namespace jwt { 27 | 28 | verify_result_t is_secret_a_public_key(const jwt::string_view secret) 29 | { 30 | std::error_code ec{}; 31 | 32 | BIO_uptr bufkey{ 33 | BIO_new_mem_buf((void*)secret.data(), static_cast(secret.length())), 34 | bio_deletor 35 | }; 36 | if (!bufkey) { 37 | throw MemoryAllocationException("BIO_new_mem_buf failed"); 38 | } 39 | 40 | EC_PKEY_uptr pkey{ 41 | PEM_read_bio_PUBKEY(bufkey.get(), nullptr, nullptr, nullptr), 42 | ev_pkey_deletor 43 | }; 44 | 45 | if (!pkey) { 46 | ec = AlgorithmErrc::InvalidKeyErr; 47 | return { false, ec }; 48 | } 49 | 50 | return {true, ec}; 51 | } 52 | 53 | template 54 | verify_result_t HMACSign::verify( 55 | const jwt::string_view key, 56 | const jwt::string_view head, 57 | const jwt::string_view jwt_sign) 58 | { 59 | std::error_code ec{}; 60 | 61 | unsigned char enc_buf[EVP_MAX_MD_SIZE]; 62 | uint32_t enc_buf_len = 0; 63 | 64 | unsigned char* res = HMAC(Hasher{}(), 65 | key.data(), 66 | static_cast(key.length()), 67 | reinterpret_cast(head.data()), 68 | head.length(), 69 | enc_buf, 70 | &enc_buf_len); 71 | if (!res) { 72 | ec = AlgorithmErrc::VerificationErr; 73 | return {false, ec}; 74 | } 75 | if (enc_buf_len == 0) { 76 | ec = AlgorithmErrc::VerificationErr; 77 | return {false, ec}; 78 | } 79 | 80 | std::string b64_enc_str = jwt::base64_encode((const char*)&enc_buf[0], enc_buf_len); 81 | 82 | if (!b64_enc_str.length()) { 83 | ec = AlgorithmErrc::VerificationErr; 84 | return {false, ec}; 85 | } 86 | 87 | // Make the base64 string url safe 88 | auto new_len = jwt::base64_uri_encode(&b64_enc_str[0], b64_enc_str.length()); 89 | b64_enc_str.resize(new_len); 90 | 91 | bool ret = (new_len == jwt_sign.size()) && (CRYPTO_memcmp(b64_enc_str.data(), jwt_sign.data(), new_len) == 0); 92 | 93 | return { ret, ec }; 94 | } 95 | 96 | 97 | template 98 | verify_result_t PEMSign::verify( 99 | const jwt::string_view key, 100 | const jwt::string_view head, 101 | const jwt::string_view jwt_sign) 102 | { 103 | std::error_code ec{}; 104 | std::string dec_sig = base64_uri_decode(jwt_sign.data(), jwt_sign.length()); 105 | 106 | BIO_uptr bufkey{ 107 | BIO_new_mem_buf((void*)key.data(), static_cast(key.length())), 108 | bio_deletor}; 109 | 110 | if (!bufkey) { 111 | throw MemoryAllocationException("BIO_new_mem_buf failed"); 112 | } 113 | 114 | EC_PKEY_uptr pkey{ 115 | PEM_read_bio_PUBKEY(bufkey.get(), nullptr, nullptr, nullptr), 116 | ev_pkey_deletor}; 117 | 118 | if (!pkey) { 119 | ec = AlgorithmErrc::InvalidKeyErr; 120 | return { false, ec }; 121 | } 122 | 123 | int pkey_type = EVP_PKEY_id(pkey.get()); 124 | 125 | if (pkey_type != Hasher::type) { 126 | ec = AlgorithmErrc::VerificationErr; 127 | return { false, ec }; 128 | } 129 | 130 | //Convert EC signature back to ASN1 131 | if (Hasher::type == EVP_PKEY_EC) { 132 | EC_SIG_uptr ec_sig{ECDSA_SIG_new(), ec_sig_deletor}; 133 | if (!ec_sig) { 134 | throw MemoryAllocationException("ECDSA_SIG_new failed"); 135 | } 136 | 137 | //Get the actual ec_key 138 | EC_KEY_uptr ec_key{EVP_PKEY_get1_EC_KEY(pkey.get()), ec_key_deletor}; 139 | if (!ec_key) { 140 | throw MemoryAllocationException("EVP_PKEY_get1_EC_KEY failed"); 141 | } 142 | 143 | unsigned int degree = EC_GROUP_get_degree( 144 | EC_KEY_get0_group(ec_key.get())); 145 | 146 | unsigned int bn_len = (degree + 7) / 8; 147 | 148 | if ((bn_len * 2) != dec_sig.length()) { 149 | ec = AlgorithmErrc::VerificationErr; 150 | return { false, ec }; 151 | } 152 | 153 | BIGNUM* ec_sig_r = BN_bin2bn((unsigned char*)dec_sig.data(), bn_len, nullptr); 154 | BIGNUM* ec_sig_s = BN_bin2bn((unsigned char*)dec_sig.data() + bn_len, bn_len, nullptr); 155 | 156 | if (!ec_sig_r || !ec_sig_s) { 157 | ec = AlgorithmErrc::VerificationErr; 158 | return { false, ec }; 159 | } 160 | 161 | ECDSA_SIG_set0(ec_sig.get(), ec_sig_r, ec_sig_s); 162 | 163 | size_t nlen = i2d_ECDSA_SIG(ec_sig.get(), nullptr); 164 | dec_sig.resize(nlen); 165 | 166 | auto data = reinterpret_cast(&dec_sig[0]); 167 | nlen = i2d_ECDSA_SIG(ec_sig.get(), &data); 168 | 169 | if (nlen == 0) { 170 | ec = AlgorithmErrc::VerificationErr; 171 | return { false, ec }; 172 | } 173 | } 174 | 175 | EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor}; 176 | if (!mdctx_ptr) { 177 | throw MemoryAllocationException("EVP_MD_CTX_create failed"); 178 | } 179 | 180 | if (EVP_DigestVerifyInit( 181 | mdctx_ptr.get(), nullptr, Hasher{}(), nullptr, pkey.get()) != 1) { 182 | ec = AlgorithmErrc::VerificationErr; 183 | return { false, ec }; 184 | } 185 | 186 | if (EVP_DigestVerifyUpdate(mdctx_ptr.get(), head.data(), head.length()) != 1) { 187 | ec = AlgorithmErrc::VerificationErr; 188 | return { false, ec }; 189 | } 190 | 191 | if (EVP_DigestVerifyFinal( 192 | mdctx_ptr.get(), (unsigned char*)&dec_sig[0], dec_sig.length()) != 1) { 193 | ec = AlgorithmErrc::VerificationErr; 194 | return { false, ec }; 195 | } 196 | 197 | return { true, ec }; 198 | } 199 | 200 | template 201 | EVP_PKEY* PEMSign::load_key( 202 | const jwt::string_view key, 203 | std::error_code& ec) 204 | { 205 | ec.clear(); 206 | 207 | BIO_uptr bio_ptr{ 208 | BIO_new_mem_buf((void*)key.data(), static_cast(key.length())), 209 | bio_deletor}; 210 | 211 | if (!bio_ptr) { 212 | throw MemoryAllocationException("BIO_new_mem_buf failed"); 213 | } 214 | 215 | EVP_PKEY* pkey = PEM_read_bio_PrivateKey( 216 | bio_ptr.get(), nullptr, nullptr, nullptr); 217 | 218 | if (!pkey) { 219 | ec = AlgorithmErrc::SigningErr; 220 | return nullptr; 221 | } 222 | 223 | auto pkey_type = EVP_PKEY_id(pkey); 224 | if (pkey_type != Hasher::type) { 225 | ec = AlgorithmErrc::SigningErr; 226 | return nullptr; 227 | } 228 | 229 | return pkey; 230 | } 231 | 232 | template 233 | std::string PEMSign::evp_digest( 234 | EVP_PKEY* pkey, 235 | const jwt::string_view data, 236 | std::error_code& ec) 237 | { 238 | ec.clear(); 239 | 240 | EVP_MDCTX_uptr mdctx_ptr{EVP_MD_CTX_create(), evp_md_ctx_deletor}; 241 | 242 | if (!mdctx_ptr) { 243 | throw MemoryAllocationException("EVP_MD_CTX_create failed"); 244 | } 245 | 246 | //Initialiaze the digest algorithm 247 | if (EVP_DigestSignInit( 248 | mdctx_ptr.get(), nullptr, Hasher{}(), nullptr, pkey) != 1) { 249 | ec = AlgorithmErrc::SigningErr; 250 | return {}; 251 | } 252 | 253 | //Update the digest with the input data 254 | if (EVP_DigestSignUpdate(mdctx_ptr.get(), data.data(), data.length()) != 1) { 255 | ec = AlgorithmErrc::SigningErr; 256 | return {}; 257 | } 258 | 259 | size_t len = 0; 260 | 261 | if (EVP_DigestSignFinal(mdctx_ptr.get(), nullptr, &len) != 1) { 262 | ec = AlgorithmErrc::SigningErr; 263 | return {}; 264 | } 265 | 266 | std::string sign; 267 | sign.resize(len); 268 | 269 | //Get the signature 270 | if (EVP_DigestSignFinal(mdctx_ptr.get(), (unsigned char*)&sign[0], &len) != 1) { 271 | ec = AlgorithmErrc::SigningErr; 272 | return {}; 273 | } 274 | 275 | return sign; 276 | } 277 | 278 | template 279 | std::string PEMSign::public_key_ser( 280 | EVP_PKEY* pkey, 281 | jwt::string_view sign, 282 | std::error_code& ec) 283 | { 284 | // Get the EC_KEY representing a public key and 285 | // (optionaly) an associated private key 286 | std::string new_sign; 287 | ec.clear(); 288 | 289 | EC_KEY_uptr ec_key{EVP_PKEY_get1_EC_KEY(pkey), ec_key_deletor}; 290 | 291 | if (!ec_key) { 292 | ec = AlgorithmErrc::SigningErr; 293 | return {}; 294 | } 295 | 296 | uint32_t degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key.get())); 297 | 298 | ec_key.reset(nullptr); 299 | 300 | auto char_ptr = &sign[0]; 301 | 302 | EC_SIG_uptr ec_sig{d2i_ECDSA_SIG(nullptr, 303 | (const unsigned char**)&char_ptr, 304 | static_cast(sign.length())), 305 | ec_sig_deletor}; 306 | 307 | if (!ec_sig) { 308 | ec = AlgorithmErrc::SigningErr; 309 | return {}; 310 | } 311 | 312 | const BIGNUM* ec_sig_r = nullptr; 313 | const BIGNUM* ec_sig_s = nullptr; 314 | 315 | ECDSA_SIG_get0(ec_sig.get(), &ec_sig_r, &ec_sig_s); 316 | 317 | int r_len = BN_num_bytes(ec_sig_r); 318 | int s_len = BN_num_bytes(ec_sig_s); 319 | int bn_len = static_cast((degree + 7) / 8); 320 | 321 | if ((r_len > bn_len) || (s_len > bn_len)) { 322 | ec = AlgorithmErrc::SigningErr; 323 | return {}; 324 | } 325 | 326 | auto buf_len = 2 * bn_len; 327 | new_sign.resize(buf_len); 328 | 329 | BN_bn2bin(ec_sig_r, (unsigned char*)&new_sign[0] + bn_len - r_len); 330 | BN_bn2bin(ec_sig_s, (unsigned char*)&new_sign[0] + buf_len - s_len); 331 | 332 | return new_sign; 333 | } 334 | 335 | } // END namespace jwt 336 | 337 | #endif 338 | -------------------------------------------------------------------------------- /include/jwt/impl/error_codes.ipp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_ERROR_CODES_IPP 24 | #define CPP_JWT_ERROR_CODES_IPP 25 | 26 | namespace jwt { 27 | // Anonymous namespace 28 | namespace { 29 | 30 | /** 31 | */ 32 | struct AlgorithmErrCategory: std::error_category 33 | { 34 | const char* name() const noexcept override 35 | { 36 | return "algorithms"; 37 | } 38 | 39 | std::string message(int ev) const override 40 | { 41 | switch (static_cast(ev)) 42 | { 43 | case AlgorithmErrc::SigningErr: 44 | return "signing failed"; 45 | case AlgorithmErrc::VerificationErr: 46 | return "verification failed"; 47 | case AlgorithmErrc::KeyNotFoundErr: 48 | return "key not provided"; 49 | case AlgorithmErrc::NoneAlgorithmUsed: 50 | return "none algorithm used"; 51 | case AlgorithmErrc::InvalidKeyErr: 52 | return "invalid key"; 53 | }; 54 | return "unknown algorithm error"; 55 | } 56 | }; 57 | 58 | /** 59 | */ 60 | struct DecodeErrorCategory: std::error_category 61 | { 62 | const char* name() const noexcept override 63 | { 64 | return "decode"; 65 | } 66 | 67 | std::string message(int ev) const override 68 | { 69 | switch (static_cast(ev)) 70 | { 71 | case DecodeErrc::EmptyAlgoList: 72 | return "empty algorithm list"; 73 | case DecodeErrc::SignatureFormatError: 74 | return "signature format is incorrect"; 75 | case DecodeErrc::AlgHeaderMiss: 76 | return "missing algorithm header"; 77 | case DecodeErrc::TypHeaderMiss: 78 | return "missing type header"; 79 | case DecodeErrc::TypMismatch: 80 | return "type mismatch"; 81 | case DecodeErrc::JsonParseError: 82 | return "json parse failed"; 83 | case DecodeErrc::DuplClaims: 84 | return "duplicate claims"; 85 | case DecodeErrc::KeyNotPresent: 86 | return "key not present"; 87 | case DecodeErrc::KeyNotRequiredForNoneAlg: 88 | return "key not required for NONE algorithm"; 89 | }; 90 | return "unknown decode error"; 91 | } 92 | }; 93 | 94 | /** 95 | */ 96 | struct VerificationErrorCategory: std::error_category 97 | { 98 | const char* name() const noexcept override 99 | { 100 | return "verification"; 101 | } 102 | 103 | std::string message(int ev) const override 104 | { 105 | switch (static_cast(ev)) 106 | { 107 | case VerificationErrc::InvalidAlgorithm: 108 | return "invalid algorithm"; 109 | case VerificationErrc::TokenExpired: 110 | return "token expired"; 111 | case VerificationErrc::InvalidIssuer: 112 | return "invalid issuer"; 113 | case VerificationErrc::InvalidSubject: 114 | return "invalid subject"; 115 | case VerificationErrc::InvalidAudience: 116 | return "invalid audience"; 117 | case VerificationErrc::InvalidIAT: 118 | return "invalid iat"; 119 | case VerificationErrc::InvalidJTI: 120 | return "invalid jti"; 121 | case VerificationErrc::ImmatureSignature: 122 | return "immature signature"; 123 | case VerificationErrc::InvalidSignature: 124 | return "invalid signature"; 125 | case VerificationErrc::TypeConversionError: 126 | return "type conversion error"; 127 | case VerificationErrc::AlgoConfusionAttack: 128 | return "algo confusion attack possibility"; 129 | }; 130 | return "unknown verification error"; 131 | } 132 | }; 133 | 134 | // Create global object for the error categories 135 | const AlgorithmErrCategory theAlgorithmErrCategory {}; 136 | 137 | const DecodeErrorCategory theDecodeErrorCategory {}; 138 | 139 | const VerificationErrorCategory theVerificationErrorCategory {}; 140 | 141 | } 142 | 143 | 144 | // Create the AlgorithmErrc error code 145 | inline std::error_code make_error_code(AlgorithmErrc err) 146 | { 147 | return { static_cast(err), theAlgorithmErrCategory }; 148 | } 149 | 150 | inline std::error_code make_error_code(DecodeErrc err) 151 | { 152 | return { static_cast(err), theDecodeErrorCategory }; 153 | } 154 | 155 | inline std::error_code make_error_code(VerificationErrc err) 156 | { 157 | return { static_cast(err), theVerificationErrorCategory }; 158 | } 159 | 160 | } // END namespace jwt 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /include/jwt/impl/stack_alloc.ipp: -------------------------------------------------------------------------------- 1 | /* 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2015 Howard Hinnant 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | */ 24 | 25 | #ifndef STACK_ALLOC_IPP 26 | #define STACK_ALLOC_IPP 27 | 28 | namespace jwt { 29 | 30 | template 31 | template 32 | char* Arena::allocate(size_t n) noexcept 33 | { 34 | static_assert (reqested_alignment <= alignment, 35 | "Requested alignment is too small for this arena"); 36 | 37 | assert (pointer_in_storage(ptr_) && 38 | "No more space in the arena or it has outgrown its capacity"); 39 | 40 | n = align_up(n); 41 | 42 | if ((ptr_ + n) <= (buf_ + N)) { 43 | char* ret = ptr_; 44 | ptr_ += n; 45 | 46 | return ret; 47 | } 48 | 49 | assert (0 && "Code should not reach here"); 50 | 51 | return nullptr; 52 | } 53 | 54 | template 55 | void Arena::deallocate(char* p, size_t n) noexcept 56 | { 57 | assert (pointer_in_storage(p) && 58 | "The address to de deleted does not lie inside the storage"); 59 | 60 | n = align_up(n); 61 | 62 | if ((p + n) == ptr_) { 63 | ptr_ = p; 64 | } 65 | 66 | return; 67 | } 68 | 69 | template 70 | T* stack_alloc::allocate(size_t n) noexcept 71 | { 72 | return reinterpret_cast( 73 | arena_.template allocate(n * sizeof(T)) 74 | ); 75 | } 76 | 77 | template 78 | void stack_alloc::deallocate(T* p, size_t n) noexcept 79 | { 80 | arena_.deallocate(reinterpret_cast(p), n); 81 | return; 82 | } 83 | 84 | } 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /include/jwt/impl/string_view.ipp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef JWT_STRING_VIEW_IPP 24 | #define JWT_STRING_VIEW_IPP 25 | 26 | namespace jwt { 27 | 28 | template 29 | auto basic_string_view::find( 30 | const CharT* str, 31 | size_type pos, 32 | size_type n) const noexcept -> size_type 33 | { 34 | assert (str); 35 | assert (n < (len_ - pos) && "Comparison size out of bounds"); 36 | 37 | if (n == 0) { 38 | return pos <= len_ ? pos : npos; 39 | } 40 | if (n <= len_) { 41 | for (; pos <= (len_ - n); ++pos) { 42 | if (traits_type::eq(data_[pos], str[0]) && 43 | traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) { 44 | return pos; 45 | } 46 | } 47 | } 48 | 49 | return npos; 50 | } 51 | 52 | template 53 | auto basic_string_view::rfind( 54 | const CharT* str, 55 | size_type pos, 56 | size_type n) const noexcept -> size_type 57 | { 58 | assert (str); 59 | assert (pos < len_ && "Position out of bounds"); 60 | 61 | if (n <= len_) { 62 | pos = std::min(len_ - n, pos); 63 | do { 64 | if (traits_type::eq(data_[pos], str[0]) && 65 | traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) { 66 | return pos; 67 | } 68 | } while (pos-- != 0); 69 | } 70 | 71 | return npos; 72 | } 73 | 74 | template 75 | auto basic_string_view::find( 76 | const CharT ch, 77 | size_type pos) const noexcept -> size_type 78 | { 79 | if (pos < len_) { 80 | for (size_type i = pos; i < len_; ++i) { 81 | if (traits_type::eq(data_[i], ch)) return i; 82 | } 83 | } 84 | return npos; 85 | } 86 | 87 | template 88 | auto basic_string_view::rfind( 89 | const CharT ch, 90 | size_type pos) const noexcept -> size_type 91 | { 92 | if (pos < len_) { 93 | do { 94 | if (traits_type::eq(data_[pos], ch)) { 95 | return pos; 96 | } 97 | } while (pos-- != 0); 98 | } 99 | 100 | return npos; 101 | } 102 | 103 | template 104 | auto basic_string_view::find_first_of( 105 | const CharT* str, 106 | size_type pos, 107 | size_type count) const noexcept -> size_type 108 | { 109 | assert (str); 110 | 111 | for (size_type i = pos; i < len_; ++i) { 112 | auto p = traits_type::find(str, count, data_[i]); 113 | if (p) { 114 | return i; 115 | } 116 | } 117 | 118 | return npos; 119 | } 120 | 121 | template 122 | auto basic_string_view::find_last_of( 123 | const CharT* str, 124 | size_type pos, 125 | size_type count) const noexcept -> size_type 126 | { 127 | assert (str); 128 | assert (pos < len_ && "Position must be within the bounds of the view"); 129 | size_type siz = len_; 130 | 131 | if (siz && count) { 132 | siz = std::min(pos, siz); 133 | 134 | do { 135 | auto p = traits_type::find(str, count, data_[siz]); 136 | if (p) { 137 | return siz; 138 | } 139 | } while (siz-- != 0); 140 | } 141 | 142 | return npos; 143 | } 144 | 145 | template 146 | auto basic_string_view::find_first_not_of( 147 | const CharT* str, 148 | size_type pos, 149 | size_type n) const noexcept -> size_type 150 | { 151 | assert (str); 152 | assert (pos < len_&& "Position must be within the bounds of the view"); 153 | 154 | for (size_type i = pos; i < len_; ++i) 155 | { 156 | auto p = traits_type::find(str, n, data_[i]); 157 | if (!p) return i; 158 | } 159 | 160 | return npos; 161 | } 162 | 163 | template 164 | auto basic_string_view::find_last_not_of( 165 | const CharT* str, 166 | size_type pos, 167 | size_type n) const noexcept -> size_type 168 | { 169 | assert (str); 170 | assert (pos < len_ && "Position must be within the bounds of the view"); 171 | 172 | do { 173 | for (size_type i = 0; i < n; ++i) { 174 | if (!traits_type::eq(data_[pos], str[i])) return pos; 175 | } 176 | } while (pos-- != 0); 177 | 178 | return npos; 179 | } 180 | 181 | template 182 | auto basic_string_view::find_first_not_of( 183 | CharT ch, 184 | size_type pos) const noexcept -> size_type 185 | { 186 | assert (pos < len_&& "Position must be within the bounds of the view"); 187 | 188 | for (size_type i = pos; i < len_; ++i) { 189 | if (!traits_type::eq(data_[i], ch)) return i; 190 | } 191 | 192 | return npos; 193 | } 194 | 195 | template 196 | auto basic_string_view::find_last_not_of( 197 | CharT ch, 198 | size_type pos) const noexcept -> size_type 199 | { 200 | assert (pos < len_ && "Position must be within the bounds of the view"); 201 | 202 | do { 203 | if (!traits_type::eq(data_[pos], ch)) return pos; 204 | } while (pos-- != 0); 205 | 206 | return npos; 207 | } 208 | 209 | // Comparison Operators 210 | 211 | template 212 | bool operator== (basic_string_view a, 213 | basic_string_view b) noexcept 214 | { 215 | if (a.length() != b.length()) return false; 216 | using traits_type = typename basic_string_view::traits_type; 217 | using size_type = typename basic_string_view::size_type; 218 | 219 | for (size_type i = 0; i < a.length(); ++i) { 220 | if (!traits_type::eq(a[i], b[i])) return false; 221 | } 222 | 223 | return true; 224 | } 225 | 226 | template 227 | bool operator!= (basic_string_view a, 228 | basic_string_view b) noexcept 229 | { 230 | return !( a == b ); 231 | } 232 | 233 | template 234 | bool operator< (basic_string_view a, 235 | basic_string_view b) noexcept 236 | { 237 | return a.compare(b) < 0; 238 | } 239 | 240 | template 241 | bool operator> (basic_string_view a, 242 | basic_string_view b) noexcept 243 | { 244 | return a.compare(b) > 0; 245 | } 246 | 247 | template 248 | bool operator<= (basic_string_view a, 249 | basic_string_view b) noexcept 250 | { 251 | return a.compare(b) <= 0; 252 | } 253 | 254 | template 255 | bool operator>= (basic_string_view a, 256 | basic_string_view b) noexcept 257 | { 258 | return a.compare(b) >= 0; 259 | } 260 | 261 | template 262 | std::ostream& operator<< (std::ostream& os, basic_string_view sv) 263 | { 264 | os.write(sv.data(), sv.length()); 265 | return os; 266 | } 267 | 268 | namespace { 269 | 270 | /* 271 | * Copy of gcc implementation of murmurhash 272 | * hash_bytes.cc 273 | */ 274 | 275 | inline size_t 276 | unaligned_load(const char* p) noexcept 277 | { 278 | std::size_t result; 279 | std::memcpy(&result, p, sizeof(result)); 280 | return result; 281 | } 282 | 283 | inline size_t 284 | hash_bytes(const void* ptr, size_t len, size_t seed) noexcept 285 | { 286 | const size_t m = 0x5bd1e995; 287 | size_t hash = seed ^ len; 288 | const char* buf = static_cast(ptr); 289 | 290 | // Mix 4 bytes at a time into the hash. 291 | while(len >= 4) 292 | { 293 | size_t k = unaligned_load(buf); 294 | k *= m; 295 | k ^= k >> 24; 296 | k *= m; 297 | hash *= m; 298 | hash ^= k; 299 | buf += 4; 300 | len -= 4; 301 | } 302 | 303 | // Handle the last few bytes of the input array. 304 | switch(len) 305 | { 306 | case 3: 307 | hash ^= static_cast(buf[2]) << 16; 308 | //FALLTHROUGH 309 | case 2: 310 | hash ^= static_cast(buf[1]) << 8; 311 | //FALLTHROUGH 312 | case 1: 313 | hash ^= static_cast(buf[0]); 314 | hash *= m; 315 | }; 316 | 317 | // Do a few final mixes of the hash. 318 | hash ^= hash >> 13; 319 | hash *= m; 320 | hash ^= hash >> 15; 321 | return hash; 322 | } 323 | } 324 | 325 | } // END namespace jwt 326 | 327 | /// Provide a hash specialization 328 | namespace std { 329 | template <> 330 | struct hash 331 | { 332 | size_t operator()(const jwt::string_view& sv) const noexcept 333 | { 334 | return jwt::hash_bytes((void*)sv.data(), sv.length(), static_cast(0xc70f6907UL)); 335 | } 336 | }; 337 | } 338 | 339 | #endif 340 | -------------------------------------------------------------------------------- /include/jwt/json/test_json.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #if defined( CPP_JWT_USE_VENDORED_NLOHMANN_JSON) 4 | #include "./json.hpp" 5 | #else 6 | #include "nlohmann/json.hpp" 7 | #endif 8 | using json = nlohmann::json; 9 | 10 | void basic_json_test() 11 | { 12 | json obj = json::object(); 13 | obj["test"] = "value-test"; 14 | obj["test-int"] = 42; 15 | 16 | std::string jstr = obj.dump(0); 17 | std::cout << jstr << std::endl; 18 | } 19 | 20 | int main() { 21 | basic_json_test(); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /include/jwt/parameters.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_PARAMETERS_HPP 24 | #define CPP_JWT_PARAMETERS_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "jwt/algorithm.hpp" 34 | #include "jwt/detail/meta.hpp" 35 | #include "jwt/string_view.hpp" 36 | 37 | namespace jwt { 38 | 39 | using system_time_t = std::chrono::time_point; 40 | 41 | namespace params { 42 | 43 | 44 | namespace detail { 45 | /** 46 | * Parameter for providing the payload. 47 | * Takes a Mapping concept representing 48 | * key-value pairs. 49 | * 50 | * NOTE: MappingConcept allows only strings 51 | * for both keys and values. Use `add_header` 52 | * API of `jwt_object` otherwise. 53 | * 54 | * Modeled as ParameterConcept. 55 | */ 56 | template 57 | struct payload_param 58 | { 59 | payload_param(MappingConcept&& mc) 60 | : payload_(std::forward(mc)) 61 | {} 62 | 63 | MappingConcept get() && { return std::move(payload_); } 64 | const MappingConcept& get() const& { return payload_; } 65 | 66 | MappingConcept payload_; 67 | }; 68 | 69 | /** 70 | * Parameter for providing the secret key. 71 | * Stores only the view of the provided string 72 | * as string_view. Later the implementation may or 73 | * may-not copy it. 74 | * 75 | * Modeled as ParameterConcept. 76 | */ 77 | struct secret_param 78 | { 79 | secret_param(string_view sv) 80 | : secret_(sv) 81 | {} 82 | 83 | string_view get() { return secret_; } 84 | string_view secret_; 85 | }; 86 | 87 | template 88 | struct secret_function_param 89 | { 90 | T get() const { return fun_; } 91 | template 92 | std::string get(U&& u) const { return fun_(u);} 93 | T fun_; 94 | }; 95 | 96 | /** 97 | * Parameter for providing the algorithm to use. 98 | * The parameter can accept either the string representation 99 | * or the enum class. 100 | * 101 | * Modeled as ParameterConcept. 102 | */ 103 | struct algorithm_param 104 | { 105 | algorithm_param(const string_view alg) 106 | : alg_(str_to_alg(alg)) 107 | {} 108 | 109 | algorithm_param(jwt::algorithm alg) 110 | : alg_(alg) 111 | {} 112 | 113 | jwt::algorithm get() const noexcept 114 | { 115 | return alg_; 116 | } 117 | 118 | typename jwt::algorithm alg_; 119 | }; 120 | 121 | /** 122 | * Parameter for providing additional headers. 123 | * Takes a mapping concept representing 124 | * key-value pairs. 125 | * 126 | * Modeled as ParameterConcept. 127 | */ 128 | template 129 | struct headers_param 130 | { 131 | headers_param(MappingConcept&& mc) 132 | : headers_(std::forward(mc)) 133 | {} 134 | 135 | MappingConcept get() && { return std::move(headers_); } 136 | const MappingConcept& get() const& { return headers_; } 137 | 138 | MappingConcept headers_; 139 | }; 140 | 141 | /** 142 | */ 143 | struct verify_param 144 | { 145 | verify_param(bool v) 146 | : verify_(v) 147 | {} 148 | 149 | bool get() const { return verify_; } 150 | 151 | bool verify_; 152 | }; 153 | 154 | /** 155 | */ 156 | template 157 | struct algorithms_param 158 | { 159 | algorithms_param(Sequence&& seq) 160 | : seq_(std::forward(seq)) 161 | {} 162 | 163 | Sequence get() && { return std::move(seq_); } 164 | const Sequence& get() const& { return seq_; } 165 | 166 | Sequence seq_; 167 | }; 168 | 169 | /** 170 | */ 171 | struct leeway_param 172 | { 173 | leeway_param(uint32_t v) 174 | : leeway_(v) 175 | {} 176 | 177 | uint32_t get() const noexcept { return leeway_; } 178 | 179 | uint32_t leeway_; 180 | }; 181 | 182 | /** 183 | */ 184 | struct audience_param 185 | { 186 | audience_param(std::string aud) 187 | : aud_(std::move(aud)) 188 | {} 189 | 190 | const std::string& get() const& noexcept { return aud_; } 191 | std::string get() && noexcept { return aud_; } 192 | 193 | std::string aud_; 194 | }; 195 | 196 | /** 197 | */ 198 | struct issuer_param 199 | { 200 | issuer_param(std::string iss) 201 | : iss_(std::move(iss)) 202 | {} 203 | 204 | const std::string& get() const& noexcept { return iss_; } 205 | std::string get() && noexcept { return iss_; } 206 | 207 | std::string iss_; 208 | }; 209 | 210 | /** 211 | */ 212 | struct subject_param 213 | { 214 | subject_param(std::string sub) 215 | : sub_(std::move(sub)) 216 | {} 217 | 218 | const std::string& get() const& noexcept { return sub_; } 219 | std::string get() && noexcept { return sub_; } 220 | 221 | std::string sub_; 222 | }; 223 | 224 | /** 225 | */ 226 | struct validate_iat_param 227 | { 228 | validate_iat_param(bool v) 229 | : iat_(v) 230 | {} 231 | 232 | bool get() const noexcept { return iat_; } 233 | 234 | bool iat_; 235 | }; 236 | 237 | /** 238 | */ 239 | struct validate_jti_param 240 | { 241 | validate_jti_param(bool v) 242 | : jti_(v) 243 | {} 244 | 245 | bool get() const noexcept { return jti_; } 246 | 247 | bool jti_; 248 | }; 249 | 250 | /** 251 | */ 252 | struct nbf_param 253 | { 254 | nbf_param(const jwt::system_time_t tp) 255 | : duration_(std::chrono::duration_cast< 256 | std::chrono::seconds>(tp.time_since_epoch()).count()) 257 | {} 258 | 259 | nbf_param(const uint64_t epoch) 260 | : duration_(epoch) 261 | {} 262 | 263 | uint64_t get() const noexcept { return duration_; } 264 | 265 | uint64_t duration_; 266 | }; 267 | 268 | } // END namespace detail 269 | 270 | // Useful typedef 271 | using param_init_list_t = std::initializer_list>; 272 | using param_seq_list_t = std::initializer_list; 273 | 274 | 275 | /** 276 | */ 277 | inline detail::payload_param> 278 | payload(const param_init_list_t& kvs) 279 | { 280 | std::unordered_map m; 281 | 282 | for (const auto& elem : kvs) { 283 | m.emplace(elem.first.data(), elem.second.data()); 284 | } 285 | 286 | return { std::move(m) }; 287 | } 288 | 289 | /** 290 | */ 291 | template 292 | detail::payload_param 293 | payload(MappingConcept&& mc) 294 | { 295 | static_assert (jwt::detail::meta::is_mapping_concept::value, 296 | "Template parameter does not meet the requirements for MappingConcept."); 297 | 298 | return { std::forward(mc) }; 299 | } 300 | 301 | 302 | /** 303 | */ 304 | inline detail::secret_param secret(const string_view sv) 305 | { 306 | return { sv }; 307 | } 308 | 309 | template 310 | inline std::enable_if_t::value, detail::secret_function_param> 311 | secret(T&& fun) 312 | { 313 | return detail::secret_function_param{ fun }; 314 | } 315 | 316 | /** 317 | */ 318 | inline detail::algorithm_param algorithm(const string_view sv) 319 | { 320 | return { sv }; 321 | } 322 | 323 | /** 324 | */ 325 | inline detail::algorithm_param algorithm(jwt::algorithm alg) 326 | { 327 | return { alg }; 328 | } 329 | 330 | /** 331 | */ 332 | inline detail::headers_param> 333 | headers(const param_init_list_t& kvs) 334 | { 335 | std::map m; 336 | 337 | for (const auto& elem : kvs) { 338 | m.emplace(elem.first.data(), elem.second.data()); 339 | } 340 | 341 | return { std::move(m) }; 342 | } 343 | 344 | /** 345 | */ 346 | template 347 | detail::headers_param 348 | headers(MappingConcept&& mc) 349 | { 350 | static_assert (jwt::detail::meta::is_mapping_concept::value, 351 | "Template parameter does not meet the requirements for MappingConcept."); 352 | 353 | return { std::forward(mc) }; 354 | } 355 | 356 | /** 357 | */ 358 | inline detail::verify_param 359 | verify(bool v) 360 | { 361 | return { v }; 362 | } 363 | 364 | /** 365 | */ 366 | inline detail::leeway_param 367 | leeway(uint32_t l) 368 | { 369 | return { l }; 370 | } 371 | 372 | /** 373 | */ 374 | inline detail::algorithms_param> 375 | algorithms(const param_seq_list_t& seq) 376 | { 377 | std::vector vec; 378 | vec.reserve(seq.size()); 379 | 380 | for (const auto& e: seq) { vec.emplace_back(e.data(), e.length()); } 381 | 382 | return { std::move(vec) }; 383 | } 384 | 385 | template 386 | detail::algorithms_param 387 | algorithms(SequenceConcept&& sc) 388 | { 389 | return { std::forward(sc) }; 390 | } 391 | 392 | /** 393 | */ 394 | inline detail::audience_param 395 | aud(const jwt::string_view aud) 396 | { 397 | return { aud.data() }; 398 | } 399 | 400 | /** 401 | */ 402 | inline detail::issuer_param 403 | issuer(const jwt::string_view iss) 404 | { 405 | return { iss.data() }; 406 | } 407 | 408 | /** 409 | */ 410 | inline detail::subject_param 411 | sub(const jwt::string_view subj) 412 | { 413 | return { subj.data() }; 414 | } 415 | 416 | /** 417 | */ 418 | inline detail::validate_iat_param 419 | validate_iat(bool v) 420 | { 421 | return { v }; 422 | } 423 | 424 | /** 425 | */ 426 | inline detail::validate_jti_param 427 | validate_jti(bool v) 428 | { 429 | return { v }; 430 | } 431 | 432 | /** 433 | */ 434 | inline detail::nbf_param 435 | nbf(const system_time_t tp) 436 | { 437 | return { tp }; 438 | } 439 | 440 | /** 441 | */ 442 | inline detail::nbf_param 443 | nbf(const uint64_t epoch) 444 | { 445 | return { epoch }; 446 | } 447 | 448 | } // END namespace params 449 | } // END namespace jwt 450 | 451 | #endif 452 | -------------------------------------------------------------------------------- /include/jwt/short_string.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPP_JWT_SHORT_STRING_HPP 24 | #define CPP_JWT_SHORT_STRING_HPP 25 | 26 | #include 27 | #include "jwt/stack_alloc.hpp" 28 | 29 | namespace jwt { 30 | /* 31 | * A basic_string implementation using stack allocation. 32 | */ 33 | template 34 | using short_string = std::basic_string, stack_alloc>; 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/jwt/stack_alloc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | // The MIT License (MIT) 3 | // 4 | // Copyright (c) 2015 Howard Hinnant 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | */ 24 | 25 | #ifndef STACK_ALLOC_HPP 26 | #define STACK_ALLOC_HPP 27 | 28 | /* 29 | * Based on Howard Hinnants awesome allocator boilerplate code 30 | * https://howardhinnant.github.io/short_alloc.h 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | namespace jwt { 37 | 38 | /* 39 | */ 40 | template < 41 | /// Size of the stack allocated byte buffer. 42 | size_t N, 43 | /// The alignment required for the buffer. 44 | size_t alignment = alignof(std::max_align_t) 45 | > 46 | class Arena 47 | { 48 | public: // 'tors 49 | Arena() noexcept 50 | : ptr_(buf_) 51 | { 52 | static_assert (alignment <= alignof(std::max_align_t), 53 | "Alignment chosen is more than the maximum supported alignment"); 54 | } 55 | 56 | /// Non copyable and assignable 57 | Arena(const Arena&) = delete; 58 | Arena& operator=(const Arena&) = delete; 59 | 60 | ~Arena() 61 | { 62 | ptr_ = nullptr; 63 | } 64 | 65 | public: // Public APIs 66 | 67 | /* 68 | * Reserves space within the buffer of size atleast 'n' 69 | * bytes. 70 | * More bytes maybe reserved based on the alignment requirements. 71 | * 72 | * Returns: 73 | * 1. The pointer within the storage buffer where the object can be constructed. 74 | * 2. nullptr if space cannot be reserved for requested number of bytes 75 | * (+ alignment padding if applicable) 76 | */ 77 | template < 78 | /// The requested alignment for this allocation. 79 | /// Must be less than or equal to the 'alignment'. 80 | size_t requested_alignment 81 | > 82 | char* allocate(size_t n) noexcept; 83 | 84 | /* 85 | * Free back the space pointed by p within the storage buffer. 86 | */ 87 | void deallocate(char* p, size_t n) noexcept; 88 | 89 | /* 90 | * The size of the internal storage buffer. 91 | */ 92 | constexpr static size_t size() noexcept 93 | { 94 | return N; 95 | } 96 | 97 | /* 98 | * Returns number of remaining bytes within the storage buffer 99 | * that can be used for further allocation requests. 100 | */ 101 | size_t used() const noexcept 102 | { 103 | return static_cast(ptr_ - buf_); 104 | } 105 | 106 | private: // Private member functions 107 | 108 | /* 109 | * A check to determine if the pointer 'p' 110 | * points to a region within storage. 111 | */ 112 | bool pointer_in_storage(char* p) const noexcept 113 | { 114 | return (buf_ <= p) && (p <= (buf_ + N)); 115 | } 116 | 117 | /* 118 | * Rounds up the number to the next closest number 119 | * as per the alignment. 120 | */ 121 | constexpr static size_t align_up(size_t n) noexcept 122 | { 123 | return (n + (alignment - 1)) & ~(alignment - 1); 124 | } 125 | 126 | private: // data members 127 | /// Storage 128 | alignas(alignment) char buf_[N]; 129 | 130 | /// Current allocation pointer within storage 131 | char* ptr_ = nullptr; 132 | }; 133 | 134 | 135 | 136 | /* 137 | */ 138 | template < 139 | /// The allocator for type T 140 | typename T, 141 | /// Number of bytes for the arena 142 | size_t N, 143 | /// Alignment of the arena 144 | size_t align = alignof(std::max_align_t) 145 | > 146 | class stack_alloc 147 | { 148 | public: // typedefs 149 | using value_type = T; 150 | using arena_type = Arena; 151 | 152 | static auto constexpr alignment = align; 153 | static auto constexpr size = N; 154 | 155 | public: // 'tors 156 | stack_alloc(arena_type& a) 157 | : arena_(a) 158 | { 159 | } 160 | 161 | stack_alloc(const stack_alloc&) = default; 162 | stack_alloc& operator=(const stack_alloc&) = delete; 163 | 164 | template 165 | stack_alloc(const stack_alloc& other) 166 | : arena_(other.arena_) 167 | { 168 | } 169 | 170 | template 171 | struct rebind { 172 | using other = stack_alloc; 173 | }; 174 | 175 | public: // Exposed APIs 176 | 177 | /* 178 | * Allocate memory of 'n' bytes for object 179 | * of type 'T' 180 | */ 181 | T* allocate(size_t n) noexcept; 182 | 183 | /* 184 | * Deallocate the storage reserved for the object 185 | * of type T pointed by pointer 'p' 186 | */ 187 | void deallocate(T* p, size_t n) noexcept; 188 | 189 | private: // Private APIs 190 | 191 | private: // Private data members 192 | /// The arena 193 | arena_type& arena_; 194 | }; 195 | 196 | } // END namespace jwt 197 | 198 | #include "jwt/impl/stack_alloc.ipp" 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /include/jwt/string_view.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Arun Muralidharan 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef JWT_STRING_VIEW_HPP 24 | #define JWT_STRING_VIEW_HPP 25 | 26 | #if defined(__cpp_lib_string_view) 27 | 28 | #include 29 | 30 | namespace jwt { 31 | using string_view = std::string_view; 32 | } 33 | 34 | #else // defined(__cpp_lib_string_view) 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | namespace jwt { 41 | 42 | /* 43 | * Implements c++17 string_view. 44 | * Could have used boost::string_ref, but wanted to 45 | * keep boost dependency off from this library. 46 | */ 47 | 48 | template < 49 | typename CharT, 50 | typename Traits = std::char_traits 51 | > 52 | class basic_string_view 53 | { 54 | public: // Member Types 55 | using traits_type = std::char_traits; 56 | using value_type = CharT; 57 | using pointer = const CharT*; 58 | using const_pointer = const CharT*; 59 | using reference = const CharT&; 60 | using const_reference = const CharT&; 61 | using iterator = const CharT*; 62 | using const_iterator = const CharT*; 63 | using reverse_iterator = std::reverse_iterator; 64 | using const_reverse_iterator = std::reverse_iterator; 65 | using size_type = size_t; 66 | using difference_type = std::ptrdiff_t; 67 | 68 | static constexpr size_type npos = size_type(-1); 69 | 70 | public: // 'tors 71 | /// The default constructor; 72 | basic_string_view() = default; 73 | 74 | /// Construct from string literal 75 | basic_string_view(const CharT* str) noexcept 76 | : data_(str) 77 | , len_(str ? traits_type::length(str) : 0) 78 | { 79 | } 80 | 81 | /// Construct from CharT pointer and provided length 82 | basic_string_view(const CharT* p, size_type len) noexcept 83 | : data_(p) 84 | , len_(len) 85 | { 86 | } 87 | 88 | /// Construct from std::string 89 | template 90 | basic_string_view( 91 | const std::basic_string& str) noexcept 92 | : data_(str.data()) 93 | , len_(str.length()) 94 | { 95 | } 96 | 97 | /// Copy constructor 98 | basic_string_view(const basic_string_view&) = default; 99 | 100 | /// Assignment operator 101 | basic_string_view& operator=(const basic_string_view&) = default; 102 | 103 | /// Destructor 104 | ~basic_string_view() 105 | { 106 | data_ = nullptr; 107 | len_ = 0; 108 | } 109 | 110 | public: // Exposed APIs 111 | /// Iterator Member Functions 112 | 113 | iterator begin() const noexcept { return data_; } 114 | iterator end() const noexcept { return data_ + len_; } 115 | 116 | iterator rbegin() const noexcept { return reverse_iterator(end()); } 117 | iterator rend() const noexcept { return reverse_iterator(begin()); } 118 | 119 | const_iterator cbegin() const noexcept { return begin(); } 120 | const_iterator cend() const noexcept { return end(); } 121 | 122 | const_iterator crbegin() const noexcept { return rbegin(); } 123 | const_iterator crend() const noexcept { return rend(); } 124 | 125 | /// Capacity Member Functions 126 | 127 | size_type length() const noexcept { return len_; } 128 | size_type size() const noexcept { return len_; } 129 | 130 | size_type max_size() const noexcept 131 | { 132 | return (npos - sizeof(size_type) - sizeof(void*)) 133 | / sizeof(value_type) / 4; 134 | } 135 | 136 | bool empty() const noexcept { return len_ == 0; } 137 | 138 | /// Element Access Member Functions 139 | const_reference operator[](size_type idx) const noexcept 140 | { 141 | assert(idx < len_ && "string_view subscript out of range"); 142 | return data_[idx]; 143 | } 144 | 145 | // NOTE: 'at' not supported 146 | //CharT at(size_type idx) const; 147 | 148 | const_reference front() const noexcept 149 | { 150 | return data_[0]; 151 | } 152 | 153 | const_reference back() const noexcept 154 | { 155 | return data_[len_ - 1]; 156 | } 157 | 158 | const_pointer data() const noexcept 159 | { 160 | return data_; 161 | } 162 | 163 | /// Modifier Member Functions 164 | void remove_prefix(size_type n) noexcept 165 | { 166 | assert (n < len_ && "Data would point out of bounds"); 167 | data_ += n; 168 | len_ -= n; 169 | } 170 | 171 | void remove_suffix(size_type n) noexcept 172 | { 173 | assert (n < len_ && "Suffix length more than data length"); 174 | len_ -= n; 175 | } 176 | 177 | void swap(basic_string_view& other) 178 | { 179 | std::swap(data_, other.data_); 180 | std::swap(len_, other.len_); 181 | } 182 | 183 | /// String Operation Member Functions 184 | 185 | template 186 | explicit operator std::basic_string() const 187 | { 188 | return {data_, len_}; 189 | } 190 | 191 | // NOTE: Does not throw 192 | size_type copy(CharT* dest, size_type n, size_type pos = 0) const noexcept 193 | { 194 | assert (pos < len_ && n < len_); 195 | size_type to_copy = std::min(n, len_ - pos); 196 | 197 | for (size_type i = 0; i < to_copy; i++) { 198 | dest[i] = data_[i + pos]; 199 | } 200 | 201 | return to_copy; 202 | } 203 | 204 | // NOTE: Does not throw 205 | basic_string_view substr(size_type pos, size_type n = npos) const noexcept 206 | { 207 | assert (pos < len_ && "Start position should be less than length of the view"); 208 | assert (n == npos ? 1 : (n - pos) < len_ && 209 | "Substring length asked for is more than the view length"); 210 | 211 | if (n == npos) n = len_; 212 | 213 | return basic_string_view{data_ + pos, n}; 214 | } 215 | 216 | /// Comparison Member Functions 217 | int compare(const basic_string_view& other) const noexcept 218 | { 219 | int ret = traits_type::compare(data_, other.data_, std::min(len_, other.len_)); 220 | if (ret == 0) { 221 | ret = compare_length(len_, other.len_); 222 | } 223 | return ret; 224 | } 225 | 226 | int compare(size_type pos, size_type n, basic_string_view other) const noexcept 227 | { 228 | return substr(pos, n).compare(other); 229 | } 230 | 231 | int compare(const CharT* str) const noexcept 232 | { 233 | return compare(basic_string_view{str}); 234 | } 235 | 236 | int compare(size_type pos, size_type n, const CharT* str) const noexcept 237 | { 238 | return compare(pos, n, basic_string_view{str}); 239 | } 240 | 241 | int compare(size_type pos, size_type n1, const CharT* str, size_type n2) const noexcept 242 | { 243 | return compare(pos, n1, basic_string_view{str, n2}); 244 | } 245 | 246 | /// Find operations 247 | size_type find(const CharT* str, size_type pos, size_type n) const noexcept; 248 | 249 | size_type find(const CharT ch, size_type pos) const noexcept; 250 | 251 | size_type find(basic_string_view sv, size_type pos = 0) const noexcept 252 | { 253 | return find(sv.data(), pos, sv.length()); 254 | } 255 | 256 | size_type find(const CharT* str, size_type pos = 0) const noexcept 257 | { 258 | return find(str, pos, traits_type::length(str)); 259 | } 260 | 261 | size_type rfind(const CharT* str, size_type pos, size_type n) const noexcept; 262 | 263 | size_type rfind(const CharT ch, size_type pos) const noexcept; 264 | 265 | size_type rfind(basic_string_view sv, size_type pos = 0) const noexcept 266 | { 267 | return rfind(sv.data(), pos, sv.length()); 268 | } 269 | 270 | size_type rfind(const CharT* str, size_type pos = 0) const noexcept 271 | { 272 | return rfind(str, pos, traits_type::length(str)); 273 | } 274 | 275 | size_type find_first_of(const CharT* str, size_type pos, size_type count) const noexcept; 276 | 277 | size_type find_first_of(basic_string_view str, size_type pos = 0) const noexcept 278 | { 279 | return find_first_of(str.data(), pos, str.length()); 280 | } 281 | 282 | size_type find_first_of(CharT ch, size_type pos = 0) const noexcept 283 | { 284 | return find(ch, pos); 285 | } 286 | 287 | size_type find_first_of(const CharT* str, size_type pos = 0) const noexcept 288 | { 289 | return find_first_of(str, pos, traits_type::length(str)); 290 | } 291 | 292 | size_type find_last_of(const CharT* str, size_type pos, size_type count) const noexcept; 293 | 294 | size_type find_last_of(basic_string_view str, size_type pos = npos) const noexcept 295 | { 296 | return find_last_of(str.data(), (pos == npos ? len_ - 1 : pos), str.length()); 297 | } 298 | 299 | size_type find_last_of(CharT ch, size_type pos = npos) const noexcept 300 | { 301 | return rfind(ch, pos == npos ? len_ - 1 : pos); 302 | } 303 | 304 | size_type find_last_of(const CharT* str, size_type pos = npos) const noexcept 305 | { 306 | return find_last_of(str, (pos == npos ? len_ - 1 : pos), traits_type::length(str)); 307 | } 308 | 309 | size_type find_first_not_of(const CharT* str, size_type pos, size_type n) const noexcept; 310 | 311 | size_type find_first_not_of(CharT ch, size_type pos) const noexcept; 312 | 313 | size_type find_first_not_of(basic_string_view str, size_type pos = 0) const noexcept 314 | { 315 | return find_first_not_of(str.data(), pos, str.length()); 316 | } 317 | 318 | size_type find_first_not_of(const CharT* str, size_type pos = 0) const noexcept 319 | { 320 | return find_first_not_of(str, pos, traits_type::length(str)); 321 | } 322 | 323 | size_type find_last_not_of(const CharT* str, size_type pos, size_type n) const noexcept; 324 | 325 | size_type find_last_not_of(CharT ch, size_type pos) const noexcept; 326 | 327 | size_type find_last_not_of(basic_string_view str, size_type pos = npos) const noexcept 328 | { 329 | return find_last_not_of(str.data(), (pos == npos ? len_ - 1 : pos), str.length()); 330 | } 331 | 332 | size_type find_last_not_of(const CharT* str, size_type pos = npos) const noexcept 333 | { 334 | return find_last_not_of(str, (pos == npos ? len_ - 1 : pos), traits_type::length(str)); 335 | } 336 | 337 | /// Comparison operators Member Functions 338 | /* 339 | friend bool operator== (basic_string_view a, basic_string_view b) noexcept; 340 | 341 | friend bool operator!= (basic_string_view a, basic_string_view b) noexcept; 342 | 343 | friend bool operator< (basic_string_view a, basic_string_view b) noexcept; 344 | 345 | friend bool operator> (basic_string_view a, basic_string_view b) noexcept; 346 | 347 | friend bool operator<= (basic_string_view a, basic_string_view b) noexcept; 348 | 349 | friend bool operator>= (basic_string_view a, basic_string_view b) noexcept; 350 | */ 351 | 352 | private: // private implementations 353 | 354 | static constexpr int compare_length(size_type n1, size_type n2) noexcept 355 | { 356 | return static_cast(n1 - n2) > std::numeric_limits::max() 357 | ? std::numeric_limits::max() 358 | : static_cast(n1 - n2) < std::numeric_limits::min() 359 | ? std::numeric_limits::min() 360 | : static_cast(n1 - n2) 361 | ; 362 | } 363 | 364 | private: 365 | // This is what view is basically... 366 | const char* data_ = nullptr; 367 | size_type len_ = 0; 368 | }; 369 | 370 | 371 | /// Helper typedef 372 | using string_view = basic_string_view; 373 | 374 | 375 | } // END namespace jwt 376 | 377 | #include "jwt/impl/string_view.ipp" 378 | 379 | #endif // defined(__cpp_lib_string_view) 380 | 381 | #endif 382 | -------------------------------------------------------------------------------- /include/jwt/test/compile.txt: -------------------------------------------------------------------------------- 1 | g++ -std=c++14 -I /usr/local/Cellar/openssl/1.0.2j/include/ -I /Users/amuralid/dev_test/cpp-jwt/include/ -o test_rsa test_rsa.cc -L /usr/local/Cellar//openssl/1.0.2j/lib/ -lssl -lcrypto 2 | -------------------------------------------------------------------------------- /include/jwt/test/test_base64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_base64 -------------------------------------------------------------------------------- /include/jwt/test/test_base64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "jwt/base64.hpp" 5 | 6 | void base64_test_encode() 7 | { 8 | std::string input = "ArunMu"; 9 | std::string output = jwt::base64_encode(input.c_str(), input.length()); 10 | assert (output == "QXJ1bk11"); 11 | 12 | input = "Something really strange!!"; 13 | output = jwt::base64_encode(input.c_str(), input.length()); 14 | assert (output == "U29tZXRoaW5nIHJlYWxseSBzdHJhbmdlISE="); 15 | 16 | input = "Do you want to know something more stranger ????"; 17 | output = jwt::base64_encode(input.c_str(), input.length()); 18 | assert (output == "RG8geW91IHdhbnQgdG8ga25vdyBzb21ldGhpbmcgbW9yZSBzdHJhbmdlciA/Pz8/"); 19 | 20 | input = R"({"a" : "b", "c" : [1,2,3,4,5]})"; 21 | output = jwt::base64_encode(input.c_str(), input.length()); 22 | assert (output == "eyJhIiA6ICJiIiwgImMiIDogWzEsMiwzLDQsNV19"); 23 | } 24 | 25 | void base64_test_decode() 26 | { 27 | std::string input = "QXJ1bk11"; 28 | std::string output = jwt::base64_decode(input.c_str(), input.length()); 29 | assert (output == "ArunMu"); 30 | 31 | input = "U29tZXRoaW5nIHJlYWxseSBzdHJhbmdlISE="; 32 | output = jwt::base64_decode(input.c_str(), input.length()); 33 | assert (output == "Something really strange!!"); 34 | 35 | input = "RG8geW91IHdhbnQgdG8ga25vdyBzb21ldGhpbmcgbW9yZSBzdHJhbmdlciA/Pz8/"; 36 | output = jwt::base64_decode(input.c_str(), input.length()); 37 | assert (output == "Do you want to know something more stranger ????"); 38 | 39 | input = "eyJhIiA6ICJiIiwgImMiIDogWzEsMiwzLDQsNV19"; 40 | output = jwt::base64_decode(input.c_str(), input.length()); 41 | assert (output == R"({"a" : "b", "c" : [1,2,3,4,5]})"); 42 | } 43 | 44 | int main() { 45 | base64_test_encode(); 46 | base64_test_decode(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /include/jwt/test/test_evp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | EVP_MD_CTX *mdctx; 7 | const EVP_MD *md; 8 | char mess1[] = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaXNzIjoiYXJ1bi5jb20iLCJ0aW1lX3N0ciI6Ijg6MThwbSAyNCBOb3YgMjAxNyIsIndoZXJlIjoiYWlycG9ydCJ9"; 9 | unsigned char md_value[EVP_MAX_MD_SIZE]; 10 | int md_len, i; 11 | 12 | //OpenSSL_add_all_digests(); 13 | 14 | if(!argv[1]) { 15 | printf("Usage: mdtest digestname\n"); 16 | exit(1); 17 | } 18 | 19 | md = EVP_sha256(); 20 | 21 | if(!md) { 22 | printf("Unknown message digest %s\n", argv[1]); 23 | exit(1); 24 | } 25 | 26 | mdctx = EVP_MD_CTX_create(); 27 | EVP_DigestInit_ex(mdctx, md, NULL); 28 | EVP_DigestUpdate(mdctx, mess1, strlen(mess1)); 29 | EVP_DigestFinal_ex(mdctx, md_value, &md_len); 30 | EVP_MD_CTX_destroy(mdctx); 31 | 32 | printf("Dig: %s\n", md_value); 33 | printf("Dig: %d\n", md_len); 34 | 35 | printf("Digest is: "); 36 | for(i = 0; i < md_len; i++) 37 | printf("%02x", md_value[i]); 38 | printf("\n"); 39 | 40 | d2i_ECDSA_SIG(NULL, (const unsigned char **)&md_value[0], md_len); 41 | 42 | /* Call this once before exit. */ 43 | EVP_cleanup(); 44 | exit(0); 45 | } 46 | -------------------------------------------------------------------------------- /include/jwt/test/test_hmac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_hmac -------------------------------------------------------------------------------- /include/jwt/test/test_hmac.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/algorithm.hpp" 3 | 4 | void basic_hmac_test() 5 | { 6 | jwt::string_view sv = "secret" ; 7 | jwt::string_view d = "Some random data string"; 8 | auto res = jwt::HMACSign::sign(sv, d); 9 | 10 | std::cout << res.first << std::endl; 11 | } 12 | 13 | int main() { 14 | basic_hmac_test(); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_decode: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_jwt_decode -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_decode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/jwt.hpp" 3 | 4 | void basic_decode_test() 5 | { 6 | // Create header 7 | jwt::jwt_header hdr; 8 | hdr = jwt::jwt_header{jwt::algorithm::HS256}; 9 | 10 | // Create payload 11 | jwt::jwt_payload jp; 12 | jp.add_claim("sub", "1234567890"); 13 | jp.add_claim("name", "John Doe"); 14 | jp.add_claim("admin", true); 15 | 16 | jwt::jwt_signature sgn{"secret"}; 17 | std::error_code ec{}; 18 | auto res = sgn.encode(hdr, jp, ec); 19 | std::cout << res << std::endl; 20 | 21 | using namespace jwt::params; 22 | 23 | std::cout << "DECODE: \n"; 24 | jwt::decode(res, algorithms({"none", "HS256"}), ec, verify(false), secret("secret")); 25 | } 26 | 27 | int main() { 28 | basic_decode_test(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_header: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_jwt_header -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_header.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/jwt.hpp" 3 | 4 | void test_basic_header() 5 | { 6 | jwt::jwt_header hdr; 7 | hdr = jwt::jwt_header{jwt::algorithm::HS256}; 8 | std::string jstr = to_json_str(hdr); 9 | std::cout << jstr << std::endl; 10 | 11 | std::string enc_str = hdr.base64_encode(); 12 | std::cout << "Base64: " << enc_str << std::endl; 13 | std::cout << "Decoded: " << hdr.base64_decode(enc_str) << std::endl; 14 | } 15 | 16 | int main() { 17 | test_basic_header(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_object: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_jwt_object -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_object.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "jwt/jwt.hpp" 8 | 9 | void basic_jwt_object_test() 10 | { 11 | using namespace jwt::params; 12 | jwt::jwt_object obj(payload({ 13 | {"a", "b"}, 14 | {"c", "d"} 15 | })); 16 | 17 | //check with std::map 18 | std::map m; 19 | m["a"] = "b"; 20 | m["c"] = "d"; 21 | 22 | jwt::jwt_object obj1{payload(m)}; 23 | 24 | auto obj2 = std::move(obj1); 25 | 26 | std::cout << obj2.payload() << std::endl; 27 | 28 | //check with unordered map of string_view 29 | std::unordered_map um = { 30 | {"a", "b"}, 31 | {"c", "d"} 32 | }; 33 | jwt::jwt_object obj3{payload(um)}; 34 | 35 | obj3.add_claim("f", true) 36 | .add_claim("time", 176353563) 37 | .add_claim("exp", std::chrono::system_clock::now()) 38 | ; 39 | 40 | std::cout << jwt::to_json_str(obj3.payload(), true) << std::endl; 41 | 42 | obj3.remove_claim(std::string{"a"}); 43 | std::cout << obj3.payload() << std::endl; 44 | 45 | obj3.secret("secret"); 46 | obj3.header().algo("HS256"); 47 | 48 | auto dec_obj = jwt::decode(obj3.signature(), algorithms({"HS256"}), secret("secret")); 49 | } 50 | 51 | void jwt_object_pem_test() 52 | { 53 | using namespace jwt::params; 54 | 55 | std::string pub_key = 56 | R"(-----BEGIN PUBLIC KEY----- 57 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEomxC9ycc8AkXSwWQpu1kN5Fmgy/sD/KJ 58 | qN3tlSZmUEZ3w3c6KYJfK97PMOSZQaUdeydBoq/IOglQQOj8zLqubq5IpaaUiDQ5 59 | 0eJg79PvXuLiVUH98cBL/o8sDVB/sGzz 60 | -----END PUBLIC KEY-----)"; 61 | 62 | std::string priv_key = 63 | R"(-----BEGIN EC PRIVATE KEY----- 64 | MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT 65 | 13edeU8YdDugBwYFK4EEACKhZANiAASibEL3JxzwCRdLBZCm7WQ3kWaDL+wP8omo 66 | 3e2VJmZQRnfDdzopgl8r3s8w5JlBpR17J0Gir8g6CVBA6PzMuq5urkilppSINDnR 67 | 4mDv0+9e4uJVQf3xwEv+jywNUH+wbPM= 68 | -----END EC PRIVATE KEY-----)"; 69 | 70 | jwt::jwt_object obj; 71 | obj.secret(priv_key); 72 | obj.header().algo(jwt::algorithm::ES256); 73 | 74 | obj.add_claim("iss", "arun.com") 75 | .add_claim("where", "airport") 76 | .add_claim("time_str", "8:18pm 24 Nov 2017") 77 | .add_claim("id", 1) 78 | .add_claim("exp", std::chrono::system_clock::now()) 79 | ; 80 | 81 | std::cout << "pem sign " << obj.signature() << std::endl; 82 | std::cout << "Get claim value for exp: " << 83 | obj.payload().get_claim_value("exp") << std::endl; 84 | 85 | auto dec_obj = jwt::decode(obj.signature(), algorithms({"ES256"}), secret(pub_key)); 86 | std::cout << dec_obj.payload() << std::endl; 87 | } 88 | 89 | int main() { 90 | basic_jwt_object_test(); 91 | //jwt_object_pem_test(); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_payload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_jwt_payload -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_payload.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/jwt.hpp" 3 | 4 | void basic_payload_test() 5 | { 6 | jwt::jwt_payload jp; 7 | jp.add_claim("iss", "myself"); 8 | jp.add_claim("exp", 1234567); 9 | jp.add_claim("Exp", 1234567, true); 10 | 11 | auto jstr = jwt::to_json_str(jp); 12 | std::cout << jstr << std::endl; 13 | 14 | auto enc = jp.base64_encode(); 15 | std::cout << "Base64 enc: " << enc << std::endl; 16 | 17 | auto dec = jp.base64_decode(enc); 18 | std::cout << "Base64 dec: " << dec << std::endl; 19 | std::cout << "Base64 dec: " << jstr << std::endl; 20 | 21 | assert (jstr == dec && "Encoded and decoded messages do not match"); 22 | assert (jp.has_claim("exp") && "Claim exp must exist"); 23 | assert (jp.has_claim("Exp") && "Claim Exp must exist"); 24 | 25 | assert (!jp.has_claim("aud") && "Claim aud does not exist"); 26 | assert (jp.has_claim_with_value("exp", 1234567) && "Claim exp with value 1234567 does not exist"); 27 | 28 | return; 29 | } 30 | 31 | int main() { 32 | basic_payload_test(); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_signature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_jwt_signature -------------------------------------------------------------------------------- /include/jwt/test/test_jwt_signature.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/jwt.hpp" 3 | 4 | void basic_sign_test() 5 | { 6 | // Create header 7 | jwt::jwt_header hdr; 8 | hdr = jwt::jwt_header{jwt::algorithm::HS256}; 9 | 10 | // Create payload 11 | jwt::jwt_payload jp; 12 | jp.add_claim("sub", "1234567890"); 13 | jp.add_claim("name", "John Doe"); 14 | jp.add_claim("admin", true); 15 | 16 | jwt::jwt_signature sgn{"secret"}; 17 | std::error_code ec{}; 18 | auto res = sgn.encode(hdr, jp, ec); 19 | std::cout << res << std::endl; 20 | } 21 | 22 | int main() { 23 | basic_sign_test(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /include/jwt/test/test_rsa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_rsa -------------------------------------------------------------------------------- /include/jwt/test/test_rsa.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jwt/algorithm.hpp" 3 | 4 | static const char* rsa_2048_pem = 5 | R"(-----BEGIN PRIVATE KEY----- 6 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDC2kwAziXUf33m 7 | iqWp0yG6o259+nj7hpQLC4UT0Hmz0wmvreDJ/yNbSgOvsxvVdvzL2IaRZ+Gi5mo0 8 | lswWvL6IGz7PZO0kXTq9sdBnNqMOx27HddV9e/2/p0MgibJTbgywY2Sk23QYhJpq 9 | Kq/nU0xlBfSaI5ddZ2RC9ZNkVeGawUKYksTruhAVJqviHN8BoK6VowP5vcxyyOWH 10 | TK9KruDqzCIhqwRTeo0spokBkTN/LCuhVivcHAzUiJVtB4qAiTI9L/zkzhjpKz9P 11 | 45aLU54rj011gG8U/6E1USh5nMnPkr+d3oLfkhfS3Zs3kJVdyFQWZpQxiTaI92Fd 12 | 2wLvbS0HAgMBAAECggEAD8dTnkETSSjlzhRuI9loAtAXM3Zj86JLPLW7GgaoxEoT 13 | n7lJ2bGicFMHB2ROnbOb9vnas82gtOtJsGaBslmoaCckp/C5T1eJWTEb+i+vdpPp 14 | wZcmKZovyyRFSE4+NYlU17fEv6DRvuaGBpDcW7QgHJIl45F8QWEM+msee2KE+V4G 15 | z/9vAQ+sOlvsb4mJP1tJIBx9Lb5loVREwCRy2Ha9tnWdDNar8EYkOn8si4snPT+E 16 | 3ZCy8mlcZyUkZeiS/HdtydxZfoiwrSRYamd1diQpPhWCeRteQ802a7ds0Y2YzgfF 17 | UaYjNuRQm7zA//hwbXS7ELPyNMU15N00bajlG0tUOQKBgQDnLy01l20OneW6A2cI 18 | DIDyYhy5O7uulsaEtJReUlcjEDMkin8b767q2VZHb//3ZH+ipnRYByUUyYUhdOs2 19 | DYRGGeAebnH8wpTT4FCYxUsIUpDfB7RwfdBONgaKewTJz/FPswy1Ye0b5H2c6vVi 20 | m2FZ33HQcoZ3wvFFqyGVnMzpOwKBgQDXxL95yoxUGKa8vMzcE3Cn01szh0dFq0sq 21 | cFpM+HWLVr84CItuG9H6L0KaStEEIOiJsxOVpcXfFFhsJvOGhMA4DQTwH4WuXmXp 22 | 1PoVMDlV65PYqvhzwL4+QhvZO2bsrEunITXOmU7CI6kilnAN3LuP4HbqZgoX9lqP 23 | I31VYzLupQKBgGEYck9w0s/xxxtR9ILv5XRnepLdoJzaHHR991aKFKjYU/KD7JDK 24 | INfoAhGs23+HCQhCCtkx3wQVA0Ii/erM0II0ueluD5fODX3TV2ZibnoHW2sgrEsW 25 | vFcs36BnvIIaQMptc+f2QgSV+Z/fGsKYadG6Q+39O7au/HB7SHayzWkjAoGBAMgt 26 | Fzslp9TpXd9iBWjzfCOnGUiP65Z+GWkQ/SXFqD+SRir0+m43zzGdoNvGJ23+Hd6K 27 | TdQbDJ0uoe4MoQeepzoZEgi4JeykVUZ/uVfo+nh06yArVf8FxTm7WVzLGGzgV/uA 28 | +wtl/cRtEyAsk1649yW/KHPEIP8kJdYAJeoO8xSlAoGAERMrkFR7KGYZG1eFNRdV 29 | mJMq+Ibxyw8ks/CbiI+n3yUyk1U8962ol2Q0T4qjBmb26L5rrhNQhneM4e8mo9FX 30 | LlQapYkPvkdrqW0Bp72A/UNAvcGTmN7z5OCJGMUutx2hmEAlrYmpLKS8pM/p9zpK 31 | tEOtzsP5GMDYVlEp1jYSjzQ= 32 | -----END PRIVATE KEY-----)"; 33 | 34 | void basic_rsa_test() 35 | { 36 | jwt::string_view sv = rsa_2048_pem; 37 | jwt::string_view d = "Some random data string"; 38 | 39 | auto res = jwt::PEMSign::sign(sv, d); 40 | 41 | std::cout << res.first << std::endl; 42 | } 43 | 44 | int main() { 45 | basic_rsa_test(); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /include/jwt/test/test_stack_alloc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_stack_alloc -------------------------------------------------------------------------------- /include/jwt/test/test_stack_alloc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "jwt/stack_alloc.hpp" 4 | 5 | template 6 | using SmallVector = std::vector>; 7 | 8 | 9 | int main() 10 | { 11 | SmallVector::allocator_type::arena_type a; 12 | SmallVector v{a}; 13 | 14 | v.push_back(1); 15 | v.push_back(1); 16 | v.push_back(1); 17 | v.push_back(1); 18 | v.push_back(1); 19 | v.push_back(1); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /include/jwt/test/test_sv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun11299/cpp-jwt/a54fa08a3bc929ce16cd84264bb0653e548955f9/include/jwt/test/test_sv -------------------------------------------------------------------------------- /include/jwt/test/test_sv.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "jwt/string_view.hpp" 6 | 7 | using string_view = jwt::basic_string_view; 8 | 9 | void basic_cons() 10 | { 11 | // Default construction 12 | string_view sv{}; 13 | assert (sv.length() == 0 && "Size must be zero for default constructor"); 14 | 15 | // Construction from string literal 16 | string_view sv2{"Arun Muralidharan"}; 17 | assert (sv2.length() == strlen("Arun Muralidharan") && "Lengths must match"); 18 | 19 | const char* haystack = "some really big data with infinite objects...."; 20 | 21 | // Construct using part of data 22 | string_view sv3{haystack, 4}; 23 | assert (sv3.length() == 4 && "Partial construction is not ok"); 24 | assert (sv3.to_string() == "some" && "Partial strings are not equal"); 25 | 26 | return; 27 | } 28 | 29 | void iterator_test() 30 | { 31 | string_view sv{"Arun Muralidharan"}; 32 | for (auto c : sv) std::cout << c; 33 | std::cout << std::endl; 34 | return; 35 | } 36 | 37 | void str_operations() 38 | { 39 | string_view sv{"Arun Muralidharan"}; 40 | string_view tmp = sv; 41 | sv.remove_prefix(5); 42 | assert (sv.to_string() == "Muralidharan" && "Remove prefix failed"); 43 | 44 | sv = tmp; 45 | sv.remove_suffix(strlen("Muralidharan")); 46 | assert (sv.to_string() == "Arun " && "Remove suffix failed"); 47 | 48 | sv=tmp; 49 | { 50 | std::unique_ptr dst{new char[32]}; 51 | sv.copy(dst.get(), 6, 0); 52 | dst[6] = '\0'; 53 | assert (strlen(dst.get()) == 6 && "Copy Failed-1"); 54 | assert (std::string{dst.get()} == "Arun M" && "Copy Failed-2"); 55 | 56 | sv.copy(dst.get(), 8, 4); 57 | dst[8] = '\0'; 58 | assert (strlen(dst.get()) == 8 && "Middle copy failed-1"); 59 | assert (std::string{dst.get()} == " Muralid" && "Middle copy failed-2"); 60 | } 61 | 62 | { 63 | auto ss1 = sv.substr(0, 4); 64 | assert (ss1.to_string() == "Arun" && "Substr failed - 1"); 65 | 66 | auto ss2 = sv.substr(1, 3); 67 | assert (ss2.to_string() == "run" && "Substr failed - 2"); 68 | 69 | auto ss3 = sv.substr(0); 70 | assert (ss3.length() == sv.length() && "Substr failed - 3"); 71 | } 72 | 73 | return; 74 | } 75 | 76 | void find_oper() 77 | { 78 | string_view sv{"Arun Muralidharan"}; 79 | auto pos = sv.find("Arun", 0, 4); 80 | assert (pos == 0 && "Arun not found in sv"); 81 | 82 | pos = sv.find("arun", 0, 4); 83 | assert (pos == string_view::npos && "arun is not there in sv"); 84 | 85 | sv = "This has a, in it."; 86 | pos = sv.find_first_of(",", 0, 1); 87 | assert (pos != string_view::npos); 88 | assert (pos == 10 && "Comma not found at correct place"); 89 | 90 | pos = sv.find_first_of(",", 10, 1); 91 | assert (pos != string_view::npos); 92 | assert (pos == 10 && "Comma not found at correct place"); 93 | 94 | pos = sv.find_first_of(":", 10, 1); 95 | assert (pos == string_view::npos); 96 | 97 | pos = sv.find_last_of(",", 5, 1); 98 | assert (pos == string_view::npos); 99 | 100 | pos = sv.find_last_of(",", sv.length() - 1, 1); 101 | assert (pos != string_view::npos); 102 | assert (pos == 10 && "Comma not found at correct place"); 103 | 104 | pos = sv.find_first_of(".", 0, 1); 105 | assert (pos == sv.length() - 1 && "Dot not found at correct place"); 106 | 107 | pos = sv.find_last_of(".", sv.length() - 2, 1); 108 | assert (pos == string_view::npos); 109 | 110 | pos = sv.find_last_of(".", sv.length() - 1, 1); 111 | assert (pos == sv.length() - 1); 112 | 113 | sv = "Some string :<> with some ??? pattern --**"; 114 | 115 | pos = sv.rfind("???", sv.length() - 1, 3); 116 | assert (pos != string_view::npos && "??? not found"); 117 | assert (pos == 26 && "??? not found at the correct place"); 118 | 119 | sv = "ATCGTTCACGRRRTCGGGGACGTC"; 120 | 121 | pos = sv.find_first_not_of("ATCG"); 122 | assert (pos != string_view::npos); 123 | assert (pos == 10); 124 | 125 | return; 126 | } 127 | 128 | void conversions() 129 | { 130 | auto c2sv = [](int num) -> string_view { 131 | switch (num) { 132 | case 1: return "one"; 133 | case 2: return "two"; 134 | case 3: return "three"; 135 | default: return "many"; 136 | }; 137 | }; 138 | 139 | auto res = c2sv(2); 140 | assert (res.to_string() == "two"); 141 | 142 | auto s2sv = [](std::string s) { 143 | return s; 144 | }; 145 | 146 | s2sv(static_cast(res)); 147 | } 148 | 149 | void comparisons() 150 | { 151 | string_view s1{"Apple"}; 152 | string_view s2{"Orange"}; 153 | 154 | assert (s1 != s2 && "Two string views are not equal"); 155 | assert (s2 > s1 && "Orange is lexicographically bigger than Apple"); 156 | 157 | s2 = "Apples"; 158 | assert (s2 > s1 && "Because Apples is plural"); 159 | } 160 | 161 | int main() { 162 | basic_cons(); 163 | iterator_test(); 164 | str_operations(); 165 | find_oper(); 166 | conversions(); 167 | comparisons(); 168 | return 0; 169 | }; 170 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CERT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/certs") 2 | set(CMAKE_CXX_FLAGS 3 | "${CMAKE_CXX_FLAGS} -DCERT_ROOT_DIR=\"\\\"${CERT_ROOT_DIR}\\\"\"") 4 | 5 | add_executable(test_jwt_object test_jwt_object.cc) 6 | target_link_libraries(test_jwt_object GTest::GTest GTest::Main ${PROJECT_NAME}) 7 | target_include_directories(test_jwt_object PRIVATE ${GTEST_INCLUDE_DIRS} 8 | ${GTest_INCLUDE_DIRS}) 9 | add_test( 10 | NAME test_jwt_object 11 | COMMAND ./test_jwt_object 12 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 13 | 14 | add_executable(test_jwt_encode test_jwt_encode.cc) 15 | target_link_libraries(test_jwt_encode GTest::GTest GTest::Main ${PROJECT_NAME}) 16 | target_include_directories(test_jwt_encode PRIVATE ${GTEST_INCLUDE_DIRS} 17 | ${GTest_INCLUDE_DIRS}) 18 | add_test( 19 | NAME test_jwt_encode 20 | COMMAND ./test_jwt_encode 21 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 22 | 23 | add_executable(test_jwt_decode test_jwt_decode.cc) 24 | target_link_libraries(test_jwt_decode GTest::GTest GTest::Main ${PROJECT_NAME}) 25 | target_include_directories(test_jwt_decode PRIVATE ${GTEST_INCLUDE_DIRS} 26 | ${GTest_INCLUDE_DIRS}) 27 | add_test( 28 | NAME test_jwt_decode 29 | COMMAND ./test_jwt_decode 30 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 31 | 32 | add_executable(test_jwt_decode_verifiy test_jwt_decode_verifiy.cc) 33 | target_link_libraries(test_jwt_decode_verifiy GTest::GTest GTest::Main 34 | ${PROJECT_NAME}) 35 | target_include_directories(test_jwt_decode_verifiy 36 | PRIVATE ${GTEST_INCLUDE_DIRS} ${GTest_INCLUDE_DIRS}) 37 | add_test( 38 | NAME test_jwt_decode_verifiy 39 | COMMAND ./test_jwt_decode_verifiy 40 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 41 | 42 | add_executable(test_jwt_decode_verifiy_with_exception 43 | test_jwt_decode_verifiy_with_exception.cc) 44 | target_link_libraries(test_jwt_decode_verifiy_with_exception GTest::GTest GTest::Main 45 | ${PROJECT_NAME}) 46 | target_include_directories(test_jwt_decode_verifiy_with_exception 47 | PRIVATE ${GTEST_INCLUDE_DIRS} ${GTest_INCLUDE_DIRS}) 48 | add_test( 49 | NAME test_jwt_decode_verifiy_with_exception 50 | COMMAND ./test_jwt_decode_verifiy_with_exception 51 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 52 | 53 | add_executable(test_jwt_rsa test_jwt_rsa.cc) 54 | target_link_libraries(test_jwt_rsa GTest::GTest GTest::Main ${PROJECT_NAME}) 55 | target_include_directories(test_jwt_rsa PRIVATE ${GTEST_INCLUDE_DIRS} 56 | ${GTest_INCLUDE_DIRS}) 57 | add_test( 58 | NAME test_jwt_rsa 59 | COMMAND ./test_jwt_rsa 60 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 61 | 62 | add_executable(test_jwt_es test_jwt_es.cc) 63 | target_link_libraries(test_jwt_es GTest::GTest GTest::Main ${PROJECT_NAME}) 64 | target_include_directories(test_jwt_es PRIVATE ${GTEST_INCLUDE_DIRS} 65 | ${GTest_INCLUDE_DIRS}) 66 | add_test( 67 | NAME test_jwt_es 68 | COMMAND ./test_jwt_es 69 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 70 | -------------------------------------------------------------------------------- /tests/certs/ec_certs/ec384_priv.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT 3 | 13edeU8YdDugBwYFK4EEACKhZANiAASibEL3JxzwCRdLBZCm7WQ3kWaDL+wP8omo 4 | 3e2VJmZQRnfDdzopgl8r3s8w5JlBpR17J0Gir8g6CVBA6PzMuq5urkilppSINDnR 5 | 4mDv0+9e4uJVQf3xwEv+jywNUH+wbPM= 6 | -----END EC PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /tests/certs/ec_certs/ec384_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEomxC9ycc8AkXSwWQpu1kN5Fmgy/sD/KJ 3 | qN3tlSZmUEZ3w3c6KYJfK97PMOSZQaUdeydBoq/IOglQQOj8zLqubq5IpaaUiDQ5 4 | 0eJg79PvXuLiVUH98cBL/o8sDVB/sGzz 5 | -----END PUBLIC KEY----- 6 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa256_priv.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDC2kwAziXUf33m 3 | iqWp0yG6o259+nj7hpQLC4UT0Hmz0wmvreDJ/yNbSgOvsxvVdvzL2IaRZ+Gi5mo0 4 | lswWvL6IGz7PZO0kXTq9sdBnNqMOx27HddV9e/2/p0MgibJTbgywY2Sk23QYhJpq 5 | Kq/nU0xlBfSaI5ddZ2RC9ZNkVeGawUKYksTruhAVJqviHN8BoK6VowP5vcxyyOWH 6 | TK9KruDqzCIhqwRTeo0spokBkTN/LCuhVivcHAzUiJVtB4qAiTI9L/zkzhjpKz9P 7 | 45aLU54rj011gG8U/6E1USh5nMnPkr+d3oLfkhfS3Zs3kJVdyFQWZpQxiTaI92Fd 8 | 2wLvbS0HAgMBAAECggEAD8dTnkETSSjlzhRuI9loAtAXM3Zj86JLPLW7GgaoxEoT 9 | n7lJ2bGicFMHB2ROnbOb9vnas82gtOtJsGaBslmoaCckp/C5T1eJWTEb+i+vdpPp 10 | wZcmKZovyyRFSE4+NYlU17fEv6DRvuaGBpDcW7QgHJIl45F8QWEM+msee2KE+V4G 11 | z/9vAQ+sOlvsb4mJP1tJIBx9Lb5loVREwCRy2Ha9tnWdDNar8EYkOn8si4snPT+E 12 | 3ZCy8mlcZyUkZeiS/HdtydxZfoiwrSRYamd1diQpPhWCeRteQ802a7ds0Y2YzgfF 13 | UaYjNuRQm7zA//hwbXS7ELPyNMU15N00bajlG0tUOQKBgQDnLy01l20OneW6A2cI 14 | DIDyYhy5O7uulsaEtJReUlcjEDMkin8b767q2VZHb//3ZH+ipnRYByUUyYUhdOs2 15 | DYRGGeAebnH8wpTT4FCYxUsIUpDfB7RwfdBONgaKewTJz/FPswy1Ye0b5H2c6vVi 16 | m2FZ33HQcoZ3wvFFqyGVnMzpOwKBgQDXxL95yoxUGKa8vMzcE3Cn01szh0dFq0sq 17 | cFpM+HWLVr84CItuG9H6L0KaStEEIOiJsxOVpcXfFFhsJvOGhMA4DQTwH4WuXmXp 18 | 1PoVMDlV65PYqvhzwL4+QhvZO2bsrEunITXOmU7CI6kilnAN3LuP4HbqZgoX9lqP 19 | I31VYzLupQKBgGEYck9w0s/xxxtR9ILv5XRnepLdoJzaHHR991aKFKjYU/KD7JDK 20 | INfoAhGs23+HCQhCCtkx3wQVA0Ii/erM0II0ueluD5fODX3TV2ZibnoHW2sgrEsW 21 | vFcs36BnvIIaQMptc+f2QgSV+Z/fGsKYadG6Q+39O7au/HB7SHayzWkjAoGBAMgt 22 | Fzslp9TpXd9iBWjzfCOnGUiP65Z+GWkQ/SXFqD+SRir0+m43zzGdoNvGJ23+Hd6K 23 | TdQbDJ0uoe4MoQeepzoZEgi4JeykVUZ/uVfo+nh06yArVf8FxTm7WVzLGGzgV/uA 24 | +wtl/cRtEyAsk1649yW/KHPEIP8kJdYAJeoO8xSlAoGAERMrkFR7KGYZG1eFNRdV 25 | mJMq+Ibxyw8ks/CbiI+n3yUyk1U8962ol2Q0T4qjBmb26L5rrhNQhneM4e8mo9FX 26 | LlQapYkPvkdrqW0Bp72A/UNAvcGTmN7z5OCJGMUutx2hmEAlrYmpLKS8pM/p9zpK 27 | tEOtzsP5GMDYVlEp1jYSjzQ= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa256_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwtpMAM4l1H995oqlqdMh 3 | uqNuffp4+4aUCwuFE9B5s9MJr63gyf8jW0oDr7Mb1Xb8y9iGkWfhouZqNJbMFry+ 4 | iBs+z2TtJF06vbHQZzajDsdux3XVfXv9v6dDIImyU24MsGNkpNt0GISaaiqv51NM 5 | ZQX0miOXXWdkQvWTZFXhmsFCmJLE67oQFSar4hzfAaCulaMD+b3Mcsjlh0yvSq7g 6 | 6swiIasEU3qNLKaJAZEzfywroVYr3BwM1IiVbQeKgIkyPS/85M4Y6Ss/T+OWi1Oe 7 | K49NdYBvFP+hNVEoeZzJz5K/nd6C35IX0t2bN5CVXchUFmaUMYk2iPdhXdsC720t 8 | BwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa384_priv.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | nfictCHvTZXlDWYlp5Uf8IDXrd4= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa384_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAybi/3guc70NLoGecAdyA 3 | o0dJYLRXCYFdx7Iaq20REXb5SsyqSjGV/KEr8sdyFhr/PasKb1XbV7G8/gdtxU+S 4 | l5dGI9h8mymIQ7VzbyEhwQqjzdyCKoz2levKPgjsTDN93IQiNfSOfc4qUux5viWQ 5 | aPWt3bzpvOZXHcMUbzEz/jahKZPU/hMq/N3DroE6xFYB91fb74qHOC5RGMPjskUY 6 | KOjCtj+v+sZqznuckf2x0a2r5X++gsqGZT8dHaX9smyrpBbV9Y/g1VZ+CO8XFdRi 7 | HWth98FnlbEeHsrXbho9CE2GEACWvRRApMn1uSpghpENbkefpbYCIN7tq6X4lKvS 8 | YQZARiLkD1ELHcmWCX+cpIlfxihrKpVnRR4iLJNl33VtOBIPaMvtifojkLxsi3dt 9 | yJkcEFQI/kXbKW8Kdw5Fd+UOcsQf8PKk7k9LgFaH8GZRFhbwT0bLjjy0UIV5NDHc 10 | SozydV2uQh+ON6BsygCSvME8V4lu9z74Rq3T7eP25pC+Q0mN+1n7QGQL4zKshkKN 11 | h6Rx+QCP0hVGNosL6MoLzseluapTqnHrQEHTbG1Jm+WL/ces3thH7PySyWKJcUQ/ 12 | iWBD0FFkya0KTvTfWvBg/WPdqBHLIQh6ie/7lOFyE56FbRYuRU0cF8+NykA/6HN2 13 | 47pFtw1PSgQ68Dqtv9bZMFUCAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa512_priv.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 99 | EtoiU3WKndSOrpIVOqOQTQU54puQoOE= 100 | -----END PRIVATE KEY----- 101 | -------------------------------------------------------------------------------- /tests/certs/rsa_certs/rsa512_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAs0XMckvY06KW80N/Fz5r 3 | BJUN3BlsUoViZYjpZy5UbhNAt96tdnoMMXJw6vd9+/DWwBEgpq7cRUsWq1qRkqSL 4 | z8dxTQ8OGsxauFVTWRTX3ZMQ/YtZJDGa1+snkxhsLxnvpXx/KPgYU1WTqB46GV+i 5 | twsZ69S0nq+cNMjIFiz6TJMNVNwI5yEdYUildxb0YmGu/ZBQMihcrYesAJSQezNu 6 | 10YvioSIQUASHjfVcFMMLtZRYvi7idIfejb7iW2rPlO7sF4ZNhTaSoszB03BvnNZ 7 | jikORBnDz71AgMKqW/Itlq/uMuMb0XlPCiLZgS83oLfSvMQQspeOks3yv5w3Hv+s 8 | EFXrSZyyt3SPxHuc3gggSqLcfzCV4PG/p2H7y5Q6i9VHPaA89ZQXlKWQC46sripP 9 | OtkSAkyJU9NJ/WkYNnnXzQiKA3kfN2mLCOzpv62SGoUrEssycTuVLUKTzM76LaYQ 10 | /lGbpbSrTGvZEmm3OJjjFr5r2JSPmzGw+5dOUpJ+i3r9+um+iUKKpOkTISYyCXY1 11 | 7w9yf13W4Gms7l5XJU+pRIlBlb3H2QFN2u9wp7mEXYOJzGNGpA3oHFKUmn40jlz5 12 | 09dNpGaG4SXzJG8Uku+mWrjWWsnh9VcZQhgLKVobJsmmSIkqcpJCityl21LAk7Do 13 | UB0GeMCFOjzPhZ0ncD7RVBwq762A6rcowuuY8Lwbrp9auNgzzhHHr+c01aFvqZbU 14 | T4oaxSFInyrocsyCqJYQEG3sDK6NMxNIPs9NIyC+IWPbqvxESOGJK6rLmh2WCaD0 15 | irCvboW5yxfxEaCuu3WWUFFEecR0KvHRQig/dFb2Jyo4fypzqdSRtAu0R7/qOn6p 16 | LsEO9XseQh7uRzdagwb9CjdBB8nKB5zVQ79gswBDY2+gDl1UphywtT+ISr4kLUm3 17 | tvOFQZjj1SNaZdLTDQbxO9GWjwaijIQbAdMU0f9kE7FHIR3vPEMLfwNgpo6hEyuk 18 | TBfBTT1cq8eHQt0WbDLDYFcuA1fFa9XGrZPmmGCoV8AFKQaUNRcIbfRWnykPs9oJ 19 | Ki60gKbhoIStIq/DkV/B8OPTMRTbFranSJDaO2P6O0A5Y7Rezhjnqyb0oiJsKg74 20 | +/TcgL/tZB+YB3AG3gdElVnu9cWuR2FpY35L1WAk9zA46Z4dxQyL7nNpQDg5pX4Q 21 | 8sXK2x3Ov1VmYy1TmUxpv1eLTMxts0yXYDQFGcDS4VuDfZZNkIXMOMEo4y5fQw11 22 | OOcElpvyVMUkYl0LgJvIqbUCzCulkrruKKPPdHrtJvhImysgT46lbjKPGDT4D/6q 23 | It4UqV9B969PNbqfqFORnmgaH3oF3xxbAQfcasfUxCPxChYpOPs25ldtAASAAqDO 24 | RwIDAQAB 25 | -----END PUBLIC KEY----- 26 | -------------------------------------------------------------------------------- /tests/compile.txt: -------------------------------------------------------------------------------- 1 | g++ -std=c++14 -I /usr/local/Cellar/openssl/1.0.2j/include/ -I /Users/amuralid/dev_test/cpp-jwt/include/ -o test_jwt_encode test_jwt_encode.cc -L /usr/local/Cellar//openssl/1.0.2j/lib/ -lssl -lcrypto -lgtest 2 | -------------------------------------------------------------------------------- /tests/test_jwt_decode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "gtest/gtest.h" 3 | #include "jwt/jwt.hpp" 4 | 5 | TEST (DecodeTest, InvalidFinalDotForNoneAlg) 6 | { 7 | using namespace jwt::params; 8 | const char* inv_enc_str = 9 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ"; 10 | 11 | std::error_code ec; 12 | auto obj = jwt::decode(inv_enc_str, algorithms({"none", "HS256"}), ec); 13 | 14 | ASSERT_TRUE (ec); 15 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::SignatureFormatError)); 16 | } 17 | 18 | TEST (DecodeTest, DecodeNoneAlgSign) 19 | { 20 | using namespace jwt::params; 21 | const char* enc_str = 22 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjo0NTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 23 | 24 | std::error_code ec; 25 | auto obj = jwt::decode(enc_str, algorithms({"none"}), ec, verify(true)); 26 | EXPECT_TRUE (ec); 27 | EXPECT_EQ (ec.value(), static_cast(jwt::AlgorithmErrc::NoneAlgorithmUsed)); 28 | 29 | std::cout << obj.payload() << std::endl; 30 | 31 | EXPECT_FALSE (obj.has_claim("iss")); 32 | EXPECT_FALSE (obj.has_claim("ISS")); 33 | 34 | EXPECT_TRUE (obj.has_claim("aud")); 35 | EXPECT_TRUE (obj.has_claim("exp")); 36 | 37 | EXPECT_EQ (obj.payload().get_claim_value("exp"), static_cast(4513863371)); 38 | } 39 | 40 | TEST (DecodeTest, DecodeWrongAlgo) 41 | { 42 | using namespace jwt::params; 43 | 44 | const char* enc_str = 45 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 46 | 47 | std::error_code ec; 48 | auto obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret(""), verify(true)); 49 | EXPECT_TRUE (ec); 50 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::InvalidAlgorithm)); 51 | } 52 | 53 | TEST (DecodeTest, DecodeInvalidHeader) 54 | { 55 | using namespace jwt::params; 56 | 57 | const char* enc_str = 58 | "ehbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 59 | 60 | std::error_code ec; 61 | auto obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret(""), verify(true)); 62 | ASSERT_TRUE (ec); 63 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::JsonParseError)); 64 | 65 | } 66 | 67 | TEST (DecodeTest, DecodeEmptyHeader) 68 | { 69 | using namespace jwt::params; 70 | 71 | const char* enc_str = 72 | ".eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 73 | 74 | std::error_code ec; 75 | auto obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret(""), verify(true)); 76 | ASSERT_TRUE (ec); 77 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::JsonParseError)); 78 | 79 | } 80 | 81 | TEST (DecodeTest, DecodeInvalidPayload) 82 | { 83 | using namespace jwt::params; 84 | 85 | const char* enc_str = 86 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyfhuWcikiJyaWZ0LmlvIiwiZXhwIsexNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 87 | 88 | std::error_code ec; 89 | auto obj = jwt::decode(enc_str, algorithms({"none"}), ec, verify(true)); 90 | ASSERT_TRUE (ec); 91 | 92 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::JsonParseError)); 93 | } 94 | 95 | TEST (DecodeTest, DecodeHS256) 96 | { 97 | using namespace jwt::params; 98 | 99 | const char* enc_str = 100 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 101 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 102 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 103 | 104 | std::error_code ec; 105 | auto obj = jwt::decode(enc_str, algorithms({"none", "HS256"}), ec, verify(false), secret("secret")); 106 | ASSERT_FALSE (ec); 107 | 108 | EXPECT_TRUE (obj.has_claim("iss")); 109 | EXPECT_TRUE (obj.payload().has_claim_with_value("iss", "arun.muralidharan")); 110 | 111 | //Case sensitive search 112 | EXPECT_FALSE (obj.has_claim("IAT")); 113 | EXPECT_TRUE (obj.payload().has_claim_with_value(jwt::registered_claims::issued_at, 1513862371)); 114 | 115 | EXPECT_FALSE (obj.payload().has_claim_with_value(jwt::registered_claims::issued_at, 1513862372)); 116 | } 117 | 118 | TEST (DecodeTest, SecretKeyNotPassed) 119 | { 120 | using namespace jwt::params; 121 | 122 | const char* enc_str = 123 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 124 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 125 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 126 | 127 | std::error_code ec; 128 | auto obj = jwt::decode(enc_str, algorithms({"none", "HS256"}), ec, verify(true)); 129 | 130 | ASSERT_TRUE (ec); 131 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::KeyNotPresent)); 132 | } 133 | 134 | TEST (DecodeTest, DecodeHS384) 135 | { 136 | using namespace jwt::params; 137 | 138 | const char* enc_str = 139 | "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9." 140 | "eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ." 141 | "cGN4FZCe9Y2c1dA-jP71IXGnYbJRc4OaUTa5m7N7ybF5h6wBwxWQ-pdcxYchjDBL"; 142 | 143 | const jwt::string_view key = "0123456789abcdefghijklmnopqrstuvwxyz"; 144 | 145 | std::error_code ec; 146 | auto obj = jwt::decode(enc_str, algorithms({"none", "HS384"}), ec, verify(false), secret(key)); 147 | ASSERT_FALSE (ec); 148 | 149 | EXPECT_TRUE (obj.has_claim("sub")); 150 | EXPECT_TRUE (obj.payload().has_claim_with_value("sub", "nothing much")); 151 | } 152 | 153 | TEST (DecodeTest, DecodeHS512) 154 | { 155 | using namespace jwt::params; 156 | 157 | const char* enc_str = 158 | "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9." 159 | "eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ." 160 | "vQ-1JSFN1kPjUI3URP6AFK5z8V7xLhyhw-76QWhQg9Xcy-IgrJ-bCTYLBjgaprrcEWwpSnBQnP3QnIxYK0HEaQ"; 161 | 162 | const jwt::string_view key = "00112233445566778899"; 163 | 164 | std::error_code ec; 165 | auto obj = jwt::decode(enc_str, algorithms({"none", "HS384", "HS512"}), ec, verify(false), secret(key)); 166 | 167 | ASSERT_FALSE (ec); 168 | 169 | EXPECT_TRUE (obj.has_claim("sub")); 170 | EXPECT_TRUE (obj.payload().has_claim_with_value("sub", "nothing much")); 171 | } 172 | 173 | TEST (DecodeTest, TypHeaderMiss) 174 | { 175 | using namespace jwt::params; 176 | 177 | const char* enc_str = 178 | "eyJhbGciOiJIUzI1NiJ9." 179 | "eyJleHAiOjE1MzM0NjE1NTMsImlhdCI6MTUxMzg2MjM3MSwiaWQiOiJhLWItYy1kLWUtZi0xLTItMyIsImlzcyI6ImFydW4ubXVyYWxpZGhhcmFuIiwic3ViIjoiYWRtaW4ifQ." 180 | "pMWBLSWl1p4V958lfe_6ZhvgFMOQv9Eq5mlndVKFKkA"; 181 | 182 | std::error_code ec; 183 | auto obj = jwt::decode(enc_str, algorithms({"none", "HS256"}), ec, verify(false)); 184 | std::cout << "Decode header: " << obj.header() << std::endl; 185 | 186 | EXPECT_FALSE (ec); 187 | } 188 | 189 | TEST (DecodeTest, AlgoConfusionAttack) 190 | { 191 | using namespace jwt::params; 192 | 193 | using namespace jwt::params; 194 | 195 | const char* enc_str = 196 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 197 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 198 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 199 | 200 | std::string pub_key = R"(-----BEGIN PUBLIC KEY----- 201 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwtpMAM4l1H995oqlqdMh 202 | uqNuffp4+4aUCwuFE9B5s9MJr63gyf8jW0oDr7Mb1Xb8y9iGkWfhouZqNJbMFry+ 203 | iBs+z2TtJF06vbHQZzajDsdux3XVfXv9v6dDIImyU24MsGNkpNt0GISaaiqv51NM 204 | ZQX0miOXXWdkQvWTZFXhmsFCmJLE67oQFSar4hzfAaCulaMD+b3Mcsjlh0yvSq7g 205 | 6swiIasEU3qNLKaJAZEzfywroVYr3BwM1IiVbQeKgIkyPS/85M4Y6Ss/T+OWi1Oe 206 | K49NdYBvFP+hNVEoeZzJz5K/nd6C35IX0t2bN5CVXchUFmaUMYk2iPdhXdsC720t 207 | BwIDAQAB 208 | -----END PUBLIC KEY-----)"; 209 | 210 | std::error_code ec; 211 | auto obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, verify(true), secret(pub_key)); 212 | 213 | ASSERT_TRUE (ec); 214 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::AlgoConfusionAttack)); 215 | 216 | } -------------------------------------------------------------------------------- /tests/test_jwt_decode_verifiy.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "jwt/jwt.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | TEST (DecodeVerify, BeforeExpiryTest) 9 | { 10 | using namespace jwt::params; 11 | 12 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 13 | obj.add_claim("iss", "arun.muralidharan") 14 | .add_claim("exp", std::chrono::system_clock::now() + std::chrono::seconds{10}) 15 | ; 16 | 17 | std::error_code ec; 18 | auto enc_str = obj.signature(ec); 19 | 20 | ASSERT_FALSE (ec); 21 | 22 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), verify(true)); 23 | ASSERT_FALSE (ec); 24 | } 25 | 26 | TEST (DecodeVerify, AfterExpiryTest) 27 | { 28 | using namespace jwt::params; 29 | 30 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 31 | obj.add_claim("iss", "arun.muralidharan") 32 | .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1}) 33 | ; 34 | 35 | std::error_code ec; 36 | auto enc_str = obj.signature(ec); 37 | ASSERT_FALSE (ec); 38 | 39 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), verify(true)); 40 | ASSERT_TRUE (ec); 41 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::TokenExpired)); 42 | } 43 | 44 | TEST (DecodeVerify, AfterExpiryWithLeeway) 45 | { 46 | using namespace jwt::params; 47 | 48 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 49 | obj.add_claim("iss", "arun.muralidharan") 50 | .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1}) 51 | ; 52 | 53 | std::error_code ec; 54 | auto enc_str = obj.signature(ec); 55 | ASSERT_FALSE (ec); 56 | 57 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), verify(true), leeway(2)); 58 | ASSERT_FALSE (ec); 59 | } 60 | 61 | TEST (DecodeVerify, ValidIssuerTest) 62 | { 63 | using namespace jwt::params; 64 | 65 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 66 | obj.add_claim("iss", "arun.muralidharan") 67 | .add_claim("sub", "test") 68 | ; 69 | 70 | std::error_code ec; 71 | auto enc_str = obj.signature(ec); 72 | ASSERT_FALSE (ec); 73 | 74 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), issuer("arun.muralidharan")); 75 | ASSERT_FALSE (ec); 76 | } 77 | 78 | TEST (DecodeVerify, InvalidIssuerTest_1) 79 | { 80 | using namespace jwt::params; 81 | 82 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 83 | std::error_code ec; 84 | auto enc_str = obj.signature(ec); 85 | ASSERT_FALSE (ec); 86 | 87 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), issuer("arun.muralidharan")); 88 | ASSERT_TRUE (ec); 89 | 90 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::InvalidIssuer)); 91 | } 92 | 93 | TEST (DecodeVerify, InvalidIssuerTest_2) 94 | { 95 | using namespace jwt::params; 96 | 97 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 98 | obj.add_claim("iss", "arun.muralidharan"); 99 | 100 | std::error_code ec; 101 | auto enc_str = obj.signature(ec); 102 | ASSERT_FALSE (ec); 103 | 104 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), issuer("arun.murali")); 105 | ASSERT_TRUE (ec); 106 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::InvalidIssuer)); 107 | } 108 | 109 | TEST (DecodeVerify, NotImmatureSignatureTest) 110 | { 111 | using namespace jwt::params; 112 | 113 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 114 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() - std::chrono::seconds{10}); 115 | 116 | std::error_code ec; 117 | auto enc_str = obj.signature(ec); 118 | ASSERT_FALSE (ec); 119 | 120 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret")); 121 | ASSERT_FALSE (ec); 122 | } 123 | 124 | TEST (DecodeVerify, ImmatureSignatureTest) 125 | { 126 | using namespace jwt::params; 127 | 128 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 129 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() + std::chrono::seconds{10}); 130 | 131 | std::error_code ec; 132 | auto enc_str = obj.signature(ec); 133 | ASSERT_FALSE (ec); 134 | 135 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret")); 136 | ASSERT_TRUE (ec); 137 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::ImmatureSignature)); 138 | } 139 | 140 | TEST (DecodeVerify, ImmatureSignatureTestWithLeeway) 141 | { 142 | using namespace jwt::params; 143 | 144 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 145 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() + std::chrono::seconds{10}); 146 | 147 | std::error_code ec; 148 | auto enc_str = obj.signature(ec); 149 | ASSERT_FALSE (ec); 150 | 151 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), leeway(10)); 152 | ASSERT_FALSE (ec); 153 | } 154 | 155 | TEST (DecodeVerify, InvalidAudienceTest) 156 | { 157 | using namespace jwt::params; 158 | 159 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}, {"aud", "www"}})}; 160 | 161 | std::error_code ec; 162 | auto enc_str = obj.signature(ec); 163 | ASSERT_FALSE (ec); 164 | 165 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), aud("ww")); 166 | ASSERT_TRUE (ec); 167 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::InvalidAudience)); 168 | } 169 | 170 | TEST (DecodeVerify, InvalidIATTest) 171 | { 172 | using namespace jwt::params; 173 | 174 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}, {"aud", "www"}})}; 175 | 176 | obj.add_claim("iat", "what?"); 177 | auto enc_str = obj.signature(); 178 | 179 | std::error_code ec; 180 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), validate_iat(true)); 181 | EXPECT_EQ (ec.value(), static_cast(jwt::VerificationErrc::TypeConversionError)); 182 | } 183 | 184 | TEST (DecodeVerify, InvalidSignatureTest) 185 | { 186 | using namespace jwt::params; 187 | 188 | std::error_code ec; 189 | auto dec_obj = jwt::decode("", algorithms({"HS256"}), ec, secret("secret"), validate_iat(true)); 190 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::SignatureFormatError)); 191 | 192 | ec.clear(); 193 | dec_obj = jwt::decode("abcdsdfhbsdhjfbsdj.", algorithms({"HS256"}), ec, secret("secret"), validate_iat(true)); 194 | EXPECT_EQ (ec.value(), static_cast(jwt::DecodeErrc::SignatureFormatError)); 195 | } 196 | 197 | -------------------------------------------------------------------------------- /tests/test_jwt_decode_verifiy_with_exception.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "jwt/jwt.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | TEST (DecodeVerifyExp, BeforeExpiryTest) 9 | { 10 | using namespace jwt::params; 11 | 12 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 13 | obj.add_claim("iss", "arun.muralidharan") 14 | .add_claim("exp", std::chrono::system_clock::now() + std::chrono::seconds{10}) 15 | ; 16 | 17 | auto enc_str = obj.signature(); 18 | 19 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), verify(true)); 20 | } 21 | 22 | TEST (DecodeVerifyExp, AfterExpiryTest) 23 | { 24 | using namespace jwt::params; 25 | 26 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 27 | obj.add_claim("iss", "arun.muralidharan") 28 | .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1}) 29 | ; 30 | 31 | auto enc_str = obj.signature(); 32 | 33 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), verify(true)), 34 | jwt::TokenExpiredError); 35 | 36 | } 37 | 38 | TEST (DecodeVerifyExp, AfterExpiryWithLeeway) 39 | { 40 | using namespace jwt::params; 41 | 42 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 43 | obj.add_claim("iss", "arun.muralidharan") 44 | .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1}) 45 | ; 46 | 47 | auto enc_str = obj.signature(); 48 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), verify(true), leeway(2)); 49 | (void)dec_obj; 50 | } 51 | 52 | TEST (DecodeVerifyExp, ValidIssuerTest) 53 | { 54 | using namespace jwt::params; 55 | 56 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 57 | obj.add_claim("iss", "arun.muralidharan") 58 | .add_claim("sub", "test") 59 | ; 60 | 61 | auto enc_str = obj.signature(); 62 | 63 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), issuer("arun.muralidharan")); 64 | (void)dec_obj; 65 | } 66 | 67 | TEST (DecodeVerifyExp, InvalidIssuerTest_1) 68 | { 69 | using namespace jwt::params; 70 | 71 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 72 | auto enc_str = obj.signature(); 73 | 74 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), issuer("arun.muralidharan")), 75 | jwt::InvalidIssuerError); 76 | 77 | } 78 | 79 | TEST (DecodeVerifyExp, InvalidIssuerTest_2) 80 | { 81 | using namespace jwt::params; 82 | 83 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 84 | obj.add_claim("iss", "arun.muralidharan"); 85 | 86 | auto enc_str = obj.signature(); 87 | 88 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), issuer("arun.murali")), 89 | jwt::InvalidIssuerError); 90 | } 91 | 92 | TEST (DecodeVerifyExp, NotImmatureSignatureTest) 93 | { 94 | using namespace jwt::params; 95 | 96 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 97 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() - std::chrono::seconds{10}); 98 | 99 | auto enc_str = obj.signature(); 100 | 101 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret")); 102 | (void)dec_obj; 103 | } 104 | 105 | TEST (DecodeVerifyExp, ImmatureSignatureTest) 106 | { 107 | using namespace jwt::params; 108 | 109 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 110 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() + std::chrono::seconds{10}); 111 | 112 | auto enc_str = obj.signature(); 113 | 114 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret")), 115 | jwt::ImmatureSignatureError); 116 | } 117 | 118 | TEST (DecodeVerifyExp, ImmatureSignatureTestWithLeeway) 119 | { 120 | using namespace jwt::params; 121 | 122 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})}; 123 | obj.add_claim(jwt::registered_claims::not_before, std::chrono::system_clock::now() + std::chrono::seconds{10}); 124 | 125 | auto enc_str = obj.signature(); 126 | 127 | auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), leeway(10)); 128 | (void)dec_obj; 129 | } 130 | 131 | TEST (DecodeVerifyExp, InvalidAudienceTest) 132 | { 133 | using namespace jwt::params; 134 | 135 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}, {"aud", "www"}})}; 136 | 137 | auto enc_str = obj.signature(); 138 | 139 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), aud("ww")), 140 | jwt::InvalidAudienceError); 141 | } 142 | 143 | TEST (DecodeVerifyExp, InvalidSignatureTest) 144 | { 145 | using namespace jwt::params; 146 | 147 | const char* inv_enc_str = 148 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ"; 149 | 150 | EXPECT_THROW (jwt::decode(inv_enc_str, algorithms({"none", "HS256"})), 151 | jwt::SignatureFormatError); 152 | } 153 | 154 | TEST (DecodeVerifyExp, KeyNotPresentTest) 155 | { 156 | using namespace jwt::params; 157 | 158 | const char* enc_str = 159 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 160 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 161 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 162 | 163 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"none", "HS256"}), verify(true)), 164 | jwt::KeyNotPresentError); 165 | } 166 | 167 | TEST (DecodeVerifyExp, InvalidSubjectTest) 168 | { 169 | using namespace jwt::params; 170 | 171 | jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}, {"aud", "www"}})}; 172 | 173 | auto enc_str = obj.signature(); 174 | 175 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), sub("TEST")), 176 | jwt::InvalidSubjectError); 177 | } 178 | 179 | -------------------------------------------------------------------------------- /tests/test_jwt_encode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "gtest/gtest.h" 5 | #include "jwt/jwt.hpp" 6 | 7 | TEST (EncodeTest, TestRemoveClaim) 8 | { 9 | using namespace jwt::params; 10 | 11 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 12 | 13 | obj.add_claim("iss", "arun.muralidharan") 14 | .add_claim("sub", "admin") 15 | .add_claim("id", "a-b-c-d-e-f-1-2-3") 16 | .add_claim("iat", 1513862371) 17 | .add_claim("exp", std::chrono::system_clock::now()); 18 | 19 | EXPECT_TRUE (obj.has_claim(jwt::registered_claims::expiration)); 20 | 21 | obj.remove_claim("exp"); 22 | EXPECT_FALSE (obj.has_claim(jwt::registered_claims::expiration)); 23 | 24 | obj.remove_claim(jwt::registered_claims::subject); 25 | EXPECT_FALSE (obj.has_claim("sub")); 26 | } 27 | 28 | TEST (EncodeTest, TestRemoveTypHeader) 29 | { 30 | using namespace jwt::params; 31 | 32 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 33 | 34 | obj.add_claim("iss", "arun.muralidharan") 35 | .add_claim("sub", "admin") 36 | .add_claim("id", "a-b-c-d-e-f-1-2-3") 37 | .add_claim("iat", 1513862371) 38 | .add_claim("exp", std::chrono::system_clock::now()); 39 | 40 | EXPECT_TRUE (obj.header().has_header("typ")); 41 | obj.header().remove_header("typ"); 42 | EXPECT_FALSE (obj.header().has_header("typ")); 43 | 44 | std::cout << "Header: " << obj.header() << '\n'; 45 | std::cout << "Signature: " << obj.signature() << '\n'; 46 | } 47 | 48 | TEST (EncodeTest, StrEncodeHS256_1) 49 | { 50 | using namespace jwt::params; 51 | 52 | const char* expected_sign = 53 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 54 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 55 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 56 | 57 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 58 | 59 | obj.add_claim("iss", "arun.muralidharan") 60 | .add_claim("sub", "admin") 61 | .add_claim("id", "a-b-c-d-e-f-1-2-3") 62 | .add_claim("iat", 1513862371) 63 | ; 64 | 65 | std::cout << "Header: " << obj.header() << std::endl; 66 | std::cout << "Payload: "<< obj.payload() << std::endl; 67 | 68 | std::string enc_str = obj.signature(); 69 | 70 | std::cout << "Signature: " << enc_str << std::endl; 71 | 72 | EXPECT_EQ (enc_str, expected_sign); 73 | } 74 | 75 | TEST (EncodeTest, StrEncodeHS256_2) 76 | { 77 | using namespace jwt::params; 78 | 79 | const char* expected_sign = 80 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 81 | "eyJpYXQiOjE1MTM4NjIzNzEsImlkIjoiYS1iLWMtZC1lLWYtMS0yLTMiLCJpc3MiOiJhcnVuLm11cmFsaWRoYXJhbiIsInN1YiI6ImFkbWluIn0." 82 | "jk7bRQKTLvs1RcuvMc2B_rt6WBYPoVPirYi_QRBPiuk"; 83 | 84 | jwt::jwt_object obj{algorithm("HS256"), 85 | secret("secret"), 86 | payload( 87 | { 88 | {"iss", "arun.muralidharan"}, 89 | {"sub", "admin"}, 90 | {"id", "a-b-c-d-e-f-1-2-3"} 91 | }) 92 | }; 93 | 94 | obj.add_claim("iat", 1513862371); 95 | 96 | std::string enc_str = obj.signature(); 97 | EXPECT_EQ (enc_str, expected_sign); 98 | } 99 | 100 | 101 | TEST (EncodeTest, StrEncodeNONE) 102 | { 103 | using namespace jwt::params; 104 | 105 | const char* expected_sign = 106 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 107 | 108 | jwt::jwt_object obj{algorithm("none")}; 109 | 110 | obj.add_claim("aud", "rift.io") 111 | .add_claim("exp", 1513863371) 112 | .add_claim("sub", "nothing much") 113 | ; 114 | 115 | std::cout << "Header: " << obj.header() << std::endl; 116 | std::cout << "Payload: " << obj.payload() << std::endl; 117 | 118 | std::string enc_str = obj.signature(); 119 | 120 | EXPECT_EQ (enc_str, expected_sign); 121 | } 122 | 123 | TEST (EncodeTest, StrEncodeHS256WithKey) 124 | { 125 | using namespace jwt::params; 126 | 127 | const char* expected_sign = 128 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." 129 | "eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ." 130 | "W6t7mUX6ZJwOVTsVhHSKyBSwi0wnibobdsk456wSmJg"; 131 | 132 | jwt::jwt_object obj{algorithm(jwt::algorithm::HS256), 133 | secret("0123456789abcdefghijklmnopqrstuvwxyz"), 134 | payload( 135 | { 136 | {"aud", "rift.io"}, 137 | {"sub", "nothing much"} 138 | }) 139 | }; 140 | obj.add_claim("exp", 1513863371); 141 | 142 | std::string enc_str = obj.signature(); 143 | 144 | EXPECT_EQ (expected_sign, enc_str); 145 | } 146 | 147 | TEST (EncodeTest, StrEncodeHS384WithKey) 148 | { 149 | 150 | using namespace jwt::params; 151 | 152 | const char* expected_sign = 153 | "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9." 154 | "eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ." 155 | "cGN4FZCe9Y2c1dA-jP71IXGnYbJRc4OaUTa5m7N7ybF5h6wBwxWQ-pdcxYchjDBL"; 156 | 157 | jwt::jwt_object obj{algorithm(jwt::algorithm::HS384), 158 | secret("0123456789abcdefghijklmnopqrstuvwxyz"), 159 | payload( 160 | { 161 | {"aud", "rift.io"}, 162 | {"sub", "nothing much"} 163 | }) 164 | }; 165 | obj.add_claim("exp", 1513863371); 166 | 167 | std::string enc_str = obj.signature(); 168 | 169 | EXPECT_EQ (expected_sign, enc_str); 170 | } 171 | 172 | TEST (EncodeTest, StrEncodeHS512WithKey) 173 | { 174 | using namespace jwt::params; 175 | 176 | const char* expected_sign = 177 | "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9." 178 | "eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ." 179 | "vQ-1JSFN1kPjUI3URP6AFK5z8V7xLhyhw-76QWhQg9Xcy-IgrJ-bCTYLBjgaprrcEWwpSnBQnP3QnIxYK0HEaQ"; 180 | 181 | jwt::string_view key = "00112233445566778899"; 182 | 183 | std::map p; 184 | p["aud"] = "rift.io"; 185 | p["sub"] = "nothing much"; 186 | 187 | jwt::jwt_object obj{algorithm(jwt::algorithm::HS512), 188 | secret(key), 189 | payload(std::move(p)) 190 | }; 191 | obj.add_claim("exp", 1513863371); 192 | 193 | std::string enc_str = obj.signature(); 194 | 195 | EXPECT_EQ (enc_str, expected_sign); 196 | } 197 | 198 | TEST (EncodeTest, StrEncodeChangeAlg) 199 | { 200 | using namespace jwt::params; 201 | 202 | const char* expected_none_sign = 203 | "eyJhbGciOiJOT05FIiwidHlwIjoiSldUIn0.eyJhdWQiOiJyaWZ0LmlvIiwiZXhwIjoxNTEzODYzMzcxLCJzdWIiOiJub3RoaW5nIG11Y2gifQ."; 204 | 205 | jwt::string_view key = "00112233445566778899"; 206 | 207 | std::map p; 208 | p["aud"] = "rift.io"; 209 | p["sub"] = "nothing much"; 210 | 211 | jwt::jwt_object obj{algorithm(jwt::algorithm::HS512), 212 | secret(key), 213 | payload(std::move(p)) 214 | }; 215 | obj.add_claim("exp", 1513863371); 216 | 217 | obj.header().algo("none"); 218 | std::string enc_str = obj.signature(); 219 | 220 | EXPECT_EQ (expected_none_sign, enc_str); 221 | } 222 | 223 | TEST (EncodeTest, StrEncodeNoKey) 224 | { 225 | using namespace jwt::params; 226 | 227 | jwt::jwt_object obj{algorithm(jwt::algorithm::HS512), 228 | payload({{"iss", "arn-ml"}}) 229 | }; 230 | 231 | std::error_code ec; 232 | std::string enc_str = obj.signature(ec); 233 | 234 | ASSERT_TRUE (ec); 235 | EXPECT_EQ (ec.value(), static_cast(jwt::AlgorithmErrc::KeyNotFoundErr)); 236 | } 237 | 238 | TEST (EncodeTest, StrEncodeNoneAlgWithKey) 239 | { 240 | using namespace jwt::params; 241 | 242 | const jwt::string_view secret1 = "abcdefghijklmnopqrstuvwxyz"; 243 | const jwt::string_view secret2 = "0123456789qwertybabe"; 244 | 245 | jwt::jwt_object obj{algorithm("none"), 246 | payload({{"iss", "arn-ml"}}), 247 | secret(secret1)}; 248 | 249 | std::error_code ec; 250 | std::string enc_str1 = obj.signature(ec); 251 | ASSERT_FALSE (ec); 252 | 253 | obj.secret(secret2); 254 | std::string enc_str2 = obj.signature(ec); 255 | ASSERT_FALSE (ec); 256 | 257 | EXPECT_EQ (enc_str1, enc_str2); 258 | } 259 | 260 | TEST (EncodeTest, OverwriteClaimsTest) 261 | { 262 | using namespace jwt::params; 263 | 264 | jwt::jwt_object obj{algorithm("none"), 265 | payload({ 266 | {"iss", "arn-ml"}, 267 | {"x-pld1", "data1"}, 268 | {"x-pld2", "data2"}, 269 | {"x-pld3", "123"} 270 | }) 271 | }; 272 | 273 | bool ret = obj.payload().add_claim("x-pld1", "1data"); 274 | EXPECT_FALSE (ret); 275 | 276 | ret = obj.payload().add_claim("x-pld1", "1data", true/*overwrite*/); 277 | EXPECT_TRUE (ret); 278 | 279 | EXPECT_TRUE (obj.payload().has_claim_with_value("x-pld1", "1data")); 280 | } 281 | 282 | TEST (EncodeTest, HeaderParamTest) 283 | { 284 | using namespace jwt::params; 285 | 286 | jwt::jwt_object obj{ 287 | headers({ 288 | {"alg", "none"}, 289 | {"typ", "jwt"}, 290 | }), 291 | payload({ 292 | {"iss", "arun.muralidharan"}, 293 | {"sub", "nsfw"}, 294 | {"x-pld", "not my ex"} 295 | }) 296 | }; 297 | 298 | bool ret = obj.header().add_header("kid", 1234567); 299 | EXPECT_TRUE (ret); 300 | 301 | ret = obj.header().add_header("crit", std::array{ {"exp"} }); 302 | EXPECT_TRUE (ret); 303 | 304 | std::cout << obj.header() << std::endl; 305 | 306 | std::error_code ec; 307 | auto enc_str = obj.signature(); 308 | 309 | auto dec_obj = jwt::decode(enc_str, algorithms({"none"}), ec, verify(true)); 310 | EXPECT_EQ (ec.value(), static_cast(jwt::AlgorithmErrc::NoneAlgorithmUsed)); 311 | 312 | std::cout << dec_obj.header() << std::endl; 313 | } 314 | 315 | -------------------------------------------------------------------------------- /tests/test_jwt_es.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gtest/gtest.h" 7 | #include "jwt/jwt.hpp" 8 | 9 | #define EC384_PUB_KEY CERT_ROOT_DIR "/ec_certs/ec384_pub.pem" 10 | #define EC384_PRIV_KEY CERT_ROOT_DIR "/ec_certs/ec384_priv.pem" 11 | 12 | std::string read_from_file(const std::string& path) 13 | { 14 | std::string contents; 15 | std::ifstream is{path, std::ifstream::binary}; 16 | 17 | if (is) { 18 | // get length of file: 19 | is.seekg (0, is.end); 20 | auto length = is.tellg(); 21 | is.seekg (0, is.beg); 22 | contents.resize(length); 23 | 24 | is.read(&contents[0], length); 25 | if (!is) { 26 | is.close(); 27 | return {}; 28 | } 29 | } 30 | 31 | is.close(); 32 | return contents; 33 | } 34 | 35 | TEST (ESAlgo, ES256EncodingDecodingTest) 36 | { 37 | using namespace jwt::params; 38 | 39 | std::string key = read_from_file(EC384_PRIV_KEY); 40 | ASSERT_TRUE (key.length()); 41 | 42 | jwt::jwt_object obj{algorithm("ES256"), secret(key)}; 43 | 44 | obj.add_claim("iss", "arun.muralidharan") 45 | .add_claim("aud", "all") 46 | .add_claim("exp", 1513862371) 47 | ; 48 | 49 | std::error_code ec; 50 | auto enc_str = obj.signature(ec); 51 | EXPECT_FALSE (ec); 52 | 53 | key = read_from_file(EC384_PUB_KEY); 54 | ASSERT_TRUE (key.length()); 55 | 56 | auto dec_obj = jwt::decode(enc_str, algorithms({"ES256"}), ec, verify(false), secret(key)); 57 | EXPECT_FALSE (ec); 58 | 59 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::ES256); 60 | EXPECT_TRUE (dec_obj.has_claim("iss")); 61 | EXPECT_TRUE (dec_obj.has_claim("aud")); 62 | EXPECT_TRUE (dec_obj.has_claim("exp")); 63 | 64 | EXPECT_FALSE (dec_obj.has_claim("sub")); 65 | } 66 | 67 | TEST (ESAlgo, ES384EncodingDecodingTest) 68 | { 69 | using namespace jwt::params; 70 | 71 | std::string key = read_from_file(EC384_PRIV_KEY); 72 | ASSERT_TRUE (key.length()); 73 | 74 | jwt::jwt_object obj{algorithm("ES384"), secret(key)}; 75 | 76 | obj.add_claim("iss", "arun.muralidharan") 77 | .add_claim("aud", "all") 78 | .add_claim("exp", 1513862371) 79 | ; 80 | 81 | auto enc_str = obj.signature(); 82 | 83 | key = read_from_file(EC384_PUB_KEY); 84 | ASSERT_TRUE (key.length()); 85 | 86 | auto dec_obj = jwt::decode(enc_str, algorithms({"ES384"}), verify(false), secret(key)); 87 | 88 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::ES384); 89 | } 90 | 91 | TEST (ESAlgo, ES512EncodingDecodingTest) 92 | { 93 | using namespace jwt::params; 94 | 95 | std::string key = read_from_file(EC384_PRIV_KEY); 96 | ASSERT_TRUE (key.length()); 97 | 98 | jwt::jwt_object obj{algorithm("ES512"), secret(key)}; 99 | 100 | obj.add_claim("iss", "arun.muralidharan") 101 | .add_claim("aud", "all") 102 | .add_claim("exp", 1513862371) 103 | ; 104 | 105 | auto enc_str = obj.signature(); 106 | 107 | key = read_from_file(EC384_PUB_KEY); 108 | ASSERT_TRUE (key.length()); 109 | 110 | auto dec_obj = jwt::decode(enc_str, algorithms({"ES512"}), verify(false), secret(key)); 111 | 112 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::ES512); 113 | } 114 | 115 | TEST (ESAlgo, ES384EncodingDecodingValidTest) 116 | { 117 | using namespace jwt::params; 118 | 119 | std::string key = read_from_file(EC384_PRIV_KEY); 120 | ASSERT_TRUE (key.length()); 121 | 122 | jwt::jwt_object obj{algorithm("ES384"), secret(key)}; 123 | 124 | obj.add_claim("iss", "arun.muralidharan") 125 | .add_claim("aud", "all") 126 | .add_claim("exp", 4682665886) // Expires on Sunday, May 22, 2118 12:31:26 PM GMT 127 | ; 128 | 129 | auto enc_str = obj.signature(); 130 | 131 | key = read_from_file(EC384_PUB_KEY); 132 | ASSERT_TRUE (key.length()); 133 | 134 | auto dec_obj = jwt::decode(enc_str, algorithms({"ES384"}), verify(true), secret(key)); 135 | 136 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::ES384); 137 | EXPECT_TRUE (dec_obj.has_claim("exp")); 138 | EXPECT_TRUE (obj.payload().has_claim_with_value("exp", 4682665886)); 139 | 140 | std::map keystore{{"arun.muralidharan", key}}; 141 | 142 | auto l = [&keystore](const jwt::jwt_payload& payload){ 143 | auto iss = payload.get_claim_value("iss"); 144 | return keystore[iss]; 145 | }; 146 | auto dec_obj2 = jwt::decode(enc_str, algorithms({"ES384"}), verify(true), secret(l)); 147 | EXPECT_EQ (dec_obj2.header().algo(), jwt::algorithm::ES384); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /tests/test_jwt_object.cc: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include "jwt/jwt.hpp" 3 | 4 | namespace { 5 | 6 | struct Wrapper 7 | { 8 | // The std::move here is required to resolve to the move ctor 9 | // rather than to the universal reference ctor. 10 | Wrapper(jwt::jwt_object&& obj) : object{std::move(obj)} {} 11 | jwt::jwt_object object; 12 | }; 13 | 14 | } // END namespace 15 | 16 | TEST (ObjectTest, MoveConstructor) 17 | { 18 | using namespace jwt::params; 19 | 20 | jwt::jwt_object obj{algorithm("HS256"), secret("secret")}; 21 | 22 | obj.add_claim("iss", "arun.muralidharan"); 23 | 24 | auto wrapper = Wrapper{std::move(obj)}; 25 | 26 | EXPECT_EQ(wrapper.object.header().algo(), jwt::algorithm::HS256); 27 | EXPECT_EQ(wrapper.object.secret(), "secret"); 28 | EXPECT_TRUE(wrapper.object.payload().has_claim_with_value("iss", "arun.muralidharan")); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /tests/test_jwt_rsa.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gtest/gtest.h" 7 | #include "jwt/jwt.hpp" 8 | 9 | #define RSA256_PUB_KEY CERT_ROOT_DIR "/rsa_certs/rsa256_pub.pem" 10 | #define RSA256_PRIV_KEY CERT_ROOT_DIR "/rsa_certs/rsa256_priv.pem" 11 | #define RSA384_PUB_KEY CERT_ROOT_DIR "/rsa_certs/rsa384_pub.pem" 12 | #define RSA384_PRIV_KEY CERT_ROOT_DIR "/rsa_certs/rsa384_priv.pem" 13 | #define RSA512_PUB_KEY CERT_ROOT_DIR "/rsa_certs/rsa512_pub.pem" 14 | #define RSA512_PRIV_KEY CERT_ROOT_DIR "/rsa_certs/rsa512_priv.pem" 15 | 16 | std::string read_from_file(const std::string& path) 17 | { 18 | std::string contents; 19 | std::ifstream is{path, std::ifstream::binary}; 20 | 21 | if (is) { 22 | // get length of file: 23 | is.seekg (0, is.end); 24 | auto length = is.tellg(); 25 | is.seekg (0, is.beg); 26 | contents.resize(length); 27 | 28 | is.read(&contents[0], length); 29 | if (!is) { 30 | is.close(); 31 | return {}; 32 | } 33 | } 34 | 35 | is.close(); 36 | return contents; 37 | } 38 | 39 | TEST (RSAAlgo, RSA256EncodingDecodingTest) 40 | { 41 | using namespace jwt::params; 42 | 43 | const char* expected_sign = 44 | "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhbGwiLCJleHAiOjE1MTM4NjIzNzEsImlzcyI6ImFydW4ubXVyYWxpZGhhcmFuIn0.jr-Nrny0yGFuIUH8zHLuxpGH5aClwQVin2As2ISsgclu-9IDi1cVCtloIUNRb_ock6X7X41FtGMA_lt_T9wGyLmMzNf4Vu7OPBGfzjEdCHKD8OgcvI0Z4qw7_TFuXEuNSnbwkYFZ9S2g8uPzO0raVk4aIuczo58btwEDrsoE7TNBMTHjfL92zZ90YcFqW5WZKn9Y_dF1rb5UXARF6YSzzVjaNC86FWUl86wwo9cir0nxVPD4zKol_x2xyiP6n4n-sUX0_dM_-KMSfDqdr34quq3ZxcP5vjT-8FWb4t_IWHBmLrNsjS1so9a_5u7vcSBX1llX9Vgztv0zB7B8rEkFTw"; 45 | 46 | std::string key = read_from_file(RSA256_PRIV_KEY); 47 | ASSERT_TRUE (key.length()); 48 | 49 | jwt::jwt_object obj{algorithm("RS256"), secret(key)}; 50 | 51 | obj.add_claim("iss", "arun.muralidharan") 52 | .add_claim("aud", "all") 53 | .add_claim("exp", 1513862371) 54 | ; 55 | 56 | std::error_code ec; 57 | auto enc_str = obj.signature(ec); 58 | EXPECT_FALSE (ec); 59 | 60 | EXPECT_EQ (enc_str, expected_sign); 61 | 62 | //Decode 63 | key = read_from_file(RSA256_PUB_KEY); 64 | ASSERT_TRUE (key.length()); 65 | 66 | auto dec_obj = jwt::decode(enc_str, algorithms({"RS256"}), ec, verify(false), secret(key)); 67 | EXPECT_FALSE (ec); 68 | } 69 | 70 | TEST (RSAAlgo, RSA384EncodingDecodingTest) 71 | { 72 | using namespace jwt::params; 73 | 74 | std::string key = read_from_file(RSA384_PRIV_KEY); 75 | ASSERT_TRUE (key.length()); 76 | 77 | const char* expected_str = 78 | "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhbGwiLCJleHAiOjE1MTM4NjIzNzIsImlzcyI6ImFydW4ubXVyYWxpZGhhcmFuIn0.iXQyGTmHAjdfXXgcMZn31xqv05h8Qoa3GGlSF5-42kPkd6iLPWzxky15FFW8qkvO-DiXDpOM4BoDANYCKNTSOToyuhCZ6dn_WH8RQzU6KOqRccYe2Fgvo7XnrgE_iHIMYPejc2kAUh1xLpE31WCU2P1afo2KN_-DV7kCmDJY6qpFtCctbbPNOhv6XbYpQlTblZeYDh1HVO--KWuhYl17kgjj3W-3fEoQjgaiprZ_JsTxRTN05aGT_AY15-FW0jPgPPBw5FnIX6P-j18F3BrG-lji7BuNrvyCUT3ZX35yBkBv9Ri5B3SLALy2bD0qGGE_G9_Orfm9yU9oQySLMO1qLiMbKLakLB5kMSy049C2Pdx9Nz47hqQWOHOWNRGwwTkKAwjeu1dTjv14QOmLcefM6GoXoCMZaFcmEqr63CgyLrnlsVS6vLkazyWcKD6eg51vPa8Rnn1V5u1EgNNnT6nU6iZ9_POJcf9_s-7HNpAXtlckia-OIrdLG-5cm93h1rAfVois43m0EwNtTr_DZ2JDtM9BifaS5MsktztUjrh1hjF5vDLBQc8vAYX0YbWOx_0NTn0aRYzOZ9kIhFxkaY320h8AS_7iFa5sA-ygeJdR-EvdlUZcoRzPzQFkrtatK-UE_VlSisUCsqoxHefx799aNjqz4FDLcyQRekdmVMb8Ew8"; 79 | 80 | jwt::jwt_object obj{algorithm("RS384"), secret(key)}; 81 | 82 | obj.add_claim("iss", "arun.muralidharan") 83 | .add_claim("aud", "all") 84 | .add_claim("exp", 1513862372) 85 | ; 86 | 87 | auto enc_str = obj.signature(); 88 | EXPECT_EQ (enc_str, expected_str); 89 | 90 | //Decode 91 | key = read_from_file(RSA384_PUB_KEY); 92 | ASSERT_TRUE (key.length()); 93 | 94 | auto dec_obj = jwt::decode(enc_str, algorithms({"none", "HS384", "RS384"}), verify(false), secret(key)); 95 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::RS384); 96 | } 97 | 98 | TEST (RSAAlgo, RSA512EncodingDecodingTest) 99 | { 100 | using namespace jwt::params; 101 | 102 | const char* expected_str = 103 | "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhbGwiLCJleHAiOjE1MTM4NjIzNzIsImlzcyI6ImFydW4ubXVyYWxpZGhhcmFuIn0.ZNkLnf565-NFfxkbosJra1CJEgCLFf0jmgb7Q8eZrzxIrE4C4dOjpGD13f0jm2FqidUxAvFVrHI2ahhZi4Bu65qQtV4mVVftiD0qTaYzh26ql0MFqTKYEeKtU0kFXAzH7f9689z7mQ2n8aw7H8WHrfe17ub19Xyj-MirCECcWjcuGWBhsdz0y-dKy_GJYnpf8mHvmQAjkH5ynUV5NXHIBDO6eKssxX36Ow9_KYZ1HrCCUT_B-TQfNrnHAJgCydO-cX9iaAxV5aKvOdMGopHz14fX4oI9qH4aBzcroRbs77UsJZ-CMoRnUoXQP7DPORvEEUOQepANu9gqmymfJin8oEDotlj7eoJkFD3j64dkMT2bnRe8k2akPgUiDTeIrvNBuOIMDJtekoVpTo0fytveeDVPpDli9uX6DkJW1GGFLSRR-J-I8WbKRMKadmKOpDn3LF71hOo2mcXAsSwleFi9xB39bLBKJcqL_DtBoZBt0QSqMs6nRVj1U-3vYtuaa_eM3TfxhWWPZULaGVaVfpefRGdqtjrU0z5oO_vjviYujXK5_vM8zTroLVEaOyJYCeh2h_5N5LaOlf8BDu2PF3epNuCmM7G2PWEH7aPn5o-vvKTg_SM32jJXbXp2gkplEdQIWFh3jtjcRe9wNa9aPJE3I1hn1ZbqiAGUzBLWYUYpvstWXGbmxOoh6FkNJERb2hOIZgGLMvwWZXUU3GICcI5DMFOdDsuANpLg5FygsQ68JpuqKrUxu1Yh55--GHuDI7tqdHsPhPUzTmZrSvRog0w07dUAZCIBsGsSLX3wViobWbpVuY4pB7KXGIfdXgLfLgcERe_CxtnoPGF36zsqBflSXcqXwJ4qRK6BpTvKyUXf6pWEWOnuKomk8aENbT6nTr7naRJb5L3J4zhE-5O_Yetw9aCTzy9vN8a22n0JHXeroAwTpLR_wsQwDPwN-K99JVUKwR-FvOkJhE7_wwbUXmjiacKjXrwQ0OWnhXigQRLfdHG2OyH6_It5dpBmBOyWx2X-tfQ6Wz-_2bKCALl487Amq56hhNJhbQuJFIR59RylVAWKmfeeno2qcTZgrI_mO3PJCCUxBn5hK81HJuOtZ4YmeDHPvLW8Tiv5KqfRMWJKhyFthB74FvUINiEn0jvbuLR3YuyTgpf22lohT4-mHq5FrEd3plGvj0fVI_zeGhAFBhQYMW-MAJo7oylTOMtSZ1JHHuvBPR6FvMTgaPTAum6Dsl-I4_O_OKgtgovefBgwh4TOm_vsJmjVYFRr0Eo3OqsfNw3OwSKnuv5I76thh6DN879UZiyJG_7lcz_L6d0g4fGCvdM45zgQp3U3l8fJN1MRYCx5mxJAYeVlnCpmqueuww"; 104 | 105 | std::string key = read_from_file(RSA512_PRIV_KEY); 106 | ASSERT_TRUE (key.length()); 107 | 108 | jwt::jwt_object obj{algorithm("RS512"), secret(key)}; 109 | obj.add_claim("iss", "arun.muralidharan") 110 | .add_claim("aud", "all") 111 | .add_claim("exp", 1513862372) 112 | ; 113 | 114 | auto enc_str = obj.signature(); 115 | EXPECT_EQ (enc_str, expected_str); 116 | 117 | 118 | key = read_from_file(RSA512_PUB_KEY); 119 | ASSERT_TRUE (key.length()); 120 | 121 | auto dec_obj = jwt::decode(enc_str, algorithms({"none", "HS384", "RS512"}), verify(false), secret(key)); 122 | EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::RS512); 123 | } 124 | 125 | TEST (RSAAlgo, NoSpecificAlgo) 126 | { 127 | using namespace jwt::params; 128 | 129 | std::string key = read_from_file(RSA512_PRIV_KEY); 130 | ASSERT_TRUE (key.length()); 131 | 132 | jwt::jwt_object obj{algorithm("RS512"), secret(key)}; 133 | obj.add_claim("iss", "arun.muralidharan") 134 | .add_claim("aud", "all") 135 | .add_claim("exp", 1513862372) 136 | ; 137 | 138 | auto enc_str = obj.signature(); 139 | key = read_from_file(RSA512_PUB_KEY); 140 | ASSERT_TRUE (key.length()); 141 | 142 | EXPECT_THROW (jwt::decode(enc_str, algorithms({"none", "HS384", "RS384"}), verify(true), secret(key)), 143 | jwt::InvalidAlgorithmError); 144 | } -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cpp-jwt", 3 | "version": "1.5", 4 | "description": "JSON Web Token library for C++", 5 | "homepage": "https://github.com/arun11299/cpp-jwt", 6 | "dependencies": [ 7 | "nlohmann-json", 8 | "openssl", 9 | "gtest" 10 | ] 11 | } 12 | --------------------------------------------------------------------------------