podofo / podofo

A C++17 PDF manipulation library

Home Page:https://podofo.github.io/podofo/documentation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PdfErrorCode::OutOfMemory, PoDoFo is out of memory. in Signer.ComputeSignatureSequential({ }, Buff, true);

omerbrandis opened this issue · comments

Hi,

I'm trying to create a new pdf and sign it.
I'm using the latest version of Podofo, downloaded today on 17.3.2024.
I have manged to follow the "hello world" documentation to create a new doc.

I am trying to follow example 4 ("TestPdfSignerCms") in provided in tests

PoDoFo::charbuff Buff;
std::string cert;
std::cout << "before read cert"<< std::endl;
readTestInputFile("/home/omerbrandis/openssl_test/march2024/myCA.pem", cert);
PoDoFo::PdfSignerCms Signer(cert);
Signer.ComputeSignatureSequential({ }, Buff, true);

  • please provide more documentation on this example.
    what is the difference between ComputeSignatureSequential and ComputeSignature
    why must both be used?
    why are there multiple executions of each of them.

:-)

tried example 3 (TestPdfSignerCms)

ctx.StartSigning(document, stream, results, PoDoFo::PdfSaveOptions::NoMetadataUpdate); also fails with PdfErrorCode::OutOfMemory

my code :
std::string cert,pkey;
readTestInputFile("...myCA.pem", cert);
readTestInputFile("....private.pem", pkey);

PoDoFo::PdfSignerCmsParams params;
auto signer = std::make_sharedPoDoFo::PdfSignerCms(cert, params);

PoDoFo::PdfSigningContext ctx;
auto signerId = ctx.AddSigner(signature, signer);
PoDoFo::PdfSigningResults results;
auto stream = std::make_sharedPoDoFo::FileStreamDevice("signedPdf.pdf", PoDoFo::FileMode::Create);
ctx.StartSigning(document, stream, results, PoDoFo::PdfSaveOptions::NoMetadataUpdate);
PoDoFo::charbuff signedHash;
ssl::DoSign(results.Intermediate[signerId], pkey, params.Hashing, signedHash);
results.Intermediate[signerId] = signedHash;
ctx.FinishSigning(results);

I guess its the same problem....?

what is the difference between ComputeSignatureSequential and ComputeSignature

That's the low level API, you shouldn't deal with it unless you know what you are doing, but I believe PdfSignerCms really covers everything that's meaningful in PDF signing. Another question may be what's the difference between an event-driven (aka "blocking") and a sequential (aka "async") signing procedure: the former is a blocking procedure, can be issued with PdfSigningContext::Sign() or PoDoFo::SignDocument(), and requires the PdfSigner to immediately supply a signed digest when requested. The latter (the sequential signing) splits the signing procedure in 2 steps: the first collects the hash to be signed, the second supplies the signed digests to the context and finish the signing. It can be issued with PdfSigningContext::StartSigning().

Both event-driven and sequential signing can cover the external signing service use case, but there's something you should consider: if you have a private key at hand, you don't need a sequential/async procedure. Just use PoDoFo::SignDocument(), or create a context and do a blocking signature with PdfSigningContext::Sign().

ctx.StartSigning(document, stream, results, PoDoFo::PdfSaveOptions::NoMetadataUpdate); also fails with PdfErrorCode::OutOfMemory

The error for loading invalid certificate/private key was very bad, I just improved it (pull git). Basically: you can't load PEM, everything should be DER. I leave to you the exercise of converting your certificate and key from PEM to DER (suggestion: use openssl). I believe that's the only issue preventing you from signing the document.

Dear Fransecso,

thank you for your time.

  1. after converting to der, and using the latest version I was able to sign the document.
    ( i currently use code that is similar to the information provided in the faq ).

  2. but when I opened the document in adobe reader, it showed that the signing time is not available.
    I tried to use signature.signature.SetSignatureDate(PdfDate()); ( as in tools/podofosign ) but that method does not exist.

  3. can you please explain how to add an image to the signature?

  4. can you please provide more information about the second parameter to PoDoFo::SignDocument?
    what is its purpose?
    if/how can i do this in memory?
    ( is
    std::string Buffer;
    auto stream = std::make_sharedPoDoFo::SpanStreamDevice(Buffer);
    ok ? )

  5. while trying to use the der files,
    I encountered the following errror ( think it was issued by ssl::do_sign ):
    terminate called after throwing an instance of 'PoDoFo::PdfError'
    what(): PdfErrorCode::OpenSSL, OpenSSL error
    Callstack:t#0 Error Source: private/OpenSSLInternal.cpp(121), Information: 140420407334720:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149:
    140420407334720:error:0D06C03A:asn1 encoding routines:asn1_d2i_ex_primitive:nested asn1 error:crypto/asn1/tasn_dec.c:713:
    140420407334720:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=version, Type=RSAPrivateKey
    140420407334720:error:04093004:rsa routines:old_rsa_priv_decode:RSA lib:crypto/rsa/rsa_ameth.c:145:
    140420407334720:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149:
    140420407334720:error:0D06C03A:asn1 encoding routines:asn1_d2i_ex_primitive:nested asn1 error:crypto/asn1/tasn_dec.c:713:
    140420407334720:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=version, Type=PKCS8_PRIV_KEY_INFO

I was able to figure out that this is caused by an invalid der file, I found it to be my private key...
my point is , you should add more descriptive information , there are 2 files involved ... you should at least specifiy which of the two.

  1. but when I opened the document in adobe reader, it showed that the signing time is not available.
    I tried to use signature.signature.SetSignatureDate(PdfDate()); ( as in tools/podofosign ) but that method does not exist.
  2. can you please explain how to add an image to the signature?

I do both on the new example, which also features a new PdfSaveOptions::SaveOnSigning option. Don't use it unless you want to recreate the document from scratch upon signing, which would invalidate previous signatures if existing.

  1. can you please provide more information about the second parameter to PoDoFo::SignDocument?

The stream where the signing operation will be performed must be explicit. It's a simpler API that may be harder to use but it's better than not knowing/not being hinted about what happens under the hood. If you want to sign on a memory stream look at the FAQ and the tests that use BufferStreamDevice.

  1. while trying to use the der files ... you should at least specifiy which of the two.

You are right. I improved the error.

I believe I can close the issue now since I fixed the wrong error message, answered to all your questions and improved the UX of the API, adding more documentation/tests as well.

Dear Fransecso,

thank you again for your time & patience.

with the new information, I was able to add an image, and avoid using the FileStreamDevice.

please note that :
when I set a non-existent file to image->Load, I got a Segmentation fault (core dumped), no explicit exception was thrown, no error msg, the Load method returns void.

moreover,
can you please explain what the SpanStreamDevice is and how it is different from the ContainerStreamDevice?

:-)

when I set a non-existent file to image->Load, I got a Segmentation fault (core dumped), no explicit exception was thrown

Should be fixed now (3e8f47b).

can you please explain what the SpanStreamDevice is and how it is different from the ContainerStreamDevice?

Both are stream/device wrappers around something. You can say the difference looking at what they take as an input: SpanStreamDevice is built around a span and can't grow, ContainerStreamDevice is built around a resizable container, which it makes a big difference when you have to persist the PDF document.