From 3e610f8496a0b6ef126426b807e0af366a98b8f3 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 4 Nov 2016 09:13:02 +0100 Subject: vcl: extract PDFWriter::GetDateTime() from PDFWriterImpl And use it in xmlsecurity when signing an existing PDF. This is especially important on Windows, where the PKCS#7 blob doesn't have an (unsigned) timestamp. Change-Id: I4051dc19a43f8f8114d9f4d02309f28d6754e9ae --- include/vcl/pdfwriter.hxx | 3 + vcl/source/gdi/pdfwriter_impl.cxx | 85 ++++++++++++++++++--------- vcl/source/gdi/pdfwriter_impl.hxx | 2 +- xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx | 12 +++- xmlsecurity/source/pdfio/pdfdocument.cxx | 6 ++ 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx index 79ac5db594a5..0e059a601658 100644 --- a/include/vcl/pdfwriter.hxx +++ b/include/vcl/pdfwriter.hxx @@ -1270,6 +1270,9 @@ The following structure describes the permissions used in PDF security /// Write rString as a PDF hex string into rBuffer. static void AppendUnicodeTextString(const OUString& rString, OStringBuffer& rBuffer); + + /// Get current date/time in PDF D:YYYYMMDDHHMMSS form. + static OString GetDateTime(); }; } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 94c730ecb5a7..80cb0a00b798 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -1855,14 +1855,67 @@ PDFWriterImpl::~PDFWriterImpl() void PDFWriterImpl::setupDocInfo() { std::vector< sal_uInt8 > aId; + m_aCreationDateString = PDFWriter::GetDateTime(); computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString ); if( m_aContext.Encryption.DocumentIdentifier.empty() ) m_aContext.Encryption.DocumentIdentifier = aId; } +OString PDFWriter::GetDateTime() +{ + OStringBuffer aRet; + + TimeValue aTVal, aGMT; + oslDateTime aDT; + osl_getSystemTime(&aGMT); + osl_getLocalTimeFromSystemTime(&aGMT, &aTVal); + osl_getDateTimeFromTimeValue(&aTVal, &aDT); + aRet.append("D:"); + aRet.append((sal_Char)('0' + ((aDT.Year / 1000) % 10))); + aRet.append((sal_Char)('0' + ((aDT.Year / 100) % 10))); + aRet.append((sal_Char)('0' + ((aDT.Year / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Year % 10))); + aRet.append((sal_Char)('0' + ((aDT.Month / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Month % 10))); + aRet.append((sal_Char)('0' + ((aDT.Day / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Day % 10))); + aRet.append((sal_Char)('0' + ((aDT.Hours / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Hours % 10))); + aRet.append((sal_Char)('0' + ((aDT.Minutes / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Minutes % 10))); + aRet.append((sal_Char)('0' + ((aDT.Seconds / 10) % 10))); + aRet.append((sal_Char)('0' + (aDT.Seconds % 10))); + + sal_uInt32 nDelta = 0; + if (aGMT.Seconds > aTVal.Seconds) + { + aRet.append("-"); + nDelta = aGMT.Seconds-aTVal.Seconds; + } + else if (aGMT.Seconds < aTVal.Seconds) + { + aRet.append("+"); + nDelta = aTVal.Seconds-aGMT.Seconds; + } + else + aRet.append("Z"); + + if (nDelta) + { + aRet.append((sal_Char)('0' + ((nDelta / 36000) % 10))); + aRet.append((sal_Char)('0' + ((nDelta / 3600) % 10))); + aRet.append("'"); + aRet.append((sal_Char)('0' + ((nDelta / 600) % 6))); + aRet.append((sal_Char)('0' + ((nDelta / 60) % 10))); + } + aRet.append( "'" ); + + return aRet.makeStringAndClear(); +} + void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, - OString& o_rCString1, + const OString& i_rCString1, OString& o_rCString2 ) { @@ -1889,22 +1942,7 @@ void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIden osl_getSystemTime( &aGMT ); osl_getLocalTimeFromSystemTime( &aGMT, &aTVal ); osl_getDateTimeFromTimeValue( &aTVal, &aDT ); - OStringBuffer aCreationDateString(64), aCreationMetaDateString(64); - aCreationDateString.append( "D:" ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); + OStringBuffer aCreationMetaDateString(64); //--> i59651, we fill the Metadata date string as well, if PDF/A is requested // according to ISO 19005-1:2005 6.7.3 the date is corrected for @@ -1935,41 +1973,30 @@ void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIden sal_uInt32 nDelta = 0; if( aGMT.Seconds > aTVal.Seconds ) { - aCreationDateString.append( "-" ); nDelta = aGMT.Seconds-aTVal.Seconds; aCreationMetaDateString.append( "-" ); } else if( aGMT.Seconds < aTVal.Seconds ) { - aCreationDateString.append( "+" ); nDelta = aTVal.Seconds-aGMT.Seconds; aCreationMetaDateString.append( "+" ); } else { - aCreationDateString.append( "Z" ); aCreationMetaDateString.append( "Z" ); } if( nDelta ) { - aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); - aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); - aCreationDateString.append( "'" ); - aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); - aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); - aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); aCreationMetaDateString.append( ":" ); aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); } - aCreationDateString.append( "'" ); - aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() ); + aID.append( i_rCString1.getStr(), i_rCString1.getLength() ); aInfoValuesOut = aID.makeStringAndClear(); - o_rCString1 = aCreationDateString.makeStringAndClear(); o_rCString2 = aCreationMetaDateString.makeStringAndClear(); rtlDigest aDigest = rtl_digest_createMD5(); diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index a49b6200eaa8..16f1fbd7f24c 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -972,7 +972,7 @@ i12626 static void computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, - OString& o_rCString1, + const OString& i_rCString1, OString& o_rCString2 ); static sal_Int32 computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index 49da58a2fbcd..5a95586e072b 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -152,7 +153,16 @@ void PDFSigningTest::testPDFAdd() OUString aInURL = aSourceDir + "no.pdf"; OUString aTargetDir = m_directories.getURLFromWorkdir("/CppunitTest/xmlsecurity_pdfsigning.test.user/"); OUString aOutURL = aTargetDir + "add.pdf"; - sign(aInURL, aOutURL, 0); + bool bHadCertificates = sign(aInURL, aOutURL, 0); + + if (bHadCertificates) + { + // Make sure the timestamp is correct. + std::vector 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(aDateTime.GetYear()), aInfos[0].stDateTime.Year); + } } void PDFSigningTest::testPDFAdd2() diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index 31ac58576469..6822e149c47b 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -356,6 +356,12 @@ bool PDFDocument::Sign(const uno::Reference& xCertificat comphelper::string::padToLength(aContentFiller, MAX_SIGNATURE_CONTENT_LENGTH, '0'); aSigBuffer.append(aContentFiller.makeStringAndClear()); aSigBuffer.append(">\n/Type/Sig/SubFilter/adbe.pkcs7.detached"); + + // Time of signing. + aSigBuffer.append(" /M ("); + aSigBuffer.append(vcl::PDFWriter::GetDateTime()); + aSigBuffer.append(")"); + // Byte range: we can write offset1-length1 and offset2 right now, will // write length2 later. aSigBuffer.append(" /ByteRange [ 0 "); -- cgit