summaryrefslogtreecommitdiff
path: root/xmlsecurity
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-11-09 09:50:31 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-11-09 16:07:09 +0000
commit05bdc6739c6b29bcce41716000dc02d1271abd13 (patch)
treebe5a0ccd090ae50e39f451304982d8170abfcbc2 /xmlsecurity
parent2e84e730a89de683c97bbcab89cd2dbf5a7a9b6d (diff)
xmlsecurity PDF sign: handle when Page object's Annots is an indirect array
Normally it's a direct array, but it's OK to have it as a reference, and then the referenced object is an array. Change-Id: I191150632c2d8317ee6fd8c8169a90996298faa4 Reviewed-on: https://gerrit.libreoffice.org/30718 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'xmlsecurity')
-rw-r--r--xmlsecurity/source/pdfio/pdfdocument.cxx115
1 files changed, 82 insertions, 33 deletions
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 2af2da8f164f..8c01cd94f44b 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -437,46 +437,95 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat
m_aEditBuffer.WriteCharPtr(" 0 R\n>>\n");
m_aEditBuffer.WriteCharPtr(">>\nendobj\n\n");
- // Write the updated first page object, references nAnnotId.
- sal_uInt32 nFirstPageId = pFirstPage->GetObjectValue();
- if (nFirstPageId >= m_aXRef.size())
+ PDFElement* pAnnots = pFirstPage->Lookup("Annots");
+ auto pAnnotsReference = dynamic_cast<PDFReferenceElement*>(pAnnots);
+ if (pAnnotsReference)
{
- SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: invalid first page obj id");
- return false;
- }
- m_aXRef[nFirstPageId].m_nOffset = m_aEditBuffer.Tell();
- m_aXRef[nFirstPageId].m_bDirty = true;
- m_aEditBuffer.WriteUInt32AsString(nFirstPageId);
- m_aEditBuffer.WriteCharPtr(" 0 obj\n");
- m_aEditBuffer.WriteCharPtr("<<");
- auto pAnnots = dynamic_cast<PDFArrayElement*>(pFirstPage->Lookup("Annots"));
- if (!pAnnots)
- {
- // No Annots key, just write the key with a single reference.
- m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pFirstPage->GetDictionaryOffset(), pFirstPage->GetDictionaryLength());
- m_aEditBuffer.WriteCharPtr("/Annots[");
+ // Write the updated Annots key of the Page object.
+ PDFObjectElement* pAnnotsObject = pAnnotsReference->LookupObject();
+ if (!pAnnotsObject)
+ {
+ SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: invalid Annots reference");
+ return false;
+ }
+
+ sal_uInt32 nAnnotsId = pAnnotsObject->GetObjectValue();
+ m_aXRef[nAnnotsId].m_eType = XRefEntryType::NOT_COMPRESSED;
+ m_aXRef[nAnnotsId].m_nOffset = m_aEditBuffer.Tell();
+ m_aXRef[nAnnotsId].m_nGenerationNumber = 0;
+ m_aXRef[nAnnotsId].m_bDirty = true;
+ m_aEditBuffer.WriteUInt32AsString(nAnnotsId);
+ m_aEditBuffer.WriteCharPtr(" 0 obj\n[");
+
+ // Write existing references.
+ PDFArrayElement* pArray = pAnnotsObject->GetArray();
+ if (!pArray)
+ {
+ SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: Page Annots is a reference to a non-array");
+ return false;
+ }
+
+ for (size_t i = 0; i < pArray->GetElements().size(); ++i)
+ {
+ auto pReference = dynamic_cast<PDFReferenceElement*>(pArray->GetElements()[i]);
+ if (!pReference)
+ continue;
+
+ if (i)
+ m_aEditBuffer.WriteCharPtr(" ");
+ m_aEditBuffer.WriteUInt32AsString(pReference->GetObjectValue());
+ m_aEditBuffer.WriteCharPtr(" 0 R");
+ }
+ // Write our reference.
+ m_aEditBuffer.WriteCharPtr(" ");
m_aEditBuffer.WriteUInt32AsString(nAnnotId);
- m_aEditBuffer.WriteCharPtr(" 0 R]");
+ m_aEditBuffer.WriteCharPtr(" 0 R");
+
+ m_aEditBuffer.WriteCharPtr("]\nendobj\n\n");
}
else
{
- // Annots key is already there, insert our reference at the end.
- PDFDictionaryElement* pDictionary = pFirstPage->GetDictionary();
+ // Write the updated first page object, references nAnnotId.
+ sal_uInt32 nFirstPageId = pFirstPage->GetObjectValue();
+ if (nFirstPageId >= m_aXRef.size())
+ {
+ SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: invalid first page obj id");
+ return false;
+ }
+ m_aXRef[nFirstPageId].m_nOffset = m_aEditBuffer.Tell();
+ m_aXRef[nFirstPageId].m_bDirty = true;
+ m_aEditBuffer.WriteUInt32AsString(nFirstPageId);
+ m_aEditBuffer.WriteCharPtr(" 0 obj\n");
+ m_aEditBuffer.WriteCharPtr("<<");
+ auto pAnnotsArray = dynamic_cast<PDFArrayElement*>(pAnnots);
+ if (!pAnnotsArray)
+ {
+ // No Annots key, just write the key with a single reference.
+ m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pFirstPage->GetDictionaryOffset(), pFirstPage->GetDictionaryLength());
+ m_aEditBuffer.WriteCharPtr("/Annots[");
+ m_aEditBuffer.WriteUInt32AsString(nAnnotId);
+ m_aEditBuffer.WriteCharPtr(" 0 R]");
+ }
+ else
+ {
+ // Annots key is already there, insert our reference at the end.
+ PDFDictionaryElement* pDictionary = pFirstPage->GetDictionary();
- // Offset right before the end of the Annots array.
- sal_uInt64 nAnnotsEndOffset = pDictionary->GetKeyOffset("Annots") + pDictionary->GetKeyValueLength("Annots") - 1;
- // Length of beginning of the dictionary -> Annots end.
- sal_uInt64 nAnnotsBeforeEndLength = nAnnotsEndOffset - pFirstPage->GetDictionaryOffset();
- m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pFirstPage->GetDictionaryOffset(), nAnnotsBeforeEndLength);
- m_aEditBuffer.WriteCharPtr(" ");
- m_aEditBuffer.WriteUInt32AsString(nAnnotId);
- m_aEditBuffer.WriteCharPtr(" 0 R");
- // Length of Annots end -> end of the dictionary.
- sal_uInt64 nAnnotsAfterEndLength = pFirstPage->GetDictionaryOffset() + pFirstPage->GetDictionaryLength() - nAnnotsEndOffset;
- m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + nAnnotsEndOffset, nAnnotsAfterEndLength);
+ // Offset right before the end of the Annots array.
+ sal_uInt64 nAnnotsEndOffset = pDictionary->GetKeyOffset("Annots") + pDictionary->GetKeyValueLength("Annots") - 1;
+ // Length of beginning of the dictionary -> Annots end.
+ sal_uInt64 nAnnotsBeforeEndLength = nAnnotsEndOffset - pFirstPage->GetDictionaryOffset();
+ m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pFirstPage->GetDictionaryOffset(), nAnnotsBeforeEndLength);
+ m_aEditBuffer.WriteCharPtr(" ");
+ m_aEditBuffer.WriteUInt32AsString(nAnnotId);
+ m_aEditBuffer.WriteCharPtr(" 0 R");
+ // Length of Annots end -> end of the dictionary.
+ sal_uInt64 nAnnotsAfterEndLength = pFirstPage->GetDictionaryOffset() + pFirstPage->GetDictionaryLength() - nAnnotsEndOffset;
+ m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + nAnnotsEndOffset, nAnnotsAfterEndLength);
+ }
+ m_aEditBuffer.WriteCharPtr(">>");
+ m_aEditBuffer.WriteCharPtr("\nendobj\n\n");
}
- m_aEditBuffer.WriteCharPtr(">>");
- m_aEditBuffer.WriteCharPtr("\nendobj\n\n");
// Write the updated Catalog object, references nAnnotId.
PDFReferenceElement* pRoot = nullptr;