• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Thalhammer / jwt-cpp / 4991023813

pending completion
4991023813

push

github

GitHub
Replace deprecated wstring_convert (#290)

20 of 20 new or added lines in 1 file covered. (100.0%)

1133 of 1180 relevant lines covered (96.02%)

768.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.76
/include/jwt-cpp/jwt.h
1
#ifndef JWT_CPP_JWT_H
2
#define JWT_CPP_JWT_H
3

4
#ifndef JWT_DISABLE_PICOJSON
5
#ifndef PICOJSON_USE_INT64
6
#define PICOJSON_USE_INT64
7
#endif
8
#include "picojson/picojson.h"
9
#endif
10

11
#ifndef JWT_DISABLE_BASE64
12
#include "base.h"
13
#endif
14

15
#include <openssl/ec.h>
16
#include <openssl/ecdsa.h>
17
#include <openssl/err.h>
18
#include <openssl/evp.h>
19
#include <openssl/hmac.h>
20
#include <openssl/pem.h>
21
#include <openssl/rsa.h>
22
#include <openssl/ssl.h>
23

24
#include <algorithm>
25
#include <chrono>
26
#include <cmath>
27
#include <cstring>
28
#include <functional>
29
#include <iterator>
30
#include <locale>
31
#include <memory>
32
#include <set>
33
#include <system_error>
34
#include <type_traits>
35
#include <unordered_map>
36
#include <utility>
37
#include <vector>
38

39
#if __cplusplus > 201103L
40
#include <codecvt>
41
#endif
42

43
#if __cplusplus >= 201402L
44
#ifdef __has_include
45
#if __has_include(<experimental/type_traits>)
46
#include <experimental/type_traits>
47
#endif
48
#endif
49
#endif
50

51
#if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0
52
#define JWT_OPENSSL_3_0
53
#elif OPENSSL_VERSION_NUMBER >= 0x10101000L // 1.1.1
54
#define JWT_OPENSSL_1_1_1
55
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L // 1.1.0
56
#define JWT_OPENSSL_1_1_0
57
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L // 1.0.0
58
#define JWT_OPENSSL_1_0_0
59
#endif
60

61
#if defined(LIBRESSL_VERSION_NUMBER)
62
#if LIBRESSL_VERSION_NUMBER >= 0x3050300fL
63
#define JWT_OPENSSL_1_1_0
64
#else
65
#define JWT_OPENSSL_1_0_0
66
#endif
67
#endif
68

69
#if defined(LIBWOLFSSL_VERSION_HEX)
70
#define JWT_OPENSSL_1_1_1
71
#endif
72

73
#ifndef JWT_CLAIM_EXPLICIT
74
#define JWT_CLAIM_EXPLICIT explicit
75
#endif
76

77
/**
78
 * \brief JSON Web Token
79
 *
80
 * A namespace to contain everything related to handling JSON Web Tokens, JWT for short,
81
 * as a part of [RFC7519](https://tools.ietf.org/html/rfc7519), or alternatively for
82
 * JWS (JSON Web Signature) from [RFC7515](https://tools.ietf.org/html/rfc7515)
83
 */
84
namespace jwt {
85
        /**
86
         * Default system time point in UTC
87
         */
88
        using date = std::chrono::system_clock::time_point;
89

90
        /**
91
         * \brief Everything related to error codes issued by the library
92
         */
93
        namespace error {
94
                struct signature_verification_exception : public std::system_error {
95
                        using system_error::system_error;
96
                };
97
                struct signature_generation_exception : public std::system_error {
98
                        using system_error::system_error;
99
                };
100
                struct rsa_exception : public std::system_error {
101
                        using system_error::system_error;
102
                };
103
                struct ecdsa_exception : public std::system_error {
104
                        using system_error::system_error;
105
                };
106
                struct token_verification_exception : public std::system_error {
107
                        using system_error::system_error;
108
                };
109
                /**
110
                 * \brief Errors related to processing of RSA signatures
111
                 */
112
                enum class rsa_error {
113
                        ok = 0,
114
                        cert_load_failed = 10,
115
                        get_key_failed,
116
                        write_key_failed,
117
                        write_cert_failed,
118
                        convert_to_pem_failed,
119
                        load_key_bio_write,
120
                        load_key_bio_read,
121
                        create_mem_bio_failed,
122
                        no_key_provided
123
                };
124
                /**
125
                 * \brief Error category for RSA errors
126
                 */
127
                inline std::error_category& rsa_error_category() {
208✔
128
                        class rsa_error_cat : public std::error_category {
129
                        public:
130
                                const char* name() const noexcept override { return "rsa_error"; };
1✔
131
                                std::string message(int ev) const override {
59✔
132
                                        switch (static_cast<rsa_error>(ev)) {
59✔
133
                                        case rsa_error::ok: return "no error";
1✔
134
                                        case rsa_error::cert_load_failed: return "error loading cert into memory";
4✔
135
                                        case rsa_error::get_key_failed: return "error getting key from certificate";
4✔
136
                                        case rsa_error::write_key_failed: return "error writing key data in PEM format";
4✔
137
                                        case rsa_error::write_cert_failed: return "error writing cert data in PEM format";
2✔
138
                                        case rsa_error::convert_to_pem_failed: return "failed to convert key to pem";
5✔
139
                                        case rsa_error::load_key_bio_write: return "failed to load key: bio write failed";
7✔
140
                                        case rsa_error::load_key_bio_read: return "failed to load key: bio read failed";
6✔
141
                                        case rsa_error::create_mem_bio_failed: return "failed to create memory bio";
11✔
142
                                        case rsa_error::no_key_provided: return "at least one of public or private key need to be present";
3✔
143
                                        default: return "unknown RSA error";
12✔
144
                                        }
145
                                }
146
                        };
147
                        static rsa_error_cat cat;
208✔
148
                        return cat;
208✔
149
                }
150

151
                inline std::error_code make_error_code(rsa_error e) { return {static_cast<int>(e), rsa_error_category()}; }
129✔
152
                /**
153
                 * \brief Errors related to processing of RSA signatures
154
                 */
155
                enum class ecdsa_error {
156
                        ok = 0,
157
                        load_key_bio_write = 10,
158
                        load_key_bio_read,
159
                        create_mem_bio_failed,
160
                        no_key_provided,
161
                        invalid_key_size,
162
                        invalid_key,
163
                        create_context_failed
164
                };
165
                /**
166
                 * \brief Error category for ECDSA errors
167
                 */
168
                inline std::error_category& ecdsa_error_category() {
114✔
169
                        class ecdsa_error_cat : public std::error_category {
170
                        public:
171
                                const char* name() const noexcept override { return "ecdsa_error"; };
1✔
172
                                std::string message(int ev) const override {
56✔
173
                                        switch (static_cast<ecdsa_error>(ev)) {
56✔
174
                                        case ecdsa_error::ok: return "no error";
1✔
175
                                        case ecdsa_error::load_key_bio_write: return "failed to load key: bio write failed";
4✔
176
                                        case ecdsa_error::load_key_bio_read: return "failed to load key: bio read failed";
4✔
177
                                        case ecdsa_error::create_mem_bio_failed: return "failed to create memory bio";
4✔
178
                                        case ecdsa_error::no_key_provided:
2✔
179
                                                return "at least one of public or private key need to be present";
2✔
180
                                        case ecdsa_error::invalid_key_size: return "invalid key size";
25✔
181
                                        case ecdsa_error::invalid_key: return "invalid key";
3✔
182
                                        case ecdsa_error::create_context_failed: return "failed to create context";
3✔
183
                                        default: return "unknown ECDSA error";
10✔
184
                                        }
185
                                }
186
                        };
187
                        static ecdsa_error_cat cat;
114✔
188
                        return cat;
114✔
189
                }
190

191
                inline std::error_code make_error_code(ecdsa_error e) { return {static_cast<int>(e), ecdsa_error_category()}; }
70✔
192

193
                /**
194
                 * \brief Errors related to verification of signatures
195
                 */
196
                enum class signature_verification_error {
197
                        ok = 0,
198
                        invalid_signature = 10,
199
                        create_context_failed,
200
                        verifyinit_failed,
201
                        verifyupdate_failed,
202
                        verifyfinal_failed,
203
                        get_key_failed,
204
                        set_rsa_pss_saltlen_failed,
205
                        signature_encoding_failed
206
                };
207
                /**
208
                 * \brief Error category for verification errors
209
                 */
210
                inline std::error_category& signature_verification_error_category() {
108✔
211
                        class verification_error_cat : public std::error_category {
212
                        public:
213
                                const char* name() const noexcept override { return "signature_verification_error"; };
1✔
214
                                std::string message(int ev) const override {
36✔
215
                                        switch (static_cast<signature_verification_error>(ev)) {
36✔
216
                                        case signature_verification_error::ok: return "no error";
1✔
217
                                        case signature_verification_error::invalid_signature: return "invalid signature";
10✔
218
                                        case signature_verification_error::create_context_failed:
1✔
219
                                                return "failed to verify signature: could not create context";
1✔
220
                                        case signature_verification_error::verifyinit_failed:
1✔
221
                                                return "failed to verify signature: VerifyInit failed";
1✔
222
                                        case signature_verification_error::verifyupdate_failed:
1✔
223
                                                return "failed to verify signature: VerifyUpdate failed";
1✔
224
                                        case signature_verification_error::verifyfinal_failed:
8✔
225
                                                return "failed to verify signature: VerifyFinal failed";
8✔
226
                                        case signature_verification_error::get_key_failed:
1✔
227
                                                return "failed to verify signature: Could not get key";
1✔
228
                                        case signature_verification_error::set_rsa_pss_saltlen_failed:
1✔
229
                                                return "failed to verify signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
1✔
230
                                        case signature_verification_error::signature_encoding_failed:
1✔
231
                                                return "failed to verify signature: i2d_ECDSA_SIG failed";
1✔
232
                                        default: return "unknown signature verification error";
11✔
233
                                        }
234
                                }
235
                        };
236
                        static verification_error_cat cat;
108✔
237
                        return cat;
108✔
238
                }
239

240
                inline std::error_code make_error_code(signature_verification_error e) {
73✔
241
                        return {static_cast<int>(e), signature_verification_error_category()};
73✔
242
                }
243

244
                /**
245
                 * \brief Errors related to signature generation errors
246
                 */
247
                enum class signature_generation_error {
248
                        ok = 0,
249
                        hmac_failed = 10,
250
                        create_context_failed,
251
                        signinit_failed,
252
                        signupdate_failed,
253
                        signfinal_failed,
254
                        ecdsa_do_sign_failed,
255
                        digestinit_failed,
256
                        digestupdate_failed,
257
                        digestfinal_failed,
258
                        rsa_padding_failed,
259
                        rsa_private_encrypt_failed,
260
                        get_key_failed,
261
                        set_rsa_pss_saltlen_failed,
262
                        signature_decoding_failed
263
                };
264
                /**
265
                 * \brief Error category for signature generation errors
266
                 */
267
                inline std::error_category& signature_generation_error_category() {
91✔
268
                        class signature_generation_error_cat : public std::error_category {
269
                        public:
270
                                const char* name() const noexcept override { return "signature_generation_error"; };
1✔
271
                                std::string message(int ev) const override {
35✔
272
                                        switch (static_cast<signature_generation_error>(ev)) {
35✔
273
                                        case signature_generation_error::ok: return "no error";
1✔
274
                                        case signature_generation_error::hmac_failed: return "hmac failed";
1✔
275
                                        case signature_generation_error::create_context_failed:
1✔
276
                                                return "failed to create signature: could not create context";
1✔
277
                                        case signature_generation_error::signinit_failed:
1✔
278
                                                return "failed to create signature: SignInit failed";
1✔
279
                                        case signature_generation_error::signupdate_failed:
1✔
280
                                                return "failed to create signature: SignUpdate failed";
1✔
281
                                        case signature_generation_error::signfinal_failed:
4✔
282
                                                return "failed to create signature: SignFinal failed";
4✔
283
                                        case signature_generation_error::ecdsa_do_sign_failed: return "failed to generate ecdsa signature";
1✔
284
                                        case signature_generation_error::digestinit_failed:
1✔
285
                                                return "failed to create signature: DigestInit failed";
1✔
286
                                        case signature_generation_error::digestupdate_failed:
1✔
287
                                                return "failed to create signature: DigestUpdate failed";
1✔
288
                                        case signature_generation_error::digestfinal_failed:
1✔
289
                                                return "failed to create signature: DigestFinal failed";
1✔
290
                                        case signature_generation_error::rsa_padding_failed:
1✔
291
                                                return "failed to create signature: EVP_PKEY_CTX_set_rsa_padding failed";
1✔
292
                                        case signature_generation_error::rsa_private_encrypt_failed:
1✔
293
                                                return "failed to create signature: RSA_private_encrypt failed";
1✔
294
                                        case signature_generation_error::get_key_failed:
1✔
295
                                                return "failed to generate signature: Could not get key";
1✔
296
                                        case signature_generation_error::set_rsa_pss_saltlen_failed:
1✔
297
                                                return "failed to create signature: EVP_PKEY_CTX_set_rsa_pss_saltlen failed";
1✔
298
                                        case signature_generation_error::signature_decoding_failed:
1✔
299
                                                return "failed to create signature: d2i_ECDSA_SIG failed";
1✔
300
                                        default: return "unknown signature generation error";
17✔
301
                                        }
302
                                }
303
                        };
304
                        static signature_generation_error_cat cat = {};
91✔
305
                        return cat;
91✔
306
                }
307

308
                inline std::error_code make_error_code(signature_generation_error e) {
72✔
309
                        return {static_cast<int>(e), signature_generation_error_category()};
72✔
310
                }
311

312
                /**
313
                 * \brief Errors related to token verification errors
314
                 */
315
                enum class token_verification_error {
316
                        ok = 0,
317
                        wrong_algorithm = 10,
318
                        missing_claim,
319
                        claim_type_missmatch,
320
                        claim_value_missmatch,
321
                        token_expired,
322
                        audience_missmatch
323
                };
324
                /**
325
                 * \brief Error category for token verification errors
326
                 */
327
                inline std::error_category& token_verification_error_category() {
61✔
328
                        class token_verification_error_cat : public std::error_category {
329
                        public:
330
                                const char* name() const noexcept override { return "token_verification_error"; };
1✔
331
                                std::string message(int ev) const override {
32✔
332
                                        switch (static_cast<token_verification_error>(ev)) {
32✔
333
                                        case token_verification_error::ok: return "no error";
1✔
334
                                        case token_verification_error::wrong_algorithm: return "wrong algorithm";
2✔
335
                                        case token_verification_error::missing_claim: return "decoded JWT is missing required claim(s)";
5✔
336
                                        case token_verification_error::claim_type_missmatch:
2✔
337
                                                return "claim type does not match expected type";
2✔
338
                                        case token_verification_error::claim_value_missmatch:
3✔
339
                                                return "claim value does not match expected value";
3✔
340
                                        case token_verification_error::token_expired: return "token expired";
7✔
341
                                        case token_verification_error::audience_missmatch:
3✔
342
                                                return "token doesn't contain the required audience";
3✔
343
                                        default: return "unknown token verification error";
9✔
344
                                        }
345
                                }
346
                        };
347
                        static token_verification_error_cat cat = {};
61✔
348
                        return cat;
61✔
349
                }
350

351
                inline std::error_code make_error_code(token_verification_error e) {
39✔
352
                        return {static_cast<int>(e), token_verification_error_category()};
39✔
353
                }
354

355
                inline void throw_if_error(std::error_code ec) {
245✔
356
                        if (ec) {
245✔
357
                                if (ec.category() == rsa_error_category()) throw rsa_exception(ec);
79✔
358
                                if (ec.category() == ecdsa_error_category()) throw ecdsa_exception(ec);
44✔
359
                                if (ec.category() == signature_verification_error_category())
35✔
360
                                        throw signature_verification_exception(ec);
16✔
361
                                if (ec.category() == signature_generation_error_category()) throw signature_generation_exception(ec);
19✔
362
                                if (ec.category() == token_verification_error_category()) throw token_verification_exception(ec);
16✔
363
                        }
364
                }
166✔
365
        } // namespace error
366
} // namespace jwt
367

368
namespace std {
369
        template<>
370
        struct is_error_code_enum<jwt::error::rsa_error> : true_type {};
371
        template<>
372
        struct is_error_code_enum<jwt::error::ecdsa_error> : true_type {};
373
        template<>
374
        struct is_error_code_enum<jwt::error::signature_verification_error> : true_type {};
375
        template<>
376
        struct is_error_code_enum<jwt::error::signature_generation_error> : true_type {};
377
        template<>
378
        struct is_error_code_enum<jwt::error::token_verification_error> : true_type {};
379
} // namespace std
380

381
namespace jwt {
382
        /**
383
         * \brief A collection for working with certificates
384
         *
385
         * These _helpers_ are usefully when working with certificates OpenSSL APIs.
386
         * For example, when dealing with JWKS (JSON Web Key Set)[https://tools.ietf.org/html/rfc7517]
387
         * you maybe need to extract the modulus and exponent of an RSA Public Key.
388
         */
389
        namespace helper {
390
                /**
391
                 * \brief Handle class for EVP_PKEY structures
392
                 *
393
                 * Starting from OpenSSL 1.1.0, EVP_PKEY has internal reference counting. This handle class allows
394
                 * jwt-cpp to leverage that and thus safe an allocation for the control block in std::shared_ptr.
395
                 * The handle uses shared_ptr as a fallback on older versions. The behaviour should be identical between both.
396
                 */
397
                class evp_pkey_handle {
398
                public:
399
                        constexpr evp_pkey_handle() noexcept = default;
151✔
400
#ifdef JWT_OPENSSL_1_0_0
401
                        /**
402
                         * \brief Construct a new handle. The handle takes ownership of the key.
403
                         * \param key The key to store
404
                         */
405
                        explicit evp_pkey_handle(EVP_PKEY* key) { m_key = std::shared_ptr<EVP_PKEY>(key, EVP_PKEY_free); }
406

407
                        EVP_PKEY* get() const noexcept { return m_key.get(); }
408
                        bool operator!() const noexcept { return m_key == nullptr; }
409
                        explicit operator bool() const noexcept { return m_key != nullptr; }
410

411
                private:
412
                        std::shared_ptr<EVP_PKEY> m_key{nullptr};
413
#else
414
                        /**
415
                         * \brief Construct a new handle. The handle takes ownership of the key.
416
                         * \param key The key to store
417
                         */
418
                        explicit constexpr evp_pkey_handle(EVP_PKEY* key) noexcept : m_key{key} {}
101✔
419
                        evp_pkey_handle(const evp_pkey_handle& other) : m_key{other.m_key} {
62✔
420
                                if (m_key != nullptr && EVP_PKEY_up_ref(m_key) != 1) throw std::runtime_error("EVP_PKEY_up_ref failed");
62✔
421
                        }
62✔
422
// C++11 requires the body of a constexpr constructor to be empty
423
#if __cplusplus >= 201402L
424
                        constexpr
425
#endif
426
                                evp_pkey_handle(evp_pkey_handle&& other) noexcept
101✔
427
                                : m_key{other.m_key} {
101✔
428
                                other.m_key = nullptr;
101✔
429
                        }
101✔
430
                        evp_pkey_handle& operator=(const evp_pkey_handle& other) {
431
                                if (&other == this) return *this;
432
                                decrement_ref_count(m_key);
433
                                m_key = other.m_key;
434
                                increment_ref_count(m_key);
435
                                return *this;
436
                        }
437
                        evp_pkey_handle& operator=(evp_pkey_handle&& other) noexcept {
87✔
438
                                if (&other == this) return *this;
87✔
439
                                decrement_ref_count(m_key);
87✔
440
                                m_key = other.m_key;
87✔
441
                                other.m_key = nullptr;
87✔
442
                                return *this;
87✔
443
                        }
444
                        evp_pkey_handle& operator=(EVP_PKEY* key) {
445
                                decrement_ref_count(m_key);
446
                                m_key = key;
447
                                increment_ref_count(m_key);
448
                                return *this;
449
                        }
450
                        ~evp_pkey_handle() noexcept { decrement_ref_count(m_key); }
415✔
451

452
                        EVP_PKEY* get() const noexcept { return m_key; }
186✔
453
                        bool operator!() const noexcept { return m_key == nullptr; }
158✔
454
                        explicit operator bool() const noexcept { return m_key != nullptr; }
3✔
455

456
                private:
457
                        EVP_PKEY* m_key{nullptr};
458

459
                        static void increment_ref_count(EVP_PKEY* key) {
460
                                if (key != nullptr && EVP_PKEY_up_ref(key) != 1) throw std::runtime_error("EVP_PKEY_up_ref failed");
461
                        }
462
                        static void decrement_ref_count(EVP_PKEY* key) noexcept {
502✔
463
                                if (key != nullptr) EVP_PKEY_free(key);
502✔
464
                        }
502✔
465
#endif
466
                };
467

468
                inline std::unique_ptr<BIO, decltype(&BIO_free_all)> make_mem_buf_bio() {
175✔
469
                        return std::unique_ptr<BIO, decltype(&BIO_free_all)>(BIO_new(BIO_s_mem()), BIO_free_all);
175✔
470
                }
471

472
                inline std::unique_ptr<BIO, decltype(&BIO_free_all)> make_mem_buf_bio(const std::string& data) {
31✔
473
                        return std::unique_ptr<BIO, decltype(&BIO_free_all)>(
474
#if OPENSSL_VERSION_NUMBER <= 0x10100003L
475
                                BIO_new_mem_buf(const_cast<char*>(data.data()), static_cast<int>(data.size())), BIO_free_all
476
#else
477
                                BIO_new_mem_buf(data.data(), static_cast<int>(data.size())), BIO_free_all
62✔
478
#endif
479
                        );
62✔
480
                }
481

482
                inline std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX*)> make_evp_md_ctx() {
84✔
483
                        return
484
#ifdef JWT_OPENSSL_1_0_0
485
                                std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_destroy)>(EVP_MD_CTX_create(), &EVP_MD_CTX_destroy);
486
#else
487
                                std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(EVP_MD_CTX_new(), &EVP_MD_CTX_free);
84✔
488
#endif
489
                }
490

491
                /**
492
                 * \brief Extract the public key of a pem certificate
493
                 *
494
                 * \param certstr        String containing the certificate encoded as pem
495
                 * \param pw                Password used to decrypt certificate (leave empty if not encrypted)
496
                 * \param ec                error_code for error_detection (gets cleared if no error ocurred)
497
                 */
498
                inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw,
31✔
499
                                                                                                        std::error_code& ec) {
500
                        ec.clear();
31✔
501
                        auto certbio = make_mem_buf_bio(certstr);
31✔
502
                        auto keybio = make_mem_buf_bio();
31✔
503
                        if (!certbio || !keybio) {
31✔
504
                                ec = error::rsa_error::create_mem_bio_failed;
4✔
505
                                return {};
4✔
506
                        }
507

508
                        std::unique_ptr<X509, decltype(&X509_free)> cert(
509
                                PEM_read_bio_X509(certbio.get(), nullptr, nullptr, const_cast<char*>(pw.c_str())), X509_free);
27✔
510
                        if (!cert) {
27✔
511
                                ec = error::rsa_error::cert_load_failed;
4✔
512
                                return {};
4✔
513
                        }
514
                        std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> key(X509_get_pubkey(cert.get()), EVP_PKEY_free);
23✔
515
                        if (!key) {
23✔
516
                                ec = error::rsa_error::get_key_failed;
4✔
517
                                return {};
4✔
518
                        }
519
                        if (PEM_write_bio_PUBKEY(keybio.get(), key.get()) == 0) {
19✔
520
                                ec = error::rsa_error::write_key_failed;
4✔
521
                                return {};
4✔
522
                        }
523
                        char* ptr = nullptr;
15✔
524
                        auto len = BIO_get_mem_data(keybio.get(), &ptr);
15✔
525
                        if (len <= 0 || ptr == nullptr) {
15✔
526
                                ec = error::rsa_error::convert_to_pem_failed;
4✔
527
                                return {};
4✔
528
                        }
529
                        return {ptr, static_cast<size_t>(len)};
11✔
530
                }
