* \brief Base class for EdDSA family of algorithms * * https://tools.ietf.org/html/rfc8032 * * The EdDSA algorithms were introduced in [OpenSSL v1.1.1](https://www.openssl.org/news/openssl-1.1.1-notes.html), * so these algorithms are only available when building against this version or higher. */
| 1808 | * so these algorithms are only available when building against this version or higher. |
| 1809 | */ |
| 1810 | struct eddsa { |
| 1811 | /** |
| 1812 | * Construct new eddsa algorithm |
| 1813 | * \param public_key EdDSA public key in PEM format |
| 1814 | * \param private_key EdDSA private key or empty string if not available. If empty, signing will always |
| 1815 | * fail. |
| 1816 | * \param public_key_password Password to decrypt public key pem. |
| 1817 | * \param private_key_password Password |
| 1818 | * to decrypt private key pem. |
| 1819 | * \param name Name of the algorithm |
| 1820 | */ |
| 1821 | eddsa(const std::string& public_key, const std::string& private_key, const std::string& public_key_password, |
| 1822 | const std::string& private_key_password, std::string name) |
| 1823 | : alg_name(std::move(name)) { |
| 1824 | if (!private_key.empty()) { |
| 1825 | pkey = helper::load_private_key_from_string(private_key, private_key_password); |
| 1826 | } else if (!public_key.empty()) { |
| 1827 | pkey = helper::load_public_key_from_string(public_key, public_key_password); |
| 1828 | } else |
| 1829 | throw error::ecdsa_exception(error::ecdsa_error::load_key_bio_read); |
| 1830 | } |
| 1831 | /** |
| 1832 | * Sign jwt data |
| 1833 | * \param data The data to sign |
| 1834 | * \param ec error_code filled with details on error |
| 1835 | * \return EdDSA signature for the given data |
| 1836 | */ |
| 1837 | std::string sign(const std::string& data, std::error_code& ec) const { |
| 1838 | ec.clear(); |
| 1839 | auto ctx = helper::make_evp_md_ctx(); |
| 1840 | if (!ctx) { |
| 1841 | ec = error::signature_generation_error::create_context_failed; |
| 1842 | return {}; |
| 1843 | } |
| 1844 | if (!EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, pkey.get())) { |
| 1845 | ec = error::signature_generation_error::signinit_failed; |
| 1846 | return {}; |
| 1847 | } |
| 1848 | |
| 1849 | size_t len = EVP_PKEY_size(pkey.get()); |
| 1850 | std::string res(len, '\0'); |
| 1851 | |
| 1852 | // LibreSSL is the special kid in the block, as it does not support EVP_DigestSign. |
| 1853 | // OpenSSL on the otherhand does not support using EVP_DigestSignUpdate for eddsa, which is why we end up with this |
| 1854 | // mess. |
| 1855 | #if defined(LIBRESSL_VERSION_NUMBER) || defined(LIBWOLFSSL_VERSION_HEX) |
| 1856 | ERR_clear_error(); |
| 1857 | if (EVP_DigestSignUpdate(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()), data.size()) != |
| 1858 | 1) { |
| 1859 | std::cout << ERR_error_string(ERR_get_error(), NULL) << '\n'; |
| 1860 | ec = error::signature_generation_error::signupdate_failed; |
| 1861 | return {}; |
| 1862 | } |
| 1863 | if (EVP_DigestSignFinal(ctx.get(), reinterpret_cast<unsigned char*>(&res[0]), &len) != 1) { |
| 1864 | ec = error::signature_generation_error::signfinal_failed; |
| 1865 | return {}; |
| 1866 | } |
| 1867 | #else |
nothing calls this directly
no outgoing calls
no test coverage detected