JWT-CPP v0.7.2
A header only library for creating and validating JSON Web Tokens (JWT) in C++
Loading...
Searching...
No Matches
jwt.h
1#ifndef JWT_CPP_JWT_H
2#define JWT_CPP_JWT_H
3
4#ifndef JWT_DISABLE_PICOJSON
5#ifndef PICOJSON_USE_INT64
6#define PICOJSON_USE_INT64
7#endif
8#include "picojson/picojson.h"
9#endif
10
11#ifndef JWT_DISABLE_BASE64
12#include "base.h"
13#endif
14
15#include <openssl/ec.h>
16#include <openssl/ecdsa.h>
17#include <openssl/err.h>
18#include <openssl/evp.h>
19#include <openssl/hmac.h>
20#include <openssl/pem.h>
21#include <openssl/rsa.h>
22#include <openssl/ssl.h>
23
24#include <algorithm>
25#include <chrono>
26#include <climits>
27#include <cmath>
28#include <cstring>
29#include <functional>
30#include <iterator>
31#include <locale>
32#include <memory>
33#include <set>
34#include <system_error>
35#include <type_traits>
36#include <unordered_map>
37#include <utility>
38#include <vector>
39
40#if __cplusplus >= 201402L
41#ifdef __has_include
42#if __has_include(<experimental/type_traits>)
43#include <experimental/type_traits>
44#endif
45#endif
46#endif
47
48#if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0
49#define JWT_OPENSSL_3_0
50#include <openssl/param_build.h>
51#elif OPENSSL_VERSION_NUMBER >= 0x10101000L // 1.1.1
52#define JWT_OPENSSL_1_1_1
53#elif OPENSSL_VERSION_NUMBER >= 0x10100000L // 1.1.0
54#define JWT_OPENSSL_1_1_0
55#elif OPENSSL_VERSION_NUMBER >= 0x10000000L // 1.0.0
56#define JWT_OPENSSL_1_0_0
57#endif
58
59#if defined(LIBRESSL_VERSION_NUMBER)
60#if LIBRESSL_VERSION_NUMBER >= 0x3070100fL // 3.7.1 - EdDSA support
61#define JWT_OPENSSL_1_1_1
62#elif LIBRESSL_VERSION_NUMBER >= 0x3050300fL // 3.5.3
63#define JWT_OPENSSL_1_1_0
64#else
65#define JWT_OPENSSL_1_0_0
66#endif
67#endif
68
69#if defined(LIBWOLFSSL_VERSION_HEX)
70#define JWT_OPENSSL_1_1_1
71#endif
72
73#ifndef JWT_CLAIM_EXPLICIT
74#define JWT_CLAIM_EXPLICIT explicit
75#endif
76
84namespace jwt {
88 using date = std::chrono::system_clock::time_point;
89
93 namespace error {
94 struct signature_verification_exception : public std::system_error {
95 using system_error::system_error;
96 };
97 struct signature_generation_exception : public std::system_error {
98 using system_error::system_error;
99 };
100 struct rsa_exception : public std::system_error {
101 using system_error::system_error;
102 };
103 struct ecdsa_exception : public std::system_error {
104 using system_error::system_error;
105 };
106 struct token_verification_exception : public std::system_error {
107 using system_error::system_error;
108 };
109
112 enum class rsa_error {
113 ok = 0,
114 cert_load_failed = 10,
115 get_key_failed,
116 write_key_failed,
117 write_cert_failed,
118 convert_to_pem_failed,
119 load_key_bio_write,
120 load_key_bio_read,
121 create_mem_bio_failed,
122 no_key_provided,
123 set_rsa_failed,
124 create_context_failed
125 };
126
129 inline std::error_category& rsa_error_category() {
130 class rsa_error_cat : public std::error_category {
131 public:
132 const char* name() const noexcept override { return "rsa_error"; };
133 std::string message(int ev) const override {
134 switch (static_cast<rsa_error>(ev)) {
135 case rsa_error::ok: return "no error";
136 case rsa_error::cert_load_failed: return "error loading cert into memory";
137 case rsa_error::get_key_failed: return "error getting key from certificate";
138 case rsa_error::write_key_failed: return "error writing key data in PEM format";
139 case rsa_error::write_cert_failed: return "error writing cert data in PEM format";
140 case rsa_error::convert_to_pem_failed: return "failed to convert key to pem";
141 case rsa_error::load_key_bio_write: return "failed to load key: bio write failed";
142 case rsa_error::load_key_bio_read: return "failed to load key: bio read failed";
143 case rsa_error::create_mem_bio_failed: return "failed to create memory bio";
144 case rsa_error::no_key_provided: return "at least one of public or private key need to be present";
145 case rsa_error::set_rsa_failed: return "set modulus and exponent to RSA failed";
146 case rsa_error::create_context_failed: return "failed to create context";
147 default: return "unknown RSA error";
148 }
149 }
150 };
151 static rsa_error_cat cat;
152 return cat;
153 }
154
157 inline std::error_code make_error_code(rsa_error e) { return {static_cast<int>(e), rsa_error_category()}; }
161 enum class ecdsa_error {
162 ok = 0,
163 load_key_bio_write = 10,
164 load_key_bio_read,
165 create_mem_bio_failed,
166 no_key_provided,
167 invalid_key_size,
168 invalid_key,
169 create_context_failed,
170 cert_load_failed,
171 get_key_failed,
172 write_key_failed,
173 write_cert_failed,
174 convert_to_pem_failed,
175 unknown_curve,
176 set_ecdsa_failed
177 };
178
181 inline std::error_category& ecdsa_error_category() {
182 class ecdsa_error_cat : public std::error_category {
183 public:
184 const char* name() const noexcept override { return "ecdsa_error"; };
185 std::string message(int ev) const override {
186 switch (static_cast<ecdsa_error>(ev)) {
187 case ecdsa_error::ok: return "no error";
188 case ecdsa_error::load_key_bio_write: return "failed to load key: bio write failed";
189 case ecdsa_error::load_key_bio_read: return "failed to load key: bio read failed";
190 case ecdsa_error::create_mem_bio_failed: return "failed to create memory bio";
191 case ecdsa_error::no_key_provided:
192 return "at least one of public or private key need to be present";
193 case ecdsa_error::invalid_key_size: return "invalid key size";
194 case ecdsa_error::invalid_key: return "invalid key";
195 case ecdsa_error::create_context_failed: return "failed to create context";
196 case ecdsa_error::cert_load_failed: return "error loading cert into memory";
197 case ecdsa_error::get_key_failed: return "error getting key from certificate";
198 case ecdsa_error::write_key_failed: return "error writing key data in PEM format";
199 case ecdsa_error::write_cert_failed: return "error writing cert data in PEM format";
200 case ecdsa_error::convert_to_pem_failed: return "failed to convert key to pem";
201 case ecdsa_error::unknown_curve: return "unknown curve";
202 case ecdsa_error::set_ecdsa_failed: return "set parameters to ECDSA failed";
203 default: return "unknown ECDSA error";
204 }
205 }
206 };
207 static ecdsa_error_cat cat;
208 return cat;
209 }
210
213 inline std::error_code make_error_code(ecdsa_error e) { return {static_cast<int>(e), ecdsa_error_category()}; }
214
219 ok = 0,
220 invalid_signature = 10,
221 create_context_failed,
222 verifyinit_failed,
223 verifyupdate_failed,
224 verifyfinal_failed,
225 get_key_failed,
226 set_rsa_pss_saltlen_failed,
227 signature_encoding_failed
228 };
229
232 inline std::error_category& signature_verification_error_category() {
233 class verification_error_cat : public std::error_category {
234 public:
235 const char* name() const noexcept override { return "signature_verification_error"; };
236 std::string message(int ev) const override {
237 switch (static_cast<signature_verification_error>(ev)) {
238 case signature_verification_error::ok: return "no error";
239 case signature_verification_error::invalid_signature: return "invalid signature";
240 case signature_verification_error::create_context_failed:
241 return "failed to verify signature: could not create context";
242 case signature_verification_error::verifyinit_failed:
243 return "failed to verify signature: VerifyInit failed";
244 case signature_verification_error::verifyupdate_failed:
245 return "failed to verify signature: VerifyUpdate failed";
246 case signature_verification_error::verifyfinal_failed:
247 return "failed to verify signature: VerifyFinal failed";
248 case signature_verification_error::get_key_failed:
249 return "failed to verify signature: Could not get key";
250 case signature_verification_error::set_rsa_pss_saltlen_failed:
251 return "failed to verify signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
252 case signature_verification_error::signature_encoding_failed:
253 return "failed to verify signature: i2d_ECDSA_SIG failed";
254 default: return "unknown signature verification error";
255 }
256 }
257 };
258 static verification_error_cat cat;
259 return cat;
260 }
261
265 return {static_cast<int>(e), signature_verification_error_category()};
266 }
267
272 ok = 0,
273 hmac_failed = 10,
274 create_context_failed,
275 signinit_failed,
276 signupdate_failed,
277 signfinal_failed,
278 ecdsa_do_sign_failed,
279 digestinit_failed,
280 digestupdate_failed,
281 digestfinal_failed,
282 rsa_padding_failed,
283 rsa_private_encrypt_failed,
284 get_key_failed,
285 set_rsa_pss_saltlen_failed,
286 signature_decoding_failed
287 };
288
291 inline std::error_category& signature_generation_error_category() {
292 class signature_generation_error_cat : public std::error_category {
293 public:
294 const char* name() const noexcept override { return "signature_generation_error"; };
295 std::string message(int ev) const override {
296 switch (static_cast<signature_generation_error>(ev)) {
297 case signature_generation_error::ok: return "no error";
298 case signature_generation_error::hmac_failed: return "hmac failed";
299 case signature_generation_error::create_context_failed:
300 return "failed to create signature: could not create context";
301 case signature_generation_error::signinit_failed:
302 return "failed to create signature: SignInit failed";
303 case signature_generation_error::signupdate_failed:
304 return "failed to create signature: SignUpdate failed";
305 case signature_generation_error::signfinal_failed:
306 return "failed to create signature: SignFinal failed";
307 case signature_generation_error::ecdsa_do_sign_failed: return "failed to generate ecdsa signature";
308 case signature_generation_error::digestinit_failed:
309 return "failed to create signature: DigestInit failed";
310 case signature_generation_error::digestupdate_failed:
311 return "failed to create signature: DigestUpdate failed";
312 case signature_generation_error::digestfinal_failed:
313 return "failed to create signature: DigestFinal failed";
314 case signature_generation_error::rsa_padding_failed:
315 return "failed to create signature: EVP_PKEY_CTX_set_rsa_padding failed";
316 case signature_generation_error::rsa_private_encrypt_failed:
317 return "failed to create signature: RSA_private_encrypt failed";
318 case signature_generation_error::get_key_failed:
319 return "failed to generate signature: Could not get key";
320 case signature_generation_error::set_rsa_pss_saltlen_failed:
321 return "failed to create signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
322 case signature_generation_error::signature_decoding_failed:
323 return "failed to create signature: d2i_ECDSA_SIG failed";
324 default: return "unknown signature generation error";
325 }
326 }
327 };
328 static signature_generation_error_cat cat = {};
329 return cat;
330 }
331
334 inline std::error_code make_error_code(signature_generation_error e) {
335 return {static_cast<int>(e), signature_generation_error_category()};
336 }
337
342 ok = 0,
343 wrong_algorithm = 10,
344 missing_claim,
345 claim_type_missmatch,
346 claim_value_missmatch,
347 token_expired,
348 audience_missmatch
349 };
350
353 inline std::error_category& token_verification_error_category() {
354 class token_verification_error_cat : public std::error_category {
355 public:
356 const char* name() const noexcept override { return "token_verification_error"; };
357 std::string message(int ev) const override {
358 switch (static_cast<token_verification_error>(ev)) {
359 case token_verification_error::ok: return "no error";
360 case token_verification_error::wrong_algorithm: return "wrong algorithm";
361 case token_verification_error::missing_claim: return "decoded JWT is missing required claim(s)";
362 case token_verification_error::claim_type_missmatch:
363 return "claim type does not match expected type";
364 case token_verification_error::claim_value_missmatch:
365 return "claim value does not match expected value";
366 case token_verification_error::token_expired: return "token expired";
367 case token_verification_error::audience_missmatch:
368 return "token doesn't contain the required audience";
369 default: return "unknown token verification error";
370 }
371 }
372 };
373 static token_verification_error_cat cat = {};
374 return cat;
375 }
376
379 inline std::error_code make_error_code(token_verification_error e) {
380 return {static_cast<int>(e), token_verification_error_category()};
381 }
382
385 inline void throw_if_error(std::error_code ec) {
386 if (ec) {
387 if (ec.category() == rsa_error_category()) throw rsa_exception(ec);
388 if (ec.category() == ecdsa_error_category()) throw ecdsa_exception(ec);
389 if (ec.category() == signature_verification_error_category())
392 if (ec.category() == token_verification_error_category()) throw token_verification_exception(ec);
393 }
394 }
395 } // namespace error
396} // namespace jwt
397
398namespace std {
399 template<>
400 struct is_error_code_enum<jwt::error::rsa_error> : true_type {};
401 template<>
402 struct is_error_code_enum<jwt::error::ecdsa_error> : true_type {};
403 template<>
404 struct is_error_code_enum<jwt::error::signature_verification_error> : true_type {};
405 template<>
406 struct is_error_code_enum<jwt::error::signature_generation_error> : true_type {};
407 template<>
408 struct is_error_code_enum<jwt::error::token_verification_error> : true_type {};
409} // namespace std
410
411namespace jwt {
419 namespace helper {
428 public:
432 constexpr evp_pkey_handle() noexcept = default;
433#ifdef JWT_OPENSSL_1_0_0
438 explicit evp_pkey_handle(EVP_PKEY* key) { m_key = std::shared_ptr<EVP_PKEY>(key, EVP_PKEY_free); }
439
440 EVP_PKEY* get() const noexcept { return m_key.get(); }
441 bool operator!() const noexcept { return m_key == nullptr; }
442 explicit operator bool() const noexcept { return m_key != nullptr; }
443
444 private:
445 std::shared_ptr<EVP_PKEY> m_key{nullptr};
446#else
451 explicit constexpr evp_pkey_handle(EVP_PKEY* key) noexcept : m_key{key} {}
452 evp_pkey_handle(const evp_pkey_handle& other) : m_key{other.m_key} {
453 if (m_key != nullptr && EVP_PKEY_up_ref(m_key) != 1) throw std::runtime_error("EVP_PKEY_up_ref failed");
454 }
455// C++11 requires the body of a constexpr constructor to be empty
456#if __cplusplus >= 201402L
457 constexpr
458#endif
459 evp_pkey_handle(evp_pkey_handle&& other) noexcept
460 : m_key{other.m_key} {
461 other.m_key = nullptr;
462 }
463 evp_pkey_handle& operator=(const evp_pkey_handle& other) {
464 if (&other == this) return *this;
465 decrement_ref_count(m_key);
466 m_key = other.m_key;
467 increment_ref_count(m_key);
468 return *this;
469 }
470 evp_pkey_handle& operator=(evp_pkey_handle&& other) noexcept {
471 if (&other == this) return *this;
472 decrement_ref_count(m_key);
473 m_key = other.m_key;
474 other.m_key = nullptr;
475 return *this;
476 }
477 evp_pkey_handle& operator=(EVP_PKEY* key) {
478 decrement_ref_count(m_key);
479 m_key = key;
480 increment_ref_count(m_key);
481 return *this;
482 }
483 ~evp_pkey_handle() noexcept { decrement_ref_count(m_key); }
484
485 EVP_PKEY* get() const noexcept { return m_key; }
486 bool operator!() const noexcept { return m_key == nullptr; }
487 explicit operator bool() const noexcept { return m_key != nullptr; }
488
489 private:
490 EVP_PKEY* m_key{nullptr};
491
492 static void increment_ref_count(EVP_PKEY* key) {
493 if (key != nullptr && EVP_PKEY_up_ref(key) != 1) throw std::runtime_error("EVP_PKEY_up_ref failed");
494 }
495 static void decrement_ref_count(EVP_PKEY* key) noexcept {
496 if (key != nullptr) EVP_PKEY_free(key);
497 }
498#endif
499 };
500
501 inline std::unique_ptr<BIO, decltype(&BIO_free_all)> make_mem_buf_bio() {
502 return std::unique_ptr<BIO, decltype(&BIO_free_all)>(BIO_new(BIO_s_mem()), BIO_free_all);
503 }
504
505 inline std::unique_ptr<BIO, decltype(&BIO_free_all)> make_mem_buf_bio(const std::string& data) {
506 return std::unique_ptr<BIO, decltype(&BIO_free_all)>(
507#if OPENSSL_VERSION_NUMBER <= 0x10100003L
508 BIO_new_mem_buf(const_cast<char*>(data.data()), static_cast<int>(data.size())), BIO_free_all
509#else
510 BIO_new_mem_buf(data.data(), static_cast<int>(data.size())), BIO_free_all
511#endif
512 );
513 }
514
515 template<typename error_category = error::rsa_error>
516 std::string write_bio_to_string(std::unique_ptr<BIO, decltype(&BIO_free_all)>& bio_out, std::error_code& ec) {
517 char* ptr = nullptr;
518 auto len = BIO_get_mem_data(bio_out.get(), &ptr);
519 if (len <= 0 || ptr == nullptr) {
520 ec = error_category::convert_to_pem_failed;
521 return {};
522 }
523 return {ptr, static_cast<size_t>(len)};
524 }
525
526 inline std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX*)> make_evp_md_ctx() {
527 return
528#ifdef JWT_OPENSSL_1_0_0
529 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)>(EVP_MD_CTX_create(), &EVP_MD_CTX_destroy);
530#else
531 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(EVP_MD_CTX_new(), &EVP_MD_CTX_free);
532#endif
533 }
534
543 template<typename error_category = error::rsa_error>
544 std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, std::error_code& ec) {
545 ec.clear();
546 auto certbio = make_mem_buf_bio(certstr);
547 auto keybio = make_mem_buf_bio();
548 if (!certbio || !keybio) {
549 ec = error_category::create_mem_bio_failed;
550 return {};
551 }
552
553 std::unique_ptr<X509, decltype(&X509_free)> cert(
554 PEM_read_bio_X509(certbio.get(), nullptr, nullptr, const_cast<char*>(pw.c_str())), X509_free);
555 if (!cert) {
556 ec = error_category::cert_load_failed;
557 return {};
558 }
559 std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> key(X509_get_pubkey(cert.get()), EVP_PKEY_free);
560 if (!key) {
561 ec = error_category::get_key_failed;
562 return {};
563 }
564 if (PEM_write_bio_PUBKEY(keybio.get(), key.get()) == 0) {
565 ec = error_category::write_key_failed;
566 return {};
567 }
568
569 return write_bio_to_string<error_category>(keybio, ec);
570 }
571
580 template<typename error_category = error::rsa_error>
581 std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") {
582 std::error_code ec;
583 auto res = extract_pubkey_from_cert<error_category>(certstr, pw, ec);
585 return res;
586 }
587
594 inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) {
595 ec.clear();
596
597 auto c_str = reinterpret_cast<const unsigned char*>(cert_der_str.c_str());
598
599 std::unique_ptr<X509, decltype(&X509_free)> cert(
600 d2i_X509(NULL, &c_str, static_cast<int>(cert_der_str.size())), X509_free);
601 auto certbio = make_mem_buf_bio();
602 if (!cert || !certbio) {
603 ec = error::rsa_error::create_mem_bio_failed;
604 return {};
605 }
606
607 if (!PEM_write_bio_X509(certbio.get(), cert.get())) {
608 ec = error::rsa_error::write_cert_failed;
609 return {};
610 }
611
612 return write_bio_to_string(certbio, ec);
613 }
614
629 template<typename Decode>
630 std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode,
631 std::error_code& ec) {
632 ec.clear();
633 const auto decoded_str = decode(cert_base64_der_str);
634 return convert_der_to_pem(decoded_str, ec);
635 }
636
651 template<typename Decode>
652 std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode) {
653 std::error_code ec;
654 auto res = convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
656 return res;
657 }
658
665 inline std::string convert_der_to_pem(const std::string& cert_der_str) {
666 std::error_code ec;
667 auto res = convert_der_to_pem(cert_der_str, ec);
669 return res;
670 }
671
672#ifndef JWT_DISABLE_BASE64
682 inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, std::error_code& ec) {
683 auto decode = [](const std::string& token) {
685 };
686 return convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
687 }
688
698 inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) {
699 std::error_code ec;
700 auto res = convert_base64_der_to_pem(cert_base64_der_str, ec);
702 return res;
703 }
704#endif
715 template<typename error_category = error::rsa_error>
716 evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password,
717 std::error_code& ec) {
718 ec.clear();
719 auto pubkey_bio = make_mem_buf_bio();
720 if (!pubkey_bio) {
721 ec = error_category::create_mem_bio_failed;
722 return {};
723 }
724 if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----") {
725 auto epkey = helper::extract_pubkey_from_cert<error_category>(key, password, ec);
726 if (ec) return {};
727 // Ensure the size fits into an int before casting
728 if (epkey.size() > static_cast<std::size_t>((std::numeric_limits<int>::max)())) {
729 ec = error_category::load_key_bio_write; // Add an appropriate error here
730 return {};
731 }
732 int len = static_cast<int>(epkey.size());
733 if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len) {
734 ec = error_category::load_key_bio_write;
735 return {};
736 }
737 } else {
738 // Ensure the size fits into an int before casting
739 if (key.size() > static_cast<std::size_t>((std::numeric_limits<int>::max)())) {
740 ec = error_category::load_key_bio_write; // Add an appropriate error here
741 return {};
742 }
743 int len = static_cast<int>(key.size());
744 if (BIO_write(pubkey_bio.get(), key.data(), len) != len) {
745 ec = error_category::load_key_bio_write;
746 return {};
747 }
748 }
749
750 evp_pkey_handle pkey(PEM_read_bio_PUBKEY(
751 pubkey_bio.get(), nullptr, nullptr,
752 (void*)password.data())); // NOLINT(google-readability-casting) requires `const_cast`
753 if (!pkey) ec = error_category::load_key_bio_read;
754 return pkey;
755 }
756
767 template<typename error_category = error::rsa_error>
768 inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password = "") {
769 std::error_code ec;
770 auto res = load_public_key_from_string<error_category>(key, password, ec);
772 return res;
773 }
774
783 template<typename error_category = error::rsa_error>
784 inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password,
785 std::error_code& ec) {
786 ec.clear();
787 auto private_key_bio = make_mem_buf_bio();
788 if (!private_key_bio) {
789 ec = error_category::create_mem_bio_failed;
790 return {};
791 }
792 const int len = static_cast<int>(key.size());
793 if (BIO_write(private_key_bio.get(), key.data(), len) != len) {
794 ec = error_category::load_key_bio_write;
795 return {};
796 }
797 evp_pkey_handle pkey(
798 PEM_read_bio_PrivateKey(private_key_bio.get(), nullptr, nullptr, const_cast<char*>(password.c_str())));
799 if (!pkey) ec = error_category::load_key_bio_read;
800 return pkey;
801 }
802
811 template<typename error_category = error::rsa_error>
812 inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password = "") {
813 std::error_code ec;
814 auto res = load_private_key_from_string<error_category>(key, password, ec);
816 return res;
817 }
818
830 inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password,
831 std::error_code& ec) {
832 return load_public_key_from_string<error::ecdsa_error>(key, password, ec);
833 }
834
840 inline
841#ifdef JWT_OPENSSL_1_0_0
842 std::string
843 bn2raw(BIGNUM* bn)
844#else
845 std::string
846 bn2raw(const BIGNUM* bn)
847#endif
848 {
849 std::string res(BN_num_bytes(bn), '\0');
850 BN_bn2bin(bn, (unsigned char*)res.data()); // NOLINT(google-readability-casting) requires `const_cast`
851 return res;
852 }
853
859 inline std::unique_ptr<BIGNUM, decltype(&BN_free)> raw2bn(const std::string& raw, std::error_code& ec) {
860 auto bn =
861 BN_bin2bn(reinterpret_cast<const unsigned char*>(raw.data()), static_cast<int>(raw.size()), nullptr);
862 // https://www.openssl.org/docs/man1.1.1/man3/BN_bin2bn.html#RETURN-VALUES
863 if (!bn) {
864 ec = error::rsa_error::set_rsa_failed;
865 return {nullptr, BN_free};
866 }
867 return {bn, BN_free};
868 }
869
874 inline std::unique_ptr<BIGNUM, decltype(&BN_free)> raw2bn(const std::string& raw) {
875 std::error_code ec;
876 auto res = raw2bn(raw, ec);
878 return res;
879 }
880
892 inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key,
893 const std::string& password = "") {
894 std::error_code ec;
895 auto res = load_public_key_from_string<error::ecdsa_error>(key, password, ec);
897 return res;
898 }
899
909 inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password,
910 std::error_code& ec) {
911 return load_private_key_from_string<error::ecdsa_error>(key, password, ec);
912 }
913
928 template<typename Decode>
929 std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent,
930 Decode decode, std::error_code& ec) {
931 ec.clear();
932 auto decoded_modulus = decode(modulus);
933 auto decoded_exponent = decode(exponent);
934
935 auto n = helper::raw2bn(decoded_modulus, ec);
936 if (ec) return {};
937 auto e = helper::raw2bn(decoded_exponent, ec);
938 if (ec) return {};
939
940#if defined(JWT_OPENSSL_3_0)
941 // OpenSSL deprecated mutable keys and there is a new way for making them
942 // https://mta.openssl.org/pipermail/openssl-users/2021-July/013994.html
943 // https://www.openssl.org/docs/man3.1/man3/OSSL_PARAM_BLD_new.html#Example-2
944 std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)> param_bld(OSSL_PARAM_BLD_new(),
945 OSSL_PARAM_BLD_free);
946 if (!param_bld) {
947 ec = error::rsa_error::create_context_failed;
948 return {};
949 }
950
951 if (OSSL_PARAM_BLD_push_BN(param_bld.get(), "n", n.get()) != 1 ||
952 OSSL_PARAM_BLD_push_BN(param_bld.get(), "e", e.get()) != 1) {
953 ec = error::rsa_error::set_rsa_failed;
954 return {};
955 }
956
957 std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)> params(OSSL_PARAM_BLD_to_param(param_bld.get()),
958 OSSL_PARAM_free);
959 if (!params) {
960 ec = error::rsa_error::set_rsa_failed;
961 return {};
962 }
963
964 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
965 EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr), EVP_PKEY_CTX_free);
966 if (!ctx) {
967 ec = error::rsa_error::create_context_failed;
968 return {};
969 }
970
971 // https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html#EXAMPLES
972 // Error codes based on https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_fromdata_init.html#RETURN-VALUES
973 EVP_PKEY* pkey = NULL;
974 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0 ||
975 EVP_PKEY_fromdata(ctx.get(), &pkey, EVP_PKEY_KEYPAIR, params.get()) <= 0) {
976 // It's unclear if this can fail after allocating but free it anyways
977 // https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html
978 EVP_PKEY_free(pkey);
979
980 ec = error::rsa_error::cert_load_failed;
981 return {};
982 }
983
984 // Transfer ownership so we get ref counter and cleanup
985 evp_pkey_handle rsa(pkey);
986
987#else
988 std::unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
989
990#if defined(JWT_OPENSSL_1_1_1) || defined(JWT_OPENSSL_1_1_0)
991 // After this RSA_free will also free the n and e big numbers
992 // See https://github.com/Thalhammer/jwt-cpp/pull/298#discussion_r1282619186
993 if (RSA_set0_key(rsa.get(), n.get(), e.get(), nullptr) == 1) {
994 // This can only fail we passed in NULL for `n` or `e`
995 // https://github.com/openssl/openssl/blob/d6e4056805f54bb1a0ef41fa3a6a35b70c94edba/crypto/rsa/rsa_lib.c#L396
996 // So to make sure there is no memory leak, we hold the references
997 n.release();
998 e.release();
999 } else {
1000 ec = error::rsa_error::set_rsa_failed;
1001 return {};
1002 }
1003#elif defined(JWT_OPENSSL_1_0_0)
1004 rsa->e = e.release();
1005 rsa->n = n.release();
1006 rsa->d = nullptr;
1007#endif
1008#endif
1009
1010 auto pub_key_bio = make_mem_buf_bio();
1011 if (!pub_key_bio) {
1012 ec = error::rsa_error::create_mem_bio_failed;
1013 return {};
1014 }
1015
1016 auto write_pem_to_bio =
1017#if defined(JWT_OPENSSL_3_0)
1018 // https://www.openssl.org/docs/man3.1/man3/PEM_write_bio_RSA_PUBKEY.html
1019 &PEM_write_bio_PUBKEY;
1020#else
1021 &PEM_write_bio_RSA_PUBKEY;
1022#endif
1023 if (write_pem_to_bio(pub_key_bio.get(), rsa.get()) != 1) {
1024 ec = error::rsa_error::load_key_bio_write;
1025 return {};
1026 }
1027
1028 return write_bio_to_string<error::rsa_error>(pub_key_bio, ec);
1029 }
1030
1044 template<typename Decode>
1045 std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent,
1046 Decode decode) {
1047 std::error_code ec;
1048 auto res = create_public_key_from_rsa_components(modulus, exponent, decode, ec);
1050 return res;
1051 }
1052
1053#ifndef JWT_DISABLE_BASE64
1064 inline std::string create_public_key_from_rsa_components(const std::string& modulus,
1065 const std::string& exponent, std::error_code& ec) {
1066 auto decode = [](const std::string& token) {
1068 };
1069 return create_public_key_from_rsa_components(modulus, exponent, std::move(decode), ec);
1070 }
1071
1080 inline std::string create_public_key_from_rsa_components(const std::string& modulus,
1081 const std::string& exponent) {
1082 std::error_code ec;
1083 auto res = create_public_key_from_rsa_components(modulus, exponent, ec);
1085 return res;
1086 }
1087#endif
1098 const std::string& password = "") {
1099 std::error_code ec;
1100 auto res = load_private_key_from_string<error::ecdsa_error>(key, password, ec);
1102 return res;
1103 }
1104
1105#if defined(JWT_OPENSSL_3_0)
1106
1114 inline std::string curve2group(const std::string curve, std::error_code& ec) {
1115 if (curve == "P-256") {
1116 return "prime256v1";
1117 } else if (curve == "P-384") {
1118 return "secp384r1";
1119 } else if (curve == "P-521") {
1120 return "secp521r1";
1121 } else {
1122 ec = jwt::error::ecdsa_error::unknown_curve;
1123 return {};
1124 }
1125 }
1126
1127#else
1128
1136 inline int curve2nid(const std::string curve, std::error_code& ec) {
1137 if (curve == "P-256") {
1138 return NID_X9_62_prime256v1;
1139 } else if (curve == "P-384") {
1140 return NID_secp384r1;
1141 } else if (curve == "P-521") {
1142 return NID_secp521r1;
1143 } else {
1144 ec = jwt::error::ecdsa_error::unknown_curve;
1145 return {};
1146 }
1147 }
1148
1149#endif
1150
1166 template<typename Decode>
1167 std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x,
1168 const std::string& y, Decode decode, std::error_code& ec) {
1169 ec.clear();
1170 auto decoded_x = decode(x);
1171 auto decoded_y = decode(y);
1172
1173#if defined(JWT_OPENSSL_3_0)
1174 // OpenSSL deprecated mutable keys and there is a new way for making them
1175 // https://mta.openssl.org/pipermail/openssl-users/2021-July/013994.html
1176 // https://www.openssl.org/docs/man3.1/man3/OSSL_PARAM_BLD_new.html#Example-2
1177 std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)> param_bld(OSSL_PARAM_BLD_new(),
1178 OSSL_PARAM_BLD_free);
1179 if (!param_bld) {
1180 ec = error::ecdsa_error::create_context_failed;
1181 return {};
1182 }
1183
1184 std::string group = helper::curve2group(curve, ec);
1185 if (ec) return {};
1186
1187 // https://github.com/openssl/openssl/issues/16270#issuecomment-895734092
1188 std::string pub = std::string("\x04").append(decoded_x).append(decoded_y);
1189
1190 if (OSSL_PARAM_BLD_push_utf8_string(param_bld.get(), "group", group.data(), group.size()) != 1 ||
1191 OSSL_PARAM_BLD_push_octet_string(param_bld.get(), "pub", pub.data(), pub.size()) != 1) {
1192 ec = error::ecdsa_error::set_ecdsa_failed;
1193 return {};
1194 }
1195
1196 std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)> params(OSSL_PARAM_BLD_to_param(param_bld.get()),
1197 OSSL_PARAM_free);
1198 if (!params) {
1199 ec = error::ecdsa_error::set_ecdsa_failed;
1200 return {};
1201 }
1202
1203 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1204 EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr), EVP_PKEY_CTX_free);
1205 if (!ctx) {
1206 ec = error::ecdsa_error::create_context_failed;
1207 return {};
1208 }
1209
1210 // https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html#EXAMPLES
1211 // Error codes based on https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_fromdata_init.html#RETURN-VALUES
1212 EVP_PKEY* pkey = NULL;
1213 if (EVP_PKEY_fromdata_init(ctx.get()) <= 0 ||
1214 EVP_PKEY_fromdata(ctx.get(), &pkey, EVP_PKEY_KEYPAIR, params.get()) <= 0) {
1215 // It's unclear if this can fail after allocating but free it anyways
1216 // https://www.openssl.org/docs/man3.0/man3/EVP_PKEY_fromdata.html
1217 EVP_PKEY_free(pkey);
1218
1219 ec = error::ecdsa_error::cert_load_failed;
1220 return {};
1221 }
1222
1223 // Transfer ownership so we get ref counter and cleanup
1224 evp_pkey_handle ecdsa(pkey);
1225
1226#else
1227 int nid = helper::curve2nid(curve, ec);
1228 if (ec) return {};
1229
1230 auto qx = helper::raw2bn(decoded_x, ec);
1231 if (ec) return {};
1232 auto qy = helper::raw2bn(decoded_y, ec);
1233 if (ec) return {};
1234
1235 std::unique_ptr<EC_GROUP, decltype(&EC_GROUP_free)> ecgroup(EC_GROUP_new_by_curve_name(nid), EC_GROUP_free);
1236 if (!ecgroup) {
1237 ec = error::ecdsa_error::set_ecdsa_failed;
1238 return {};
1239 }
1240
1241 EC_GROUP_set_asn1_flag(ecgroup.get(), OPENSSL_EC_NAMED_CURVE);
1242
1243 std::unique_ptr<EC_POINT, decltype(&EC_POINT_free)> ecpoint(EC_POINT_new(ecgroup.get()), EC_POINT_free);
1244 if (!ecpoint ||
1245 EC_POINT_set_affine_coordinates_GFp(ecgroup.get(), ecpoint.get(), qx.get(), qy.get(), nullptr) != 1) {
1246 ec = error::ecdsa_error::set_ecdsa_failed;
1247 return {};
1248 }
1249
1250 std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ecdsa(EC_KEY_new(), EC_KEY_free);
1251 if (!ecdsa || EC_KEY_set_group(ecdsa.get(), ecgroup.get()) != 1 ||
1252 EC_KEY_set_public_key(ecdsa.get(), ecpoint.get()) != 1) {
1253 ec = error::ecdsa_error::set_ecdsa_failed;
1254 return {};
1255 }
1256
1257#endif
1258
1259 auto pub_key_bio = make_mem_buf_bio();
1260 if (!pub_key_bio) {
1261 ec = error::ecdsa_error::create_mem_bio_failed;
1262 return {};
1263 }
1264
1265 auto write_pem_to_bio =
1266#if defined(JWT_OPENSSL_3_0)
1267 // https://www.openssl.org/docs/man3.1/man3/PEM_write_bio_EC_PUBKEY.html
1268 &PEM_write_bio_PUBKEY;
1269#else
1270 &PEM_write_bio_EC_PUBKEY;
1271#endif
1272 if (write_pem_to_bio(pub_key_bio.get(), ecdsa.get()) != 1) {
1273 ec = error::ecdsa_error::load_key_bio_write;
1274 return {};
1275 }
1276
1277 return write_bio_to_string<error::ecdsa_error>(pub_key_bio, ec);
1278 }
1279
1294 template<typename Decode>
1295 std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x,
1296 const std::string& y, Decode decode) {
1297 std::error_code ec;
1298 auto res = create_public_key_from_ec_components(curve, x, y, decode, ec);
1300 return res;
1301 }
1302
1303#ifndef JWT_DISABLE_BASE64
1315 inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x,
1316 const std::string& y, std::error_code& ec) {
1317 auto decode = [](const std::string& token) {
1319 };
1320 return create_public_key_from_ec_components(curve, x, y, std::move(decode), ec);
1321 }
1322
1332 inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x,
1333 const std::string& y) {
1334 std::error_code ec;
1335 auto res = create_public_key_from_ec_components(curve, x, y, ec);
1337 return res;
1338 }
1339#endif
1340 } // namespace helper
1341
1351 namespace algorithm {
1359 struct none {
1363 std::string sign(const std::string& /*unused*/, std::error_code& ec) const {
1364 ec.clear();
1365 return {};
1366 }
1367
1374 void verify(const std::string& /*unused*/, const std::string& signature, std::error_code& ec) const {
1375 ec.clear();
1376 if (!signature.empty()) { ec = error::signature_verification_error::invalid_signature; }
1377 }
1378
1379 std::string name() const { return "none"; }
1380 };
1381
1384 struct hmacsha {
1392 hmacsha(std::string key, const EVP_MD* (*md)(), std::string name)
1393 : secret(std::move(key)), md(md), alg_name(std::move(name)) {}
1394
1401 std::string sign(const std::string& data, std::error_code& ec) const {
1402 ec.clear();
1403 std::string res(static_cast<size_t>(EVP_MAX_MD_SIZE), '\0');
1404 auto len = static_cast<unsigned int>(res.size());
1405 if (HMAC(md(), secret.data(), static_cast<int>(secret.size()),
1406 reinterpret_cast<const unsigned char*>(data.data()), static_cast<int>(data.size()),
1407 (unsigned char*)res.data(), // NOLINT(google-readability-casting) requires `const_cast`
1408 &len) == nullptr) {
1409 ec = error::signature_generation_error::hmac_failed;
1410 return {};
1411 }
1412 res.resize(len);
1413 return res;
1414 }
1415
1422 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
1423 ec.clear();
1424 auto res = sign(data, ec);
1425 if (ec) return;
1426
1427 bool matched = true;
1428 for (size_t i = 0; i < std::min<size_t>(res.size(), signature.size()); i++)
1429 if (res[i] != signature[i]) matched = false;
1430 if (res.size() != signature.size()) matched = false;
1431 if (!matched) {
1432 ec = error::signature_verification_error::invalid_signature;
1433 return;
1434 }
1435 }
1436
1441 std::string name() const { return alg_name; }
1442
1443 private:
1445 const std::string secret;
1447 const EVP_MD* (*md)();
1449 const std::string alg_name;
1450 };
1451
1454 struct rsa {
1465 rsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
1466 const std::string& private_key_password, const EVP_MD* (*md)(), std::string name)
1467 : md(md), alg_name(std::move(name)) {
1468 if (!private_key.empty()) {
1469 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1470 } else if (!public_key.empty()) {
1471 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1472 } else
1473 throw error::rsa_exception(error::rsa_error::no_key_provided);
1474 }
1475
1482 rsa(helper::evp_pkey_handle key_pair, const EVP_MD* (*md)(), std::string name)
1483 : pkey(std::move(key_pair)), md(md), alg_name(std::move(name)) {
1484 if (!pkey) { throw error::rsa_exception(error::rsa_error::no_key_provided); }
1485 }
1486
1492 std::string sign(const std::string& data, std::error_code& ec) const {
1493 ec.clear();
1494 auto ctx = helper::make_evp_md_ctx();
1495 if (!ctx) {
1496 ec = error::signature_generation_error::create_context_failed;
1497 return {};
1498 }
1499 if (!EVP_SignInit(ctx.get(), md())) {
1500 ec = error::signature_generation_error::signinit_failed;
1501 return {};
1502 }
1503
1504 std::string res(EVP_PKEY_size(pkey.get()), '\0');
1505 unsigned int len = 0;
1506
1507 if (!EVP_SignUpdate(ctx.get(), data.data(), data.size())) {
1508 ec = error::signature_generation_error::signupdate_failed;
1509 return {};
1510 }
1511 if (EVP_SignFinal(ctx.get(), (unsigned char*)res.data(), &len, pkey.get()) == 0) {
1512 ec = error::signature_generation_error::signfinal_failed;
1513 return {};
1514 }
1515
1516 res.resize(len);
1517 return res;
1518 }
1519
1526 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
1527 ec.clear();
1528 auto ctx = helper::make_evp_md_ctx();
1529 if (!ctx) {
1530 ec = error::signature_verification_error::create_context_failed;
1531 return;
1532 }
1533 if (!EVP_VerifyInit(ctx.get(), md())) {
1534 ec = error::signature_verification_error::verifyinit_failed;
1535 return;
1536 }
1537 if (!EVP_VerifyUpdate(ctx.get(), data.data(), data.size())) {
1538 ec = error::signature_verification_error::verifyupdate_failed;
1539 return;
1540 }
1541 auto res = EVP_VerifyFinal(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
1542 static_cast<unsigned int>(signature.size()), pkey.get());
1543 if (res != 1) {
1544 ec = error::signature_verification_error::verifyfinal_failed;
1545 return;
1546 }
1547 }
1548
1552 std::string name() const { return alg_name; }
1553
1554 private:
1558 const EVP_MD* (*md)();
1560 const std::string alg_name;
1561 };
1562
1565 struct ecdsa {
1577 ecdsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
1578 const std::string& private_key_password, const EVP_MD* (*md)(), std::string name, size_t siglen)
1579 : md(md), alg_name(std::move(name)), signature_length(siglen) {
1580 if (!private_key.empty()) {
1581 pkey = helper::load_private_ec_key_from_string(private_key, private_key_password);
1582 check_private_key(pkey.get());
1583 } else if (!public_key.empty()) {
1584 pkey = helper::load_public_ec_key_from_string(public_key, public_key_password);
1585 check_public_key(pkey.get());
1586 } else {
1587 throw error::ecdsa_exception(error::ecdsa_error::no_key_provided);
1588 }
1589 if (!pkey) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1590
1591 size_t keysize = EVP_PKEY_bits(pkey.get());
1592 if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521))
1593 throw error::ecdsa_exception(error::ecdsa_error::invalid_key_size);
1594 }
1595
1604 ecdsa(helper::evp_pkey_handle key_pair, const EVP_MD* (*md)(), std::string name, size_t siglen)
1605 : pkey(std::move(key_pair)), md(md), alg_name(std::move(name)), signature_length(siglen) {
1606 if (!pkey) { throw error::ecdsa_exception(error::ecdsa_error::no_key_provided); }
1607 size_t keysize = EVP_PKEY_bits(pkey.get());
1608 if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521))
1609 throw error::ecdsa_exception(error::ecdsa_error::invalid_key_size);
1610 }
1611
1618 std::string sign(const std::string& data, std::error_code& ec) const {
1619 ec.clear();
1620 auto ctx = helper::make_evp_md_ctx();
1621 if (!ctx) {
1622 ec = error::signature_generation_error::create_context_failed;
1623 return {};
1624 }
1625 if (!EVP_DigestSignInit(ctx.get(), nullptr, md(), nullptr, pkey.get())) {
1626 ec = error::signature_generation_error::signinit_failed;
1627 return {};
1628 }
1629 if (!EVP_DigestUpdate(ctx.get(), data.data(), static_cast<unsigned int>(data.size()))) {
1630 ec = error::signature_generation_error::digestupdate_failed;
1631 return {};
1632 }
1633
1634 size_t len = 0;
1635 if (!EVP_DigestSignFinal(ctx.get(), nullptr, &len)) {
1636 ec = error::signature_generation_error::signfinal_failed;
1637 return {};
1638 }
1639 std::string res(len, '\0');
1640 if (!EVP_DigestSignFinal(ctx.get(), (unsigned char*)res.data(), &len)) {
1641 ec = error::signature_generation_error::signfinal_failed;
1642 return {};
1643 }
1644
1645 res.resize(len);
1646 return der_to_p1363_signature(res, ec);
1647 }
1648
1655 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
1656 ec.clear();
1657 std::string der_signature = p1363_to_der_signature(signature, ec);
1658 if (ec) { return; }
1659
1660 auto ctx = helper::make_evp_md_ctx();
1661 if (!ctx) {
1662 ec = error::signature_verification_error::create_context_failed;
1663 return;
1664 }
1665 if (!EVP_DigestVerifyInit(ctx.get(), nullptr, md(), nullptr, pkey.get())) {
1666 ec = error::signature_verification_error::verifyinit_failed;
1667 return;
1668 }
1669 if (!EVP_DigestUpdate(ctx.get(), data.data(), static_cast<unsigned int>(data.size()))) {
1670 ec = error::signature_verification_error::verifyupdate_failed;
1671 return;
1672 }
1673
1674#if OPENSSL_VERSION_NUMBER < 0x10002000L
1675 unsigned char* der_sig_data = reinterpret_cast<unsigned char*>(const_cast<char*>(der_signature.data()));
1676#else
1677 const unsigned char* der_sig_data = reinterpret_cast<const unsigned char*>(der_signature.data());
1678#endif
1679 auto res =
1680 EVP_DigestVerifyFinal(ctx.get(), der_sig_data, static_cast<unsigned int>(der_signature.length()));
1681 if (res == 0) {
1682 ec = error::signature_verification_error::invalid_signature;
1683 return;
1684 }
1685 if (res == -1) {
1686 ec = error::signature_verification_error::verifyfinal_failed;
1687 return;
1688 }
1689 }
1690
1694 std::string name() const { return alg_name; }
1695
1696 private:
1697 static void check_public_key(EVP_PKEY* pkey) {
1698#ifdef JWT_OPENSSL_3_0
1699 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1700 EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
1701 if (!ctx) { throw error::ecdsa_exception(error::ecdsa_error::create_context_failed); }
1702 if (EVP_PKEY_public_check(ctx.get()) != 1) {
1703 throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1704 }
1705#else
1706 std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey), EC_KEY_free);
1707 if (!eckey) { throw error::ecdsa_exception(error::ecdsa_error::invalid_key); }
1708 if (EC_KEY_check_key(eckey.get()) == 0) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1709#endif
1710 }
1711
1712 static void check_private_key(EVP_PKEY* pkey) {
1713#ifdef JWT_OPENSSL_3_0
1714 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1715 EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
1716 if (!ctx) { throw error::ecdsa_exception(error::ecdsa_error::create_context_failed); }
1717 if (EVP_PKEY_private_check(ctx.get()) != 1) {
1718 throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1719 }
1720#else
1721 std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey), EC_KEY_free);
1722 if (!eckey) { throw error::ecdsa_exception(error::ecdsa_error::invalid_key); }
1723 if (EC_KEY_check_key(eckey.get()) == 0) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1724#endif
1725 }
1726
1727 std::string der_to_p1363_signature(const std::string& der_signature, std::error_code& ec) const {
1728 const unsigned char* possl_signature = reinterpret_cast<const unsigned char*>(der_signature.data());
1729 std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(
1730 d2i_ECDSA_SIG(nullptr, &possl_signature, static_cast<long>(der_signature.length())),
1731 ECDSA_SIG_free);
1732 if (!sig) {
1733 ec = error::signature_generation_error::signature_decoding_failed;
1734 return {};
1735 }
1736
1737#ifdef JWT_OPENSSL_1_0_0
1738 auto rr = helper::bn2raw(sig->r);
1739 auto rs = helper::bn2raw(sig->s);
1740#else
1741 const BIGNUM* r;
1742 const BIGNUM* s;
1743 ECDSA_SIG_get0(sig.get(), &r, &s);
1744 auto rr = helper::bn2raw(r);
1745 auto rs = helper::bn2raw(s);
1746#endif
1747 if (rr.size() > signature_length / 2 || rs.size() > signature_length / 2)
1748 throw std::logic_error("bignum size exceeded expected length");
1749 rr.insert(0, signature_length / 2 - rr.size(), '\0');
1750 rs.insert(0, signature_length / 2 - rs.size(), '\0');
1751 return rr + rs;
1752 }
1753
1754 std::string p1363_to_der_signature(const std::string& signature, std::error_code& ec) const {
1755 ec.clear();
1756 auto r = helper::raw2bn(signature.substr(0, signature.size() / 2), ec);
1757 if (ec) return {};
1758 auto s = helper::raw2bn(signature.substr(signature.size() / 2), ec);
1759 if (ec) return {};
1760
1761 ECDSA_SIG* psig;
1762#ifdef JWT_OPENSSL_1_0_0
1763 ECDSA_SIG sig;
1764 sig.r = r.get();
1765 sig.s = s.get();
1766 psig = &sig;
1767#else
1768 std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(ECDSA_SIG_new(), ECDSA_SIG_free);
1769 if (!sig) {
1770 ec = error::signature_verification_error::create_context_failed;
1771 return {};
1772 }
1773 ECDSA_SIG_set0(sig.get(), r.release(), s.release());
1774 psig = sig.get();
1775#endif
1776
1777 int length = i2d_ECDSA_SIG(psig, nullptr);
1778 if (length < 0) {
1779 ec = error::signature_verification_error::signature_encoding_failed;
1780 return {};
1781 }
1782 std::string der_signature(length, '\0');
1783 unsigned char* psbuffer = (unsigned char*)der_signature.data();
1784 length = i2d_ECDSA_SIG(psig, &psbuffer);
1785 if (length < 0) {
1786 ec = error::signature_verification_error::signature_encoding_failed;
1787 return {};
1788 }
1789 der_signature.resize(length);
1790 return der_signature;
1791 }
1792
1794 helper::evp_pkey_handle pkey;
1796 const EVP_MD* (*md)();
1798 const std::string alg_name;
1800 const size_t signature_length;
1801 };
1802
1803#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
1813 struct eddsa {
1824 eddsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
1825 const std::string& private_key_password, std::string name)
1826 : alg_name(std::move(name)) {
1827 if (!private_key.empty()) {
1828 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1829 } else if (!public_key.empty()) {
1830 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1831 } else
1832 throw error::ecdsa_exception(error::ecdsa_error::load_key_bio_read);
1833 }
1834
1840 std::string sign(const std::string& data, std::error_code& ec) const {
1841 ec.clear();
1842 auto ctx = helper::make_evp_md_ctx();
1843 if (!ctx) {
1844 ec = error::signature_generation_error::create_context_failed;
1845 return {};
1846 }
1847 if (!EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())) {
1848 ec = error::signature_generation_error::signinit_failed;
1849 return {};
1850 }
1851
1852 size_t len = EVP_PKEY_size(pkey.get());
1853 std::string res(len, '\0');
1854
1855// LibreSSL and OpenSSL, require the oneshot EVP_DigestSign API.
1856// wolfSSL uses the Update/Final pattern.
1857#if defined(LIBWOLFSSL_VERSION_HEX)
1858 ERR_clear_error();
1859 if (EVP_DigestSignUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()), data.size()) !=
1860 1) {
1861 std::cout << ERR_error_string(ERR_get_error(), NULL) << '\n';
1862 ec = error::signature_generation_error::signupdate_failed;
1863 return {};
1864 }
1865 if (EVP_DigestSignFinal(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len) != 1) {
1866 ec = error::signature_generation_error::signfinal_failed;
1867 return {};
1868 }
1869#else
1870 if (EVP_DigestSign(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len,
1871 reinterpret_cast<const unsigned char*>(data.data()), data.size()) != 1) {
1872 ec = error::signature_generation_error::signfinal_failed;
1873 return {};
1874 }
1875#endif
1876
1877 res.resize(len);
1878 return res;
1879 }
1880
1887 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
1888 ec.clear();
1889 auto ctx = helper::make_evp_md_ctx();
1890 if (!ctx) {
1891 ec = error::signature_verification_error::create_context_failed;
1892 return;
1893 }
1894 if (!EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())) {
1895 ec = error::signature_verification_error::verifyinit_failed;
1896 return;
1897 }
1898// LibreSSL and OpenSSL, require the oneshot EVP_DigestVerify API.
1899// wolfSSL uses the Update/Final pattern.
1900#if defined(LIBWOLFSSL_VERSION_HEX)
1901 if (EVP_DigestVerifyUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()),
1902 data.size()) != 1) {
1903 ec = error::signature_verification_error::verifyupdate_failed;
1904 return;
1905 }
1906 if (EVP_DigestVerifyFinal(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
1907 signature.size()) != 1) {
1908 ec = error::signature_verification_error::verifyfinal_failed;
1909 return;
1910 }
1911#else
1912 auto res = EVP_DigestVerify(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
1913 signature.size(), reinterpret_cast<const unsigned char*>(data.data()),
1914 data.size());
1915 if (res != 1) {
1916 ec = error::signature_verification_error::verifyfinal_failed;
1917 return;
1918 }
1919#endif
1920 }
1921
1925 std::string name() const { return alg_name; }
1926
1927 private:
1931 const std::string alg_name;
1932 };
1933#endif
1937 struct pss {
1947 pss(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
1948 const std::string& private_key_password, const EVP_MD* (*md)(), std::string name)
1949 : md(md), alg_name(std::move(name)) {
1950 if (!private_key.empty()) {
1951 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1952 } else if (!public_key.empty()) {
1953 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1954 } else
1955 throw error::rsa_exception(error::rsa_error::no_key_provided);
1956 }
1957
1964 std::string sign(const std::string& data, std::error_code& ec) const {
1965 ec.clear();
1966 auto md_ctx = helper::make_evp_md_ctx();
1967 if (!md_ctx) {
1968 ec = error::signature_generation_error::create_context_failed;
1969 return {};
1970 }
1971 EVP_PKEY_CTX* ctx = nullptr;
1972 if (EVP_DigestSignInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1) {
1973 ec = error::signature_generation_error::signinit_failed;
1974 return {};
1975 }
1976 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
1977 ec = error::signature_generation_error::rsa_padding_failed;
1978 return {};
1979 }
1980// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1981// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1982#ifndef LIBWOLFSSL_VERSION_HEX
1983 if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0) {
1984 ec = error::signature_generation_error::set_rsa_pss_saltlen_failed;
1985 return {};
1986 }
1987#endif
1988 if (EVP_DigestUpdate(md_ctx.get(), data.data(), static_cast<unsigned int>(data.size())) != 1) {
1989 ec = error::signature_generation_error::digestupdate_failed;
1990 return {};
1991 }
1992
1993 size_t size = EVP_PKEY_size(pkey.get());
1994 std::string res(size, 0x00);
1995 if (EVP_DigestSignFinal(
1996 md_ctx.get(),
1997 (unsigned char*)res.data(), // NOLINT(google-readability-casting) requires `const_cast`
1998 &size) <= 0) {
1999 ec = error::signature_generation_error::signfinal_failed;
2000 return {};
2001 }
2002
2003 return res;
2004 }
2005
2012 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
2013 ec.clear();
2014
2015 auto md_ctx = helper::make_evp_md_ctx();
2016 if (!md_ctx) {
2017 ec = error::signature_verification_error::create_context_failed;
2018 return;
2019 }
2020 EVP_PKEY_CTX* ctx = nullptr;
2021 if (EVP_DigestVerifyInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1) {
2022 ec = error::signature_verification_error::verifyinit_failed;
2023 return;
2024 }
2025 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
2026 ec = error::signature_generation_error::rsa_padding_failed;
2027 return;
2028 }
2029// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
2030// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
2031#ifndef LIBWOLFSSL_VERSION_HEX
2032 if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0) {
2033 ec = error::signature_verification_error::set_rsa_pss_saltlen_failed;
2034 return;
2035 }
2036#endif
2037 if (EVP_DigestUpdate(md_ctx.get(), data.data(), static_cast<unsigned int>(data.size())) != 1) {
2038 ec = error::signature_verification_error::verifyupdate_failed;
2039 return;
2040 }
2041
2042 if (EVP_DigestVerifyFinal(md_ctx.get(), (unsigned char*)signature.data(), signature.size()) <= 0) {
2043 ec = error::signature_verification_error::verifyfinal_failed;
2044 return;
2045 }
2046 }
2047
2051 std::string name() const { return alg_name; }
2052
2053 private:
2057 const EVP_MD* (*md)();
2059 const std::string alg_name;
2060 };
2061
2065 struct hs256 : public hmacsha {
2070 explicit hs256(std::string key) : hmacsha(std::move(key), EVP_sha256, "HS256") {}
2071 };
2072
2075 struct hs384 : public hmacsha {
2080 explicit hs384(std::string key) : hmacsha(std::move(key), EVP_sha384, "HS384") {}
2081 };
2082
2085 struct hs512 : public hmacsha {
2090 explicit hs512(std::string key) : hmacsha(std::move(key), EVP_sha512, "HS512") {}
2091 };
2092
2097 struct rs256 : public rsa {
2106 explicit rs256(const std::string& public_key, const std::string& private_key = "",
2107 const std::string& public_key_password = "", const std::string& private_key_password = "")
2108 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "RS256") {}
2109 };
2110
2113 struct rs384 : public rsa {
2121 explicit rs384(const std::string& public_key, const std::string& private_key = "",
2122 const std::string& public_key_password = "", const std::string& private_key_password = "")
2123 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "RS384") {}
2124 };
2125
2128 struct rs512 : public rsa {
2136 explicit rs512(const std::string& public_key, const std::string& private_key = "",
2137 const std::string& public_key_password = "", const std::string& private_key_password = "")
2138 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "RS512") {}
2139 };
2140
2143 struct es256 : public ecdsa {
2153 explicit es256(const std::string& public_key, const std::string& private_key = "",
2154 const std::string& public_key_password = "", const std::string& private_key_password = "")
2155 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "ES256", 64) {}
2156 };
2157
2160 struct es384 : public ecdsa {
2170 explicit es384(const std::string& public_key, const std::string& private_key = "",
2171 const std::string& public_key_password = "", const std::string& private_key_password = "")
2172 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "ES384", 96) {}
2173 };
2174
2177 struct es512 : public ecdsa {
2187 explicit es512(const std::string& public_key, const std::string& private_key = "",
2188 const std::string& public_key_password = "", const std::string& private_key_password = "")
2189 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "ES512", 132) {}
2190 };
2191
2194 struct es256k : public ecdsa {
2203 explicit es256k(const std::string& public_key, const std::string& private_key = "",
2204 const std::string& public_key_password = "", const std::string& private_key_password = "")
2205 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "ES256K", 64) {}
2206 };
2207
2208#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
2216 struct ed25519 : public eddsa {
2226 explicit ed25519(const std::string& public_key, const std::string& private_key = "",
2227 const std::string& public_key_password = "", const std::string& private_key_password = "")
2228 : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA") {}
2229 };
2230
2231#if !defined(LIBRESSL_VERSION_NUMBER)
2239 struct ed448 : public eddsa {
2249 explicit ed448(const std::string& public_key, const std::string& private_key = "",
2250 const std::string& public_key_password = "", const std::string& private_key_password = "")
2251 : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA") {}
2252 };
2253#endif // !LIBRESSL_VERSION_NUMBER
2254#endif // !JWT_OPENSSL_1_0_0 && !JWT_OPENSSL_1_1_0
2255
2259 struct ps256 : public pss {
2267 explicit ps256(const std::string& public_key, const std::string& private_key = "",
2268 const std::string& public_key_password = "", const std::string& private_key_password = "")
2269 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "PS256") {}
2270 };
2271
2274 struct ps384 : public pss {
2282 explicit ps384(const std::string& public_key, const std::string& private_key = "",
2283 const std::string& public_key_password = "", const std::string& private_key_password = "")
2284 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "PS384") {}
2285 };
2286
2289 struct ps512 : public pss {
2297 explicit ps512(const std::string& public_key, const std::string& private_key = "",
2298 const std::string& public_key_password = "", const std::string& private_key_password = "")
2299 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "PS512") {}
2300 };
2301 } // namespace algorithm
2302
2306 namespace json {
2314 enum class type { boolean, integer, number, string, array, object };
2315 } // namespace json
2316
2317 namespace details {
2318#ifdef __cpp_lib_void_t
2319 template<typename... Ts>
2320 using void_t = std::void_t<Ts...>;
2321#else
2322 // https://en.cppreference.com/w/cpp/types/void_t
2323 template<typename... Ts>
2324 struct make_void {
2325 using type = void;
2326 };
2327
2328 template<typename... Ts>
2329 using void_t = typename make_void<Ts...>::type;
2330#endif
2331
2332#ifdef __cpp_lib_experimental_detect
2333 template<template<typename...> class _Op, typename... _Args>
2334 using is_detected = std::experimental::is_detected<_Op, _Args...>;
2335#else
2336 struct nonesuch {
2337 nonesuch() = delete;
2338 ~nonesuch() = delete;
2339 nonesuch(nonesuch const&) = delete;
2340 nonesuch(nonesuch const&&) = delete;
2341 void operator=(nonesuch const&) = delete;
2342 void operator=(nonesuch&&) = delete;
2343 };
2344
2345 // https://en.cppreference.com/w/cpp/experimental/is_detected
2346 template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
2347 struct detector {
2348 using value = std::false_type;
2349 using type = Default;
2350 };
2351
2352 template<class Default, template<class...> class Op, class... Args>
2353 struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
2354 using value = std::true_type;
2355 using type = Op<Args...>;
2356 };
2357
2358 template<template<class...> class Op, class... Args>
2359 using is_detected = typename detector<nonesuch, void, Op, Args...>::value;
2360#endif
2361
2362 template<typename T, typename Signature>
2363 using is_signature = typename std::is_same<T, Signature>;
2364
2365 template<typename traits_type, template<typename...> class Op, typename Signature>
2366 struct is_function_signature_detected {
2367 using type = Op<traits_type>;
2368 static constexpr auto value = is_detected<Op, traits_type>::value && std::is_function<type>::value &&
2369 is_signature<type, Signature>::value;
2370 };
2371
2372 template<typename traits_type, typename value_type>
2373 struct supports_get_type {
2374 template<typename T>
2375 using get_type_t = decltype(T::get_type);
2376
2377 static constexpr auto value =
2378 is_function_signature_detected<traits_type, get_type_t, json::type(const value_type&)>::value;
2379
2380 // Internal assertions for better feedback
2381 static_assert(value, "traits implementation must provide `jwt::json::type get_type(const value_type&)`");
2382 };
2383
2384#define JWT_CPP_JSON_TYPE_TYPE(TYPE) json_##TYPE_type
2385#define JWT_CPP_AS_TYPE_T(TYPE) as_##TYPE_t
2386#define JWT_CPP_SUPPORTS_AS(TYPE) \
2387 template<typename traits_type, typename value_type, typename JWT_CPP_JSON_TYPE_TYPE(TYPE)> \
2388 struct supports_as_##TYPE { \
2389 template<typename T> \
2390 using JWT_CPP_AS_TYPE_T(TYPE) = decltype(T::as_##TYPE); \
2391 \
2392 static constexpr auto value = \
2393 is_function_signature_detected<traits_type, JWT_CPP_AS_TYPE_T(TYPE), \
2394 JWT_CPP_JSON_TYPE_TYPE(TYPE)(const value_type&)>::value; \
2395 \
2396 static_assert(value, "traits implementation must provide `" #TYPE "_type as_" #TYPE "(const value_type&)`"); \
2397 }
2398
2399 JWT_CPP_SUPPORTS_AS(object);
2400 JWT_CPP_SUPPORTS_AS(array);
2401 JWT_CPP_SUPPORTS_AS(string);
2402 JWT_CPP_SUPPORTS_AS(number);
2403 JWT_CPP_SUPPORTS_AS(integer);
2404 JWT_CPP_SUPPORTS_AS(boolean);
2405
2406#undef JWT_CPP_JSON_TYPE_TYPE
2407#undef JWT_CPP_AS_TYPE_T
2408#undef JWT_CPP_SUPPORTS_AS
2409
2410 template<typename traits>
2411 struct is_valid_traits {
2412 static constexpr auto value =
2413 supports_get_type<traits, typename traits::value_type>::value &&
2414 supports_as_object<traits, typename traits::value_type, typename traits::object_type>::value &&
2415 supports_as_array<traits, typename traits::value_type, typename traits::array_type>::value &&
2416 supports_as_string<traits, typename traits::value_type, typename traits::string_type>::value &&
2417 supports_as_number<traits, typename traits::value_type, typename traits::number_type>::value &&
2418 supports_as_integer<traits, typename traits::value_type, typename traits::integer_type>::value &&
2419 supports_as_boolean<traits, typename traits::value_type, typename traits::boolean_type>::value;
2420 };
2421
2422 template<typename value_type>
2423 struct is_valid_json_value {
2424 static constexpr auto value =
2425 std::is_default_constructible<value_type>::value &&
2426 std::is_constructible<value_type, const value_type&>::value && // a more generic is_copy_constructible
2427 std::is_move_constructible<value_type>::value && std::is_assignable<value_type, value_type>::value &&
2428 std::is_copy_assignable<value_type>::value && std::is_move_assignable<value_type>::value;
2429 };
2430
2431 // https://stackoverflow.com/a/53967057/8480874
2432 template<typename T, typename = void>
2433 struct is_iterable : std::false_type {};
2434
2435 template<typename T>
2436 struct is_iterable<T, void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>())),
2437#if __cplusplus > 201402L
2438 decltype(std::cbegin(std::declval<T>())), decltype(std::cend(std::declval<T>()))
2439#else
2440 decltype(std::begin(std::declval<const T>())),
2441 decltype(std::end(std::declval<const T>()))
2442#endif
2443 >> : std::true_type {
2444 };
2445
2446#if __cplusplus > 201703L
2447 template<typename T>
2448 inline constexpr bool is_iterable_v = is_iterable<T>::value;
2449#endif
2450
2451 template<typename object_type, typename string_type>
2452 using is_count_signature = typename std::is_integral<decltype(std::declval<const object_type>().count(
2453 std::declval<const string_type>()))>;
2454
2455 template<typename object_type, typename string_type, typename = void>
2456 struct is_subcription_operator_signature : std::false_type {};
2457
2458 template<typename object_type, typename string_type>
2459 struct is_subcription_operator_signature<
2460 object_type, string_type,
2461 void_t<decltype(std::declval<object_type>().operator[](std::declval<string_type>()))>> : std::true_type {
2462 // TODO(prince-chrismc): I am not convienced this is meaningful anymore
2463 static_assert(
2464 value,
2465 "object_type must implementate the subscription operator '[]' taking string_type as an argument");
2466 };
2467
2468 template<typename object_type, typename value_type, typename string_type>
2469 using is_at_const_signature =
2470 typename std::is_same<decltype(std::declval<const object_type>().at(std::declval<const string_type>())),
2471 const value_type&>;
2472
2473 template<typename value_type, typename string_type, typename object_type>
2474 struct is_valid_json_object {
2475 template<typename T>
2476 using mapped_type_t = typename T::mapped_type;
2477 template<typename T>
2478 using key_type_t = typename T::key_type;
2479 template<typename T>
2480 using iterator_t = typename T::iterator;
2481 template<typename T>
2482 using const_iterator_t = typename T::const_iterator;
2483
2484 static constexpr auto value =
2485 std::is_constructible<value_type, object_type>::value &&
2486 is_detected<mapped_type_t, object_type>::value &&
2487 std::is_same<typename object_type::mapped_type, value_type>::value &&
2488 is_detected<key_type_t, object_type>::value &&
2489 (std::is_same<typename object_type::key_type, string_type>::value ||
2490 std::is_constructible<typename object_type::key_type, string_type>::value) &&
2491 is_detected<iterator_t, object_type>::value && is_detected<const_iterator_t, object_type>::value &&
2492 is_iterable<object_type>::value && is_count_signature<object_type, string_type>::value &&
2493 is_subcription_operator_signature<object_type, string_type>::value &&
2494 is_at_const_signature<object_type, value_type, string_type>::value;
2495 };
2496
2497 template<typename array_type>
2498 using is_size_signature = typename std::is_integral<decltype(std::declval<const array_type>().size())>;
2499
2500 template<typename array_type>
2501 using is_empty_signature = typename std::is_same<bool, decltype(std::declval<const array_type>().empty())>;
2502
2503 template<typename value_type, typename array_type>
2504 struct is_valid_json_array {
2505 template<typename T>
2506 using value_type_t = typename T::value_type;
2507 using front_base_type = typename std::decay<decltype(std::declval<array_type>().front())>::type;
2508
2509 static constexpr auto value = std::is_constructible<value_type, array_type>::value &&
2510 is_iterable<array_type>::value &&
2511 is_detected<value_type_t, array_type>::value &&
2512 std::is_same<typename array_type::value_type, value_type>::value &&
2513 std::is_same<front_base_type, value_type>::value &&
2514 is_size_signature<array_type>::value && is_empty_signature<array_type>::value;
2515 };
2516
2517 template<typename string_type, typename integer_type>
2518 using is_substr_start_end_index_signature =
2519 typename std::is_same<decltype(std::declval<string_type>().substr(
2520 static_cast<size_t>(std::declval<integer_type>()),
2521 static_cast<size_t>(std::declval<integer_type>()))),
2522 string_type>;
2523
2524 template<typename string_type, typename integer_type>
2525 using is_substr_start_index_signature =
2526 typename std::is_same<decltype(std::declval<string_type>().substr(
2527 static_cast<size_t>(std::declval<integer_type>()))),
2528 string_type>;
2529
2530 template<typename string_type>
2531 using is_std_operate_plus_signature =
2532 typename std::is_same<decltype(std::operator+(std::declval<string_type>(), std::declval<string_type>())),
2533 string_type>;
2534
2535 template<typename value_type, typename string_type, typename integer_type>
2536 struct is_valid_json_string {
2537 static constexpr auto substr = is_substr_start_end_index_signature<string_type, integer_type>::value &&
2538 is_substr_start_index_signature<string_type, integer_type>::value;
2539 static_assert(substr, "string_type must have a substr method taking only a start index and an overload "
2540 "taking a start and end index, both must return a string_type");
2541
2542 static constexpr auto operator_plus = is_std_operate_plus_signature<string_type>::value;
2543 static_assert(operator_plus,
2544 "string_type must have a '+' operator implemented which returns the concatenated string");
2545
2546 static constexpr auto value =
2547 std::is_constructible<value_type, string_type>::value && substr && operator_plus;
2548 };
2549
2550 template<typename value_type, typename number_type>
2551 struct is_valid_json_number {
2552 static constexpr auto value =
2553 std::is_floating_point<number_type>::value && std::is_constructible<value_type, number_type>::value;
2554 };
2555
2556 template<typename value_type, typename integer_type>
2557 struct is_valid_json_integer {
2558 static constexpr auto value = std::is_signed<integer_type>::value &&
2559 !std::is_floating_point<integer_type>::value &&
2560 std::is_constructible<value_type, integer_type>::value;
2561 };
2562 template<typename value_type, typename boolean_type>
2563 struct is_valid_json_boolean {
2564 static constexpr auto value = std::is_convertible<boolean_type, bool>::value &&
2565 std::is_constructible<value_type, boolean_type>::value;
2566 };
2567
2568 template<typename value_type, typename object_type, typename array_type, typename string_type,
2569 typename number_type, typename integer_type, typename boolean_type>
2570 struct is_valid_json_types {
2571 // Internal assertions for better feedback
2572 static_assert(is_valid_json_value<value_type>::value,
2573 "value_type must meet basic requirements, default constructor, copyable, moveable");
2574 static_assert(is_valid_json_object<value_type, string_type, object_type>::value,
2575 "object_type must be a string_type to value_type container");
2576 static_assert(is_valid_json_array<value_type, array_type>::value,
2577 "array_type must be a container of value_type");
2578
2579 static constexpr auto value = is_valid_json_value<value_type>::value &&
2580 is_valid_json_object<value_type, string_type, object_type>::value &&
2581 is_valid_json_array<value_type, array_type>::value &&
2582 is_valid_json_string<value_type, string_type, integer_type>::value &&
2583 is_valid_json_number<value_type, number_type>::value &&
2584 is_valid_json_integer<value_type, integer_type>::value &&
2585 is_valid_json_boolean<value_type, boolean_type>::value;
2586 };
2587 } // namespace details
2588
2596 template<typename json_traits>
2597 class basic_claim {
2604 static_assert(std::is_same<typename json_traits::string_type, std::string>::value ||
2605 std::is_convertible<typename json_traits::string_type, std::string>::value ||
2606 std::is_constructible<typename json_traits::string_type, std::string>::value,
2607 "string_type must be a std::string, convertible to a std::string, or construct a std::string.");
2608
2609 static_assert(
2610 details::is_valid_json_types<typename json_traits::value_type, typename json_traits::object_type,
2611 typename json_traits::array_type, typename json_traits::string_type,
2612 typename json_traits::number_type, typename json_traits::integer_type,
2613 typename json_traits::boolean_type>::value,
2614 "must satisfy json container requirements");
2615 static_assert(details::is_valid_traits<json_traits>::value, "traits must satisfy requirements");
2616
2617 typename json_traits::value_type val;
2618
2619 public:
2623 using set_t = std::set<typename json_traits::string_type>;
2624
2625 basic_claim() = default;
2626 basic_claim(const basic_claim&) = default;
2627 basic_claim(basic_claim&&) = default;
2628 basic_claim& operator=(const basic_claim&) = default;
2629 basic_claim& operator=(basic_claim&&) = default;
2630 ~basic_claim() = default;
2631
2632 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::string_type s) : val(std::move(s)) {}
2633 JWT_CLAIM_EXPLICIT basic_claim(const date& d)
2634 : val(typename json_traits::integer_type(
2635 std::chrono::duration_cast<std::chrono::seconds>(d.time_since_epoch()).count())) {}
2636 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::array_type a) : val(std::move(a)) {}
2637 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::value_type v) : val(std::move(v)) {}
2638 JWT_CLAIM_EXPLICIT basic_claim(const set_t& s) : val(typename json_traits::array_type(s.begin(), s.end())) {}
2639 template<typename Iterator>
2640 basic_claim(Iterator begin, Iterator end) : val(typename json_traits::array_type(begin, end)) {}
2641
2646 typename json_traits::value_type to_json() const { return val; }
2647
2652 std::istream& operator>>(std::istream& is) {
2653 typename json_traits::string_type buffer{std::istreambuf_iterator<char>(is),
2654 std::istreambuf_iterator<char>()};
2655 json_traits::parse(val, buffer);
2656 return is;
2657 }
2658
2663 std::ostream& operator<<(std::ostream& os) { return os << json_traits::serialize(val); }
2664
2670 json::type get_type() const { return json_traits::get_type(val); }
2671
2677 typename json_traits::string_type as_string() const { return json_traits::as_string(val); }
2678
2687 date as_date() const {
2688 using std::chrono::system_clock;
2689 if (get_type() == json::type::number)
2690 return date(std::chrono::seconds(static_cast<int64_t>(std::llround(as_number()))));
2691 return date(std::chrono::seconds(as_integer()));
2692 }
2693
2699 typename json_traits::array_type as_array() const { return json_traits::as_array(val); }
2700
2706 set_t as_set() const {
2707 set_t res;
2708 for (const auto& e : json_traits::as_array(val)) {
2709 res.insert(json_traits::as_string(e));
2710 }
2711 return res;
2712 }
2713
2719 typename json_traits::integer_type as_integer() const { return json_traits::as_integer(val); }
2720
2726 typename json_traits::boolean_type as_boolean() const { return json_traits::as_boolean(val); }
2727
2733 typename json_traits::number_type as_number() const { return json_traits::as_number(val); }
2734 };
2735
2736 namespace error {
2740 struct invalid_json_exception : public std::runtime_error {
2741 invalid_json_exception() : runtime_error("invalid json") {}
2742 };
2743
2746 struct claim_not_present_exception : public std::out_of_range {
2747 claim_not_present_exception() : out_of_range("claim not found") {}
2748 };
2749 } // namespace error
2750
2751 namespace details {
2752 template<typename json_traits>
2753 struct map_of_claims {
2754 typename json_traits::object_type claims;
2755 using basic_claim_t = basic_claim<json_traits>;
2756 using iterator = typename json_traits::object_type::iterator;
2757 using const_iterator = typename json_traits::object_type::const_iterator;
2758
2759 map_of_claims() = default;
2760 map_of_claims(const map_of_claims&) = default;
2761 map_of_claims(map_of_claims&&) = default;
2762 map_of_claims& operator=(const map_of_claims&) = default;
2763 map_of_claims& operator=(map_of_claims&&) = default;
2764
2765 map_of_claims(typename json_traits::object_type json) : claims(std::move(json)) {}
2766
2767 iterator begin() { return claims.begin(); }
2768 iterator end() { return claims.end(); }
2769 const_iterator cbegin() const { return claims.begin(); }
2770 const_iterator cend() const { return claims.end(); }
2771 const_iterator begin() const { return claims.begin(); }
2772 const_iterator end() const { return claims.end(); }
2773
2782 static typename json_traits::object_type parse_claims(const typename json_traits::string_type& str) {
2783 typename json_traits::value_type val;
2784 if (!json_traits::parse(val, str)) throw error::invalid_json_exception();
2785
2786 return json_traits::as_object(val);
2787 };
2788
2793 bool has_claim(const typename json_traits::string_type& name) const noexcept {
2794 return claims.count(name) != 0;
2795 }
2796
2804 basic_claim_t get_claim(const typename json_traits::string_type& name) const {
2805 if (!has_claim(name)) throw error::claim_not_present_exception();
2806 return basic_claim_t{claims.at(name)};
2807 }
2808 };
2809 } // namespace details
2810
2815 template<typename json_traits>
2816 class payload {
2817 protected:
2818 details::map_of_claims<json_traits> payload_claims;
2819
2820 public:
2821 using basic_claim_t = basic_claim<json_traits>;
2822
2827 bool has_issuer() const noexcept { return has_payload_claim("iss"); }
2832 bool has_subject() const noexcept { return has_payload_claim("sub"); }
2837 bool has_audience() const noexcept { return has_payload_claim("aud"); }
2842 bool has_expires_at() const noexcept { return has_payload_claim("exp"); }
2847 bool has_not_before() const noexcept { return has_payload_claim("nbf"); }
2852 bool has_issued_at() const noexcept { return has_payload_claim("iat"); }
2857 bool has_id() const noexcept { return has_payload_claim("jti"); }
2864 typename json_traits::string_type get_issuer() const { return get_payload_claim("iss").as_string(); }
2871 typename json_traits::string_type get_subject() const { return get_payload_claim("sub").as_string(); }
2879 auto aud = get_payload_claim("aud");
2880 if (aud.get_type() == json::type::string) return {aud.as_string()};
2881
2882 return aud.as_set();
2883 }
2884
2890 date get_expires_at() const { return get_payload_claim("exp").as_date(); }
2897 date get_not_before() const { return get_payload_claim("nbf").as_date(); }
2904 date get_issued_at() const { return get_payload_claim("iat").as_date(); }
2911 typename json_traits::string_type get_id() const { return get_payload_claim("jti").as_string(); }
2916 bool has_payload_claim(const typename json_traits::string_type& name) const noexcept {
2917 return payload_claims.has_claim(name);
2918 }
2919
2924 basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const {
2925 return payload_claims.get_claim(name);
2926 }
2927 };
2928
2933 template<typename json_traits>
2934 class header {
2935 protected:
2936 details::map_of_claims<json_traits> header_claims;
2937
2938 public:
2939 using basic_claim_t = basic_claim<json_traits>;
2944 bool has_algorithm() const noexcept { return has_header_claim("alg"); }
2949 bool has_type() const noexcept { return has_header_claim("typ"); }
2954 bool has_content_type() const noexcept { return has_header_claim("cty"); }
2959 bool has_key_id() const noexcept { return has_header_claim("kid"); }
2966 typename json_traits::string_type get_algorithm() const { return get_header_claim("alg").as_string(); }
2973 typename json_traits::string_type get_type() const { return get_header_claim("typ").as_string(); }
2980 typename json_traits::string_type get_content_type() const { return get_header_claim("cty").as_string(); }
2987 typename json_traits::string_type get_key_id() const { return get_header_claim("kid").as_string(); }
2992 bool has_header_claim(const typename json_traits::string_type& name) const noexcept {
2993 return header_claims.has_claim(name);
2994 }
2995
3000 basic_claim_t get_header_claim(const typename json_traits::string_type& name) const {
3001 return header_claims.get_claim(name);
3002 }
3003 };
3004
3008 template<typename json_traits>
3009 class decoded_jwt : public header<json_traits>, public payload<json_traits> {
3010 protected:
3012 typename json_traits::string_type token;
3014 typename json_traits::string_type header;
3016 typename json_traits::string_type header_base64;
3018 typename json_traits::string_type payload;
3020 typename json_traits::string_type payload_base64;
3022 typename json_traits::string_type signature;
3024 typename json_traits::string_type signature_base64;
3025
3026 public:
3027 using basic_claim_t = basic_claim<json_traits>;
3028#ifndef JWT_DISABLE_BASE64
3038 JWT_CLAIM_EXPLICIT decoded_jwt(const typename json_traits::string_type& token)
3039 : decoded_jwt(token, [](const typename json_traits::string_type& str) {
3041 }) {}
3042#endif
3054 template<typename Decode>
3055 decoded_jwt(const typename json_traits::string_type& token, Decode decode) : token(token) {
3056 auto hdr_end = token.find('.');
3057 if (hdr_end == json_traits::string_type::npos) throw std::invalid_argument("invalid token supplied");
3058 auto payload_end = token.find('.', hdr_end + 1);
3059 if (payload_end == json_traits::string_type::npos) throw std::invalid_argument("invalid token supplied");
3060 header_base64 = token.substr(0, hdr_end);
3061 payload_base64 = token.substr(hdr_end + 1, payload_end - hdr_end - 1);
3062 signature_base64 = token.substr(payload_end + 1);
3063
3067
3068 this->header_claims = details::map_of_claims<json_traits>::parse_claims(header);
3069 this->payload_claims = details::map_of_claims<json_traits>::parse_claims(payload);
3070 }
3071
3076 const typename json_traits::string_type& get_token() const noexcept { return token; }
3081 const typename json_traits::string_type& get_header() const noexcept { return header; }
3086 const typename json_traits::string_type& get_payload() const noexcept { return payload; }
3091 const typename json_traits::string_type& get_signature() const noexcept { return signature; }
3096 const typename json_traits::string_type& get_header_base64() const noexcept { return header_base64; }
3101 const typename json_traits::string_type& get_payload_base64() const noexcept { return payload_base64; }
3106 const typename json_traits::string_type& get_signature_base64() const noexcept { return signature_base64; }
3111 typename json_traits::object_type get_payload_json() const { return this->payload_claims.claims; }
3116 typename json_traits::object_type get_header_json() const { return this->header_claims.claims; }
3124 basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const {
3125 return this->payload_claims.get_claim(name);
3126 }
3127
3134 basic_claim_t get_header_claim(const typename json_traits::string_type& name) const {
3135 return this->header_claims.get_claim(name);
3136 }
3137 };
3138
3143 template<typename Clock, typename json_traits>
3144 class builder {
3145 typename json_traits::object_type header_claims;
3146 typename json_traits::object_type payload_claims;
3147
3149 Clock clock;
3150
3151 public:
3156 JWT_CLAIM_EXPLICIT builder(Clock c) : clock(c) {}
3163 builder& set_header_claim(const typename json_traits::string_type& id, typename json_traits::value_type c) {
3164 header_claims[id] = std::move(c);
3165 return *this;
3166 }
3167
3174 builder& set_header_claim(const typename json_traits::string_type& id, basic_claim<json_traits> c) {
3175 header_claims[id] = c.to_json();
3176 return *this;
3177 }
3178
3184 builder& set_payload_claim(const typename json_traits::string_type& id, typename json_traits::value_type c) {
3185 payload_claims[id] = std::move(c);
3186 return *this;
3187 }
3188
3194 builder& set_payload_claim(const typename json_traits::string_type& id, basic_claim<json_traits> c) {
3195 payload_claims[id] = c.to_json();
3196 return *this;
3197 }
3198
3205 builder& set_algorithm(typename json_traits::string_type str) {
3206 return set_header_claim("alg", typename json_traits::value_type(str));
3207 }
3208
3213 builder& set_type(typename json_traits::string_type str) {
3214 return set_header_claim("typ", typename json_traits::value_type(str));
3215 }
3216
3221 builder& set_content_type(typename json_traits::string_type str) {
3222 return set_header_claim("cty", typename json_traits::value_type(str));
3223 }
3224
3230 builder& set_key_id(typename json_traits::string_type str) {
3231 return set_header_claim("kid", typename json_traits::value_type(str));
3232 }
3233
3238 builder& set_issuer(typename json_traits::string_type str) {
3239 return set_payload_claim("iss", typename json_traits::value_type(str));
3240 }
3241
3246 builder& set_subject(typename json_traits::string_type str) {
3247 return set_payload_claim("sub", typename json_traits::value_type(str));
3248 }
3249
3254 builder& set_audience(typename json_traits::array_type a) {
3255 return set_payload_claim("aud", typename json_traits::value_type(a));
3256 }
3257
3262 builder& set_audience(typename json_traits::string_type aud) {
3263 return set_payload_claim("aud", typename json_traits::value_type(aud));
3264 }
3265
3276 template<class Rep, class Period>
3277 builder& set_expires_in(const std::chrono::duration<Rep, Period>& d) {
3278 return set_payload_claim("exp", basic_claim<json_traits>(clock.now() + d));
3279 }
3280
3296 builder& set_issued_now() { return set_issued_at(clock.now()); }
3302 builder& set_id(const typename json_traits::string_type& str) {
3303 return set_payload_claim("jti", typename json_traits::value_type(str));
3304 }
3305
3317 template<typename Algo, typename Encode>
3318 typename json_traits::string_type sign(const Algo& algo, Encode encode) const {
3319 std::error_code ec;
3320 auto res = sign(algo, encode, ec);
3322 return res;
3323 }
3324#ifndef JWT_DISABLE_BASE64
3333 template<typename Algo>
3334 typename json_traits::string_type sign(const Algo& algo) const {
3335 std::error_code ec;
3336 auto res = sign(algo, ec);
3338 return res;
3339 }
3340#endif
3341
3354 template<typename Algo, typename Encode>
3355 typename json_traits::string_type sign(const Algo& algo, Encode encode, std::error_code& ec) const {
3356 // make a copy such that a builder can be re-used
3357 typename json_traits::object_type obj_header = header_claims;
3358 if (header_claims.count("alg") == 0) obj_header["alg"] = typename json_traits::value_type(algo.name());
3359
3360 const auto header = encode(json_traits::serialize(typename json_traits::value_type(obj_header)));
3361 const auto payload = encode(json_traits::serialize(typename json_traits::value_type(payload_claims)));
3362 const auto token = header + "." + payload;
3363
3364 auto signature = algo.sign(token, ec);
3365 if (ec) return {};
3366
3367 return token + "." + encode(signature);
3368 }
3369#ifndef JWT_DISABLE_BASE64
3379 template<typename Algo>
3380 typename json_traits::string_type sign(const Algo& algo, std::error_code& ec) const {
3381 return sign(
3382 algo,
3383 [](const typename json_traits::string_type& data) {
3385 },
3386 ec);
3387 }
3388#endif
3389 };
3390
3391 namespace verify_ops {
3395 template<typename json_traits>
3396 struct verify_context {
3397 verify_context(date ctime, const decoded_jwt<json_traits>& j, size_t l)
3398 : current_time(ctime), jwt(j), default_leeway(l) {}
3405
3407 typename json_traits::string_type claim_key{};
3408
3415 basic_claim<json_traits> get_claim(bool in_header, std::error_code& ec) const {
3416 if (in_header) {
3417 if (!jwt.has_header_claim(claim_key)) {
3418 ec = error::token_verification_error::missing_claim;
3419 return {};
3420 }
3421 return jwt.get_header_claim(claim_key);
3422 } else {
3423 if (!jwt.has_payload_claim(claim_key)) {
3424 ec = error::token_verification_error::missing_claim;
3425 return {};
3426 }
3427 return jwt.get_payload_claim(claim_key);
3428 }
3429 }
3430
3437 basic_claim<json_traits> get_claim(bool in_header, json::type t, std::error_code& ec) const {
3438 auto c = get_claim(in_header, ec);
3439 if (ec) return {};
3440 if (c.get_type() != t) {
3441 ec = error::token_verification_error::claim_type_missmatch;
3442 return {};
3443 }
3444 return c;
3445 }
3446
3451 basic_claim<json_traits> get_claim(std::error_code& ec) const { return get_claim(false, ec); }
3458 basic_claim<json_traits> get_claim(json::type t, std::error_code& ec) const {
3459 return get_claim(false, t, ec);
3460 }
3461 };
3462
3466 template<typename json_traits, bool in_header = false>
3468 const basic_claim<json_traits> expected;
3469 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3470 auto jc = ctx.get_claim(in_header, expected.get_type(), ec);
3471 if (ec) return;
3472 const bool matches = [&]() {
3473 switch (expected.get_type()) {
3474 case json::type::boolean: return expected.as_boolean() == jc.as_boolean();
3475 case json::type::integer: return expected.as_integer() == jc.as_integer();
3476 case json::type::number: return expected.as_number() == jc.as_number();
3477 case json::type::string: return expected.as_string() == jc.as_string();
3478 case json::type::array:
3479 case json::type::object:
3480 return json_traits::serialize(expected.to_json()) == json_traits::serialize(jc.to_json());
3481 default: throw std::logic_error("internal error, should be unreachable");
3482 }
3483 }();
3484 if (!matches) {
3485 ec = error::token_verification_error::claim_value_missmatch;
3486 return;
3487 }
3488 }
3489 };
3490
3495 template<typename json_traits, bool in_header = false>
3497 const size_t leeway;
3498 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3499 auto jc = ctx.get_claim(in_header, json::type::integer, ec);
3500 if (ec) return;
3501 auto c = jc.as_date();
3502 if (ctx.current_time > c + std::chrono::seconds(leeway)) {
3503 ec = error::token_verification_error::token_expired;
3504 }
3505 }
3506 };
3507
3512 template<typename json_traits, bool in_header = false>
3514 const size_t leeway;
3515 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3516 auto jc = ctx.get_claim(in_header, json::type::integer, ec);
3517 if (ec) return;
3518 auto c = jc.as_date();
3519 if (ctx.current_time < c - std::chrono::seconds(leeway)) {
3520 ec = error::token_verification_error::token_expired;
3521 }
3522 }
3523 };
3524
3530 template<typename json_traits, bool in_header = false>
3532 const typename basic_claim<json_traits>::set_t expected;
3533 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3534 auto c = ctx.get_claim(in_header, ec);
3535 if (ec) return;
3536 if (c.get_type() == json::type::string) {
3537 if (expected.size() != 1 || *expected.begin() != c.as_string()) {
3538 ec = error::token_verification_error::audience_missmatch;
3539 return;
3540 }
3541 } else if (c.get_type() == json::type::array) {
3542 auto jc = c.as_set();
3543 for (auto& e : expected) {
3544 if (jc.find(e) == jc.end()) {
3545 ec = error::token_verification_error::audience_missmatch;
3546 return;
3547 }
3548 }
3549 } else {
3550 ec = error::token_verification_error::claim_type_missmatch;
3551 return;
3552 }
3553 }
3554 };
3555
3559 template<typename json_traits, bool in_header = false>
3560 struct insensitive_string_claim {
3561 const typename json_traits::string_type expected;
3562 std::locale locale;
3563 insensitive_string_claim(const typename json_traits::string_type& e, std::locale loc)
3564 : expected(to_lower_unicode(e, loc)), locale(loc) {}
3565
3566 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3567 const auto c = ctx.get_claim(in_header, json::type::string, ec);
3568 if (ec) return;
3569 if (to_lower_unicode(c.as_string(), locale) != expected) {
3570 ec = error::token_verification_error::claim_value_missmatch;
3571 }
3572 }
3573
3574 static std::string to_lower_unicode(const std::string& str, const std::locale& loc) {
3575 std::mbstate_t state = std::mbstate_t();
3576 const char* in_next = str.data();
3577 const char* in_end = str.data() + str.size();
3578 std::wstring wide;
3579 wide.reserve(str.size());
3580
3581 while (in_next != in_end) {
3582 wchar_t wc;
3583 std::size_t result = std::mbrtowc(&wc, in_next, in_end - in_next, &state);
3584 if (result == static_cast<std::size_t>(-1)) {
3585 throw std::runtime_error("encoding error: " + std::string(std::strerror(errno)));
3586 } else if (result == static_cast<std::size_t>(-2)) {
3587 throw std::runtime_error("conversion error: next bytes constitute an incomplete, but so far "
3588 "valid, multibyte character.");
3589 }
3590 in_next += result;
3591 wide.push_back(wc);
3592 }
3593
3594 auto& f = std::use_facet<std::ctype<wchar_t>>(loc);
3595 f.tolower(&wide[0], &wide[0] + wide.size());
3596
3597 std::string out;
3598 out.reserve(wide.size());
3599 for (wchar_t wc : wide) {
3600 char mb[MB_LEN_MAX];
3601 std::size_t n = std::wcrtomb(mb, wc, &state);
3602 if (n != static_cast<std::size_t>(-1)) out.append(mb, n);
3603 }
3604
3605 return out;
3606 }
3607 };
3608 } // namespace verify_ops
3609
3614 template<typename Clock, typename json_traits>
3615 class verifier {
3616 public:
3617 using basic_claim_t = basic_claim<json_traits>;
3628 std::function<void(const verify_ops::verify_context<json_traits>&, std::error_code& ec)>;
3629
3630 private:
3631 struct algo_base {
3632 virtual ~algo_base() = default;
3633 virtual void verify(const std::string& data, const std::string& sig, std::error_code& ec) = 0;
3634 };
3635 template<typename T>
3636 struct algo : public algo_base {
3637 T alg;
3638 explicit algo(T a) : alg(a) {}
3639 void verify(const std::string& data, const std::string& sig, std::error_code& ec) override {
3640 alg.verify(data, sig, ec);
3641 }
3642 };
3644 std::unordered_map<typename json_traits::string_type, verify_check_fn_t> claims;
3646 size_t default_leeway = 0;
3648 Clock clock;
3650 std::unordered_map<std::string, std::shared_ptr<algo_base>> algs;
3651
3652 public:
3657 explicit verifier(Clock c) : clock(c) {
3658 claims["exp"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
3659 if (!ctx.jwt.has_expires_at()) return;
3660 auto exp = ctx.jwt.get_expires_at();
3661 if (ctx.current_time > exp + std::chrono::seconds(ctx.default_leeway)) {
3662 ec = error::token_verification_error::token_expired;
3663 }
3664 };
3665 claims["iat"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
3666 if (!ctx.jwt.has_issued_at()) return;
3667 auto iat = ctx.jwt.get_issued_at();
3668 if (ctx.current_time < iat - std::chrono::seconds(ctx.default_leeway)) {
3669 ec = error::token_verification_error::token_expired;
3670 }
3671 };
3672 claims["nbf"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
3673 if (!ctx.jwt.has_not_before()) return;
3674 auto nbf = ctx.jwt.get_not_before();
3675 if (ctx.current_time < nbf - std::chrono::seconds(ctx.default_leeway)) {
3676 ec = error::token_verification_error::token_expired;
3677 }
3678 };
3679 }
3680
3687 default_leeway = leeway;
3688 return *this;
3689 }
3690
3698 return *this;
3699 }
3700
3708 return *this;
3709 }
3710
3718 return *this;
3719 }
3720
3732 verifier& with_type(const typename json_traits::string_type& type, std::locale locale = std::locale{}) {
3733 return with_claim("typ", verify_ops::insensitive_string_claim<json_traits, true>{type, std::move(locale)});
3734 }
3735
3742 verifier& with_issuer(const typename json_traits::string_type& iss) {
3743 return with_claim("iss", basic_claim_t(iss));
3744 }
3745
3752 verifier& with_subject(const typename json_traits::string_type& sub) {
3753 return with_claim("sub", basic_claim_t(sub));
3754 }
3755
3762 claims["aud"] = verify_ops::is_subset_claim<json_traits>{aud};
3763 return *this;
3764 }
3765
3771 verifier& with_audience(const typename json_traits::string_type& aud) {
3772 typename basic_claim_t::set_t s;
3773 s.insert(aud);
3774 return with_audience(s);
3775 }
3776
3782 verifier& with_id(const typename json_traits::string_type& id) { return with_claim("jti", basic_claim_t(id)); }
3783
3795 verifier& with_claim(const typename json_traits::string_type& name, verify_check_fn_t fn) {
3796 claims[name] = fn;
3797 return *this;
3798 }
3799
3810 verifier& with_claim(const typename json_traits::string_type& name, basic_claim_t c) {
3812 }
3813
3827 template<typename Algorithm>
3828 verifier& allow_algorithm(Algorithm alg) {
3829 algs[alg.name()] = std::make_shared<algo<Algorithm>>(alg);
3830 return *this;
3831 }
3832
3839 std::error_code ec;
3840 verify(jwt, ec);
3842 }
3843
3848 void verify(const decoded_jwt<json_traits>& jwt, std::error_code& ec) const {
3849 ec.clear();
3850 const typename json_traits::string_type data = jwt.get_header_base64() + "." + jwt.get_payload_base64();
3851 const typename json_traits::string_type sig = jwt.get_signature();
3852 const std::string algo = jwt.get_algorithm();
3853 if (algs.count(algo) == 0) {
3854 ec = error::token_verification_error::wrong_algorithm;
3855 return;
3856 }
3857 algs.at(algo)->verify(data, sig, ec);
3858 if (ec) return;
3859
3860 verify_ops::verify_context<json_traits> ctx{clock.now(), jwt, default_leeway};
3861 for (auto& c : claims) {
3862 ctx.claim_key = c.first;
3863 c.second(ctx, ec);
3864 if (ec) return;
3865 }
3866 }
3867 };
3868
3877 template<typename json_traits>
3878 class jwk {
3879 using basic_claim_t = basic_claim<json_traits>;
3880 const details::map_of_claims<json_traits> jwk_claims;
3881
3882 public:
3883 JWT_CLAIM_EXPLICIT jwk(const typename json_traits::string_type& str)
3884 : jwk_claims(details::map_of_claims<json_traits>::parse_claims(str)) {}
3885
3886 JWT_CLAIM_EXPLICIT jwk(const typename json_traits::value_type& json)
3887 : jwk_claims(json_traits::as_object(json)) {}
3888
3897 typename json_traits::string_type get_key_type() const { return get_jwk_claim("kty").as_string(); }
3898
3905 typename json_traits::string_type get_use() const { return get_jwk_claim("use").as_string(); }
3906
3913 typename basic_claim_t::set_t get_key_operations() const { return get_jwk_claim("key_ops").as_set(); }
3914
3921 typename json_traits::string_type get_algorithm() const { return get_jwk_claim("alg").as_string(); }
3922
3929 typename json_traits::string_type get_key_id() const { return get_jwk_claim("kid").as_string(); }
3930
3941 typename json_traits::string_type get_curve() const { return get_jwk_claim("crv").as_string(); }
3942
3949 typename json_traits::array_type get_x5c() const { return get_jwk_claim("x5c").as_array(); };
3950
3957 typename json_traits::string_type get_x5u() const { return get_jwk_claim("x5u").as_string(); };
3958
3965 typename json_traits::string_type get_x5t() const { return get_jwk_claim("x5t").as_string(); };
3966
3973 typename json_traits::string_type get_x5t_sha256() const { return get_jwk_claim("x5t#S256").as_string(); };
3974
3981 typename json_traits::string_type get_x5c_key_value() const {
3982 auto x5c_array = get_jwk_claim("x5c").as_array();
3983 if (x5c_array.size() == 0) throw error::claim_not_present_exception();
3984
3985 return json_traits::as_string(x5c_array.front());
3986 };
3987
3992 bool has_key_type() const noexcept { return has_jwk_claim("kty"); }
3993
3998 bool has_use() const noexcept { return has_jwk_claim("use"); }
3999
4004 bool has_key_operations() const noexcept { return has_jwk_claim("key_ops"); }
4005
4010 bool has_algorithm() const noexcept { return has_jwk_claim("alg"); }
4011
4016 bool has_curve() const noexcept { return has_jwk_claim("crv"); }
4017
4022 bool has_key_id() const noexcept { return has_jwk_claim("kid"); }
4023
4028 bool has_x5u() const noexcept { return has_jwk_claim("x5u"); }
4029
4034 bool has_x5c() const noexcept { return has_jwk_claim("x5c"); }
4035
4040 bool has_x5t() const noexcept { return has_jwk_claim("x5t"); }
4041
4046 bool has_x5t_sha256() const noexcept { return has_jwk_claim("x5t#S256"); }
4047
4052 bool has_jwk_claim(const typename json_traits::string_type& name) const noexcept {
4053 return jwk_claims.has_claim(name);
4054 }
4055
4061 basic_claim_t get_jwk_claim(const typename json_traits::string_type& name) const {
4062 return jwk_claims.get_claim(name);
4063 }
4064
4069 bool empty() const noexcept { return jwk_claims.empty(); }
4070
4075 typename json_traits::object_type get_claims() const { return this->jwk_claims.claims; }
4076 };
4077
4088 template<typename json_traits>
4089 class jwks {
4090 public:
4094 using jwks_vector_t = std::vector<jwks_t>;
4095 using iterator = typename jwks_vector_t::iterator;
4096 using const_iterator = typename jwks_vector_t::const_iterator;
4097
4101 jwks() = default;
4102
4109 JWT_CLAIM_EXPLICIT jwks(const typename json_traits::string_type& str) {
4110 typename json_traits::value_type parsed_val;
4111 if (!json_traits::parse(parsed_val, str)) throw error::invalid_json_exception();
4112
4113 const details::map_of_claims<json_traits> jwks_json = json_traits::as_object(parsed_val);
4114 if (!jwks_json.has_claim("keys")) throw error::invalid_json_exception();
4115
4116 auto jwk_list = jwks_json.get_claim("keys").as_array();
4117 std::transform(jwk_list.begin(), jwk_list.end(), std::back_inserter(jwk_claims),
4118 [](const typename json_traits::value_type& val) { return jwks_t{val}; });
4119 }
4120
4121 iterator begin() { return jwk_claims.begin(); }
4122 iterator end() { return jwk_claims.end(); }
4123 const_iterator cbegin() const { return jwk_claims.begin(); }
4124 const_iterator cend() const { return jwk_claims.end(); }
4125 const_iterator begin() const { return jwk_claims.begin(); }
4126 const_iterator end() const { return jwk_claims.end(); }
4127
4132 bool has_jwk(const typename json_traits::string_type& key_id) const noexcept {
4133 return find_by_kid(key_id) != end();
4134 }
4135
4141 jwks_t get_jwk(const typename json_traits::string_type& key_id) const {
4142 const auto maybe = find_by_kid(key_id);
4143 if (maybe == end()) throw error::claim_not_present_exception();
4144 return *maybe;
4145 }
4146
4147 private:
4148 jwks_vector_t jwk_claims;
4149
4150 const_iterator find_by_kid(const typename json_traits::string_type& key_id) const noexcept {
4151 return std::find_if(cbegin(), cend(), [key_id](const jwks_t& jwk) {
4152 if (!jwk.has_key_id()) { return false; }
4153 return jwk.get_key_id() == key_id;
4154 });
4155 }
4156 };
4157
4163 template<typename Clock, typename json_traits>
4167
4173 template<typename Clock, typename json_traits>
4177
4186 date now() const { return date::clock::now(); }
4187 };
4188
4197 template<typename json_traits>
4199 return verifier<default_clock, json_traits>(c);
4200 }
4201
4205 template<typename json_traits>
4207 return builder<default_clock, json_traits>(c);
4208 }
4209
4224 template<typename json_traits, typename Decode>
4225 decoded_jwt<json_traits> decode(const typename json_traits::string_type& token, Decode decode) {
4226 return decoded_jwt<json_traits>(token, decode);
4227 }
4228
4239 template<typename json_traits>
4240 decoded_jwt<json_traits> decode(const typename json_traits::string_type& token) {
4241 return decoded_jwt<json_traits>(token);
4242 }
4243
4249 template<typename json_traits>
4250 jwk<json_traits> parse_jwk(const typename json_traits::string_type& jwk_) {
4251 return jwk<json_traits>(jwk_);
4252 }
4253
4263 template<typename json_traits>
4264 jwks<json_traits> parse_jwks(const typename json_traits::string_type& jwks_) {
4265 return jwks<json_traits>(jwks_);
4266 }
4267} // namespace jwt
4268
4269template<typename json_traits>
4270std::istream& operator>>(std::istream& is, jwt::basic_claim<json_traits>& c) {
4271 return c.operator>>(is);
4272}
4273
4274template<typename json_traits>
4275std::ostream& operator<<(std::ostream& os, const jwt::basic_claim<json_traits>& c) {
4276 return os << c.to_json();
4277}
4278
4279#ifndef JWT_DISABLE_PICOJSON
4280#include "traits/kazuho-picojson/defaults.h"
4281#endif
4282
4283#endif
a class to store a generic JSON value as claim
Definition jwt.h:2597
json_traits::number_type as_number() const
Definition jwt.h:2733
set_t as_set() const
Definition jwt.h:2706
json::type get_type() const
Definition jwt.h:2670
std::set< typename json_traits::string_type > set_t
Definition jwt.h:2623
std::istream & operator>>(std::istream &is)
Definition jwt.h:2652
json_traits::boolean_type as_boolean() const
Definition jwt.h:2726
date as_date() const
Get the contained JSON value as a date.
Definition jwt.h:2687
std::ostream & operator<<(std::ostream &os)
Definition jwt.h:2663
json_traits::integer_type as_integer() const
Definition jwt.h:2719
json_traits::value_type to_json() const
Definition jwt.h:2646
json_traits::array_type as_array() const
Definition jwt.h:2699
json_traits::string_type as_string() const
Definition jwt.h:2677
Definition jwt.h:3144
builder & set_audience(typename json_traits::string_type aud)
Definition jwt.h:3262
builder & set_payload_claim(const typename json_traits::string_type &id, basic_claim< json_traits > c)
Definition jwt.h:3194
builder & set_algorithm(typename json_traits::string_type str)
Set algorithm claim You normally don't need to do this, as the algorithm is automatically set if you ...
Definition jwt.h:3205
builder & set_expires_at(const date &d)
Definition jwt.h:3270
builder & set_expires_in(const std::chrono::duration< Rep, Period > &d)
Definition jwt.h:3277
builder & set_type(typename json_traits::string_type str)
Definition jwt.h:3213
JWT_CLAIM_EXPLICIT builder(Clock c)
Definition jwt.h:3156
json_traits::string_type sign(const Algo &algo, std::error_code &ec) const
Definition jwt.h:3380
builder & set_issued_at(const date &d)
Definition jwt.h:3291
json_traits::string_type sign(const Algo &algo) const
Definition jwt.h:3334
builder & set_payload_claim(const typename json_traits::string_type &id, typename json_traits::value_type c)
Definition jwt.h:3184
builder & set_id(const typename json_traits::string_type &str)
Definition jwt.h:3302
builder & set_header_claim(const typename json_traits::string_type &id, typename json_traits::value_type c)
Definition jwt.h:3163
builder & set_header_claim(const typename json_traits::string_type &id, basic_claim< json_traits > c)
Definition jwt.h:3174
json_traits::string_type sign(const Algo &algo, Encode encode) const
Definition jwt.h:3318
builder & set_audience(typename json_traits::array_type a)
Definition jwt.h:3254
json_traits::string_type sign(const Algo &algo, Encode encode, std::error_code &ec) const
Definition jwt.h:3355
builder & set_content_type(typename json_traits::string_type str)
Definition jwt.h:3221
builder & set_not_before(const date &d)
Definition jwt.h:3285
builder & set_subject(typename json_traits::string_type str)
Definition jwt.h:3246
builder & set_issued_now()
Definition jwt.h:3296
builder & set_key_id(typename json_traits::string_type str)
Set key id claim.
Definition jwt.h:3230
builder & set_issuer(typename json_traits::string_type str)
Definition jwt.h:3238
Definition jwt.h:3009
const json_traits::string_type & get_header() const noexcept
Definition jwt.h:3081
const json_traits::string_type & get_signature_base64() const noexcept
Definition jwt.h:3106
json_traits::string_type signature
Signature part decoded from base64.
Definition jwt.h:3022
json_traits::string_type header
Header part decoded from base64.
Definition jwt.h:3014
json_traits::string_type header_base64
Unmodified header part in base64.
Definition jwt.h:3016
json_traits::string_type token
Unmodified token, as passed to constructor.
Definition jwt.h:3012
basic_claim_t get_payload_claim(const typename json_traits::string_type &name) const
Definition jwt.h:3124
const json_traits::string_type & get_signature() const noexcept
Definition jwt.h:3091
JWT_CLAIM_EXPLICIT decoded_jwt(const typename json_traits::string_type &token)
Parses a given token.
Definition jwt.h:3038
basic_claim_t get_header_claim(const typename json_traits::string_type &name) const
Definition jwt.h:3134
decoded_jwt(const typename json_traits::string_type &token, Decode decode)
Parses a given token.
Definition jwt.h:3055
json_traits::object_type get_payload_json() const
Definition jwt.h:3111
json_traits::string_type signature_base64
Unmodified signature part in base64.
Definition jwt.h:3024
const json_traits::string_type & get_payload_base64() const noexcept
Definition jwt.h:3101
const json_traits::string_type & get_token() const noexcept
Definition jwt.h:3076
json_traits::object_type get_header_json() const
Definition jwt.h:3116
const json_traits::string_type & get_payload() const noexcept
Definition jwt.h:3086
const json_traits::string_type & get_header_base64() const noexcept
Definition jwt.h:3096
json_traits::string_type payload_base64
Unmodified payload part in base64.
Definition jwt.h:3020
json_traits::string_type payload
Payload part decoded from base64.
Definition jwt.h:3018
Definition jwt.h:2934
json_traits::string_type get_type() const
Definition jwt.h:2973
bool has_header_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:2992
bool has_algorithm() const noexcept
Definition jwt.h:2944
bool has_type() const noexcept
Definition jwt.h:2949
json_traits::string_type get_algorithm() const
Definition jwt.h:2966
bool has_content_type() const noexcept
Definition jwt.h:2954
basic_claim_t get_header_claim(const typename json_traits::string_type &name) const
Definition jwt.h:3000
json_traits::string_type get_key_id() const
Definition jwt.h:2987
json_traits::string_type get_content_type() const
Definition jwt.h:2980
bool has_key_id() const noexcept
Definition jwt.h:2959
Handle class for EVP_PKEY structures.
Definition jwt.h:427
constexpr evp_pkey_handle() noexcept=default
Creates a null key pointer.
constexpr evp_pkey_handle(EVP_PKEY *key) noexcept
Construct a new handle. The handle takes ownership of the key.
Definition jwt.h:451
JSON Web Key.
Definition jwt.h:3878
bool has_x5c() const noexcept
Definition jwt.h:4034
json_traits::string_type get_curve() const
Get curve claim.
Definition jwt.h:3941
bool has_x5t_sha256() const noexcept
Definition jwt.h:4046
json_traits::string_type get_algorithm() const
Definition jwt.h:3921
json_traits::array_type get_x5c() const
Definition jwt.h:3949
json_traits::object_type get_claims() const
Definition jwt.h:4075
json_traits::string_type get_x5t() const
Definition jwt.h:3965
json_traits::string_type get_x5c_key_value() const
Definition jwt.h:3981
json_traits::string_type get_x5t_sha256() const
Definition jwt.h:3973
json_traits::string_type get_key_id() const
Definition jwt.h:3929
bool has_algorithm() const noexcept
Definition jwt.h:4010
json_traits::string_type get_use() const
Definition jwt.h:3905
bool has_key_id() const noexcept
Definition jwt.h:4022
bool has_x5u() const noexcept
Definition jwt.h:4028
bool has_key_operations() const noexcept
Definition jwt.h:4004
bool empty() const noexcept
Definition jwt.h:4069
bool has_use() const noexcept
Definition jwt.h:3998
bool has_x5t() const noexcept
Definition jwt.h:4040
bool has_jwk_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:4052
basic_claim_t::set_t get_key_operations() const
Definition jwt.h:3913
bool has_curve() const noexcept
Definition jwt.h:4016
bool has_key_type() const noexcept
Definition jwt.h:3992
basic_claim_t get_jwk_claim(const typename json_traits::string_type &name) const
Definition jwt.h:4061
json_traits::string_type get_x5u() const
Definition jwt.h:3957
json_traits::string_type get_key_type() const
Definition jwt.h:3897
JWK Set.
Definition jwt.h:4089
jwk< json_traits > jwks_t
JWK instance template specialization.
Definition jwt.h:4092
jwks_t get_jwk(const typename json_traits::string_type &key_id) const
Definition jwt.h:4141
jwks()=default
std::vector< jwks_t > jwks_vector_t
Type specialization for the vector of JWK.
Definition jwt.h:4094
JWT_CLAIM_EXPLICIT jwks(const typename json_traits::string_type &str)
Definition jwt.h:4109
bool has_jwk(const typename json_traits::string_type &key_id) const noexcept
Definition jwt.h:4132
Definition jwt.h:2816
basic_claim_t::set_t get_audience() const
Definition jwt.h:2878
json_traits::string_type get_id() const
Definition jwt.h:2911
bool has_issued_at() const noexcept
Definition jwt.h:2852
bool has_not_before() const noexcept
Definition jwt.h:2847
bool has_payload_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:2916
bool has_subject() const noexcept
Definition jwt.h:2832
date get_not_before() const
Definition jwt.h:2897
bool has_issuer() const noexcept
Definition jwt.h:2827
bool has_id() const noexcept
Definition jwt.h:2857
bool has_expires_at() const noexcept
Definition jwt.h:2842
date get_issued_at() const
Definition jwt.h:2904
basic_claim_t get_payload_claim(const typename json_traits::string_type &name) const
Definition jwt.h:2924
bool has_audience() const noexcept
Definition jwt.h:2837
date get_expires_at() const
Definition jwt.h:2890
json_traits::string_type get_subject() const
Definition jwt.h:2871
json_traits::string_type get_issuer() const
Definition jwt.h:2864
Definition jwt.h:3615
verifier & expires_at_leeway(size_t leeway)
Definition jwt.h:3696
verifier & with_claim(const typename json_traits::string_type &name, verify_check_fn_t fn)
Definition jwt.h:3795
void verify(const decoded_jwt< json_traits > &jwt, std::error_code &ec) const
Definition jwt.h:3848
std::function< void(const verify_ops::verify_context< json_traits > &, std::error_code &ec)> verify_check_fn_t
Verification function data structure.
Definition jwt.h:3627
verifier & not_before_leeway(size_t leeway)
Definition jwt.h:3706
verifier & issued_at_leeway(size_t leeway)
Definition jwt.h:3716
verifier & with_subject(const typename json_traits::string_type &sub)
Definition jwt.h:3752
verifier & with_audience(const typename basic_claim_t::set_t &aud)
Definition jwt.h:3761
verifier & with_claim(const typename json_traits::string_type &name, basic_claim_t c)
Definition jwt.h:3810
verifier & with_audience(const typename json_traits::string_type &aud)
Definition jwt.h:3771
void verify(const decoded_jwt< json_traits > &jwt) const
Definition jwt.h:3838
verifier(Clock c)
Definition jwt.h:3657
verifier & leeway(size_t leeway)
Definition jwt.h:3686
verifier & with_issuer(const typename json_traits::string_type &iss)
Definition jwt.h:3742
verifier & allow_algorithm(Algorithm alg)
Add an algorithm available for checking.
Definition jwt.h:3828
verifier & with_type(const typename json_traits::string_type &type, std::locale locale=std::locale{})
Definition jwt.h:3732
verifier & with_id(const typename json_traits::string_type &id)
Definition jwt.h:3782
Various cryptographic algorithms when working with JWT.
Definition jwt.h:1351
std::string trim(const std::string &base)
Generic base64 trimming.
Definition base.h:350
std::string decode(const std::string &base)
Generic base64 decoding.
Definition base.h:322
std::string pad(const std::string &base)
Generic base64 padding.
Definition base.h:336
std::string encode(const std::string &bin)
Generic base64 encoding.
Definition base.h:308
Everything related to error codes issued by the library.
Definition jwt.h:93
signature_verification_error
Errors related to verification of signatures.
Definition jwt.h:218
std::error_category & token_verification_error_category()
Error category for token verification errors.
Definition jwt.h:353
void throw_if_error(std::error_code ec)
Raises an exception if any JWT-CPP error codes are active.
Definition jwt.h:385
std::error_category & ecdsa_error_category()
Error category for ECDSA errors.
Definition jwt.h:181
std::error_category & signature_verification_error_category()
Error category for verification errors.
Definition jwt.h:232
std::error_category & rsa_error_category()
Error category for RSA errors.
Definition jwt.h:129
std::error_category & signature_generation_error_category()
Error category for signature generation errors.
Definition jwt.h:291
ecdsa_error
Errors related to processing of RSA signatures.
Definition jwt.h:161
rsa_error
Errors related to processing of RSA signatures.
Definition jwt.h:112
signature_generation_error
Errors related to signature generation errors.
Definition jwt.h:271
token_verification_error
Errors related to token verification errors.
Definition jwt.h:341
std::error_code make_error_code(rsa_error e)
Converts JWT-CPP errors into generic STL error_codes.
Definition jwt.h:157
A collection for working with certificates.
Definition jwt.h:419
std::string extract_pubkey_from_cert(const std::string &certstr, const std::string &pw, std::error_code &ec)
Extract the public key of a pem certificate.
Definition jwt.h:544
evp_pkey_handle load_public_ec_key_from_string(const std::string &key, const std::string &password, std::error_code &ec)
Load a public key from a string.
Definition jwt.h:830
evp_pkey_handle load_public_key_from_string(const std::string &key, const std::string &password, std::error_code &ec)
Load a public key from a string.
Definition jwt.h:716
std::string create_public_key_from_rsa_components(const std::string &modulus, const std::string &exponent, Decode decode, std::error_code &ec)
create public key from modulus and exponent. This is defined in RFC 7518 Section 6....
Definition jwt.h:929
std::unique_ptr< BIGNUM, decltype(&BN_free)> raw2bn(const std::string &raw, std::error_code &ec)
Definition jwt.h:859
evp_pkey_handle load_private_ec_key_from_string(const std::string &key, const std::string &password, std::error_code &ec)
Load a private key from a string.
Definition jwt.h:909
int curve2nid(const std::string curve, std::error_code &ec)
Convert a curve name to an ID.
Definition jwt.h:1136
std::string convert_base64_der_to_pem(const std::string &cert_base64_der_str, Decode decode, std::error_code &ec)
Convert the certificate provided as base64 DER to PEM.
Definition jwt.h:630
std::string bn2raw(const BIGNUM *bn)
Definition jwt.h:846
std::string create_public_key_from_ec_components(const std::string &curve, const std::string &x, const std::string &y, Decode decode, std::error_code &ec)
Definition jwt.h:1167
evp_pkey_handle load_private_key_from_string(const std::string &key, const std::string &password, std::error_code &ec)
Load a private key from a string.
Definition jwt.h:784
std::string convert_der_to_pem(const std::string &cert_der_str, std::error_code &ec)
Convert the certificate provided as DER to PEM.
Definition jwt.h:594
JSON Abstractions for working with any library.
Definition jwt.h:2306
type
Categories for the various JSON types used in JWTs.
Definition jwt.h:2314
JSON Web Token.
Definition base.h:21
verifier< Clock, json_traits > verify(Clock c)
Definition jwt.h:4164
verify_ops::verify_context< traits::boost_json > verify_context
Definition defaults.h:88
std::chrono::system_clock::time_point date
Definition jwt.h:88
builder< Clock, json_traits > create(Clock c)
Definition jwt.h:4174
jwk< json_traits > parse_jwk(const typename json_traits::string_type &jwk_)
Definition jwt.h:4250
jwks< json_traits > parse_jwks(const typename json_traits::string_type &jwks_)
Definition jwt.h:4264
verifier< default_clock, traits::boost_json > verify()
Definition defaults.h:23
decoded_jwt< json_traits > decode(const typename json_traits::string_type &token, Decode decode)
Decode a token. This can be used to to help access important feild like 'x5c' for verifying tokens....
Definition jwt.h:4225
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1655
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1618
ecdsa(const std::string &public_key, const std::string &private_key, const std::string &public_key_password, const std::string &private_key_password, const EVP_MD *(*md)(), std::string name, size_t siglen)
Definition jwt.h:1577
ecdsa(helper::evp_pkey_handle key_pair, const EVP_MD *(*md)(), std::string name, size_t siglen)
Definition jwt.h:1604
std::string name() const
Definition jwt.h:1694
ed25519(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2226
ed448(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2249
std::string name() const
Definition jwt.h:1925
eddsa(const std::string &public_key, const std::string &private_key, const std::string &public_key_password, const std::string &private_key_password, std::string name)
Definition jwt.h:1824
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1840
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1887
es256(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2153
es256k(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2203
es384(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2170
es512(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2187
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1401
std::string name() const
Definition jwt.h:1441
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1422
hmacsha(std::string key, const EVP_MD *(*md)(), std::string name)
Definition jwt.h:1392
hs256(std::string key)
Definition jwt.h:2070
hs384(std::string key)
Definition jwt.h:2080
hs512(std::string key)
Definition jwt.h:2090
"none" algorithm.
Definition jwt.h:1359
void verify(const std::string &, const std::string &signature, std::error_code &ec) const
Check if the given signature is empty.
Definition jwt.h:1374
std::string name() const
Get algorithm name.
Definition jwt.h:1379
std::string sign(const std::string &, std::error_code &ec) const
Return an empty string.
Definition jwt.h:1363
ps256(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2267
ps384(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2282
ps512(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2297
std::string name() const
Definition jwt.h:2051
pss(const std::string &public_key, const std::string &private_key, const std::string &public_key_password, const std::string &private_key_password, const EVP_MD *(*md)(), std::string name)
Definition jwt.h:1947
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:2012
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1964
rs256(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Construct new instance of algorithm.
Definition jwt.h:2106
rs384(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2121
rs512(const std::string &public_key, const std::string &private_key="", const std::string &public_key_password="", const std::string &private_key_password="")
Definition jwt.h:2136
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1526
rsa(helper::evp_pkey_handle key_pair, const EVP_MD *(*md)(), std::string name)
Definition jwt.h:1482
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1492
rsa(const std::string &public_key, const std::string &private_key, const std::string &public_key_password, const std::string &private_key_password, const EVP_MD *(*md)(), std::string name)
Definition jwt.h:1465
std::string name() const
Definition jwt.h:1552
Definition jwt.h:4181
date now() const
Definition jwt.h:4186
Definition jwt.h:103
Definition jwt.h:100
Definition jwt.h:3467
Definition jwt.h:3396
date current_time
Current time, retrieved from the verifiers clock and cached for performance and consistency.
Definition jwt.h:3400
basic_claim< json_traits > get_claim(bool in_header, json::type t, std::error_code &ec) const
Definition jwt.h:3437
size_t default_leeway
The configured default leeway for this verification.
Definition jwt.h:3404
basic_claim< json_traits > get_claim(bool in_header, std::error_code &ec) const
Helper method to get a claim from the jwt in this context.
Definition jwt.h:3415
basic_claim< json_traits > get_claim(json::type t, std::error_code &ec) const
Helper method to get a payload claim of a specific type from the jwt.
Definition jwt.h:3458
basic_claim< json_traits > get_claim(std::error_code &ec) const
Helper method to get a payload claim from the jwt.
Definition jwt.h:3451
traits::boost_json::string_type claim_key
Definition jwt.h:3407
const decoded_jwt< json_traits > & jwt
The jwt passed to the verifier.
Definition jwt.h:3402