summaryrefslogtreecommitdiffstats
path: root/xmlsecurity
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-10-21 16:00:58 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-10-21 16:19:49 +0000
commit5819448023377b81ac785dc31ccf8333562ee51f (patch)
tree84b9b5af386e13cb9c092a45f0e5f550aa4c84c2 /xmlsecurity
parentAdapt Windows-only code to deletion of the "Any-to-Any" specializatios (diff)
downloadcore-5819448023377b81ac785dc31ccf8333562ee51f.tar.gz
core-5819448023377b81ac785dc31ccf8333562ee51f.zip
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@collabora.co.uk> Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'xmlsecurity')
-rw-r--r--xmlsecurity/inc/pdfio/pdfdocument.hxx6
-rw-r--r--xmlsecurity/source/pdfio/pdfdocument.cxx42
-rw-r--r--xmlsecurity/source/pdfio/pdfverify.cxx35
3 files changed, 80 insertions, 3 deletions
diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx
index 816904f9f61f..b02bf9322088 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 479bc1c627e2..6543734a6fb5 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 5787aff41c2e..f980db8a4a78 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())