1

i got the same problem( develop with podofo in c++). after Insert multiple(2 times)digital signatures,i found there are 3 info——dictionary in the pdf file:

how to add two digital signature without invalidating the previous one?

thanks!

i open file in notepad++,and i found the different

the first:  97 0 obj<</Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0) /Author(edison qian) /Keywords(GISerClub) /Creator(? M i c r o s o f t ?  W o r d   2 0 1 3) 
            /CreationDate(D:20150601200942+08'00') /ModDate(D:20150601200942+08'00') /Producer(? M i c r o s o f t ?  W o r d   2 0 1 3) >>

the second: 97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ?  W o r d   2 0 1 3)/Keywords(GISerClub)
            /ModDate(D:20190426155330+08'00')/Producer(? M i c r o s o f t ?  W o r d   2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>

the third:  97 0 obj<</Author(edison qian)/CreationDate(D:20150601200942+08'00')/Creator(? M i c r o s o f t ?  W o r d   2 0 1 3)/Keywords(GISerClub)
            /ModDate(D:20190426155428+08'00')/Producer(? M i c r o s o f t ?  W o r d   2 0 1 3)/Title(? G I S e r C l u bThR\n 2 0 1 4 0 7 2 0)>>

my code:



    bool pdfSign(PdfMemDocument* document,PdfOutputDevice* outputDevice,PKCS12* p12,RSA* rsa,int npage,PdfRect rect,int min_signature_size,const char* ImgFile/*,PdfDate& sigData*/)
    {
        PdfInfo* pInfo = document->GetInfo();
        TKeyMap itm = pInfo->GetObject()->GetDictionary().GetKeys();
        PdfObject* pobj = pInfo->GetObject()->GetDictionary().GetKey(PdfName("ModDate"));
        PdfString modDate = pobj->GetString();
        string sDate = modDate.GetString();
        string sutf8Date = modDate.GetStringUtf8();

        PdfOutlines* pOutLine = document->GetOutlines();
        TKeyMap itm2 = pOutLine->GetObject()->GetDictionary().GetKeys();

        const char *field_name = NULL;
        bool field_use_existing = false;
        int annot_page = npage;
        //double annot_left = 80.0, annot_top = 70.0, annot_width = 150.0, annot_height = 150.0;
        bool annot_print = true;
        const char *reason = "I agree";

        int result = 0;
        PdfSignatureField *pSignField = NULL;

        try
        {
            PdfSignOutputDevice signer( outputDevice );

            PdfAcroForm* pAcroForm = document->GetAcroForm();
            if( !pAcroForm )
                PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "acroForm == NULL" );

            if( !pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) || 
                !pAcroForm->GetObject()->GetDictionary().GetKey( PdfName( "SigFlags" ) )->IsNumber() || 
                pAcroForm->GetObject()->GetDictionary().GetKeyAsLong( PdfName( "SigFlags" ) ) != 3 )
            {
                if( pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) )
                    pAcroForm->GetObject()->GetDictionary().RemoveKey( PdfName( "SigFlags" ) );

                pdf_int64 val = 3;
                pAcroForm->GetObject()->GetDictionary().AddKey( PdfName( "SigFlags" ), PdfObject( val ) );
            }

            if( pAcroForm->GetNeedAppearances() )
            {
                #if 0 /* TODO */
                update_default_appearance_streams( pAcroForm );
                #endif

                pAcroForm->SetNeedAppearances( false );
            }

            PdfString name;
            PdfObject* pExistingSigField = NULL;

            PdfImage image( document );
            image.LoadFromFile( ImgFile );
            double dimgWidth = image.GetWidth();
            double dimgHeight = image.GetHeight();

            char fldName[96]; // use bigger buffer to make sure sprintf does not overflow
            sprintf( fldName, "PodofoSignatureField%" PDF_FORMAT_INT64, static_cast( document->GetObjects().GetObjectCount() ) );
            name = PdfString( fldName );

            PdfPage* pPage = document->GetPage( annot_page );
            if( !pPage )
                PODOFO_RAISE_ERROR( ePdfError_PageNotFound );

            double dPageHeight = pPage->GetPageSize().GetHeight();
            double dPageWidth = pPage->GetPageSize().GetWidth();

            PdfRect annot_rect;
            annot_rect = PdfRect( rect.GetLeft(), 
                pPage->GetPageSize().GetHeight() - rect.GetBottom() - rect.GetHeight(),
                dimgWidth, 
                dimgHeight );

            PdfAnnotation* pAnnot = pPage->CreateAnnotation( ePdfAnnotation_Widget, annot_rect );
            if( !pAnnot )
                PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate annotation object" );

            if( annot_print )
                pAnnot->SetFlags( ePdfAnnotationFlags_Print );
            else if(  !field_name || !field_use_existing  )
                pAnnot->SetFlags( ePdfAnnotationFlags_Invisible | ePdfAnnotationFlags_Hidden );

            PdfPainter painter;
            try
            {
                painter.SetPage( /*&sigXObject*/pPage );

                /* Workaround Adobe's reader error 'Expected a dict object.' when the stream
                    contains only one object which does Save()/Restore() on its own, like
                    the image XObject. */
                painter.Save();
                painter.Restore();
                draw_annotation( *document, painter, image, annot_rect );

            }
            catch( PdfError & e )
            {
                if( painter.GetPage() )
                {
                    try
                    {
                        painter.FinishPage();
                    }
                    catch( ... )
                    {
                    }
                }
            }

            painter.FinishPage();

            //pSignField = new PdfSignatureField( pAnnot, pAcroForm, document );
            pSignField = new PdfSignatureField( pPage, annot_rect, document );
            if( !pSignField )
                PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate signature field object" );

            PdfRect annotSize( 0.0, 0.0, dimgWidth, dimgHeight );
            PdfXObject sigXObject( annotSize, document );

            pSignField->SetAppearanceStream( &sigXObject );


            // use large-enough buffer to hold the signature with the certificate
            signer.SetSignatureSize( min_signature_size );

            pSignField->SetFieldName( name );
            pSignField->SetSignatureReason( PdfString( reinterpret_cast( reason ) ) );
            pSignField->SetSignatureDate( /*sigData*/PdfDate() );
            pSignField->SetSignature( *signer.GetSignatureBeacon() );
            pSignField->SetBackgroundColorTransparent();
            pSignField->SetBorderColorTransparent();

            // The outPdfFile != NULL means that the write happens to a new file,
            // which will be truncated first and then the content of the srcPdfFile
            // will be copied into the document, follwed by the changes.
            //signer.Seek(0);
            document->WriteUpdate( &signer, true ); 

            if( !signer.HasSignaturePosition() )
                PODOFO_RAISE_ERROR_INFO( ePdfError_SignatureError, "Cannot find signature position in the document data" );

            // Adjust ByteRange for signature
            signer.AdjustByteRange();

            // Read data for signature and count it
            // We seek at the beginning of the file
            signer.Seek( 0 );
            sign_with_signer( signer, g_x509, g_pKey );
            signer.Flush();
        }
        catch( PdfError & e )
        {

        }

        if( pSignField )
            delete pSignField;

    }

i use the code above two times, and the first signature is invalid. how to add two digital signature without invalidating the previous one?

pengpeng
  • 13
  • 4
  • You say you *got the same problem*... the same as what? You say you *found there are 3 info——dictionary*... that's completely ok, in case of incremental updates you usually get one info dictionary per revision. You may also want to show the pivotal code of your approach and share an example result. – mkl Apr 26 '19 at 13:28
  • i post my code above, was i missed something? you are right, i open the "PdfMemDocument" for incremental update – pengpeng Apr 28 '19 at 01:29
  • Can you also share an example result which illustrates the issue for analysis? – mkl Apr 28 '19 at 06:42
  • ofcourse [link](https://drive.google.com/open?id=1hMY0LiPQEzr8hQr5rmQEL8Zo26hlkSHY) – pengpeng Apr 28 '19 at 07:34

1 Answers1

0

Painting on the right PdfCanvas

After analyzing the example pdf the reason why your second signature invalidated your first one became clear: In the course of signing you change the page content of the page with the widget annotation of the signature.

But changing the content of any page invalidates any previous signature! Cf. this answer for details on allowed and disallowed changes of signed documents.

Indeed:

PdfPainter painter;

try
{
    painter.SetPage( /*&sigXObject*/pPage );

    /* Workaround Adobe's reader error 'Expected a dict object.' when the stream
        contains only one object which does Save()/Restore() on its own, like
        the image XObject. */
    painter.Save();
    painter.Restore();
    draw_annotation( *document, painter, image, annot_rect );
}

Apparently you here change something in the page content itself. When this code is executed while applying the second signature, the first signature is invalidated.

You confirmed in a comment:

i use '&sigXObject' instead of 'pPage ',All two signatures are working! but the red seal disappeared

Using the right coordinates

Concerning your observation that the red seal disappeared: You use the wrong coordinates for drawing the image on the annotation appearance!

You use coordinates for the page coordinate system, but you have to use the coordinates in the coordinate system given by the appearance's bounding box.

Thus, your

painter.DrawImage( annot_rect.GetLeft(), annot_rect.GetBottom(), &image );

is wrong, instead try something like

painter.DrawImage( 0, 0, &image );

as the bounding box of your appearance is is

[ 0 0 151 151 ]
Community
  • 1
  • 1
mkl
  • 90,588
  • 15
  • 125
  • 265
  • i use '&sigXObject' instead of 'pPage ',All two signatures are working! but the red seal disappeared,How should I modify my code? Sincere thanks – pengpeng Apr 29 '19 at 01:56
  • Your code ignores `PdfError`s. Could you check whether such an exception is thrown, and if it is, share the details? – mkl Apr 29 '19 at 06:51
  • i debug my code,and there is no exception .see [link](https://drive.google.com/drive/folders/1hMY0LiPQEzr8hQr5rmQEL8Zo26hlkSHY) – pengpeng Apr 29 '19 at 07:07
  • Ok. In that case can you also share the code of the `draw_annotation` method and an example signed pdf using *'&sigXObject' instead of 'pPage'*? – mkl Apr 29 '19 at 08:18
  • yes, see [link](https://drive.google.com/drive/folders/1hMY0LiPQEzr8hQr5rmQEL8Zo26hlkSHY) – pengpeng Apr 29 '19 at 08:35
  • “The appearance is contained in a number of XObjects that are assembled to create layers” acorrding to 'AcrobatDC_acrobat_digital_signature_appearances.pdf'(you can find it in my google netdisk), i realize that i wasn't create these layers(n0 - n4), but the point is that i don't konw how to create with podofo.It makes me confused. – pengpeng Apr 30 '19 at 00:59
  • thanks! i have noticed your modification above, and it is effective! my code is also working. but ,as mentioned above, the problem about layers is still unsolved. – pengpeng Apr 30 '19 at 07:40
  • This layers stuff has been deprecated more than 10 years ago. It actually never has been part of the pdf specification since its first release as ISO 32000-1 in 2008. Even worse, support for those layers actually is discouraged by modern standards. For some backgrounds read [this answer](https://stackoverflow.com/a/40391641/1729265). – mkl Apr 30 '19 at 09:24
  • Furthermore, you never mentioned those layers in your question before now. If you really need them, please make that the topic of a separate question, referencing this question to show that you implemented regular pdf signing, and then mention that you need to support this deprecated, Adobe-specific pattern of constructing the signature appearance in "layers" even if it does not conform to modern standards. – mkl Apr 30 '19 at 09:27
  • Most likely I cannot seriously help with those layers. I have not actually programmed with podofo, the answer above merely was based on source code review. For helping with those layers, though, some hands-on work most likely is necessary. – mkl Apr 30 '19 at 10:08
  • I just saw in your copy of that document that Adobe does still actively promote the use of the layers **n0** and **n2**, at least they still are documented in the DC SDK. Be aware, though, that these layers are Adobe-specific, they are meaningless as far as the pdf standard is concerned. – mkl Apr 30 '19 at 10:39
  • i just found those layers after signing with Adobe Acrobt DC,i thought it was indispensable. now, i see,thanks. – pengpeng May 05 '19 at 10:18