31✔
531

532
                /**
533
                 * \brief Extract the public key of a pem certificate
534
                 *
535
                 * \param certstr        String containing the certificate encoded as pem
536
                 * \param pw                Password used to decrypt certificate (leave empty if not encrypted)
537
                 * \throw                        rsa_exception if an error occurred
538
                 */
539
                inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") {
6✔
540
                        std::error_code ec;
6✔
541
                        auto res = extract_pubkey_from_cert(certstr, pw, ec);
6✔
542
                        error::throw_if_error(ec);
6✔
543
                        return res;
2✔
544
                }
5✔
545

546
                /**
547
                 * \brief Convert the certificate provided as DER to PEM.
548
                 *
549
                 * \param cert_der_str         String containing the certificate encoded as base64 DER
550
                 * \param ec                        error_code for error_detection (gets cleared if no error occures)
551
                 */
552
                inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) {
9✔
553
                        ec.clear();
9✔
554

555
                        auto c_str = reinterpret_cast<const unsigned char*>(cert_der_str.c_str());
9✔
556

557
                        std::unique_ptr<X509, decltype(&X509_free)> cert(
558
                                d2i_X509(NULL, &c_str, static_cast<int>(cert_der_str.size())), X509_free);
9✔
559
                        auto certbio = make_mem_buf_bio();
9✔
560
                        if (!cert || !certbio) {
9✔
561
                                ec = error::rsa_error::create_mem_bio_failed;
2✔
562
                                return {};
2✔
563
                        }
564

565
                        if (!PEM_write_bio_X509(certbio.get(), cert.get())) {
7✔
566
                                ec = error::rsa_error::write_cert_failed;
2✔
567
                                return {};
2✔
568
                        }
569

570
                        char* ptr = nullptr;
5✔
571
                        const auto len = BIO_get_mem_data(certbio.get(), &ptr);
5✔
572
                        if (len <= 0 || ptr == nullptr) {
5✔
573
                                ec = error::rsa_error::convert_to_pem_failed;
2✔
574
                                return {};
2✔
575
                        }
576

577
                        return {ptr, static_cast<size_t>(len)};
3✔
578
                }
9✔
579

580
                /**
581
                 * \brief Convert the certificate provided as base64 DER to PEM.
582
                 *
583
                 * This is useful when using with JWKs as x5c claim is encoded as base64 DER. More info
584
                 * (here)[https://tools.ietf.org/html/rfc7517#section-4.7]
585
                 *
586
                 * \tparam Decode is callabled, taking a string_type and returns a string_type.
587
                 * It should ensure the padding of the input and then base64 decode and return
588
                 * the results.
589
                 *
590
                 * \param cert_base64_der_str         String containing the certificate encoded as base64 DER
591
                 * \param decode                                 The function to decode the cert
592
                 * \param ec                                        error_code for error_detection (gets cleared if no error occures)
593
                 */
594
                template<typename Decode>
595
                std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode,
8✔
596
                                                                                          std::error_code& ec) {
597
                        ec.clear();
8✔
598
                        const auto decoded_str = decode(cert_base64_der_str);
8✔
599
                        return convert_der_to_pem(decoded_str, ec);
16✔
600
                }
8✔
601

602
                /**
603
                 * \brief Convert the certificate provided as base64 DER to PEM.
604
                 *
605
                 * This is useful when using with JWKs as x5c claim is encoded as base64 DER. More info
606
                 * (here)[https://tools.ietf.org/html/rfc7517#section-4.7]
607
                 *
608
                 * \tparam Decode is callabled, taking a string_type and returns a string_type.
609
                 * It should ensure the padding of the input and then base64 decode and return
610
                 * the results.
611
                 *
612
                 * \param cert_base64_der_str         String containing the certificate encoded as base64 DER
613
                 * \param decode                                 The function to decode the cert
614
                 * \throw                                                rsa_exception if an error occurred
615
                 */
616
                template<typename Decode>
617
                std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode) {
618
                        std::error_code ec;
619
                        auto res = convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
620
                        error::throw_if_error(ec);
621
                        return res;
622
                }
623

624
                /**
625
                 * \brief Convert the certificate provided as DER to PEM.
626
                 *
627
                 * \param cert_der_str         String containing the DER certificate
628
                 * \param decode                 The function to decode the cert
629
                 * \throw                                rsa_exception if an error occurred
630
                 */
631
                inline std::string convert_der_to_pem(const std::string& cert_der_str) {
1✔
632
                        std::error_code ec;
1✔
633
                        auto res = convert_der_to_pem(cert_der_str, ec);
1✔
634
                        error::throw_if_error(ec);
1✔
635
                        return res;
2✔
636
                }
×
637

638
#ifndef JWT_DISABLE_BASE64
639
                /**
640
                 * \brief Convert the certificate provided as base64 DER to PEM.
641
                 *
642
                 * This is useful when using with JWKs as x5c claim is encoded as base64 DER. More info
643
                 * (here)[https://tools.ietf.org/html/rfc7517#section-4.7]
644
                 *
645
                 * \param cert_base64_der_str         String containing the certificate encoded as base64 DER
646
                 * \param ec                                        error_code for error_detection (gets cleared if no error occures)
647
                 */
648
                inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, std::error_code& ec) {
8✔
649
                        auto decode = [](const std::string& token) {
8✔
650
                                return base::decode<alphabet::base64>(base::pad<alphabet::base64>(token));
16✔
651
                        };
652
                        return convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec);
16✔
653
                }
654

655
                /**
656
                 * \brief Convert the certificate provided as base64 DER to PEM.
657
                 *
658
                 * This is useful when using with JWKs as x5c claim is encoded as base64 DER. More info
659
                 * (here)[https://tools.ietf.org/html/rfc7517#section-4.7]
660
                 *
661
                 * \param cert_base64_der_str         String containing the certificate encoded as base64 DER
662
                 * \throw                                                rsa_exception if an error occurred
663
                 */
664
                inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) {
4✔
665
                        std::error_code ec;
4✔
666
                        auto res = convert_base64_der_to_pem(cert_base64_der_str, ec);
4✔
667
                        error::throw_if_error(ec);
4✔
668
                        return res;
2✔
669
                }
3✔
670
#endif
671
                /**
672
                 * \brief Load a public key from a string.
673
                 *
674
                 * The string should contain a pem encoded certificate or public key
675
                 *
676
                 * \param key                String containing the certificate encoded as pem
677
                 * \param password        Password used to decrypt certificate (leave empty if not encrypted)
678
                 * \param ec                error_code for error_detection (gets cleared if no error occures)
679
                 */
680
                inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password,
36✔
681
                                                                                                                   std::error_code& ec) {
682
                        ec.clear();
36✔
683
                        auto pubkey_bio = make_mem_buf_bio();
36✔
684
                        if (!pubkey_bio) {
36✔
685
                                ec = error::rsa_error::create_mem_bio_failed;
5✔
686
                                return {};
5✔
687
                        }
688
                        if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----") {
31✔
689
                                auto epkey = helper::extract_pubkey_from_cert(key, password, ec);
12✔
690
                                if (ec) return {};
12✔
691
                                const int len = static_cast<int>(epkey.size());
7✔
692
                                if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len) {
7✔
693
                                        ec = error::rsa_error::load_key_bio_write;
3✔
694
                                        return {};
3✔
695
                                }
696
                        } else {
12✔
697
                                const int len = static_cast<int>(key.size());
19✔
698
                                if (BIO_write(pubkey_bio.get(), key.data(), len) != len) {
19✔
699
                                        ec = error::rsa_error::load_key_bio_write;
2✔
700
                                        return {};
2✔
701
                                }
702
                        }
703

704
                        evp_pkey_handle pkey(PEM_read_bio_PUBKEY(
705
                                pubkey_bio.get(), nullptr, nullptr,
706
                                (void*)password.data())); // NOLINT(google-readability-casting) requires `const_cast`
21✔
707
                        if (!pkey) ec = error::rsa_error::load_key_bio_read;
21✔
708
                        return pkey;
21✔
709
                }
36✔
710

711
                /**
712
                 * \brief Load a public key from a string.
713
                 *
714
                 * The string should contain a pem encoded certificate or public key
715
                 *
716
                 * \param key                String containing the certificate or key encoded as pem
717
                 * \param password        Password used to decrypt certificate or key (leave empty if not encrypted)
718
                 * \throw                        rsa_exception if an error occurred
719
                 */
720
                inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password = "") {
30✔
721
                        std::error_code ec;
30✔
722
                        auto res = load_public_key_from_string(key, password, ec);
30✔
723
                        error::throw_if_error(ec);
30✔
724
                        return res;
32✔
725
                }
14✔
726

727
                /**
728
                 * \brief Load a private key from a string.
729
                 *
730
                 * \param key                String containing a private key as pem
731
                 * \param password        Password used to decrypt key (leave empty if not encrypted)
732
                 * \param ec                error_code for error_detection (gets cleared if no error occures)
733
                 */
734
                inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password,
33✔
735
                                                                                                                        std::error_code& ec) {
736
                        auto privkey_bio = make_mem_buf_bio();
33✔
737
                        if (!privkey_bio) {
33✔
738
                                ec = error::rsa_error::create_mem_bio_failed;
4✔
739
                                return {};
4✔
740
                        }
741
                        const int len = static_cast<int>(key.size());
29✔
742
                        if (BIO_write(privkey_bio.get(), key.data(), len) != len) {
29✔
743
                                ec = error::rsa_error::load_key_bio_write;
4✔
744
                                return {};
4✔
745
                        }
746
                        evp_pkey_handle pkey(
747
                                PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr, const_cast<char*>(password.c_str())));
25✔
748
                        if (!pkey) ec = error::rsa_error::load_key_bio_read;
25✔
749
                        return pkey;
25✔
750
                }
33✔
751

752
                /**
753
                 * \brief Load a private key from a string.
754
                 *
755
                 * \param key                String containing a private key as pem
756
                 * \param password        Password used to decrypt key (leave empty if not encrypted)
757
                 * \throw                        rsa_exception if an error occurred
758
                 */
759
                inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password = "") {
30✔
760
                        std::error_code ec;
30✔
761
                        auto res = load_private_key_from_string(key, password, ec);
30✔
762
                        error::throw_if_error(ec);
30✔
763
                        return res;
44✔
764
                }
8✔
765

766
                /**
767
                 * \brief Load a public key from a string.
768
                 *
769
                 * The string should contain a pem encoded certificate or public key
770
                 *
771
                 * \param key                String containing the certificate encoded as pem
772
                 * \param password        Password used to decrypt certificate (leave empty if not encrypted)
773
                 * \param ec                error_code for error_detection (gets cleared if no error occures)
774
                 */
775
                inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password,
34✔
776
                                                                                                                          std::error_code& ec) {
777
                        ec.clear();
34✔
778
                        auto pubkey_bio = make_mem_buf_bio();
34✔
779
                        if (!pubkey_bio) {
34✔
780
                                ec = error::ecdsa_error::create_mem_bio_failed;
2✔
781
                                return {};
2✔
782
                        }
783
                        if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----") {
32✔
784
                                auto epkey = helper::extract_pubkey_from_cert(key, password, ec);
7✔
785
                                if (ec) return {};
7✔
786
                                const int len = static_cast<int>(epkey.size());
2✔
787
                                if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len) {
2✔
788
                                        ec = error::ecdsa_error::load_key_bio_write;
1✔
789
                                        return {};
1✔
790
                                }
791
                        } else {
7✔
792
                                const int len = static_cast<int>(key.size());
25✔
793
                                if (BIO_write(pubkey_bio.get(), key.data(), len) != len) {
25✔
794
                                        ec = error::ecdsa_error::load_key_bio_write;
1✔
795
                                        return {};
1✔
796
                                }
797
                        }
798

799
                        evp_pkey_handle pkey(PEM_read_bio_PUBKEY(
800
                                pubkey_bio.get(), nullptr, nullptr,
801
                                (void*)password.data())); // NOLINT(google-readability-casting) requires `const_cast`
25✔
802
                        if (!pkey) ec = error::ecdsa_error::load_key_bio_read;
25✔
803
                        return pkey;
25✔
804
                }
34✔
805

806
                /**
807
                 * \brief Load a public key from a string.
808
                 *
809
                 * The string should contain a pem encoded certificate or public key
810
                 *
811
                 * \param key                String containing the certificate or key encoded as pem
812
                 * \param password        Password used to decrypt certificate or key (leave empty if not encrypted)
813
                 * \throw                        ecdsa_exception if an error occurred
814
                 */
815
                inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key,
34✔
816
                                                                                                                          const std::string& password = "") {
817
                        std::error_code ec;
34✔
818
                        auto res = load_public_ec_key_from_string(key, password, ec);
34✔
819
                        error::throw_if_error(ec);
34✔
820
                        return res;
46✔
821
                }
11✔
822

823
                /**
824
                 * \brief Load a private key from a string.
825
                 *
826
                 * \param key                String containing a private key as pem
827
                 * \param password        Password used to decrypt key (leave empty if not encrypted)
828
                 * \param ec                error_code for error_detection (gets cleared if no error occures)
829
                 */
830
                inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password,
32✔
831
                                                                                                                           std::error_code& ec) {
832
                        auto privkey_bio = make_mem_buf_bio();
32✔
833
                        if (!privkey_bio) {
32✔
834
                                ec = error::ecdsa_error::create_mem_bio_failed;
1✔
835
                                return {};
1✔
836
                        }
837
                        const int len = static_cast<int>(key.size());
31✔
838
                        if (BIO_write(privkey_bio.get(), key.data(), len) != len) {
31✔
839
                                ec = error::ecdsa_error::load_key_bio_write;
1✔
840
                                return {};
1✔
841
                        }
842
                        evp_pkey_handle pkey(
843
                                PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr, const_cast<char*>(password.c_str())));
30✔
844
                        if (!pkey) ec = error::ecdsa_error::load_key_bio_read;
30✔
845
                        return pkey;
30✔
846
                }
32✔
847

848
                /**
849
                 * \brief Load a private key from a string.
850
                 *
851
                 * \param key                String containing a private key as pem
852
                 * \param password        Password used to decrypt key (leave empty if not encrypted)
853
                 * \throw                        ecdsa_exception if an error occurred
854
                 */
855
                inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key,
32✔
856
                                                                                                                           const std::string& password = "") {
857
                        std::error_code ec;
32✔
858
                        auto res = load_private_ec_key_from_string(key, password, ec);
32✔
859
                        error::throw_if_error(ec);
32✔
860
                        return res;
58✔
861
                }
3✔
862

863
                /**
864
                 * Convert a OpenSSL BIGNUM to a std::string
865
                 * \param bn BIGNUM to convert
866
                 * \return bignum as string
867
                 */
868
                inline
869
#ifdef JWT_OPENSSL_1_0_0
870
                        std::string
871
                        bn2raw(BIGNUM* bn)
872
#else
873
                        std::string
874
                        bn2raw(const BIGNUM* bn)
8✔
875
#endif
876
                {
877
                        std::string res(BN_num_bytes(bn), '\0');
8✔
878
                        BN_bn2bin(bn, (unsigned char*)res.data()); // NOLINT(google-readability-casting) requires `const_cast`
8✔
879
                        return res;
8✔
880
                }
×
881
                /**
882
                 * Convert an std::string to a OpenSSL BIGNUM
883
                 * \param raw String to convert
884
                 * \return BIGNUM representation
885
                 */
886
                inline std::unique_ptr<BIGNUM, decltype(&BN_free)> raw2bn(const std::string& raw) {
40✔
887
                        return std::unique_ptr<BIGNUM, decltype(&BN_free)>(
888
                                BN_bin2bn(reinterpret_cast<const unsigned char*>(raw.data()), static_cast<int>(raw.size()), nullptr),
80✔
889
                                BN_free);
40✔
890
                }
891
        } // namespace helper
892

893
        /**
894
         * \brief Various cryptographic algorithms when working with JWT
895
         *
896
         * JWT (JSON Web Tokens) signatures are typically used as the payload for a JWS (JSON Web Signature) or
897
         * JWE (JSON Web Encryption). Both of these use various cryptographic as specified by
898
         * [RFC7518](https://tools.ietf.org/html/rfc7518) and are exposed through the a [JOSE
899
         * Header](https://tools.ietf.org/html/rfc7515#section-4) which points to one of the JWA (JSON Web
900
         * Algorithms)(https://tools.ietf.org/html/rfc7518#section-3.1)
901
         */
902
        namespace algorithm {
903
                /**
904
                 * \brief "none" algorithm.
905
                 *
906
                 * Returns and empty signature and checks if the given signature is empty.
907
                 */
908
                struct none {
909
                        /**
910
                         * \brief Return an empty string
911
                         */
912
                        std::string sign(const std::string& /*unused*/, std::error_code& ec) const {
16✔
913
                                ec.clear();
16✔
914
                                return {};
16✔
915
                        }
916
                        /**
917
                         * \brief Check if the given signature is empty.
918
                         *
919
                         * JWT's with "none" algorithm should not contain a signature.
920
                         * \param signature Signature data to verify
921
                         * \param ec                error_code filled with details about the error
922
                         */
923
                        void verify(const std::string& /*unused*/, const std::string& signature, std::error_code& ec) const {
27✔
924
                                ec.clear();
27✔
925
                                if (!signature.empty()) { ec = error::signature_verification_error::invalid_signature; }
27✔
926
                        }
27✔
927
                        /// Get algorithm name
928
                        std::string name() const { return "none"; }
36✔
929
                };
930
                /**
931
                 * \brief Base class for HMAC family of algorithms
932
                 */
933
                struct hmacsha {
934
                        /**
935
                         * Construct new hmac algorithm
936
                         * \param key Key to use for HMAC
937
                         * \param md Pointer to hash function
938
                         * \param name Name of the algorithm
939
                         */
940
                        hmacsha(std::string key, const EVP_MD* (*md)(), std::string name)
28✔
941
                                : secret(std::move(key)), md(md), alg_name(std::move(name)) {}
28✔
942
                        /**
943
                         * Sign jwt data
944
                         * \param data The data to sign
945
                         * \param ec error_code filled with details on error
946
                         * \return HMAC signature for the given data
947
                         */
948
                        std::string sign(const std::string& data, std::error_code& ec) const {
31✔
949
                                ec.clear();
31✔
950
                                std::string res(static_cast<size_t>(EVP_MAX_MD_SIZE), '\0');
31✔
951
                                auto len = static_cast<unsigned int>(res.size());
31✔
952
                                if (HMAC(md(), secret.data(), static_cast<int>(secret.size()),
31✔
953
                                                 reinterpret_cast<const unsigned char*>(data.data()), static_cast<int>(data.size()),
31✔
954
                                                 (unsigned char*)res.data(), // NOLINT(google-readability-casting) requires `const_cast`
31✔
955
                                                 &len) == nullptr) {
31✔
956
                                        ec = error::signature_generation_error::hmac_failed;
1✔
957
                                        return {};
1✔
958
                                }
959
                                res.resize(len);
30✔
960
                                return res;
30✔
961
                        }
31✔
962
                        /**
963
                         * Check if signature is valid
964
                         * \param data The data to check signature against
965
                         * \param signature Signature provided by the jwt
966
                         * \param ec Filled with details about failure.
967
                         */
968
                        void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
19✔
969
                                ec.clear();
19✔
970
                                auto res = sign(data, ec);
19✔
971
                                if (ec) return;
19✔
972

973
                                bool matched = true;
18✔
974
                                for (size_t i = 0; i < std::min<size_t>(res.size(), signature.size()); i++)
593✔
975
                                        if (res[i] != signature[i]) matched = false;
575✔
976
                                if (res.size() != signature.size()) matched = false;
18✔
977
                                if (!matched) {
18✔
978
                                        ec = error::signature_verification_error::invalid_signature;
2✔
979
                                        return;
2✔
980
                                }
981
                        }
19✔
982
                        /**
983
                         * Returns the algorithm name provided to the constructor
984
                         * \return algorithm's name
985
                         */
986
                        std::string name() const { return alg_name; }
28✔
987

988
                private:
989
                        /// HMAC secrect
990
                        const std::string secret;
991
                        /// HMAC hash generator
992
                        const EVP_MD* (*md)();
993
                        /// algorithm's name
994
                        const std::string alg_name;
995
                };
996
                /**
997
                 * \brief Base class for RSA family of algorithms
998
                 */
999
                struct rsa {
1000
                        /**
1001
                         * Construct new rsa algorithm
1002
                         * \param public_key RSA public key in PEM format
1003
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1004
                         * \param public_key_password Password to decrypt public key pem.
1005
                         * \param private_key_password Password to decrypt private key pem.
1006
                         * \param md Pointer to hash function
1007
                         * \param name Name of the algorithm
1008
                         */
1009
                        rsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
14✔
1010
                                const std::string& private_key_password, const EVP_MD* (*md)(), std::string name)
1011
                                : md(md), alg_name(std::move(name)) {
14✔
1012
                                if (!private_key.empty()) {
14✔
1013
                                        pkey = helper::load_private_key_from_string(private_key, private_key_password);
9✔
1014
                                } else if (!public_key.empty()) {
5✔
1015
                                        pkey = helper::load_public_key_from_string(public_key, public_key_password);
4✔
1016
                                } else
1017
                                        throw error::rsa_exception(error::rsa_error::no_key_provided);
1✔
1018
                        }
15✔
1019
                        /**
1020
                         * Sign jwt data
1021
                         * \param data The data to sign
1022
                         * \param ec error_code filled with details on error
1023
                         * \return RSA signature for the given data
1024
                         */
1025
                        std::string sign(const std::string& data, std::error_code& ec) const {
7✔
1026
                                ec.clear();
7✔
1027
                                auto ctx = helper::make_evp_md_ctx();
7✔
1028
                                if (!ctx) {
7✔
1029
                                        ec = error::signature_generation_error::create_context_failed;
1✔
1030
                                        return {};
1✔
1031
                                }
1032
                                if (!EVP_SignInit(ctx.get(), md())) {
6✔
1033
                                        ec = error::signature_generation_error::signinit_failed;
1✔
1034
                                        return {};
1✔
1035
                                }
1036

1037
                                std::string res(EVP_PKEY_size(pkey.get()), '\0');
5✔
1038
                                unsigned int len = 0;
5✔
1039

1040
                                if (!EVP_SignUpdate(ctx.get(), data.data(), data.size())) {
5✔
1041
                                        ec = error::signature_generation_error::signupdate_failed;
1✔
1042
                                        return {};
1✔
1043
                                }
1044
                                if (EVP_SignFinal(ctx.get(), (unsigned char*)res.data(), &len, pkey.get()) == 0) {
4✔
1045
                                        ec = error::signature_generation_error::signfinal_failed;
1✔
1046
                                        return {};
1✔
1047
                                }
1048

1049
                                res.resize(len);
3✔
1050
                                return res;
3✔
1051
                        }
7✔
1052
                        /**
1053
                         * Check if signature is valid
1054
                         * \param data The data to check signature against
1055
                         * \param signature Signature provided by the jwt
1056
                         * \param ec Filled with details on failure
1057
                         */
1058
                        void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
13✔
1059
                                ec.clear();
13✔
1060
                                auto ctx = helper::make_evp_md_ctx();
13✔
1061
                                if (!ctx) {
13✔
1062
                                        ec = error::signature_verification_error::create_context_failed;
1✔
1063
                                        return;
1✔
1064
                                }
1065
                                if (!EVP_VerifyInit(ctx.get(), md())) {
12✔
1066
                                        ec = error::signature_verification_error::verifyinit_failed;
1✔
1067
                                        return;
1✔
1068
                                }
1069
                                if (!EVP_VerifyUpdate(ctx.get(), data.data(), data.size())) {
11✔
1070
                                        ec = error::signature_verification_error::verifyupdate_failed;
1✔
1071
                                        return;
1✔
1072
                                }
1073
                                auto res = EVP_VerifyFinal(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
20✔
1074
                                                                                   static_cast<unsigned int>(signature.size()), pkey.get());
10✔
1075
                                if (res != 1) {
10✔
1076
                                        ec = error::signature_verification_error::verifyfinal_failed;
3✔
1077
                                        return;
3✔
1078
                                }
1079
                        }
13✔
1080
                        /**
1081
                         * Returns the algorithm name provided to the constructor
1082
                         * \return algorithm's name
1083
                         */
1084
                        std::string name() const { return alg_name; }
10✔
1085

1086
                private:
1087
                        /// OpenSSL structure containing converted keys
1088
                        helper::evp_pkey_handle pkey;
1089
                        /// Hash generator
1090
                        const EVP_MD* (*md)();
1091
                        /// algorithm's name
1092
                        const std::string alg_name;
1093
                };
1094
                /**
1095
                 * \brief Base class for ECDSA family of algorithms
1096
                 */
1097
                struct ecdsa {
1098
                        /**
1099
                         * Construct new ecdsa algorithm
1100
                         *
1101
                         * \param public_key ECDSA public key in PEM format
1102
                         * \param private_key ECDSA private key or empty string if not available. If empty, signing will always fail
1103
                         * \param public_key_password Password to decrypt public key pem
1104
                         * \param private_key_password Password to decrypt private key pem
1105
                         * \param md Pointer to hash function
1106
                         * \param name Name of the algorithm
1107
                         * \param siglen The bit length of the signature
1108
                         */
1109
                        ecdsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
67✔
1110
                                  const std::string& private_key_password, const EVP_MD* (*md)(), std::string name, size_t siglen)
1111
                                : md(md), alg_name(std::move(name)), signature_length(siglen) {
67✔
1112
                                if (!private_key.empty()) {
67✔
1113
                                        pkey = helper::load_private_ec_key_from_string(private_key, private_key_password);
32✔
1114
                                        check_private_key(pkey.get());
29✔
1115
                                } else if (!public_key.empty()) {
35✔
1116
                                        pkey = helper::load_public_ec_key_from_string(public_key, public_key_password);
34✔
1117
                                        check_public_key(pkey.get());
23✔
1118
                                } else {
1119
                                        throw error::ecdsa_exception(error::ecdsa_error::no_key_provided);
1✔
1120
                                }
1121
                                if (!pkey) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
48✔
1122

1123
                                size_t keysize = EVP_PKEY_bits(pkey.get());
48✔
1124
                                if (keysize != signature_length * 4 && (signature_length != 132 || keysize != 521))
48✔
1125
                                        throw error::ecdsa_exception(error::ecdsa_error::invalid_key_size);
24✔
1126
                        }
110✔
1127

1128
                        /**
1129
                         * Sign jwt data
1130
                         * \param data The data to sign
1131
                         * \param ec error_code filled with details on error
1132
                         * \return ECDSA signature for the given data
1133
                         */
1134
                        std::string sign(const std::string& data, std::error_code& ec) const {
13✔
1135
                                ec.clear();
13✔
1136
                                auto ctx = helper::make_evp_md_ctx();
13✔
1137
                                if (!ctx) {
13✔
1138
                                        ec = error::signature_generation_error::create_context_failed;
1✔
1139
                                        return {};
1✔
1140
                                }
1141
                                if (!EVP_DigestSignInit(ctx.get(), nullptr, md(), nullptr, pkey.get())) {
12✔
1142
                                        ec = error::signature_generation_error::signinit_failed;
1✔
1143
                                        return {};
1✔
1144
                                }
1145
                                if (!EVP_DigestUpdate(ctx.get(), data.data(), data.size())) {
11✔
1146
                                        ec = error::signature_generation_error::digestupdate_failed;
1✔
1147
                                        return {};
1✔
1148
                                }
1149

1150
                                size_t len = 0;
10✔
1151
                                if (!EVP_DigestSignFinal(ctx.get(), nullptr, &len)) {
10✔
1152
                                        ec = error::signature_generation_error::signfinal_failed;
1✔
1153
                                        return {};
1✔
1154
                                }
1155
                                std::string res(len, '\0');
9✔
1156
                                if (!EVP_DigestSignFinal(ctx.get(), (unsigned char*)res.data(), &len)) {
9✔
1157
                                        ec = error::signature_generation_error::signfinal_failed;
4✔
1158
                                        return {};
4✔
1159
                                }
1160

1161
                                res.resize(len);
5✔
1162
                                return der_to_p1363_signature(res, ec);
5✔
1163
                        }
13✔
1164

1165
                        /**
1166
                         * Check if signature is valid
1167
                         * \param data The data to check signature against
1168
                         * \param signature Signature provided by the jwt
1169
                         * \param ec Filled with details on error
1170
                         */
1171
                        void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
20✔
1172
                                ec.clear();
20✔
1173
                                std::string der_signature = p1363_to_der_signature(signature, ec);
20✔
1174
                                if (ec) { return; }
20✔
1175

1176
                                auto ctx = helper::make_evp_md_ctx();
17✔
1177
                                if (!ctx) {
17✔
1178
                                        ec = error::signature_verification_error::create_context_failed;
1✔
1179
                                        return;
1✔
1180
                                }
1181
                                if (!EVP_DigestVerifyInit(ctx.get(), nullptr, md(), nullptr, pkey.get())) {
16✔
1182
                                        ec = error::signature_verification_error::verifyinit_failed;
1✔
1183
                                        return;
1✔
1184
                                }
1185
                                if (!EVP_DigestUpdate(ctx.get(), data.data(), data.size())) {
15✔
1186
                                        ec = error::signature_verification_error::verifyupdate_failed;
1✔
1187
                                        return;
1✔
1188
                                }
1189

1190
#if OPENSSL_VERSION_NUMBER < 0x10002000L
1191
                                unsigned char* der_sig_data = reinterpret_cast<unsigned char*>(const_cast<char*>(der_signature.data()));
1192
#else
1193
                                const unsigned char* der_sig_data = reinterpret_cast<const unsigned char*>(der_signature.data());
14✔
1194
#endif
1195
                                auto res =
1196
                                        EVP_DigestVerifyFinal(ctx.get(), der_sig_data, static_cast<unsigned int>(der_signature.length()));
14✔
1197
                                if (res == 0) {
14✔
1198
                                        ec = error::signature_verification_error::invalid_signature;
7✔
1199
                                        return;
7✔
1200
                                }
1201
                                if (res == -1) {
7✔
1202
                                        ec = error::signature_verification_error::verifyfinal_failed;
×
1203
                                        return;
×
1204
                                }
1205
                        }
30✔
1206
                        /**
1207
                         * Returns the algorithm name provided to the constructor
1208
                         * \return algorithm's name
1209
                         */
1210
                        std::string name() const { return alg_name; }
18✔
1211

1212
                private:
1213
                        static void check_public_key(EVP_PKEY* pkey) {
23✔
1214
#ifdef JWT_OPENSSL_3_0
1215
                                std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1216
                                        EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
23✔
1217
                                if (!ctx) { throw error::ecdsa_exception(error::ecdsa_error::create_context_failed); }
23✔
1218
                                if (EVP_PKEY_public_check(ctx.get()) != 1) {
22✔
1219
                                        throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1✔
1220
                                }
1221
#else
1222
                                std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey), EC_KEY_free);
1223
                                if (!eckey) { throw error::ecdsa_exception(error::ecdsa_error::invalid_key); }
1224
                                if (EC_KEY_check_key(eckey.get()) == 0) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1225
#endif
1226
                        }
23✔
1227

1228
                        static void check_private_key(EVP_PKEY* pkey) {
29✔
1229
#ifdef JWT_OPENSSL_3_0
1230
                                std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ctx(
1231
                                        EVP_PKEY_CTX_new_from_pkey(nullptr, pkey, nullptr), EVP_PKEY_CTX_free);
29✔
1232
                                if (!ctx) { throw error::ecdsa_exception(error::ecdsa_error::create_context_failed); }
29✔
1233
                                if (EVP_PKEY_private_check(ctx.get()) != 1) {
28✔
1234
                                        throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1✔
1235
                                }
1236
#else
1237
                                std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> eckey(EVP_PKEY_get1_EC_KEY(pkey), EC_KEY_free);
1238
                                if (!eckey) { throw error::ecdsa_exception(error::ecdsa_error::invalid_key); }
1239
                                if (EC_KEY_check_key(eckey.get()) == 0) throw error::ecdsa_exception(error::ecdsa_error::invalid_key);
1240
#endif
1241
                        }
29✔
1242

1243
                        std::string der_to_p1363_signature(const std::string& der_signature, std::error_code& ec) const {
5✔
1244
                                const unsigned char* possl_signature = reinterpret_cast<const unsigned char*>(der_signature.data());
5✔
1245
                                std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(
1246
                                        d2i_ECDSA_SIG(nullptr, &possl_signature, static_cast<long>(der_signature.length())),
5✔
1247
                                        ECDSA_SIG_free);
5✔
1248
                                if (!sig) {
5✔
1249
                                        ec = error::signature_generation_error::signature_decoding_failed;
1✔
1250
                                        return {};
1✔
1251
                                }
1252

1253
#ifdef JWT_OPENSSL_1_0_0
1254

1255
                                auto rr = helper::bn2raw(sig->r);
1256
                                auto rs = helper::bn2raw(sig->s);
1257
#else
1258
                                const BIGNUM* r;
1259
                                const BIGNUM* s;
1260
                                ECDSA_SIG_get0(sig.get(), &r, &s);
4✔
1261
                                auto rr = helper::bn2raw(r);
4✔
1262
                                auto rs = helper::bn2raw(s);
4✔
1263
#endif
1264
                                if (rr.size() > signature_length / 2 || rs.size() > signature_length / 2)
4✔
1265
                                        throw std::logic_error("bignum size exceeded expected length");
×
1266
                                rr.insert(0, signature_length / 2 - rr.size(), '\0');
4✔
1267
                                rs.insert(0, signature_length / 2 - rs.size(), '\0');
4✔
1268
                                return rr + rs;
4✔
1269
                        }
5✔
1270

1271
                        std::string p1363_to_der_signature(const std::string& signature, std::error_code& ec) const {
20✔
1272
                                ec.clear();
20✔
1273
                                auto r = helper::raw2bn(signature.substr(0, signature.size() / 2));
20✔
1274
                                auto s = helper::raw2bn(signature.substr(signature.size() / 2));
20✔
1275

1276
                                ECDSA_SIG* psig;
1277
#ifdef JWT_OPENSSL_1_0_0
1278
                                ECDSA_SIG sig;
1279
                                sig.r = r.get();
1280
                                sig.s = s.get();
1281
                                psig = &sig;
1282
#else
1283
                                std::unique_ptr<ECDSA_SIG, decltype(&ECDSA_SIG_free)> sig(ECDSA_SIG_new(), ECDSA_SIG_free);
20✔
1284
                                if (!sig) {
20✔
1285
                                        ec = error::signature_verification_error::create_context_failed;
1✔
1286
                                        return {};
1✔
1287
                                }
1288
                                ECDSA_SIG_set0(sig.get(), r.release(), s.release());
19✔
1289
                                psig = sig.get();
19✔
1290
#endif
1291

1292
                                int length = i2d_ECDSA_SIG(psig, nullptr);
19✔
1293
                                if (length < 0) {
19✔
1294
                                        ec = error::signature_verification_error::signature_encoding_failed;
1✔
1295
                                        return {};
1✔
1296
                                }
1297
                                std::string der_signature(length, '\0');
18✔
1298
                                unsigned char* psbuffer = (unsigned char*)der_signature.data();
18✔
1299
                                length = i2d_ECDSA_SIG(psig, &psbuffer);
18✔
1300
                                if (length < 0) {
18✔
1301
                                        ec = error::signature_verification_error::signature_encoding_failed;
1✔
1302
                                        return {};
1✔
1303
                                }
1304
                                der_signature.resize(length);
17✔
1305
                                return der_signature;
17✔
1306
                        }
20✔
1307

1308
                        /// OpenSSL struct containing keys
1309
                        helper::evp_pkey_handle pkey;
1310
                        /// Hash generator function
1311
                        const EVP_MD* (*md)();
1312
                        /// algorithm's name
1313
                        const std::string alg_name;
1314
                        /// Length of the resulting signature
1315
                        const size_t signature_length;
1316
                };
1317

1318
#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
1319
                /**
1320
                 * \brief Base class for EdDSA family of algorithms
1321
                 *
1322
                 * https://tools.ietf.org/html/rfc8032
1323
                 *
1324
                 * The EdDSA algorithms were introduced in [OpenSSL v1.1.1](https://www.openssl.org/news/openssl-1.1.1-notes.html),
1325
                 * so these algorithms are only available when building against this version or higher.
1326
                 */
