[Libreoffice-commits] core.git: xmlsecurity/source
Miklos Vajna
vmiklos at collabora.co.uk
Tue Oct 25 17:53:50 UTC 2016
xmlsecurity/source/pdfio/pdfdocument.cxx | 153 +++++++++++++++++++++++--------
1 file changed, 115 insertions(+), 38 deletions(-)
New commits:
commit a3b3e336e5bd83754d9caae85dd5b9246bb4f7c1
Author: Miklos Vajna <vmiklos at 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 <vmiklos at collabora.co.uk>
Tested-by: Jenkins <ci at 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),
More information about the Libreoffice-commits
mailing list