summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-10-28 18:33:47 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-10-28 18:34:14 +0200
commit5c33253daf23224424cf6b181a2c2235c4a82539 (patch)
treeb99b284f811702a4f3e8e776d82d26f092367d31
parent56cc352d8229c16604f39a21bd77a05b422470f4 (diff)
xmlsecurity PDF verify: start using offsets from xref streams
This is needed (but not enough) to verify PDF 1.5 signatures. What's missing next is support for object streams. Change-Id: I5afec0a77839ffabe0aaa07e367064210535a1a9
-rw-r--r--xmlsecurity/inc/pdfio/pdfdocument.hxx7
-rw-r--r--xmlsecurity/source/pdfio/pdfdocument.cxx78
2 files changed, 46 insertions, 39 deletions
diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx
index 80a8de68f1fd..95663e6c190b 100644
--- a/xmlsecurity/inc/pdfio/pdfdocument.hxx
+++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx
@@ -63,11 +63,17 @@ class XMLSECURITY_DLLPUBLIC PDFDocument
std::map<size_t, size_t> m_aXRef;
/// Object ID <-> "are changed as part of an incremental update?" map.
std::map<size_t, bool> m_aXRefDirty;
+ /// Object offset <-> Object pointer map.
+ std::map<size_t, PDFObjectElement*> m_aOffsetObjects;
+ /// Object ID <-> Object pointer map.
+ std::map<size_t, PDFObjectElement*> m_aIDObjects;
/// List of xref offsets we know.
std::vector<size_t> m_aStartXRefs;
/// List of EOF offsets we know.
std::vector<size_t> m_aEOFs;
PDFTrailerElement* m_pTrailer;
+ /// When m_pTrailer is nullptr, this can still have a dictionary.
+ PDFObjectElement* m_pXRefStream;
/// All editing takes place in this buffer, if it happens.
SvMemoryStream m_aEditBuffer;
@@ -93,6 +99,7 @@ public:
std::vector<PDFObjectElement*> GetPages();
/// Remember the end location of an EOF token.
void PushBackEOF(size_t nOffset);
+ const std::map<size_t, PDFObjectElement*>& GetIDObjects() const;
/// Read elements from the start of the stream till its end.
bool Read(SvStream& rStream);
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 1fef027f4163..4d6cbd4fd9b7 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -100,7 +100,6 @@ public:
PDFElement* Lookup(const OString& rDictionaryKey);
PDFObjectElement* LookupObject(const OString& rDictionaryKey);
double GetObjectValue() const;
- double GetGenerationValue() const;
void SetDictionaryOffset(sal_uInt64 nDictionaryOffset);
sal_uInt64 GetDictionaryOffset();
void SetDictionaryLength(sal_uInt64 nDictionaryLength);
@@ -277,7 +276,8 @@ public:
};
PDFDocument::PDFDocument()
- : m_pTrailer(nullptr)
+ : m_pTrailer(nullptr),
+ m_pXRefStream(nullptr)
{
}
@@ -746,6 +746,10 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode)
{
bInStartXRef = false;
m_aStartXRefs.push_back(pNumberElement->GetValue());
+
+ auto it = m_aOffsetObjects.find(pNumberElement->GetValue());
+ if (it != m_aOffsetObjects.end())
+ m_pXRefStream = it->second;
}
}
else if (isalpha(ch))
@@ -776,6 +780,8 @@ bool PDFDocument::Tokenize(SvStream& rStream, TokenizeMode eMode)
{
pObject = new PDFObjectElement(*this, pObjectNumber->GetValue(), pGenerationNumber->GetValue());
m_aElements.push_back(std::unique_ptr<PDFElement>(pObject));
+ m_aOffsetObjects[pObjectNumber->GetLocation()] = pObject;
+ m_aIDObjects[pObjectNumber->GetValue()] = pObject;
}
else
{
@@ -918,13 +924,9 @@ bool PDFDocument::Read(SvStream& rStream)
return false;
}
- if (!m_pTrailer)
- {
- SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Read: found no trailer");
- return false;
- }
-
- auto pPrev = dynamic_cast<PDFNumberElement*>(m_pTrailer->Lookup("Prev"));
+ PDFNumberElement* pPrev = nullptr;
+ if (m_pTrailer)
+ pPrev = dynamic_cast<PDFNumberElement*>(m_pTrailer->Lookup("Prev"));
if (pPrev)
nStartXRef = pPrev->GetValue();
@@ -933,6 +935,7 @@ bool PDFDocument::Read(SvStream& rStream)
m_aStartXRefs.clear();
m_aEOFs.clear();
m_pTrailer = nullptr;
+ m_pXRefStream = nullptr;
if (!pPrev)
break;
}
@@ -1197,6 +1200,7 @@ void PDFDocument::ReadXRefStream(SvStream& rStream)
nStreamOffset = (nStreamOffset << 8) + nCh;
}
+ // Generation number of the object.
size_t nGenerationNumber = 0;
nOffset = nPos;
for (; nPos < nOffset + aW[2]; ++nPos)
@@ -1204,6 +1208,16 @@ void PDFDocument::ReadXRefStream(SvStream& rStream)
unsigned char nCh = aFilteredLine[nPos];
nGenerationNumber = (nGenerationNumber << 8) + nCh;
}
+
+ // "n" entry of the xref table
+ if (nType == 1)
+ {
+ if (m_aXRef.find(nIndex) == m_aXRef.end())
+ {
+ m_aXRef[nIndex] = nStreamOffset;
+ m_aXRefDirty[nIndex] = false;
+ }
+ }
}
}
@@ -1346,17 +1360,21 @@ const std::vector< std::unique_ptr<PDFElement> >& PDFDocument::GetElements()
return m_aElements;
}
+const std::map<size_t, PDFObjectElement*>& PDFDocument::GetIDObjects() const
+{
+ return m_aIDObjects;
+}
+
std::vector<PDFObjectElement*> PDFDocument::GetPages()
{
std::vector<PDFObjectElement*> aRet;
- if (!m_pTrailer)
- {
- SAL_WARN("xmlsecurity.pdfio", "PDFDocument::GetPages: found no trailer");
- return aRet;
- }
+ PDFReferenceElement* pRoot = nullptr;
+ if (m_pTrailer)
+ pRoot = dynamic_cast<PDFReferenceElement*>(m_pTrailer->Lookup("Root"));
+ else if (m_pXRefStream)
+ pRoot = dynamic_cast<PDFReferenceElement*>(m_pXRefStream->Lookup("Root"));
- auto pRoot = dynamic_cast<PDFReferenceElement*>(m_pTrailer->Lookup("Root"));
if (!pRoot)
{
SAL_WARN("xmlsecurity.pdfio", "PDFDocument::GetPages: trailer has no Root key");
@@ -1373,7 +1391,7 @@ std::vector<PDFObjectElement*> PDFDocument::GetPages()
PDFObjectElement* pPages = pCatalog->LookupObject("Pages");
if (!pPages)
{
- SAL_WARN("xmlsecurity.pdfio", "PDFDocument::GetPages: catalog has no pages");
+ SAL_WARN("xmlsecurity.pdfio", "PDFDocument::GetPages: catalog (obj " << pCatalog->GetObjectValue() << ") has no pages");
return aRet;
}
@@ -2237,11 +2255,6 @@ double PDFObjectElement::GetObjectValue() const
return m_fObjectValue;
}
-double PDFObjectElement::GetGenerationValue() const
-{
- return m_fGenerationValue;
-}
-
void PDFObjectElement::SetDictionaryOffset(sal_uInt64 nDictionaryOffset)
{
m_nDictionaryOffset = nDictionaryOffset;
@@ -2395,25 +2408,12 @@ double PDFReferenceElement::LookupNumber(SvStream& rStream) const
PDFObjectElement* PDFReferenceElement::LookupObject() const
{
- const std::vector< std::unique_ptr<PDFElement> >& rElements = m_rDoc.GetElements();
- // Iterate in reverse order, so in case an incremental update adds a newer
- // version, we find it.
- for (int i = rElements.size() - 1; i >= 0; --i)
- {
- const std::unique_ptr<PDFElement>& rElement = rElements[i];
- auto* pObjectElement = dynamic_cast<PDFObjectElement*>(rElement.get());
- if (!pObjectElement)
- continue;
-
- if (pObjectElement->GetObjectValue() != m_fObjectValue)
- continue;
-
- if (pObjectElement->GetGenerationValue() != m_fGenerationValue)
- continue;
-
- return pObjectElement;
- }
+ const std::map<size_t, PDFObjectElement*>& rIDObjects = m_rDoc.GetIDObjects();
+ auto it = rIDObjects.find(m_fObjectValue);
+ if (it != rIDObjects.end())
+ return it->second;
+ SAL_WARN("xmlsecurity.pdfio", "PDFReferenceElement::LookupObject: can't find obj " << m_fObjectValue);
return nullptr;
}