1327
                struct eddsa {
1328
                        /**
1329
                         * Construct new eddsa algorithm
1330
                         * \param public_key EdDSA public key in PEM format
1331
                         * \param private_key EdDSA private key or empty string if not available. If empty, signing will always
1332
                         * fail.
1333
                         * \param public_key_password Password to decrypt public key pem.
1334
                         * \param private_key_password Password
1335
                         * to decrypt private key pem.
1336
                         * \param name Name of the algorithm
1337
                         */
1338
                        eddsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
26✔
1339
                                  const std::string& private_key_password, std::string name)
1340
                                : alg_name(std::move(name)) {
26✔
1341
                                if (!private_key.empty()) {
26✔
1342
                                        pkey = helper::load_private_key_from_string(private_key, private_key_password);
10✔
1343
                                } else if (!public_key.empty()) {
16✔
1344
                                        pkey = helper::load_public_key_from_string(public_key, public_key_password);
16✔
1345
                                } else
1346
                                        throw error::ecdsa_exception(error::ecdsa_error::load_key_bio_read);
×
1347
                        }
39✔
1348
                        /**
1349
                         * Sign jwt data
1350
                         * \param data The data to sign
1351
                         * \param ec error_code filled with details on error
1352
                         * \return EdDSA signature for the given data
1353
                         */
1354
                        std::string sign(const std::string& data, std::error_code& ec) const {
6✔
1355
                                ec.clear();
6✔
1356
                                auto ctx = helper::make_evp_md_ctx();
6✔
1357
                                if (!ctx) {
6✔
1358
                                        ec = error::signature_generation_error::create_context_failed;
1✔
1359
                                        return {};
1✔
1360
                                }
1361
                                if (!EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())) {
5✔
1362
                                        ec = error::signature_generation_error::signinit_failed;
1✔
1363
                                        return {};
1✔
1364
                                }
1365

1366
                                size_t len = EVP_PKEY_size(pkey.get());
4✔
1367
                                std::string res(len, '\0');
4✔
1368

1369
// LibreSSL is the special kid in the block, as it does not support EVP_DigestSign.
1370
// OpenSSL on the otherhand does not support using EVP_DigestSignUpdate for eddsa, which is why we end up with this
1371
// mess.
1372
#if defined(LIBRESSL_VERSION_NUMBER) || defined(LIBWOLFSSL_VERSION_HEX)
1373
                                ERR_clear_error();
1374
                                if (EVP_DigestSignUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()), data.size()) !=
1375
                                        1) {
1376
                                        std::cout << ERR_error_string(ERR_get_error(), NULL) << std::endl;
1377
                                        ec = error::signature_generation_error::signupdate_failed;
1378
                                        return {};
1379
                                }
1380
                                if (EVP_DigestSignFinal(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len) != 1) {
1381
                                        ec = error::signature_generation_error::signfinal_failed;
1382
                                        return {};
1383
                                }
1384
#else
1385
                                if (EVP_DigestSign(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len,
8✔
1386
                                                                   reinterpret_cast<const unsigned char*>(data.data()), data.size()) != 1) {
8✔
1387
                                        ec = error::signature_generation_error::signfinal_failed;
1✔
1388
                                        return {};
1✔
1389
                                }
1390
#endif
1391

1392
                                res.resize(len);
3✔
1393
                                return res;
3✔
1394
                        }
6✔
1395

1396
                        /**
1397
                         * Check if signature is valid
1398
                         * \param data The data to check signature against
1399
                         * \param signature Signature provided by the jwt
1400
                         * \param ec Filled with details on error
1401
                         */
1402
                        void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
12✔
1403
                                ec.clear();
12✔
1404
                                auto ctx = helper::make_evp_md_ctx();
12✔
1405
                                if (!ctx) {
12✔
1406
                                        ec = error::signature_verification_error::create_context_failed;
1✔
1407
                                        return;
1✔
1408
                                }
1409
                                if (!EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())) {
11✔
1410
                                        ec = error::signature_verification_error::verifyinit_failed;
1✔
1411
                                        return;
1✔
1412
                                }
1413
// LibreSSL is the special kid in the block, as it does not support EVP_DigestVerify.
1414
// OpenSSL on the otherhand does not support using EVP_DigestVerifyUpdate for eddsa, which is why we end up with this
1415
// mess.
1416
#if defined(LIBRESSL_VERSION_NUMBER) || defined(LIBWOLFSSL_VERSION_HEX)
1417
                                if (EVP_DigestVerifyUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()),
1418
                                                                                   data.size()) != 1) {
1419
                                        ec = error::signature_verification_error::verifyupdate_failed;
1420
                                        return;
1421
                                }
1422
                                if (EVP_DigestVerifyFinal(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
1423
                                                                                  signature.size()) != 1) {
1424
                                        ec = error::signature_verification_error::verifyfinal_failed;
1425
                                        return;
1426
                                }
1427
#else
1428
                                auto res = EVP_DigestVerify(ctx.get(), reinterpret_cast<const unsigned char*>(signature.data()),
20✔
1429
                                                                                        signature.size(), reinterpret_cast<const unsigned char*>(data.data()),
10✔
1430
                                                                                        data.size());
1431
                                if (res != 1) {
10✔
1432
                                        ec = error::signature_verification_error::verifyfinal_failed;
5✔
1433
                                        return;
5✔
1434
                                }
1435
#endif
1436
                        }
12✔
1437
                        /**
1438
                         * Returns the algorithm name provided to the constructor
1439
                         * \return algorithm's name
1440
                         */
1441
                        std::string name() const { return alg_name; }
10✔
1442

1443
                private:
1444
                        /// OpenSSL struct containing keys
1445
                        helper::evp_pkey_handle pkey;
1446
                        /// algorithm's name
1447
                        const std::string alg_name;
1448
                };
1449
#endif
1450
                /**
1451
                 * \brief Base class for PSS-RSA family of algorithms
1452
                 */
1453
                struct pss {
1454
                        /**
1455
                         * Construct new pss algorithm
1456
                         * \param public_key RSA public key in PEM format
1457
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1458
                         * \param public_key_password Password to decrypt public key pem.
1459
                         * \param private_key_password Password to decrypt private key pem.
1460
                         * \param md Pointer to hash function
1461
                         * \param name Name of the algorithm
1462
                         */
1463
                        pss(const std::string& public_key, const std::string& private_key, const std::string& public_key_password,
10✔
1464
                                const std::string& private_key_password, const EVP_MD* (*md)(), std::string name)
1465
                                : md(md), alg_name(std::move(name)) {
10✔
1466
                                if (!private_key.empty()) {
10✔
1467
                                        pkey = helper::load_private_key_from_string(private_key, private_key_password);
7✔
1468
                                } else if (!public_key.empty()) {
3✔
1469
                                        pkey = helper::load_public_key_from_string(public_key, public_key_password);
2✔
1470
                                } else
1471
                                        throw error::rsa_exception(error::rsa_error::no_key_provided);
1✔
1472
                        }
11✔
1473

1474
                        /**
1475
                         * Sign jwt data
1476
                         * \param data The data to sign
1477
                         * \param ec error_code filled with details on error
1478
                         * \return ECDSA signature for the given data
1479
                         */
1480
                        std::string sign(const std::string& data, std::error_code& ec) const {
8✔
1481
                                ec.clear();
8✔
1482
                                auto md_ctx = helper::make_evp_md_ctx();
8✔
1483
                                if (!md_ctx) {
8✔
1484
                                        ec = error::signature_generation_error::create_context_failed;
1✔
1485
                                        return {};
1✔
1486
                                }
1487
                                EVP_PKEY_CTX* ctx = nullptr;
7✔
1488
                                if (EVP_DigestSignInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1) {
7✔
1489
                                        ec = error::signature_generation_error::signinit_failed;
1✔
1490
                                        return {};
1✔
1491
                                }
1492
                                if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
6✔
1493
                                        ec = error::signature_generation_error::rsa_padding_failed;
×
1494
                                        return {};
×
1495
                                }
1496
// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1497
// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1498
#ifndef LIBWOLFSSL_VERSION_HEX
1499
                                if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0) {
6✔
1500
                                        ec = error::signature_generation_error::set_rsa_pss_saltlen_failed;
×
1501
                                        return {};
×
1502
                                }
1503
#endif
1504
                                if (EVP_DigestUpdate(md_ctx.get(), data.data(), data.size()) != 1) {
6✔
1505
                                        ec = error::signature_generation_error::digestupdate_failed;
1✔
1506
                                        return {};
1✔
1507
                                }
1508

1509
                                size_t size = EVP_PKEY_size(pkey.get());
5✔
1510
                                std::string res(size, 0x00);
5✔
1511
                                if (EVP_DigestSignFinal(
5✔
1512
                                                md_ctx.get(),
1513
                                                (unsigned char*)res.data(), // NOLINT(google-readability-casting) requires `const_cast`
5✔
1514
                                                &size) <= 0) {
5✔
1515
                                        ec = error::signature_generation_error::signfinal_failed;
1✔
1516
                                        return {};
1✔
1517
                                }
1518

1519
                                return res;
4✔
1520
                        }
8✔
1521

1522
                        /**
1523
                         * Check if signature is valid
1524
                         * \param data The data to check signature against
1525
                         * \param signature Signature provided by the jwt
1526
                         * \param ec Filled with error details
1527
                         */
1528
                        void verify(const std::string& data, const std::string& signature, std::error_code& ec) const {
8✔
1529
                                ec.clear();
8✔
1530

1531
                                auto md_ctx = helper::make_evp_md_ctx();
8✔
1532
                                if (!md_ctx) {
8✔
1533
                                        ec = error::signature_verification_error::create_context_failed;
1✔
1534
                                        return;
1✔
1535
                                }
1536
                                EVP_PKEY_CTX* ctx = nullptr;
7✔
1537
                                if (EVP_DigestVerifyInit(md_ctx.get(), &ctx, md(), nullptr, pkey.get()) != 1) {
7✔
1538
                                        ec = error::signature_verification_error::verifyinit_failed;
1✔
1539
                                        return;
1✔
1540
                                }
1541
                                if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
6✔
1542
                                        ec = error::signature_generation_error::rsa_padding_failed;
×
1543
                                        return;
×
1544
                                }
1545
// wolfSSL does not require EVP_PKEY_CTX_set_rsa_pss_saltlen. The default behavior
1546
// sets the salt length to the hash length. Unlike OpenSSL which exposes this functionality.
1547
#ifndef LIBWOLFSSL_VERSION_HEX
1548
                                if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0) {
6✔
1549
                                        ec = error::signature_verification_error::set_rsa_pss_saltlen_failed;
×
1550
                                        return;
×
1551
                                }
1552
#endif
1553
                                if (EVP_DigestUpdate(md_ctx.get(), data.data(), data.size()) != 1) {
6✔
1554
                                        ec = error::signature_verification_error::verifyupdate_failed;
1✔
1555
                                        return;
1✔
1556
                                }
1557

1558
                                if (EVP_DigestVerifyFinal(md_ctx.get(), (unsigned char*)signature.data(), signature.size()) <= 0) {
5✔
1559
                                        ec = error::signature_verification_error::verifyfinal_failed;
2✔
1560
                                        return;
2✔
1561
                                }
1562
                        }
8✔
1563
                        /**
1564
                         * Returns the algorithm name provided to the constructor
1565
                         * \return algorithm's name
1566
                         */
1567
                        std::string name() const { return alg_name; }
6✔
1568

1569
                private:
1570
                        /// OpenSSL structure containing keys
1571
                        helper::evp_pkey_handle pkey;
1572
                        /// Hash generator function
1573
                        const EVP_MD* (*md)();
1574
                        /// algorithm's name
1575
                        const std::string alg_name;
1576
                };
1577

1578
                /**
1579
                 * HS256 algorithm
1580
                 */
1581
                struct hs256 : public hmacsha {
1582
                        /**
1583
                         * Construct new instance of algorithm
1584
                         * \param key HMAC signing key
1585
                         */
1586
                        explicit hs256(std::string key) : hmacsha(std::move(key), EVP_sha256, "HS256") {}
28✔
1587
                };
1588
                /**
1589
                 * HS384 algorithm
1590
                 */
1591
                struct hs384 : public hmacsha {
1592
                        /**
1593
                         * Construct new instance of algorithm
1594
                         * \param key HMAC signing key
1595
                         */
1596
                        explicit hs384(std::string key) : hmacsha(std::move(key), EVP_sha384, "HS384") {}
1597
                };
1598
                /**
1599
                 * HS512 algorithm
1600
                 */
1601
                struct hs512 : public hmacsha {
1602
                        /**
1603
                         * Construct new instance of algorithm
1604
                         * \param key HMAC signing key
1605
                         */
1606
                        explicit hs512(std::string key) : hmacsha(std::move(key), EVP_sha512, "HS512") {}
1607
                };
1608
                /**
1609
                 * RS256 algorithm
1610
                 */
1611
                struct rs256 : public rsa {
1612
                        /**
1613
                         * Construct new instance of algorithm
1614
                         * \param public_key RSA public key in PEM format
1615
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1616
                         * \param public_key_password Password to decrypt public key pem.
1617
                         * \param private_key_password Password to decrypt private key pem.
1618
                         */
1619
                        explicit rs256(const std::string& public_key, const std::string& private_key = "",
9✔
1620
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1621
                                : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "RS256") {}
10✔
1622
                };
1623
                /**
1624
                 * RS384 algorithm
1625
                 */
1626
                struct rs384 : public rsa {
1627
                        /**
1628
                         * Construct new instance of algorithm
1629
                         * \param public_key RSA public key in PEM format
1630
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1631
                         * \param public_key_password Password to decrypt public key pem.
1632
                         * \param private_key_password Password to decrypt private key pem.
1633
                         */
1634
                        explicit rs384(const std::string& public_key, const std::string& private_key = "",
1635
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1636
                                : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "RS384") {}
1637
                };
1638
                /**
1639
                 * RS512 algorithm
1640
                 */
1641
                struct rs512 : public rsa {
1642
                        /**
1643
                         * Construct new instance of algorithm
1644
                         * \param public_key RSA public key in PEM format
1645
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1646
                         * \param public_key_password Password to decrypt public key pem.
1647
                         * \param private_key_password Password to decrypt private key pem.
1648
                         */
1649
                        explicit rs512(const std::string& public_key, const std::string& private_key = "",
5✔
1650
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1651
                                : rsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "RS512") {}
5✔
1652
                };
1653
                /**
1654
                 * ES256 algorithm
1655
                 */
1656
                struct es256 : public ecdsa {
1657
                        /**
1658
                         * Construct new instance of algorithm
1659
                         * \param public_key ECDSA public key in PEM format
1660
                         * \param private_key ECDSA private key or empty string if not available. If empty, signing will always
1661
                         * fail.
1662
                         * \param public_key_password Password to decrypt public key pem.
1663
                         * \param private_key_password Password
1664
                         * to decrypt private key pem.
1665
                         */
1666
                        explicit es256(const std::string& public_key, const std::string& private_key = "",
37✔
1667
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1668
                                : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "ES256", 64) {}
64✔
1669
                };
1670
                /**
1671
                 * ES384 algorithm
1672
                 */
1673
                struct es384 : public ecdsa {
1674
                        /**
1675
                         * Construct new instance of algorithm
1676
                         * \param public_key ECDSA public key in PEM format
1677
                         * \param private_key ECDSA private key or empty string if not available. If empty, signing will always
1678
                         * fail.
1679
                         * \param public_key_password Password to decrypt public key pem.
1680
                         * \param private_key_password Password
1681
                         * to decrypt private key pem.
1682
                         */
1683
                        explicit es384(const std::string& public_key, const std::string& private_key = "",
15✔
1684
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1685
                                : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "ES384", 96) {}
23✔
1686
                };
1687
                /**
1688
                 * ES512 algorithm
1689
                 */
1690
                struct es512 : public ecdsa {
1691
                        /**
1692
                         * Construct new instance of algorithm
1693
                         * \param public_key ECDSA public key in PEM format
1694
                         * \param private_key ECDSA private key or empty string if not available. If empty, signing will always
1695
                         * fail.
1696
                         * \param public_key_password Password to decrypt public key pem.
1697
                         * \param private_key_password Password
1698
                         * to decrypt private key pem.
1699
                         */
1700
                        explicit es512(const std::string& public_key, const std::string& private_key = "",
15✔
1701
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1702
                                : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "ES512", 132) {}
23✔
1703
                };
1704
                /**
1705
                 * ES256K algorithm
1706
                 */
1707
                struct es256k : public ecdsa {
1708
                        /**
1709
                         * Construct new instance of algorithm
1710
                         * \param public_key ECDSA public key in PEM format
1711
                         * \param private_key ECDSA private key or empty string if not available. If empty, signing will always
1712
                         * fail.
1713
                         * \param public_key_password Password to decrypt public key pem.
1714
                         * \param private_key_password Password to decrypt private key pem.
1715
                         */
1716
                        explicit es256k(const std::string& public_key, const std::string& private_key = "",
1717
                                                        const std::string& public_key_password = "", const std::string& private_key_password = "")
1718
                                : ecdsa(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "ES256K", 64) {}
1719
                };
1720

1721
#if !defined(JWT_OPENSSL_1_0_0) && !defined(JWT_OPENSSL_1_1_0)
1722
                /**
1723
                 * Ed25519 algorithm
1724
                 *
1725
                 * https://en.wikipedia.org/wiki/EdDSA#Ed25519
1726
                 *
1727
                 * Requires at least OpenSSL 1.1.1.
1728
                 */
1729
                struct ed25519 : public eddsa {
1730
                        /**
1731
                         * Construct new instance of algorithm
1732
                         * \param public_key Ed25519 public key in PEM format
1733
                         * \param private_key Ed25519 private key or empty string if not available. If empty, signing will always
1734
                         * fail.
1735
                         * \param public_key_password Password to decrypt public key pem.
1736
                         * \param private_key_password Password
1737
                         * to decrypt private key pem.
1738
                         */
1739
                        explicit ed25519(const std::string& public_key, const std::string& private_key = "",
21✔
1740
                                                         const std::string& public_key_password = "", const std::string& private_key_password = "")
1741
                                : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA") {}
34✔
1742
                };
1743

1744
                /**
1745
                 * Ed448 algorithm
1746
                 *
1747
                 * https://en.wikipedia.org/wiki/EdDSA#Ed448
1748
                 *
1749
                 * Requires at least OpenSSL 1.1.1.
1750
                 */
1751
                struct ed448 : public eddsa {
1752
                        /**
1753
                         * Construct new instance of algorithm
1754
                         * \param public_key Ed448 public key in PEM format
1755
                         * \param private_key Ed448 private key or empty string if not available. If empty, signing will always
1756
                         * fail.
1757
                         * \param public_key_password Password to decrypt public key pem.
1758
                         * \param private_key_password Password
1759
                         * to decrypt private key pem.
1760
                         */
1761
                        explicit ed448(const std::string& public_key, const std::string& private_key = "",
5✔
1762
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1763
                                : eddsa(public_key, private_key, public_key_password, private_key_password, "EdDSA") {}
5✔
1764
                };
1765
#endif
1766

1767
                /**
1768
                 * PS256 algorithm
1769
                 */
1770
                struct ps256 : public pss {
1771
                        /**
1772
                         * Construct new instance of algorithm
1773
                         * \param public_key RSA public key in PEM format
1774
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1775
                         * \param public_key_password Password to decrypt public key pem.
1776
                         * \param private_key_password Password to decrypt private key pem.
1777
                         */
1778
                        explicit ps256(const std::string& public_key, const std::string& private_key = "",
8✔
1779
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1780
                                : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha256, "PS256") {}
9✔
1781
                };
1782
                /**
1783
                 * PS384 algorithm
1784
                 */
1785
                struct ps384 : public pss {
1786
                        /**
1787
                         * Construct new instance of algorithm
1788
                         * \param public_key RSA public key in PEM format
1789
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1790
                         * \param public_key_password Password to decrypt public key pem.
1791
                         * \param private_key_password Password to decrypt private key pem.
1792
                         */
1793
                        explicit ps384(const std::string& public_key, const std::string& private_key = "",
1✔
1794
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1795
                                : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha384, "PS384") {}
1✔
1796
                };
1797
                /**
1798
                 * PS512 algorithm
1799
                 */
1800
                struct ps512 : public pss {
1801
                        /**
1802
                         * Construct new instance of algorithm
1803
                         * \param public_key RSA public key in PEM format
1804
                         * \param private_key RSA private key or empty string if not available. If empty, signing will always fail.
1805
                         * \param public_key_password Password to decrypt public key pem.
1806
                         * \param private_key_password Password to decrypt private key pem.
1807
                         */
1808
                        explicit ps512(const std::string& public_key, const std::string& private_key = "",
1✔
1809
                                                   const std::string& public_key_password = "", const std::string& private_key_password = "")
1810
                                : pss(public_key, private_key, public_key_password, private_key_password, EVP_sha512, "PS512") {}
1✔
1811
                };
1812
        } // namespace algorithm
