diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-09 09:50:31 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-09 16:07:09 +0000 |
commit | 05bdc6739c6b29bcce41716000dc02d1271abd13 (patch) | |
tree | be5a0ccd090ae50e39f451304982d8170abfcbc2 /xmlsecurity | |
parent | 2e84e730a89de683c97bbcab89cd2dbf5a7a9b6d (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.cxx | 115 |
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; |