我在 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;
}