1813

1814
        /**
1815
         * \brief JSON Abstractions for working with any library
1816
         */
1817
        namespace json {
1818
                /**
1819
                 * \brief Generic JSON types used in JWTs
1820
                 *
1821
                 * This enum is to abstract the third party underlying types
1822
                 */
1823
                enum class type { boolean, integer, number, string, array, object };
1824
        } // namespace json
1825

1826
        namespace details {
1827
#ifdef __cpp_lib_void_t
1828
                template<typename... Ts>
1829
                using void_t = std::void_t<Ts...>;
1830
#else
1831
                // https://en.cppreference.com/w/cpp/types/void_t
1832
                template<typename... Ts>
1833
                struct make_void {
1834
                        using type = void;
1835
                };
1836

1837
                template<typename... Ts>
1838
                using void_t = typename make_void<Ts...>::type;
1839
#endif
1840

1841
#ifdef __cpp_lib_experimental_detect
1842
                template<template<typename...> class _Op, typename... _Args>
1843
                using is_detected = std::experimental::is_detected<_Op, _Args...>;
1844
#else
1845
                struct nonesuch {
1846
                        nonesuch() = delete;
1847
                        ~nonesuch() = delete;
1848
                        nonesuch(nonesuch const&) = delete;
1849
                        nonesuch(nonesuch const&&) = delete;
1850
                        void operator=(nonesuch const&) = delete;
1851
                        void operator=(nonesuch&&) = delete;
1852
                };
1853

1854
                // https://en.cppreference.com/w/cpp/experimental/is_detected
1855
                template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
1856
                struct detector {
1857
                        using value = std::false_type;
1858
                        using type = Default;
1859
                };
1860

1861
                template<class Default, template<class...> class Op, class... Args>
1862
                struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
1863
                        using value = std::true_type;
1864
                        using type = Op<Args...>;
1865
                };
1866

1867
                template<template<class...> class Op, class... Args>
1868
                using is_detected = typename detector<nonesuch, void, Op, Args...>::value;
1869
#endif
1870

1871
                template<typename T, typename Signature>
1872
                using is_signature = typename std::is_same<T, Signature>;
1873

1874
                template<typename traits_type, template<typename...> class Op, typename Signature>
1875
                struct is_function_signature_detected {
1876
                        using type = Op<traits_type>;
1877
                        static constexpr auto value = is_detected<Op, traits_type>::value && std::is_function<type>::value &&
1878
                                                                                  is_signature<type, Signature>::value;
1879
                };
1880

1881
                template<typename traits_type, typename value_type>
1882
                struct supports_get_type {
1883
                        template<typename T>
1884
                        using get_type_t = decltype(T::get_type);
1885

1886
                        static constexpr auto value =
1887
                                is_function_signature_detected<traits_type, get_type_t, json::type(const value_type&)>::value;
1888

1889
                        // Internal assertions for better feedback
1890
                        static_assert(value, "traits implementation must provide `jwt::json::type get_type(const value_type&)`");
1891
                };
1892

1893
#define JWT_CPP_JSON_TYPE_TYPE(TYPE) json_##TYPE_type
1894
#define JWT_CPP_AS_TYPE_T(TYPE) as_##TYPE_t
1895
#define JWT_CPP_SUPPORTS_AS(TYPE)                                                                                      \
1896
        template<typename traits_type, typename value_type, typename JWT_CPP_JSON_TYPE_TYPE(TYPE)>                         \
1897
        struct supports_as_##TYPE {                                                                                        \
1898
                template<typename T>                                                                                           \
1899
                using JWT_CPP_AS_TYPE_T(TYPE) = decltype(T::as_##TYPE);                                                        \
1900
                                                                                                                       \
1901
                static constexpr auto value =                                                                                  \
1902
                        is_function_signature_detected<traits_type, JWT_CPP_AS_TYPE_T(TYPE),                                       \
1903
                                                                                   JWT_CPP_JSON_TYPE_TYPE(TYPE)(const value_type&)>::value;                    \
1904
                                                                                                                       \
1905
                static_assert(value, "traits implementation must provide `" #TYPE "_type as_" #TYPE "(const value_type&)`");   \
1906
        }
1907

1908
                JWT_CPP_SUPPORTS_AS(object);
1909
                JWT_CPP_SUPPORTS_AS(array);
1910
                JWT_CPP_SUPPORTS_AS(string);
1911
                JWT_CPP_SUPPORTS_AS(number);
1912
                JWT_CPP_SUPPORTS_AS(integer);
1913
                JWT_CPP_SUPPORTS_AS(boolean);
1914

1915
#undef JWT_CPP_JSON_TYPE_TYPE
1916
#undef JWT_CPP_AS_TYPE_T
1917
#undef JWT_CPP_SUPPORTS_AS
1918

1919
                template<typename traits>
1920
                struct is_valid_traits {
1921
                        static constexpr auto value =
1922
                                supports_get_type<traits, typename traits::value_type>::value &&
1923
                                supports_as_object<traits, typename traits::value_type, typename traits::object_type>::value &&
1924
                                supports_as_array<traits, typename traits::value_type, typename traits::array_type>::value &&
1925
                                supports_as_string<traits, typename traits::value_type, typename traits::string_type>::value &&
1926
                                supports_as_number<traits, typename traits::value_type, typename traits::number_type>::value &&
1927
                                supports_as_integer<traits, typename traits::value_type, typename traits::integer_type>::value &&
1928
                                supports_as_boolean<traits, typename traits::value_type, typename traits::boolean_type>::value;
1929
                };
1930

1931
                template<typename value_type>
1932
                struct is_valid_json_value {
1933
                        static constexpr auto value =
1934
                                std::is_default_constructible<value_type>::value &&
1935
                                std::is_constructible<value_type, const value_type&>::value && // a more generic is_copy_constructible
1936
                                std::is_move_constructible<value_type>::value && std::is_assignable<value_type, value_type>::value &&
1937
                                std::is_copy_assignable<value_type>::value && std::is_move_assignable<value_type>::value;
1938
                        // TODO(prince-chrismc): Stream operators
1939
                };
1940

1941
                // https://stackoverflow.com/a/53967057/8480874
1942
                template<typename T, typename = void>
1943
                struct is_iterable : std::false_type {};
1944

1945
                template<typename T>
1946
                struct is_iterable<T, void_t<decltype(std::begin(std::declval<T>())), decltype(std::end(std::declval<T>())),
1947
#if __cplusplus > 201402L
1948
                                                                         decltype(std::cbegin(std::declval<T>())), decltype(std::cend(std::declval<T>()))
1949
#else
1950
                                                                         decltype(std::begin(std::declval<const T>())),
1951
                                                                         decltype(std::end(std::declval<const T>()))
1952
#endif
1953
                                                                         >> : std::true_type {
1954
                };
1955

1956
#if __cplusplus > 201703L
1957
                template<typename T>
1958
                inline constexpr bool is_iterable_v = is_iterable<T>::value;
1959
#endif
1960

1961
                template<typename object_type, typename string_type>
1962
                using is_count_signature = typename std::is_integral<decltype(std::declval<const object_type>().count(
1963
                        std::declval<const string_type>()))>;
1964

1965
                template<typename object_type, typename string_type, typename = void>
1966
                struct is_subcription_operator_signature : std::false_type {};
1967

1968
                template<typename object_type, typename string_type>
1969
                struct is_subcription_operator_signature<
1970
                        object_type, string_type,
1971
                        void_t<decltype(std::declval<object_type>().operator[](std::declval<string_type>()))>> : std::true_type {
1972
                        // TODO(prince-chrismc): I am not convienced this is meaningful anymore
1973
                        static_assert(
1974
                                value,
1975
                                "object_type must implementate the subscription operator '[]' taking string_type as an arguement");
1976
                };
1977

1978
                template<typename object_type, typename value_type, typename string_type>
1979
                using is_at_const_signature =
1980
                        typename std::is_same<decltype(std::declval<const object_type>().at(std::declval<const string_type>())),
1981
                                                                  const value_type&>;
1982

1983
                template<typename value_type, typename string_type, typename object_type>
1984
                struct is_valid_json_object {
1985
                        template<typename T>
1986
                        using mapped_type_t = typename T::mapped_type;
1987
                        template<typename T>
1988
                        using key_type_t = typename T::key_type;
1989
                        template<typename T>
1990
                        using iterator_t = typename T::iterator;
1991
                        template<typename T>
1992
                        using const_iterator_t = typename T::const_iterator;
1993

1994
                        static constexpr auto value =
1995
                                std::is_constructible<value_type, object_type>::value &&
1996
                                is_detected<mapped_type_t, object_type>::value &&
1997
                                std::is_same<typename object_type::mapped_type, value_type>::value &&
1998
                                is_detected<key_type_t, object_type>::value &&
1999
                                (std::is_same<typename object_type::key_type, string_type>::value ||
2000
                                 std::is_constructible<typename object_type::key_type, string_type>::value) &&
2001
                                is_detected<iterator_t, object_type>::value && is_detected<const_iterator_t, object_type>::value &&
2002
                                is_iterable<object_type>::value && is_count_signature<object_type, string_type>::value &&
2003
                                is_subcription_operator_signature<object_type, string_type>::value &&
2004
                                is_at_const_signature<object_type, value_type, string_type>::value;
2005
                };
2006

2007
                template<typename value_type, typename array_type>
2008
                struct is_valid_json_array {
2009
                        template<typename T>
2010
                        using value_type_t = typename T::value_type;
2011

2012
                        static constexpr auto value = std::is_constructible<value_type, array_type>::value &&
2013
                                                                                  is_iterable<array_type>::value &&
2014
                                                                                  is_detected<value_type_t, array_type>::value &&
2015
                                                                                  std::is_same<typename array_type::value_type, value_type>::value;
2016
                };
2017

2018
                template<typename string_type, typename integer_type>
2019
                using is_substr_start_end_index_signature =
2020
                        typename std::is_same<decltype(std::declval<string_type>().substr(std::declval<integer_type>(),
2021
                                                                                                                                                          std::declval<integer_type>())),
2022
                                                                  string_type>;
2023

2024
                template<typename string_type, typename integer_type>
2025
                using is_substr_start_index_signature =
2026
                        typename std::is_same<decltype(std::declval<string_type>().substr(std::declval<integer_type>())),
2027
                                                                  string_type>;
2028

2029
                template<typename string_type>
2030
                using is_std_operate_plus_signature =
2031
                        typename std::is_same<decltype(std::operator+(std::declval<string_type>(), std::declval<string_type>())),
2032
                                                                  string_type>;
2033

2034
                template<typename value_type, typename string_type, typename integer_type>
2035
                struct is_valid_json_string {
2036
                        static constexpr auto substr = is_substr_start_end_index_signature<string_type, integer_type>::value &&
2037
                                                                                   is_substr_start_index_signature<string_type, integer_type>::value;
2038
                        static_assert(substr, "string_type must have a substr method taking only a start index and an overload "
2039
                                                                  "taking a start and end index, both must return a string_type");
2040

2041
                        static constexpr auto operator_plus = is_std_operate_plus_signature<string_type>::value;
2042
                        static_assert(operator_plus,
2043
                                                  "string_type must have a '+' operator implemented which returns the concatenated string");
2044

2045
                        static constexpr auto value =
2046
                                std::is_constructible<value_type, string_type>::value && substr && operator_plus;
2047
                };
2048

2049
                template<typename value_type, typename number_type>
2050
                struct is_valid_json_number {
2051
                        static constexpr auto value =
2052
                                std::is_floating_point<number_type>::value && std::is_constructible<value_type, number_type>::value;
2053
                };
2054

2055
                template<typename value_type, typename integer_type>
2056
                struct is_valid_json_integer {
2057
                        static constexpr auto value = std::is_signed<integer_type>::value &&
2058
                                                                                  !std::is_floating_point<integer_type>::value &&
2059
                                                                                  std::is_constructible<value_type, integer_type>::value;
2060
                };
2061
                template<typename value_type, typename boolean_type>
2062
                struct is_valid_json_boolean {
2063
                        static constexpr auto value = std::is_convertible<boolean_type, bool>::value &&
2064
                                                                                  std::is_constructible<value_type, boolean_type>::value;
2065
                };
2066

2067
                template<typename value_type, typename object_type, typename array_type, typename string_type,
2068
                                 typename number_type, typename integer_type, typename boolean_type>
2069
                struct is_valid_json_types {
2070
                        // Internal assertions for better feedback
2071
                        static_assert(is_valid_json_value<value_type>::value,
2072
                                                  "value_type must meet basic requirements, default constructor, copyable, moveable");
2073
                        static_assert(is_valid_json_object<value_type, string_type, object_type>::value,
2074
                                                  "object_type must be a string_type to value_type container");
2075
                        static_assert(is_valid_json_array<value_type, array_type>::value,
2076
                                                  "array_type must be a container of value_type");
2077

2078
                        static constexpr auto value = is_valid_json_value<value_type>::value &&
2079
                                                                                  is_valid_json_object<value_type, string_type, object_type>::value &&
2080
                                                                                  is_valid_json_array<value_type, array_type>::value &&
2081
                                                                                  is_valid_json_string<value_type, string_type, integer_type>::value &&
2082
                                                                                  is_valid_json_number<value_type, number_type>::value &&
2083
                                                                                  is_valid_json_integer<value_type, integer_type>::value &&
2084
                                                                                  is_valid_json_boolean<value_type, boolean_type>::value;
2085
                };
2086
        } // namespace details
2087

2088
        /**
2089
         * \brief a class to store a generic JSON value as claim
2090
         *
2091
         * \tparam json_traits : JSON implementation traits
2092
         *
2093
         * \see [RFC 7519: JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519)
2094
         */
2095
        template<typename json_traits>
2096
        class basic_claim {
2097
                /**
2098
                 * The reason behind this is to provide an expressive abstraction without
2099
                 * over complexifying the API. For more information take the time to read
2100
                 * https://github.com/nlohmann/json/issues/774. It maybe be expanded to
2101
                 * support custom string types.
2102
                 */
2103
                static_assert(std::is_same<typename json_traits::string_type, std::string>::value ||
2104
                                                  std::is_convertible<typename json_traits::string_type, std::string>::value ||
2105
                                                  std::is_constructible<typename json_traits::string_type, std::string>::value,
2106
                                          "string_type must be a std::string, convertible to a std::string, or construct a std::string.");
2107

2108
                static_assert(
2109
                        details::is_valid_json_types<typename json_traits::value_type, typename json_traits::object_type,
2110
                                                                                 typename json_traits::array_type, typename json_traits::string_type,
2111
                                                                                 typename json_traits::number_type, typename json_traits::integer_type,
2112
                                                                                 typename json_traits::boolean_type>::value,
2113
                        "must staisfy json container requirements");
2114
                static_assert(details::is_valid_traits<json_traits>::value, "traits must satisfy requirements");
2115

2116
                typename json_traits::value_type val;
2117

2118
        public:
2119
                using set_t = std::set<typename json_traits::string_type>;
2120

2121
                basic_claim() = default;
14✔
2122
                basic_claim(const basic_claim&) = default;
183✔
2123
                basic_claim(basic_claim&&) = default;
33✔
2124
                basic_claim& operator=(const basic_claim&) = default;
2125
                basic_claim& operator=(basic_claim&&) = default;
2126
                ~basic_claim() = default;
498✔
2127

2128
                JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::string_type s) : val(std::move(s)) {}
38✔
2129
                JWT_CLAIM_EXPLICIT basic_claim(const date& d)
18✔
2130
                        : val(typename json_traits::integer_type(std::chrono::system_clock::to_time_t(d))) {}
18✔
2131
                JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::array_type a) : val(std::move(a)) {}
2132
                JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::value_type v) : val(std::move(v)) {}
202✔
2133
                JWT_CLAIM_EXPLICIT basic_claim(const set_t& s) : val(typename json_traits::array_type(s.begin(), s.end())) {}
3✔
2134
                template<typename Iterator>
2135
                basic_claim(Iterator begin, Iterator end) : val(typename json_traits::array_type(begin, end)) {}
7✔
2136

2137
                /**
2138
                 * Get wrapped JSON value
2139
                 * \return Wrapped JSON value
2140
                 */
2141
                typename json_traits::value_type to_json() const { return val; }
38✔
2142

2143
                /**
2144
                 * Parse input stream into underlying JSON value
2145
                 * \return input stream
2146
                 */
2147
                std::istream& operator>>(std::istream& is) { return is >> val; }
6✔
2148

2149
                /**
2150
                 * Serialize claim to output stream from wrapped JSON value
2151
                 * \return ouput stream
2152
                 */
2153
                std::ostream& operator<<(std::ostream& os) { return os << val; }
2154

2155
                /**
2156
                 * Get type of contained JSON value
2157
                 * \return Type
2158
                 * \throw std::logic_error An internal error occured
2159
                 */
2160
                json::type get_type() const { return json_traits::get_type(val); }
150✔
2161

2162
                /**
2163
                 * Get the contained JSON value as a string
2164
                 * \return content as string
2165
                 * \throw std::bad_cast Content was not a string
2166
                 */
2167
                typename json_traits::string_type as_string() const { return json_traits::as_string(val); }
170✔
2168

2169
                /**
2170
                 * \brief Get the contained JSON value as a date
2171
                 *
2172
                 * If the value is a decimal, it is rounded up to the closest integer
2173
                 *
2174
                 * \return content as date
2175
                 * \throw std::bad_cast Content was not a date
2176
                 */
2177
                date as_date() const {
31✔
2178
                        using std::chrono::system_clock;
2179
                        if (get_type() == json::type::number) return system_clock::from_time_t(std::round(as_number()));
31✔
2180
                        return system_clock::from_time_t(as_integer());
31✔
2181
                }
2182

2183
                /**
2184
                 * Get the contained JSON value as an array
2185
                 * \return content as array
2186
                 * \throw std::bad_cast Content was not an array
2187
                 */
2188
                typename json_traits::array_type as_array() const { return json_traits::as_array(val); }
7✔
2189

2190
                /**
2191
                 * Get the contained JSON value as a set of strings
2192
                 * \return content as set of strings
2193
                 * \throw std::bad_cast Content was not an array of string
2194
                 */
2195
                set_t as_set() const {
1✔
2196
                        set_t res;
1✔
2197
                        for (const auto& e : json_traits::as_array(val)) {
3✔
2198
                                res.insert(json_traits::as_string(e));
2✔
2199
                        }
2200
                        return res;
1✔
2201
                }
×
2202

2203
                /**
2204
                 * Get the contained JSON value as an integer
2205
                 * \return content as int
2206
                 * \throw std::bad_cast Content was not an int
2207
                 */
2208
                typename json_traits::integer_type as_integer() const { return json_traits::as_integer(val); }
33✔
2209

2210
                /**
2211
                 * Get the contained JSON value as a bool
2212
                 * \return content as bool
2213
                 * \throw std::bad_cast Content was not a bool
2214
                 */
2215
                typename json_traits::boolean_type as_boolean() const { return json_traits::as_boolean(val); }
1✔
2216

2217
                /**
2218
                 * Get the contained JSON value as a number
2219
                 * \return content as double
2220
                 * \throw std::bad_cast Content was not a number
2221
                 */
2222
                typename json_traits::number_type as_number() const { return json_traits::as_number(val); }
1✔
2223
        };
2224

