summaryrefslogtreecommitdiff
path: root/xmlsecurity
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-11-10 10:18:31 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-11-10 17:46:27 +0100
commitc21329fa904b682bde3df1082821df0af7ebbea3 (patch)
tree0716a5b31a05ee4e3e35538d7309494ac0a76c00 /xmlsecurity
parent8445764681bfe7bd6cd31194878e1314a8fafa3b (diff)
xmlsecurity PDF verify: fix incremental updates vs object streams
The problem: an object stream provies obj#1 and obj#2, then an incremental updates provides an updated obj#1'. Then we look up obj#2, parse the stored objects on-demand, so at the end when later we look up the first object, we find obj#1, not obj#1'. An easy workaround would be to never update already existing objects from object streams, but that would break when an incremental update provides an object stream. Fix the problem by parsing stored objects right after tokenizing the object stream, and not later, on-demand, when we no longer have the context what objects should be ignored. This is needed (but not enough) to correctly append a signature at the end of a PDF file that has both object streams and incremental updates. Change-Id: I3c1fae5ac26804c8e8cc1984511f43cfa881c97b
Diffstat (limited to 'xmlsecurity')
-rw-r--r--xmlsecurity/source/pdfio/pdfdocument.cxx37
1 files changed, 18 insertions, 19 deletions
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 58aac9428051..29212224ced6 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -603,7 +603,7 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat
SvMemoryStream* pStreamBuffer = pAcroFormObject->GetStreamBuffer();
if (!pStreamBuffer)
{
- SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: AcroForm object is in an object stream");
+ SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: AcroForm object is not in an object stream");
return false;
}
@@ -982,6 +982,8 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
{
// Last seen object token.
PDFObjectElement* pObject = pObjectElement;
+ PDFNameElement* pObjectKey = nullptr;
+ PDFObjectElement* pObjectStream = nullptr;
bool bInXRef = false;
// The next number will be an xref offset.
bool bInStartXRef = false;
@@ -1064,10 +1066,15 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
}
case '/':
{
- rElements.push_back(std::unique_ptr<PDFElement>(new PDFNameElement()));
+ auto pNameElement = new PDFNameElement();
+ rElements.push_back(std::unique_ptr<PDFElement>(pNameElement));
rStream.SeekRel(-1);
- if (!rElements.back()->Read(rStream))
+ if (!pNameElement->Read(rStream))
return false;
+ if (pObject && pObjectKey && pObjectKey->GetValue() == "Type" && pNameElement->GetValue() == "ObjStm")
+ pObjectStream = pObject;
+ else
+ pObjectKey = pNameElement;
break;
}
case '(':
@@ -1197,6 +1204,14 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode, std::vector< s
// Found endobj and only object parsing was requested, we're done.
return true;
}
+
+ if (pObjectStream)
+ {
+ // We're at the end of an object stream, parse the stored objects.
+ pObjectStream->ParseStoredObjects();
+ pObjectStream = nullptr;
+ pObjectKey = nullptr;
+ }
}
else if (aKeyword == "true" || aKeyword == "false")
rElements.push_back(std::unique_ptr<PDFElement>(new PDFBooleanElement(aKeyword.toBoolean())));
@@ -3096,22 +3111,6 @@ PDFObjectElement* PDFReferenceElement::LookupObject()
PDFObjectElement* PDFDocument::LookupObject(size_t nObjectNumber)
{
auto itIDObjects = m_aIDObjects.find(nObjectNumber);
- auto itXRef = m_aXRef.find(nObjectNumber);
- if (itIDObjects == m_aIDObjects.end() && itXRef != m_aXRef.end())
- {
- // We don't have an object for this number yet, but there is an xref
- // entry for it.
- const XRefEntry& rEntry = itXRef->second;
- if (rEntry.m_eType == XRefEntryType::COMPRESSED)
- {
- // It's a compressed entry, try parsing the stored objects.
- if (PDFObjectElement* pObjectStream = LookupObject(rEntry.m_nOffset))
- // This registers new IDs.
- pObjectStream->ParseStoredObjects();
- }
- // Find again, now that the new objects are registered.
- itIDObjects = m_aIDObjects.find(nObjectNumber);
- }
if (itIDObjects != m_aIDObjects.end())
return itIDObjects->second;