[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.3' - filter/source include/vcl vcl/Library_vcl.mk vcl/source
Tor Lillqvist
tml at collabora.com
Fri Dec 12 13:58:01 PST 2014
filter/source/pdf/impdialog.cxx | 18 +--
filter/source/pdf/impdialog.hrc | 4
filter/source/pdf/impdialog.src | 10 +
filter/source/pdf/pdfexport.cxx | 2
include/vcl/pdfwriter.hxx | 5
vcl/Library_vcl.mk | 4
vcl/source/gdi/pdfwriter_impl.cxx | 202 ++++++++++++++++++++++++++++++++------
7 files changed, 203 insertions(+), 42 deletions(-)
New commits:
commit 4ffc81782072148f8ffeb9793c4bf4421866eefe
Author: Tor Lillqvist <tml at collabora.com>
Date: Wed Dec 3 14:00:38 2014 +0200
PDF signing feature backported from 4.4
Cherry picked from:
840f75065918c4584fa9159fdc90242b5374ab37
1fe9ee73a758603ee0e1465931352c41ef8bd999
d8a8ff8177df628636d80c4dc1d8f597f6677dfc
bfa01d8a8248f7e44675de5ed1f85a1d17105022
bbb18f679f5a50e9c709520d6c3260d3d9db5aa9
c4cc31b5b55019aabad4045c8174b45e1b27073a
7e3c931786c3cbe83ee170b8b0746d141b520ce6
070c93af73df9aa4eb333265c81060d123b530b9
6e91763769a562b88882a4c2a94b1367c6ed4866
Change-Id: Ie8ac5e1e067f8e3b15e2f11389bd0517d348f1e3
diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx
index 0825ea0..7cffddd 100644
--- a/filter/source/pdf/impdialog.cxx
+++ b/filter/source/pdf/impdialog.cxx
@@ -251,11 +251,6 @@ ImpPDFTabDialog::ImpPDFTabDialog(Window* pParent, Sequence< PropertyValue >& rFi
mnInterfacePageId = AddTabPage("userinterface", ImpPDFTabViewerPage::Create, 0);
mnViewPageId = AddTabPage("initialview", ImpPDFTabOpnFtrPage::Create, 0);
-//remove tabpage if experimentalmode is not set
- SvtMiscOptions aMiscOptions;
- if (!aMiscOptions.IsExperimentalMode())
- RemoveTabPage(mnSigningPageId);
-
//last queued is the first to be displayed (or so it seems..)
mnGeneralPageId = AddTabPage("general", ImpPDFTabGeneralPage::Create, 0 );
@@ -322,11 +317,7 @@ ImpPDFTabDialog::~ImpPDFTabDialog()
RemoveTabPage(mnViewPageId);
RemoveTabPage(mnLinksPage);
RemoveTabPage(mnSecurityPageId);
-
-//remove tabpage if experimentalmode is set
- SvtMiscOptions aMiscOptions;
- if (aMiscOptions.IsExperimentalMode())
- RemoveTabPage(mnSigningPageId);
+ RemoveTabPage(mnSigningPageId);
}
@@ -1495,6 +1486,13 @@ ImplErrorDialog::ImplErrorDialog(const std::set< vcl::PDFWriter::ErrorCode >& rE
m_pErrors->SetEntryData( nPos, new OUString( PDFFilterResId( STR_WARN_TRANSP_CONVERTED ) ) );
}
break;
+ case vcl::PDFWriter::Error_Signature_Failed:
+ {
+ sal_uInt16 nPos = m_pErrors->InsertEntry( OUString( PDFFilterResId( STR_ERR_SIGNATURE_FAILED ) ),
+ aErrImg );
+ m_pErrors->SetEntryData( nPos, new OUString( PDFFilterResId( STR_ERR_PDF_EXPORT_ABORTED ) ) );
+ }
+ break;
default:
break;
}
diff --git a/filter/source/pdf/impdialog.hrc b/filter/source/pdf/impdialog.hrc
index 0927cb0..3b03503 100644
--- a/filter/source/pdf/impdialog.hrc
+++ b/filter/source/pdf/impdialog.hrc
@@ -19,6 +19,9 @@
#include <filter.hrc>
+#define STR_ERR_SIGNATURE_FAILED (RID_PDF_DIALOG_START + 0)
+#define STR_ERR_PDF_EXPORT_ABORTED (RID_PDF_DIALOG_START + 1)
+
#define RID_PDF_WARNPDFAPASSWORD (RID_PDF_DIALOG_START + 6)
//strings for PDF security, user password management
@@ -39,5 +42,6 @@
#define IMG_ERR (RID_PDF_DIALOG_START + 18)
//ATTENTION: maximum allowed value is (RID_PDF_DIALOG_START + 19)
+//(see filter/inc/filter.hrc)
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/pdf/impdialog.src b/filter/source/pdf/impdialog.src
index 32d81a4..1aee2df 100644
--- a/filter/source/pdf/impdialog.src
+++ b/filter/source/pdf/impdialog.src
@@ -79,6 +79,16 @@ String STR_WARN_TRANSP_CONVERTED_SHORT
Text [en-US] = "Transparencies removed";
};
+String STR_ERR_SIGNATURE_FAILED
+{
+ Text [en-US] = "Signature generation failed";
+};
+
+String STR_ERR_PDF_EXPORT_ABORTED
+{
+ Text [en-US] = "PDF export aborted";
+};
+
Bitmap IMG_WARN
{
File = "ballgreen_7.png";
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index 8aceae6..164eff9 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -915,7 +915,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
if( bRet )
{
pPDFExtOutDevData->PlayGlobalActions( *pPDFWriter );
- pPDFWriter->Emit();
+ bRet = pPDFWriter->Emit();
aErrors = pPDFWriter->GetErrors();
}
pOut->SetExtOutDevData( NULL );
diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index d4b6e90..9357c91 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -215,7 +215,10 @@ public:
// transparent objects were converted to a bitmap in order
// to removetransparencies from the output
- Warning_Transparency_Converted
+ Warning_Transparency_Converted,
+
+ // signature generation failed
+ Error_Signature_Failed,
};
struct VCL_DLLPUBLIC AnyWidget
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 4e53256..aed7a60 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -55,7 +55,8 @@ $(eval $(call gb_Library_use_custom_headers,vcl,\
$(eval $(call gb_Library_use_externals,vcl,\
jpeg \
- nss3 \
+ $(if $(filter-out WNT,$(OS)), \
+ nss3) \
libeot \
))
@@ -625,6 +626,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
$(eval $(call gb_Library_use_system_win32_libs,vcl,\
advapi32 \
+ crypt32 \
gdi32 \
gdiplus \
imm32 \
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 5548629..7d7b779 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -66,8 +66,8 @@
#include "pdfwriter_impl.hxx"
-#if !defined(ANDROID) && !defined(IOS)
-// NSS header files for PDF signing support
+#if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
+// NSS headers for PDF signing
#include "nss.h"
#include "cert.h"
#include "hasht.h"
@@ -76,6 +76,13 @@
#include "cmst.h"
#endif
+#ifdef _WIN32
+// WinCrypt headers for PDF signing
+#include <prewin.h>
+#include <wincrypt.h>
+#include <postwin.h>
+#endif
+
#include <config_eot.h>
#if ENABLE_EOT
@@ -5940,6 +5947,8 @@ bool PDFWriterImpl::emitSignature()
return true;
}
+#if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
+
char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
{
return (char *)arg;
@@ -5956,6 +5965,39 @@ namespace {
};
}
+#endif
+
+#ifdef _WIN32
+
+namespace {
+
+OUString WindowsError(DWORD nErrorCode)
+{
+ LPWSTR pMsgBuf;
+
+ if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ nErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&pMsgBuf,
+ 0,
+ NULL) == 0)
+ return OUString::number(nErrorCode, 16);
+
+ if (pMsgBuf[wcslen(pMsgBuf)-1] == '\n')
+ pMsgBuf[wcslen(pMsgBuf)-1] = '\0';
+
+ OUString result(pMsgBuf);
+
+ LocalFree(pMsgBuf);
+
+ return result;
+}
+
+}
+
+#endif
+
bool PDFWriterImpl::finalizeSignature()
{
@@ -5990,25 +6032,23 @@ bool PDFWriterImpl::finalizeSignature()
sal_Int8* n_derArray = derEncoded.getArray();
sal_Int32 n_derLength = derEncoded.getLength();
- NSS_NoDB_Init(".");
+#ifndef _WIN32
CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(n_derArray), n_derLength);
if (!cert)
{
- SAL_WARN("vcl.gdi", "PDF Signing: Error occurred, certificate cannot be reconstructed.");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: Error occurred, certificate cannot be reconstructed.");
return false;
}
- SAL_WARN("vcl.gdi", "PDF Signing: Certificate Subject: " << cert->subjectName << "\n\tCertificate Issuer: " << cert->issuerName);
-
// Prepare buffer and calculate PDF file digest
CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, 0) ) );
HashContextScope hc(HASH_Create(HASH_AlgSHA1));
if (!hc.get())
{
- SAL_WARN("vcl.gdi", "PDF Signing: SHA1 HASH_Create failed!");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: SHA1 HASH_Create failed!");
return false;
}
@@ -6021,7 +6061,7 @@ bool PDFWriterImpl::finalizeSignature()
CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer.get(), m_nSignatureContentOffset - 1 , &bytesRead ) ) );
if (bytesRead != (sal_uInt64)m_nSignatureContentOffset - 1)
- SAL_WARN("vcl.gdi", "PDF Signing: First buffer read failed!");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: First buffer read failed!");
HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
@@ -6029,7 +6069,7 @@ bool PDFWriterImpl::finalizeSignature()
buffer.reset(new char[nLastByteRangeNo + 1]);
CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer.get(), nLastByteRangeNo, &bytesRead ) ) );
if (bytesRead != (sal_uInt64) nLastByteRangeNo)
- SAL_WARN("vcl.gdi", "PDF Signing: Second buffer read failed!");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: Second buffer read failed!");
HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
@@ -6044,21 +6084,21 @@ bool PDFWriterImpl::finalizeSignature()
NSSCMSMessage *cms_msg = NSS_CMSMessage_Create(NULL);
if (!cms_msg)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't create new CMS message.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't create new CMS message.");
return false;
}
NSSCMSSignedData *cms_sd = NSS_CMSSignedData_Create(cms_msg);
if (!cms_sd)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't create CMS SignedData.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't create CMS SignedData.");
return false;
}
NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(cms_msg);
if (NSS_CMSContentInfo_SetContent_SignedData(cms_msg, cms_cinfo, cms_sd) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: Can't set CMS content signed data.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: Can't set CMS content signed data.");
return false;
}
@@ -6066,49 +6106,47 @@ bool PDFWriterImpl::finalizeSignature()
//attach NULL data as detached data
if (NSS_CMSContentInfo_SetContent_Data(cms_msg, cms_cinfo, NULL, PR_TRUE) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: Can't set CMS content data.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: Can't set CMS content data.");
return false;
}
NSSCMSSignerInfo *cms_signer = NSS_CMSSignerInfo_Create(cms_msg, cert, SEC_OID_SHA1);
if (!cms_signer)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't create CMS SignerInfo.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't create CMS SignerInfo.");
return false;
}
if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't include cert chain.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't include cert chain.");
return false;
}
if (NSS_CMSSignerInfo_AddSigningTime(cms_signer, PR_Now()) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't add signing time.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't add signing time.");
return false;
}
if (NSS_CMSSignedData_AddCertificate(cms_sd, cert) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't add signer certificate.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't add signer certificate.");
return false;
}
if (NSS_CMSSignedData_AddSignerInfo(cms_sd, cms_signer) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't add signer info.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't add signer info.");
return false;
}
if (NSS_CMSSignedData_SetDigestValue(cms_sd, SEC_OID_SHA1, &digest) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF signing: can't set PDF digest value.");
+ SAL_WARN("vcl.pdfwriter", "PDF signing: can't set PDF digest value.");
return false;
}
- SAL_WARN("vcl.gdi","PKCS7 Object created successfully!");
-
SECItem cms_output;
cms_output.data = 0;
cms_output.len = 0;
@@ -6120,25 +6158,21 @@ bool PDFWriterImpl::finalizeSignature()
if (!cms_ecx)
{
- SAL_WARN("vcl.gdi", "PDF Signing: can't start DER encoder.");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: can't start DER encoder.");
return false;
}
- SAL_WARN("vcl.gdi", "PDF Signing: Started DER encoding.");
if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
{
- SAL_WARN("vcl.gdi", "PDF Signing: can't finish DER encoder.");
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: can't finish DER encoder.");
return false;
}
- SAL_WARN("vcl.gdi", "PDF Signing: Finished DER encoding.");
OStringBuffer cms_hexbuffer;
for (unsigned int i = 0; i < cms_output.len ; i++)
appendHex(cms_output.data[i], cms_hexbuffer);
- SAL_WARN("vcl.gdi","PKCS7 object encoded successfully!");
-
// Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
nWritten = 0;
CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset) ) );
@@ -6148,6 +6182,104 @@ bool PDFWriterImpl::finalizeSignature()
CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, nOffset ) ) );
return true;
+
+#else
+
+ // Prepare buffer and calculate PDF file digest
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos(m_aFile, osl_Pos_Absolut, 0)));
+
+ PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(n_derArray), n_derLength);
+ if (pCertContext == NULL)
+ {
+ SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsError(GetLastError()));
+ return false;
+ }
+
+ boost::scoped_array<char> buffer1(new char[m_nSignatureContentOffset - 1]);
+ sal_uInt64 bytesRead1;
+
+ if (osl_File_E_None != osl_readFile(m_aFile, buffer1.get(), m_nSignatureContentOffset - 1 , &bytesRead1) ||
+ bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1)
+ {
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: First buffer read failed!");
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ boost::scoped_array<char> buffer2(new char[nLastByteRangeNo]);
+ sal_uInt64 bytesRead2;
+
+ if (osl_File_E_None != osl_setFilePos(m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1) ||
+ osl_File_E_None != osl_readFile(m_aFile, buffer2.get(), nLastByteRangeNo, &bytesRead2) ||
+ bytesRead2 != (sal_uInt64) nLastByteRangeNo)
+ {
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: Second buffer read failed!");
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ OString pass = OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 );
+
+ CRYPT_SIGN_MESSAGE_PARA aPara;
+
+ memset(&aPara, 0, sizeof(aPara));
+ aPara.cbSize = sizeof(aPara);
+ aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
+ aPara.pSigningCert = pCertContext;
+ aPara.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
+ aPara.HashAlgorithm.Parameters.cbData = 0;
+ aPara.cMsgCert = 1;
+ aPara.rgpMsgCert = &pCertContext;
+
+ const BYTE *aBuffers[] =
+ { reinterpret_cast<BYTE*>(buffer1.get()), reinterpret_cast<BYTE*>(buffer2.get()) };
+ DWORD aBufferLens[] =
+ { bytesRead1, bytesRead2 };
+ assert(SAL_N_ELEMENTS(aBuffers) == SAL_N_ELEMENTS(aBufferLens));
+
+ DWORD nSigLen(0);
+
+ if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, NULL, &nSigLen))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+ {
+ SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ SAL_INFO("vcl.pdfwriter", "Signature size is " << nSigLen << " bytes");
+
+ boost::scoped_array<BYTE> pSig(new BYTE[nSigLen]);
+ if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, pSig.get(), &nSigLen))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ // Release resources
+ CertFreeCertificateContext(pCertContext);
+
+ OStringBuffer cms_hexbuffer;
+
+ for (unsigned int i = 0; i < nSigLen ; i++)
+ appendHex(pSig[i], cms_hexbuffer);
+
+ // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
+ nWritten = 0;
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos(m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset)) );
+ osl_writeFile(m_aFile, cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), &nWritten);
+
+ CHECK_RETURN( (osl_File_E_None == osl_setFilePos(m_aFile, osl_Pos_Absolut, nOffset)) );
+
+ return true;
+#endif
}
#endif
@@ -6951,7 +7083,13 @@ bool PDFWriterImpl::emit()
#if !defined(ANDROID) && !defined(IOS)
if (m_nSignatureObject != -1) // if document is signed, emit sigdict
- CHECK_RETURN( emitSignature() );
+ {
+ if( !emitSignature() )
+ {
+ m_aErrors.insert( PDFWriter::Error_Signature_Failed );
+ return false;
+ }
+ }
#endif
// emit trailer
@@ -6959,7 +7097,13 @@ bool PDFWriterImpl::emit()
#if !defined(ANDROID) && !defined(IOS)
if (m_nSignatureObject != -1) // finalize the signature
- CHECK_RETURN( finalizeSignature() );
+ {
+ if( !finalizeSignature() )
+ {
+ m_aErrors.insert( PDFWriter::Error_Signature_Failed );
+ return false;
+ }
+ }
#endif
osl_closeFile( m_aFile );
More information about the Libreoffice-commits
mailing list