Skip to content

Commit

Permalink
Fix memory leaks and add helper memory.h util
Browse files Browse the repository at this point in the history
Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma committed Feb 17, 2025
1 parent 4a5b1ad commit d80c65d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 43 deletions.
2 changes: 0 additions & 2 deletions cdoc/CDoc1Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ static const std::string MIME_ZLIB = "http://www.isi.edu/in-noes/iana/assignment
static const std::string MIME_DDOC = "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd";
static const std::string MIME_DDOC_OLD = "http://www.sk.ee/DigiDoc/1.3.0/digidoc.xsd";

#define SCOPE(TYPE, VAR, DATA) std::unique_ptr<TYPE,decltype(&TYPE##_free)> VAR(DATA, TYPE##_free)

static const std::set<std::string> SUPPORTED_METHODS = {
libcdoc::Crypto::AES128CBC_MTH, libcdoc::Crypto::AES192CBC_MTH, libcdoc::Crypto::AES256CBC_MTH, libcdoc::Crypto::AES128GCM_MTH, libcdoc::Crypto::AES192GCM_MTH, libcdoc::Crypto::AES256GCM_MTH
};
Expand Down
22 changes: 10 additions & 12 deletions cdoc/CDoc1Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "XmlWriter.h"
#include "CDoc1Writer.h"
#include "ILogger.h"
#include "utils/memory.h"

#if defined(_WIN32) || defined(_WIN64)
#include <IntSafe.h>
Expand All @@ -32,9 +33,6 @@

#include <openssl/x509.h>


#define SCOPE(TYPE, VAR, DATA) std::unique_ptr<TYPE,decltype(&TYPE##_free)> VAR(DATA, TYPE##_free)

using namespace libcdoc;

struct FileEntry {
Expand Down Expand Up @@ -79,7 +77,7 @@ CDoc1Writer::~CDoc1Writer()

bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uint8_t> &recipient, const libcdoc::Crypto::Key& transportKey)
{
SCOPE(X509, peerCert, libcdoc::Crypto::toX509(recipient));
auto peerCert = make_unique_ptr<X509_free>(libcdoc::Crypto::toX509(recipient));
if(!peerCert)
return false;
std::string cn = [&]{
Expand All @@ -102,12 +100,12 @@ bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uin
}();
xmlw->writeElement(Private::DENC, "EncryptedKey", {{"Recipient", cn}}, [&]{
std::vector<uint8_t> encryptedData;
SCOPE(EVP_PKEY, peerPKey, X509_get_pubkey(peerCert.get()));
switch(EVP_PKEY_base_id(peerPKey.get()))
auto *peerPKey = X509_get0_pubkey(peerCert.get());
switch(EVP_PKEY_base_id(peerPKey))
{
case EVP_PKEY_RSA:
{
SCOPE(RSA, rsa, EVP_PKEY_get1_RSA(peerPKey.get()));
auto rsa = make_unique_ptr<RSA_free>(EVP_PKEY_get1_RSA(peerPKey));
encryptedData.resize(size_t(RSA_size(rsa.get())));
RSA_public_encrypt(int(transportKey.key.size()), transportKey.key.data(),
encryptedData.data(), rsa.get(), RSA_PKCS1_PADDING);
Expand All @@ -121,13 +119,13 @@ bool CDoc1Writer::Private::writeRecipient(XMLWriter *xmlw, const std::vector<uin
}
case EVP_PKEY_EC:
{
SCOPE(EC_KEY, peerECKey, EVP_PKEY_get1_EC_KEY(peerPKey.get()));
int curveName = EC_GROUP_get_curve_name(EC_KEY_get0_group(peerECKey.get()));
SCOPE(EC_KEY, priv, EC_KEY_new_by_curve_name(curveName));
auto *peerECKey = EVP_PKEY_get0_EC_KEY(peerPKey);
int curveName = EC_GROUP_get_curve_name(EC_KEY_get0_group(peerECKey));
auto priv = make_unique_ptr<EC_KEY_free>(EC_KEY_new_by_curve_name(curveName));
EC_KEY_generate_key(priv.get());
SCOPE(EVP_PKEY, pkey, EVP_PKEY_new());
auto pkey = make_unique_ptr<EVP_PKEY_free>(EVP_PKEY_new());
EVP_PKEY_set1_EC_KEY(pkey.get(), priv.get());
std::vector<uint8_t> sharedSecret = libcdoc::Crypto::deriveSharedSecret(pkey.get(), peerPKey.get());
std::vector<uint8_t> sharedSecret = libcdoc::Crypto::deriveSharedSecret(pkey.get(), peerPKey);

std::string oid(50, 0);
oid.resize(size_t(OBJ_obj2txt(&oid[0], int(oid.size()), OBJ_nid2obj(curveName), 1)));
Expand Down
2 changes: 1 addition & 1 deletion cdoc/CDoc2Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ CDoc2Reader::beginDecryption(const std::vector<uint8_t>& fmk)

priv->tgs = std::make_unique<TaggedSource>(priv->_src, false, 16);
libcdoc::CipherSource *csrc = new libcdoc::CipherSource(priv->tgs.get(), false, priv->cipher.get());
priv->zsrc = std::make_unique<libcdoc::ZSource>(csrc, false);
priv->zsrc = std::make_unique<libcdoc::ZSource>(csrc, true);
priv->tar = std::make_unique<libcdoc::TarSource>(priv->zsrc.get(), false);

return libcdoc::OK;
Expand Down
9 changes: 4 additions & 5 deletions cdoc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ add_library(cdoc
ToolConf.h
CDoc2.h
Wrapper.h
utils/memory.h
)
set_target_properties(cdoc PROPERTIES
VERSION ${PROJECT_VERSION}
Expand All @@ -82,7 +83,7 @@ target_link_libraries(cdoc PRIVATE
OpenSSL::SSL
LibXml2::LibXml2
ZLIB::ZLIB
#cdoc_ver
$<$<BOOL:BUILD_SHARED_LIBS>:cdoc_ver>
$<TARGET_NAME_IF_EXISTS:flatbuffers::flatbuffers>
#$<TARGET_NAME_IF_EXISTS:flatbuffers::flatbuffers_shared>
)
Expand All @@ -94,6 +95,8 @@ if(BUILD_TOOLS)
set_target_properties(cdoc-tool PROPERTIES
INSTALL_RPATH $<$<PLATFORM_ID:Darwin>:@executable_path/../lib>
)
install(TARGETS cdoc-tool DESTINATION ${CMAKE_INSTALL_BINDIR})
#install( FILES ${CMAKE_CURRENT_BINARY_DIR}/cdoc-tool.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
endif()

if(WIN32)
Expand Down Expand Up @@ -230,8 +233,4 @@ if(NOT ANDROID)
)
endif()

if(BUILD_TOOLS)
install(TARGETS cdoc-tool DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
#install( FILES ${CMAKE_CURRENT_BINARY_DIR}/cdoc-tool.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
#install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libcdoc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig )
41 changes: 20 additions & 21 deletions cdoc/Crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@

#include <cstring>

#define SCOPE(TYPE, VAR, DATA) std::unique_ptr<TYPE,decltype(&TYPE##_free)> VAR(DATA, TYPE##_free)

using namespace libcdoc;

const std::string Crypto::SHA256_MTH = "http://www.w3.org/2001/04/xmlenc#sha256";
Expand Down Expand Up @@ -218,7 +216,7 @@ std::vector<uint8_t> Crypto::concatKDF(const std::string &hashAlg, uint32_t keyD
std::vector<uint8_t> Crypto::encrypt(const std::string &method, const Key &key, const std::vector<uint8_t> &data)
{
const EVP_CIPHER *c = cipher(method);
SCOPE(EVP_CIPHER_CTX, ctx, EVP_CIPHER_CTX_new());
auto ctx = make_unique_ptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
if (SSL_FAILED(EVP_CipherInit(ctx.get(), c, key.key.data(), key.iv.data(), 1), "EVP_CipherInit"))
return {};

Expand Down Expand Up @@ -249,7 +247,7 @@ std::vector<uint8_t> Crypto::encrypt(const std::string &method, const Key &key,
std::vector<uint8_t>
Crypto::encrypt(EVP_PKEY *pub, int padding, const std::vector<uint8_t> &data)
{
SCOPE(EVP_PKEY_CTX, ctx, EVP_PKEY_CTX_new(pub, nullptr));
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new(pub, nullptr));
size_t size = 0;
if (SSL_FAILED(EVP_PKEY_encrypt_init(ctx.get()), "EVP_PKEY_encrypt_init") ||
SSL_FAILED(EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding), "EVP_PKEY_CTX_set_rsa_padding") ||
Expand Down Expand Up @@ -277,7 +275,7 @@ std::vector<uint8_t> Crypto::decrypt(const std::string &method, const std::vecto
LOG_DBG("iv {}", toHex(iv));
LOG_DBG("transport {}", toHex(key));

SCOPE(EVP_CIPHER_CTX, ctx, EVP_CIPHER_CTX_new());
auto ctx = make_unique_ptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
if (!ctx)
{
LOG_SSL_ERROR("EVP_CIPHER_CTX_new");
Expand Down Expand Up @@ -322,7 +320,7 @@ std::vector<uint8_t> Crypto::decodeBase64(const uint8_t *data)
return result;
}
result.resize(strlen((const char*)data));
SCOPE(EVP_ENCODE_CTX, ctx, EVP_ENCODE_CTX_new());
auto ctx = make_unique_ptr<EVP_ENCODE_CTX_free>(EVP_ENCODE_CTX_new());
if (!ctx)
{
LOG_SSL_ERROR("EVP_ENCODE_CTX_new");
Expand Down Expand Up @@ -350,7 +348,7 @@ std::vector<uint8_t> Crypto::deriveSharedSecret(EVP_PKEY *pkey, EVP_PKEY *peerPK
{
std::vector<uint8_t> sharedSecret;
size_t sharedSecretLen = 0;
SCOPE(EVP_PKEY_CTX, ctx, EVP_PKEY_CTX_new(pkey, nullptr));
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new(pkey, nullptr));
if (!ctx)
{
LOG_SSL_ERROR("EVP_PKEY_CTX_new");
Expand Down Expand Up @@ -396,7 +394,7 @@ uint32_t Crypto::keySize(const std::string &algo)
std::vector<uint8_t>
Crypto::hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, const std::vector<uint8_t> &info, int len, int mode)
{
SCOPE(EVP_PKEY_CTX, ctx, EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
if (!ctx)
{
LOG_SSL_ERROR("EVP_PKEY_CTX_new_id");
Expand Down Expand Up @@ -432,26 +430,28 @@ Crypto::extract(const std::vector<uint8_t> &key, const std::vector<uint8_t> &sal
std::vector<uint8_t>
Crypto::sign_hmac(const std::vector<uint8_t> &key, const std::vector<uint8_t> &data)
{
EVP_PKEY *pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), int(key.size()));
std::vector<uint8_t> sig;
auto pkey = make_unique_ptr<EVP_PKEY_free>(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), int(key.size())));
if (!pkey)
{
LOG_SSL_ERROR("EVP_PKEY_new_mac_key");
return {};
return sig;
}

size_t req = 0;
SCOPE(EVP_MD_CTX, ctx, EVP_MD_CTX_new());
auto ctx = make_unique_ptr<EVP_MD_CTX_free>(EVP_MD_CTX_new());
if (!ctx)
{
LOG_SSL_ERROR("EVP_MD_CTX_new");
return {};
return sig;
}
if (SSL_FAILED(EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey), "EVP_DigestSignInit") ||

size_t req = 0;
if (SSL_FAILED(EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey.get()), "EVP_DigestSignInit") ||
SSL_FAILED(EVP_DigestSignUpdate(ctx.get(), data.data(), data.size()), "EVP_DigestSignUpdate") ||
SSL_FAILED(EVP_DigestSignFinal(ctx.get(), nullptr, &req), "EVP_DigestSignFinal"))
return {};
return sig;

std::vector<uint8_t> sig(int(req), 0);
sig.resize(req);
if(SSL_FAILED(EVP_DigestSignFinal(ctx.get(), sig.data(), &req), "EVP_DigestSignFinal"))
sig.clear();
return sig;
Expand Down Expand Up @@ -482,7 +482,7 @@ Crypto::EVP_PKEY_ptr
Crypto::fromECPublicKeyDer(const std::vector<uint8_t> &der, int curveName)
{
EVP_PKEY *params = nullptr;
SCOPE(EVP_PKEY_CTX, ctx, EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
if (!ctx)
LOG_SSL_ERROR("EVP_PKEY_CTX_new_id");

Expand Down Expand Up @@ -516,13 +516,12 @@ Crypto::EVP_PKEY_ptr
Crypto::genECKey(EVP_PKEY *params)
{
EVP_PKEY *key = nullptr;
SCOPE(EVP_PKEY_CTX, ctx, EVP_PKEY_CTX_new(params, nullptr));
SCOPE(EVP_PKEY, result, nullptr);
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new(params, nullptr));
if(ctx &&
!SSL_FAILED(EVP_PKEY_keygen_init(ctx.get()), "EVP_PKEY_keygen_init") &&
!SSL_FAILED(EVP_PKEY_keygen(ctx.get(), &key), "EVP_PKEY_keygen"))
result.reset(key);
return result;
{}
return EVP_PKEY_ptr(key, EVP_PKEY_free);
}

std::vector<uint8_t>
Expand Down
5 changes: 3 additions & 2 deletions cdoc/Crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

#pragma once

#include <memory>
#include "utils/memory.h"

#include <string>
#include <vector>

Expand All @@ -36,7 +37,7 @@ namespace libcdoc {
class Crypto
{
public:
typedef typename std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> EVP_PKEY_ptr;
using EVP_PKEY_ptr = unique_free_t<EVP_PKEY>;

struct Cipher {
struct evp_cipher_ctx_st *ctx;
Expand Down
75 changes: 75 additions & 0 deletions cdoc/utils/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* libcdoc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include <memory>

namespace libcdoc {

template<auto D>
struct free_deleter
{
template<class T>
void operator()(T *p) const noexcept
{
D(p);
}
};

template<typename> struct free_argument;
template<class T, class R>
struct free_argument<R (*)(T *)>
{
using type = T;
};

template <class T>
using unique_free_t = std::unique_ptr<T, void(*)(T*)>;

template<class T, typename D>
[[nodiscard]]
constexpr std::unique_ptr<T, D> make_unique_ptr(T *p, D d) noexcept
{
return {p, std::forward<D>(d)};
}

template<auto D, class T>
[[nodiscard]]
constexpr auto make_unique_ptr(T *p) noexcept
{
return std::unique_ptr<T, free_deleter<D>>(p);
}

template<auto D>
[[nodiscard]]
constexpr auto make_unique_ptr(nullptr_t) noexcept
{
using T = typename free_argument<decltype(D)>::type;
return std::unique_ptr<T, free_deleter<D>>(nullptr);
}

template<auto D, class P>
[[nodiscard]]
constexpr auto make_unique_cast(P *p) noexcept
{
using T = typename free_argument<decltype(D)>::type;
return make_unique_ptr<D>(static_cast<T*>(p));
}

}

0 comments on commit d80c65d

Please sign in to comment.