diff options
author | Gökçen Eraslan <gokcen.eraslan@gmail.com> | 2012-07-09 10:16:17 +0300 |
---|---|---|
committer | Gökçen Eraslan <gokcen.eraslan@gmail.com> | 2012-07-09 10:16:17 +0300 |
commit | 9c8dc01d3a40ec905c9d816c733ceb5d621e0426 (patch) | |
tree | ed4182827ad2645a621fcde32887f6d0c5248740 | |
parent | f8f2296a510612381fc86273d0380133d5929bf0 (diff) | |
parent | 9ba7fda79cd36a20732fee663f52bdb4946cb2cf (diff) |
Merge branch 'feature/pdf-signing'
-rw-r--r-- | filter/inc/filter.hrc | 1 | ||||
-rw-r--r-- | filter/source/pdf/impdialog.cxx | 155 | ||||
-rw-r--r-- | filter/source/pdf/impdialog.hrc | 13 | ||||
-rw-r--r-- | filter/source/pdf/impdialog.hxx | 39 | ||||
-rw-r--r-- | filter/source/pdf/impdialog.src | 90 | ||||
-rw-r--r-- | filter/source/pdf/pdfexport.cxx | 20 | ||||
-rw-r--r-- | filter/source/pdf/pdfexport.hxx | 8 | ||||
-rw-r--r-- | offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 4 | ||||
-rw-r--r-- | vcl/inc/vcl/pdfwriter.hxx | 37 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 231 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.hxx | 9 | ||||
-rw-r--r-- | xmlsecurity/source/component/documentdigitalsignatures.cxx | 23 | ||||
-rw-r--r-- | xmlsecurity/source/component/documentdigitalsignatures.hxx | 1 |
13 files changed, 612 insertions, 19 deletions
diff --git a/filter/inc/filter.hrc b/filter/inc/filter.hrc index dc1c348bcc05..0aac90775665 100644 --- a/filter/inc/filter.hrc +++ b/filter/inc/filter.hrc @@ -37,6 +37,7 @@ #define HID_FILTER_PDF_USER_INTERFACE "HID_FILTER_PDF_USER_INTERFACE" #define HID_FILTER_PDF_SECURITY "HID_FILTER_PDF_SECURITY" #define HID_FILTER_PDF_LINKS "HID_FILTER_PDF_LINKS" +#define HID_FILTER_PDF_SIGNING "HID_FILTER_PDF_SIGNING" #endif diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx index 03de7492d46a..f6f9b158864f 100644 --- a/filter/source/pdf/impdialog.cxx +++ b/filter/source/pdf/impdialog.cxx @@ -32,6 +32,8 @@ #include "vcl/svapp.hxx" #include "vcl/msgbox.hxx" #include "sfx2/passwd.hxx" +#include "svtools/miscopt.hxx" +//#include "xmlsecurity/certificatechooser.hxx" #include "comphelper/storagehelper.hxx" @@ -40,6 +42,7 @@ #include "com/sun/star/container/XIndexAccess.hpp" #include "com/sun/star/frame/XController.hpp" #include "com/sun/star/view/XSelectionSupplier.hpp" +#include "com/sun/star/security/XDocumentDigitalSignatures.hpp" #include <boost/shared_ptr.hpp> @@ -124,7 +127,10 @@ ImpPDFTabDialog::ImpPDFTabDialog( Window* pParent, mbExportRelativeFsysLinks( sal_False ), mnViewPDFMode( 0 ), mbConvertOOoTargets( sal_False ), - mbExportBmkToPDFDestination( sal_False ) + mbExportBmkToPDFDestination( sal_False ), + + mbSignPDF( sal_False ) + { FreeResource(); // check for selection @@ -241,12 +247,21 @@ ImpPDFTabDialog::ImpPDFTabDialog( Window* pParent, mbConvertOOoTargets = maConfigItem.ReadBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ConvertOOoTargetToPDFTarget" ) ), sal_False ); mbExportBmkToPDFDestination = maConfigItem.ReadBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarksToPDFDestination" ) ), sal_False ); +//prepare values for digital signatures + mbSignPDF = maConfigItem.ReadBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "SignPDF" ) ), sal_False ); + //queue the tab pages for later creation (created when first shown) + AddTabPage( RID_PDF_TAB_SIGNING, ImpPDFTabSigningPage::Create, 0 ); AddTabPage( RID_PDF_TAB_SECURITY, ImpPDFTabSecurityPage::Create, 0 ); AddTabPage( RID_PDF_TAB_LINKS, ImpPDFTabLinksPage::Create, 0 ); AddTabPage( RID_PDF_TAB_VPREFER, ImpPDFTabViewerPage::Create, 0 ); AddTabPage( RID_PDF_TAB_OPNFTR, ImpPDFTabOpnFtrPage::Create, 0 ); +//remove tabpage if experimentalmode is not set + SvtMiscOptions aMiscOptions; + if (!aMiscOptions.IsExperimentalMode()) + RemoveTabPage( RID_PDF_TAB_SIGNING ); + //last queued is the first to be displayed (or so it seems..) AddTabPage( RID_PDF_TAB_GENER, ImpPDFTabGeneralPage::Create, 0 ); @@ -281,6 +296,11 @@ ImpPDFTabDialog::~ImpPDFTabDialog() RemoveTabPage( RID_PDF_TAB_OPNFTR ); RemoveTabPage( RID_PDF_TAB_LINKS ); RemoveTabPage( RID_PDF_TAB_SECURITY ); + +//remove tabpage if experimentalmode is set + SvtMiscOptions aMiscOptions; + if (aMiscOptions.IsExperimentalMode()) + RemoveTabPage( RID_PDF_TAB_SIGNING ); } // ----------------------------------------------------------------------------- @@ -304,6 +324,9 @@ void ImpPDFTabDialog::PageCreated( sal_uInt16 _nId, case RID_PDF_TAB_SECURITY: ( ( ImpPDFTabSecurityPage* )&_rPage )->SetFilterConfigItem( this ); break; + case RID_PDF_TAB_SIGNING: + ( ( ImpPDFTabSigningPage* )&_rPage )->SetFilterConfigItem( this ); + break; } } @@ -329,6 +352,8 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() ( ( ImpPDFTabLinksPage* )GetTabPage( RID_PDF_TAB_LINKS ) )->GetFilterConfigItem( this ); if( GetTabPage( RID_PDF_TAB_SECURITY ) ) ( ( ImpPDFTabSecurityPage* )GetTabPage( RID_PDF_TAB_SECURITY ) )->GetFilterConfigItem( this ); + if( GetTabPage( RID_PDF_TAB_SIGNING ) ) + ( ( ImpPDFTabSigningPage* )GetTabPage( RID_PDF_TAB_SIGNING ) )->GetFilterConfigItem( this ); //prepare the items to be returned maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "UseLosslessCompression" ) ), mbUseLosslessCompression ); @@ -379,6 +404,8 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ConvertOOoTargetToPDFTarget" ) ), mbConvertOOoTargets ); maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarksToPDFDestination" ) ), mbExportBmkToPDFDestination ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "SignPDF" ) ), mbSignPDF ); + maConfigItem.WriteInt32( OUString( RTL_CONSTASCII_USTRINGPARAM( "Printing" ) ), mnPrint ); maConfigItem.WriteInt32( OUString( RTL_CONSTASCII_USTRINGPARAM( "Changes" ) ), mnChangesAllowed ); maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableCopyingOfContent" ) ), mbCanCopyOrExtract ); @@ -386,7 +413,7 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() Sequence< PropertyValue > aRet( maConfigItem.GetFilterData() ); - int nElementAdded = 6; + int nElementAdded = 11; aRet.realloc( aRet.getLength() + nElementAdded ); @@ -421,13 +448,35 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() { aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ); aRet[ nLength - nElementAdded ].Value <<= OUString( msPageRange ); + nElementAdded--; } else if( mbSelectionIsChecked ) { aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Selection" ) ); aRet[ nLength - nElementAdded ].Value <<= maSelection; + nElementAdded--; } + aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "SignatureLocation" ) ); + aRet[ nLength - nElementAdded ].Value <<= msSignLocation; + nElementAdded--; + + aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "SignatureReason" ) ); + aRet[ nLength - nElementAdded ].Value <<= msSignReason; + nElementAdded--; + + aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "SignatureContactInfo" ) ); + aRet[ nLength - nElementAdded ].Value <<= msSignContact; + nElementAdded--; + + aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "SignaturePassword" ) ); + aRet[ nLength - nElementAdded ].Value <<= msSignPassword; + nElementAdded--; + + aRet[ nLength - nElementAdded ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "SignatureCertificate" ) ); + aRet[ nLength - nElementAdded ].Value <<= maSignCertificate; + nElementAdded--; + return aRet; } @@ -1626,4 +1675,106 @@ IMPL_LINK_NOARG(ImplErrorDialog, SelectHdl) return 0; } +//////////////////////////////////////////////////////// +// The digital signatures tab page +// ----------------------------------------------------------------------------- +ImpPDFTabSigningPage::ImpPDFTabSigningPage( Window* pParent, + const SfxItemSet& rCoreSet ) : + SfxTabPage( pParent, PDFFilterResId( RID_PDF_TAB_SIGNING ), rCoreSet ), + + maCbSignPDF( this, PDFFilterResId( CB_SIGN_PDF ) ), + maFtSignPassword( this, PDFFilterResId( FT_SIGN_PASSWORD ) ), + maEdSignPassword( this, PDFFilterResId( ED_SIGN_PASSWORD ) ), + maFtSignLocation( this, PDFFilterResId( FT_SIGN_LOCATION ) ), + maEdSignLocation( this, PDFFilterResId( ED_SIGN_LOCATION ) ), + maFtSignContactInfo( this, PDFFilterResId( FT_SIGN_CONTACT ) ), + maEdSignContactInfo( this, PDFFilterResId( ED_SIGN_CONTACT ) ), + maFtSignReason( this, PDFFilterResId( FT_SIGN_REASON ) ), + maEdSignReason( this, PDFFilterResId( ED_SIGN_REASON ) ), + maPbSignSelectCert( this, PDFFilterResId( BTN_SIGN_SELECT_CERT ) ), + maSignCertificate() +{ + FreeResource(); + + maPbSignSelectCert.SetClickHdl( LINK( this, ImpPDFTabSigningPage, ClickmaPbSignSelectCert ) ); +} + +// ----------------------------------------------------------------------------- +ImpPDFTabSigningPage::~ImpPDFTabSigningPage() +{ +} + +IMPL_LINK_NOARG( ImpPDFTabSigningPage, ClickmaPbSignSelectCert ) +{ + + uno::Sequence< uno::Any > aArgs( 2 ); + aArgs[0] <<= rtl::OUString("1.2"); + aArgs[1] <<= sal_False; + + Reference< security::XDocumentDigitalSignatures > xSigner( + comphelper::getProcessServiceFactory()->createInstanceWithArguments( + rtl::OUString( "com.sun.star.security.DocumentDigitalSignatures" ), aArgs ), + uno::UNO_QUERY ); + + if ( !xSigner.is() ) + return 0; + + maSignCertificate = xSigner->chooseCertificate(); + + return 0; +} + +// ----------------------------------------------------------------------------- +SfxTabPage* ImpPDFTabSigningPage::Create( Window* pParent, + const SfxItemSet& rAttrSet) +{ + return ( new ImpPDFTabSigningPage( pParent, rAttrSet ) ); +} + +// ----------------------------------------------------------------------------- +void ImpPDFTabSigningPage::GetFilterConfigItem( ImpPDFTabDialog* paParent ) +{ + paParent->mbSignPDF = maCbSignPDF.IsChecked(); + paParent->msSignLocation = maEdSignLocation.GetText(); + paParent->msSignPassword = maEdSignPassword.GetText(); + paParent->msSignContact = maEdSignContactInfo.GetText(); + paParent->msSignReason = maEdSignReason.GetText(); + paParent->maSignCertificate = maSignCertificate; + +} + +// ----------------------------------------------------------------------------- +void ImpPDFTabSigningPage::SetFilterConfigItem( const ImpPDFTabDialog* paParent ) +{ + + maCbSignPDF.SetToggleHdl( LINK( this, ImpPDFTabSigningPage, ToggleSignPDFHdl ) ); + maEdSignLocation.Enable( false ); + maEdSignPassword.Enable( false ); + maEdSignContactInfo.Enable( false ); + maEdSignReason.Enable( false ); + maPbSignSelectCert.Enable( false ); + + if (paParent->mbSignPDF) + { + maCbSignPDF.Check(); + maEdSignPassword.SetText(paParent->msSignPassword); + maEdSignLocation.SetText(paParent->msSignLocation); + maEdSignContactInfo.SetText(paParent->msSignContact); + maEdSignReason.SetText(paParent->msSignReason); + maSignCertificate = paParent->maSignCertificate; + } +} + +// ----------------------------------------------------------------------------- +IMPL_LINK_NOARG(ImpPDFTabSigningPage, ToggleSignPDFHdl) +{ + maEdSignPassword.Enable( maCbSignPDF.IsChecked() ); + maEdSignLocation.Enable( maCbSignPDF.IsChecked() ); + maEdSignContactInfo.Enable( maCbSignPDF.IsChecked() ); + maEdSignReason.Enable( maCbSignPDF.IsChecked() ); + maPbSignSelectCert.Enable( maCbSignPDF.IsChecked() ); + + return 0; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/impdialog.hrc b/filter/source/pdf/impdialog.hrc index 7a4630ed833f..110bae0e94bd 100644 --- a/filter/source/pdf/impdialog.hrc +++ b/filter/source/pdf/impdialog.hrc @@ -24,6 +24,7 @@ #define RID_PDF_TAB_OPNFTR (RID_PDF_DIALOG_START + 3) #define RID_PDF_TAB_SECURITY (RID_PDF_DIALOG_START + 4) #define RID_PDF_TAB_LINKS (RID_PDF_DIALOG_START + 12) +#define RID_PDF_TAB_SIGNING (RID_PDF_DIALOG_START + 13) #define RID_PDF_WARNPDFAPASSWORD (RID_PDF_DIALOG_START + 6) //strings @@ -177,3 +178,15 @@ #define FL_INITVIEW_VERTICAL 158 #define FL_VPREFER_VERTICAL 158 #define FL_SECURITY_VERTICAL 160 + +//controls for digital signatures tab page +#define CB_SIGN_PDF 170 +#define FT_SIGN_PASSWORD 171 +#define ED_SIGN_PASSWORD 172 +#define FT_SIGN_LOCATION 173 +#define ED_SIGN_LOCATION 174 +#define FT_SIGN_CONTACT 175 +#define ED_SIGN_CONTACT 176 +#define FT_SIGN_REASON 177 +#define ED_SIGN_REASON 178 +#define BTN_SIGN_SELECT_CERT 179 diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx index acbedaffcc42..45747fd5c6d0 100644 --- a/filter/source/pdf/impdialog.hxx +++ b/filter/source/pdf/impdialog.hxx @@ -148,6 +148,14 @@ protected: sal_Int32 mnViewPDFMode; sal_Bool mbConvertOOoTargets; sal_Bool mbExportBmkToPDFDestination; + + sal_Bool mbSignPDF; + ::rtl::OUString msSignPassword; + ::rtl::OUString msSignLocation; + ::rtl::OUString msSignContact; + ::rtl::OUString msSignReason; + com::sun::star::uno::Reference< com::sun::star::security::XCertificate > maSignCertificate; + ::rtl::OUString maWatermarkText; public: @@ -157,6 +165,7 @@ public: friend class ImpPDFTabOpnFtrPage; friend class ImpPDFTabSecurityPage; friend class ImpPDFTabLinksPage; + friend class ImpPDFTabSigningPage; ImpPDFTabDialog( Window* pParent, Sequence< PropertyValue >& rFilterData, @@ -429,6 +438,36 @@ public: void ImplPDFALinkControl( sal_Bool bEnableLaunch ); }; +//class to implement the digital signing +class ImpPDFTabSigningPage : public SfxTabPage +{ + CheckBox maCbSignPDF; + FixedText maFtSignPassword; + Edit maEdSignPassword; + FixedText maFtSignLocation; + Edit maEdSignLocation; + FixedText maFtSignContactInfo; + Edit maEdSignContactInfo; + FixedText maFtSignReason; + Edit maEdSignReason; + PushButton maPbSignSelectCert; + com::sun::star::uno::Reference< com::sun::star::security::XCertificate > maSignCertificate; + + DECL_LINK( ToggleSignPDFHdl, void* ); + DECL_LINK( ClickmaPbSignSelectCert, void* ); + +public: + ImpPDFTabSigningPage( Window* pParent, + const SfxItemSet& rSet ); + + ~ImpPDFTabSigningPage(); + static SfxTabPage* Create( Window* pParent, + const SfxItemSet& rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + #endif // IMPDIALOG_HXX diff --git a/filter/source/pdf/impdialog.src b/filter/source/pdf/impdialog.src index 8c73d20690d9..afae67e7eab1 100644 --- a/filter/source/pdf/impdialog.src +++ b/filter/source/pdf/impdialog.src @@ -817,6 +817,91 @@ TabPage RID_PDF_TAB_SECURITY }; //---------------------------------------------------------- +//tab page for PDF Export, digital signatures +TabPage RID_PDF_TAB_SIGNING +{ + HelpId = HID_FILTER_PDF_SIGNING ; + Text [ en-US ] = "Digital Signatures"; + TAB_PDF_SIZE; + Hide = TRUE; + + CheckBox CB_SIGN_PDF + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 164 , 16 ) ; + TabStop = TRUE ; + WordBreak = TRUE ; + Text[ en-US ] = "Sign PDF file" ; + }; + + PushButton BTN_SIGN_SELECT_CERT + { + TabStop = TRUE ; + Disable = TRUE ; + Pos = MAP_APPFONT ( 12, 17 ) ; + Size = MAP_APPFONT ( 120 , 13 ) ; + Text[ en-US ] = "Select c~ertificate..."; + }; + + FixedText FT_SIGN_PASSWORD + { + Pos = MAP_APPFONT( 12, 35 ); + Size = MAP_APPFONT( 109, 10 ); + Text[ en-US ] = "Certificate Password"; + }; + + Edit ED_SIGN_PASSWORD + { + Border = TRUE ; + Pos = MAP_APPFONT ( 102, 35 ) ; + Size = MAP_APPFONT ( 68 , 12 ) ; + }; + + FixedText FT_SIGN_LOCATION + { + Pos = MAP_APPFONT( 12, 48 ); + Size = MAP_APPFONT( 109, 10 ); + Text[ en-US ] = "Location"; + }; + + Edit ED_SIGN_LOCATION + { + Border = TRUE ; + Pos = MAP_APPFONT ( 102, 48 ) ; + Size = MAP_APPFONT ( 68 , 12 ) ; + }; + + FixedText FT_SIGN_CONTACT + { + Pos = MAP_APPFONT( 12, 61 ); + Size = MAP_APPFONT( 109, 10 ); + Text[ en-US ] = "Contact Information"; + }; + + Edit ED_SIGN_CONTACT + { + Border = TRUE ; + Pos = MAP_APPFONT ( 102, 61 ) ; + Size = MAP_APPFONT ( 68 , 12 ) ; + }; + + FixedText FT_SIGN_REASON + { + Pos = MAP_APPFONT( 12, 74 ); + Size = MAP_APPFONT( 109, 10 ); + Text[ en-US ] = "Reason"; + }; + + Edit ED_SIGN_REASON + { + Border = TRUE ; + Pos = MAP_APPFONT ( 102, 74 ) ; + Size = MAP_APPFONT ( 68 , 12 ) ; + }; + +}; + +//---------------------------------------------------------- //tab page for PDF Export, links management TabPage RID_PDF_TAB_LINKS { @@ -930,6 +1015,11 @@ TabDialog RID_PDF_EXPORT_DLG Identifier = RID_PDF_TAB_SECURITY; Text [ en-US ] = "Security"; }; + PageItem + { + Identifier = RID_PDF_TAB_SIGNING; + Text [ en-US ] = "Digital Signatures"; + }; }; }; }; diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx index db93010d1ee1..30727c6773f1 100644 --- a/filter/source/pdf/pdfexport.cxx +++ b/filter/source/pdf/pdfexport.cxx @@ -554,6 +554,18 @@ sal_Bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue rFilterData[ nData ].Value >>= mbExportHiddenSlides; else if ( rFilterData[ nData ].Name == "OpenBookmarkLevels" ) rFilterData[ nData ].Value >>= mnOpenBookmarkLevels; + else if ( rFilterData[ nData ].Name == "SignPDF" ) + rFilterData[ nData ].Value >>= mbSignPDF; + else if ( rFilterData[ nData ].Name == "SignatureLocation" ) + rFilterData[ nData ].Value >>= msSignLocation; + else if ( rFilterData[ nData ].Name == "SignatureReason" ) + rFilterData[ nData ].Value >>= msSignReason; + else if ( rFilterData[ nData ].Name == "SignatureContactInfo" ) + rFilterData[ nData ].Value >>= msSignContact; + else if ( rFilterData[ nData ].Name == "SignaturePassword" ) + rFilterData[ nData ].Value >>= msSignPassword; + else if ( rFilterData[ nData ].Name == "SignatureCertificate" ) + rFilterData[ nData ].Value >>= maSignCertificate; } aContext.URL = aURL.GetMainURL(INetURLObject::DECODE_TO_IURI); @@ -781,6 +793,14 @@ sal_Bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue aContext.ForcePDFAction = sal_False; } } + + aContext.SignPDF = mbSignPDF; + aContext.SignLocation = msSignLocation; + aContext.SignContact = msSignContact; + aContext.SignReason = msSignReason; + aContext.SignPassword = msSignPassword; + aContext.SignCertificate = maSignCertificate; + // all context data set, time to create the printing device PDFWriter* pPDFWriter = new PDFWriter( aContext, xEnc ); OutputDevice* pOut = pPDFWriter->GetReferenceDevice(); diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx index a571cd44dbe6..4c884ee5d568 100644 --- a/filter/source/pdf/pdfexport.hxx +++ b/filter/source/pdf/pdfexport.hxx @@ -111,6 +111,14 @@ private: sal_Bool mbExportBmkToDest; sal_Bool ImplExportPage( ::vcl::PDFWriter& rWriter, ::vcl::PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf ); + + sal_Bool mbSignPDF; + OUString msSignLocation; + OUString msSignContact; + OUString msSignReason; + OUString msSignPassword; + Reference< security::XCertificate > maSignCertificate; + void ImplWriteWatermark( ::vcl::PDFWriter& rWriter, const Size& rPageSize ); public: diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl index be75dc1dee3d..8e9089e75495 100644 --- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl +++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl @@ -143,7 +143,9 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface void addAuthorToTrustedSources( [in] com::sun::star::security::XCertificate Author ); void addLocationToTrustedSources( [in] string Location ); - + /** This method shows CertificateChooser dialog, used by document and PDF signing + */ + com::sun::star::security::XCertificate chooseCertificate(); } ; diff --git a/vcl/inc/vcl/pdfwriter.hxx b/vcl/inc/vcl/pdfwriter.hxx index cb6d271dfe73..0e93cdd9c6a1 100644 --- a/vcl/inc/vcl/pdfwriter.hxx +++ b/vcl/inc/vcl/pdfwriter.hxx @@ -41,6 +41,7 @@ #include "com/sun/star/io/XOutputStream.hpp" #include "com/sun/star/beans/XMaterialHolder.hpp" +#include "com/sun/star/security/XCertificate.hpp" #include "com/sun/star/lang/Locale.hpp" #include <boost/scoped_ptr.hpp> @@ -197,7 +198,8 @@ public: enum WidgetType { - PushButton, RadioButton, CheckBox, Edit, ListBox, ComboBox, Hierarchy + PushButton, RadioButton, CheckBox, Edit, ListBox, ComboBox, Hierarchy, + Signature }; enum WidgetState @@ -449,6 +451,28 @@ public: } }; + struct SignatureWidget: public AnyWidget + { + // Use Sig prefix for members to avoid conflict with + // the Location member of the AnyWidget which spcifies the coordinates + // of the signature + + rtl::OUString SigLocation; + rtl::OUString SigReason; + rtl::OUString SigContactInfo; + bool SigHidden; + + SignatureWidget() + : AnyWidget( vcl::PDFWriter::Signature ), + SigHidden( true ) + {} + + virtual AnyWidget* Clone() const + { + return new SignatureWidget( *this ); + } + }; + enum ExportDataFormat { HTML, XML, FDF, PDF }; // see 3.6.1 of PDF 1.4 ref for details, used for 8.1 PDF v 1.4 ref also // These emuns are treated as integer while reading/writing to configuration @@ -606,6 +630,13 @@ The following structure describes the permissions used in PDF security PDFWriter::PDFEncryptionProperties Encryption; PDFWriter::PDFDocInfo DocumentInfo; + bool SignPDF; + rtl::OUString SignLocation; + rtl::OUString SignPassword; + rtl::OUString SignReason; + rtl::OUString SignContact; + com::sun::star::uno::Reference< com::sun::star::security::XCertificate> SignCertificate; + com::sun::star::lang::Locale DocumentLocale; // defines the document default language sal_uInt32 DPIx, DPIy; // how to handle MapMode( MAP_PIXEL ) // 0 here specifies a default handling @@ -637,9 +668,11 @@ The following structure describes the permissions used in PDF security InitialPage( 1 ), OpenBookmarkLevels( -1 ), Encryption(), + SignPDF( false ), DPIx( 0 ), DPIy( 0 ), - ColorMode( PDFWriter::DrawColor ) + ColorMode( PDFWriter::DrawColor ), + SignCertificate( 0 ) {} }; diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 5eb5ad7e41ab..f89bbebe2b38 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -74,6 +74,7 @@ #include <lcms2.h> #include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/util/URLTransformer.hpp> @@ -97,6 +98,8 @@ using ::rtl::OUStringBuffer; #define DEBUG_DISABLE_PDFCOMPRESSION // also do not compress streams #endif +#define MAX_SIGNATURE_CONTENT_LENGTH 0x4000 + #ifdef DO_TEST_PDF class PDFTestOutputStream : public PDFOutputStream { @@ -135,6 +138,11 @@ void doTestCode() aContext.DocumentInfo.Title = OUString( "PDF export test document" ); aContext.DocumentInfo.Producer = OUString( "VCL" ); + aContext.SignPDF = true; + aContext.SignLocation = OUString( "Burdur" ); + aContext.SignReason = OUString( "Some valid reason to sign" ); + aContext.SignContact = OUString( "signer@example.com" ); + com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > xEnc; PDFWriter aWriter( aContext, xEnc ); aWriter.NewPage( 595, 842 ); @@ -520,6 +528,7 @@ void doTestCode() aWriter.CreateOutlineItem( nPage2OL, OUString( "Dest 1" ), nFirstDest ); aWriter.EndStructureElement(); // close document + aWriter.Emit(); } #endif @@ -1755,6 +1764,9 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal m_eInheritedOrientation( PDFWriter::Portrait ), m_nCurrentPage( -1 ), m_nResourceDict( -1 ), + m_nSignatureObject( -1 ), + m_nSignatureContentOffset( 0 ), + m_nSignatureLastByteRangeNoOffset( 0 ), m_nFontDictObject( -1 ), m_pCodec( NULL ), m_aDocDigest( rtl_digest_createMD5() ), @@ -5452,15 +5464,29 @@ bool PDFWriterImpl::emitWidgetAnnotations() // emit widget annotation only for terminal fields if( rWidget.m_aKids.empty() ) { - aLine.append( "/Type/Annot/Subtype/Widget/F 4\n" - "/Rect[" ); - appendFixedInt( rWidget.m_aRect.Left()-1, aLine ); + int iRectMargin; + + aLine.append( "/Type/Annot/Subtype/Widget/F " ); + + if (rWidget.m_eType == PDFWriter::Signature) + { + aLine.append( "132\n" ); // Print & Locked + iRectMargin = 0; + } + else + { + aLine.append( "4\n" ); + iRectMargin = 1; + } + + aLine.append("/Rect[" ); + appendFixedInt( rWidget.m_aRect.Left()-iRectMargin, aLine ); aLine.append( ' ' ); - appendFixedInt( rWidget.m_aRect.Top()+1, aLine ); + appendFixedInt( rWidget.m_aRect.Top()+iRectMargin, aLine ); aLine.append( ' ' ); - appendFixedInt( rWidget.m_aRect.Right()+1, aLine ); + appendFixedInt( rWidget.m_aRect.Right()+iRectMargin, aLine ); aLine.append( ' ' ); - appendFixedInt( rWidget.m_aRect.Bottom()-1, aLine ); + appendFixedInt( rWidget.m_aRect.Bottom()-iRectMargin, aLine ); aLine.append( "]\n" ); } aLine.append( "/FT/" ); @@ -5515,6 +5541,10 @@ bool PDFWriterImpl::emitWidgetAnnotations() aLine.append( "Tx" ); appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue ); break; + case PDFWriter::Signature: + aLine.append( "Sig" ); + aValue.append(OUStringToOString(rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US)); + break; case PDFWriter::Hierarchy: // make the compiler happy break; } @@ -5877,6 +5907,14 @@ bool PDFWriterImpl::emitCatalog() } else aInitPageRef.append( "0" ); + + if (m_nSignatureObject != -1) // Document will be signed + { + aLine.append("/Perms<</DocMDP "); + aLine.append(m_nSignatureObject); + aLine.append(" 0 R>>"); + } + switch( m_aContext.PDFDocumentAction ) { case PDFWriter::ActionDefault : //do nothing, this is the Acrobat default @@ -6001,10 +6039,16 @@ bool PDFWriterImpl::emitCatalog() aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " ); } } - aLine.append( "\n]/DR " ); + aLine.append( "\n]" ); + + if (m_nSignatureObject != -1) + aLine.append( "/SigFlags 3"); + + aLine.append( "/DR " ); aLine.append( getResourceDictObj() ); aLine.append( " 0 R" ); - if( m_bIsPDF_A1 ) + // /NeedAppearances must not be used if PDF is signed + if( m_bIsPDF_A1 || ( m_nSignatureObject != -1 ) ) aLine.append( ">>\n" ); else aLine.append( "/NeedAppearances true>>\n" ); @@ -6031,6 +6075,129 @@ bool PDFWriterImpl::emitCatalog() return true; } +bool PDFWriterImpl::emitSignature() +{ + if( !updateObject( m_nSignatureObject ) ) + return false; + + OStringBuffer aLine( 0x5000 ); + aLine.append( m_nSignatureObject ); + aLine.append( " 0 obj\n" ); + aLine.append("<</Reference[<</Data "); + aLine.append( m_nCatalogObject ); + aLine.append(" 0 R/Type/SigRef/TransformParams<</Type/TransformParams" + "/V/1.2/P 1>>/DigestMethod/MD5/DigestLocation[0 0]" + "/DigestValue(aa)/TransformMethod/DocMDP>>]/Contents <" ); + + sal_uInt64 nOffset = ~0U; + CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nOffset ) ) ); + DBG_ASSERT( aError == osl_File_E_None, "could not get file position" ); + + m_nSignatureContentOffset = nOffset + aLine.getLength(); + + // reserve some space for the PKCS#7 object + OStringBuffer aContentFiller( MAX_SIGNATURE_CONTENT_LENGTH ); + comphelper::string::padToLength(aContentFiller, MAX_SIGNATURE_CONTENT_LENGTH, '0'); + aLine.append( aContentFiller.makeStringAndClear() ); + aLine.append( ">\n/Type/Sig/SubFilter/adbe.pkcs7.sha1"); + + if( m_aContext.DocumentInfo.Author.Len() ) + { + aLine.append( "/Name" ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, m_nSignatureObject, aLine ); + } + + aLine.append( " /M "); + appendLiteralStringEncrypt( m_aCreationDateString, m_nSignatureObject, aLine ); + + aLine.append( " /ByteRange [ 0 "); + aLine.append( m_nSignatureContentOffset - 1, 10 ); + aLine.append( " " ); + aLine.append( m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1, 10 ); + aLine.append( " " ); + + m_nSignatureLastByteRangeNoOffset = nOffset + aLine.getLength(); + + // mark the last ByteRange no and add some space. Now, we don't know + // how many bytes we need for this ByteRange value + // The real value will be overwritten in the finalizeSignature method + OStringBuffer aByteRangeFiller( 100 ); + comphelper::string::padToLength(aByteRangeFiller, 100, ' '); + aLine.append( aByteRangeFiller.makeStringAndClear() ); + aLine.append(" /Filter/Adobe.PPKMS"); + + //emit reason, location and contactinfo + if ( !m_aContext.SignReason.isEmpty() ) + { + aLine.append("/Reason"); + appendUnicodeTextStringEncrypt( m_aContext.SignReason, m_nSignatureObject, aLine ); + } + + if ( !m_aContext.SignLocation.isEmpty() ) + { + aLine.append("/Location"); + appendUnicodeTextStringEncrypt( m_aContext.SignLocation, m_nSignatureObject, aLine ); + } + + if ( !m_aContext.SignContact.isEmpty() ) + { + aLine.append("/ContactInfo"); + appendUnicodeTextStringEncrypt( m_aContext.SignContact, m_nSignatureObject, aLine ); + } + + aLine.append(" >>\nendobj\n\n" ); + + if (!writeBuffer( aLine.getStr(), aLine.getLength() )) + return false; + + return true; +} + +bool PDFWriterImpl::finalizeSignature() +{ + + if (!m_aContext.SignCertificate.is()) + return false; + + // 1- calculate last ByteRange value + sal_uInt64 nOffset = ~0U; + CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nOffset ) ) ); + + sal_Int64 nLastByteRangeNo = nOffset - (m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH) - 1; + + // 2- overwrite the value to the m_nSignatureLastByteRangeNoOffset position + sal_uInt64 nWritten = 0; + CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureLastByteRangeNoOffset ) ) ); + OStringBuffer aByteRangeNo( 256 ); + aByteRangeNo.append( nLastByteRangeNo, 10); + aByteRangeNo.append( " ]" ); + + if( osl_writeFile( m_aFile, aByteRangeNo.getStr(), aByteRangeNo.getLength(), &nWritten ) != osl_File_E_None ) + { + CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, nOffset ) ) ); + return false; + } + + // 3- create the PKCS#7 object using NSS + // use m_aContext.SignCertificate and m_aContext.SignPassword as certificate and private key password + // SignCertificate->getEncoded is DER encoded certificate + com::sun::star::uno::Sequence< sal_Int8 > derEncoded = m_aContext.SignCertificate->getEncoded(); + + if (!derEncoded.hasElements()) + return false; + + sal_Int8* n_derArray = derEncoded.getArray(); + sal_Int32 n_derLength = derEncoded.getLength(); + + // 4- overwrite the PKCS7 content to the m_nSignatureContentOffset + CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset ) ) ); + // osl_writeFile() + + // revert the file position back + CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, nOffset ) ) ); + return true; +} + sal_Int32 PDFWriterImpl::emitInfoDict( ) { sal_Int32 nObject = createObject(); @@ -6812,15 +6979,29 @@ bool PDFWriterImpl::emit() // needed for widget tab order sortWidgets(); + if( m_aContext.SignPDF ) + { + // sign the document + PDFWriter::SignatureWidget aSignature; + aSignature.Name = OUString("Signature1"); + createControl( aSignature, 0 ); + } + // emit additional streams CHECK_RETURN( emitAdditionalStreams() ); // emit catalog CHECK_RETURN( emitCatalog() ); + if (m_nSignatureObject != -1) // if document is signed, emit sigdict + CHECK_RETURN( emitSignature() ); + // emit trailer CHECK_RETURN( emitTrailer() ); + if (m_nSignatureObject != -1) // finalize the signature + CHECK_RETURN( finalizeSignature() ); + osl_closeFile( m_aFile ); m_bOpen = false; @@ -11552,13 +11733,14 @@ sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sa if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) return -1; + bool sigHidden; sal_Int32 nNewWidget = m_aWidgets.size(); m_aWidgets.push_back( PDFWidget() ); m_aWidgets.back().m_nObject = createObject(); - m_aWidgets.back().m_aRect = rControl.Location; - m_aWidgets.back().m_nPage = nPageNr; - m_aWidgets.back().m_eType = rControl.getType(); + m_aWidgets.back().m_aRect = rControl.Location; + m_aWidgets.back().m_nPage = nPageNr; + m_aWidgets.back().m_eType = rControl.getType(); sal_Int32 nRadioGroupWidget = -1; // for unknown reasons the radio buttons of a radio group must not have a @@ -11716,10 +11898,31 @@ sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sa createDefaultEditAppearance( rNewWidget, rEdit ); } + else if( rControl.getType() == PDFWriter::Signature) + { + const PDFWriter::SignatureWidget& rSig = static_cast<const PDFWriter::SignatureWidget&>(rControl); + sigHidden = rSig.SigHidden; - // convert to default user space now, since the mapmode may change - // note: create default appearances before m_aRect gets transformed - m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect ); + if ( sigHidden ) + rNewWidget.m_aRect = Rectangle(0, 0, 0, 0); + + m_nSignatureObject = createObject(); + rNewWidget.m_aValue = OUString::valueOf( m_nSignatureObject ); + rNewWidget.m_aValue += OUString(" 0 R"); + //createDefaultSignatureAppearance( rNewWidget, rSig ); + // let's add a fake appearance + rNewWidget.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream(); + } + + + // if control is a hidden signature, do not convert coordinates since we + // need /Rect [ 0 0 0 0 ] + if ( ! ( ( rControl.getType() == PDFWriter::Signature ) && ( sigHidden ) ) ) + { + // convert to default user space now, since the mapmode may change + // note: create default appearances before m_aRect gets transformed + m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect ); + } // insert widget to page's annotation list m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject ); diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index 36429a004c6d..2f3a6b3bbbaf 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -678,6 +678,10 @@ private: sal_Int32 m_nCurrentPage; sal_Int32 m_nCatalogObject; + // object number of the main signature dictionary + sal_Int32 m_nSignatureObject; + sal_Int64 m_nSignatureContentOffset; + sal_Int64 m_nSignatureLastByteRangeNoOffset; sal_Int32 m_nResourceDict; ResourceDict m_aGlobalResourceDict; sal_Int32 m_nFontDictObject; @@ -950,6 +954,11 @@ i12626 sal_Int32 emitStructParentTree( sal_Int32 nTreeObject ); // writes page tree and catalog bool emitCatalog(); + // writes signature dictionary object + bool emitSignature(); + // creates a PKCS7 object using the ByteRange and overwrite /Contents + // of the signature dictionary + bool finalizeSignature(); // writes xref and trailer bool emitTrailer(); // emit additional streams collected; also create there object numbers diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 3282dfede4d3..f52c1a4411d0 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -28,6 +28,7 @@ #include <documentdigitalsignatures.hxx> #include <xmlsecurity/digitalsignaturesdialog.hxx> +#include <xmlsecurity/certificatechooser.hxx> #include <xmlsecurity/certificateviewer.hxx> #include <xmlsecurity/macrosecurity.hxx> #include <xmlsecurity/biginteger.hxx> @@ -424,6 +425,28 @@ void DocumentDigitalSignatures::showCertificate( return bFound; } +Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificate() throw (RuntimeException) +{ + Reference< dcss::xml::crypto::XSecurityEnvironment > xSecEnv; + + XMLSignatureHelper aSignatureHelper( mxCtx ); + if ( aSignatureHelper.Init() ) + xSecEnv = aSignatureHelper.GetSecurityEnvironment(); + + CertificateChooser aChooser( NULL, mxCtx, xSecEnv, aSignatureHelper.GetSignatureInformations()); + + if (aChooser.Execute() != RET_OK) + return Reference< css::security::XCertificate >(0); + + Reference< css::security::XCertificate > xCert = aChooser.GetSelectedCertificate(); + + if ( !xCert.is() ) + return Reference< css::security::XCertificate >(0); + + return xCert; +} + + ::sal_Bool DocumentDigitalSignatures::isLocationTrusted( const ::rtl::OUString& Location ) throw (RuntimeException) { sal_Bool bFound = sal_False; diff --git a/xmlsecurity/source/component/documentdigitalsignatures.hxx b/xmlsecurity/source/component/documentdigitalsignatures.hxx index 03bf1b926d75..141bc911ca1d 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.hxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.hxx @@ -85,6 +85,7 @@ public: void SAL_CALL addAuthorToTrustedSources( const ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >& Author ) throw (::com::sun::star::uno::RuntimeException); void SAL_CALL addLocationToTrustedSources( const ::rtl::OUString& Location ) throw (::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate > SAL_CALL chooseCertificate( ) throw (::com::sun::star::uno::RuntimeException); }; com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL DocumentDigitalSignatures_CreateInstance( |