From 90270f0959d490d56db891809d83c91b3d4b9bf0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 18 Dec 2024 19:37:40 +0100 Subject: hashes, methods: Add OpenSSL backends Introduce an OpenSSL::Crypto backend for the hashes library and an OpenSSL::SSL backend for the TLS support in our https method. Many thanks to curl for showing the way with how to handle a CRL file. There are some memory leaks here with the TlsFd itself as well as the proxy support; and we should reorganize the code to generate the ssl object as late as possible. A peculiar aspect of OpenSSL is that SSL_has_pending() returns 1 even if SSL_read() will fail to read anything and return the equivalent of EAGAIN. We work around this here by also peeking ahead 1 byte. I was running a very high RTT connection from Germany to Australia for testing, and with the peeking it's using negligible amounts of CPU; before that, it was busy looping at 100%. Bad OpenSSL! --- apt-pkg/contrib/hashes.cc | 73 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'apt-pkg/contrib') diff --git a/apt-pkg/contrib/hashes.cc b/apt-pkg/contrib/hashes.cc index 033cd0845..664ad0ac7 100644 --- a/apt-pkg/contrib/hashes.cc +++ b/apt-pkg/contrib/hashes.cc @@ -30,7 +30,9 @@ #include #include -#ifdef HAVE_GNUTLS +#if defined(WITH_OPENSSL) +#include +#elif defined(HAVE_GNUTLS) #include #else #include @@ -329,7 +331,74 @@ class PrivateHashes unsigned long long FileSize{0}; private: -#ifdef HAVE_GNUTLS +#if defined(WITH_OPENSSL) + std::array contexts{}; + + public: + struct HashAlgo + { + size_t index; + const char *name; + const EVP_MD *(*evpLink)(void); + Hashes::SupportedHashes ourAlgo; + }; + + static constexpr std::array Algorithms{ + HashAlgo{0, "MD5Sum", EVP_md5, Hashes::MD5SUM}, + HashAlgo{1, "SHA1", EVP_sha1, Hashes::SHA1SUM}, + HashAlgo{2, "SHA256", EVP_sha256, Hashes::SHA256SUM}, + HashAlgo{3, "SHA512", EVP_sha512, Hashes::SHA512SUM}, + }; + + bool Write(unsigned char const *Data, size_t Size) + { + for (auto &context : contexts) + { + if (context) + EVP_DigestUpdate(context, Data, Size); + } + return true; + } + + std::string HexDigest(HashAlgo const &algo) + { + auto Size = EVP_MD_size(algo.evpLink()); + unsigned char Sum[Size]; + + // We need to work on a copy, as we update the hash after creating a digest... + auto tmpContext = EVP_MD_CTX_create(); + EVP_MD_CTX_copy(tmpContext, contexts[algo.index]); + EVP_DigestFinal_ex(tmpContext, Sum, nullptr); + EVP_MD_CTX_destroy(tmpContext); + + return ::HexDigest(std::basic_string_view(Sum, Size)); + } + + bool Enable(HashAlgo const &algo) + { + contexts[algo.index] = EVP_MD_CTX_new(); + if (contexts[algo.index] == nullptr) + return false; + if (EVP_DigestInit_ex(contexts[algo.index], algo.evpLink(), NULL)) + return true; + EVP_MD_CTX_destroy(contexts[algo.index]); + contexts[algo.index] = nullptr; + return false; + } + bool IsEnabled(HashAlgo const &algo) + { + return contexts[algo.index] != nullptr; + } + + explicit PrivateHashes() {} + ~PrivateHashes() + { + for (auto ctx : contexts) + if (ctx != nullptr) + EVP_MD_CTX_free(ctx); + } + +#elif defined(HAVE_GNUTLS) std::array, 4> digs{}; public: -- cgit v1.2.3-70-g09d2