2225
        namespace error {
2226
                /**
2227
                 * Attempt to parse JSON was unsuccessful
2228
                 */
2229
                struct invalid_json_exception : public std::runtime_error {
2230
                        invalid_json_exception() : runtime_error("invalid json") {}
3✔
2231
                };
2232
                /**
2233
                 * Attempt to access claim was unsuccessful
2234
                 */
2235
                struct claim_not_present_exception : public std::out_of_range {
2236
                        claim_not_present_exception() : out_of_range("claim not found") {}
6✔
2237
                };
2238
        } // namespace error
2239

2240
        namespace details {
2241
                template<typename json_traits>
2242
                struct map_of_claims {
2243
                        typename json_traits::object_type claims;
2244
                        using basic_claim_t = basic_claim<json_traits>;
2245
                        using iterator = typename json_traits::object_type::iterator;
2246
                        using const_iterator = typename json_traits::object_type::const_iterator;
2247

2248
                        map_of_claims() = default;
142✔
2249
                        map_of_claims(const map_of_claims&) = default;
13✔
2250
                        map_of_claims(map_of_claims&&) = default;
2251
                        map_of_claims& operator=(const map_of_claims&) = default;
2252
                        map_of_claims& operator=(map_of_claims&&) = default;
134✔
2253

2254
                        map_of_claims(typename json_traits::object_type json) : claims(std::move(json)) {}
141✔
2255

2256
                        iterator begin() { return claims.begin(); }
2257
                        iterator end() { return claims.end(); }
2258
                        const_iterator cbegin() const { return claims.begin(); }
2259
                        const_iterator cend() const { return claims.end(); }
2260
                        const_iterator begin() const { return claims.begin(); }
2261
                        const_iterator end() const { return claims.end(); }
2262

2263
                        /**
2264
                         * \brief Parse a JSON string into a map of claims
2265
                         *
2266
                         * The implication is that a "map of claims" is identic to a JSON object
2267
                         *
2268
                         * \param str JSON data to be parse as an object
2269
                         * \return content as JSON object
2270
                         */
2271
                        static typename json_traits::object_type parse_claims(const typename json_traits::string_type& str) {
138✔
2272
                                typename json_traits::value_type val;
138✔
2273
                                if (!json_traits::parse(val, str)) throw error::invalid_json_exception();
138✔
2274

2275
                                return json_traits::as_object(val);
269✔
2276
                        };
138✔
2277

2278
                        /**
2279
                         * Check if a claim is present in the map
2280
                         * \return true if claim was present, false otherwise
2281
                         */
2282
                        bool has_claim(const typename json_traits::string_type& name) const noexcept {
492✔
2283
                                return claims.count(name) != 0;
492✔
2284
                        }
2285

2286
                        /**
2287
                         * Get a claim by name
2288
                         *
2289
                         * \param name the name of the desired claim
2290
                         * \return Requested claim
2291
                         * \throw jwt::error::claim_not_present_exception if the claim was not present
2292
                         */
2293
                        basic_claim_t get_claim(const typename json_traits::string_type& name) const {
197✔
2294
                                if (!has_claim(name)) throw error::claim_not_present_exception();
197✔
2295
                                return basic_claim_t{claims.at(name)};
193✔
2296
                        }
2297
                };
2298
        } // namespace details
2299

2300
        /**
2301
         * Base class that represents a token payload.
2302
         * Contains Convenience accessors for common claims.
2303
         */
2304
        template<typename json_traits>
2305
        class payload {
2306
        protected:
2307
                details::map_of_claims<json_traits> payload_claims;
2308

2309
        public:
2310
                using basic_claim_t = basic_claim<json_traits>;
2311

2312
                /**
2313
                 * Check if issuer is present ("iss")
2314
                 * \return true if present, false otherwise
2315
                 */
2316
                bool has_issuer() const noexcept { return has_payload_claim("iss"); }
7✔
2317
                /**
2318
                 * Check if subject is present ("sub")
2319
                 * \return true if present, false otherwise
2320
                 */
2321
                bool has_subject() const noexcept { return has_payload_claim("sub"); }
7✔
2322
                /**
2323
                 * Check if audience is present ("aud")
2324
                 * \return true if present, false otherwise
2325
                 */
2326
                bool has_audience() const noexcept { return has_payload_claim("aud"); }
7✔
2327
                /**
2328
                 * Check if expires is present ("exp")
2329
                 * \return true if present, false otherwise
2330
                 */
2331
                bool has_expires_at() const noexcept { return has_payload_claim("exp"); }
54✔
2332
                /**
2333
                 * Check if not before is present ("nbf")
2334
                 * \return true if present, false otherwise
2335
                 */
2336
                bool has_not_before() const noexcept { return has_payload_claim("nbf"); }
60✔
2337
                /**
2338
                 * Check if issued at is present ("iat")
2339
                 * \return true if present, false otherwise
2340
                 */
2341
                bool has_issued_at() const noexcept { return has_payload_claim("iat"); }
56✔
2342
                /**
2343
                 * Check if token id is present ("jti")
2344
                 * \return true if present, false otherwise
2345
                 */
2346
                bool has_id() const noexcept { return has_payload_claim("jti"); }
7✔
2347
                /**
2348
                 * Get issuer claim
2349
                 * \return issuer as string
2350
                 * \throw std::runtime_error If claim was not present
2351
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2352
                 */
2353
                typename json_traits::string_type get_issuer() const { return get_payload_claim("iss").as_string(); }
2✔
2354
                /**
2355
                 * Get subject claim
2356
                 * \return subject as string
2357
                 * \throw std::runtime_error If claim was not present
2358
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2359
                 */
2360
                typename json_traits::string_type get_subject() const { return get_payload_claim("sub").as_string(); }
2361
                /**
2362
                 * Get audience claim
2363
                 * \return audience as a set of strings
2364
                 * \throw std::runtime_error If claim was not present
2365
                 * \throw std::bad_cast Claim was present but not a set (Should not happen in a valid token)
2366
                 */
2367
                typename basic_claim_t::set_t get_audience() const {
5✔
2368
                        auto aud = get_payload_claim("aud");
10✔
2369
                        if (aud.get_type() == json::type::string) return {aud.as_string()};
9✔
2370

2371
                        return aud.as_set();
1✔
2372
                }
5✔
2373
                /**
2374
                 * Get expires claim
2375
                 * \return expires as a date in utc
2376
                 * \throw std::runtime_error If claim was not present
2377
                 * \throw std::bad_cast Claim was present but not a date (Should not happen in a valid token)
2378
                 */
2379
                date get_expires_at() const { return get_payload_claim("exp").as_date(); }
13✔
2380
                /**
2381
                 * Get not valid before claim
2382
                 * \return nbf date in utc
2383
                 * \throw std::runtime_error If claim was not present
2384
                 * \throw std::bad_cast Claim was present but not a date (Should not happen in a valid token)
2385
                 */
2386
                date get_not_before() const { return get_payload_claim("nbf").as_date(); }
4✔
2387
                /**
2388
                 * Get issued at claim
2389
                 * \return issued at as date in utc
2390
                 * \throw std::runtime_error If claim was not present
2391
                 * \throw std::bad_cast Claim was present but not a date (Should not happen in a valid token)
2392
                 */
2393
                date get_issued_at() const { return get_payload_claim("iat").as_date(); }
13✔
2394
                /**
2395
                 * Get id claim
2396
                 * \return id as string
2397
                 * \throw std::runtime_error If claim was not present
2398
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2399
                 */
2400
                typename json_traits::string_type get_id() const { return get_payload_claim("jti").as_string(); }
2401
                /**
2402
                 * Check if a payload claim is present
2403
                 * \return true if claim was present, false otherwise
2404
                 */
2405
                bool has_payload_claim(const typename json_traits::string_type& name) const noexcept {
235✔
2406
                        return payload_claims.has_claim(name);
235✔
2407
                }
2408
                /**
2409
                 * Get payload claim
2410
                 * \return Requested claim
2411
                 * \throw std::runtime_error If claim was not present
2412
                 */
2413
                basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const {
37✔
2414
                        return payload_claims.get_claim(name);
37✔
2415
                }
2416
        };
2417

2418
        /**
2419
         * Base class that represents a token header.
2420
         * Contains Convenience accessors for common claims.
2421
         */
2422
        template<typename json_traits>
2423
        class header {
2424
        protected:
2425
                details::map_of_claims<json_traits> header_claims;
2426

2427
        public:
2428
                using basic_claim_t = basic_claim<json_traits>;
2429
                /**
2430
                 * Check if algortihm is present ("alg")
2431
                 * \return true if present, false otherwise
2432
                 */
2433
                bool has_algorithm() const noexcept { return has_header_claim("alg"); }
7✔
2434
                /**
2435
                 * Check if type is present ("typ")
2436
                 * \return true if present, false otherwise
2437
                 */
2438
                bool has_type() const noexcept { return has_header_claim("typ"); }
7✔
2439
                /**
2440
                 * Check if content type is present ("cty")
2441
                 * \return true if present, false otherwise
2442
                 */
2443
                bool has_content_type() const noexcept { return has_header_claim("cty"); }
7✔
2444
                /**
2445
                 * Check if key id is present ("kid")
2446
                 * \return true if present, false otherwise
2447
                 */
2448
                bool has_key_id() const noexcept { return has_header_claim("kid"); }
7✔
2449
                /**
2450
                 * Get algorithm claim
2451
                 * \return algorithm as string
2452
                 * \throw std::runtime_error If claim was not present
2453
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2454
                 */
2455
                typename json_traits::string_type get_algorithm() const { return get_header_claim("alg").as_string(); }
86✔
2456
                /**
2457
                 * Get type claim
2458
                 * \return type as a string
2459
                 * \throw std::runtime_error If claim was not present
2460
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2461
                 */
2462
                typename json_traits::string_type get_type() const { return get_header_claim("typ").as_string(); }
7✔
2463
                /**
2464
                 * Get content type claim
2465
                 * \return content type as string
2466
                 * \throw std::runtime_error If claim was not present
2467
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2468
                 */
2469
                typename json_traits::string_type get_content_type() const { return get_header_claim("cty").as_string(); }
2470
                /**
2471
                 * Get key id claim
2472
                 * \return key id as string
2473
                 * \throw std::runtime_error If claim was not present
2474
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
2475
                 */
2476
                typename json_traits::string_type get_key_id() const { return get_header_claim("kid").as_string(); }
2477
                /**
2478
                 * Check if a header claim is present
2479
                 * \return true if claim was present, false otherwise
2480
                 */
2481
                bool has_header_claim(const typename json_traits::string_type& name) const noexcept {
31✔
2482
                        return header_claims.has_claim(name);
31✔
2483
                }
2484
                /**
2485
                 * Get header claim
2486
                 * \return Requested claim
2487
                 * \throw std::runtime_error If claim was not present
2488
                 */
2489
                basic_claim_t get_header_claim(const typename json_traits::string_type& name) const {
93✔
2490
                        return header_claims.get_claim(name);
93✔
2491
                }
2492
        };
2493

2494
        /**
2495
         * Class containing all information about a decoded token
2496
         */
2497
        template<typename json_traits>
2498
        class decoded_jwt : public header<json_traits>, public payload<json_traits> {
2499
        protected:
2500
                /// Unmodifed token, as passed to constructor
2501
                typename json_traits::string_type token;
2502
                /// Header part decoded from base64
2503
                typename json_traits::string_type header;
2504
                /// Unmodified header part in base64
2505
                typename json_traits::string_type header_base64;
2506
                /// Payload part decoded from base64
2507
                typename json_traits::string_type payload;
2508
                /// Unmodified payload part in base64
2509
                typename json_traits::string_type payload_base64;
2510
                /// Signature part decoded from base64
2511
                typename json_traits::string_type signature;
2512
                /// Unmodified signature part in base64
2513
                typename json_traits::string_type signature_base64;
2514

2515
        public:
2516
                using basic_claim_t = basic_claim<json_traits>;
2517
#ifndef JWT_DISABLE_BASE64
2518
                /**
2519
                 * \brief Parses a given token
2520
                 *
2521
                 * \note Decodes using the jwt::base64url which supports an std::string
2522
                 *
2523
                 * \param token The token to parse
2524
                 * \throw std::invalid_argument Token is not in correct format
2525
                 * \throw std::runtime_error Base64 decoding failed or invalid json
2526
                 */
2527
                JWT_CLAIM_EXPLICIT decoded_jwt(const typename json_traits::string_type& token)
71✔
2528
                        : decoded_jwt(token, [](const typename json_traits::string_type& str) {
202✔
2529
                                  return base::decode<alphabet::base64url>(base::pad<alphabet::base64url>(str));
202✔
2530
                          }) {}
71✔
2531
#endif
2532
                /**
2533
                 * \brief Parses a given token
2534
                 *
2535
                 * \tparam Decode is callabled, taking a string_type and returns a string_type.
2536
                 * It should ensure the padding of the input and then base64url decode and
2537
                 * return the results.
2538
                 * \param token The token to parse
2539
                 * \param decode The function to decode the token
2540
                 * \throw std::invalid_argument Token is not in correct format
2541
                 * \throw std::runtime_error Base64 decoding failed or invalid json
2542
                 */
2543
                template<typename Decode>
2544
                decoded_jwt(const typename json_traits::string_type& token, Decode decode) : token(token) {
71✔
2545
                        auto hdr_end = token.find('.');
71✔
2546
                        if (hdr_end == json_traits::string_type::npos) throw std::invalid_argument("invalid token supplied");
71✔
2547
                        auto payload_end = token.find('.', hdr_end + 1);
70✔
2548
                        if (payload_end == json_traits::string_type::npos) throw std::invalid_argument("invalid token supplied");
70✔
2549
                        header_base64 = token.substr(0, hdr_end);
68✔
2550
                        payload_base64 = token.substr(hdr_end + 1, payload_end - hdr_end - 1);
68✔
2551
                        signature_base64 = token.substr(payload_end + 1);
68✔
2552

2553
                        header = decode(header_base64);
68✔
2554
                        payload = decode(payload_base64);
67✔
2555
                        signature = decode(signature_base64);
67✔
2556

2557
                        this->header_claims = details::map_of_claims<json_traits>::parse_claims(header);
67✔
2558
                        this->payload_claims = details::map_of_claims<json_traits>::parse_claims(payload);
66✔
2559
                }
111✔
2560

2561
                /**
2562
                 * Get token string, as passed to constructor
2563
                 * \return token as passed to constructor
2564
                 */
2565
                const typename json_traits::string_type& get_token() const noexcept { return token; }
1✔
2566
                /**
2567
                 * Get header part as json string
2568
                 * \return header part after base64 decoding
2569
                 */
2570
                const typename json_traits::string_type& get_header() const noexcept { return header; }
2571
                /**
2572
                 * Get payload part as json string
2573
                 * \return payload part after base64 decoding
2574
                 */
2575
                const typename json_traits::string_type& get_payload() const noexcept { return payload; }
2576
                /**
2577
                 * Get signature part as json string
2578
                 * \return signature part after base64 decoding
2579
                 */
2580
                const typename json_traits::string_type& get_signature() const noexcept { return signature; }
78✔
2581
                /**
2582
                 * Get header part as base64 string
2583
                 * \return header part before base64 decoding
2584
                 */
2585
                const typename json_traits::string_type& get_header_base64() const noexcept { return header_base64; }
78✔
2586
                /**
2587
                 * Get payload part as base64 string
2588
                 * \return payload part before base64 decoding
2589
                 */
2590
                const typename json_traits::string_type& get_payload_base64() const noexcept { return payload_base64; }
78✔
2591
                /**
2592
                 * Get signature part as base64 string
2593
                 * \return signature part before base64 decoding
2594
                 */
2595
                const typename json_traits::string_type& get_signature_base64() const noexcept { return signature_base64; }
2596
                /**
2597
                 * Get all payload as JSON object
2598
                 * \return map of claims
2599
                 */
2600
                typename json_traits::object_type get_payload_json() const { return this->payload_claims.claims; }
2601
                /**
2602
                 * Get all header as JSON object
2603
                 * \return map of claims
2604
                 */
2605
                typename json_traits::object_type get_header_json() const { return this->header_claims.claims; }
2606
                /**
2607
                 * Get a payload claim by name
2608
                 *
2609
                 * \param name the name of the desired claim
2610
                 * \return Requested claim
2611
                 * \throw jwt::error::claim_not_present_exception if the claim was not present
2612
                 */
2613
                basic_claim_t get_payload_claim(const typename json_traits::string_type& name) const {
34✔
2614
                        return this->payload_claims.get_claim(name);
34✔
2615
                }
2616
                /**
2617
                 * Get a header claim by name
2618
                 *
2619
                 * \param name the name of the desired claim
2620
                 * \return Requested claim
2621
                 * \throw jwt::error::claim_not_present_exception if the claim was not present
2622
                 */
2623
                basic_claim_t get_header_claim(const typename json_traits::string_type& name) const {
4✔
2624
                        return this->header_claims.get_claim(name);
4✔
2625
                }
2626
        };
2627

2628
        /**
2629
         * Builder class to build and sign a new token
2630
         * Use jwt::create() to get an instance of this class.
2631
         */
2632
        template<typename json_traits>
