Skip to content

Instantly share code, notes, and snippets.

@avafinger
Last active December 27, 2021 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avafinger/d2e2007d3ed87c452fa0c0b184dd11fa to your computer and use it in GitHub Desktop.
Save avafinger/d2e2007d3ed87c452fa0c0b184dd11fa to your computer and use it in GitHub Desktop.
libpodofo memory leak (some cleanup - UPDATED)
//
//
// =====================================================================
// g++ sign.cpp -o sign -I/usr/include/openssl -lssl -lpodofo -lcrypto
// =====================================================================
//
// OpenSSL includes
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <podofo/podofo.h>
#include <iostream>
using namespace PoDoFo;
class Ossl {
private:
SHA_CTX m_sha_ctx;
EVP_PKEY* mp_pkey; // private key
X509* mp_x509; // signing certificate
STACK_OF(X509)* mp_ca; // certificate chain up to the CA
unsigned char * mp_p7Buf;
public:
Ossl(){}
~Ossl(){}
void init(const char * file, const char * passwd) {
OPENSSL_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
FILE* fp = fopen(file, "rb");
if (fp == NULL) {
std::cout << "fp null" << std::endl;
return;
}
PKCS12* p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (p12 == NULL) {
std::cout << "p12 null" << std::endl;
return;
}
mp_pkey = NULL;
mp_x509 = NULL;
mp_ca = NULL;
int ok = PKCS12_parse(p12, passwd, &mp_pkey, &mp_x509, &mp_ca);
if (ok == 0) {
std::cout << "not ok" << std::endl;
return;
}
PKCS12_free(p12);
SHA1_Init(&m_sha_ctx);
std::cout << "init ok" << std::endl;
}
void close() {
if (mp_ca)
sk_X509_pop_free(mp_ca, X509_free);
if (mp_x509) {
X509_free(mp_x509);
}
if (mp_pkey) {
EVP_PKEY_free(mp_pkey);
}
if (mp_p7Buf) {
free(mp_p7Buf);
}
ERR_free_strings();
}
void append(const char* data, int len) {
SHA1_Update(&m_sha_ctx, data, len);
return;
}
char * signature() {
unsigned char sha_buffer[SHA_DIGEST_LENGTH];
memset((void*) sha_buffer, 0, SHA_DIGEST_LENGTH);
SHA1_Final(sha_buffer, &m_sha_ctx);
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_SIGNER_INFO* p7Si = PKCS7_add_signature(p7, mp_x509, mp_pkey, EVP_sha1());
PKCS7_add_attrib_content_type(p7Si, OBJ_nid2obj(NID_pkcs7_data));
PKCS7_add0_attrib_signing_time(p7Si, NULL);
PKCS7_add1_attrib_digest(p7Si, (const unsigned char*) sha_buffer, SHA_DIGEST_LENGTH);
PKCS7_add_certificate(p7, mp_x509);
int c = 0;
for ( ; c < sk_X509_num(mp_ca); c++) {
X509* cert = sk_X509_value(mp_ca, c);
PKCS7_add_certificate(p7, cert);
}
PKCS7_set_detached(p7, 1);
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_SIGNER_INFO_sign(p7Si);
mp_p7Buf = NULL;
int p7Len = i2d_PKCS7(p7, NULL);
unsigned char* p7Buf = (unsigned char*) calloc(1, p7Len + 1);
if (p7Buf != NULL) {
mp_p7Buf = p7Buf;
i2d_PKCS7(p7, &p7Buf);
std::cout << "p7Buf filled";
}
PKCS7_free(p7);
return (char *) p7Buf;
}
};
using namespace PoDoFo;
#define CONVERSION_CONSTANT 0.002834645669291339
void CreateSimpleForm( PdfPage* pPage, PdfStreamedDocument* pDoc, const PdfData &signatureData )
{
PdfPainter painter;
PdfFont* pFont = pDoc->CreateFont( "Courier" );
painter.SetPage( pPage );
painter.SetFont( pFont );
painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" );
painter.FinishPage();
PdfSignatureField signField( pPage, PdfRect( 70000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT,
50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc );
signField.SetFieldName("SignatureFieldName");
signField.SetSignature(signatureData);
signField.SetSignatureReason("I agree");
}
int main( int argc, char* argv[] )
{
PdfPage* pPage;
if( argc != 4 )
{
printf("Usage: sign [output_filename] [pfx certificate] [password]\n");
printf(" - Create a PDF ready to be signed\n");
return 0;
}
PdfSignOutputDevice signer(argv[1]);
// Reserve space for signature
signer.SetSignatureSize(1024);
PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 );
// Disable default appearance
writer.GetAcroForm(ePdfCreateObject, ePdfAcroFormDefaultAppearance_None);
pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) );
CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon());
writer.Close();
// Adjust ByteRange for signature
if(signer.HasSignaturePosition()) {
signer.AdjustByteRange();
// read data for signature and count it
signer.Seek(0);
Ossl * ossl = new Ossl();
ossl->init(argv[2], argv[3]);
// generate digest and count signature
// use NSS, MS Crypto API or OpenSSL
// to generate signature in DER format
char buff[65536];
size_t len;
while( (len = signer.ReadForSignature(buff, 65536))>0 )
{
ossl->append(buff, len);
}
// Paste signature to the file
PdfData sigData(ossl->signature());
signer.SetSignature(sigData);
ossl->close();
delete ossl;
}
signer.Flush();
return 0;
}
@avafinger
Copy link
Author

Add ossl->close();

==9319== 65,536 bytes in 1 blocks are still reachable in loss record 6 of 6
==9319==    at 0x4C33B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9319==    by 0x27AE19: PoDoFo::podofo_calloc(unsigned long, unsigned long) (PdfMemoryManagement.cpp:136)
==9319==    by 0x272392: PoDoFo::PdfSimpleEncoding::InitEncodingTable() (PdfEncoding.cpp:385)
==9319==    by 0x2729B0: PoDoFo::PdfSimpleEncoding::ConvertToEncoding(PoDoFo::PdfString const&, PoDoFo::PdfFont const*) const (PdfEncoding.cpp:474)
==9319==    by 0x2A9B76: PoDoFo::PdfFont::WriteStringToStream(PoDoFo::PdfString const&, PoDoFo::PdfStream*) (PdfFont.cpp:144)
==9319==    by 0x253EF0: PoDoFo::PdfPainter::DrawText(double, double, PoDoFo::PdfString const&, long) (PdfPainter.cpp:828)
==9319==    by 0x253512: PoDoFo::PdfPainter::DrawText(double, double, PoDoFo::PdfString const&) (PdfPainter.cpp:744)
==9319==    by 0x1F63DD: CreateSimpleForm(PoDoFo::PdfPage*, PoDoFo::PdfStreamedDocument*, PoDoFo::PdfData const&) (sign.cpp:139)
==9319==    by 0x1F66DD: main (sign.cpp:170)
==9319== 
==9319== LEAK SUMMARY:
==9319==    definitely lost: 7,549 bytes in 1 blocks
==9319==    indirectly lost: 0 bytes in 0 blocks
==9319==      possibly lost: 0 bytes in 0 blocks
==9319==    still reachable: 65,904 bytes in 5 blocks
==9319==         suppressed: 0 bytes in 0 blocks
==9319== 
==9319== For counts of detected and suppressed errors, rerun with: -v
==9319== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment