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

Miklos Vajna vmiklos at collabora.co.uk
Fri Nov 25 07:13:15 UTC 2016


 xmlsecurity/inc/pdfio/pdfdocument.hxx         |   66 ++++++++++++++++++++++++
 xmlsecurity/inc/sigstruct.hxx                 |    3 +
 xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx |   28 +++++++---
 xmlsecurity/source/pdfio/pdfdocument.cxx      |   70 +-------------------------
 4 files changed, 93 insertions(+), 74 deletions(-)

New commits:
commit 5cb580144c286117db485e605c79ce1139cb94fb
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Nov 24 17:37:09 2016 +0100

    CppunitTest_xmlsecurity_pdfsigning: add PAdES testcase
    
    Assert the two user-visible changes: SHA-256 hashes and the SubFilter of the
    signature.
    
    Change-Id: I12a2355e2ddfc368bed4430a7b5ad244b5778afe
    Reviewed-on: https://gerrit.libreoffice.org/31173
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx
index 31a0546..e2f2913 100644
--- a/xmlsecurity/inc/pdfio/pdfdocument.hxx
+++ b/xmlsecurity/inc/pdfio/pdfdocument.hxx
@@ -27,9 +27,12 @@ namespace pdfio
 {
 
 class PDFTrailerElement;
-class PDFObjectElement;
 class PDFHexStringElement;
 class PDFReferenceElement;
+class PDFDocument;
+class PDFDictionaryElement;
+class PDFArrayElement;
+class PDFStreamElement;
 
 /// A byte range in a PDF file.
 class PDFElement
@@ -39,6 +42,67 @@ public:
     virtual ~PDFElement() { }
 };
 
+/// Indirect object: something with a unique ID.
+class XMLSECURITY_DLLPUBLIC PDFObjectElement : public PDFElement
+{
+    PDFDocument& m_rDoc;
+    double m_fObjectValue;
+    double m_fGenerationValue;
+    std::map<OString, PDFElement*> m_aDictionary;
+    /// Position after the '<<' token.
+    sal_uInt64 m_nDictionaryOffset;
+    /// Length of the dictionary buffer till (before) the '<<' token.
+    sal_uInt64 m_nDictionaryLength;
+    PDFDictionaryElement* m_pDictionaryElement;
+    /// The contained direct array, if any.
+    PDFArrayElement* m_pArrayElement;
+    /// The stream of this object, used when this is an object stream.
+    PDFStreamElement* m_pStreamElement;
+    /// Objects of an object stream.
+    std::vector< std::unique_ptr<PDFObjectElement> > m_aStoredElements;
+    /// Elements of an object in an object stream.
+    std::vector< std::unique_ptr<PDFElement> > m_aElements;
+    /// Uncompressed buffer of an object in an object stream.
+    std::unique_ptr<SvMemoryStream> m_pStreamBuffer;
+
+public:
+    PDFObjectElement(PDFDocument& rDoc, double fObjectValue, double fGenerationValue);
+    bool Read(SvStream& rStream) override;
+    PDFElement* Lookup(const OString& rDictionaryKey);
+    PDFObjectElement* LookupObject(const OString& rDictionaryKey);
+    double GetObjectValue() const;
+    void SetDictionaryOffset(sal_uInt64 nDictionaryOffset);
+    sal_uInt64 GetDictionaryOffset();
+    void SetDictionaryLength(sal_uInt64 nDictionaryLength);
+    sal_uInt64 GetDictionaryLength();
+    PDFDictionaryElement* GetDictionary() const;
+    void SetDictionary(PDFDictionaryElement* pDictionaryElement);
+    void SetArray(PDFArrayElement* pArrayElement);
+    void SetStream(PDFStreamElement* pStreamElement);
+    PDFArrayElement* GetArray() const;
+    /// Parse objects stored in this object stream.
+    void ParseStoredObjects();
+    std::vector< std::unique_ptr<PDFElement> >& GetStoredElements();
+    SvMemoryStream* GetStreamBuffer() const;
+    void SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamBuffer);
+};
+
+/// Name object: a key string.
+class XMLSECURITY_DLLPUBLIC PDFNameElement : public PDFElement
+{
+    OString m_aValue;
+    /// Offset after the '/' token.
+    sal_uInt64 m_nLocation;
+    /// Length till the next token start.
+    sal_uInt64 m_nLength;
+public:
+    PDFNameElement();
+    bool Read(SvStream& rStream) override;
+    const OString& GetValue() const;
+    sal_uInt64 GetLocation() const;
+    sal_uInt64 GetLength() const;
+};
+
 enum class TokenizeMode
 {
     /// Full file.
diff --git a/xmlsecurity/inc/sigstruct.hxx b/xmlsecurity/inc/sigstruct.hxx
index 6dd4f7f..ab455d5 100644
--- a/xmlsecurity/inc/sigstruct.hxx
+++ b/xmlsecurity/inc/sigstruct.hxx
@@ -102,11 +102,14 @@ struct SignatureInformation
     OUString ouCertDigest;
     /// A full OOXML signguature for unchanged roundtrip, empty for ODF.
     css::uno::Sequence<sal_Int8> aSignatureBytes;
+    /// For PDF: digest format, from css::xml::crypto::DigestID
+    sal_Int32 nDigestID;
 
     SignatureInformation( sal_Int32 nId )
     {
         nSecurityId = nId;
         nStatus = css::xml::crypto::SecurityOperationStatus_UNKNOWN;
+        nDigestID = 0;
     }
 };
 
diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index 99e176b..4d0ce52 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -40,7 +40,7 @@ class PDFSigningTest : public test::BootstrapFixture
      * Read a pdf and make sure that it has the expected number of valid
      * signatures.
      */
-    std::vector<SignatureInformation> verify(const OUString& rURL, size_t nCount);
+    std::vector<SignatureInformation> verify(const OUString& rURL, size_t nCount, const OString& rExpectedSubFilter);
 
 public:
     PDFSigningTest();
@@ -98,7 +98,7 @@ void PDFSigningTest::setUp()
 #endif
 }
 
-std::vector<SignatureInformation> PDFSigningTest::verify(const OUString& rURL, size_t nCount)
+std::vector<SignatureInformation> PDFSigningTest::verify(const OUString& rURL, size_t nCount, const OString& rExpectedSubFilter)
 {
     uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(mxComponentContext);
     uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext = xSEInitializer->createSecurityContext(OUString());
@@ -115,6 +115,15 @@ std::vector<SignatureInformation> PDFSigningTest::verify(const OUString& rURL, s
         bool bLast = i == aSignatures.size() - 1;
         CPPUNIT_ASSERT(xmlsecurity::pdfio::PDFDocument::ValidateSignature(aStream, aSignatures[i], aInfo, bLast));
         aRet.push_back(aInfo);
+
+        if (!rExpectedSubFilter.isEmpty())
+        {
+            xmlsecurity::pdfio::PDFObjectElement* pValue = aSignatures[i]->LookupObject("V");
+            CPPUNIT_ASSERT(pValue);
+            auto pSubFilter = dynamic_cast<xmlsecurity::pdfio::PDFNameElement*>(pValue->Lookup("SubFilter"));
+            CPPUNIT_ASSERT(pSubFilter);
+            CPPUNIT_ASSERT_EQUAL(rExpectedSubFilter, pSubFilter->GetValue());
+        }
     }
 
     return aRet;
@@ -148,7 +157,7 @@ bool PDFSigningTest::sign(const OUString& rInURL, const OUString& rOutURL, size_
     }
 
     // This was nOriginalSignatureCount when PDFDocument::Sign() silently returned success, without doing anything.
-    verify(rOutURL, nOriginalSignatureCount + 1);
+    verify(rOutURL, nOriginalSignatureCount + 1, /*rExpectedSubFilter=*/OString());
 
     return true;
 }
@@ -163,11 +172,14 @@ void PDFSigningTest::testPDFAdd()
 
     if (bHadCertificates)
     {
+        // Assert that the SubFilter is not adbe.pkcs7.detached in the bAdES case.
+        std::vector<SignatureInformation> aInfos = verify(aOutURL, 1, "ETSI.CAdES.detached");
         // Make sure the timestamp is correct.
-        std::vector<SignatureInformation> aInfos = verify(aOutURL, 1);
         DateTime aDateTime(DateTime::SYSTEM);
         // This was 0 (on Windows), as neither the /M key nor the PKCS#7 blob contained a timestamp.
         CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(aDateTime.GetYear()), aInfos[0].stDateTime.Year);
+        // Assert that the digest algorithm is not SHA-1 in the bAdES case.
+        CPPUNIT_ASSERT_EQUAL(xml::crypto::DigestID::SHA256, aInfos[0].nDigestID);
     }
 }
 
@@ -218,7 +230,7 @@ void PDFSigningTest::testPDFRemove()
     // Read back the pdf and make sure that it no longer has signatures.
     // This failed when PDFDocument::RemoveSignature() silently returned
     // success, without doing anything.
-    verify(aOutURL, 0);
+    verify(aOutURL, 0, /*rExpectedSubFilter=*/OString());
 }
 
 void PDFSigningTest::testPDFRemoveAll()
@@ -259,7 +271,7 @@ void PDFSigningTest::testPDF14Adobe()
     // Two signatures, first is SHA1, the second is SHA256.
     // This was 0, as we failed to find the Annots key's value when it was a
     // reference-to-array, not an array.
-    std::vector<SignatureInformation> aInfos = verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf14adobe.pdf", 2);
+    std::vector<SignatureInformation> aInfos = verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf14adobe.pdf", 2, /*rExpectedSubFilter=*/OString());
     // This was 0, out-of-PKCS#7 signature date wasn't read.
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(2016), aInfos[1].stDateTime.Year);
 }
@@ -270,7 +282,7 @@ void PDFSigningTest::testPDF16Adobe()
     // stream with a predictor. And a valid signature.
     // Found signatures was 0, as parsing failed due to lack of support for
     // these features.
