[Libreoffice-commits] core.git: xmlsecurity/inc xmlsecurity/source

Miklos Vajna vmiklos at collabora.co.uk
Fri Oct 21 16:20:22 UTC 2016


 xmlsecurity/inc/pdfio/pdfdocument.hxx    |    6 ++++
 xmlsecurity/source/pdfio/pdfdocument.cxx |   42 ++++++++++++++++++++++++++++++-
 xmlsecurity/source/pdfio/pdfverify.cxx   |   35 ++++++++++++++++++++++++-
 3 files changed, 80 insertions(+), 3 deletions(-)

New commits:
commit 5819448023377b81ac785dc31ccf8333562ee51f
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Oct 21 16:00:58 2016 +0200

    xmlsecurity: implement removal of a signature in pdfverify
    
    It's not exactly clear how one should guess what was file end before
    signing, for now assume the followings:
    
    - the file ended with a %%EOF, an optional \r, and a \n
    - the number of incremental updates is the same as the number of
      signatures
    
    When the later is not the case, don't attempt to remove the signature.
    
    Change-Id: I203a7b0605fc061ec6aacfde3a8eedc4736379f2
    Reviewed-on: https://gerrit.libreoffice.org/30140
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx
index 816904f..b02bf93 100644
--- a/xmlsecurity/inc/pdfio/pdfdocument.hxx
+++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx
@@ -46,6 +46,8 @@ class XMLSECURITY_DLLPUBLIC PDFDocument
     std::vector<size_t> m_aXRef;
     /// 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;
     /// All editing takes place in this buffer, if it happens.
     SvMemoryStream m_aEditBuffer;
@@ -65,6 +67,8 @@ public:
     size_t GetObjectOffset(size_t nIndex) const;
     const std::vector< std::unique_ptr<PDFElement> >& GetElements();
     std::vector<PDFObjectElement*> GetPages();
+    /// Remember the end location of an EOF token.
+    void PushBackEOF(size_t nOffset);
 
     bool Read(SvStream& rStream);
     /// Sign the read document with xCertificate in the edit buffer.
@@ -74,6 +78,8 @@ public:
     std::vector<PDFObjectElement*> GetSignatureWidgets();
     /// Return value is about if we can determine a result, rInformation is about the actual result.
     static bool ValidateSignature(SvStream& rStream, PDFObjectElement* pSignature, SignatureInformation& rInformation);
+    /// Remove the nth signature from read document in the edit buffer.
+    bool RemoveSignature(size_t nPosition);
 };
 
 } // namespace pdfio
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 479bc1c..6543734 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -48,9 +48,11 @@ class PDFObjectElement;
 /// A one-liner comment.
 class PDFCommentElement : public PDFElement
 {
+    PDFDocument& m_rDoc;
     OString m_aComment;
 
 public:
+    PDFCommentElement(PDFDocument& rDoc);
     bool Read(SvStream& rStream) override;
 };
 
@@ -233,6 +235,30 @@ PDFDocument::PDFDocument()
 {
 }
 