2633
        class builder {
2634
                typename json_traits::object_type header_claims;
2635
                typename json_traits::object_type payload_claims;
2636

2637
        public:
2638
                builder() = default;
41✔
2639
                /**
2640
                 * Set a header claim.
2641
                 * \param id Name of the claim
2642
                 * \param c Claim to add
2643
                 * \return *this to allow for method chaining
2644
                 */
2645
                builder& set_header_claim(const typename json_traits::string_type& id, typename json_traits::value_type c) {
21✔
2646
                        header_claims[id] = std::move(c);
21✔
2647
                        return *this;
21✔
2648
                }
2649

2650
                /**
2651
                 * Set a header claim.
2652
                 * \param id Name of the claim
2653
                 * \param c Claim to add
2654
                 * \return *this to allow for method chaining
2655
                 */
2656
                builder& set_header_claim(const typename json_traits::string_type& id, basic_claim<json_traits> c) {
2657
                        header_claims[id] = c.to_json();
2658
                        return *this;
2659
                }
2660
                /**
2661
                 * Set a payload claim.
2662
                 * \param id Name of the claim
2663
                 * \param c Claim to add
2664
                 * \return *this to allow for method chaining
2665
                 */
2666
                builder& set_payload_claim(const typename json_traits::string_type& id, typename json_traits::value_type c) {
27✔
2667
                        payload_claims[id] = std::move(c);
27✔
2668
                        return *this;
27✔
2669
                }
2670
                /**
2671
                 * Set a payload claim.
2672
                 * \param id Name of the claim
2673
                 * \param c Claim to add
2674
                 * \return *this to allow for method chaining
2675
                 */
2676
                builder& set_payload_claim(const typename json_traits::string_type& id, basic_claim<json_traits> c) {
26✔
2677
                        payload_claims[id] = c.to_json();
26✔
2678
                        return *this;
26✔
2679
                }
2680
                /**
2681
                 * \brief Set algorithm claim
2682
                 * You normally don't need to do this, as the algorithm is automatically set if you don't change it.
2683
                 *
2684
                 * \param str Name of algorithm
2685
                 * \return *this to allow for method chaining
2686
                 */
2687
                builder& set_algorithm(typename json_traits::string_type str) {
1✔
2688
                        return set_header_claim("alg", typename json_traits::value_type(str));
1✔
2689
                }
2690
                /**
2691
                 * Set type claim
2692
                 * \param str Type to set
2693
                 * \return *this to allow for method chaining
2694
                 */
2695
                builder& set_type(typename json_traits::string_type str) {
20✔
2696
                        return set_header_claim("typ", typename json_traits::value_type(str));
20✔
2697
                }
2698
                /**
2699
                 * Set content type claim
2700
                 * \param str Type to set
2701
                 * \return *this to allow for method chaining
2702
                 */
2703
                builder& set_content_type(typename json_traits::string_type str) {
2704
                        return set_header_claim("cty", typename json_traits::value_type(str));
2705
                }
2706
                /**
2707
                 * \brief Set key id claim
2708
                 *
2709
                 * \param str Key id to set
2710
                 * \return *this to allow for method chaining
2711
                 */
2712
                builder& set_key_id(typename json_traits::string_type str) {
2713
                        return set_header_claim("kid", typename json_traits::value_type(str));
2714
                }
2715
                /**
2716
                 * Set issuer claim
2717
                 * \param str Issuer to set
2718
                 * \return *this to allow for method chaining
2719
                 */
2720
                builder& set_issuer(typename json_traits::string_type str) {
23✔
2721
                        return set_payload_claim("iss", typename json_traits::value_type(str));
23✔
2722
                }
2723
                /**
2724
                 * Set subject claim
2725
                 * \param str Subject to set
2726
                 * \return *this to allow for method chaining
2727
                 */
2728
                builder& set_subject(typename json_traits::string_type str) {
2729
                        return set_payload_claim("sub", typename json_traits::value_type(str));
2730
                }
2731
                /**
2732
                 * Set audience claim
2733
                 * \param a Audience set
2734
                 * \return *this to allow for method chaining
2735
                 */
2736
                builder& set_audience(typename json_traits::array_type a) {
1✔
2737
                        return set_payload_claim("aud", typename json_traits::value_type(a));
1✔
2738
                }
2739
                /**
2740
                 * Set audience claim
2741
                 * \param aud Single audience
2742
                 * \return *this to allow for method chaining
2743
                 */
2744
                builder& set_audience(typename json_traits::string_type aud) {
2✔
2745
                        return set_payload_claim("aud", typename json_traits::value_type(aud));
2✔
2746
                }
2747
                /**
2748
                 * Set expires at claim
2749
                 * \param d Expires time
2750
                 * \return *this to allow for method chaining
2751
                 */
2752
                builder& set_expires_at(const date& d) { return set_payload_claim("exp", basic_claim<json_traits>(d)); }
8✔
2753
                /**
2754
                 * Set not before claim
2755
                 * \param d First valid time
2756
                 * \return *this to allow for method chaining
2757
                 */
2758
                builder& set_not_before(const date& d) { return set_payload_claim("nbf", basic_claim<json_traits>(d)); }
2✔
2759
                /**
2760
                 * Set issued at claim
2761
                 * \param d Issued at time, should be current time
2762
                 * \return *this to allow for method chaining
2763
                 */
2764
                builder& set_issued_at(const date& d) { return set_payload_claim("iat", basic_claim<json_traits>(d)); }
8✔
2765
                /**
2766
                 * Set id claim
2767
                 * \param str ID to set
2768
                 * \return *this to allow for method chaining
2769
                 */
2770
                builder& set_id(const typename json_traits::string_type& str) {
2771
                        return set_payload_claim("jti", typename json_traits::value_type(str));
2772
                }
2773

2774
                /**
2775
                 * Sign token and return result
2776
                 * \tparam Algo Callable method which takes a string_type and return the signed input as a string_type
2777
                 * \tparam Encode Callable method which takes a string_type and base64url safe encodes it,
2778
                 * MUST return the result with no padding; trim the result.
2779
                 * \param algo Instance of an algorithm to sign the token with
2780
                 * \param encode Callable to transform the serialized json to base64 with no padding
2781
                 * \return Final token as a string
2782
                 *
2783
                 * \note If the 'alg' header in not set in the token it will be set to `algo.name()`
2784
                 */
2785
                template<typename Algo, typename Encode>
2786
                typename json_traits::string_type sign(const Algo& algo, Encode encode) const {
2787
                        std::error_code ec;
2788
                        auto res = sign(algo, encode, ec);
2789
                        error::throw_if_error(ec);
2790
                        return res;
2791
                }
2792
#ifndef JWT_DISABLE_BASE64
2793
                /**
2794
                 * Sign token and return result
2795
                 *
2796
                 * using the `jwt::base` functions provided
2797
                 *
2798
                 * \param algo Instance of an algorithm to sign the token with
2799
                 * \return Final token as a string
2800
                 */
2801
                template<typename Algo>
2802
                typename json_traits::string_type sign(const Algo& algo) const {
41✔
2803
                        std::error_code ec;
41✔
2804
                        auto res = sign(algo, ec);
41✔
2805
                        error::throw_if_error(ec);
41✔
2806
                        return res;
76✔
2807
                }
3✔
2808
#endif
2809

2810
                /**
2811
                 * Sign token and return result
2812
                 * \tparam Algo Callable method which takes a string_type and return the signed input as a string_type
2813
                 * \tparam Encode Callable method which takes a string_type and base64url safe encodes it,
2814
                 * MUST return the result with no padding; trim the result.
2815
                 * \param algo Instance of an algorithm to sign the token with
2816
                 * \param encode Callable to transform the serialized json to base64 with no padding
2817
                 * \param ec error_code filled with details on error
2818
                 * \return Final token as a string
2819
                 *
2820
                 * \note If the 'alg' header in not set in the token it will be set to `algo.name()`
2821
                 */
2822
                template<typename Algo, typename Encode>
2823
                typename json_traits::string_type sign(const Algo& algo, Encode encode, std::error_code& ec) const {
41✔
2824
                        // make a copy such that a builder can be re-used
2825
                        typename json_traits::object_type obj_header = header_claims;
41✔
2826
                        if (header_claims.count("alg") == 0) obj_header["alg"] = typename json_traits::value_type(algo.name());
41✔
2827

2828
                        const auto header = encode(json_traits::serialize(typename json_traits::value_type(obj_header)));
82✔
2829
                        const auto payload = encode(json_traits::serialize(typename json_traits::value_type(payload_claims)));
82✔
2830
                        const auto token = header + "." + payload;
41✔
2831

2832
                        auto signature = algo.sign(token, ec);
41✔
2833
                        if (ec) return {};
41✔
2834

2835
                        return token + "." + encode(signature);
38✔
2836
                }
41✔
2837
#ifndef JWT_DISABLE_BASE64
2838
                /**
2839
                 * Sign token and return result
2840
                 *
2841
                 * using the `jwt::base` functions provided
2842
                 *
2843
                 * \param algo Instance of an algorithm to sign the token with
2844
                 * \param ec error_code filled with details on error
2845
                 * \return Final token as a string
2846
                 */
2847
                template<typename Algo>
2848
                typename json_traits::string_type sign(const Algo& algo, std::error_code& ec) const {
41✔
2849
                        return sign(
2850
                                algo,
2851
                                [](const typename json_traits::string_type& data) {
120✔
2852
                                        return base::trim<alphabet::base64url>(base::encode<alphabet::base64url>(data));
120✔
2853
                                },
2854
                                ec);
41✔
2855
                }
2856
#endif
2857
        };
2858

2859
        namespace verify_ops {
2860
                /**
2861
                 * This is the base container which holds the token that need to be verified
2862
                 */
2863
                template<typename json_traits>
2864
                struct verify_context {
2865
                        verify_context(date ctime, const decoded_jwt<json_traits>& j, size_t l)
60✔
2866
                                : current_time(ctime), jwt(j), default_leeway(l) {}
60✔
2867
                        // Current time, retrieved from the verifiers clock and cached for performance and consistency
2868
                        date current_time;
2869
                        // The jwt passed to the verifier
2870
                        const decoded_jwt<json_traits>& jwt;
2871
                        // The configured default leeway for this verification
2872
                        size_t default_leeway{0};
2873

2874
                        // The claim key to apply this comparision on
2875
                        typename json_traits::string_type claim_key{};
2876

2877
                        // Helper method to get a claim from the jwt in this context
2878
                        basic_claim<json_traits> get_claim(bool in_header, std::error_code& ec) const {
40✔
2879
                                if (in_header) {
40✔
2880
                                        if (!jwt.has_header_claim(claim_key)) {
3✔
2881
                                                ec = error::token_verification_error::missing_claim;
×
2882
                                                return {};
×
2883
                                        }
2884
                                        return jwt.get_header_claim(claim_key);
3✔
2885
                                } else {
2886
                                        if (!jwt.has_payload_claim(claim_key)) {
37✔
2887
                                                ec = error::token_verification_error::missing_claim;
4✔
2888
                                                return {};
4✔
2889
                                        }
2890
                                        return jwt.get_payload_claim(claim_key);
33✔
2891
                                }
2892
                        }
2893
                        basic_claim<json_traits> get_claim(bool in_header, json::type t, std::error_code& ec) const {
37✔
2894
                                auto c = get_claim(in_header, ec);
37✔
2895
                                if (ec) return {};
37✔
2896
                                if (c.get_type() != t) {
34✔
2897
                                        ec = error::token_verification_error::claim_type_missmatch;
1✔
2898
                                        return {};
1✔
2899
                                }
2900
                                return c;
33✔
2901
                        }
37✔
2902
                        basic_claim<json_traits> get_claim(std::error_code& ec) const { return get_claim(false, ec); }
2903
                        basic_claim<json_traits> get_claim(json::type t, std::error_code& ec) const {
2904
                                return get_claim(false, t, ec);
2905
                        }
2906
                };
2907

2908
                /**
2909
                 * This is the default operation and does case sensitive matching
2910
                 */
2911
                template<typename json_traits, bool in_header = false>
2912
                struct equals_claim {
2913
                        const basic_claim<json_traits> expected;
2914
                        void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
34✔
2915
                                auto jc = ctx.get_claim(in_header, expected.get_type(), ec);
34✔
2916
                                if (ec) return;
34✔
2917
                                const bool matches = [&]() {
90✔
2918
                                        switch (expected.get_type()) {
30✔
2919
                                        case json::type::boolean: return expected.as_boolean() == jc.as_boolean();
×
2920
                                        case json::type::integer: return expected.as_integer() == jc.as_integer();
×
2921
                                        case json::type::number: return expected.as_number() == jc.as_number();
×
2922
                                        case json::type::string: return expected.as_string() == jc.as_string();
24✔
2923
                                        case json::type::array:
6✔
2924
                                        case json::type::object:
2925
                                                return json_traits::serialize(expected.to_json()) == json_traits::serialize(jc.to_json());
6✔
2926
                                        default: throw std::logic_error("internal error, should be unreachable");
×
2927
                                        }
2928
                                }();
30✔
2929
                                if (!matches) {
30✔
2930
                                        ec = error::token_verification_error::claim_value_missmatch;
1✔
2931
                                        return;
1✔
2932
                                }
2933
                        }
34✔
2934
                };
2935

2936
                /**
2937
                 * Checks that the current time is before the time specified in the given
2938
                 * claim. This is identical to how the "exp" check works.
2939
                 */
2940
                template<typename json_traits, bool in_header = false>
2941
                struct date_before_claim {
2942
                        const size_t leeway;
2943
                        void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
2944
                                auto jc = ctx.get_claim(in_header, json::type::integer, ec);
2945
                                if (ec) return;
2946
                                auto c = jc.as_date();
2947
                                if (ctx.current_time > c + std::chrono::seconds(leeway)) {
2948
                                        ec = error::token_verification_error::token_expired;
2949
                                }
2950
                        }
2951
                };
2952

2953
                /**
2954
                 * Checks that the current time is after the time specified in the given
2955
                 * claim. This is identical to how the "nbf" and "iat" check works.
2956
                 */
2957
                template<typename json_traits, bool in_header = false>
2958
                struct date_after_claim {
2959
                        const size_t leeway;
2960
                        void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
2961
                                auto jc = ctx.get_claim(in_header, json::type::integer, ec);
2962
                                if (ec) return;
2963
                                auto c = jc.as_date();
2964
                                if (ctx.current_time < c - std::chrono::seconds(leeway)) {
2965
                                        ec = error::token_verification_error::token_expired;
2966
                                }
2967
                        }
2968
                };
2969

2970
                /**
2971
                 * Checks if the given set is a subset of the set inside the token.
2972
                 * If the token value is a string it is traited as a set of a single element.
2973
                 * The comparison is case sensitive.
2974
                 */
2975
                template<typename json_traits, bool in_header = false>
2976
                struct is_subset_claim {
2977
                        const typename basic_claim<json_traits>::set_t expected;
2978
                        void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3✔
2979
                                auto c = ctx.get_claim(in_header, ec);
3✔
2980
                                if (ec) return;
3✔
2981
                                if (c.get_type() == json::type::string) {
2✔
2982
                                        if (expected.size() != 1 || *expected.begin() != c.as_string()) {
2✔
2983
                                                ec = error::token_verification_error::audience_missmatch;
2✔
2984
                                                return;
2✔
2985
                                        }
2986
                                } else if (c.get_type() == json::type::array) {
×
2987
                                        auto jc = c.as_set();
×
2988
                                        for (auto& e : expected) {
×
2989
                                                if (jc.find(e) == jc.end()) {
×
2990
                                                        ec = error::token_verification_error::audience_missmatch;
×
2991
                                                        return;
×
2992
                                                }
2993
                                        }
2994
                                } else {
×
2995
                                        ec = error::token_verification_error::claim_type_missmatch;
×
2996
                                        return;
×
2997
                                }
2998
                        }
3✔
2999
                };
3000

3001
                /**
3002
                 * Checks if the claim is a string and does an case insensitive comparison.
3003
                 */
3004
                template<typename json_traits, bool in_header = false>
3005
                struct insensitive_string_claim {
3006
                        const typename json_traits::string_type expected;
3007
                        std::locale locale;
3008
                        insensitive_string_claim(const typename json_traits::string_type& e, std::locale loc)
2✔
3009
                                : expected(to_lower_unicode(e, loc)), locale(loc) {}
2✔
3010

3011
                        void operator()(const verify_context<json_traits>& ctx, std::error_code& ec) const {
3✔
3012
                                const auto c = ctx.get_claim(in_header, json::type::string, ec);
3✔
3013
                                if (ec) return;
3✔
3014
                                if (to_lower_unicode(c.as_string(), locale) != expected) {
3✔
3015
                                        ec = error::token_verification_error::claim_value_missmatch;
1✔
3016
                                }
3017
                        }
3✔
3018

3019
                        static std::string to_lower_unicode(const std::string& str, const std::locale& loc) {
5✔
3020
                                std::mbstate_t state = std::mbstate_t();
5✔
3021
                                const char* in_next = str.data();
5✔
3022
                                const char* in_end = str.data() + str.size();
5✔
3023
                                std::wstring wide;
5✔
3024
                                wide.reserve(str.size());
5✔
3025

3026
                                while (in_next != in_end) {
20✔
3027
                                        wchar_t wc;
3028
                                        std::size_t result = std::mbrtowc(&wc, in_next, in_end - in_next, &state);
15✔
3029
                                        if (result == static_cast<std::size_t>(-1)) {
15✔
3030
                                                throw std::runtime_error("encoding error: " + std::string(std::strerror(errno)));
×
3031
                                        } else if (result == static_cast<std::size_t>(-2)) {
15✔
3032
                                                throw std::runtime_error("conversion error: next bytes constitute an incomplete, but so far "
×
3033
                                                                                                 "valid, multibyte character.");
3034
                                        }
3035
                                        in_next += result;
15✔
3036
                                        wide.push_back(wc);
15✔
3037
                                }
3038

3039
                                auto& f = std::use_facet<std::ctype<wchar_t>>(loc);
5✔
3040
                                f.tolower(&wide[0], &wide[0] + wide.size());
5✔
3041

3042
                                std::string out;
5✔
3043
                                out.reserve(wide.size());
5✔
3044
                                for (wchar_t wc : wide) {
20✔
3045
                                        char mb[MB_CUR_MAX];
15✔
3046
                                        std::size_t n = std::wcrtomb(mb, wc, &state);
15✔
3047
                                        if (n != static_cast<std::size_t>(-1)) out.append(mb, n);
15✔
3048
                                }
3049

3050
                                return out;
10✔
3051
                        }
5✔
3052
                };
3053
        } // namespace verify_ops
3054

3055
        /**
3056
         * Verifier class used to check if a decoded token contains all claims required by your application and has a valid
3057
         * signature.
3058
         */
3059
        template<typename Clock, typename json_traits>