-    verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf16adobe.pdf", 1);
+    verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf16adobe.pdf", 1, /*rExpectedSubFilter=*/OString());
 }
 
 void PDFSigningTest::testPDF16Add()
@@ -299,7 +311,7 @@ void PDFSigningTest::testPDF14LOWin()
     // algorithm when it meant SEC_OID_SHA1, make sure we tolerate that on all
     // platforms.
     // This failed, as NSS HASH_Create() didn't handle the sign algorithm.
-    verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf14lowin.pdf", 1);
+    verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf14lowin.pdf", 1, /*rExpectedSubFilter=*/OString());
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(PDFSigningTest);
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 1537500..29b4a02 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -54,7 +54,6 @@ namespace pdfio
 const int MAX_SIGNATURE_CONTENT_LENGTH = 50000;
 
 class PDFTrailerElement;
-class PDFObjectElement;
 
 /// A one-liner comment.
 class PDFCommentElement : public PDFElement
@@ -85,54 +84,6 @@ public:
 };
 
 class PDFReferenceElement;
-class PDFDictionaryElement;
-class PDFArrayElement;
-class PDFStreamElement;
-
-/// Indirect object: something with a unique ID.
-class PDFObjectElement : public PDFElement
-{
-    PDFDocument& m_rDoc;
-    double m_fObjectValue;
-    double m_fGenerationValue;
-    std::map<OString, PDFElement*> m_aDictionary;
-    /// Position after the '<<' token.
-    sal_uInt64 m_nDictionaryOffset;
-    /// Length of the dictionary buffer till (before) the '<<' token.
-    sal_uInt64 m_nDictionaryLength;
-    PDFDictionaryElement* m_pDictionaryElement;
-    /// The contained direct array, if any.
-    PDFArrayElement* m_pArrayElement;
-    /// The stream of this object, used when this is an object stream.
-    PDFStreamElement* m_pStreamElement;
-    /// Objects of an object stream.
-    std::vector< std::unique_ptr<PDFObjectElement> > m_aStoredElements;
-    /// Elements of an object in an object stream.
-    std::vector< std::unique_ptr<PDFElement> > m_aElements;
-    /// Uncompressed buffer of an object in an object stream.
-    std::unique_ptr<SvMemoryStream> m_pStreamBuffer;
-
-public:
-    PDFObjectElement(PDFDocument& rDoc, double fObjectValue, double fGenerationValue);
-    bool Read(SvStream& rStream) override;
-    PDFElement* Lookup(const OString& rDictionaryKey);
-    PDFObjectElement* LookupObject(const OString& rDictionaryKey);
-    double GetObjectValue() const;
-    void SetDictionaryOffset(sal_uInt64 nDictionaryOffset);
-    sal_uInt64 GetDictionaryOffset();
-    void SetDictionaryLength(sal_uInt64 nDictionaryLength);
-    sal_uInt64 GetDictionaryLength();
-    PDFDictionaryElement* GetDictionary() const;
-    void SetDictionary(PDFDictionaryElement* pDictionaryElement);
-    void SetArray(PDFArrayElement* pArrayElement);
-    void SetStream(PDFStreamElement* pStreamElement);
-    PDFArrayElement* GetArray() const;
-    /// Parse objects stored in this object stream.
-    void ParseStoredObjects();
-    std::vector< std::unique_ptr<PDFElement> >& GetStoredElements();
-    SvMemoryStream* GetStreamBuffer() const;
-    void SetStreamBuffer(std::unique_ptr<SvMemoryStream>& pStreamBuffer);
-};
 
 /// Dictionary object: a set key-value pairs.
 class PDFDictionaryElement : public PDFElement
@@ -170,22 +121,6 @@ public:
     sal_uInt64 GetLocation() const;
 };
 
-/// Name object: a key string.
-class PDFNameElement : public PDFElement
-{
-    OString m_aValue;
-    /// Offset after the '/' token.
-    sal_uInt64 m_nLocation;
-    /// Length till the next token start.
-    sal_uInt64 m_nLength;
-public:
-    PDFNameElement();
-    bool Read(SvStream& rStream) override;
-    const OString& GetValue() const;
-    sal_uInt64 GetLocation() const;
-    sal_uInt64 GetLength() const;
-};
-
 /// Reference object: something with a unique ID.
 class PDFReferenceElement : public PDFElement
 {
@@ -2239,9 +2174,14 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat
     {
     case SEC_OID_SHA1:
         nMaxResultLen = msfilter::SHA1_HASH_LENGTH;
+        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
         break;
     case SEC_OID_SHA256:
         nMaxResultLen = msfilter::SHA256_HASH_LENGTH;
+        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
+        break;
+    case SEC_OID_SHA512:
+        nMaxResultLen = msfilter::SHA512_HASH_LENGTH;
         break;
     default:
         SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ValidateSignature: unrecognized algorithm");


More information about the Libreoffice-commits mailing list