1 /*
2 Copyright (c) 2017 Arun Muralidharan
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21  */
22 
23 #ifndef CPP_JWT_ALGORITHM_HPP
24 #define CPP_JWT_ALGORITHM_HPP
25 
26 /*!
27  * Most of the signing and verification code has been taken
28  * and modified for C++ specific use from the C implementation
29  * JWT library, libjwt.
30  * https://github.com/benmcollins/libjwt/tree/master/libjwt
31  */
32 
33 #include <cassert>
34 #include <memory>
35 #include <system_error>
36 
37 #include <openssl/bn.h>
38 #include <openssl/bio.h>
39 #include <openssl/pem.h>
40 #include <openssl/evp.h>
41 #include <openssl/hmac.h>
42 #include <openssl/ecdsa.h>
43 #include <openssl/buffer.h>
44 #include <openssl/opensslv.h>
45 
46 #include "jwt/exceptions.hpp"
47 #include "jwt/string_view.hpp"
48 #include "jwt/error_codes.hpp"
49 #include "jwt/base64.hpp"
50 #include "jwt/config.hpp"
51 
52 namespace jwt {
53 
54 /// The result type of the signing function
55 using sign_result_t = std::pair<std::string, std::error_code>;
56 /// The result type of verification function
57 using verify_result_t = std::pair<bool, std::error_code>;
58 /// The function pointer type for the signing function
59 using sign_func_t   = sign_result_t (*) (const jwt::string_view key,
60                                          const jwt::string_view data);
61 /// The function pointer type for the verifying function
62 using verify_func_t = verify_result_t (*) (const jwt::string_view key,
63                                            const jwt::string_view head,
64                                            const jwt::string_view jwt_sign);
65 
66 namespace algo {
67 
68 //Me: TODO: All these can be done using code generaion.
69 //Me: NO. NEVER. I hate Macros.
70 //Me: You can use templates too.
71 //Me: No. I would rather prefer explicit.
72 //Me: Ok. You win.
73 //Me: Same to you.
74 
75 /**
76  * HS256 algorithm.
77  */
78 struct HS256
79 {
operator ()jwt::algo::HS25680   const EVP_MD* operator()() noexcept
81   {
82     return EVP_sha256();
83   }
84 };
85 
86 /**
87  * HS384 algorithm.
88  */
89 struct HS384
90 {
operator ()jwt::algo::HS38491   const EVP_MD* operator()() noexcept
92   {
93     return EVP_sha384();
94   }
95 };
96 
97 /**
98  * HS512 algorithm.
99  */
100 struct HS512
101 {
operator ()jwt::algo::HS512102   const EVP_MD* operator()() noexcept
103   {
104     return EVP_sha512();
105   }
106 };
107 
108 /**
109  * NONE algorithm.
110  */
111 struct NONE
112 {
operator ()jwt::algo::NONE113   void operator()() noexcept
114   {
115     return;
116   }
117 };
118 
119 /**
120  * RS256 algorithm.
121  */
122 struct RS256
123 {
124   static const int type = EVP_PKEY_RSA;
125 
operator ()jwt::algo::RS256126   const EVP_MD* operator()() noexcept
127   {
128     return EVP_sha256();
129   }
130 };
131 
132 /**
133  * RS384 algorithm.
134  */
135 struct RS384
136 {
137   static const int type = EVP_PKEY_RSA;
138 
operator ()jwt::algo::RS384139   const EVP_MD* operator()() noexcept
140   {
141     return EVP_sha384();
142   }
143 };
144 
145 /**
146  * RS512 algorithm.
147  */
148 struct RS512
149 {
150   static const int type = EVP_PKEY_RSA;
151 
operator ()jwt::algo::RS512152   const EVP_MD* operator()() noexcept
153   {
154     return EVP_sha512();
155   }
156 };
157 
158 /**
159  * ES256 algorithm.
160  */
161 struct ES256
162 {
163   static const int type = EVP_PKEY_EC;
164 
operator ()jwt::algo::ES256165   const EVP_MD* operator()() noexcept
166   {
167     return EVP_sha256();
168   }
169 };
170 
171 /**
172  * ES384 algorithm.
173  */
174 struct ES384
175 {
176   static const int type = EVP_PKEY_EC;
177 
operator ()jwt::algo::ES384178   const EVP_MD* operator()() noexcept
179   {
180     return EVP_sha384();
181   }
182 };
183 
184 /**
185  * ES512 algorithm.
186  */
187 struct ES512
188 {
189   static const int type = EVP_PKEY_EC;
190 
operator ()jwt::algo::ES512191   const EVP_MD* operator()() noexcept
192   {
193     return EVP_sha512();
194   }
195 };
196 
197 } //END Namespace algo
198 
199 
200 /**
201  * JWT signing algorithm types.
202  */
203 enum class algorithm
204 {
205   NONE = 0,
206   HS256,
207   HS384,
208   HS512,
209   RS256,
210   RS384,
211   RS512,
212   ES256,
213   ES384,
214   ES512,
215   UNKN,
216   TERM,
217 };
218 
219 
220 /**
221  * Convert the algorithm enum class type to
222  * its stringified form.
223  */
alg_to_str(SCOPED_ENUM algorithm alg)224 inline jwt::string_view alg_to_str(SCOPED_ENUM algorithm alg) noexcept
225 {
226   switch (alg) {
227     case algorithm::HS256: return "HS256";
228     case algorithm::HS384: return "HS384";
229     case algorithm::HS512: return "HS512";
230     case algorithm::RS256: return "RS256";
231     case algorithm::RS384: return "RS384";
232     case algorithm::RS512: return "RS512";
233     case algorithm::ES256: return "ES256";
234     case algorithm::ES384: return "ES384";
235     case algorithm::ES512: return "ES512";
236     case algorithm::TERM:  return "TERM";
237     case algorithm::NONE:  return "NONE";
238     case algorithm::UNKN:  return "UNKN";
239     default:               assert (0 && "Unknown Algorithm");
240   };
241   return "UNKN";
242   assert (0 && "Code not reached");
243 }
244 
245 /**
246  * Convert stringified algorithm to enum class.
247  * The string comparison is case insesitive.
248  */
str_to_alg(const jwt::string_view alg)249 inline SCOPED_ENUM algorithm str_to_alg(const jwt::string_view alg) noexcept
250 {
251   if (!alg.length()) return algorithm::NONE;
252 
253   if (!strcasecmp(alg.data(), "none"))  return algorithm::NONE;
254   if (!strcasecmp(alg.data(), "hs256")) return algorithm::HS256;
255   if (!strcasecmp(alg.data(), "hs384")) return algorithm::HS384;
256   if (!strcasecmp(alg.data(), "hs512")) return algorithm::HS512;
257   if (!strcasecmp(alg.data(), "rs256")) return algorithm::RS256;
258   if (!strcasecmp(alg.data(), "rs384")) return algorithm::RS384;
259   if (!strcasecmp(alg.data(), "rs512")) return algorithm::RS512;
260   if (!strcasecmp(alg.data(), "es256")) return algorithm::ES256;
261   if (!strcasecmp(alg.data(), "es384")) return algorithm::ES384;
262   if (!strcasecmp(alg.data(), "es512")) return algorithm::ES512;
263 
264   return algorithm::UNKN;
265 
266   assert (0 && "Code not reached");
267 }
268 
269 /**
270  */
bio_deletor(BIO * ptr)271 inline void bio_deletor(BIO* ptr)
272 {
273   if (ptr) BIO_free_all(ptr);
274 }
275 
276 /**
277  */
evp_md_ctx_deletor(EVP_MD_CTX * ptr)278 inline void evp_md_ctx_deletor(EVP_MD_CTX* ptr)
279 {
280   if (ptr) EVP_MD_CTX_destroy(ptr);
281 }
282 
283 /**
284  */
ec_key_deletor(EC_KEY * ptr)285 inline void ec_key_deletor(EC_KEY* ptr)
286 {
287   if (ptr) EC_KEY_free(ptr);
288 }
289 
290 /**
291  */
ec_sig_deletor(ECDSA_SIG * ptr)292 inline void ec_sig_deletor(ECDSA_SIG* ptr)
293 {
294   if (ptr) ECDSA_SIG_free(ptr);
295 }
296 
297 /**
298  */
ev_pkey_deletor(EVP_PKEY * ptr)299 inline void ev_pkey_deletor(EVP_PKEY* ptr)
300 {
301   if (ptr) EVP_PKEY_free(ptr);
302 }
303 
304 /// Useful typedefs
305 using bio_deletor_t = decltype(&bio_deletor);
306 using BIO_uptr = std::unique_ptr<BIO, bio_deletor_t>;
307 
308 using evp_mdctx_deletor_t = decltype(&evp_md_ctx_deletor);
309 using EVP_MDCTX_uptr = std::unique_ptr<EVP_MD_CTX, evp_mdctx_deletor_t>;
310 
311 using eckey_deletor_t = decltype(&ec_key_deletor);
312 using EC_KEY_uptr = std::unique_ptr<EC_KEY, eckey_deletor_t>;
313 
314 using ecsig_deletor_t = decltype(&ec_sig_deletor);
315 using EC_SIG_uptr = std::unique_ptr<ECDSA_SIG, ecsig_deletor_t>;
316 
317 using evpkey_deletor_t = decltype(&ev_pkey_deletor);
318 using EC_PKEY_uptr = std::unique_ptr<EVP_PKEY, evpkey_deletor_t>;
319 
320 
321 
322 /**
323  * OpenSSL HMAC based signature and verfication.
324  *
325  * The template type `Hasher` takes the type representing
326  * the HMAC algorithm type from the `jwt::algo` namespace.
327  *
328  * The struct is specialized for NONE algorithm. See the
329  * details of that class as well.
330  */
331 template <typename Hasher>
332 struct HMACSign
333 {
334   /// The type of Hashing algorithm
335   using hasher_type = Hasher;
336 
337   /**
338    * Signs the input using the HMAC algorithm using the
339    * provided key.
340    *
341    * Arguments:
342    *  @key : The secret/key to use for the signing.
343    *         Cannot be empty string.
344    *  @data : The data to be signed.
345    *
346    *  Exceptions:
347    *    Any allocation failure will result in jwt::MemoryAllocationException
348    *    being thrown.
349    */
signjwt::HMACSign350   static sign_result_t sign(const jwt::string_view key, const jwt::string_view data)
351   {
352     std::string sign;
353     sign.resize(EVP_MAX_MD_SIZE);
354     std::error_code ec{};
355 
356     uint32_t len = 0;
357 
358     unsigned char* res = HMAC(Hasher{}(),
359                               key.data(),
360                               key.length(),
361                               reinterpret_cast<const unsigned char*>(data.data()),
362                               data.length(),
363                               reinterpret_cast<unsigned char*>(&sign[0]),
364                               &len);
365     if (!res) {
366       ec = AlgorithmErrc::SigningErr;
367     }
368 
369     sign.resize(len);
370     return { std::move(sign), ec };
371   }
372 
373   /**
374    * Verifies the JWT string against the signature using
375    * the provided key.
376    *
377    * Arguments:
378    *  @key : The secret/key to use for the signing.
379    *         Cannot be empty string.
380    *  @head : The part of JWT encoded string representing header
381    *          and the payload claims.
382    *  @sign : The signature part of the JWT encoded string.
383    *
384    *  Returns:
385    *    verify_result_t
386    *    verify_result_t::first set to true if verification succeeds.
387    *    false otherwise.
388    *    verify_result_t::second set to relevant error if verification fails.
389    *
390    *  Exceptions:
391    *    Any allocation failure will result in jwt::MemoryAllocationException
392    *    being thrown.
393    */
394   static verify_result_t
395   verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign);
396 
397 };
398 
399 /**
400  * Specialization of `HMACSign` class
401  * for NONE algorithm.
402  *
403  * This specialization is selected for even
404  * PEM based algorithms.
405  *
406  * The signing and verification APIs are
407  * basically no-op except that they would
408  * set the relevant error code.
409  *
410  * NOTE: error_code would be set in the case
411  * of usage of NONE algorithm.
412  * Users of this API are expected to check for
413  * the case explicitly.
414  */
415 template <>
416 struct HMACSign<algo::NONE>
417 {
418   using hasher_type = algo::NONE;
419 
420   /**
421    * Basically a no-op. Sets the error code to NoneAlgorithmUsed.
422    */
signjwt::HMACSign423   static sign_result_t sign(const jwt::string_view key, const jwt::string_view data)
424   {
425     (void)key;
426     (void)data;
427     std::error_code ec{};
428     ec = AlgorithmErrc::NoneAlgorithmUsed;
429 
430     return { std::string{}, ec };
431   }
432 
433   /**
434    * Basically a no-op. Sets the error code to NoneAlgorithmUsed.
435    */
436   static verify_result_t
verifyjwt::HMACSign437   verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign)
438   {
439     (void)key;
440     (void)head;
441     (void)sign;
442     std::error_code ec{};
443     ec = AlgorithmErrc::NoneAlgorithmUsed;
444 
445     return { true, ec };
446   }
447 
448 };
449 
450 
451 
452 /**
453  * OpenSSL PEM based signature and verfication.
454  *
455  * The template type `Hasher` takes the type representing
456  * the PEM algorithm type from the `jwt::algo` namespace.
457  *
458  * For NONE algorithm, HMACSign<> specialization is used.
459  * See that for more details.
460  */
461 template <typename Hasher>
462 struct PEMSign
463 {
464 public:
465   /// The type of Hashing algorithm
466   using hasher_type = Hasher;
467 
468   /**
469    * Signs the input data using PEM encryption algorithm.
470    *
471    * Arguments:
472    *  @key : The key/secret to be used for signing.
473    *         Cannot be an empty string.
474    *  @data: The data to be signed.
475    *
476    * Exceptions:
477    *  Any allocation failure would be thrown out as
478    *  jwt::MemoryAllocationException.
479    */
signjwt::PEMSign480   static sign_result_t sign(const jwt::string_view key, const jwt::string_view data)
481   {
482     std::error_code ec{};
483 
484     std::string ii{data.data(), data.length()};
485 
486     EC_PKEY_uptr pkey{load_key(key, ec), ev_pkey_deletor};
487     if (ec) return { std::string{}, ec };
488 
489     //TODO: Use stack string here ?
490     std::string sign = evp_digest(pkey.get(), data, ec);
491 
492     if (ec) return { std::string{}, ec };
493 
494     if (Hasher::type == EVP_PKEY_EC) {
495       sign = public_key_ser(pkey.get(), sign, ec);
496     }
497 
498     return { std::move(sign), ec };
499   }
500 
501   /**
502    */
503   static verify_result_t
504   verify(const jwt::string_view key, const jwt::string_view head, const jwt::string_view sign);
505 
506 private:
507 
508   /*!
509    */
510   static EVP_PKEY* load_key(const jwt::string_view key, std::error_code& ec);
511 
512   /*!
513    */
514   static std::string evp_digest(EVP_PKEY* pkey, const jwt::string_view data, std::error_code& ec);
515 
516   /*!
517    */
518   static std::string public_key_ser(EVP_PKEY* pkey, jwt::string_view sign, std::error_code& ec);
519 
520 #if OPENSSL_VERSION_NUMBER < 0x10100000L
521 
522   //ATTN: Below 2 functions
523   //are Taken from https://github.com/nginnever/zogminer/issues/39
524 
525   /**
526    */
ECDSA_SIG_get0jwt::PEMSign527   static void ECDSA_SIG_get0(const ECDSA_SIG* sig, const BIGNUM** pr, const BIGNUM** ps)
528   {
529     if (pr != nullptr) *pr = sig->r;
530     if (ps != nullptr) *ps = sig->s;
531   };
532 
533   /**
534    */
ECDSA_SIG_set0jwt::PEMSign535   static int ECDSA_SIG_set0(ECDSA_SIG* sig, BIGNUM* r, BIGNUM* s)
536   {
537     if (r == nullptr || s == nullptr) return 0;
538 
539     BN_clear_free(sig->r);
540     BN_clear_free(sig->s);
541 
542     sig->r = r;
543     sig->s = s;
544     return 1;
545   }
546 
547 #endif
548 };
549 
550 } // END namespace jwt
551 
552 #include "jwt/impl/algorithm.ipp"
553 
554 
555 #endif
556