@@ -388,6 +388,83 @@ namespace jwt {
388
388
* you maybe need to extract the modulus and exponent of an RSA Public Key.
389
389
*/
390
390
namespace helper {
391
+ /* *
392
+ * \brief Handle class for EVP_PKEY structures
393
+ *
394
+ * Starting from OpenSSL 1.1.0, EVP_PKEY has internal reference counting. This handle class allows
395
+ * jwt-cpp to leverage that and thus safe an allocation for the control block in std::shared_ptr.
396
+ * The handle uses shared_ptr as a fallback on older versions. The behaviour should be identical between both.
397
+ */
398
+ class evp_pkey_handle {
399
+ public:
400
+ constexpr evp_pkey_handle () noexcept = default;
401
+ #ifdef JWT_OPENSSL_1_0_0
402
+ /* *
403
+ * \brief Contruct a new handle. The handle takes ownership of the key.
404
+ * \param key The key to store
405
+ */
406
+ explicit evp_pkey_handle (EVP_PKEY* key) { m_key = std::shared_ptr<EVP_PKEY>(key, EVP_PKEY_free); }
407
+
408
+ EVP_PKEY* get () const noexcept { return m_key.get (); }
409
+ bool operator !() const noexcept { return m_key == nullptr ; }
410
+ explicit operator bool () const noexcept { return m_key != nullptr ; }
411
+
412
+ private:
413
+ std::shared_ptr<EVP_PKEY> m_key{nullptr };
414
+ #else
415
+ /* *
416
+ * \brief Contruct a new handle. The handle takes ownership of the key.
417
+ * \param key The key to store
418
+ */
419
+ explicit constexpr evp_pkey_handle (EVP_PKEY* key) noexcept : m_key{key} {}
420
+ evp_pkey_handle (const evp_pkey_handle& other) : m_key{other.m_key } {
421
+ if (m_key != nullptr && EVP_PKEY_up_ref (m_key) != 1 ) throw std::runtime_error (" EVP_PKEY_up_ref failed" );
422
+ }
423
+ // C++11 requires the body of a constexpr constructor to be empty
424
+ #if __cplusplus >= 201402L
425
+ constexpr
426
+ #endif
427
+ evp_pkey_handle (evp_pkey_handle&& other) noexcept
428
+ : m_key{other.m_key } {
429
+ other.m_key = nullptr ;
430
+ }
431
+ evp_pkey_handle& operator =(const evp_pkey_handle& other) {
432
+ if (&other == this ) return *this ;
433
+ decrement_ref_count (m_key);
434
+ m_key = other.m_key ;
435
+ increment_ref_count (m_key);
436
+ return *this ;
437
+ }
438
+ evp_pkey_handle& operator =(evp_pkey_handle&& other) noexcept {
439
+ if (&other == this ) return *this ;
440
+ decrement_ref_count (m_key);
441
+ m_key = other.m_key ;
442
+ other.m_key = nullptr ;
443
+ return *this ;
444
+ }
445
+ evp_pkey_handle& operator =(EVP_PKEY* key) {
446
+ decrement_ref_count (m_key);
447
+ m_key = key;
448
+ increment_ref_count (m_key);
449
+ return *this ;
450
+ }
451
+ ~evp_pkey_handle () noexcept { decrement_ref_count (m_key); }
452
+
453
+ EVP_PKEY* get () const noexcept { return m_key; }
454
+ bool operator !() const noexcept { return m_key == nullptr ; }
455
+ explicit operator bool () const noexcept { return m_key != nullptr ; }
456
+
457
+ private:
458
+ EVP_PKEY* m_key{nullptr };
459
+
460
+ static void increment_ref_count (EVP_PKEY* key) {
461
+ if (key != nullptr && EVP_PKEY_up_ref (key) != 1 ) throw std::runtime_error (" EVP_PKEY_up_ref failed" );
462
+ }
463
+ static void decrement_ref_count (EVP_PKEY* key) noexcept {
464
+ if (key != nullptr ) EVP_PKEY_free (key);
465
+ }
466
+ #endif
467
+ };
391
468
/* *
392
469
* \brief Extract the public key of a pem certificate
393
470
*
@@ -556,38 +633,34 @@ namespace jwt {
556
633
* \param password Password used to decrypt certificate (leave empty if not encrypted)
557
634
* \param ec error_code for error_detection (gets cleared if no error occures)
558
635
*/
559
- inline std::shared_ptr<EVP_PKEY> load_public_key_from_string (const std::string& key,
560
- const std::string& password, std::error_code& ec) {
636
+ inline evp_pkey_handle load_public_key_from_string (const std::string& key, const std::string& password ,
637
+ std::error_code& ec) {
561
638
ec.clear ();
562
639
std::unique_ptr<BIO, decltype (&BIO_free_all)> pubkey_bio (BIO_new (BIO_s_mem ()), BIO_free_all);
563
640
if (!pubkey_bio) {
564
641
ec = error::rsa_error::create_mem_bio_failed;
565
- return nullptr ;
642
+ return {} ;
566
643
}
567
644
if (key.substr (0 , 27 ) == " -----BEGIN CERTIFICATE-----" ) {
568
645
auto epkey = helper::extract_pubkey_from_cert (key, password, ec);
569
- if (ec) return nullptr ;
646
+ if (ec) return {} ;
570
647
const int len = static_cast <int >(epkey.size ());
571
648
if (BIO_write (pubkey_bio.get (), epkey.data (), len) != len) {
572
649
ec = error::rsa_error::load_key_bio_write;
573
- return nullptr ;
650
+ return {} ;
574
651
}
575
652
} else {
576
653
const int len = static_cast <int >(key.size ());
577
654
if (BIO_write (pubkey_bio.get (), key.data (), len) != len) {
578
655
ec = error::rsa_error::load_key_bio_write;
579
- return nullptr ;
656
+ return {} ;
580
657
}
581
658
}
582
659
583
- std::shared_ptr<EVP_PKEY> pkey (
584
- PEM_read_bio_PUBKEY (pubkey_bio.get (), nullptr , nullptr ,
585
- (void *)password.data ()), // NOLINT(google-readability-casting) requires `const_cast`
586
- EVP_PKEY_free);
587
- if (!pkey) {
588
- ec = error::rsa_error::load_key_bio_read;
589
- return nullptr ;
590
- }
660
+ evp_pkey_handle pkey (PEM_read_bio_PUBKEY (
661
+ pubkey_bio.get (), nullptr , nullptr ,
662
+ (void *)password.data ())); // NOLINT(google-readability-casting) requires `const_cast`
663
+ if (!pkey) ec = error::rsa_error::load_key_bio_read;
591
664
return pkey;
592
665
}
593
666
@@ -600,8 +673,7 @@ namespace jwt {
600
673
* \param password Password used to decrypt certificate or key (leave empty if not encrypted)
601
674
* \throw rsa_exception if an error occurred
602
675
*/
603
- inline std::shared_ptr<EVP_PKEY> load_public_key_from_string (const std::string& key,
604
- const std::string& password = " " ) {
676
+ inline evp_pkey_handle load_public_key_from_string (const std::string& key, const std::string& password = " " ) {
605
677
std::error_code ec;
606
678
auto res = load_public_key_from_string (key, password, ec);
607
679
error::throw_if_error (ec);
@@ -615,25 +687,21 @@ namespace jwt {
615
687
* \param password Password used to decrypt key (leave empty if not encrypted)
616
688
* \param ec error_code for error_detection (gets cleared if no error occures)
617
689
*/
618
- inline std::shared_ptr<EVP_PKEY>
619
- load_private_key_from_string ( const std::string& key, const std::string& password, std::error_code& ec) {
690
+ inline evp_pkey_handle load_private_key_from_string ( const std::string& key, const std::string& password,
691
+ std::error_code& ec) {
620
692
std::unique_ptr<BIO, decltype (&BIO_free_all)> privkey_bio (BIO_new (BIO_s_mem ()), BIO_free_all);
621
693
if (!privkey_bio) {
622
694
ec = error::rsa_error::create_mem_bio_failed;
623
- return nullptr ;
695
+ return {} ;
624
696
}
625
697
const int len = static_cast <int >(key.size ());
626
698
if (BIO_write (privkey_bio.get (), key.data (), len) != len) {
627
699
ec = error::rsa_error::load_key_bio_write;
628
- return nullptr ;
629
- }
630
- std::shared_ptr<EVP_PKEY> pkey (
631
- PEM_read_bio_PrivateKey (privkey_bio.get (), nullptr , nullptr , const_cast <char *>(password.c_str ())),
632
- EVP_PKEY_free);
633
- if (!pkey) {
634
- ec = error::rsa_error::load_key_bio_read;
635
- return nullptr ;
700
+ return {};
636
701
}
702
+ evp_pkey_handle pkey (
703
+ PEM_read_bio_PrivateKey (privkey_bio.get (), nullptr , nullptr , const_cast <char *>(password.c_str ())));
704
+ if (!pkey) ec = error::rsa_error::load_key_bio_read;
637
705
return pkey;
638
706
}
639
707
@@ -644,8 +712,7 @@ namespace jwt {
644
712
* \param password Password used to decrypt key (leave empty if not encrypted)
645
713
* \throw rsa_exception if an error occurred
646
714
*/
647
- inline std::shared_ptr<EVP_PKEY> load_private_key_from_string (const std::string& key,
648
- const std::string& password = " " ) {
715
+ inline evp_pkey_handle load_private_key_from_string (const std::string& key, const std::string& password = " " ) {
649
716
std::error_code ec;
650
717
auto res = load_private_key_from_string (key, password, ec);
651
718
error::throw_if_error (ec);
@@ -661,38 +728,34 @@ namespace jwt {
661
728
* \param password Password used to decrypt certificate (leave empty if not encrypted)
662
729
* \param ec error_code for error_detection (gets cleared if no error occures)
663
730
*/
664
- inline std::shared_ptr<EVP_PKEY>
665
- load_public_ec_key_from_string ( const std::string& key, const std::string& password, std::error_code& ec) {
731
+ inline evp_pkey_handle load_public_ec_key_from_string ( const std::string& key, const std::string& password,
732
+ std::error_code& ec) {
666
733
ec.clear ();
667
734
std::unique_ptr<BIO, decltype (&BIO_free_all)> pubkey_bio (BIO_new (BIO_s_mem ()), BIO_free_all);
668
735
if (!pubkey_bio) {
669
736
ec = error::ecdsa_error::create_mem_bio_failed;
670
- return nullptr ;
737
+ return {} ;
671
738
}
672
739
if (key.substr (0 , 27 ) == " -----BEGIN CERTIFICATE-----" ) {
673
740
auto epkey = helper::extract_pubkey_from_cert (key, password, ec);
674
- if (ec) return nullptr ;
741
+ if (ec) return {} ;
675
742
const int len = static_cast <int >(epkey.size ());
676
743
if (BIO_write (pubkey_bio.get (), epkey.data (), len) != len) {
677
744
ec = error::ecdsa_error::load_key_bio_write;
678
- return nullptr ;
745
+ return {} ;
679
746
}
680
747
} else {
681
748
const int len = static_cast <int >(key.size ());
682
749
if (BIO_write (pubkey_bio.get (), key.data (), len) != len) {
683
750
ec = error::ecdsa_error::load_key_bio_write;
684
- return nullptr ;
751
+ return {} ;
685
752
}
686
753
}
687
754
688
- std::shared_ptr<EVP_PKEY> pkey (
689
- PEM_read_bio_PUBKEY (pubkey_bio.get (), nullptr , nullptr ,
690
- (void *)password.data ()), // NOLINT(google-readability-casting) requires `const_cast`
691
- EVP_PKEY_free);
692
- if (!pkey) {
693
- ec = error::ecdsa_error::load_key_bio_read;
694
- return nullptr ;
695
- }
755
+ evp_pkey_handle pkey (PEM_read_bio_PUBKEY (
756
+ pubkey_bio.get (), nullptr , nullptr ,
757
+ (void *)password.data ())); // NOLINT(google-readability-casting) requires `const_cast`
758
+ if (!pkey) ec = error::ecdsa_error::load_key_bio_read;
696
759
return pkey;
697
760
}
698
761
@@ -705,8 +768,8 @@ namespace jwt {
705
768
* \param password Password used to decrypt certificate or key (leave empty if not encrypted)
706
769
* \throw ecdsa_exception if an error occurred
707
770
*/
708
- inline std::shared_ptr<EVP_PKEY> load_public_ec_key_from_string (const std::string& key,
709
- const std::string& password = " " ) {
771
+ inline evp_pkey_handle load_public_ec_key_from_string (const std::string& key,
772
+ const std::string& password = " " ) {
710
773
std::error_code ec;
711
774
auto res = load_public_ec_key_from_string (key, password, ec);
712
775
error::throw_if_error (ec);
@@ -720,25 +783,21 @@ namespace jwt {
720
783
* \param password Password used to decrypt key (leave empty if not encrypted)
721
784
* \param ec error_code for error_detection (gets cleared if no error occures)
722
785
*/
723
- inline std::shared_ptr<EVP_PKEY>
724
- load_private_ec_key_from_string ( const std::string& key, const std::string& password, std::error_code& ec) {
786
+ inline evp_pkey_handle load_private_ec_key_from_string ( const std::string& key, const std::string& password,
787
+ std::error_code& ec) {
725
788
std::unique_ptr<BIO, decltype (&BIO_free_all)> privkey_bio (BIO_new (BIO_s_mem ()), BIO_free_all);
726
789
if (!privkey_bio) {
727
790
ec = error::ecdsa_error::create_mem_bio_failed;
728
- return nullptr ;
791
+ return {} ;
729
792
}
730
793
const int len = static_cast <int >(key.size ());
731
794
if (BIO_write (privkey_bio.get (), key.data (), len) != len) {
732
795
ec = error::ecdsa_error::load_key_bio_write;
733
- return nullptr ;
734
- }
735
- std::shared_ptr<EVP_PKEY> pkey (
736
- PEM_read_bio_PrivateKey (privkey_bio.get (), nullptr , nullptr , const_cast <char *>(password.c_str ())),
737
- EVP_PKEY_free);
738
- if (!pkey) {
739
- ec = error::ecdsa_error::load_key_bio_read;
740
- return nullptr ;
796
+ return {};
741
797
}
798
+ evp_pkey_handle pkey (
799
+ PEM_read_bio_PrivateKey (privkey_bio.get (), nullptr , nullptr , const_cast <char *>(password.c_str ())));
800
+ if (!pkey) ec = error::ecdsa_error::load_key_bio_read;
742
801
return pkey;
743
802
}
744
803
@@ -749,8 +808,8 @@ namespace jwt {
749
808
* \param password Password used to decrypt key (leave empty if not encrypted)
750
809
* \throw ecdsa_exception if an error occurred
751
810
*/
752
- inline std::shared_ptr<EVP_PKEY> load_private_ec_key_from_string (const std::string& key,
753
- const std::string& password = " " ) {
811
+ inline evp_pkey_handle load_private_ec_key_from_string (const std::string& key,
812
+ const std::string& password = " " ) {
754
813
std::error_code ec;
755
814
auto res = load_private_ec_key_from_string (key, password, ec);
756
815
error::throw_if_error (ec);
@@ -990,7 +1049,7 @@ namespace jwt {
990
1049
991
1050
private:
992
1051
// / OpenSSL structure containing converted keys
993
- std::shared_ptr<EVP_PKEY> pkey;
1052
+ helper::evp_pkey_handle pkey;
994
1053
// / Hash generator
995
1054
const EVP_MD* (*md)();
996
1055
// / algorithm's name
@@ -1214,7 +1273,7 @@ namespace jwt {
1214
1273
}
1215
1274
1216
1275
// / OpenSSL struct containing keys
1217
- std::shared_ptr<EVP_PKEY> pkey;
1276
+ helper::evp_pkey_handle pkey;
1218
1277
// / Hash generator function
1219
1278
const EVP_MD* (*md)();
1220
1279
// / algorithm's name
@@ -1360,7 +1419,7 @@ namespace jwt {
1360
1419
1361
1420
private:
1362
1421
// / OpenSSL struct containing keys
1363
- std::shared_ptr<EVP_PKEY> pkey;
1422
+ helper::evp_pkey_handle pkey;
1364
1423
// / algorithm's name
1365
1424
const std::string alg_name;
1366
1425
};
@@ -1496,7 +1555,7 @@ namespace jwt {
1496
1555
1497
1556
private:
1498
1557
// / OpenSSL structure containing keys
1499
- std::shared_ptr<EVP_PKEY> pkey;
1558
+ helper::evp_pkey_handle pkey;
1500
1559
// / Hash generator function
1501
1560
const EVP_MD* (*md)();
1502
1561
// / algorithm's name
0 commit comments