0

我在 Ubuntu 环境中使用 Podofo 库和 c++ 代码进行 PDf 签名。实际上,我能够在 Windows 环境中使用相同的库和代码成功地进行 pdf 签名。但是,在 Ubuntu 32 位环境中出现“字节范围无效”问题。我附上了“字节范围无效”签名证书。请参考这个并给我一些输入。

文件链接

 try
    {
        PdfXObject *m_pImgXObj_vs;
        PdfMemDocument document;

        document.Load(inputfile, true);
        if (!document.GetPageCount())
            PODOFO_RAISE_ERROR_INFO(ePdfError_PageNotFound, "The document has no page. Only documents with at least one page can be signed");

        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);
        }

        PdfOutputDevice outputDevice(outputfile ? outputfile : inputfile, outputfile != NULL);
        PdfSignOutputDevice signer(&outputDevice);

        PdfString name;
        PdfObject* pExistingSigField = NULL;




        if (field_name)
        {
            name = PdfString(field_name);

            pExistingSigField = find_existing_signature_field(pAcroForm, name);
            if (pExistingSigField && !field_use_existing)
            {
                std::string err = "Signature field named '";
                err += name.GetString();
                err += "' already exists";

                PODOFO_RAISE_ERROR_INFO(ePdfError_WrongDestinationType, err.c_str());
            }
        }
        else
        {
            char fldName[96]; 
            sprintf(fldName, "PodofoSignatureField%" PDF_FORMAT_INT64, static_cast<pdf_int64>(document.GetObjects().GetObjectCount()));

            name = PdfString(fldName);
        }
        if (pExistingSigField)
        {
            if (!pExistingSigField->GetDictionary().HasKey("P"))
            {
                std::string err = "Signature field named '";
                err += name.GetString();
                err += "' doesn't have a page reference";

                PODOFO_RAISE_ERROR_INFO(ePdfError_PageNotFound, err.c_str());
            }

            PdfPage* pPage;

            pPage = document.GetPagesTree()->GetPage(pExistingSigField->GetDictionary().GetKey("P")->GetReference());
            if (!pPage)
                PODOFO_RAISE_ERROR(ePdfError_PageNotFound);

            pTemporaryAnnot = new PdfAnnotation(pExistingSigField, pPage);
            if (!pTemporaryAnnot)
                PODOFO_RAISE_ERROR_INFO(ePdfError_OutOfMemory, "Cannot allocate annotation object for existing signature field");

            pSignField = new PdfSignatureField(pTemporaryAnnot);
            if (!pSignField)
                PODOFO_RAISE_ERROR_INFO(ePdfError_OutOfMemory, "Cannot allocate existing signature field object");

            pSignField->EnsureSignatureObject();
        }
        else
        {
            PdfRect annot_rect;
            PdfPage* pPage = document.GetPage(document.GetPageCount() - 1);
            if (!pPage)
                PODOFO_RAISE_ERROR(ePdfError_PageNotFound);

            
            if (annot_position)
            {
                annot_rect = PdfRect(annot_left, pPage->GetPageSize().GetHeight() - annot_top - annot_height, annot_width, annot_height);
                annot_rect = PdfRect(annot_left, pPage->GetPageSize().GetBottom() - annot_top + 3, annot_width, annot_height);
            }

            PdfAnnotation* pAnnot = pPage->CreateAnnotation(ePdfAnnotation_Widget, annot_rect);
            if (!pAnnot)
                PODOFO_RAISE_ERROR_INFO(ePdfError_OutOfMemory, "Cannot allocate annotation object");
            pAnnot->GetTitle();
            if (annot_position && annot_print)
                pAnnot->SetFlags(ePdfAnnotationFlags_Print);
            else if (!annot_position && (!field_name || !field_use_existing))
                pAnnot->SetFlags(ePdfAnnotationFlags_Invisible | ePdfAnnotationFlags_Hidden);

            pAnnot->SetContents("ABC");
            
            PdfImage *pdfImage = NULL;
            
            PdfSigIncMemDocument m_psigMemDoc;
            PdfXObject *m_pImgXObj_vs = NULL;
            PdfXObject *m_n2XObj = NULL;
            PdfFont *m_pFont = document.CreateFont("Times-Roman", true, true);
            PdfRect objRect(0, 0, annot_rect.GetWidth(), annot_rect.GetHeight());
                        
            m_pImgXObj_vs = new PdfXObject(objRect, &document);
            PdfSigIncPainter pnt(&document, true);
            pnt.SetPageCanvas(pPage, m_pImgXObj_vs->GetContents());
            PdfXObject frmXObj(objRect, &document, "FRM", true);
            
            m_pImgXObj_vs->AddResource(PdfName("FRM"), frmXObj.GetObjectReference(), PdfName("XObject"));
            pnt.DrawXObject(0, 0, &frmXObj);
            pnt.SetFont(m_pFont);
            
            pnt.SetPageCanvas(pPage, frmXObj.GetContents());

            PdfXObject n0XObj(objRect, &document, "n0", true);
            PdfXObject n2XObj(objRect, &document, "n2", true);

            frmXObj.AddResource(PdfName("n0"), n0XObj.GetObjectReference(), PdfName("XObject"));
            frmXObj.AddResource(PdfName("n2"), n2XObj.GetObjectReference(), PdfName("XObject"));

            pnt.DrawXObject(0, 0, &n0XObj);
            pnt.DrawXObject(0, 0, &n2XObj);


            
            PdfString text = "podofo";
            
            m_pFont = document.CreateFont("Times-Roman", true, true);
            m_pFont->SetFontSize(25);
            pnt.SetFont(m_pFont);
            pnt.SetColor(0, 0, 0);
            pnt.DrawText(2, 31, "e");
            m_pFont->SetFontSize(27);
            pnt.SetColor(0.92, 0.60, 0.08);
            pnt.DrawText(10, 19, "Sign");
            n2XObj.AddResource(m_pFont->GetIdentifier(), m_pFont->GetObject()->Reference(), PdfName("Font"));


            m_pFont->SetFontSize(6.5);
            
            pnt.SetFont(m_pFont);
            pnt.SetColor(0, 0, 0);
            int width = annot_rect.GetWidth() / 2 - 15;
            pnt.DrawText(width, 40, "Digitally Signed By");
            pnt.DrawText(width, 32, "ABC");

            pnt.DrawText(width, 24, "XYZ");
            pnt.DrawText(width, 16, "Unknown");
            pnt.DrawText(width, 8, "29/10/2020");
            n2XObj.AddResource(m_pFont->GetIdentifier(), m_pFont->GetObject()->Reference(), PdfName("Font"));
            
            pnt.EndCanvas();
            pnt.FinishPage();
        
            pSignField = new PdfSignatureField(pAnnot, pAcroForm, &document);
            if (!pSignField)
                PODOFO_RAISE_ERROR_INFO(ePdfError_OutOfMemory, "Cannot allocate signature field object");

            signer.SetSignatureSize(10200);
            pSignField->SetFieldName("Signature");
            pSignField->SetSignatureReason(PdfString(reinterpret_cast<const pdf_utf8 *>(reason)));
            pSignField->SetSignatureDate(PdfDate());
            pSignField->SetSignature(*signer.GetSignatureBeacon());

            
            document.WriteUpdate(&signer, outputfile != NULL);
            if (signer.HasSignaturePosition())
            {
                signer.AdjustByteRange();
                
                signer.Seek(0);
                
                size_t len;

                unsigned char hash[SHA256_DIGEST_LENGTH];
                SHA256_CTX sha256;
                SHA256_Init(&sha256);
                const int bufSize = 65536;
                char outputBuffer[65];
                char *buffer = (char *)malloc(bufSize);
                
                unsigned int uBufferLen = 65535;
                char *pBuffer;

                while (pBuffer = reinterpret_cast<char *>(podofo_malloc(sizeof(char) * uBufferLen)), !pBuffer)
                {
                    uBufferLen = uBufferLen / 2;
                    if (!uBufferLen)
                        break;
                }
                
                int rc;
                BIO *mem = BIO_new(BIO_s_mem());
                if (!mem)
                {
                    podofo_free(pBuffer);
                    podofo_free(buffer);
                    
                }
                
                while ((len = signer.ReadForSignature(pBuffer, uBufferLen)) > 0)
                {
                    SHA256_Update(&sha256, pBuffer, len);
                    rc = BIO_write(mem, pBuffer, len);
                    

                }
                SHA256_Final(hash, &sha256);
                sha256_hash_string(hash, outputBuffer);

                
                unsigned int flags = PKCS7_DETACHED | PKCS7_BINARY;
                
                
                //Adding PKCS7 data(str_pkcs7) for Signing  
                createXPemformate(str_pkcs7, 64);
                PKCS7 *p7 = NULL;
                BIO *in = BIO_new(BIO_s_file());
                BIO *out = BIO_new(BIO_s_file());
                int der = 0; 
                int text = 0; 
                STACK_OF(X509) *certs = NULL;
                int i;

                                                             \
                    ERR_load_crypto_strings();
                OpenSSL_add_all_algorithms();

                BIO_set_fp(out, stdout, BIO_NOCLOSE);
                BIO_read_filename(in, "myfile.p7b");
                
                p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
                
                i = OBJ_obj2nid(p7->type);
                if (i == NID_pkcs7_signed) {
                    certs = p7->d.sign->cert;
                }
                else if (i == NID_pkcs7_signedAndEnveloped) {
                    certs = p7->d.signed_and_enveloped->cert;
                }
                if (PKCS7_final(p7, mem, flags) <= 0)
                {
                    PKCS7_free(p7);
                    BIO_free(mem);
                    
                }
                
                char *outBuff = NULL;
                long outLen;
                BIO *bio = BIO_new(BIO_s_mem());
                int p7_len = i2d_PKCS7_bio(bio, p7);
                outLen = BIO_get_mem_data(bio, &outBuff);
                cout << "outLen" << outLen << std::endl;
                if (outLen > 0 && outBuff)
                {
                    if (static_cast<size_t>(outLen) > signer.GetSignatureSize())
                    {
                        std::ostringstream oss;
                        oss << "Requires at least " << outLen << " bytes for the signature, but reserved is only " << signer.GetSignatureSize() << " bytes";
                        
                    }
                }
                
                PoDoFo::PdfData sigData(outBuff, outLen);
                signer.SetSignature(sigData);// Paste signature to the file
                
            }
            signer.Flush();
        }
    }
    catch (PoDoFo::PdfError & e)
    {
        std::cerr << "Error: An error " << e.what() << " occurred during the sign of the pdf file:" << std::endl;
        
    }
4

1 回答 1

0

PDF 中的交叉引用表无效:

xref
0 12
0000000000 00000 ÿ 
0000000172 00000   
0000000231 00000   
0000000328 00000   
0000000379 00000   
0000000414 00000   
0000000583 00000   
0000000706 00000   
0000000015 00000   
0000001747 00000   
0000001765 00000   
0000001932 00000    

根据 PDF 规范,

在用条目的格式应为:

nnnnnnnnnn ggggg n eol

[...]

自由对象的交叉引用条目具有基本相同的格式,不同之处在于关键字应为 n 而不是 n 并且第一项的解释不同:

nnnnnnnnnn ggggg f eol

而不是fandn你有 0xff ( ÿ) 和 0x00 (在上面显示为一个空格)。

于 2020-11-02T10:31:28.457 回答