+bool PDFDocument::RemoveSignature(size_t nPosition)
+{
+    std::vector<PDFObjectElement*> aSignatures = GetSignatureWidgets();
+    if (nPosition >= aSignatures.size())
+    {
+        SAL_WARN("xmlsecurity.pdfio", "PDFDocument::RemoveSignature: invalid nPosition");
+        return false;
+    }
+
+    if (aSignatures.size() != m_aEOFs.size() - 1)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "PDFDocument::RemoveSignature: no 1:1 mapping between signatures and incremental updates");
+        return false;
+    }
+
+    // The EOF offset is the end of the original file, without the signature at
+    // nPosition.
+    m_aEditBuffer.Seek(m_aEOFs[nPosition]);
+    // Drop all bytes after the current position.
+    m_aEditBuffer.SetStreamSize(m_aEditBuffer.Tell() + 1);
+
+    return m_aEditBuffer.good();
+}
+
 bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificate, const OUString& rDescription)
 {
     m_aEditBuffer.WriteCharPtr("\n");
@@ -530,7 +556,7 @@ bool PDFDocument::Read(SvStream& rStream)
         {
         case '%':
         {
-            m_aElements.push_back(std::unique_ptr<PDFElement>(new PDFCommentElement()));
+            m_aElements.push_back(std::unique_ptr<PDFElement>(new PDFCommentElement(*this)));
             rStream.SeekRel(-1);
             if (!m_aElements.back()->Read(rStream))
                 return false;
@@ -927,6 +953,11 @@ std::vector<PDFObjectElement*> PDFDocument::GetPages()
     return aRet;
 }
 
+void PDFDocument::PushBackEOF(size_t nOffset)
+{
+    m_aEOFs.push_back(nOffset);
+}
+
 std::vector<PDFObjectElement*> PDFDocument::GetSignatureWidgets()
 {
     std::vector<PDFObjectElement*> aRet;
@@ -1288,6 +1319,11 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat
 #endif
 }
 
+PDFCommentElement::PDFCommentElement(PDFDocument& rDoc)
+    : m_rDoc(rDoc)
+{
+}
+
 bool PDFCommentElement::Read(SvStream& rStream)
 {
     // Read from (including) the % char till (excluding) the end of the line.
@@ -1299,6 +1335,10 @@ bool PDFCommentElement::Read(SvStream& rStream)
         if (ch == 0x0a)
         {
             m_aComment = aBuf.makeStringAndClear();
+
+            if (m_aComment.startsWith("%%EOF"))
+                m_rDoc.PushBackEOF(rStream.Tell());
+
             SAL_INFO("xmlsecurity.pdfio", "PDFCommentElement::Read: m_aComment is '" << m_aComment << "'");
             return true;
         }
diff --git a/xmlsecurity/source/pdfio/pdfverify.cxx b/xmlsecurity/source/pdfio/pdfverify.cxx
index 5787aff..f980db8 100644
--- a/xmlsecurity/source/pdfio/pdfverify.cxx
+++ b/xmlsecurity/source/pdfio/pdfverify.cxx
@@ -62,6 +62,10 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(nArgc, pArgv)
     if (nArgc > 2)
         osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pArgv[2]), aOutURL);
 
+    bool bRemoveSignature = false;
+    if (nArgc > 3 && OString(pArgv[3]) == "-r")
+        bRemoveSignature = true;
+
     SvFileStream aStream(aInURL, StreamMode::READ);
     xmlsecurity::pdfio::PDFDocument aDocument;
     if (!aDocument.Read(aStream))
@@ -70,9 +74,36 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(nArgc, pArgv)
         return 1;
     }
 
+    if (bRemoveSignature)
+    {
+        std::cerr << "removing the last signature" << std::endl;
+        std::vector<xmlsecurity::pdfio::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets();
+        if (aSignatures.empty())
+        {
+            std::cerr << "found no signatures" << std::endl;
+            return 1;
+        }
+
+        size_t nPosition = aSignatures.size() - 1;
+        if (!aDocument.RemoveSignature(nPosition))
+        {
+            SAL_WARN("xmlsecurity.pdfio", "failed to remove signature #" << nPosition);
+            return 1;
+        }
+
+        SvFileStream aOutStream(aOutURL, StreamMode::WRITE | StreamMode::TRUNC);
+        if (!aDocument.Write(aOutStream))
+        {
+            SAL_WARN("xmlsecurity.pdfio", "failed to write the document");
+            return 1;
+        }
+
+        return 0;
+    }
+
     if (aOutURL.isEmpty())
     {
-        // Verify.
+        std::cerr << "verifying signatures" << std::endl;
         std::vector<xmlsecurity::pdfio::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets();
         if (aSignatures.empty())
             std::cerr << "found no signatures" << std::endl;
@@ -96,7 +127,7 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(nArgc, pArgv)
         return 0;
     }
 
-    // Sign.
+    std::cerr << "adding a new signature" << std::endl;
     uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment = xSecurityContext->getSecurityEnvironment();
     uno::Sequence<uno::Reference<security::XCertificate>> aCertificates = xSecurityEnvironment->getPersonalCertificates();
     if (!aCertificates.hasElements())


More information about the Libreoffice-commits mailing list