3060
        class verifier {
3061
        public:
3062
                using basic_claim_t = basic_claim<json_traits>;
3063
                /**
3064
                 * Verification function
3065
                 *
3066
                 * This gets passed the current verifier, a reference to the decoded jwt, a reference to the key of this claim,
3067
                 * as well as a reference to an error_code.
3068
                 * The function checks if the actual value matches certain rules (e.g. equality to value x) and sets the error_code if
3069
                 * it does not. Once a non zero error_code is encountered the verification stops and this error_code becomes the result
3070
                 * returned from verify
3071
                 */
3072
                using verify_check_fn_t =
3073
                        std::function<void(const verify_ops::verify_context<json_traits>&, std::error_code& ec)>;
3074

3075
        private:
3076
                struct algo_base {
3077
                        virtual ~algo_base() = default;
68✔
3078
                        virtual void verify(const std::string& data, const std::string& sig, std::error_code& ec) = 0;
3079
                };
3080
                template<typename T>
3081
                struct algo : public algo_base {
3082
                        T alg;
3083
                        explicit algo(T a) : alg(a) {}
68✔
3084
                        void verify(const std::string& data, const std::string& sig, std::error_code& ec) override {
77✔
3085
                                alg.verify(data, sig, ec);
77✔
3086
                        }
77✔
3087
                };
3088
                /// Required claims
3089
                std::unordered_map<typename json_traits::string_type, verify_check_fn_t> claims;
3090
                /// Leeway time for exp, nbf and iat
3091
                size_t default_leeway = 0;
3092
                /// Instance of clock type
3093
                Clock clock;
3094
                /// Supported algorithms
3095
                std::unordered_map<std::string, std::shared_ptr<algo_base>> algs;
3096

3097
        public:
3098
                /**
3099
                 * Constructor for building a new verifier instance
3100
                 * \param c Clock instance
3101
                 */
3102
                explicit verifier(Clock c) : clock(c) {
71✔
3103
                        claims["exp"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
100✔
3104
                                if (!ctx.jwt.has_expires_at()) return;
47✔
3105
                                auto exp = ctx.jwt.get_expires_at();
13✔
3106
                                if (ctx.current_time > exp + std::chrono::seconds(ctx.default_leeway)) {
13✔
3107
                                        ec = error::token_verification_error::token_expired;
8✔
3108
                                }
3109
                        };
3110
                        claims["iat"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
102✔
3111
                                if (!ctx.jwt.has_issued_at()) return;
49✔
3112
                                auto iat = ctx.jwt.get_issued_at();
13✔
3113
                                if (ctx.current_time < iat - std::chrono::seconds(ctx.default_leeway)) {
13✔
3114
                                        ec = error::token_verification_error::token_expired;
2✔
3115
                                }
3116
                        };
3117
                        claims["nbf"] = [](const verify_ops::verify_context<json_traits>& ctx, std::error_code& ec) {
106✔
3118
                                if (!ctx.jwt.has_not_before()) return;
53✔
3119
                                auto nbf = ctx.jwt.get_not_before();
4✔
3120
                                if (ctx.current_time < nbf - std::chrono::seconds(ctx.default_leeway)) {
4✔
3121
                                        ec = error::token_verification_error::token_expired;
2✔
3122
                                }
3123
                        };
3124
                }
71✔
3125

3126
                /**
3127
                 * Set default leeway to use.
3128
                 * \param leeway Default leeway to use if not specified otherwise
3129
                 * \return *this to allow chaining
3130
                 */
3131
                verifier& leeway(size_t leeway) {
3132
                        default_leeway = leeway;
3133
                        return *this;
3134
                }
3135
                /**
3136
                 * Set leeway for expires at.
3137
                 * If not specified the default leeway will be used.
3138
                 * \param leeway Set leeway to use for expires at.
3139
                 * \return *this to allow chaining
3140
                 */
3141
                verifier& expires_at_leeway(size_t leeway) {
3142
                        claims["exp"] = verify_ops::date_before_claim<json_traits>{leeway};
3143
                        return *this;
3144
                }
3145
                /**
3146
                 * Set leeway for not before.
3147
                 * If not specified the default leeway will be used.
3148
                 * \param leeway Set leeway to use for not before.
3149
                 * \return *this to allow chaining
3150
                 */
3151
                verifier& not_before_leeway(size_t leeway) {
3152
                        claims["nbf"] = verify_ops::date_after_claim<json_traits>{leeway};
3153
                        return *this;
3154
                }
3155
                /**
3156
                 * Set leeway for issued at.
3157
                 * If not specified the default leeway will be used.
3158
                 * \param leeway Set leeway to use for issued at.
3159
                 * \return *this to allow chaining
3160
                 */
3161
                verifier& issued_at_leeway(size_t leeway) {
3162
                        claims["iat"] = verify_ops::date_after_claim<json_traits>{leeway};
3163
                        return *this;
3164
                }
3165

3166
                /**
3167
                 * Set an type to check for.
3168
                 *
3169
                 * According to [RFC 7519 Section 5.1](https://datatracker.ietf.org/doc/html/rfc7519#section-5.1),
3170
                 * This parameter is ignored by JWT implementations; any processing of this parameter is performed by the JWT application.
3171
                 * Check is casesensitive.
3172
                 *
3173
                 * \param type Type Header Parameter to check for.
3174
                 * \param locale Localization functionality to use when comapring
3175
                 * \return *this to allow chaining
3176
                 */
3177
                verifier& with_type(const typename json_traits::string_type& type, std::locale locale = std::locale{}) {
2✔
3178
                        return with_claim("typ", verify_ops::insensitive_string_claim<json_traits, true>{type, std::move(locale)});
2✔
3179
                }
3180

3181
                /**
3182
                 * Set an issuer to check for.
3183
                 * Check is casesensitive.
3184
                 * \param iss Issuer to check for.
3185
                 * \return *this to allow chaining
3186
                 */
3187
                verifier& with_issuer(const typename json_traits::string_type& iss) {
33✔
3188
                        return with_claim("iss", basic_claim_t(iss));
33✔
3189
                }
3190

3191
                /**
3192
                 * Set a subject to check for.
3193
                 * Check is casesensitive.
3194
                 * \param sub Subject to check for.
3195
                 * \return *this to allow chaining
3196
                 */
3197
                verifier& with_subject(const typename json_traits::string_type& sub) {
1✔
3198
                        return with_claim("sub", basic_claim_t(sub));
1✔
3199
                }
3200
                /**
3201
                 * Set an audience to check for.
3202
                 * If any of the specified audiences is not present in the token the check fails.
3203
                 * \param aud Audience to check for.
3204
                 * \return *this to allow chaining
3205
                 */
3206
                verifier& with_audience(const typename basic_claim_t::set_t& aud) {
3✔
3207
                        claims["aud"] = verify_ops::is_subset_claim<json_traits>{aud};
3✔
3208
                        return *this;
3✔
3209
                }
3210
                /**
3211
                 * Set an audience to check for.
3212
                 * If the specified audiences is not present in the token the check fails.
3213
                 * \param aud Audience to check for.
3214
                 * \return *this to allow chaining
3215
                 */
3216
                verifier& with_audience(const typename json_traits::string_type& aud) {
2✔
3217
                        typename basic_claim_t::set_t s;
2✔
3218
                        s.insert(aud);
2✔
3219
                        return with_audience(s);
4✔
3220
                }
2✔
3221
                /**
3222
                 * Set an id to check for.
3223
                 * Check is casesensitive.
3224
                 * \param id ID to check for.
3225
                 * \return *this to allow chaining
3226
                 */
3227
                verifier& with_id(const typename json_traits::string_type& id) { return with_claim("jti", basic_claim_t(id)); }
3228

3229
                /**
3230
                 * Specify a claim to check for using the specified operation.
3231
                 * \param name Name of the claim to check for
3232
                 * \param fn Function to use for verifying the claim
3233
                 * \return *this to allow chaining
3234
                 */
3235
                verifier& with_claim(const typename json_traits::string_type& name, verify_check_fn_t fn) {
45✔
3236
                        claims[name] = fn;
45✔
3237
                        return *this;
45✔
3238
                }
3239

3240
                /**
3241
                 * Specify a claim to check for equality (both type & value).
3242
                 * \param name Name of the claim to check for
3243
                 * \param c Claim to check for
3244
                 * \return *this to allow chaining
3245
                 */
3246
                verifier& with_claim(const typename json_traits::string_type& name, basic_claim_t c) {
43✔
3247
                        return with_claim(name, verify_ops::equals_claim<json_traits>{c});
43✔
3248
                }
3249

3250
                /**
3251
                 * Add an algorithm available for checking.
3252
                 * \param alg Algorithm to allow
3253
                 * \return *this to allow chaining
3254
                 */
3255
                template<typename Algorithm>
3256
                verifier& allow_algorithm(Algorithm alg) {
68✔
3257
                        algs[alg.name()] = std::make_shared<algo<Algorithm>>(alg);
68✔
3258
                        return *this;
68✔
3259
                }
3260

3261
                /**
3262
                 * Verify the given token.
3263
                 * \param jwt Token to check
3264
                 * \throw token_verification_exception Verification failed
3265
                 */
3266
                void verify(const decoded_jwt<json_traits>& jwt) const {
67✔
3267
                        std::error_code ec;
67✔
3268
                        verify(jwt, ec);
67✔
3269
                        error::throw_if_error(ec);
67✔
3270
                }
35✔
3271
                /**
3272
                 * Verify the given token.
3273
                 * \param jwt Token to check
3274
                 * \param ec error_code filled with details on error
3275
                 */
3276
                void verify(const decoded_jwt<json_traits>& jwt, std::error_code& ec) const {
78✔
3277
                        ec.clear();
78✔
3278
                        const typename json_traits::string_type data = jwt.get_header_base64() + "." + jwt.get_payload_base64();
78✔
3279
                        const typename json_traits::string_type sig = jwt.get_signature();
78✔
3280
                        const std::string algo = jwt.get_algorithm();
78✔
3281
                        if (algs.count(algo) == 0) {
78✔
3282
                                ec = error::token_verification_error::wrong_algorithm;
1✔
3283
                                return;
1✔
3284
                        }
3285
                        algs.at(algo)->verify(data, sig, ec);
77✔
3286
                        if (ec) return;
77✔
3287

3288
                        verify_ops::verify_context<json_traits> ctx{clock.now(), jwt, default_leeway};
60✔
3289
                        for (auto& c : claims) {
228✔
3290
                                ctx.claim_key = c.first;
189✔
3291
                                c.second(ctx, ec);
189✔
3292
                                if (ec) return;
189✔
3293
                        }
3294
                }
177✔
3295
        };
3296

3297
        /**
3298
         * \brief JSON Web Key
3299
         *
3300
         * https://tools.ietf.org/html/rfc7517
3301
         *
3302
         * A JSON object that represents a cryptographic key.  The members of
3303
         * the object represent properties of the key, including its value.
3304
         */
3305
        template<typename json_traits>
3306
        class jwk {
3307
                using basic_claim_t = basic_claim<json_traits>;
3308
                const details::map_of_claims<json_traits> jwk_claims;
3309

3310
        public:
3311
                JWT_CLAIM_EXPLICIT jwk(const typename json_traits::string_type& str)
3✔
3312
                        : jwk_claims(details::map_of_claims<json_traits>::parse_claims(str)) {}
3✔
3313

3314
                JWT_CLAIM_EXPLICIT jwk(const typename json_traits::value_type& json)
5✔
3315
                        : jwk_claims(json_traits::as_object(json)) {}
5✔
3316

3317
                /**
3318
                 * Get key type claim
3319
                 *
3320
                 * This returns the general type (e.g. RSA or EC), not a specific algorithm value.
3321
                 * \return key type as string
3322
                 * \throw std::runtime_error If claim was not present
3323
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3324
                 */
3325
                typename json_traits::string_type get_key_type() const { return get_jwk_claim("kty").as_string(); }
3326

3327
                /**
3328
                 * Get public key usage claim
3329
                 * \return usage parameter as string
3330
                 * \throw std::runtime_error If claim was not present
3331
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3332
                 */
3333
                typename json_traits::string_type get_use() const { return get_jwk_claim("use").as_string(); }
3334

3335
                /**
3336
                 * Get key operation types claim
3337
                 * \return key operation types as a set of strings
3338
                 * \throw std::runtime_error If claim was not present
3339
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3340
                 */
3341
                typename basic_claim_t::set_t get_key_operations() const { return get_jwk_claim("key_ops").as_set(); }
3342

3343
                /**
3344
                 * Get algorithm claim
3345
                 * \return algorithm as string
3346
                 * \throw std::runtime_error If claim was not present
3347
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3348
                 */
3349
                typename json_traits::string_type get_algorithm() const { return get_jwk_claim("alg").as_string(); }
2✔
3350

3351
                /**
3352
                 * Get key id claim
3353
                 * \return key id as string
3354
                 * \throw std::runtime_error If claim was not present
3355
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3356
                 */
3357
                typename json_traits::string_type get_key_id() const { return get_jwk_claim("kid").as_string(); }
15✔
3358

3359
                /**
3360
                 * \brief Get curve claim
3361
                 *
3362
                 * https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2.1.1
3363
                 * https://www.iana.org/assignments/jose/jose.xhtml#table-web-key-elliptic-curve
3364
                 *
3365
                 * \return curve as string
3366
                 * \throw std::runtime_error If claim was not present
3367
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3368
                 */
3369
                typename json_traits::string_type get_curve() const { return get_jwk_claim("crv").as_string(); }
3370

3371
                /**
3372
                 * Get x5c claim
3373
                 * \return x5c as an array
3374
                 * \throw std::runtime_error If claim was not present
3375
                 * \throw std::bad_cast Claim was present but not a array (Should not happen in a valid token)
3376
                 */
3377
                typename json_traits::array_type get_x5c() const { return get_jwk_claim("x5c").as_array(); };
4✔
3378

3379
                /**
3380
                 * Get X509 URL claim
3381
                 * \return x5u as string
3382
                 * \throw std::runtime_error If claim was not present
3383
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3384
                 */
3385
                typename json_traits::string_type get_x5u() const { return get_jwk_claim("x5u").as_string(); };
3386

3387
                /**
3388
                 * Get X509 thumbprint claim
3389
                 * \return x5t as string
3390
                 * \throw std::runtime_error If claim was not present
3391
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3392
                 */
3393
                typename json_traits::string_type get_x5t() const { return get_jwk_claim("x5t").as_string(); };
3394

3395
                /**
3396
                 * Get X509 SHA256 thumbprint claim
3397
                 * \return x5t#S256 as string
3398
                 * \throw std::runtime_error If claim was not present
3399
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3400
                 */
3401
                typename json_traits::string_type get_x5t_sha256() const { return get_jwk_claim("x5t#S256").as_string(); };
3402

3403
                /**
3404
                 * Get x5c claim as a string
3405
                 * \return x5c as an string
3406
                 * \throw std::runtime_error If claim was not present
3407
                 * \throw std::bad_cast Claim was present but not a string (Should not happen in a valid token)
3408
                 */
3409
                typename json_traits::string_type get_x5c_key_value() const {
2✔
3410
                        auto x5c_array = get_jwk_claim("x5c").as_array();
4✔
3411
                        if (x5c_array.size() == 0) throw error::claim_not_present_exception();
2✔
3412

3413
                        return json_traits::as_string(x5c_array.front());
2✔
3414
                };
2✔
3415

3416
                /**
3417
                 * Check if a key type is present ("kty")
3418
                 * \return true if present, false otherwise
3419
                 */
3420
                bool has_key_type() const noexcept { return has_jwk_claim("kty"); }
3421

3422
                /**
3423
                 * Check if a public key usage indication is present ("use")
3424
                 * \return true if present, false otherwise
3425
                 */
3426
                bool has_use() const noexcept { return has_jwk_claim("use"); }
3427

3428
                /**
3429
                 * Check if a key operations parameter is present ("key_ops")
3430
                 * \return true if present, false otherwise
3431
                 */
3432
                bool has_key_operations() const noexcept { return has_jwk_claim("key_ops"); }
3433

3434
                /**
3435
                 * Check if algortihm is present ("alg")
3436
                 * \return true if present, false otherwise
3437
                 */
3438
                bool has_algorithm() const noexcept { return has_jwk_claim("alg"); }
3✔
3439

3440
                /**
3441
                 * Check if curve is present ("crv")
3442
                 * \return true if present, false otherwise
3443
                 */
3444
                bool has_curve() const noexcept { return has_jwk_claim("crv"); }
3445

3446
                /**
3447
                 * Check if key id is present ("kid")
3448
                 * \return true if present, false otherwise
3449
                 */
3450
                bool has_key_id() const noexcept { return has_jwk_claim("kid"); }
15✔
3451

3452
                /**
3453
                 * Check if X509 URL is present ("x5u")
3454
                 * \return true if present, false otherwise
3455
                 */
3456
                bool has_x5u() const noexcept { return has_jwk_claim("x5u"); }
3457

3458
                /**
3459
                 * Check if X509 Chain is present ("x5c")
3460
                 * \return true if present, false otherwise
3461
                 */
3462
                bool has_x5c() const noexcept { return has_jwk_claim("x5c"); }
2✔
3463

3464
                /**
3465
                 * Check if a X509 thumbprint is present ("x5t")
3466
                 * \return true if present, false otherwise
3467
                 */
3468
                bool has_x5t() const noexcept { return has_jwk_claim("x5t"); }
3469

3470
                /**
3471
                 * Check if a X509 SHA256 thumbprint is present ("x5t#S256")
3472
                 * \return true if present, false otherwise
3473
                 */
3474
                bool has_x5t_sha256() const noexcept { return has_jwk_claim("x5t#S256"); }
3475

3476
                /**
3477
                 * Check if a jwks claim is present
3478
                 * \return true if claim was present, false otherwise
3479
                 */
3480
                bool has_jwk_claim(const typename json_traits::string_type& name) const noexcept {
22✔
3481
                        return jwk_claims.has_claim(name);
22✔
3482
                }
3483

3484
                /**
3485
                 * Get jwks claim
3486
                 * \return Requested claim
3487
                 * \throw std::runtime_error If claim was not present
3488
                 */
3489
                basic_claim_t get_jwk_claim(const typename json_traits::string_type& name) const {
22✔
3490
                        return jwk_claims.get_claim(name);
22✔
3491
                }
3492

3493
                bool empty() const noexcept { return jwk_claims.empty(); }
3494

3495
                /**
3496
                 * Get all jwk claims
3497
                 * \return Map of claims
3498
                 */
3499
                typename json_traits::object_type get_claims() const { return this->jwk_claims.claims; }
3500
        };
3501

3502
        /**
3503
         * \brief JWK Set
3504
         *
3505
         * https://tools.ietf.org/html/rfc7517
3506
         *
3507
         * A JSON object that represents a set of JWKs.  The JSON object MUST
3508
         * have a "keys" member, which is an array of JWKs.
3509
         *
3510
         * This container takes a JWKs and simplifies it to a vector of JWKs
3511
         */
3512
        template<typename json_traits>
3513
        class jwks {
3514
        public:
3515
                using jwk_t = jwk<json_traits>;
3516
                using jwt_vector_t = std::vector<jwk_t>;
3517
                using iterator = typename jwt_vector_t::iterator;
3518
                using const_iterator = typename jwt_vector_t::const_iterator;
3519

3520
                JWT_CLAIM_EXPLICIT jwks(const typename json_traits::string_type& str) {
2✔
3521
                        typename json_traits::value_type parsed_val;
2✔
3522
                        if (!json_traits::parse(parsed_val, str)) throw error::invalid_json_exception();
2✔
3523

3524
                        const details::map_of_claims<json_traits> jwks_json = json_traits::as_object(parsed_val);
2✔
3525
                        if (!jwks_json.has_claim("keys")) throw error::invalid_json_exception();
2✔
3526

3527
                        auto jwk_list = jwks_json.get_claim("keys").as_array();
4✔
3528
                        std::transform(jwk_list.begin(), jwk_list.end(), std::back_inserter(jwk_claims),
2✔
3529
                                                   [](const typename json_traits::value_type& val) { return jwk_t{val}; });
5✔
3530
                }
2✔
3531

3532
                iterator begin() { return jwk_claims.begin(); }
3533
                iterator end() { return jwk_claims.end(); }
3534
                const_iterator cbegin() const { return jwk_claims.begin(); }
7✔
3535
                const_iterator cend() const { return jwk_claims.end(); }
7✔
3536
                const_iterator begin() const { return jwk_claims.begin(); }
3537
                const_iterator end() const { return jwk_claims.end(); }
7✔
3538

3539
                /**
3540
                 * Check if a jwk with the kid is present
3541
                 * \return true if jwk was present, false otherwise
3542
                 */
3543
                bool has_jwk(const typename json_traits::string_type& key_id) const noexcept {
2✔
3544
                        return find_by_kid(key_id) != end();
2✔
3545
                }
3546

3547
                /**
3548
                 * Get jwk
3549
                 * \return Requested jwk by key_id
3550
                 * \throw std::runtime_error If jwk was not present
3551
                 */
3552
                jwk_t get_jwk(const typename json_traits::string_type& key_id) const {
5✔
3553
                        const auto maybe = find_by_kid(key_id);
5✔
3554
                        if (maybe == end()) throw error::claim_not_present_exception();
5✔
3555
                        return *maybe;
8✔
3556
                }
3557

3558
        private:
3559
                jwt_vector_t jwk_claims;
3560

3561
                const_iterator find_by_kid(const typename json_traits::string_type& key_id) const noexcept {
7✔
3562
                        return std::find_if(cbegin(), cend(), [key_id](const jwk_t& jwk) {
14✔
3563
                                if (!jwk.has_key_id()) { return false; }
13✔
3564
                                return jwk.get_key_id() == key_id;
13✔
3565
                        });
7✔
3566
                }
3567
        };
3568

3569
        /**
3570
         * Create a verifier using the given clock
3571
         * \param c Clock instance to use
3572
         * \return verifier instance
3573
         */
3574
        template<typename Clock, typename json_traits>
3575
        verifier<Clock, json_traits> verify(Clock c) {
56✔
3576
                return verifier<Clock, json_traits>(c);
56✔
3577
        }
3578

3579
        /**
3580
         * Default clock class using std::chrono::system_clock as a backend.
3581
         */
3582
        struct default_clock {
3583
                date now() const { return date::clock::now(); }
48✔
3584
        };
3585

3586
        /**
3587
         * Create a verifier using the given clock
3588
         * \param c Clock instance to use
3589
         * \return verifier instance
3590
         */
3591
        template<typename json_traits>
3592
        verifier<default_clock, json_traits> verify(default_clock c = {}) {
15✔
3593
                return verifier<default_clock, json_traits>(c);
15✔
3594
        }
3595

3596
        /**
3597
         * Return a builder instance to create a new token
3598
         */
3599
        template<typename json_traits>
3600
        builder<json_traits> create() {
12✔
3601
                return builder<json_traits>();
12✔
3602
        }
3603

3604
        /**
3605
         * Decode a token
3606
         * \param token Token to decode
3607
         * \param decode function that will pad and base64url decode the token
3608
         * \return Decoded token
3609
         * \throw std::invalid_argument Token is not in correct format
3610
         * \throw std::runtime_error Base64 decoding failed or invalid json
3611
         */
3612
        template<typename json_traits, typename Decode>
3613
        decoded_jwt<json_traits> decode(const typename json_traits::string_type& token, Decode decode) {
3614
                return decoded_jwt<json_traits>(token, decode);
3615
        }
3616

3617
        /**
3618
         * Decode a token
3619
         * \param token Token to decode
3620
         * \return Decoded token
3621
         * \throw std::invalid_argument Token is not in correct format
3622
         * \throw std::runtime_error Base64 decoding failed or invalid json
3623
         */
3624
        template<typename json_traits>
3625
        decoded_jwt<json_traits> decode(const typename json_traits::string_type& token) {
18✔
3626
                return decoded_jwt<json_traits>(token);
18✔
3627
        }
3628

3629
        template<typename json_traits>
3630
        jwk<json_traits> parse_jwk(const typename json_traits::string_type& token) {
3631
                return jwk<json_traits>(token);
3632
        }
3633

3634
        template<typename json_traits>
3635
        jwks<json_traits> parse_jwks(const typename json_traits::string_type& token) {
3636
                return jwks<json_traits>(token);
3637
        }
3638
} // namespace jwt
3639

3640
template<typename json_traits>
3641
std::istream& operator>>(std::istream& is, jwt::basic_claim<json_traits>& c) {
6✔
3642
        return c.operator>>(is);
6✔
3643
}
3644

3645
template<typename json_traits>
3646
std::ostream& operator<<(std::ostream& os, const jwt::basic_claim<json_traits>& c) {
3647
        return os << c.to_json();
3648
}
3649

3650
#ifndef JWT_DISABLE_PICOJSON
3651
#include "traits/kazuho-picojson/defaults.h"
3652
#endif
3653

3654
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc