Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
jwt.h
Go to the documentation of this file.
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 "goby/util/thirdparty/jwt-cpp/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/ssl.h>
22
23#include <algorithm>
24#include <chrono>
25#include <codecvt>
26#include <functional>
27#include <iterator>
28#include <locale>
29#include <memory>
30#include <set>
31#include <system_error>
32#include <type_traits>
33#include <unordered_map>
34#include <utility>
35#include <vector>
36
37#if __cplusplus >= 201402L
38#ifdef __has_include
39#if __has_include(<experimental/type_traits>)
40#include <experimental/type_traits>
41#endif
42#endif
43#endif
44
45#if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0
46#define JWT_OPENSSL_3_0
47#elif OPENSSL_VERSION_NUMBER >= 0x10101000L // 1.1.1
48#define JWT_OPENSSL_1_1_1
49#elif OPENSSL_VERSION_NUMBER >= 0x10100000L // 1.1.0
50#define JWT_OPENSSL_1_1_0
51#elif OPENSSL_VERSION_NUMBER >= 0x10000000L // 1.0.0
52#define JWT_OPENSSL_1_0_0
53#endif
54
55#if defined(LIBRESSL_VERSION_NUMBER)
56#define JWT_OPENSSL_1_0_0
57#endif
58
59#if defined(LIBWOLFSSL_VERSION_HEX)
60#define JWT_OPENSSL_1_1_1
61#endif
62
63#ifndef JWT_CLAIM_EXPLICIT
64#define JWT_CLAIM_EXPLICIT explicit
65#endif
66
74namespace jwt
75{
79using date = std::chrono::system_clock::time_point;
80
84namespace error
85{
86struct signature_verification_exception : public std::system_error
87{
88 using system_error::system_error;
89};
90struct signature_generation_exception : public std::system_error
91{
92 using system_error::system_error;
93};
94struct rsa_exception : public std::system_error
95{
96 using system_error::system_error;
97};
98struct ecdsa_exception : public std::system_error
99{
100 using system_error::system_error;
101};
102struct token_verification_exception : public std::system_error
103{
104 using system_error::system_error;
105};
125inline std::error_category& rsa_error_category()
126{
127 class rsa_error_cat : public std::error_category
128 {
129 public:
130 const char* name() const noexcept override { return "rsa_error"; };
131 std::string message(int ev) const override
132 {
133 switch (static_cast<rsa_error>(ev))
134 {
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:
145 return "at least one of public or private key need to be present";
146 default: return "unknown RSA error";
147 }
148 }
149 };
150 static rsa_error_cat cat;
151 return cat;
152}
153
154inline std::error_code make_error_code(rsa_error e)
155{
156 return {static_cast<int>(e), rsa_error_category()};
157}
175inline std::error_category& ecdsa_error_category()
176{
177 class ecdsa_error_cat : public std::error_category
178 {
179 public:
180 const char* name() const noexcept override { return "ecdsa_error"; };
181 std::string message(int ev) const override
182 {
183 switch (static_cast<ecdsa_error>(ev))
184 {
185 case ecdsa_error::ok: return "no error";
186 case ecdsa_error::load_key_bio_write: return "failed to load key: bio write failed";
187 case ecdsa_error::load_key_bio_read: return "failed to load key: bio read failed";
188 case ecdsa_error::create_mem_bio_failed: return "failed to create memory bio";
189 case ecdsa_error::no_key_provided:
190 return "at least one of public or private key need to be present";
191 case ecdsa_error::invalid_key_size: return "invalid key size";
192 case ecdsa_error::invalid_key: return "invalid key";
193 case ecdsa_error::create_context_failed: return "failed to create context";
194 default: return "unknown ECDSA error";
195 }
196 }
197 };
198 static ecdsa_error_cat cat;
199 return cat;
200}
201
202inline std::error_code make_error_code(ecdsa_error e)
203{
204 return {static_cast<int>(e), ecdsa_error_category()};
205}
206
225inline std::error_category& signature_verification_error_category()
226{
227 class verification_error_cat : public std::error_category
228 {
229 public:
230 const char* name() const noexcept override { return "signature_verification_error"; };
231 std::string message(int ev) const override
232 {
233 switch (static_cast<signature_verification_error>(ev))
234 {
235 case signature_verification_error::ok: return "no error";
236 case signature_verification_error::invalid_signature: return "invalid signature";
237 case signature_verification_error::create_context_failed:
238 return "failed to verify signature: could not create context";
239 case signature_verification_error::verifyinit_failed:
240 return "failed to verify signature: VerifyInit failed";
241 case signature_verification_error::verifyupdate_failed:
242 return "failed to verify signature: VerifyUpdate failed";
243 case signature_verification_error::verifyfinal_failed:
244 return "failed to verify signature: VerifyFinal failed";
245 case signature_verification_error::get_key_failed:
246 return "failed to verify signature: Could not get key";
247 case signature_verification_error::set_rsa_pss_saltlen_failed:
248 return "failed to verify signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
249 case signature_verification_error::signature_encoding_failed:
250 return "failed to verify signature: i2d_ECDSA_SIG failed";
251 default: return "unknown signature verification error";
252 }
253 }
254 };
255 static verification_error_cat cat;
256 return cat;
257}
258
260{
261 return {static_cast<int>(e), signature_verification_error_category()};
262}
263
288inline std::error_category& signature_generation_error_category()
289{
290 class signature_generation_error_cat : public std::error_category
291 {
292 public:
293 const char* name() const noexcept override { return "signature_generation_error"; };
294 std::string message(int ev) const override
295 {
296 switch (static_cast<signature_generation_error>(ev))
297 {
298 case signature_generation_error::ok: return "no error";
299 case signature_generation_error::hmac_failed: return "hmac failed";
300 case signature_generation_error::create_context_failed:
301 return "failed to create signature: could not create context";
302 case signature_generation_error::signinit_failed:
303 return "failed to create signature: SignInit failed";
304 case signature_generation_error::signupdate_failed:
305 return "failed to create signature: SignUpdate failed";
306 case signature_generation_error::signfinal_failed:
307 return "failed to create signature: SignFinal failed";
308 case signature_generation_error::ecdsa_do_sign_failed:
309 return "failed to generate ecdsa signature";
310 case signature_generation_error::digestinit_failed:
311 return "failed to create signature: DigestInit failed";
312 case signature_generation_error::digestupdate_failed:
313 return "failed to create signature: DigestUpdate failed";
314 case signature_generation_error::digestfinal_failed:
315 return "failed to create signature: DigestFinal failed";
316 case signature_generation_error::rsa_padding_failed:
317 return "failed to create signature: EVP_PKEY_CTX_set_rsa_padding failed";
318 case signature_generation_error::rsa_private_encrypt_failed:
319 return "failed to create signature: RSA_private_encrypt failed";
320 case signature_generation_error::get_key_failed:
321 return "failed to generate signature: Could not get key";
322 case signature_generation_error::set_rsa_pss_saltlen_failed:
323 return "failed to create signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
324 case signature_generation_error::signature_decoding_failed:
325 return "failed to create signature: d2i_ECDSA_SIG failed";
326 default: return "unknown signature generation error";
327 }
328 }
329 };
330 static signature_generation_error_cat cat = {};
331 return cat;
332}
333
335{
336 return {static_cast<int>(e), signature_generation_error_category()};
337}
338
355inline std::error_category& token_verification_error_category()
356{
357 class token_verification_error_cat : public std::error_category
358 {
359 public:
360 const char* name() const noexcept override { return "token_verification_error"; };
361 std::string message(int ev) const override
362 {
363 switch (static_cast<token_verification_error>(ev))
364 {
365 case token_verification_error::ok: return "no error";
366 case token_verification_error::wrong_algorithm: return "wrong algorithm";
367 case token_verification_error::missing_claim:
368 return "decoded JWT is missing required claim(s)";
369 case token_verification_error::claim_type_missmatch:
370 return "claim type does not match expected type";
371 case token_verification_error::claim_value_missmatch:
372 return "claim value does not match expected value";
373 case token_verification_error::token_expired: return "token expired";
374 case token_verification_error::audience_missmatch:
375 return "token doesn't contain the required audience";
376 default: return "unknown token verification error";
377 }
378 }
379 };
380 static token_verification_error_cat cat = {};
381 return cat;
382}
383
385{
386 return {static_cast<int>(e), token_verification_error_category()};
387}
388
389inline void throw_if_error(std::error_code ec)
390{
391 if (ec)
392 {
393 if (ec.category() == rsa_error_category())
394 throw rsa_exception(ec);
395 if (ec.category() == ecdsa_error_category())
396 throw ecdsa_exception(ec);
397 if (ec.category() == signature_verification_error_category())
399 if (ec.category() == signature_generation_error_category())
401 if (ec.category() == token_verification_error_category())
403 }
404}
405} // namespace error
406
407// FIXME: Remove
408// Keep backward compat at least for a couple of revisions
409using error::ecdsa_exception;
410using error::rsa_exception;
411using error::signature_generation_exception;
412using error::signature_verification_exception;
413using error::token_verification_exception;
414} // namespace jwt
415namespace std
416{
417template <> struct is_error_code_enum<jwt::error::rsa_error> : true_type
418{
419};
420template <> struct is_error_code_enum<jwt::error::ecdsa_error> : true_type
421{
422};
423template <> struct is_error_code_enum<jwt::error::signature_verification_error> : true_type
424{
425};
426template <> struct is_error_code_enum<jwt::error::signature_generation_error> : true_type
427{
428};
429template <> struct is_error_code_enum<jwt::error::token_verification_error> : true_type
430{
431};
432} // namespace std
433namespace jwt
434{
442namespace helper
443{
451inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw,
452 std::error_code& ec)
453{
454 ec.clear();
455#if OPENSSL_VERSION_NUMBER <= 0x10100003L
456 std::unique_ptr<BIO, decltype(&BIO_free_all)> certbio(
457 BIO_new_mem_buf(const_cast<char*>(certstr.data()), static_cast<int>(certstr.size())),
458 BIO_free_all);
459#else
460 std::unique_ptr<BIO, decltype(&BIO_free_all)> certbio(
461 BIO_new_mem_buf(certstr.data(), static_cast<int>(certstr.size())), BIO_free_all);
462#endif
463 std::unique_ptr<BIO, decltype(&BIO_free_all)> keybio(BIO_new(BIO_s_mem()), BIO_free_all);
464 if (!certbio || !keybio)
465 {
467 return {};
468 }
469
470 std::unique_ptr<X509, decltype(&X509_free)> cert(
471 PEM_read_bio_X509(certbio.get(), nullptr, nullptr, const_cast<char*>(pw.c_str())),
472 X509_free);
473 if (!cert)
474 {
476 return {};
477 }
478 std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> key(X509_get_pubkey(cert.get()),
479 EVP_PKEY_free);
480 if (!key)
481 {
483 return {};
484 }
485 if (PEM_write_bio_PUBKEY(keybio.get(), key.get()) == 0)
486 {
488 return {};
489 }
490 char* ptr = nullptr;
491 auto len = BIO_get_mem_data(keybio.get(), &ptr);
492 if (len <= 0 || ptr == nullptr)
493 {
495 return {};
496 }
497 return {ptr, static_cast<size_t>(len)};
498}
499
507inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "")
508{
509 std::error_code ec;
510 auto res = extract_pubkey_from_cert(certstr, pw, ec);
512 return res;
513}
514
529template <typename Decode>
530std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode,
531 std::error_code& ec)
532{
533 ec.clear();
534 const auto decodedStr = decode(cert_base64_der_str);
535 auto c_str = reinterpret_cast<const unsigned char*>(decodedStr.c_str());
536
537 std::unique_ptr<X509, decltype(&X509_free)> cert(
538 d2i_X509(NULL, &c_str, static_cast<int>(decodedStr.size())), X509_free);
539 std::unique_ptr<BIO, decltype(&BIO_free_all)> certbio(BIO_new(BIO_s_mem()), BIO_free_all);
540 if (!cert || !certbio)
541 {
543 return {};
544 }
545
546 if (!PEM_write_bio_X509(certbio.get(), cert.get()))
547 {
549 return {};
550 }
551
552 char* ptr = nullptr;
553 const auto len = BIO_get_mem_data(certbio.get(), &ptr);
554 if (len <= 0 || ptr == nullptr)
555 {
557 return {};
558 }
559
560 return {ptr, static_cast<size_t>(len)};
561}
562
577template <typename Decode>
578std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode)
579{
580 std::error_code ec;
581 auto res = convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
583 return res;
584}
585#ifndef JWT_DISABLE_BASE64
595inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str,
596 std::error_code& ec)
597{
598 auto decode = [](const std::string& token)
599 { return base::decode<alphabet::base64>(base::pad<alphabet::base64>(token)); };
600 return convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
601}
602
612inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str)
613{
614 std::error_code ec;
615 auto res = convert_base64_der_to_pem(cert_base64_der_str, ec);
617 return res;
618}
619#endif
629inline std::shared_ptr<EVP_PKEY> load_public_key_from_string(const std::string& key,
630 const std::string& password,
631 std::error_code& ec)
632{
633 ec.clear();
634 std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
635 if (!pubkey_bio)
636 {
638 return nullptr;
639 }
640 if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----")
641 {
642 auto epkey = helper::extract_pubkey_from_cert(key, password, ec);
643 if (ec)
644 return nullptr;
645 const int len = static_cast<int>(epkey.size());
646 if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len)
647 {
649 return nullptr;
650 }
651 }
652 else
653 {
654 const int len = static_cast<int>(key.size());
655 if (BIO_write(pubkey_bio.get(), key.data(), len) != len)
656 {
658 return nullptr;
659 }
660 }
661
662 std::shared_ptr<EVP_PKEY> pkey(
663 PEM_read_bio_PUBKEY(
664 pubkey_bio.get(), nullptr, nullptr,
665 (void*)password.data()), // NOLINT(google-readability-casting) requires `const_cast`
666 EVP_PKEY_free);
667 if (!pkey)
668 {
670 return nullptr;
671 }
672 return pkey;
673}
674
684inline std::shared_ptr<EVP_PKEY> load_public_key_from_string(const std::string& key,
685 const std::string& password = "")
686{
687 std::error_code ec;
688 auto res = load_public_key_from_string(key, password, ec);
690 return res;
691}
692
700inline std::shared_ptr<EVP_PKEY> load_private_key_from_string(const std::string& key,
701 const std::string& password,
702 std::error_code& ec)
703{
704 std::unique_ptr<BIO, decltype(&BIO_free_all)> privkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
705 if (!privkey_bio)
706 {
708 return nullptr;
709 }
710 const int len = static_cast<int>(key.size());
711 if (BIO_write(privkey_bio.get(), key.data(), len) != len)
712 {
714 return nullptr;
715 }
716 std::shared_ptr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr,
717 const_cast<char*>(password.c_str())),
718 EVP_PKEY_free);
719 if (!pkey)
720 {
722 return nullptr;
723 }
724 return pkey;
725}
726
734inline std::shared_ptr<EVP_PKEY> load_private_key_from_string(const std::string& key,
735 const std::string& password = "")
736{
737 std::error_code ec;
738 auto res = load_private_key_from_string(key, password, ec);
740 return res;
741}
742
752inline std::shared_ptr<EVP_PKEY> load_public_ec_key_from_string(const std::string& key,
753 const std::string& password,
754 std::error_code& ec)
755{
756 ec.clear();
757 std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
758 if (!pubkey_bio)
759 {
761 return nullptr;
762 }
763 if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----")
764 {
765 auto epkey = helper::extract_pubkey_from_cert(key, password, ec);
766 if (ec)
767 return nullptr;
768 const int len = static_cast<int>(epkey.size());
769 if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len)
770 {
772 return nullptr;
773 }
774 }
775 else
776 {
777 const int len = static_cast<int>(key.size());
778 if (BIO_write(pubkey_bio.get(), key.data(), len) != len)
779 {
781 return nullptr;
782 }
783 }
784
785 std::shared_ptr<EVP_PKEY> pkey(
786 PEM_read_bio_PUBKEY(
787 pubkey_bio.get(), nullptr, nullptr,
788 (void*)password.data()), // NOLINT(google-readability-casting) requires `const_cast`
789 EVP_PKEY_free);
790 if (!pkey)
791 {
793 return nullptr;
794 }
795 return pkey;
796}
797
807inline std::shared_ptr<EVP_PKEY> load_public_ec_key_from_string(const std::string& key,
808 const std::string& password = "")
809{
810 std::error_code ec;
811 auto res = load_public_ec_key_from_string(key, password, ec);
813 return res;
814}
815
823inline std::shared_ptr<EVP_PKEY> load_private_ec_key_from_string(const std::string& key,
824 const std::string& password,
825 std::error_code& ec)
826{
827 std::unique_ptr<BIO, decltype(&BIO_free_all)> privkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
828 if (!privkey_bio)
829 {
831 return nullptr;
832 }
833 const int len = static_cast<int>(key.size());
834 if (BIO_write(privkey_bio.get(), key.data(), len) != len)
835 {
837 return nullptr;
838 }
839 std::shared_ptr<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr,
840 const_cast<char*>(password.c_str())),
841 EVP_PKEY_free);
842 if (!pkey)
843 {
845 return nullptr;
846 }
847 return pkey;
848}
849
857inline std::shared_ptr<EVP_PKEY> load_private_ec_key_from_string(const std::string& key,
858 const std::string& password = "")
859{
860 std::error_code ec;
861 auto res = load_private_ec_key_from_string(key, password, ec);
863 return res;
864}
865
871inline
872#ifdef JWT_OPENSSL_1_0_0
873 std::string
874 bn2raw(BIGNUM* bn)
875#else
876 std::string
877 bn2raw(const BIGNUM* bn)
878#endif
879{
880 std::string res(BN_num_bytes(bn), '\0');
881 BN_bn2bin(
882 bn, (unsigned char*)res.data()); // NOLINT(google-readability-casting) requires `const_cast`
883 return res;
884}
890inline std::unique_ptr<BIGNUM, decltype(&BN_free)> raw2bn(const std::string& raw)
891{
892 return std::unique_ptr<BIGNUM, decltype(&BN_free)>(
893 BN_bin2bn(reinterpret_cast<const unsigned char*>(raw.data()), static_cast<int>(raw.size()),
894 nullptr),
895 BN_free);
896}
897} // namespace helper
898
908namespace algorithm
909{
915struct none
916{
920 std::string sign(const std::string& /*unused*/, std::error_code& ec) const
921 {
922 ec.clear();
923 return {};
924 }
932 void verify(const std::string& /*unused*/, const std::string& signature,
933 std::error_code& ec) const
934 {
935 ec.clear();
936 if (!signature.empty())
937 {
939 }
940 }
942 std::string name() const { return "none"; }
943};
948{
955 hmacsha(std::string key, const EVP_MD* (*md)(), std::string name)
956 : secret(std::move(key)), md(md), alg_name(std::move(name))
957 {
958 }
965 std::string sign(const std::string& data, std::error_code& ec) const
966 {
967 ec.clear();
968 std::string res(static_cast<size_t>(EVP_MAX_MD_SIZE), '\0');
969 auto len = static_cast<unsigned int>(res.size());
970 if (HMAC(md(), secret.data(), static_cast<int>(secret.size()),
971 reinterpret_cast<const unsigned char*>(data.data()), static_cast<int>(data.size()),
972 (unsigned char*)
973 res.data(), // NOLINT(google-readability-casting) requires `const_cast`
974 &len) == nullptr)
975 {
977 return {};
978 }
979 res.resize(len);
980 return res;
981 }
988 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const
989 {
990 ec.clear();
991 auto res = sign(data, ec);
992 if (ec)
993 return;
994
995 bool matched = true;
996 for (size_t i = 0; i < std::min<size_t>(res.size(), signature.size()); i++)
997 if (res[i] != signature[i])
998 matched = false;
999 if (res.size() != signature.size())
1000 matched = false;
1001 if (!matched)
1002 {
1004 return;
1005 }
1006 }
1011 std::string name() const { return alg_name; }
1012
1013 private:
1015 const std::string secret;
1017 const EVP_MD* (*md)();
1019 const std::string alg_name;
1020};
1024struct rsa
1025{
1035 rsa(const std::string& public_key, const std::string& private_key,
1036 const std::string& public_key_password, const std::string& private_key_password,
1037 const EVP_MD* (*md)(), std::string name)
1038 : md(md), alg_name(std::move(name))
1039 {
1040 if (!private_key.empty())
1041 {
1042 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1043 }
1044 else if (!public_key.empty())
1045 {
1046 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1047 }
1048 else
1050 }
1057 std::string sign(const std::string& data, std::error_code& ec) const
1058 {
1059 ec.clear();
1060#ifdef JWT_OPENSSL_1_0_0
1061 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1062 EVP_MD_CTX_destroy);
1063#else
1064 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_create(),
1065 EVP_MD_CTX_free);
1066#endif
1067 if (!ctx)
1068 {
1070 return {};
1071 }
1072 if (!EVP_SignInit(ctx.get(), md()))
1073 {
1075 return {};
1076 }
1077
1078 std::string res(EVP_PKEY_size(pkey.get()), '\0');
1079 unsigned int len = 0;
1080
1081 if (!EVP_SignUpdate(ctx.get(), data.data(), data.size()))
1082 {
1084 return {};
1085 }
1086 if (EVP_SignFinal(ctx.get(), (unsigned char*)res.data(), &len, pkey.get()) == 0)
1087 {
1089 return {};
1090 }
1091
1092 res.resize(len);
1093 return res;
1094 }
1101 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const
1102 {
1103 ec.clear();
1104#ifdef JWT_OPENSSL_1_0_0
1105 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1106 EVP_MD_CTX_destroy);
1107#else
1108 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_create(),
1109 EVP_MD_CTX_free);
1110#endif
1111 if (!ctx)
1112 {
1114 return;
1115 }
1116 if (!EVP_VerifyInit(ctx.get(), md()))
1117 {
1119 return;
1120 }
1121 if (!EVP_VerifyUpdate(ctx.get(), data.data(), data.size()))
1122 {
1124 return;
1125 }
1126 auto res =
1127 EVP_VerifyFinal(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
1128 static_cast<unsigned int>(signature.size()), pkey.get());
1129 if (res != 1)
1130 {
1132 return;
1133 }
1134 }
1139 std::string name() const { return alg_name; }
1140
1141 private:
1143 std::shared_ptr<EVP_PKEY> pkey;
1145 const EVP_MD* (*md)();
1147 const std::string alg_name;
1148};
1152struct ecdsa
1153{
1165 ecdsa(const std::string& public_key, const std::string& private_key,
1166 const std::string& public_key_password, const std::string& private_key_password,
1167 const EVP_MD* (*md)(), std::string name, size_t siglen)
1168 : md(md), alg_name(std::move(name)), signature_length(siglen)
1169 {
1170 if (!private_key.empty())
1171 {
1172 pkey = helper::load_private_ec_key_from_string(private_key, private_key_password);
1173 check_private_key(pkey.get());
1174 }
1175 else if (!public_key.empty())
1176 {
1177 pkey = helper::load_public_ec_key_from_string(public_key, public_key_password);
1178 check_public_key(pkey.get());
1179 }
1180 else
1181 {
1183 }
1184 if (!pkey)
1186
1187 size_t keysize = EVP_PKEY_bits(pkey.get());
1188 if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521))
1190 }
1191
1198 std::string sign(const std::string& data, std::error_code& ec) const
1199 {
1200 ec.clear();
1201#ifdef JWT_OPENSSL_1_0_0
1202 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1203 EVP_MD_CTX_destroy);
1204#else
1205 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_create(),
1206 EVP_MD_CTX_free);
1207#endif
1208 if (!ctx)
1209 {
1211 return {};
1212 }
1213 if (!EVP_DigestSignInit(ctx.get(), nullptr, md(), nullptr, pkey.get()))
1214 {
1216 return {};
1217 }
1218 if (!EVP_DigestUpdate(ctx.get(), data.data(), data.size()))
1219 {
1221 return {};
1222 }
1223
1224 size_t len = 0;
1225 if (!EVP_DigestSignFinal(ctx.get(), nullptr, &len))
1226 {
1228 return {};
1229 }
1230 std::string res(len, '\0');
1231 if (!EVP_DigestSignFinal(ctx.get(), (unsigned char*)res.data(), &len))
1232 {
1234 return {};
1235 }
1236
1237 res.resize(len);
1238 return der_to_p1363_signature(res, ec);
1239 }
1240
1247 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const
1248 {
1249 ec.clear();
1250 std::string der_signature = p1363_to_der_signature(signature, ec);
1251 if (ec)
1252 {
1253 return;
1254 }
1255
1256#ifdef JWT_OPENSSL_1_0_0
1257 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1258 EVP_MD_CTX_destroy);
1259#else
1260 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_create(),
1261 EVP_MD_CTX_free);
1262#endif
1263 if (!ctx)
1264 {
1266 return;
1267 }
1268 if (!EVP_DigestVerifyInit(ctx.get(), nullptr, md(), nullptr, pkey.get()))
1269 {
1271 return;
1272 }
1273 if (!EVP_DigestUpdate(ctx.get(), data.data(), data.size()))
1274 {
1276 return;
1277 }
1278
1279#if OPENSSL_VERSION_NUMBER < 0x10002000L
1280 unsigned char* der_sig_data =
1281 reinterpret_cast<unsigned char*>(const_cast<char*>(der_signature.data()));
1282#else
1283 const unsigned char* der_sig_data =
1284 reinterpret_cast<const unsigned char*>(der_signature.data());
1285#endif
1286 auto res = EVP_DigestVerifyFinal(ctx.get(), der_sig_data,
1287 static_cast<unsigned int>(der_signature.length()));
1288 if (res == 0)
1289 {
1291 return;
1292 }
1293 if (res == -1)
1294 {
1296 return;
1297 }
1298 }
1303 std::string name() const { return alg_name; }
1304
1305 private:
1306 static void check_public_key(EVP_PKEY* pkey)
1307 {
1308#ifdef JWT_OPENSSL_3_0
1309 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1310 EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
1311 if (!ctx)
1312 {
1314 }
1315 if (EVP_PKEY_public_check(ctx.get()) != 1)
1316 {
1318 }
1319#else
1320 std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey),
1321 EC_KEY_free);
1322 if (!eckey)
1323 {
1324 throw ecdsa_exception(error::ecdsa_error::invalid_key);
1325 }
1326 if (EC_KEY_check_key(eckey.get()) == 0)
1327 throw ecdsa_exception(error::ecdsa_error::invalid_key);
1328#endif
1329 }
1330
1331 static void check_private_key(EVP_PKEY* pkey)
1332 {
1333#ifdef JWT_OPENSSL_3_0
1334 std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1335 EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
1336 if (!ctx)
1337 {
1338 throw ecdsa_exception(error::ecdsa_error::create_context_failed);
1339 }
1340 if (EVP_PKEY_private_check(ctx.get()) != 1)
1341 {
1342 throw ecdsa_exception(error::ecdsa_error::invalid_key);
1343 }
1344#else
1345 std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey),
1346 EC_KEY_free);
1347 if (!eckey)
1348 {
1349 throw ecdsa_exception(error::ecdsa_error::invalid_key);
1350 }
1351 if (EC_KEY_check_key(eckey.get()) == 0)
1352 throw ecdsa_exception(error::ecdsa_error::invalid_key);
1353#endif
1354 }
1355
1356 std::string der_to_p1363_signature(const std::string& der_signature, std::error_code& ec) const
1357 {
1358 const unsigned char* possl_signature =
1359 reinterpret_cast<const unsigned char*>(der_signature.data());
1360 std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(
1361 d2i_ECDSA_SIG(nullptr, &possl_signature, der_signature.length()), ECDSA_SIG_free);
1362 if (!sig)
1363 {
1365 return {};
1366 }
1367
1368#ifdef JWT_OPENSSL_1_0_0
1369
1370 auto rr = helper::bn2raw(sig->r);
1371 auto rs = helper::bn2raw(sig->s);
1372#else
1373 const BIGNUM* r;
1374 const BIGNUM* s;
1375 ECDSA_SIG_get0(sig.get(), &r, &s);
1376 auto rr = helper::bn2raw(r);
1377 auto rs = helper::bn2raw(s);
1378#endif
1379 if (rr.size() > signature_length / 2 || rs.size() > signature_length / 2)
1380 throw std::logic_error("bignum size exceeded expected length");
1381 rr.insert(0, signature_length / 2 - rr.size(), '\0');
1382 rs.insert(0, signature_length / 2 - rs.size(), '\0');
1383 return rr + rs;
1384 }
1385
1386 std::string p1363_to_der_signature(const std::string& signature, std::error_code& ec) const
1387 {
1388 ec.clear();
1389 auto r = helper::raw2bn(signature.substr(0, signature.size() / 2));
1390 auto s = helper::raw2bn(signature.substr(signature.size() / 2));
1391
1392 ECDSA_SIG* psig;
1393#ifdef JWT_OPENSSL_1_0_0
1394 ECDSA_SIG sig;
1395 sig.r = r.get();
1396 sig.s = s.get();
1397 psig = &sig;
1398#else
1399 std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(ECDSA_SIG_new(), ECDSA_SIG_free);
1400 if (!sig)
1401 {
1403 return {};
1404 }
1405 ECDSA_SIG_set0(sig.get(), r.release(), s.release());
1406 psig = sig.get();
1407#endif
1408
1409 int length = i2d_ECDSA_SIG(psig, nullptr);
1410 if (length < 0)
1411 {
1413 return {};
1414 }
1415 std::string der_signature(length, '\0');
1416 unsigned char* psbuffer = (unsigned char*)der_signature.data();
1417 length = i2d_ECDSA_SIG(psig, &psbuffer);
1418 if (length < 0)
1419 {
1421 return {};
1422 }
1423 der_signature.resize(length);
1424 return der_signature;
1425 }
1426
1428 std::shared_ptr<EVP_PKEY> pkey;
1430 const EVP_MD* (*md)();
1432 const std::string alg_name;
1434 const size_t signature_length;
1435};
1436
1437#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
1446struct eddsa
1447{
1458 eddsa(const std::string& public_key, const std::string& private_key,
1459 const std::string& public_key_password, const std::string& private_key_password,
1460 std::string name)
1461 : alg_name(std::move(name))
1462 {
1463 if (!private_key.empty())
1464 {
1465 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1466 }
1467 else if (!public_key.empty())
1468 {
1469 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1470 }
1471 else
1473 }
1480 std::string sign(const std::string& data, std::error_code& ec) const
1481 {
1482 ec.clear();
1483#ifdef JWT_OPENSSL_1_0_0
1484 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1485 &EVP_MD_CTX_destroy);
1486#else
1487 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_new(),
1488 EVP_MD_CTX_free);
1489#endif
1490 if (!ctx)
1491 {
1493 return {};
1494 }
1495 if (!EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()))
1496 {
1498 return {};
1499 }
1500
1501 size_t len = EVP_PKEY_size(pkey.get());
1502 std::string res(len, '\0');
1503
1504// LibreSSL is the special kid in the block, as it does not support EVP_DigestSign.
1505// OpenSSL on the otherhand does not support using EVP_DigestSignUpdate for eddsa, which is why we end up with this
1506// mess.
1507#if defined(LIBRESSL_VERSION_NUMBER) || defined(LIBWOLFSSL_VERSION_HEX)
1508 ERR_clear_error();
1509 if (EVP_DigestSignUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()),
1510 data.size()) != 1)
1511 {
1512 std::cout << ERR_error_string(ERR_get_error(), NULL) << std::endl;
1514 return {};
1515 }
1516 if (EVP_DigestSignFinal(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len) != 1)
1517 {
1519 return {};
1520 }
1521#else
1522 if (EVP_DigestSign(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len,
1523 reinterpret_cast<const unsigned char*>(data.data()), data.size()) != 1)
1524 {
1526 return {};
1527 }
1528#endif
1529
1530 res.resize(len);
1531 return res;
1532 }
1533
1540 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const
1541 {
1542 ec.clear();
1543#ifdef JWT_OPENSSL_1_0_0
1544 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> ctx(EVP_MD_CTX_create(),
1545 &EVP_MD_CTX_destroy);
1546#else
1547 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_new(),
1548 EVP_MD_CTX_free);
1549#endif
1550 if (!ctx)
1551 {
1553 return;
1554 }
1555 if (!EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get()))
1556 {
1558 return;
1559 }
1560// LibreSSL is the special kid in the block, as it does not support EVP_DigestVerify.
1561// OpenSSL on the otherhand does not support using EVP_DigestVerifyUpdate for eddsa, which is why we end up with this
1562// mess.
1563#if defined(LIBRESSL_VERSION_NUMBER) || defined(LIBWOLFSSL_VERSION_HEX)
1564 if (EVP_DigestVerifyUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()),
1565 data.size()) != 1)
1566 {
1568 return;
1569 }
1570 if (EVP_DigestVerifyFinal(ctx.get(),
1571 reinterpret_cast<const unsigned char*>(signature.data()),
1572 signature.size()) != 1)
1573 {
1575 return;
1576 }
1577#else
1578 auto res = EVP_DigestVerify(
1579 ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()), signature.size(),
1580 reinterpret_cast<const unsigned char*>(data.data()), data.size());
1581 if (res != 1)
1582 {
1584 return;
1585 }
1586#endif
1587 }
1592 std::string name() const { return alg_name; }
1593
1594 private:
1596 std::shared_ptr<EVP_PKEY> pkey;
1598 const std::string alg_name;
1599};
1600#endif
1604struct pss
1605{
1615 pss(const std::string& public_key, const std::string& private_key,
1616 const std::string& public_key_password, const std::string& private_key_password,
1617 const EVP_MD* (*md)(), std::string name)
1618 : md(md), alg_name(std::move(name))
1619 {
1620 if (!private_key.empty())
1621 {
1622 pkey = helper::load_private_key_from_string(private_key, private_key_password);
1623 }
1624 else if (!public_key.empty())
1625 {
1626 pkey = helper::load_public_key_from_string(public_key, public_key_password);
1627 }
1628 else
1630 }
1631
1638 std::string sign(const std::string& data, std::error_code& ec) const
1639 {
1640 ec.clear();
1641#ifdef JWT_OPENSSL_1_0_0
1642 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> md_ctx(EVP_MD_CTX_create(),
1643 &EVP_MD_CTX_destroy);
1644#else
1645 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> md_ctx(EVP_MD_CTX_new(),
1646 EVP_MD_CTX_free);
1647#endif
1648 if (!md_ctx)
1649 {
1651 return {};
1652 }
1653 EVP_PKEY_CTX* ctx = nullptr;
1654 if (EVP_DigestSignInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1)
1655 {
1657 return {};
1658 }
1659 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0)
1660 {
1662 return {};
1663 }
1664// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1665// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1666#ifndef LIBWOLFSSL_VERSION_HEX
1667 if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0)
1668 {
1670 return {};
1671 }
1672#endif
1673 if (EVP_DigestUpdate(md_ctx.get(), data.data(), data.size()) != 1)
1674 {
1676 return {};
1677 }
1678
1679 size_t size = EVP_PKEY_size(pkey.get());
1680 std::string res(size, 0x00);
1681 if (EVP_DigestSignFinal(
1682 md_ctx.get(),
1683 (unsigned char*)
1684 res.data(), // NOLINT(google-readability-casting) requires `const_cast`
1685 &size) <= 0)
1686 {
1688 return {};
1689 }
1690
1691 return res;
1692 }
1693
1700 void verify(const std::string& data, const std::string& signature, std::error_code& ec) const
1701 {
1702 ec.clear();
1703
1704#ifdef JWT_OPENSSL_1_0_0
1705 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)> md_ctx(EVP_MD_CTX_create(),
1706 &EVP_MD_CTX_destroy);
1707#else
1708 std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> md_ctx(EVP_MD_CTX_new(),
1709 EVP_MD_CTX_free);
1710#endif
1711 if (!md_ctx)
1712 {
1714 return;
1715 }
1716 EVP_PKEY_CTX* ctx = nullptr;
1717 if (EVP_DigestVerifyInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1)
1718 {
1720 return;
1721 }
1722 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0)
1723 {
1725 return;
1726 }
1727// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1728// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1729#ifndef LIBWOLFSSL_VERSION_HEX
1730 if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0)
1731 {
1733 return;
1734 }
1735#endif
1736 if (EVP_DigestUpdate(md_ctx.get(), data.data(), data.size()) != 1)
1737 {
1739 return;
1740 }
1741
1742 if (EVP_DigestVerifyFinal(md_ctx.get(), (unsigned char*)signature.data(),
1743 signature.size()) <= 0)
1744 {
1746 return;
1747 }
1748 }
1753 std::string name() const { return alg_name; }
1754
1755 private:
1757 std::shared_ptr<EVP_PKEY> pkey;
1759 const EVP_MD* (*md)();
1761 const std::string alg_name;
1762};
1763
1767struct hs256 : public hmacsha
1768{
1773 explicit hs256(std::string key) : hmacsha(std::move(key), EVP_sha256, "HS256") {}
1774};
1778struct hs384 : public hmacsha
1779{
1784 explicit hs384(std::string key) : hmacsha(std::move(key), EVP_sha384, "HS384") {}
1785};
1789struct hs512 : public hmacsha
1790{
1795 explicit hs512(std::string key) : hmacsha(std::move(key), EVP_sha512, "HS512") {}
1796};
1800struct rs256 : public rsa
1801{
1809 explicit rs256(const std::string& public_key, const std::string& private_key = "",
1810 const std::string& public_key_password = "",
1811 const std::string& private_key_password = "")
1812 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256,
1813 "RS256")
1814 {
1815 }
1816};
1820struct rs384 : public rsa
1821{
1829 explicit rs384(const std::string& public_key, const std::string& private_key = "",
1830 const std::string& public_key_password = "",
1831 const std::string& private_key_password = "")
1832 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384,
1833 "RS384")
1834 {
1835 }
1836};
1840struct rs512 : public rsa
1841{
1849 explicit rs512(const std::string& public_key, const std::string& private_key = "",
1850 const std::string& public_key_password = "",
1851 const std::string& private_key_password = "")
1852 : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512,
1853 "RS512")
1854 {
1855 }
1856};
1860struct es256 : public ecdsa
1861{
1871 explicit es256(const std::string& public_key, const std::string& private_key = "",
1872 const std::string& public_key_password = "",
1873 const std::string& private_key_password = "")
1874 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256,
1875 "ES256", 64)
1876 {
1877 }
1878};
1882struct es384 : public ecdsa
1883{
1893 explicit es384(const std::string& public_key, const std::string& private_key = "",
1894 const std::string& public_key_password = "",
1895 const std::string& private_key_password = "")
1896 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384,
1897 "ES384", 96)
1898 {
1899 }
1900};
1904struct es512 : public ecdsa
1905{
1915 explicit es512(const std::string& public_key, const std::string& private_key = "",
1916 const std::string& public_key_password = "",
1917 const std::string& private_key_password = "")
1918 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512,
1919 "ES512", 132)
1920 {
1921 }
1922};
1926struct es256k : public ecdsa
1927{
1936 explicit es256k(const std::string& public_key, const std::string& private_key = "",
1937 const std::string& public_key_password = "",
1938 const std::string& private_key_password = "")
1939 : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256,
1940 "ES256K", 64)
1941 {
1942 }
1943};
1944
1945#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
1953struct ed25519 : public eddsa
1954{
1964 explicit ed25519(const std::string& public_key, const std::string& private_key = "",
1965 const std::string& public_key_password = "",
1966 const std::string& private_key_password = "")
1967 : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA")
1968 {
1969 }
1970};
1971
1979struct ed448 : public eddsa
1980{
1990 explicit ed448(const std::string& public_key, const std::string& private_key = "",
1991 const std::string& public_key_password = "",
1992 const std::string& private_key_password = "")
1993 : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA")
1994 {
1995 }
1996};
1997#endif
1998
2002struct ps256 : public pss
2003{
2011 explicit ps256(const std::string& public_key, const std::string& private_key = "",
2012 const std::string& public_key_password = "",
2013 const std::string& private_key_password = "")
2014 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha256,
2015 "PS256")
2016 {
2017 }
2018};
2022struct ps384 : public pss
2023{
2031 explicit ps384(const std::string& public_key, const std::string& private_key = "",
2032 const std::string& public_key_password = "",
2033 const std::string& private_key_password = "")
2034 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha384,
2035 "PS384")
2036 {
2037 }
2038};
2042struct ps512 : public pss
2043{
2051 explicit ps512(const std::string& public_key, const std::string& private_key = "",
2052 const std::string& public_key_password = "",
2053 const std::string& private_key_password = "")
2054 : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha512,
2055 "PS512")
2056 {
2057 }
2058};
2059} // namespace algorithm
2060
2064namespace json
2065{
2071enum class type
2072{
2073 boolean,
2074 integer,
2075 number,
2076 string,
2077 array,
2078 object
2079};
2080} // namespace json
2081
2082namespace details
2083{
2084#ifdef __cpp_lib_void_t
2085template <typename... Ts> using void_t = std::void_t<Ts...>;
2086#else
2087// https://en.cppreference.com/w/cpp/types/void_t
2088template <typename... Ts> struct make_void
2089{
2090 using type = void;
2091};
2092
2093template <typename... Ts> using void_t = typename make_void<Ts...>::type;
2094#endif
2095
2096#ifdef __cpp_lib_experimental_detect
2097template <template <typename...> class _Op, typename... _Args>
2098using is_detected = std::experimental::is_detected<_Op, _Args...>;
2099
2100template <template <typename...> class _Op, typename... _Args>
2101using is_detected_t = std::experimental::detected_t<_Op, _Args...>;
2102#else
2104{
2105 nonesuch() = delete;
2106 ~nonesuch() = delete;
2107 nonesuch(nonesuch const&) = delete;
2108 nonesuch(nonesuch const&&) = delete;
2109 void operator=(nonesuch const&) = delete;
2110 void operator=(nonesuch&&) = delete;
2111};
2112
2113// https://en.cppreference.com/w/cpp/experimental/is_detected
2114template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
2116{
2117 using value = std::false_type;
2118 using type = Default;
2119};
2120
2121template <class Default, template <class...> class Op, class... Args>
2122struct detector<Default, void_t<Op<Args...>>, Op, Args...>
2123{
2124 using value = std::true_type;
2125 using type = Op<Args...>;
2126};
2127
2128template <template <class...> class Op, class... Args>
2129using is_detected = typename detector<nonesuch, void, Op, Args...>::value;
2130
2131template <template <class...> class Op, class... Args>
2132using is_detected_t = typename detector<nonesuch, void, Op, Args...>::type;
2133#endif
2134
2135template <typename traits_type> using get_type_function = decltype(traits_type::get_type);
2136
2137template <typename traits_type, typename value_type>
2139 typename std::is_same<get_type_function<traits_type>, json::type(const value_type&)>;
2140
2141template <typename traits_type, typename value_type> struct supports_get_type
2142{
2144 std::is_function<get_type_function<traits_type>>::value &&
2146};
2147
2148template <typename traits_type> using as_object_function = decltype(traits_type::as_object);
2149
2150template <typename traits_type, typename value_type, typename object_type>
2152 typename std::is_same<as_object_function<traits_type>, object_type(const value_type&)>;
2153
2154template <typename traits_type, typename value_type, typename object_type> struct supports_as_object
2155{
2156 static constexpr auto value =
2157 std::is_constructible<value_type, object_type>::value &&
2159 std::is_function<as_object_function<traits_type>>::value &&
2161};
2162
2163template <typename traits_type> using as_array_function = decltype(traits_type::as_array);
2164
2165template <typename traits_type, typename value_type, typename array_type>
2167 typename std::is_same<as_array_function<traits_type>, array_type(const value_type&)>;
2168
2169template <typename traits_type, typename value_type, typename array_type> struct supports_as_array
2170{
2171 static constexpr auto value = std::is_constructible<value_type, array_type>::value &&
2173 std::is_function<as_array_function<traits_type>>::value &&
2175};
2176
2177template <typename traits_type> using as_string_function = decltype(traits_type::as_string);
2178
2179template <typename traits_type, typename value_type, typename string_type>
2181 typename std::is_same<as_string_function<traits_type>, string_type(const value_type&)>;
2182
2183template <typename traits_type, typename value_type, typename string_type> struct supports_as_string
2184{
2185 static constexpr auto value =
2186 std::is_constructible<value_type, string_type>::value &&
2188 std::is_function<as_string_function<traits_type>>::value &&
2190};
2191
2192template <typename traits_type> using as_number_function = decltype(traits_type::as_number);
2193
2194template <typename traits_type, typename value_type, typename number_type>
2196 typename std::is_same<as_number_function<traits_type>, number_type(const value_type&)>;
2197
2198template <typename traits_type, typename value_type, typename number_type> struct supports_as_number
2199{
2200 static constexpr auto value =
2201 std::is_floating_point<number_type>::value &&
2202 std::is_constructible<value_type, number_type>::value &&
2204 std::is_function<as_number_function<traits_type>>::value &&
2206};
2207
2208template <typename traits_type> using as_integer_function = decltype(traits_type::as_int);
2209
2210template <typename traits_type, typename value_type, typename integer_type>
2212 typename std::is_same<as_integer_function<traits_type>, integer_type(const value_type&)>;
2213
2214template <typename traits_type, typename value_type, typename integer_type>
2216{
2217 static constexpr auto value =
2218 std::is_signed<integer_type>::value && !std::is_floating_point<integer_type>::value &&
2219 std::is_constructible<value_type, integer_type>::value &&
2221 std::is_function<as_integer_function<traits_type>>::value &&
2223};
2224
2225template <typename traits_type> using as_boolean_function = decltype(traits_type::as_bool);
2226
2227template <typename traits_type, typename value_type, typename boolean_type>
2229 typename std::is_same<as_boolean_function<traits_type>, boolean_type(const value_type&)>;
2230
2231template <typename traits_type, typename value_type, typename boolean_type>
2233{
2234 static constexpr auto value =
2235 std::is_convertible<boolean_type, bool>::value &&
2236 std::is_constructible<value_type, boolean_type>::value &&
2238 std::is_function<as_boolean_function<traits_type>>::value &&
2240};
2241
2242template <typename traits> struct is_valid_traits
2243{
2244 // Internal assertions for better feedback
2246 "traits must provide `jwt::json::type get_type(const value_type&)`");
2247 static_assert(supports_as_object<traits, typename traits::value_type,
2248 typename traits::object_type>::value,
2249 "traits must provide `object_type as_object(const value_type&)`");
2250 static_assert(
2252 "traits must provide `array_type as_array(const value_type&)`");
2253 static_assert(supports_as_string<traits, typename traits::value_type,
2254 typename traits::string_type>::value,
2255 "traits must provide `string_type as_string(const value_type&)`");
2256 static_assert(supports_as_number<traits, typename traits::value_type,
2257 typename traits::number_type>::value,
2258 "traits must provide `number_type as_number(const value_type&)`");
2259 static_assert(supports_as_integer<traits, typename traits::value_type,
2260 typename traits::integer_type>::value,
2261 "traits must provide `integer_type as_int(const value_type&)`");
2262 static_assert(supports_as_boolean<traits, typename traits::value_type,
2263 typename traits::boolean_type>::value,
2264 "traits must provide `boolean_type as_bool(const value_type&)`");
2265
2267 supports_as_object<traits, typename traits::value_type,
2268 typename traits::object_type>::value &&
2269 supports_as_array<traits, typename traits::value_type,
2270 typename traits::array_type>::value &&
2271 supports_as_string<traits, typename traits::value_type,
2272 typename traits::string_type>::value &&
2273 supports_as_number<traits, typename traits::value_type,
2274 typename traits::number_type>::value &&
2275 supports_as_integer<traits, typename traits::value_type,
2276 typename traits::integer_type>::value &&
2277 supports_as_boolean<traits, typename traits::value_type,
2278 typename traits::boolean_type>::value;
2279};
2280
2281template <typename value_type> struct is_valid_json_value
2282{
2283 static constexpr auto value =
2284 std::is_default_constructible<value_type>::value &&
2285 std::is_constructible<value_type,
2286 const value_type&>::value && // a more generic is_copy_constructible
2287 std::is_move_constructible<value_type>::value &&
2288 std::is_assignable<value_type, value_type>::value &&
2289 std::is_copy_assignable<value_type>::value && std::is_move_assignable<value_type>::value;
2290 // TODO(prince-chrismc): Stream operators
2291};
2292
2293template <typename traits_type> using has_mapped_type = typename traits_type::mapped_type;
2294
2295template <typename traits_type> using has_key_type = typename traits_type::key_type;
2296
2297template <typename traits_type> using has_value_type = typename traits_type::value_type;
2298
2299template <typename object_type> using has_iterator = typename object_type::iterator;
2300
2301template <typename object_type> using has_const_iterator = typename object_type::const_iterator;
2302
2303template <typename object_type>
2305 typename std::is_same<decltype(std::declval<object_type>().begin()), has_iterator<object_type>>;
2306
2307template <typename object_type>
2309 typename std::is_same<decltype(std::declval<const object_type>().begin()),
2311
2319
2320template <typename object_type>
2322 typename std::is_same<decltype(std::declval<object_type>().end()), has_iterator<object_type>>;
2323
2324template <typename object_type>
2326 typename std::is_same<decltype(std::declval<const object_type>().end()),
2328
2336
2337template <typename object_type, typename string_type>
2339 typename std::is_integral<decltype(std::declval<const object_type>().count(
2340 std::declval<const string_type>()))>;
2341
2342template <typename object_type, typename string_type> struct has_subcription_operator
2343{
2344 template <class> struct sfinae_true : std::true_type
2345 {
2346 };
2347
2348 template <class T, class A0>
2349 static auto test_operator_plus(int)
2350 -> sfinae_true<decltype(std::declval<T>().operator[](std::declval<A0>()))>;
2351 template <class, class A0> static auto test_operator_plus(long) -> std::false_type;
2352
2353 static constexpr auto value = decltype(test_operator_plus<object_type, string_type>(0)){};
2354};
2355
2356template <typename object_type, typename value_type, typename string_type>
2358{
2359 static constexpr auto has_subscription_operator =
2361 static_assert(has_subscription_operator,
2362 "object_type must implementate the subscription operator '[]' for this library");
2363
2364 static constexpr auto value = has_subscription_operator;
2365};
2366
2367template <typename object_type, typename value_type, typename string_type>
2368using is_at_const_signature = typename std::is_same<decltype(std::declval<const object_type>().at(
2369 std::declval<const string_type>())),
2370 const value_type&>;
2371
2372template <typename value_type, typename string_type, typename object_type>
2374{
2375 static constexpr auto value =
2377 std::is_same<typename object_type::mapped_type, value_type>::value &&
2379 (std::is_same<typename object_type::key_type, string_type>::value ||
2380 std::is_constructible<typename object_type::key_type, string_type>::value) &&
2385
2386 static constexpr auto supports_claims_transform =
2388 std::is_same<typename object_type::value_type,
2389 std::pair<const string_type, value_type>>::value;
2390};
2391
2392template <typename value_type, typename array_type> struct is_valid_json_array
2393{
2394 static constexpr auto value = std::is_same<typename array_type::value_type, value_type>::value;
2395};
2396
2397template <typename string_type, typename integer_type>
2399 typename std::is_same<decltype(std::declval<string_type>().substr(
2400 std::declval<integer_type>(), std::declval<integer_type>())),
2401 string_type>;
2402
2403template <typename string_type, typename integer_type>
2404using is_substr_start_index_signature = typename std::is_same<
2405 decltype(std::declval<string_type>().substr(std::declval<integer_type>())), string_type>;
2406
2407template <typename string_type> struct has_operate_plus_method
2408{ // https://stackoverflow.com/a/9154394/8480874
2409 template <class> struct sfinae_true : std::true_type
2410 {
2411 };
2412
2413 template <class T, class A0>
2414 static auto test_operator_plus(int)
2415 -> sfinae_true<decltype(std::declval<T>().operator+(std::declval<A0>()))>;
2416 template <class, class A0> static auto test_operator_plus(long) -> std::false_type;
2417
2418 static constexpr auto value = decltype(test_operator_plus<string_type, string_type>(0)){};
2419};
2420
2421template <typename string_type>
2423 typename std::is_same<decltype(std::operator+(std::declval<string_type>(),
2424 std::declval<string_type>())),
2425 string_type>;
2426
2427template <typename string_type, typename integer_type> struct is_valid_json_string
2428{
2429 static constexpr auto substr =
2432 static_assert(substr,
2433 "string_type must have a substr method taking only a start index and an overload "
2434 "taking a start and end index, both must return a string_type");
2435
2438 static_assert(
2440 "string_type must have a '+' operator implemented which returns the concatenated string");
2441
2442 static constexpr auto value = substr && operator_plus;
2443};
2444
2445template <typename value_type, typename string_type, typename integer_type, typename object_type,
2446 typename array_type>
2448{
2449 // Internal assertions for better feedback
2450 static_assert(
2452 "value_type must meet basic requirements, default constructor, copyable, moveable");
2454 "object_type must be a string_type to value_type container");
2456 "array_type must be a container of value_type");
2457
2458 static constexpr auto value =
2463};
2464} // namespace details
2465
2473template <typename json_traits> class basic_claim
2474{
2481 static_assert(std::is_same<typename json_traits::string_type, std::string>::value ||
2482 std::is_convertible<typename json_traits::string_type, std::string>::value ||
2483 std::is_constructible<typename json_traits::string_type, std::string>::value,
2484 "string_type must be a std::string, convertible to a std::string, or construct a "
2485 "std::string.");
2486
2487 static_assert(details::is_valid_json_types<
2488 typename json_traits::value_type, typename json_traits::string_type,
2489 typename json_traits::integer_type, typename json_traits::object_type,
2490 typename json_traits::array_type>::value,
2491 "must staisfy json container requirements");
2492 static_assert(details::is_valid_traits<json_traits>::value, "traits must satisfy requirements");
2493
2494 typename json_traits::value_type val;
2495
2496 public:
2497 using set_t = std::set<typename json_traits::string_type>;
2498
2499 basic_claim() = default;
2500 basic_claim(const basic_claim&) = default;
2504 ~basic_claim() = default;
2505
2506 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::string_type s) : val(std::move(s)) {}
2508 : val(typename json_traits::integer_type(std::chrono::system_clock::to_time_t(d)))
2509 {
2510 }
2511 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::array_type a) : val(std::move(a)) {}
2512 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::value_type v) : val(std::move(v)) {}
2514 : val(typename json_traits::array_type(s.begin(), s.end()))
2515 {
2516 }
2517 template <typename Iterator>
2518 basic_claim(Iterator begin, Iterator end) : val(typename json_traits::array_type(begin, end))
2519 {
2520 }
2521
2526 typename json_traits::value_type to_json() const { return val; }
2527
2532 std::istream& operator>>(std::istream& is) { return is >> val; }
2533
2538 std::ostream& operator<<(std::ostream& os) { return os << val; }
2539
2545 json::type get_type() const { return json_traits::get_type(val); }
2546
2552 typename json_traits::string_type as_string() const { return json_traits::as_string(val); }
2553
2559 date as_date() const { return std::chrono::system_clock::from_time_t(as_int()); }
2560
2566 typename json_traits::array_type as_array() const { return json_traits::as_array(val); }
2567
2574 {
2575 set_t res;
2576 for (const auto& e : json_traits::as_array(val)) { res.insert(json_traits::as_string(e)); }
2577 return res;
2578 }
2579
2585 typename json_traits::integer_type as_int() const { return json_traits::as_int(val); }
2586
2592 typename json_traits::boolean_type as_bool() const { return json_traits::as_bool(val); }
2593
2599 typename json_traits::number_type as_number() const { return json_traits::as_number(val); }
2600};
2601
2602namespace error
2603{
2607struct invalid_json_exception : public std::runtime_error
2608{
2609 invalid_json_exception() : runtime_error("invalid json") {}
2610};
2614struct claim_not_present_exception : public std::out_of_range
2615{
2616 claim_not_present_exception() : out_of_range("claim not found") {}
2617};
2618} // namespace error
2619
2620namespace details
2621{
2622template <typename json_traits> class map_of_claims
2623{
2624 typename json_traits::object_type claims;
2625
2626 public:
2628 using iterator = typename json_traits::object_type::iterator;
2629 using const_iterator = typename json_traits::object_type::const_iterator;
2630
2631 map_of_claims() = default;
2632 map_of_claims(const map_of_claims&) = default;
2636
2637 map_of_claims(typename json_traits::object_type json) : claims(std::move(json)) {}
2638
2639 iterator begin() { return claims.begin(); }
2640 iterator end() { return claims.end(); }
2641 const_iterator cbegin() const { return claims.begin(); }
2642 const_iterator cend() const { return claims.end(); }
2643 const_iterator begin() const { return claims.begin(); }
2644 const_iterator end() const { return claims.end(); }
2645
2654 static typename json_traits::object_type
2655 parse_claims(const typename json_traits::string_type& str)
2656 {
2657 typename json_traits::value_type val;
2658 if (!json_traits::parse(val, str))
2660
2661 return json_traits::as_object(val);
2662 };
2663
2668 bool has_claim(const typename json_traits::string_type& name) const noexcept
2669 {
2670 return claims.count(name) != 0;
2671 }
2672
2680 basic_claim_t get_claim(const typename json_traits::string_type& name) const
2681 {
2682 if (!has_claim(name))
2684 return basic_claim_t{claims.at(name)};
2685 }
2686
2687 std::unordered_map<typename json_traits::string_type, basic_claim_t> get_claims() const
2688 {
2689 static_assert(details::is_valid_json_object<
2690 typename json_traits::value_type, typename json_traits::string_type,
2691 typename json_traits::object_type>::supports_claims_transform,
2692 "currently there is a limitation on the internal implemantation of the "
2693 "`object_type` to have an "
2694 "`std::pair` like `value_type`");
2695
2696 std::unordered_map<typename json_traits::string_type, basic_claim_t> res;
2697 std::transform(claims.begin(), claims.end(), std::inserter(res, res.end()),
2698 [](const typename json_traits::object_type::value_type& val)
2699 { return std::make_pair(val.first, basic_claim_t{val.second}); });
2700 return res;
2701 }
2702};
2703} // namespace details
2704
2709template <typename json_traits> class payload
2710{
2711 protected:
2713
2714 public:
2716
2721 bool has_issuer() const noexcept { return has_payload_claim("iss"); }
2726 bool has_subject() const noexcept { return has_payload_claim("sub"); }
2731 bool has_audience() const noexcept { return has_payload_claim("aud"); }
2736 bool has_expires_at() const noexcept { return has_payload_claim("exp"); }
2741 bool has_not_before() const noexcept { return has_payload_claim("nbf"); }
2746 bool has_issued_at() const noexcept { return has_payload_claim("iat"); }
2751 bool has_id() const noexcept { return has_payload_claim("jti"); }
2758 typename json_traits::string_type get_issuer() const
2759 {
2760 return get_payload_claim("iss").as_string();
2761 }
2768 typename json_traits::string_type get_subject() const
2769 {
2770 return get_payload_claim("sub").as_string();
2771 }
2779 {
2780 auto aud = get_payload_claim("aud");
2781 if (aud.get_type() == json::type::string)
2782 return {aud.as_string()};
2783
2784 return aud.as_set();
2785 }
2792 date get_expires_at() const { return get_payload_claim("exp").as_date(); }
2799 date get_not_before() const { return get_payload_claim("nbf").as_date(); }
2806 date get_issued_at() const { return get_payload_claim("iat").as_date(); }
2813 typename json_traits::string_type get_id() const
2814 {
2815 return get_payload_claim("jti").as_string();
2816 }
2821 bool has_payload_claim(const typename json_traits::string_type& name) const noexcept
2822 {
2823 return payload_claims.has_claim(name);
2824 }
2830 basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const
2831 {
2832 return payload_claims.get_claim(name);
2833 }
2834};
2835
2840template <typename json_traits> class header
2841{
2842 protected:
2844
2845 public:
2851 bool has_algorithm() const noexcept { return has_header_claim("alg"); }
2856 bool has_type() const noexcept { return has_header_claim("typ"); }
2861 bool has_content_type() const noexcept { return has_header_claim("cty"); }
2866 bool has_key_id() const noexcept { return has_header_claim("kid"); }
2873 typename json_traits::string_type get_algorithm() const
2874 {
2875 return get_header_claim("alg").as_string();
2876 }
2883 typename json_traits::string_type get_type() const
2884 {
2885 return get_header_claim("typ").as_string();
2886 }
2893 typename json_traits::string_type get_content_type() const
2894 {
2895 return get_header_claim("cty").as_string();
2896 }
2903 typename json_traits::string_type get_key_id() const
2904 {
2905 return get_header_claim("kid").as_string();
2906 }
2911 bool has_header_claim(const typename json_traits::string_type& name) const noexcept
2912 {
2913 return header_claims.has_claim(name);
2914 }
2920 basic_claim_t get_header_claim(const typename json_traits::string_type& name) const
2921 {
2922 return header_claims.get_claim(name);
2923 }
2924};
2925
2929template <typename json_traits>
2930class decoded_jwt : public header<json_traits>, public payload<json_traits>
2931{
2932 protected:
2934 const typename json_traits::string_type token;
2936 typename json_traits::string_type header;
2938 typename json_traits::string_type header_base64;
2940 typename json_traits::string_type payload;
2942 typename json_traits::string_type payload_base64;
2944 typename json_traits::string_type signature;
2946 typename json_traits::string_type signature_base64;
2947
2948 public:
2950#ifndef JWT_DISABLE_BASE64
2960 JWT_CLAIM_EXPLICIT decoded_jwt(const typename json_traits::string_type& token)
2961 : decoded_jwt(
2962 token, [](const typename json_traits::string_type& str)
2963 { return base::decode<alphabet::base64url>(base::pad<alphabet::base64url>(str)); })
2964 {
2965 }
2966#endif
2978 template <typename Decode>
2979 decoded_jwt(const typename json_traits::string_type& token, Decode decode) : token(token)
2980 {
2981 auto hdr_end = token.find('.');
2982 if (hdr_end == json_traits::string_type::npos)
2983 throw std::invalid_argument("invalid token supplied");
2984 auto payload_end = token.find('.', hdr_end + 1);
2985 if (payload_end == json_traits::string_type::npos)
2986 throw std::invalid_argument("invalid token supplied");
2987 header_base64 = token.substr(0, hdr_end);
2988 payload_base64 = token.substr(hdr_end + 1, payload_end - hdr_end - 1);
2989 signature_base64 = token.substr(payload_end + 1);
2990
2991 header = decode(header_base64);
2992 payload = decode(payload_base64);
2993 signature = decode(signature_base64);
2994
2997 }
2998
3003 const typename json_traits::string_type& get_token() const noexcept { return token; }
3008 const typename json_traits::string_type& get_header() const noexcept { return header; }
3013 const typename json_traits::string_type& get_payload() const noexcept { return payload; }
3018 const typename json_traits::string_type& get_signature() const noexcept { return signature; }
3023 const typename json_traits::string_type& get_header_base64() const noexcept
3024 {
3025 return header_base64;
3026 }
3031 const typename json_traits::string_type& get_payload_base64() const noexcept
3032 {
3033 return payload_base64;
3034 }
3039 const typename json_traits::string_type& get_signature_base64() const noexcept
3040 {
3041 return signature_base64;
3042 }
3047 std::unordered_map<typename json_traits::string_type, basic_claim_t> get_payload_claims() const
3048 {
3049 return this->payload_claims.get_claims();
3050 }
3055 std::unordered_map<typename json_traits::string_type, basic_claim_t> get_header_claims() const
3056 {
3057 return this->header_claims.get_claims();
3058 }
3066 basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const
3067 {
3068 return this->payload_claims.get_claim(name);
3069 }
3077 basic_claim_t get_header_claim(const typename json_traits::string_type& name) const
3078 {
3079 return this->header_claims.get_claim(name);
3080 }
3081};
3082
3087template <typename json_traits> class builder
3088{
3089 typename json_traits::object_type header_claims;
3090 typename json_traits::object_type payload_claims;
3091
3092 public:
3093 builder() = default;
3100 builder& set_header_claim(const typename json_traits::string_type& id,
3101 typename json_traits::value_type c)
3102 {
3103 header_claims[id] = std::move(c);
3104 return *this;
3105 }
3106
3113 builder& set_header_claim(const typename json_traits::string_type& id,
3115 {
3116 header_claims[id] = c.to_json();
3117 return *this;
3118 }
3125 builder& set_payload_claim(const typename json_traits::string_type& id,
3126 typename json_traits::value_type c)
3127 {
3128 payload_claims[id] = std::move(c);
3129 return *this;
3130 }
3137 builder& set_payload_claim(const typename json_traits::string_type& id,
3139 {
3140 payload_claims[id] = c.to_json();
3141 return *this;
3142 }
3150 builder& set_algorithm(typename json_traits::string_type str)
3151 {
3152 return set_header_claim("alg", typename json_traits::value_type(str));
3153 }
3159 builder& set_type(typename json_traits::string_type str)
3160 {
3161 return set_header_claim("typ", typename json_traits::value_type(str));
3162 }
3168 builder& set_content_type(typename json_traits::string_type str)
3169 {
3170 return set_header_claim("cty", typename json_traits::value_type(str));
3171 }
3178 builder& set_key_id(typename json_traits::string_type str)
3179 {
3180 return set_header_claim("kid", typename json_traits::value_type(str));
3181 }
3187 builder& set_issuer(typename json_traits::string_type str)
3188 {
3189 return set_payload_claim("iss", typename json_traits::value_type(str));
3190 }
3196 builder& set_subject(typename json_traits::string_type str)
3197 {
3198 return set_payload_claim("sub", typename json_traits::value_type(str));
3199 }
3205 builder& set_audience(typename json_traits::array_type a)
3206 {
3207 return set_payload_claim("aud", typename json_traits::value_type(a));
3208 }
3214 builder& set_audience(typename json_traits::string_type aud)
3215 {
3216 return set_payload_claim("aud", typename json_traits::value_type(aud));
3217 }
3224 {
3225 return set_payload_claim("exp", basic_claim<json_traits>(d));
3226 }
3233 {
3234 return set_payload_claim("nbf", basic_claim<json_traits>(d));
3235 }
3242 {
3243 return set_payload_claim("iat", basic_claim<json_traits>(d));
3244 }
3250 builder& set_id(const typename json_traits::string_type& str)
3251 {
3252 return set_payload_claim("jti", typename json_traits::value_type(str));
3253 }
3254
3266 template <typename Algo, typename Encode>
3267 typename json_traits::string_type sign(const Algo& algo, Encode encode) const
3268 {
3269 std::error_code ec;
3270 auto res = sign(algo, encode, ec);
3271 error::throw_if_error(ec);
3272 return res;
3273 }
3274#ifndef JWT_DISABLE_BASE64
3283 template <typename Algo> typename json_traits::string_type sign(const Algo& algo) const
3284 {
3285 std::error_code ec;
3286 auto res = sign(algo, ec);
3287 error::throw_if_error(ec);
3288 return res;
3289 }
3290#endif
3291
3304 template <typename Algo, typename Encode>
3305 typename json_traits::string_type sign(const Algo& algo, Encode encode,
3306 std::error_code& ec) const
3307 {
3308 // make a copy such that a builder can be re-used
3309 typename json_traits::object_type obj_header = header_claims;
3310 if (header_claims.count("alg") == 0)
3311 obj_header["alg"] = typename json_traits::value_type(algo.name());
3312
3313 const auto header =
3314 encode(json_traits::serialize(typename json_traits::value_type(obj_header)));
3315 const auto payload =
3316 encode(json_traits::serialize(typename json_traits::value_type(payload_claims)));
3317 const auto token = header + "." + payload;
3318
3319 auto signature = algo.sign(token, ec);
3320 if (ec)
3321 return {};
3322
3323 return token + "." + encode(signature);
3324 }
3325#ifndef JWT_DISABLE_BASE64
3335 template <typename Algo>
3336 typename json_traits::string_type sign(const Algo& algo, std::error_code& ec) const
3337 {
3338 return sign(
3339 algo,
3340 [](const typename json_traits::string_type& data)
3341 { return base::trim<alphabet::base64url>(base::encode<alphabet::base64url>(data)); },
3342 ec);
3343 }
3344#endif
3345};
3346
3347namespace verify_ops
3348{
3352template <typename json_traits> struct verify_context
3353{
3355 : current_time(ctime), jwt(j), default_leeway(l)
3356 {
3357 }
3358 // Current time, retrieved from the verifiers clock and cached for performance and consistency
3360 // The jwt passed to the verifier
3362 // The configured default leeway for this verification
3363 size_t default_leeway{0};
3364
3365 // The claim key to apply this comparision on
3366 typename json_traits::string_type claim_key{};
3367
3368 // Helper method to get a claim from the jwt in this context
3369 basic_claim<json_traits> get_claim(bool in_header, std::error_code& ec) const
3370 {
3371 if (in_header)
3372 {
3373 if (!jwt.has_header_claim(claim_key))
3374 {
3375 ec = error::token_verification_error::missing_claim;
3376 return {};
3377 }
3378 return jwt.get_header_claim(claim_key);
3379 }
3380 else
3381 {
3382 if (!jwt.has_payload_claim(claim_key))
3383 {
3384 ec = error::token_verification_error::missing_claim;
3385 return {};
3386 }
3387 return jwt.get_payload_claim(claim_key);
3388 }
3389 }
3390 basic_claim<json_traits> get_claim(bool in_header, json::type t, std::error_code& ec) const
3391 {
3392 auto c = get_claim(in_header, ec);
3393 if (ec)
3394 return {};
3395 if (c.get_type() != t)
3396 {
3397 ec = error::token_verification_error::claim_type_missmatch;
3398 return {};
3399 }
3400 return c;
3401 }
3402 basic_claim<json_traits> get_claim(std::error_code& ec) const { return get_claim(false, ec); }
3403 basic_claim<json_traits> get_claim(json::type t, std::error_code& ec) const
3404 {
3405 return get_claim(false, t, ec);
3406 }
3407};
3408
3412template <typename json_traits, bool in_header = false> struct equals_claim
3413{
3415 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const
3416 {
3417 auto jc = ctx.get_claim(in_header, expected.get_type(), ec);
3418 if (ec)
3419 return;
3420 const bool matches = [&]()
3421 {
3422 switch (expected.get_type())
3423 {
3424 case json::type::boolean: return expected.as_bool() == jc.as_bool();
3425 case json::type::integer: return expected.as_int() == jc.as_int();
3426 case json::type::number: return expected.as_number() == jc.as_number();
3427 case json::type::string: return expected.as_string() == jc.as_string();
3428 case json::type::array:
3429 case json::type::object:
3430 return json_traits::serialize(expected.to_json()) ==
3431 json_traits::serialize(jc.to_json());
3432 default: throw std::logic_error("internal error, should be unreachable");
3433 }
3434 }();
3435 if (!matches)
3436 {
3437 ec = error::token_verification_error::claim_value_missmatch;
3438 return;
3439 }
3440 }
3441};
3442
3447template <typename json_traits, bool in_header = false> struct date_before_claim
3448{
3449 const size_t leeway;
3450 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const
3451 {
3452 auto jc = ctx.get_claim(in_header, json::type::integer, ec);
3453 if (ec)
3454 return;
3455 auto c = jc.as_date();
3456 if (ctx.current_time > c + std::chrono::seconds(leeway))
3457 {
3458 ec = error::token_verification_error::token_expired;
3459 }
3460 }
3461};
3462
3467template <typename json_traits, bool in_header = false> struct date_after_claim
3468{
3469 const size_t leeway;
3470 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const
3471 {
3472 auto jc = ctx.get_claim(in_header, json::type::integer, ec);
3473 if (ec)
3474 return;
3475 auto c = jc.as_date();
3476 if (ctx.current_time < c - std::chrono::seconds(leeway))
3477 {
3478 ec = error::token_verification_error::token_expired;
3479 }
3480 }
3481};
3482
3488template <typename json_traits, bool in_header = false> struct is_subset_claim
3489{
3491 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const
3492 {
3493 auto c = ctx.get_claim(in_header, ec);
3494 if (ec)
3495 return;
3496 if (c.get_type() == json::type::string)
3497 {
3498 if (expected.size() != 1 || *expected.begin() != c.as_string())
3499 {
3500 ec = error::token_verification_error::audience_missmatch;
3501 return;
3502 }
3503 }
3504 else if (c.get_type() == json::type::array)
3505 {
3506 auto jc = c.as_set();
3507 for (auto& e : expected)
3508 {
3509 if (jc.find(e) == jc.end())
3510 {
3511 ec = error::token_verification_error::audience_missmatch;
3512 return;
3513 }
3514 }
3515 }
3516 else
3517 {
3518 ec = error::token_verification_error::claim_type_missmatch;
3519 return;
3520 }
3521 }
3522};
3523
3527template <typename json_traits, bool in_header = false> struct insensitive_string_claim
3528{
3529 const typename json_traits::string_type expected;
3530 std::locale locale;
3531 insensitive_string_claim(const typename json_traits::string_type& e, std::locale loc)
3532 : expected(to_lower_unicode(e, loc)), locale(loc)
3533 {
3534 }
3535
3536 void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const
3537 {
3538 const auto c = ctx.get_claim(in_header, json::type::string, ec);
3539 if (ec)
3540 return;
3541 if (to_lower_unicode(c.as_string(), locale) != expected)
3542 {
3543 ec = error::token_verification_error::claim_value_missmatch;
3544 }
3545 }
3546
3547 static std::string to_lower_unicode(const std::string& str, const std::locale& loc)
3548 {
3549 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> conv;
3550 auto wide = conv.from_bytes(str);
3551 auto& f = std::use_facet<std::ctype<wchar_t>>(loc);
3552 f.tolower(&wide[0], &wide[0] + wide.size());
3553 return conv.to_bytes(wide);
3554 }
3555};
3556} // namespace verify_ops
3557
3562template <typename Clock, typename json_traits> class verifier
3563{
3564 public:
3576 std::function<void(const verify_ops::verify_context<json_traits>&, std::error_code& ec)>;
3577
3578 private:
3579 struct algo_base
3580 {
3581 virtual ~algo_base() = default;
3582 virtual void verify(const std::string& data, const std::string& sig,
3583 std::error_code& ec) = 0;
3584 };
3585 template <typename T> struct algo : public algo_base
3586 {
3587 T alg;
3588 explicit algo(T a) : alg(a) {}
3589 void verify(const std::string& data, const std::string& sig, std::error_code& ec) override
3590 {
3591 alg.verify(data, sig, ec);
3592 }
3593 };
3595 std::unordered_map<typename json_traits::string_type, verify_check_fn_t> claims;
3597 size_t default_leeway = 0;
3599 Clock clock;
3601 std::unordered_map<std::string, std::shared_ptr<algo_base>> algs;
3602
3603 public:
3608 explicit verifier(Clock c) : clock(c)
3609 {
3610 claims["exp"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec)
3611 {
3612 if (!ctx.jwt.has_expires_at())
3613 return;
3614 auto exp = ctx.jwt.get_expires_at();
3615 if (ctx.current_time > exp + std::chrono::seconds(ctx.default_leeway))
3616 {
3617 ec = error::token_verification_error::token_expired;
3618 }
3619 };
3620 claims["iat"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec)
3621 {
3622 if (!ctx.jwt.has_issued_at())
3623 return;
3624 auto iat = ctx.jwt.get_issued_at();
3625 if (ctx.current_time < iat - std::chrono::seconds(ctx.default_leeway))
3626 {
3627 ec = error::token_verification_error::token_expired;
3628 }
3629 };
3630 claims["nbf"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec)
3631 {
3632 if (!ctx.jwt.has_not_before())
3633 return;
3634 auto nbf = ctx.jwt.get_not_before();
3635 if (ctx.current_time < nbf - std::chrono::seconds(ctx.default_leeway))
3636 {
3637 ec = error::token_verification_error::token_expired;
3638 }
3639 };
3640 }
3641
3647 verifier& leeway(size_t leeway)
3648 {
3649 default_leeway = leeway;
3650 return *this;
3651 }
3659 {
3660 claims["exp"] = verify_ops::date_before_claim<json_traits>{leeway};
3661 return *this;
3662 }
3670 {
3671 claims["nbf"] = verify_ops::date_after_claim<json_traits>{leeway};
3672 return *this;
3673 }
3681 {
3682 claims["iat"] = verify_ops::date_after_claim<json_traits>{leeway};
3683 return *this;
3684 }
3685
3697 verifier& with_type(const typename json_traits::string_type& type,
3698 std::locale locale = std::locale{})
3699 {
3701 type, std::move(locale)});
3702 }
3703
3710 verifier& with_issuer(const typename json_traits::string_type& iss)
3711 {
3712 return with_claim("iss", basic_claim_t(iss));
3713 }
3714
3721 verifier& with_subject(const typename json_traits::string_type& sub)
3722 {
3723 return with_claim("sub", basic_claim_t(sub));
3724 }
3732 {
3733 claims["aud"] = verify_ops::is_subset_claim<json_traits>{aud};
3734 return *this;
3735 }
3742 verifier& with_audience(const typename json_traits::string_type& aud)
3743 {
3744 typename basic_claim_t::set_t s;
3745 s.insert(aud);
3746 return with_audience(s);
3747 }
3754 verifier& with_id(const typename json_traits::string_type& id)
3755 {
3756 return with_claim("jti", basic_claim_t(id));
3757 }
3758
3765 verifier& with_claim(const typename json_traits::string_type& name, verify_check_fn_t fn)
3766 {
3767 claims[name] = fn;
3768 return *this;
3769 }
3770
3777 verifier& with_claim(const typename json_traits::string_type& name, basic_claim_t c)
3778 {
3779 return with_claim(name, verify_ops::equals_claim<json_traits>{c});
3780 }
3781
3787 template <typename Algorithm> verifier& allow_algorithm(Algorithm alg)
3788 {
3789 algs[alg.name()] = std::make_shared<algo<Algorithm>>(alg);
3790 return *this;
3791 }
3792
3799 {
3800 std::error_code ec;
3801 verify(jwt, ec);
3802 error::throw_if_error(ec);
3803 }
3809 void verify(const decoded_jwt<json_traits>& jwt, std::error_code& ec) const
3810 {
3811 ec.clear();
3812 const typename json_traits::string_type data =
3813 jwt.get_header_base64() + "." + jwt.get_payload_base64();
3814 const typename json_traits::string_type sig = jwt.get_signature();
3815 const std::string algo = jwt.get_algorithm();
3816 if (algs.count(algo) == 0)
3817 {
3818 ec = error::token_verification_error::wrong_algorithm;
3819 return;
3820 }
3821 algs.at(algo)->verify(data, sig, ec);
3822 if (ec)
3823 return;
3824
3825 verify_ops::verify_context<json_traits> ctx{clock.now(), jwt, default_leeway};
3826 for (auto& c : claims)
3827 {
3828 ctx.claim_key = c.first;
3829 c.second(ctx, ec);
3830 if (ec)
3831 return;
3832 }
3833 }
3834};
3835
3844template <typename json_traits> class jwk
3845{
3847 const details::map_of_claims<json_traits> jwk_claims;
3848
3849 public:
3850 JWT_CLAIM_EXPLICIT jwk(const typename json_traits::string_type& str)
3851 : jwk_claims(details::map_of_claims<json_traits>::parse_claims(str))
3852 {
3853 }
3854
3855 JWT_CLAIM_EXPLICIT jwk(const typename json_traits::value_type& json)
3856 : jwk_claims(json_traits::as_object(json))
3857 {
3858 }
3859
3868 typename json_traits::string_type get_key_type() const
3869 {
3870 return get_jwk_claim("kty").as_string();
3871 }
3872
3879 typename json_traits::string_type get_use() const { return get_jwk_claim("use").as_string(); }
3880
3888 {
3889 return get_jwk_claim("key_ops").as_set();
3890 }
3891
3898 typename json_traits::string_type get_algorithm() const
3899 {
3900 return get_jwk_claim("alg").as_string();
3901 }
3902
3909 typename json_traits::string_type get_key_id() const
3910 {
3911 return get_jwk_claim("kid").as_string();
3912 }
3913
3924 typename json_traits::string_type get_curve() const { return get_jwk_claim("crv").as_string(); }
3925
3932 typename json_traits::array_type get_x5c() const { return get_jwk_claim("x5c").as_array(); };
3933
3940 typename json_traits::string_type get_x5u() const { return get_jwk_claim("x5u").as_string(); };
3941
3948 typename json_traits::string_type get_x5t() const { return get_jwk_claim("x5t").as_string(); };
3949
3956 typename json_traits::string_type get_x5t_sha256() const
3957 {
3958 return get_jwk_claim("x5t#S256").as_string();
3959 };
3960
3967 typename json_traits::string_type get_x5c_key_value() const
3968 {
3969 auto x5c_array = get_jwk_claim("x5c").as_array();
3970 if (x5c_array.size() == 0)
3972
3973 return json_traits::as_string(x5c_array.front());
3974 };
3975
3980 bool has_key_type() const noexcept { return has_jwk_claim("kty"); }
3981
3986 bool has_use() const noexcept { return has_jwk_claim("use"); }
3987
3992 bool has_key_operations() const noexcept { return has_jwk_claim("key_ops"); }
3993
3998 bool has_algorithm() const noexcept { return has_jwk_claim("alg"); }
3999
4004 bool has_curve() const noexcept { return has_jwk_claim("crv"); }
4005
4010 bool has_key_id() const noexcept { return has_jwk_claim("kid"); }
4011
4016 bool has_x5u() const noexcept { return has_jwk_claim("x5u"); }
4017
4022 bool has_x5c() const noexcept { return has_jwk_claim("x5c"); }
4023
4028 bool has_x5t() const noexcept { return has_jwk_claim("x5t"); }
4029
4034 bool has_x5t_sha256() const noexcept { return has_jwk_claim("x5t#S256"); }
4035
4040 bool has_jwk_claim(const typename json_traits::string_type& name) const noexcept
4041 {
4042 return jwk_claims.has_claim(name);
4043 }
4044
4050 basic_claim_t get_jwk_claim(const typename json_traits::string_type& name) const
4051 {
4052 return jwk_claims.get_claim(name);
4053 }
4054
4055 bool empty() const noexcept { return jwk_claims.empty(); }
4056};
4057
4068template <typename json_traits> class jwks
4069{
4070 public:
4072 using jwt_vector_t = std::vector<jwk_t>;
4073 using iterator = typename jwt_vector_t::iterator;
4074 using const_iterator = typename jwt_vector_t::const_iterator;
4075
4076 JWT_CLAIM_EXPLICIT jwks(const typename json_traits::string_type& str)
4077 {
4078 typename json_traits::value_type parsed_val;
4079 if (!json_traits::parse(parsed_val, str))
4081
4082 const details::map_of_claims<json_traits> jwks_json = json_traits::as_object(parsed_val);
4083 if (!jwks_json.has_claim("keys"))
4085
4086 auto jwk_list = jwks_json.get_claim("keys").as_array();
4087 std::transform(jwk_list.begin(), jwk_list.end(), std::back_inserter(jwk_claims),
4088 [](const typename json_traits::value_type& val) { return jwk_t{val}; });
4089 }
4090
4091 iterator begin() { return jwk_claims.begin(); }
4092 iterator end() { return jwk_claims.end(); }
4093 const_iterator cbegin() const { return jwk_claims.begin(); }
4094 const_iterator cend() const { return jwk_claims.end(); }
4095 const_iterator begin() const { return jwk_claims.begin(); }
4096 const_iterator end() const { return jwk_claims.end(); }
4097
4102 bool has_jwk(const typename json_traits::string_type& key_id) const noexcept
4103 {
4104 return find_by_kid(key_id) != end();
4105 }
4106
4112 jwk_t get_jwk(const typename json_traits::string_type& key_id) const
4113 {
4114 const auto maybe = find_by_kid(key_id);
4115 if (maybe == end())
4117 return *maybe;
4118 }
4119
4120 private:
4121 jwt_vector_t jwk_claims;
4122
4123 const_iterator find_by_kid(const typename json_traits::string_type& key_id) const noexcept
4124 {
4125 return std::find_if(cbegin(), cend(),
4126 [key_id](const jwk_t& jwk)
4127 {
4128 if (!jwk.has_key_id())
4129 {
4130 return false;
4131 }
4132 return jwk.get_key_id() == key_id;
4133 });
4134 }
4135};
4136
4142template <typename Clock, typename json_traits> verifier<Clock, json_traits> verify(Clock c)
4143{
4145}
4146
4151{
4152 date now() const { return date::clock::now(); }
4153};
4154
4160template <typename json_traits> verifier<default_clock, json_traits> verify(default_clock c = {})
4161{
4162 return verifier<default_clock, json_traits>(c);
4163}
4164
4168template <typename json_traits> builder<json_traits> create() { return builder<json_traits>(); }
4169
4178template <typename json_traits, typename Decode>
4179decoded_jwt<json_traits> decode(const typename json_traits::string_type& token, Decode decode)
4180{
4181 return decoded_jwt<json_traits>(token, decode);
4182}
4183
4191template <typename json_traits>
4192decoded_jwt<json_traits> decode(const typename json_traits::string_type& token)
4193{
4194 return decoded_jwt<json_traits>(token);
4195}
4196
4197template <typename json_traits>
4198jwk<json_traits> parse_jwk(const typename json_traits::string_type& token)
4199{
4200 return jwk<json_traits>(token);
4201}
4202
4203template <typename json_traits>
4204jwks<json_traits> parse_jwks(const typename json_traits::string_type& token)
4205{
4206 return jwks<json_traits>(token);
4207}
4208} // namespace jwt
4209
4210template <typename json_traits>
4211std::istream& operator>>(std::istream& is, jwt::basic_claim<json_traits>& c)
4212{
4213 return c.operator>>(is);
4214}
4215
4216template <typename json_traits>
4217std::ostream& operator<<(std::ostream& os, const jwt::basic_claim<json_traits>& c)
4218{
4219 return os << c.to_json();
4220}
4221
4222#ifndef JWT_DISABLE_PICOJSON
4223#include "traits/kazuho-picojson/defaults.h"
4224#endif
4225
4226#endif
a class to store a generic JSON value as claim
Definition jwt.h:2474
basic_claim & operator=(basic_claim &&)=default
~basic_claim()=default
basic_claim(basic_claim &&)=default
json_traits::number_type as_number() const
Definition jwt.h:2599
set_t as_set() const
Definition jwt.h:2573
json_traits::integer_type as_int() const
Definition jwt.h:2585
basic_claim & operator=(const basic_claim &)=default
basic_claim(const basic_claim &)=default
json::type get_type() const
Definition jwt.h:2545
json_traits::boolean_type as_bool() const
Definition jwt.h:2592
basic_claim(Iterator begin, Iterator end)
Definition jwt.h:2518
std::set< typename json_traits::string_type > set_t
Definition jwt.h:2497
JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::string_type s)
Definition jwt.h:2506
std::istream & operator>>(std::istream &is)
Definition jwt.h:2532
JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::array_type a)
Definition jwt.h:2511
date as_date() const
Definition jwt.h:2559
JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::value_type v)
Definition jwt.h:2512
std::ostream & operator<<(std::ostream &os)
Definition jwt.h:2538
JWT_CLAIM_EXPLICIT basic_claim(const set_t &s)
Definition jwt.h:2513
json_traits::value_type to_json() const
Definition jwt.h:2526
basic_claim()=default
json_traits::array_type as_array() const
Definition jwt.h:2566
JWT_CLAIM_EXPLICIT basic_claim(const date &d)
Definition jwt.h:2507
json_traits::string_type as_string() const
Definition jwt.h:2552
builder & set_payload_claim(const typename json_traits::string_type &id, typename json_traits::value_type c)
Definition jwt.h:3125
json_traits::string_type sign(const Algo &algo) const
Definition jwt.h:3283
json_traits::string_type sign(const Algo &algo, Encode encode) const
Definition jwt.h:3267
builder & set_audience(typename json_traits::string_type aud)
Definition jwt.h:3214
builder & set_audience(typename json_traits::array_type a)
Definition jwt.h:3205
builder & set_header_claim(const typename json_traits::string_type &id, basic_claim< json_traits > c)
Definition jwt.h:3113
builder()=default
builder & set_payload_claim(const typename json_traits::string_type &id, basic_claim< json_traits > c)
Definition jwt.h:3137
builder & set_subject(typename json_traits::string_type str)
Definition jwt.h:3196
builder & set_content_type(typename json_traits::string_type str)
Definition jwt.h:3168
builder & set_not_before(const date &d)
Definition jwt.h:3232
builder & set_issued_at(const date &d)
Definition jwt.h:3241
builder & set_id(const typename json_traits::string_type &str)
Definition jwt.h:3250
builder & set_type(typename json_traits::string_type str)
Definition jwt.h:3159
builder & set_key_id(typename json_traits::string_type str)
Set key id claim.
Definition jwt.h:3178
builder & set_issuer(typename json_traits::string_type str)
Definition jwt.h:3187
builder & set_header_claim(const typename json_traits::string_type &id, typename json_traits::value_type c)
Definition jwt.h:3100
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:3150
json_traits::string_type sign(const Algo &algo, std::error_code &ec) const
Definition jwt.h:3336
builder & set_expires_at(const date &d)
Definition jwt.h:3223
json_traits::string_type sign(const Algo &algo, Encode encode, std::error_code &ec) const
Definition jwt.h:3305
const json_traits::string_type & get_header() const noexcept
Definition jwt.h:3008
const json_traits::string_type & get_signature_base64() const noexcept
Definition jwt.h:3039
json_traits::string_type signature
Signature part decoded from base64.
Definition jwt.h:2944
std::unordered_map< typename json_traits::string_type, basic_claim_t > get_header_claims() const
Definition jwt.h:3055
json_traits::string_type header
Header part decoded from base64.
Definition jwt.h:2936
json_traits::string_type header_base64
Unmodified header part in base64.
Definition jwt.h:2938
basic_claim_t get_payload_claim(const typename json_traits::string_type &name) const
Definition jwt.h:3066
const json_traits::string_type & get_signature() const noexcept
Definition jwt.h:3018
JWT_CLAIM_EXPLICIT decoded_jwt(const typename json_traits::string_type &token)
Parses a given token.
Definition jwt.h:2960
std::unordered_map< typename json_traits::string_type, basic_claim_t > get_payload_claims() const
Definition jwt.h:3047
basic_claim_t get_header_claim(const typename json_traits::string_type &name) const
Definition jwt.h:3077
decoded_jwt(const typename json_traits::string_type &token, Decode decode)
Parses a given token.
Definition jwt.h:2979
json_traits::string_type signature_base64
Unmodified signature part in base64.
Definition jwt.h:2946
const json_traits::string_type token
Unmodifed token, as passed to constructor.
Definition jwt.h:2934
const json_traits::string_type & get_payload_base64() const noexcept
Definition jwt.h:3031
const json_traits::string_type & get_token() const noexcept
Definition jwt.h:3003
const json_traits::string_type & get_payload() const noexcept
Definition jwt.h:3013
const json_traits::string_type & get_header_base64() const noexcept
Definition jwt.h:3023
json_traits::string_type payload_base64
Unmodified payload part in base64.
Definition jwt.h:2942
json_traits::string_type payload
Payload part decoded from base64.
Definition jwt.h:2940
map_of_claims & operator=(const map_of_claims &)=default
basic_claim_t get_claim(const typename json_traits::string_type &name) const
Definition jwt.h:2680
bool has_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:2668
std::unordered_map< typename json_traits::string_type, basic_claim_t > get_claims() const
Definition jwt.h:2687
typename json_traits::object_type::const_iterator const_iterator
Definition jwt.h:2629
const_iterator cbegin() const
Definition jwt.h:2641
const_iterator begin() const
Definition jwt.h:2643
static json_traits::object_type parse_claims(const typename json_traits::string_type &str)
Parse a JSON string into a map of claims.
Definition jwt.h:2655
typename json_traits::object_type::iterator iterator
Definition jwt.h:2628
map_of_claims & operator=(map_of_claims &&)=default
map_of_claims(typename json_traits::object_type json)
Definition jwt.h:2637
map_of_claims(map_of_claims &&)=default
const_iterator cend() const
Definition jwt.h:2642
const_iterator end() const
Definition jwt.h:2644
map_of_claims(const map_of_claims &)=default
json_traits::string_type get_type() const
Definition jwt.h:2883
bool has_header_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:2911
details::map_of_claims< json_traits > header_claims
Definition jwt.h:2843
bool has_algorithm() const noexcept
Definition jwt.h:2851
bool has_type() const noexcept
Definition jwt.h:2856
json_traits::string_type get_algorithm() const
Definition jwt.h:2873
bool has_content_type() const noexcept
Definition jwt.h:2861
basic_claim_t get_header_claim(const typename json_traits::string_type &name) const
Definition jwt.h:2920
json_traits::string_type get_key_id() const
Definition jwt.h:2903
json_traits::string_type get_content_type() const
Definition jwt.h:2893
bool has_key_id() const noexcept
Definition jwt.h:2866
JSON Web Key.
Definition jwt.h:3845
bool has_x5c() const noexcept
Definition jwt.h:4022
json_traits::string_type get_curve() const
Get curve claim.
Definition jwt.h:3924
bool has_x5t_sha256() const noexcept
Definition jwt.h:4034
JWT_CLAIM_EXPLICIT jwk(const typename json_traits::string_type &str)
Definition jwt.h:3850
json_traits::string_type get_algorithm() const
Definition jwt.h:3898
json_traits::array_type get_x5c() const
Definition jwt.h:3932
json_traits::string_type get_x5t() const
Definition jwt.h:3948
json_traits::string_type get_x5c_key_value() const
Definition jwt.h:3967
json_traits::string_type get_x5t_sha256() const
Definition jwt.h:3956
json_traits::string_type get_key_id() const
Definition jwt.h:3909
bool has_algorithm() const noexcept
Definition jwt.h:3998
json_traits::string_type get_use() const
Definition jwt.h:3879
bool has_key_id() const noexcept
Definition jwt.h:4010
bool has_x5u() const noexcept
Definition jwt.h:4016
bool has_key_operations() const noexcept
Definition jwt.h:3992
bool empty() const noexcept
Definition jwt.h:4055
bool has_use() const noexcept
Definition jwt.h:3986
bool has_x5t() const noexcept
Definition jwt.h:4028
bool has_jwk_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:4040
basic_claim_t::set_t get_key_operations() const
Definition jwt.h:3887
bool has_curve() const noexcept
Definition jwt.h:4004
bool has_key_type() const noexcept
Definition jwt.h:3980
basic_claim_t get_jwk_claim(const typename json_traits::string_type &name) const
Definition jwt.h:4050
json_traits::string_type get_x5u() const
Definition jwt.h:3940
JWT_CLAIM_EXPLICIT jwk(const typename json_traits::value_type &json)
Definition jwt.h:3855
json_traits::string_type get_key_type() const
Definition jwt.h:3868
JWK Set.
Definition jwt.h:4069
const_iterator cend() const
Definition jwt.h:4094
const_iterator cbegin() const
Definition jwt.h:4093
typename jwt_vector_t::const_iterator const_iterator
Definition jwt.h:4074
std::vector< jwk_t > jwt_vector_t
Definition jwt.h:4072
const_iterator end() const
Definition jwt.h:4096
const_iterator begin() const
Definition jwt.h:4095
jwk_t get_jwk(const typename json_traits::string_type &key_id) const
Definition jwt.h:4112
typename jwt_vector_t::iterator iterator
Definition jwt.h:4073
JWT_CLAIM_EXPLICIT jwks(const typename json_traits::string_type &str)
Definition jwt.h:4076
iterator end()
Definition jwt.h:4092
bool has_jwk(const typename json_traits::string_type &key_id) const noexcept
Definition jwt.h:4102
iterator begin()
Definition jwt.h:4091
basic_claim_t::set_t get_audience() const
Definition jwt.h:2778
json_traits::string_type get_id() const
Definition jwt.h:2813
bool has_issued_at() const noexcept
Definition jwt.h:2746
bool has_not_before() const noexcept
Definition jwt.h:2741
bool has_payload_claim(const typename json_traits::string_type &name) const noexcept
Definition jwt.h:2821
bool has_subject() const noexcept
Definition jwt.h:2726
details::map_of_claims< json_traits > payload_claims
Definition jwt.h:2712
date get_not_before() const
Definition jwt.h:2799
bool has_issuer() const noexcept
Definition jwt.h:2721
bool has_id() const noexcept
Definition jwt.h:2751
bool has_expires_at() const noexcept
Definition jwt.h:2736
date get_issued_at() const
Definition jwt.h:2806
basic_claim_t get_payload_claim(const typename json_traits::string_type &name) const
Definition jwt.h:2830
bool has_audience() const noexcept
Definition jwt.h:2731
date get_expires_at() const
Definition jwt.h:2792
json_traits::string_type get_subject() const
Definition jwt.h:2768
json_traits::string_type get_issuer() const
Definition jwt.h:2758
verifier & expires_at_leeway(size_t leeway)
Definition jwt.h:3658
std::function< void(const verify_ops::verify_context< json_traits > &, std::error_code &ec)> verify_check_fn_t
Definition jwt.h:3576
verifier & with_claim(const typename json_traits::string_type &name, verify_check_fn_t fn)
Definition jwt.h:3765
void verify(const decoded_jwt< json_traits > &jwt, std::error_code &ec) const
Definition jwt.h:3809
verifier & not_before_leeway(size_t leeway)
Definition jwt.h:3669
verifier & issued_at_leeway(size_t leeway)
Definition jwt.h:3680
verifier & with_subject(const typename json_traits::string_type &sub)
Definition jwt.h:3721
verifier & with_audience(const typename basic_claim_t::set_t &aud)
Definition jwt.h:3731
verifier & with_claim(const typename json_traits::string_type &name, basic_claim_t c)
Definition jwt.h:3777
verifier & with_audience(const typename json_traits::string_type &aud)
Definition jwt.h:3742
void verify(const decoded_jwt< json_traits > &jwt) const
Definition jwt.h:3798
verifier(Clock c)
Definition jwt.h:3608
verifier & leeway(size_t leeway)
Definition jwt.h:3647
verifier & with_issuer(const typename json_traits::string_type &iss)
Definition jwt.h:3710
verifier & allow_algorithm(Algorithm alg)
Definition jwt.h:3787
verifier & with_type(const typename json_traits::string_type &type, std::locale locale=std::locale{})
Definition jwt.h:3697
verifier & with_id(const typename json_traits::string_type &id)
Definition jwt.h:3754
nlohmann::json json
#define JWT_CLAIM_EXPLICIT
Definition jwt.h:64
std::istream & operator>>(std::istream &is, jwt::basic_claim< json_traits > &c)
Definition jwt.h:4211
decltype(traits_type::as_bool) as_boolean_function
Definition jwt.h:2225
typename std::is_same< decltype(std::operator+(std::declval< string_type >(), std::declval< string_type >())), string_type > is_std_operate_plus_signature
Definition jwt.h:2425
decltype(traits_type::as_int) as_integer_function
Definition jwt.h:2208
typename detector< nonesuch, void, Op, Args... >::type is_detected_t
Definition jwt.h:2132
typename std::is_same< decltype(std::declval< object_type >().begin()), has_iterator< object_type > > is_begin_signature
Definition jwt.h:2305
typename make_void< Ts... >::type void_t
Definition jwt.h:2093
decltype(traits_type::as_array) as_array_function
Definition jwt.h:2163
typename std::is_same< as_boolean_function< traits_type >, boolean_type(const value_type &)> is_as_boolean_signature
Definition jwt.h:2229
decltype(traits_type::as_string) as_string_function
Definition jwt.h:2177
typename std::is_same< as_object_function< traits_type >, object_type(const value_type &)> is_as_object_signature
Definition jwt.h:2152
typename std::is_same< decltype(std::declval< const object_type >().at(std::declval< const string_type >())), const value_type & > is_at_const_signature
Definition jwt.h:2370
typename std::is_same< decltype(std::declval< const object_type >().begin()), has_const_iterator< object_type > > is_begin_const_signature
Definition jwt.h:2310
typename traits_type::key_type has_key_type
Definition jwt.h:2295
typename std::is_same< decltype(std::declval< object_type >().end()), has_iterator< object_type > > is_end_signature
Definition jwt.h:2322
typename traits_type::value_type has_value_type
Definition jwt.h:2297
typename std::is_same< as_integer_function< traits_type >, integer_type(const value_type &)> is_as_integer_signature
Definition jwt.h:2212
typename object_type::iterator has_iterator
Definition jwt.h:2299
typename object_type::const_iterator has_const_iterator
Definition jwt.h:2301
typename std::is_same< get_type_function< traits_type >, json::type(const value_type &)> is_get_type_signature
Definition jwt.h:2139
typename std::is_same< as_array_function< traits_type >, array_type(const value_type &)> is_as_array_signature
Definition jwt.h:2167
typename std::is_same< decltype(std::declval< string_type >().substr(std::declval< integer_type >())), string_type > is_substr_start_index_signature
Definition jwt.h:2405
decltype(traits_type::get_type) get_type_function
Definition jwt.h:2135
decltype(traits_type::as_object) as_object_function
Definition jwt.h:2148
decltype(traits_type::as_number) as_number_function
Definition jwt.h:2192
typename std::is_same< decltype(std::declval< const object_type >().end()), has_const_iterator< object_type > > is_end_const_signature
Definition jwt.h:2327
typename std::is_integral< decltype(std::declval< const object_type >().count(std::declval< const string_type >()))> is_count_signature
Definition jwt.h:2340
typename std::is_same< decltype(std::declval< string_type >().substr(std::declval< integer_type >(), std::declval< integer_type >())), string_type > is_substr_start_end_index_signature
Definition jwt.h:2401
typename std::is_same< as_string_function< traits_type >, string_type(const value_type &)> is_as_string_signature
Definition jwt.h:2181
typename traits_type::mapped_type has_mapped_type
Definition jwt.h:2293
typename std::is_same< as_number_function< traits_type >, number_type(const value_type &)> is_as_number_signature
Definition jwt.h:2196
signature_verification_error
Errors related to verification of signatures.
Definition jwt.h:211
std::error_category & token_verification_error_category()
Error category for token verification errors.
Definition jwt.h:355
void throw_if_error(std::error_code ec)
Definition jwt.h:389
std::error_category & ecdsa_error_category()
Error category for ECDSA errors.
Definition jwt.h:175
std::error_category & signature_verification_error_category()
Error category for verification errors.
Definition jwt.h:225
std::error_category & rsa_error_category()
Error category for RSA errors.
Definition jwt.h:125
std::error_category & signature_generation_error_category()
Error category for signature generation errors.
Definition jwt.h:288
ecdsa_error
Errors related to processing of RSA signatures.
Definition jwt.h:162
rsa_error
Errors related to processing of RSA signatures.
Definition jwt.h:110
signature_generation_error
Errors related to signature generation errors.
Definition jwt.h:268
token_verification_error
Errors related to token verification errors.
Definition jwt.h:343
std::error_code make_error_code(rsa_error e)
Definition jwt.h:154
std::shared_ptr< EVP_PKEY > 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:823
std::shared_ptr< EVP_PKEY > 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:700
std::shared_ptr< EVP_PKEY > 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:752
std::shared_ptr< EVP_PKEY > 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:629
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:451
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:530
std::string bn2raw(const BIGNUM *bn)
Definition jwt.h:877
std::unique_ptr< BIGNUM, decltype(&BN_free)> raw2bn(const std::string &raw)
Definition jwt.h:890
type
Generic JSON types used in JWTs.
Definition jwt.h:2072
JSON Web Token.
Definition base.h:19
verifier< Clock, json_traits > verify(Clock c)
Definition jwt.h:4142
jwk< json_traits > parse_jwk(const typename json_traits::string_type &token)
Definition jwt.h:4198
jwks< json_traits > parse_jwks(const typename json_traits::string_type &token)
Definition jwt.h:4204
std::chrono::system_clock::time_point date
Definition jwt.h:79
decoded_jwt< json_traits > decode(const typename json_traits::string_type &token, Decode decode)
Definition jwt.h:4179
builder< json_traits > create()
Definition jwt.h:4168
STL namespace.
Base class for ECDSA family of algorithms.
Definition jwt.h:1153
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1247
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1198
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:1165
std::string name() const
Definition jwt.h:1303
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:1964
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:1990
Base class for EdDSA family of algorithms.
Definition jwt.h:1447
std::string name() const
Definition jwt.h:1592
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:1458
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1480
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1540
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:1871
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:1936
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:1893
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:1915
Base class for HMAC family of algorithms.
Definition jwt.h:948
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:965
std::string name() const
Definition jwt.h:1011
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:988
hmacsha(std::string key, const EVP_MD *(*md)(), std::string name)
Definition jwt.h:955
hs256(std::string key)
Definition jwt.h:1773
hs384(std::string key)
Definition jwt.h:1784
hs512(std::string key)
Definition jwt.h:1795
"none" algorithm.
Definition jwt.h:916
void verify(const std::string &, const std::string &signature, std::error_code &ec) const
Check if the given signature is empty.
Definition jwt.h:932
std::string name() const
Get algorithm name.
Definition jwt.h:942
std::string sign(const std::string &, std::error_code &ec) const
Return an empty string.
Definition jwt.h:920
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:2011
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:2031
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:2051
Base class for PSS-RSA family of algorithms.
Definition jwt.h:1605
std::string name() const
Definition jwt.h:1753
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:1615
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1700
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1638
rs256(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:1809
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:1829
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:1849
Base class for RSA family of algorithms.
Definition jwt.h:1025
void verify(const std::string &data, const std::string &signature, std::error_code &ec) const
Definition jwt.h:1101
std::string sign(const std::string &data, std::error_code &ec) const
Definition jwt.h:1057
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:1035
std::string name() const
Definition jwt.h:1139
date now() const
Definition jwt.h:4152
std::false_type value
Definition jwt.h:2117
static auto test_operator_plus(int) -> sfinae_true< decltype(std::declval< T >().operator+(std::declval< A0 >()))>
static auto test_operator_plus(long) -> std::false_type
static constexpr auto value
Definition jwt.h:2418
static constexpr auto value
Definition jwt.h:2353
static auto test_operator_plus(int) -> sfinae_true< decltype(std::declval< T >().operator[](std::declval< A0 >()))>
static auto test_operator_plus(long) -> std::false_type
static constexpr auto has_subscription_operator
Definition jwt.h:2359
static constexpr auto value
Definition jwt.h:2394
static constexpr auto supports_claims_transform
Definition jwt.h:2386
static constexpr auto value
Definition jwt.h:2375
static constexpr auto operator_plus
Definition jwt.h:2436
static constexpr auto substr
Definition jwt.h:2429
static constexpr auto value
Definition jwt.h:2442
static constexpr auto value
Definition jwt.h:2458
static constexpr auto value
Definition jwt.h:2283
static constexpr auto value
Definition jwt.h:2266
void operator=(nonesuch const &)=delete
nonesuch(nonesuch const &)=delete
nonesuch(nonesuch const &&)=delete
void operator=(nonesuch &&)=delete
static constexpr auto value
Definition jwt.h:2171
static constexpr auto value
Definition jwt.h:2234
static constexpr auto value
Definition jwt.h:2217
static constexpr auto value
Definition jwt.h:2200
static constexpr auto value
Definition jwt.h:2156
static constexpr auto value
Definition jwt.h:2185
static constexpr auto value
Definition jwt.h:2314
static constexpr auto value
Definition jwt.h:2331
static constexpr auto value
Definition jwt.h:2143
void operator()(const verify_context< json_traits > &ctx, std::error_code &ec) const
Definition jwt.h:3470
void operator()(const verify_context< json_traits > &ctx, std::error_code &ec) const
Definition jwt.h:3450
void operator()(const verify_context< json_traits > &ctx, std::error_code &ec) const
Definition jwt.h:3415
const basic_claim< json_traits > expected
Definition jwt.h:3414
insensitive_string_claim(const typename json_traits::string_type &e, std::locale loc)
Definition jwt.h:3531
static std::string to_lower_unicode(const std::string &str, const std::locale &loc)
Definition jwt.h:3547
void operator()(const verify_context< json_traits > &ctx, std::error_code &ec) const
Definition jwt.h:3536
const json_traits::string_type expected
Definition jwt.h:3529
void operator()(const verify_context< json_traits > &ctx, std::error_code &ec) const
Definition jwt.h:3491
const basic_claim< json_traits >::set_t expected
Definition jwt.h:3490
basic_claim< json_traits > get_claim(bool in_header, json::type t, std::error_code &ec) const
Definition jwt.h:3390
basic_claim< json_traits > get_claim(bool in_header, std::error_code &ec) const
Definition jwt.h:3369
verify_context(date ctime, const decoded_jwt< json_traits > &j, size_t l)
Definition jwt.h:3354
basic_claim< json_traits > get_claim(json::type t, std::error_code &ec) const
Definition jwt.h:3403
basic_claim< json_traits > get_claim(std::error_code &ec) const
Definition jwt.h:3402
const decoded_jwt< json_traits > & jwt
Definition jwt.h:3361