From 0415e75013f64607a1ace0ea53f84cca98e8b0ce Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 15:40:34 -0500 Subject: [PATCH 01/18] add a quick test to see if rsa helpers handle ec certs LoadPublicKeyFromStringReferenceWithEcCert --- tests/OpenSSLErrorTest.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 45ada667..6f50aa6b 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -536,6 +536,11 @@ TEST(OpenSSLErrorTest, LoadPublicKeyFromStringReference) { ASSERT_TRUE(res); } +TEST(OpenSSLErrorTest, LoadPublicKeyFromStringReferenceWithEcCert) { + auto res = jwt::helper::load_public_key_from_string(ecdsa256_pub_key, ""); + ASSERT_TRUE(res); +} + TEST(OpenSSLErrorTest, LoadPublicKeyFromString) { std::vector mapping{{&fail_BIO_new, 1, jwt::error::rsa_error::create_mem_bio_failed}, {&fail_BIO_write, 1, jwt::error::rsa_error::load_key_bio_write}, From 72a320ad95f27fb53e32b38a0e6c6e9659506a44 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 15:46:58 -0500 Subject: [PATCH 02/18] run all tests with generic helper --- include/jwt-cpp/jwt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index b2b998a2..000fb0b1 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1111,10 +1111,10 @@ namespace jwt { const std::string& private_key_password, const EVP_MD* (*md)(), std::string name, size_t siglen) : md(md), alg_name(std::move(name)), signature_length(siglen) { if (!private_key.empty()) { - pkey = helper::load_private_ec_key_from_string(private_key, private_key_password); + pkey = helper::load_private_key_from_string(private_key, private_key_password); check_private_key(pkey.get()); } else if (!public_key.empty()) { - pkey = helper::load_public_ec_key_from_string(public_key, public_key_password); + pkey = helper::load_public_key_from_string(public_key, public_key_password); check_public_key(pkey.get()); } else { throw error::ecdsa_exception(error::ecdsa_error::no_key_provided); From 7909b41924aeacd8f22ccbccb068da878560685b Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:17:50 -0500 Subject: [PATCH 03/18] template out error category and new tests --- include/jwt-cpp/jwt.h | 98 +++++++++++++++++--------------------- tests/OpenSSLErrorTest.cpp | 28 +++++++++-- 2 files changed, 68 insertions(+), 58 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 000fb0b1..d51af78f 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -161,7 +161,12 @@ namespace jwt { no_key_provided, invalid_key_size, invalid_key, - create_context_failed + create_context_failed, + cert_load_failed, + get_key_failed, + write_key_failed, + convert_to_pem_failed, + }; /** * \brief Error category for ECDSA errors @@ -181,6 +186,11 @@ namespace jwt { case ecdsa_error::invalid_key_size: return "invalid key size"; case ecdsa_error::invalid_key: return "invalid key"; case ecdsa_error::create_context_failed: return "failed to create context"; + case ecdsa_error::cert_load_failed: return "error loading cert into memory"; + case ecdsa_error::get_key_failed: return "error getting key from certificate"; + case ecdsa_error::write_key_failed: return "error writing key data in PEM format"; + case ecdsa_error::write_cert_failed: return "error writing cert data in PEM format"; + case ecdsa_error::convert_to_pem_failed: return "failed to convert key to pem"; default: return "unknown ECDSA error"; } } @@ -492,39 +502,41 @@ namespace jwt { /** * \brief Extract the public key of a pem certificate * - * \param certstr String containing the certificate encoded as pem - * \param pw Password used to decrypt certificate (leave empty if not encrypted) - * \param ec error_code for error_detection (gets cleared if no error occurred) + * \tparam error_category jwt::error enum category to match with the keys being used + * \param certstr String containing the certificate encoded as pem + * \param pw Password used to decrypt certificate (leave empty if not encrypted) + * \param ec error_code for error_detection (gets cleared if no error occurred) */ - inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, + template + std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, std::error_code& ec) { ec.clear(); auto certbio = make_mem_buf_bio(certstr); auto keybio = make_mem_buf_bio(); if (!certbio || !keybio) { - ec = error::rsa_error::create_mem_bio_failed; + ec = error_category::create_mem_bio_failed; return {}; } std::unique_ptr cert( PEM_read_bio_X509(certbio.get(), nullptr, nullptr, const_cast(pw.c_str())), X509_free); if (!cert) { - ec = error::rsa_error::cert_load_failed; + ec = error_category::cert_load_failed; return {}; } std::unique_ptr key(X509_get_pubkey(cert.get()), EVP_PKEY_free); if (!key) { - ec = error::rsa_error::get_key_failed; + ec = error_category::get_key_failed; return {}; } if (PEM_write_bio_PUBKEY(keybio.get(), key.get()) == 0) { - ec = error::rsa_error::write_key_failed; + ec = error_category::write_key_failed; return {}; } char* ptr = nullptr; auto len = BIO_get_mem_data(keybio.get(), &ptr); if (len <= 0 || ptr == nullptr) { - ec = error::rsa_error::convert_to_pem_failed; + ec = error_category::convert_to_pem_failed; return {}; } return {ptr, static_cast(len)}; @@ -533,13 +545,15 @@ namespace jwt { /** * \brief Extract the public key of a pem certificate * - * \param certstr String containing the certificate encoded as pem - * \param pw Password used to decrypt certificate (leave empty if not encrypted) - * \throw rsa_exception if an error occurred + * \tparam error_category jwt::error enum category to match with the keys being used + * \param certstr String containing the certificate encoded as pem + * \param pw Password used to decrypt certificate (leave empty if not encrypted) + * \throw templated error_category's type exception if an error occurred */ - inline std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") { + template + std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") { std::error_code ec; - auto res = extract_pubkey_from_cert(certstr, pw, ec); + auto res = extract_pubkey_from_cert(certstr, pw, ec); error::throw_if_error(ec); return res; } @@ -674,30 +688,32 @@ namespace jwt { * * The string should contain a pem encoded certificate or public key * + * \tparam error_category jwt::error enum category to match with the keys being used * \param key String containing the certificate encoded as pem * \param password Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password, + template + evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { ec.clear(); auto pubkey_bio = make_mem_buf_bio(); if (!pubkey_bio) { - ec = error::rsa_error::create_mem_bio_failed; + ec = error_category::create_mem_bio_failed; return {}; } if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----") { - auto epkey = helper::extract_pubkey_from_cert(key, password, ec); + auto epkey = helper::extract_pubkey_from_cert(key, password, ec); if (ec) return {}; const int len = static_cast(epkey.size()); if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len) { - ec = error::rsa_error::load_key_bio_write; + ec = error_category::load_key_bio_write; return {}; } } else { const int len = static_cast(key.size()); if (BIO_write(pubkey_bio.get(), key.data(), len) != len) { - ec = error::rsa_error::load_key_bio_write; + ec = error_category::load_key_bio_write; return {}; } } @@ -705,7 +721,7 @@ namespace jwt { evp_pkey_handle pkey(PEM_read_bio_PUBKEY( pubkey_bio.get(), nullptr, nullptr, (void*)password.data())); // NOLINT(google-readability-casting) requires `const_cast` - if (!pkey) ec = error::rsa_error::load_key_bio_read; + if (!pkey) ec = error_category::load_key_bio_read; return pkey; } @@ -714,13 +730,15 @@ namespace jwt { * * The string should contain a pem encoded certificate or public key * - * \param key String containing the certificate or key encoded as pem - * \param password Password used to decrypt certificate or key (leave empty if not encrypted) - * \throw rsa_exception if an error occurred + * \tparam error_category jwt::error enum category to match with the keys being used + * \param key String containing the certificate encoded as pem + * \param password Password used to decrypt certificate (leave empty if not encrypted) + * \throw Templated error_category's type exception if an error occurred */ + template inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; - auto res = load_public_key_from_string(key, password, ec); + auto res = load_public_key_from_string(key, password, ec); error::throw_if_error(ec); return res; } @@ -775,33 +793,7 @@ namespace jwt { */ inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { - ec.clear(); - auto pubkey_bio = make_mem_buf_bio(); - if (!pubkey_bio) { - ec = error::ecdsa_error::create_mem_bio_failed; - return {}; - } - if (key.substr(0, 27) == "-----BEGIN CERTIFICATE-----") { - auto epkey = helper::extract_pubkey_from_cert(key, password, ec); - if (ec) return {}; - const int len = static_cast(epkey.size()); - if (BIO_write(pubkey_bio.get(), epkey.data(), len) != len) { - ec = error::ecdsa_error::load_key_bio_write; - return {}; - } - } else { - const int len = static_cast(key.size()); - if (BIO_write(pubkey_bio.get(), key.data(), len) != len) { - ec = error::ecdsa_error::load_key_bio_write; - return {}; - } - } - - evp_pkey_handle pkey(PEM_read_bio_PUBKEY( - pubkey_bio.get(), nullptr, nullptr, - (void*)password.data())); // NOLINT(google-readability-casting) requires `const_cast` - if (!pkey) ec = error::ecdsa_error::load_key_bio_read; - return pkey; + return load_public_key_from_string(key, password, ec); } /** @@ -816,7 +808,7 @@ namespace jwt { inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; - auto res = load_public_ec_key_from_string(key, password, ec); + auto res = load_public_key_from_string(key, password, ec); error::throw_if_error(ec); return res; } diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 6f50aa6b..73a6c1b8 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -541,6 +541,11 @@ TEST(OpenSSLErrorTest, LoadPublicKeyFromStringReferenceWithEcCert) { ASSERT_TRUE(res); } +TEST(OpenSSLErrorTest, LoadPublicKeyFromStringReferenceWithEcCertAndErr) { + auto res = jwt::helper::load_public_key_from_string(ecdsa256_pub_key, ""); + ASSERT_TRUE(res); +} + TEST(OpenSSLErrorTest, LoadPublicKeyFromString) { std::vector mapping{{&fail_BIO_new, 1, jwt::error::rsa_error::create_mem_bio_failed}, {&fail_BIO_write, 1, jwt::error::rsa_error::load_key_bio_write}, @@ -554,6 +559,19 @@ TEST(OpenSSLErrorTest, LoadPublicKeyFromString) { }); } +TEST(OpenSSLErrorTest, LoadPublicKeyFromStringWithEc) { + std::vector mapping{{&fail_BIO_new, 1, jwt::error::ecdsa_error::create_mem_bio_failed}, + {&fail_BIO_write, 1, jwt::error::ecdsa_error::load_key_bio_write}, + {&fail_PEM_read_bio_PUBKEY, 1, jwt::error::ecdsa_error::load_key_bio_read}}; + + run_multitest(mapping, [](std::error_code& ec) { + try { + jwt::helper::load_public_key_from_string(ecdsa256_pub_key, ""); + FAIL(); // Should never reach this + } catch (const jwt::error::ecdsa_exception& e) { ec = e.code(); } + }); +} + TEST(OpenSSLErrorTest, LoadPublicKeyFromStringErrorCode) { std::vector mapping{{&fail_BIO_new, 1, jwt::error::rsa_error::create_mem_bio_failed}, {&fail_BIO_write, 1, jwt::error::rsa_error::load_key_bio_write}, @@ -750,11 +768,11 @@ TEST(OpenSSLErrorTest, ECDSACertificate) { #endif {&fail_PEM_read_bio_PUBKEY, 1, jwt::error::ecdsa_error::load_key_bio_read}, // extract_pubkey_from_cert - {&fail_BIO_new, 2, jwt::error::rsa_error::create_mem_bio_failed}, - {&fail_PEM_read_bio_X509, 1, jwt::error::rsa_error::cert_load_failed}, - {&fail_X509_get_pubkey, 1, jwt::error::rsa_error::get_key_failed}, - {&fail_PEM_write_bio_PUBKEY, 1, jwt::error::rsa_error::write_key_failed}, { - &fail_BIO_ctrl, 1, jwt::error::rsa_error::convert_to_pem_failed + {&fail_BIO_new, 2, jwt::error::ecdsa_error::create_mem_bio_failed}, + {&fail_PEM_read_bio_X509, 1, jwt::error::ecdsa_error::cert_load_failed}, + {&fail_X509_get_pubkey, 1, jwt::error::ecdsa_error::get_key_failed}, + {&fail_PEM_write_bio_PUBKEY, 1, jwt::error::ecdsa_error::write_key_failed}, { + &fail_BIO_ctrl, 1, jwt::error::ecdsa_error::convert_to_pem_failed } }; From 9c5a16435e1d841557855d0afa254c1144dcd112 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:18:54 -0500 Subject: [PATCH 04/18] linter --- include/jwt-cpp/jwt.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index d51af78f..53dea1d6 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -508,8 +508,7 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occurred) */ template - std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, - std::error_code& ec) { + std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, std::error_code& ec) { ec.clear(); auto certbio = make_mem_buf_bio(certstr); auto keybio = make_mem_buf_bio(); @@ -695,7 +694,7 @@ namespace jwt { */ template evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password, - std::error_code& ec) { + std::error_code& ec) { ec.clear(); auto pubkey_bio = make_mem_buf_bio(); if (!pubkey_bio) { From a4ea436c222a4879c6d12dceb8d24c0c15eeac5b Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:19:49 -0500 Subject: [PATCH 05/18] missing enum entry --- include/jwt-cpp/jwt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 53dea1d6..3e80c0cd 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -165,6 +165,7 @@ namespace jwt { cert_load_failed, get_key_failed, write_key_failed, + write_cert_failed, convert_to_pem_failed, }; From 38d6e887edad1314d6292195c770787fc905297d Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:34:21 -0500 Subject: [PATCH 06/18] does convert_base64_der_to_pem work with ecdsa? --- tests/Keys.cpp | 11 +++++++++++ tests/OpenSSLErrorTest.cpp | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/tests/Keys.cpp b/tests/Keys.cpp index 60abdd25..7a3a4900 100644 --- a/tests/Keys.cpp +++ b/tests/Keys.cpp @@ -158,6 +158,17 @@ BQYDK2VwAyEAUdLe1SUWxc/95f39pfmuwe1SLHpFXf5gcRQlMH2sjgwwBQYDK2Vw A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs 3GyYtaZs6AEHwDXl/INXu2zoCQ== -----END CERTIFICATE-----)"; + // openssl x509 -outform der -in ed25519_certificate.pem -out ed25519_certificate.der + // openssl base64 -in ed25519_certificate.der -out ed25519_certificate.b64 + std::string ed25519_certificate_base64_der = "MIIBjzCCAUECFCQlWQxMEMe4c3OOimH4/y+o/HpfMAUGAytlcDBqMQswCQYDVQQG" + "EwJDQTEPMA0GA1UECAwGUXVlYmVjMREwDwYDVQQHDAhNb250cmVhbDEQMA4GA1UE" + "CgwHand0LWNwcDEPMA0GA1UECwwGZ2l0aHViMRQwEgYDVQQDDAtleGFtcGxlLmNv" + "bTAeFw0yMDA3MzAyMTIwMDBaFw0yMjA2MzAyMTIwMDBaMGoxCzAJBgNVBAYTAkNB" + "MQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMRAwDgYDVQQKDAdq" + "d3QtY3BwMQ8wDQYDVQQLDAZnaXRodWIxFDASBgNVBAMMC2V4YW1wbGUuY29tMCow" + "BQYDK2VwAyEAUdLe1SUWxc/95f39pfmuwe1SLHpFXf5gcRQlMH2sjgwwBQYDK2Vw" + "A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs" + "3GyYtaZs6AEHwDXl/INXu2zoCQ=="; std::string ed448_priv_key = R"(-----BEGIN PRIVATE KEY----- MEcCAQAwBQYDK2VxBDsEOZNyV4kIWehIWSsPCnDEZbBF+g2WoUgUwox8eQJTq8Hz y4okU+JZAV8RqQ270fJL/Safvvc1SbbF1A== diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 73a6c1b8..6222786f 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -457,6 +457,14 @@ TEST(OpenSSLErrorTest, ConvertCertBase64DerToPemReference) { ASSERT_EQ(ec.value(), 0); } +TEST(OpenSSLErrorTest, ConvertEcdsaCertBase64DerToPemReference) { + std::error_code ec; + auto res = jwt::helper::convert_base64_der_to_pem(ed25519_certificate_base64_der, ec); + ASSERT_EQ(res, sample_cert); + ASSERT_FALSE(!(!ec)); + ASSERT_EQ(ec.value(), 0); +} + struct multitest_entry { uint64_t* fail_mask_ptr; uint64_t fail_bitmask; @@ -520,6 +528,19 @@ TEST(OpenSSLErrorTest, ConvertCertBase64DerToPem) { }); } +TEST(OpenSSLErrorTest, ConvertEcdsaCertBase64DerToPem) { + std::vector mapping{{&fail_BIO_new, 1, jwt::error::rsa_error::create_mem_bio_failed}, + {&fail_PEM_write_bio_cert, 1, jwt::error::rsa_error::write_cert_failed}, + {&fail_BIO_ctrl, 1, jwt::error::rsa_error::convert_to_pem_failed}}; + + run_multitest(mapping, [](std::error_code& ec) { + try { + jwt::helper::convert_base64_der_to_pem(ed25519_certificate_base64_der); + FAIL(); // Should never reach this + } catch (const jwt::error::rsa_exception& e) { ec = e.code(); } + }); +} + TEST(OpenSSLErrorTest, ConvertCertBase64DerToPemErrorCode) { std::vector mapping{{&fail_BIO_new, 1, jwt::error::rsa_error::create_mem_bio_failed}, {&fail_PEM_write_bio_cert, 1, jwt::error::rsa_error::write_cert_failed}, From 353623bbe2fe196754e168d315c371cd6b3aabfe Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:40:59 -0500 Subject: [PATCH 07/18] use correct EC curve functions --- include/jwt-cpp/jwt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 3e80c0cd..a1dd7600 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1103,10 +1103,10 @@ namespace jwt { const std::string& private_key_password, const EVP_MD* (*md)(), std::string name, size_t siglen) : md(md), alg_name(std::move(name)), signature_length(siglen) { if (!private_key.empty()) { - pkey = helper::load_private_key_from_string(private_key, private_key_password); + pkey = helper::load_private_ec_key_from_string(private_key, private_key_password); check_private_key(pkey.get()); } else if (!public_key.empty()) { - pkey = helper::load_public_key_from_string(public_key, public_key_password); + pkey = helper::load_public_ec_key_from_string(public_key, public_key_password); check_public_key(pkey.get()); } else { throw error::ecdsa_exception(error::ecdsa_error::no_key_provided); @@ -1332,9 +1332,9 @@ namespace jwt { const std::string& private_key_password, std::string name) : alg_name(std::move(name)) { if (!private_key.empty()) { - pkey = helper::load_private_key_from_string(private_key, private_key_password); + pkey = helper::load_private_ec_key_from_string(private_key, private_key_password); } else if (!public_key.empty()) { - pkey = helper::load_public_key_from_string(public_key, public_key_password); + pkey = helper::load_public_ec_key_from_string(public_key, public_key_password); } else throw error::ecdsa_exception(error::ecdsa_error::load_key_bio_read); } From e94e4934d9694978ab7159e098e0f30d168304e6 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:48:15 -0500 Subject: [PATCH 08/18] missing extern symbol --- tests/OpenSSLErrorTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 6222786f..1f252730 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -436,6 +436,7 @@ inline namespace test_keys { extern std::string ed25519_pub_key; extern std::string ed25519_pub_key_invalid; extern std::string ed25519_certificate; + extern std::string ed25519_certificate_base64_der extern std::string ed448_priv_key; extern std::string ed448_pub_key; extern std::string ed448_pub_key_invalid; From 5fd1ad9ad585e47d255dea3d8cd16d59d721b65b Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 17:48:30 -0500 Subject: [PATCH 09/18] dont change behavior --- include/jwt-cpp/jwt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index a1dd7600..21c6a1d1 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1332,9 +1332,9 @@ namespace jwt { const std::string& private_key_password, std::string name) : alg_name(std::move(name)) { if (!private_key.empty()) { - pkey = helper::load_private_ec_key_from_string(private_key, private_key_password); + pkey = helper::load_private_key_from_string(private_key, private_key_password); } else if (!public_key.empty()) { - pkey = helper::load_public_ec_key_from_string(public_key, public_key_password); + pkey = helper::load_public_key_from_string(public_key, public_key_password); } else throw error::ecdsa_exception(error::ecdsa_error::load_key_bio_read); } From 9560bed8c063c7f98b3bab3323cf3e45342be4bd Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 18:10:52 -0500 Subject: [PATCH 10/18] typo --- tests/OpenSSLErrorTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 1f252730..2c9a2dae 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -436,7 +436,7 @@ inline namespace test_keys { extern std::string ed25519_pub_key; extern std::string ed25519_pub_key_invalid; extern std::string ed25519_certificate; - extern std::string ed25519_certificate_base64_der + extern std::string ed25519_certificate_base64_der; extern std::string ed448_priv_key; extern std::string ed448_pub_key; extern std::string ed448_pub_key_invalid; From 6d9ed18001aaf671af11ae5653ae9fb29677547b Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 18:25:36 -0500 Subject: [PATCH 11/18] fix tests --- tests/HelperTest.cpp | 2 +- tests/OpenSSLErrorTest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/HelperTest.cpp b/tests/HelperTest.cpp index 558ca90b..1d9b9fcb 100644 --- a/tests/HelperTest.cpp +++ b/tests/HelperTest.cpp @@ -59,7 +59,7 @@ TEST(HelperTest, ErrorCodeMessages) { ASSERT_EQ(std::error_code(static_cast(i)).message(), std::error_code(static_cast(-1)).message()); - for (i = 10; i < 17; i++) { + for (i = 10; i < 21; i++) { ASSERT_NE(std::error_code(static_cast(i)).message(), std::error_code(static_cast(-1)).message()); } diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 2c9a2dae..7fad2d2d 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -461,7 +461,7 @@ TEST(OpenSSLErrorTest, ConvertCertBase64DerToPemReference) { TEST(OpenSSLErrorTest, ConvertEcdsaCertBase64DerToPemReference) { std::error_code ec; auto res = jwt::helper::convert_base64_der_to_pem(ed25519_certificate_base64_der, ec); - ASSERT_EQ(res, sample_cert); + ASSERT_EQ(res, ed25519_certificate); ASSERT_FALSE(!(!ec)); ASSERT_EQ(ec.value(), 0); } From 71aa3aeb063f13c3d6ca5476d8dec344150d4ca2 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 18:25:52 -0500 Subject: [PATCH 12/18] update private key to be more generic --- include/jwt-cpp/jwt.h | 58 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 21c6a1d1..dc645a50 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -746,38 +746,43 @@ namespace jwt { /** * \brief Load a private key from a string. * - * \param key String containing a private key as pem - * \param password Password used to decrypt key (leave empty if not encrypted) - * \param ec error_code for error_detection (gets cleared if no error occurs) + * \tparam error_category jwt::error enum category to match with the keys being used + * \param key String containing a private key as pem + * \param password Password used to decrypt key (leave empty if not encrypted) + * \param ec error_code for error_detection (gets cleared if no error occurs) */ + template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { - auto privkey_bio = make_mem_buf_bio(); - if (!privkey_bio) { - ec = error::rsa_error::create_mem_bio_failed; + ec.clear(); + auto private_key_bio = make_mem_buf_bio(); + if (!private_key_bio) { + ec = error_category::create_mem_bio_failed; return {}; } const int len = static_cast(key.size()); - if (BIO_write(privkey_bio.get(), key.data(), len) != len) { - ec = error::rsa_error::load_key_bio_write; + if (BIO_write(private_key_bio.get(), key.data(), len) != len) { + ec = error_category::load_key_bio_write; return {}; } evp_pkey_handle pkey( - PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr, const_cast(password.c_str()))); - if (!pkey) ec = error::rsa_error::load_key_bio_read; + PEM_read_bio_PrivateKey(private_key_bio.get(), nullptr, nullptr, const_cast(password.c_str()))); + if (!pkey) ec = error_category::load_key_bio_read; return pkey; } /** * \brief Load a private key from a string. * - * \param key String containing a private key as pem - * \param password Password used to decrypt key (leave empty if not encrypted) - * \throw rsa_exception if an error occurred + * \tparam error_category jwt::error enum category to match with the keys being used + * \param key String containing a private key as pem + * \param password Password used to decrypt key (leave empty if not encrypted) + * \throw Templated error_category's type exception if an error occurred */ + template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; - auto res = load_private_key_from_string(key, password, ec); + auto res = load_private_key_from_string(key, password, ec); error::throw_if_error(ec); return res; } @@ -786,6 +791,8 @@ namespace jwt { * \brief Load a public key from a string. * * The string should contain a pem encoded certificate or public key + * + * \deprecated Use the templated version load_private_key_from_string with error::ecdsa_error * * \param key String containing the certificate encoded as pem * \param password Password used to decrypt certificate (leave empty if not encrypted) @@ -801,6 +808,8 @@ namespace jwt { * * The string should contain a pem encoded certificate or public key * + * \deprecated Use the templated version load_private_key_from_string with error::ecdsa_error + * * \param key String containing the certificate or key encoded as pem * \param password Password used to decrypt certificate or key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred @@ -815,6 +824,8 @@ namespace jwt { /** * \brief Load a private key from a string. + * + * \deprecated Use the templated version load_private_key_from_string with error::ecdsa_error * * \param key String containing a private key as pem * \param password Password used to decrypt key (leave empty if not encrypted) @@ -822,25 +833,14 @@ namespace jwt { */ inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { - auto privkey_bio = make_mem_buf_bio(); - if (!privkey_bio) { - ec = error::ecdsa_error::create_mem_bio_failed; - return {}; - } - const int len = static_cast(key.size()); - if (BIO_write(privkey_bio.get(), key.data(), len) != len) { - ec = error::ecdsa_error::load_key_bio_write; - return {}; - } - evp_pkey_handle pkey( - PEM_read_bio_PrivateKey(privkey_bio.get(), nullptr, nullptr, const_cast(password.c_str()))); - if (!pkey) ec = error::ecdsa_error::load_key_bio_read; - return pkey; + return load_private_key_from_string(key, password, ec); } /** * \brief Load a private key from a string. * + * \deprecated Use the templated version load_private_key_from_string with error::ecdsa_error + * * \param key String containing a private key as pem * \param password Password used to decrypt key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred @@ -848,7 +848,7 @@ namespace jwt { inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; - auto res = load_private_ec_key_from_string(key, password, ec); + auto res = load_private_key_from_string(key, password, ec); error::throw_if_error(ec); return res; } From 7645b2a30f82af285f4026c058f5356b7d37a73f Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 19:06:12 -0500 Subject: [PATCH 13/18] fixup 2 more tests --- tests/HelperTest.cpp | 2 +- tests/Keys.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/HelperTest.cpp b/tests/HelperTest.cpp index 1d9b9fcb..a806988a 100644 --- a/tests/HelperTest.cpp +++ b/tests/HelperTest.cpp @@ -59,7 +59,7 @@ TEST(HelperTest, ErrorCodeMessages) { ASSERT_EQ(std::error_code(static_cast(i)).message(), std::error_code(static_cast(-1)).message()); - for (i = 10; i < 21; i++) { + for (i = 10; i < 22; i++) { ASSERT_NE(std::error_code(static_cast(i)).message(), std::error_code(static_cast(-1)).message()); } diff --git a/tests/Keys.cpp b/tests/Keys.cpp index 7a3a4900..dbff2744 100644 --- a/tests/Keys.cpp +++ b/tests/Keys.cpp @@ -157,7 +157,8 @@ d3QtY3BwMQ8wDQYDVQQLDAZnaXRodWIxFDASBgNVBAMMC2V4YW1wbGUuY29tMCow BQYDK2VwAyEAUdLe1SUWxc/95f39pfmuwe1SLHpFXf5gcRQlMH2sjgwwBQYDK2Vw A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs 3GyYtaZs6AEHwDXl/INXu2zoCQ== ------END CERTIFICATE-----)"; +-----END CERTIFICATE----- +)"; // openssl x509 -outform der -in ed25519_certificate.pem -out ed25519_certificate.der // openssl base64 -in ed25519_certificate.der -out ed25519_certificate.b64 std::string ed25519_certificate_base64_der = "MIIBjzCCAUECFCQlWQxMEMe4c3OOimH4/y+o/HpfMAUGAytlcDBqMQswCQYDVQQG" From e69772d87fa2939c23d77d4a5a7e9b32d1432fe1 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 19:15:20 -0500 Subject: [PATCH 14/18] update exception for libressl 3.5.3 https://github.com/Thalhammer/jwt-cpp/actions/runs/7161143039/job/19496334109?pr=318#step:8:248 ``` [ RUN ] OpenSSLErrorTest.ECDSACertificate /home/runner/work/jwt-cpp/jwt-cpp/tests/OpenSSLErrorTest.cpp:487: Failure Expected equality of these values: ec Which is: ecdsa_error:19 e.expected_ec Which is: rsa_error:12 ``` --- tests/OpenSSLErrorTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 7fad2d2d..7b1b04a4 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -786,7 +786,7 @@ TEST(OpenSSLErrorTest, ECDSACertificate) { #if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x3050300fL {&fail_BIO_write, 1, jwt::error::ecdsa_error::load_key_bio_write}, #else - {&fail_BIO_write, 1, jwt::error::rsa_error::write_key_failed}, + {&fail_BIO_write, 1, jwt::error::ecdsa_error::write_key_failed}, #endif {&fail_PEM_read_bio_PUBKEY, 1, jwt::error::ecdsa_error::load_key_bio_read}, // extract_pubkey_from_cert From 2f0096a3e5818ba8275a0fc4b605bae47349fc6c Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 19:16:09 -0500 Subject: [PATCH 15/18] linter --- tests/Keys.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Keys.cpp b/tests/Keys.cpp index dbff2744..a5d81f62 100644 --- a/tests/Keys.cpp +++ b/tests/Keys.cpp @@ -162,14 +162,14 @@ A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs // openssl x509 -outform der -in ed25519_certificate.pem -out ed25519_certificate.der // openssl base64 -in ed25519_certificate.der -out ed25519_certificate.b64 std::string ed25519_certificate_base64_der = "MIIBjzCCAUECFCQlWQxMEMe4c3OOimH4/y+o/HpfMAUGAytlcDBqMQswCQYDVQQG" - "EwJDQTEPMA0GA1UECAwGUXVlYmVjMREwDwYDVQQHDAhNb250cmVhbDEQMA4GA1UE" - "CgwHand0LWNwcDEPMA0GA1UECwwGZ2l0aHViMRQwEgYDVQQDDAtleGFtcGxlLmNv" - "bTAeFw0yMDA3MzAyMTIwMDBaFw0yMjA2MzAyMTIwMDBaMGoxCzAJBgNVBAYTAkNB" - "MQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMRAwDgYDVQQKDAdq" - "d3QtY3BwMQ8wDQYDVQQLDAZnaXRodWIxFDASBgNVBAMMC2V4YW1wbGUuY29tMCow" - "BQYDK2VwAyEAUdLe1SUWxc/95f39pfmuwe1SLHpFXf5gcRQlMH2sjgwwBQYDK2Vw" - "A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs" - "3GyYtaZs6AEHwDXl/INXu2zoCQ=="; + "EwJDQTEPMA0GA1UECAwGUXVlYmVjMREwDwYDVQQHDAhNb250cmVhbDEQMA4GA1UE" + "CgwHand0LWNwcDEPMA0GA1UECwwGZ2l0aHViMRQwEgYDVQQDDAtleGFtcGxlLmNv" + "bTAeFw0yMDA3MzAyMTIwMDBaFw0yMjA2MzAyMTIwMDBaMGoxCzAJBgNVBAYTAkNB" + "MQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMRAwDgYDVQQKDAdq" + "d3QtY3BwMQ8wDQYDVQQLDAZnaXRodWIxFDASBgNVBAMMC2V4YW1wbGUuY29tMCow" + "BQYDK2VwAyEAUdLe1SUWxc/95f39pfmuwe1SLHpFXf5gcRQlMH2sjgwwBQYDK2Vw" + "A0EAezYcLIUnyy86uUnAZdAMPn7wTruNKtG36GrTF3PF4dtdoGF1OV5DLnNK0Hbs" + "3GyYtaZs6AEHwDXl/INXu2zoCQ=="; std::string ed448_priv_key = R"(-----BEGIN PRIVATE KEY----- MEcCAQAwBQYDK2VxBDsEOZNyV4kIWehIWSsPCnDEZbBF+g2WoUgUwox8eQJTq8Hz y4okU+JZAV8RqQ270fJL/Safvvc1SbbF1A== From 4d62638449e9ae99b7308cdc5bbf0572ed0c3d8e Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 20:06:29 -0500 Subject: [PATCH 16/18] add missing test --- tests/OpenSSLErrorTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 7b1b04a4..5eb7510b 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -937,6 +937,8 @@ TEST(OpenSSLErrorTest, EdDSACertificate) { } TEST(OpenSSLErrorTest, Ed25519Reference) { + ASSERT_THROW(jwt::algorithm::ed25519 alg{"", ""}, jwt::error:ecdsa_exception); + jwt::algorithm::ed25519 alg{ed25519_pub_key, ed25519_priv_key}; std::error_code ec; auto res = alg.sign("testdata", ec); From 827c5fb209652a58b092560c3e2b2a979aac68a8 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 20:11:13 -0500 Subject: [PATCH 17/18] fix copy paste --- tests/OpenSSLErrorTest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 5eb7510b..c3d93a27 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -937,7 +937,8 @@ TEST(OpenSSLErrorTest, EdDSACertificate) { } TEST(OpenSSLErrorTest, Ed25519Reference) { - ASSERT_THROW(jwt::algorithm::ed25519 alg{"", ""}, jwt::error:ecdsa_exception); + // No keys should throw + ASSERT_THROW(jwt::algorithm::ed25519("", ""), jwt::error:ecdsa_exception); jwt::algorithm::ed25519 alg{ed25519_pub_key, ed25519_priv_key}; std::error_code ec; From a15b268d707665b4f24ea85ffe738cccb6afea00 Mon Sep 17 00:00:00 2001 From: Christopher McArthur Date: Sun, 10 Dec 2023 20:13:07 -0500 Subject: [PATCH 18/18] typo part 2 --- tests/OpenSSLErrorTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index c3d93a27..00966dad 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -938,7 +938,7 @@ TEST(OpenSSLErrorTest, EdDSACertificate) { TEST(OpenSSLErrorTest, Ed25519Reference) { // No keys should throw - ASSERT_THROW(jwt::algorithm::ed25519("", ""), jwt::error:ecdsa_exception); + ASSERT_THROW(jwt::algorithm::ed25519("", ""), jwt::error::ecdsa_exception); jwt::algorithm::ed25519 alg{ed25519_pub_key, ed25519_priv_key}; std::error_code ec;