summaryrefslogtreecommitdiff
path: root/xmlsecurity
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-11-24 17:37:09 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-11-25 07:12:48 +0000
commit5cb580144c286117db485e605c79ce1139cb94fb (patch)
tree7192fe413e895b461adea4a73f32a74a902af2c1 /xmlsecurity
parent426495cb441e6a83cd0d1f74b0ddf656322815b5 (diff)
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@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'xmlsecurity')
-rw-r--r--xmlsecurity/inc/pdfio/pdfdocument.hxx66
-rw-r--r--xmlsecurity/inc/sigstruct.hxx3
-rw-r--r--xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx28
-rw-r--r--xmlsecurity/source/pdfio/pdfdocument.cxx70
4 files changed, 93 insertions, 74 deletions
diff --git a/xmlsecurity/inc/pdfio/pdfdocument.hxx b/xmlsecurity/inc/pdfio/pdfdocument.hxx
index 31a0546deb38..e2f2913e863c 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 6dd4f7f206e2..ab455d555953 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 99e176b03b07..4d0ce52c3f7f 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 1537500c2e00..29b4a026cf2b 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");