xmlsecurity/source/pdfio/pdfdocument.cxx | 153 +++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 38 deletions(-)
New commits: commit a3b3e336e5bd83754d9caae85dd5b9246bb4f7c1 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Tue Oct 25 18:08:27 2016 +0200 xmlsecurity PDF sign: append reference to the Catalog's AcroForm key Similar to the Page object's Annots key, but here we want to append our reference to the nested AcroForm/Fields key, so that needs more infrastructure. This is also needed (but not enough) to be able to sign a PDF document multiple times. Change-Id: I4d5e2aa8f49d2181a15cbf7c4e27577fc98b547d Reviewed-on: https://gerrit.libreoffice.org/30267 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@libreoffice.org> diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index 5778f20..dfd3938 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -74,6 +74,7 @@ public: }; class PDFReferenceElement; +class PDFDictionaryElement; /// Indirect object: something with a unique ID. class PDFObjectElement : public PDFElement @@ -86,10 +87,7 @@ class PDFObjectElement : public PDFElement sal_uInt64 m_nDictionaryOffset; /// Length of the dictionary buffer till (before) the '<<' token. sal_uInt64 m_nDictionaryLength; - /// Position after the '/' token. - std::map<OString, sal_uInt64> m_aDictionaryKeyOffset; - /// Length of the dictionary key and value, till (before) the next token. - std::map<OString, sal_uInt64> m_aDictionaryKeyValueLength; + PDFDictionaryElement* m_pDictionaryElement; public: PDFObjectElement(PDFDocument& rDoc, double fObjectValue, double fGenerationValue); @@ -102,24 +100,33 @@ public: sal_uInt64 GetDictionaryOffset(); void SetDictionaryLength(sal_uInt64 nDictionaryLength); sal_uInt64 GetDictionaryLength(); - void SetDictionaryKeyOffset(const OString& rKey, sal_uInt64 nOffset); - sal_uInt64 GetDictionaryKeyOffset(const OString& rKey) const; - void SetDictionaryKeyValueLength(const OString& rKey, sal_uInt64 nLength); - sal_uInt64 GetDictionaryKeyValueLength(const OString& rKey) const; + PDFDictionaryElement* GetDictionary() const; + void SetDictionary(PDFDictionaryElement* pDictionaryElement); }; /// Dictionary object: a set key-value pairs. class PDFDictionaryElement : public PDFElement { + /// Key-value pairs when the dictionary is a nested value. + std::map<OString, PDFElement*> m_aItems; /// Offset after the '<<' token. sal_uInt64 m_nLocation; + /// Position after the '/' token. + std::map<OString, sal_uInt64> m_aDictionaryKeyOffset; + /// Length of the dictionary key and value, till (before) the next token. + std::map<OString, sal_uInt64> m_aDictionaryKeyValueLength; public: PDFDictionaryElement(); bool Read(SvStream& rStream) override; - static void Parse(const std::vector< std::unique_ptr<PDFElement> >& rElements, PDFElement* pThis, std::map<OString, PDFElement*>& rDictionary); + static size_t Parse(const std::vector< std::unique_ptr<PDFElement> >& rElements, PDFElement* pThis, std::map<OString, PDFElement*>& rDictionary); static PDFElement* Lookup(const std::map<OString, PDFElement*>& rDictionary, const OString& rKey); + void SetKeyOffset(const OString& rKey, sal_uInt64 nOffset); + sal_uInt64 GetKeyOffset(const OString& rKey) const; + void SetKeyValueLength(const OString& rKey, sal_uInt64 nLength); + sal_uInt64 GetKeyValueLength(const OString& rKey) const; + const std::map<OString, PDFElement*>& GetItems() const; }; /// End of a dictionary: '>>'. @@ -396,9 +403,10 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat 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 = pFirstPage->GetDictionaryKeyOffset("Annots") + pFirstPage->GetDictionaryKeyValueLength("Annots") - 1; + 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); @@ -435,10 +443,44 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat m_aEditBuffer.WriteUInt32AsString(nCatalogId); m_aEditBuffer.WriteCharPtr(" 0 obj\n"); m_aEditBuffer.WriteCharPtr("<<"); - m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pCatalog->GetDictionaryOffset(), pCatalog->GetDictionaryLength()); - m_aEditBuffer.WriteCharPtr("/AcroForm<</Fields[\n"); - m_aEditBuffer.WriteUInt32AsString(nAnnotId); - m_aEditBuffer.WriteCharPtr(" 0 R\n]/SigFlags 3>>\n"); + auto pAcroForm = dynamic_cast<PDFDictionaryElement*>(pCatalog->Lookup("AcroForm")); + if (!pAcroForm) + { + // No AcroForm key, assume no signatures. + m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pCatalog->GetDictionaryOffset(), pCatalog->GetDictionaryLength()); + m_aEditBuffer.WriteCharPtr("/AcroForm<</Fields[\n"); + m_aEditBuffer.WriteUInt32AsString(nAnnotId); + m_aEditBuffer.WriteCharPtr(" 0 R\n]/SigFlags 3>>\n"); + } + else + { + // AcroForm key is already there, insert our reference at the Fields end. + auto it = pAcroForm->GetItems().find("Fields"); + if (it == pAcroForm->GetItems().end()) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: AcroForm without required Fields key"); + return false; + } + + auto pFields = dynamic_cast<PDFArrayElement*>(it->second); + if (!pFields) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::Sign: AcroForm Fields is not an array"); + return false; + } + + // Offset right before the end of the Fields array. + sal_uInt64 nFieldsEndOffset = pAcroForm->GetKeyOffset("Fields") + pAcroForm->GetKeyValueLength("Fields") - 1; + // Length of beginning of the Catalog dictionary -> Fields end. + sal_uInt64 nFieldsBeforeEndLength = nFieldsEndOffset - pCatalog->GetDictionaryOffset(); + m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + pCatalog->GetDictionaryOffset(), nFieldsBeforeEndLength); + m_aEditBuffer.WriteCharPtr(" "); + m_aEditBuffer.WriteUInt32AsString(nAnnotId); + m_aEditBuffer.WriteCharPtr(" 0 R"); + // Length of Fields end -> end of the Catalog dictionary. + sal_uInt64 nFieldsAfterEndLength = pCatalog->GetDictionaryOffset() + pCatalog->GetDictionaryLength() - nFieldsEndOffset; + m_aEditBuffer.WriteBytes(static_cast<const char*>(m_aEditBuffer.GetData()) + nFieldsEndOffset, nFieldsAfterEndLength); + } m_aEditBuffer.WriteCharPtr(">>\nendobj\n\n"); // Write the xref table. @@ -1542,7 +1584,8 @@ PDFObjectElement::PDFObjectElement(PDFDocument& rDoc, double fObjectValue, doubl m_fObjectValue(fObjectValue), m_fGenerationValue(fGenerationValue), m_nDictionaryOffset(0), - m_nDictionaryLength(0) + m_nDictionaryLength(0), + m_pDictionaryElement(nullptr) { } @@ -1557,12 +1600,17 @@ PDFDictionaryElement::PDFDictionaryElement() { } -void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> >& rElements, PDFElement* pThis, std::map<OString, PDFElement*>& rDictionary) +size_t PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> >& rElements, PDFElement* pThis, std::map<OString, PDFElement*>& rDictionary) { + // The index of last parsed element, in case of nested dictionaries. + size_t nRet = 0; + if (!rDictionary.empty()) - return; + return nRet; auto pThisObject = dynamic_cast<PDFObjectElement*>(pThis); + // This is set to non-nullptr here for nested dictionaries only. + auto pThisDictionary = dynamic_cast<PDFDictionaryElement*>(pThis); // Find out where the dictionary for this object starts. size_t nIndex = 0; @@ -1592,7 +1640,18 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> // First dictionary start, track start offset. nDictionaryOffset = pDictionary->m_nLocation; if (pThisObject) + { + pThisObject->SetDictionary(pDictionary); + pThisDictionary = pDictionary; pThisObject->SetDictionaryOffset(nDictionaryOffset); + } + } + else + { + // Nested dictionary. + nIndex = PDFDictionaryElement::Parse(rElements, pDictionary, pDictionary->m_aItems); + rDictionary[aName] = pDictionary; + aName.clear(); } } @@ -1603,6 +1662,7 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> // Last dictionary end, track length and stop parsing. if (pThisObject) pThisObject->SetDictionaryLength(pEndDictionary->GetLocation() - nDictionaryOffset); + nRet = nIndex; break; } } @@ -1614,10 +1674,10 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> { PDFNumberElement* pNumber = aNumbers.back(); rDictionary[aName] = pNumber; - if (pThisObject) + if (pThisDictionary) { - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); - pThisObject->SetDictionaryKeyValueLength(aName, pNumber->GetLocation() + pNumber->GetLength() - nNameOffset); + pThisDictionary->SetKeyOffset(aName, nNameOffset); + pThisDictionary->SetKeyValueLength(aName, pNumber->GetLocation() + pNumber->GetLength() - nNameOffset); } aName.clear(); aNumbers.clear(); @@ -1633,10 +1693,10 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> { // Name-name key-value. rDictionary[aName] = pName; - if (pThisObject) + if (pThisDictionary) { - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); - pThisObject->SetDictionaryKeyValueLength(aName, pName->GetLocation() + pName->GetLength() - nNameOffset); + pThisDictionary->SetKeyOffset(aName, nNameOffset); + pThisDictionary->SetKeyValueLength(aName, pName->GetLocation() + pName->GetLength() - nNameOffset); } aName.clear(); } @@ -1660,11 +1720,11 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> aNumbers.clear(); } rDictionary[aName] = pArray; - if (pThisObject) + if (pThisDictionary) { - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); + pThisDictionary->SetKeyOffset(aName, nNameOffset); // Include the ending ']' in the length of the key - (array)value pair length. - pThisObject->SetDictionaryKeyValueLength(aName, pEndArr->GetOffset() - nNameOffset + 1); + pThisDictionary->SetKeyValueLength(aName, pEndArr->GetOffset() - nNameOffset + 1); } aName.clear(); pArray = nullptr; @@ -1677,8 +1737,8 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> if (!pArray) { rDictionary[aName] = pReference; - if (pThisObject) - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); + if (pThisDictionary) + pThisDictionary->SetKeyOffset(aName, nNameOffset); aName.clear(); } else @@ -1693,8 +1753,8 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> if (pLiteralString) { rDictionary[aName] = pLiteralString; - if (pThisObject) - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); + if (pThisDictionary) + pThisDictionary->SetKeyOffset(aName, nNameOffset); aName.clear(); continue; } @@ -1705,8 +1765,8 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> if (!pArray) { rDictionary[aName] = pHexString; - if (pThisObject) - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); + if (pThisDictionary) + pThisDictionary->SetKeyOffset(aName, nNameOffset); aName.clear(); } else @@ -1729,11 +1789,13 @@ void PDFDictionaryElement::Parse(const std::vector< std::unique_ptr<PDFElement> if (!aNumbers.empty()) { rDictionary[aName] = aNumbers.back(); - if (pThisObject) - pThisObject->SetDictionaryKeyOffset(aName, nNameOffset); + if (pThisDictionary) + pThisDictionary->SetKeyOffset(aName, nNameOffset); aName.clear(); aNumbers.clear(); } + + return nRet; } PDFElement* PDFDictionaryElement::Lookup(const std::map<OString, PDFElement*>& rDictionary, const OString& rKey) @@ -1788,17 +1850,17 @@ sal_uInt64 PDFObjectElement::GetDictionaryOffset() return m_nDictionaryOffset; } -void PDFObjectElement::SetDictionaryKeyOffset(const OString& rKey, sal_uInt64 nOffset) +void PDFDictionaryElement::SetKeyOffset(const OString& rKey, sal_uInt64 nOffset) { m_aDictionaryKeyOffset[rKey] = nOffset; } -void PDFObjectElement::SetDictionaryKeyValueLength(const OString& rKey, sal_uInt64 nLength) +void PDFDictionaryElement::SetKeyValueLength(const OString& rKey, sal_uInt64 nLength) { m_aDictionaryKeyValueLength[rKey] = nLength; } -sal_uInt64 PDFObjectElement::GetDictionaryKeyOffset(const OString& rKey) const +sal_uInt64 PDFDictionaryElement::GetKeyOffset(const OString& rKey) const { auto it = m_aDictionaryKeyOffset.find(rKey); if (it == m_aDictionaryKeyOffset.end()) @@ -1807,7 +1869,7 @@ sal_uInt64 PDFObjectElement::GetDictionaryKeyOffset(const OString& rKey) const return it->second; } -sal_uInt64 PDFObjectElement::GetDictionaryKeyValueLength(const OString& rKey) const +sal_uInt64 PDFDictionaryElement::GetKeyValueLength(const OString& rKey) const { auto it = m_aDictionaryKeyValueLength.find(rKey); if (it == m_aDictionaryKeyValueLength.end()) @@ -1816,6 +1878,11 @@ sal_uInt64 PDFObjectElement::GetDictionaryKeyValueLength(const OString& rKey) co return it->second; } +const std::map<OString, PDFElement*>& PDFDictionaryElement::GetItems() const +{ + return m_aItems; +} + void PDFObjectElement::SetDictionaryLength(sal_uInt64 nDictionaryLength) { m_nDictionaryLength = nDictionaryLength; @@ -1829,6 +1896,16 @@ sal_uInt64 PDFObjectElement::GetDictionaryLength() return m_nDictionaryLength; } +PDFDictionaryElement* PDFObjectElement::GetDictionary() const +{ + return m_pDictionaryElement; +} + +void PDFObjectElement::SetDictionary(PDFDictionaryElement* pDictionaryElement) +{ + m_pDictionaryElement = pDictionaryElement; +} + PDFReferenceElement::PDFReferenceElement(PDFDocument& rDoc, int fObjectValue, int fGenerationValue) : m_rDoc(rDoc), m_fObjectValue(fObjectValue), _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits