| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_xmlsecurity.hxx" |
| #include <xmlsecurity/digitalsignaturesdialog.hxx> |
| #include <xmlsecurity/certificatechooser.hxx> |
| #include <xmlsecurity/certificateviewer.hxx> |
| #include <xmlsecurity/biginteger.hxx> |
| #include <xmloff/xmluconv.hxx> |
| #include <com/sun/star/embed/XStorage.hpp> |
| #include <com/sun/star/embed/ElementModes.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/io/XTruncate.hpp> |
| #include <com/sun/star/embed/XTransactedObject.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/lang/XComponent.hpp> |
| #include <com/sun/star/security/NoPasswordException.hpp> |
| #include <com/sun/star/lang/DisposedException.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/security/CertificateValidity.hdl> |
| #include <com/sun/star/packages/WrongPasswordException.hpp> |
| #include <com/sun/star/security/SerialNumberAdapter.hpp> |
| #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> |
| #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> |
| #include <com/sun/star/packages/manifest/XManifestReader.hpp> |
| |
| |
| #include <rtl/ustrbuf.hxx> |
| #include <rtl/uri.hxx> |
| |
| #include <tools/date.hxx> |
| #include <tools/time.hxx> |
| |
| #include "dialogs.hrc" |
| #include "digitalsignaturesdialog.hrc" |
| #include "helpids.hrc" |
| #include "resourcemanager.hxx" |
| |
| #include <vcl/msgbox.hxx> // Until encrypted docs work... |
| #include <unotools/configitem.hxx> |
| #include <comphelper/componentcontext.hxx> |
| |
| #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) |
| |
| |
| /* HACK: disable some warnings for MS-C */ |
| #ifdef _MSC_VER |
| #pragma warning (disable : 4355) // 4355: this used in initializer-list |
| #endif |
| |
| using namespace ::com::sun::star::security; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star; |
| namespace css = ::com::sun::star; |
| using ::rtl::OUString; |
| |
| namespace |
| { |
| class SaveODFItem: public utl::ConfigItem |
| { |
| sal_Int16 m_nODF; |
| public: |
| virtual void Commit(); |
| virtual void Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames ); |
| SaveODFItem(); |
| //See group ODF in Common.xcs |
| bool isLessODF1_2() |
| { |
| return m_nODF < 3; |
| } |
| }; |
| |
| void SaveODFItem::Commit() {} |
| void SaveODFItem::Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& ) {} |
| |
| SaveODFItem::SaveODFItem(): utl::ConfigItem(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "Office.Common/Save"))), m_nODF(0) |
| { |
| OUString sDef(RTL_CONSTASCII_USTRINGPARAM("ODF/DefaultVersion")); |
| Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) ); |
| if ( aValues.getLength() == 1) |
| { |
| sal_Int16 nTmp = 0; |
| if ( aValues[0] >>= nTmp ) |
| m_nODF = nTmp; |
| else |
| throw uno::RuntimeException( |
| OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!")), 0 ); |
| |
| } |
| else |
| throw uno::RuntimeException( |
| OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion")), 0); |
| } |
| } |
| |
| /* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted" |
| We use the manifest to find out if a file is xml and if it is encrypted. |
| The parameter is an encoded uri. However, the manifest contains paths. Therefore |
| the path is encoded as uri, so they can be compared. |
| */ |
| bool DigitalSignaturesDialog::isXML(const rtl::OUString& rURI ) |
| { |
| OSL_ASSERT(mxStore.is()); |
| |
| bool bIsXML = false; |
| bool bPropsAvailable = false; |
| const OUString sPropFullPath(RTL_CONSTASCII_USTRINGPARAM("FullPath")); |
| const OUString sPropMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType")); |
| const OUString sPropDigest(RTL_CONSTASCII_USTRINGPARAM("Digest")); |
| |
| for (int i = 0; i < m_manifest.getLength(); i++) |
| { |
| Any digest; |
| const Sequence< css::beans::PropertyValue >& entry = m_manifest[i]; |
| OUString sPath, sMediaType; |
| bool bEncrypted = false; |
| for (int j = 0; j < entry.getLength(); j++) |
| { |
| const css::beans::PropertyValue & prop = entry[j]; |
| |
| if (prop.Name.equals( sPropFullPath ) ) |
| prop.Value >>= sPath; |
| else if (prop.Name.equals( sPropMediaType ) ) |
| prop.Value >>= sMediaType; |
| else if (prop.Name.equals( sPropDigest ) ) |
| bEncrypted = true; |
| } |
| if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath)) |
| { |
| bIsXML = sMediaType.equals(OUSTR("text/xml")) && ! bEncrypted; |
| bPropsAvailable = true; |
| break; |
| } |
| } |
| if (!bPropsAvailable) |
| { |
| //This would be the case for at least mimetype, META-INF/manifest.xml |
| //META-INF/macrosignatures.xml. |
| //Files can only be encrypted if they are in the manifest.xml. |
| //That is, the current file cannot be encrypted, otherwise bPropsAvailable |
| //would be true. |
| OUString aXMLExt( RTL_CONSTASCII_USTRINGPARAM( "XML" ) ); |
| sal_Int32 nSep = rURI.lastIndexOf( '.' ); |
| if ( nSep != (-1) ) |
| { |
| OUString aExt = rURI.copy( nSep+1 ); |
| if (aExt.equalsIgnoreAsciiCase(aXMLExt )) |
| bIsXML = true; |
| } |
| } |
| return bIsXML; |
| } |
| |
| DigitalSignaturesDialog::DigitalSignaturesDialog( |
| Window* pParent, |
| uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode, |
| sal_Bool bReadOnly, const ::rtl::OUString& sODFVersion, bool bHasDocumentSignature) |
| :ModalDialog ( pParent, XMLSEC_RES( RID_XMLSECDLG_DIGSIG ) ) |
| ,mxCtx ( rxCtx ) |
| ,maSignatureHelper ( rxCtx ) |
| ,meSignatureMode ( eMode ) |
| ,maHintDocFT ( this, XMLSEC_RES( FT_HINT_DOC ) ) |
| ,maHintBasicFT ( this, XMLSEC_RES( FT_HINT_BASIC ) ) |
| ,maHintPackageFT ( this, XMLSEC_RES( FT_HINT_PACK ) ) |
| ,maSignaturesLB ( this, XMLSEC_RES( LB_SIGNATURES ) ) |
| ,maSigsValidImg ( this, XMLSEC_RES( IMG_STATE_VALID ) ) |
| ,maSigsValidFI ( this, XMLSEC_RES( FI_STATE_VALID ) ) |
| ,maSigsInvalidImg ( this, XMLSEC_RES( IMG_STATE_BROKEN ) ) |
| ,maSigsInvalidFI ( this, XMLSEC_RES( FI_STATE_BROKEN ) ) |
| ,maSigsNotvalidatedImg( this, XMLSEC_RES( IMG_STATE_NOTVALIDATED ) ) |
| ,maSigsNotvalidatedFI ( this, XMLSEC_RES( FI_STATE_NOTVALIDATED ) ) |
| ,maSigsOldSignatureFI ( this, XMLSEC_RES( FI_STATE_OLDSIGNATURE) ) |
| ,maViewBtn ( this, XMLSEC_RES( BTN_VIEWCERT ) ) |
| ,maAddBtn ( this, XMLSEC_RES( BTN_ADDCERT ) ) |
| ,maRemoveBtn ( this, XMLSEC_RES( BTN_REMOVECERT ) ) |
| ,maBottomSepFL ( this, XMLSEC_RES( FL_BOTTOM_SEP ) ) |
| ,maOKBtn ( this, XMLSEC_RES( BTN_OK ) ) |
| ,maHelpBtn ( this, XMLSEC_RES( BTN_HELP ) ) |
| ,m_sODFVersion (sODFVersion) |
| ,m_bHasDocumentSignature(bHasDocumentSignature) |
| ,m_bWarningShowSignMacro(false) |
| { |
| // --> PB #i48253 the tablistbox needs its own unique id |
| maSignaturesLB.Window::SetUniqueId( HID_XMLSEC_TREE_SIGNATURESDLG ); |
| // <-- |
| Size aControlSize( maSignaturesLB.GetSizePixel() ); |
| aControlSize = maSignaturesLB.PixelToLogic( aControlSize, MapMode( MAP_APPFONT ) ); |
| const long nControlWidth = aControlSize.Width(); |
| static long nTabs[] = { 4, 0, 6*nControlWidth/100, 36*nControlWidth/100, 74*nControlWidth/100 }; |
| maSignaturesLB.SetTabs( &nTabs[ 0 ] ); |
| maSignaturesLB.InsertHeaderEntry( String( XMLSEC_RES( STR_HEADERBAR ) ) ); |
| |
| maSigsNotvalidatedFI.SetText( String( XMLSEC_RES( STR_NO_INFO_TO_VERIFY ) ) ); |
| |
| if ( GetSettings().GetStyleSettings().GetHighContrastMode() ) |
| { |
| // high contrast mode needs other images |
| maSigsValidImg.SetImage( Image( XMLSEC_RES( IMG_STATE_VALID_HC ) ) ); |
| maSigsInvalidImg.SetImage( Image( XMLSEC_RES( IMG_STATE_BROKEN_HC ) ) ); |
| maSigsNotvalidatedImg.SetImage( Image( XMLSEC_RES( IMG_STATE_NOTVALIDATED_HC ) ) ); |
| } |
| |
| FreeResource(); |
| |
| mbVerifySignatures = true; |
| mbSignaturesChanged = false; |
| |
| maSignaturesLB.SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) ); |
| maSignaturesLB.SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) ); |
| |
| maViewBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) ); |
| maViewBtn.Disable(); |
| |
| maAddBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) ); |
| if ( bReadOnly ) |
| maAddBtn.Disable(); |
| |
| maRemoveBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) ); |
| maRemoveBtn.Disable(); |
| |
| maOKBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, OKButtonHdl) ); |
| |
| switch( meSignatureMode ) |
| { |
| case SignatureModeDocumentContent: maHintDocFT.Show(); break; |
| case SignatureModeMacros: maHintBasicFT.Show(); break; |
| case SignatureModePackage: maHintPackageFT.Show(); break; |
| } |
| |
| // adjust fixed text to images |
| XmlSec::AlignAndFitImageAndControl( maSigsValidImg, maSigsValidFI, 5 ); |
| XmlSec::AlignAndFitImageAndControl( maSigsInvalidImg, maSigsInvalidFI, 5 ); |
| XmlSec::AlignAndFitImageAndControl( maSigsNotvalidatedImg, maSigsNotvalidatedFI, 5 ); |
| XmlSec::AlignAndFitImageAndControl( maSigsNotvalidatedImg, maSigsOldSignatureFI, 5 ); |
| } |
| |
| DigitalSignaturesDialog::~DigitalSignaturesDialog() |
| { |
| } |
| |
| sal_Bool DigitalSignaturesDialog::Init() |
| { |
| bool bInit = maSignatureHelper.Init(); |
| |
| DBG_ASSERT( bInit, "Error initializing security context!" ); |
| |
| if ( bInit ) |
| { |
| maSignatureHelper.SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) ); |
| } |
| |
| return bInit; |
| } |
| |
| void DigitalSignaturesDialog::SetStorage( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rxStore ) |
| { |
| mxStore = rxStore; |
| maSignatureHelper.SetStorage( mxStore, m_sODFVersion); |
| |
| Reference < css::packages::manifest::XManifestReader > xReader( |
| mxCtx->getServiceManager()->createInstanceWithContext( |
| OUSTR("com.sun.star.packages.manifest.ManifestReader"), mxCtx), UNO_QUERY_THROW); |
| |
| //Get the manifest.xml |
| Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement( |
| OUSTR("META-INF"), css::embed::ElementModes::READ), UNO_QUERY_THROW); |
| |
| Reference< css::io::XInputStream > xStream( |
| xSubStore->openStreamElement(OUSTR("manifest.xml"), css::embed::ElementModes::READ), |
| UNO_QUERY_THROW); |
| |
| m_manifest = xReader->readManifestSequence(xStream); |
| } |
| |
| void DigitalSignaturesDialog::SetSignatureStream( const cssu::Reference < css::io::XStream >& rxStream ) |
| { |
| mxSignatureStream = rxStream; |
| } |
| |
| bool DigitalSignaturesDialog::canAddRemove() |
| { |
| //m56 |
| bool ret = true; |
| OSL_ASSERT(mxStore.is()); |
| bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion); |
| SaveODFItem item; |
| bool bSave1_1 = item.isLessODF1_2(); |
| |
| // see specification |
| //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw |
| //Paragraph 'Behavior with regard to ODF 1.2' |
| //For both, macro and document |
| if ( (!bSave1_1 && bDoc1_1) || (bSave1_1 && bDoc1_1) ) |
| { |
| //#4 |
| ErrorBox err(NULL, XMLSEC_RES(RID_XMLSECDLG_OLD_ODF_FORMAT)); |
| err.Execute(); |
| ret = false; |
| } |
| |
| //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is |
| //adding a macro signature will break an existing document signature. |
| //The sfx2 will remove the documentsignature when the user adds a macro signature |
| if (meSignatureMode == SignatureModeMacros |
| && ret) |
| { |
| if (m_bHasDocumentSignature && !m_bWarningShowSignMacro) |
| { |
| //The warning says that the document signatures will be removed if the user |
| //continues. He can then either press 'OK' or 'NO' |
| //It the user presses 'Add' or 'Remove' several times then, then the warning |
| //is shown every time until the user presses 'OK'. From then on, the warning |
| //is not displayed anymore as long as the signatures dialog is alive. |
| if (QueryBox( |
| NULL, XMLSEC_RES(MSG_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)).Execute() == RET_NO) |
| ret = false; |
| else |
| m_bWarningShowSignMacro = true; |
| |
| } |
| } |
| return ret; |
| } |
| |
| bool DigitalSignaturesDialog::canAdd() |
| { |
| if (canAddRemove()) |
| return true; |
| return false; |
| } |
| |
| bool DigitalSignaturesDialog::canRemove() |
| { |
| if (canAddRemove()) |
| return true; |
| return false; |
| } |
| |
| short DigitalSignaturesDialog::Execute() |
| { |
| // Verify Signatures and add certificates to ListBox... |
| mbVerifySignatures = true; |
| ImplGetSignatureInformations(false); |
| ImplFillSignaturesBox(); |
| |
| // Only verify once, content will not change. |
| // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove |
| mbVerifySignatures = false; |
| |
| return Dialog::Execute(); |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, SignatureHighlightHdl, void*, EMPTYARG ) |
| { |
| bool bSel = maSignaturesLB.FirstSelected() ? true : false; |
| maViewBtn.Enable( bSel ); |
| if ( maAddBtn.IsEnabled() ) // not read only |
| maRemoveBtn.Enable( bSel ); |
| |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, OKButtonHdl, void*, EMPTYARG ) |
| { |
| // Export all other signatures... |
| SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream( |
| embed::ElementModes::WRITE|embed::ElementModes::TRUNCATE, false ); |
| uno::Reference< io::XOutputStream > xOutputStream( |
| aStreamHelper.xSignatureStream, uno::UNO_QUERY ); |
| uno::Reference< com::sun::star::xml::sax::XDocumentHandler> xDocumentHandler = |
| maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream ); |
| |
| int nInfos = maCurrentSignatureInformations.size(); |
| for( int n = 0 ; n < nInfos ; ++n ) |
| maSignatureHelper.ExportSignature( |
| xDocumentHandler, maCurrentSignatureInformations[ n ] ); |
| |
| maSignatureHelper.CloseDocumentHandler( xDocumentHandler); |
| |
| // If stream was not provided, we are responsible for committing it.... |
| if ( !mxSignatureStream.is() ) |
| { |
| uno::Reference< embed::XTransactedObject > xTrans( |
| aStreamHelper.xSignatureStorage, uno::UNO_QUERY ); |
| xTrans->commit(); |
| } |
| |
| EndDialog(RET_OK); |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, SignatureSelectHdl, void*, EMPTYARG ) |
| { |
| ImplShowSignaturesDetails(); |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, ViewButtonHdl, Button*, EMPTYARG ) |
| { |
| ImplShowSignaturesDetails(); |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, AddButtonHdl, Button*, EMPTYARG ) |
| { |
| if( ! canAdd()) |
| return 0; |
| try |
| { |
| uno::Reference<com::sun::star::xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureHelper.GetSecurityEnvironment(); |
| |
| uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter = |
| ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); |
| CertificateChooser aChooser( this, mxCtx, xSecEnv, maCurrentSignatureInformations ); |
| if ( aChooser.Execute() == RET_OK ) |
| { |
| uno::Reference< ::com::sun::star::security::XCertificate > xCert = aChooser.GetSelectedCertificate(); |
| if ( !xCert.is() ) |
| { |
| DBG_ERRORFILE( "no certificate selected" ); |
| return -1; |
| } |
| rtl::OUString aCertSerial = xSerialNumberAdapter->toString( xCert->getSerialNumber() ); |
| if ( !aCertSerial.getLength() ) |
| { |
| DBG_ERROR( "Error in Certificate, problem with serial number!" ); |
| return -1; |
| } |
| |
| maSignatureHelper.StartMission(); |
| |
| sal_Int32 nSecurityId = maSignatureHelper.GetNewSecurityId(); |
| |
| rtl::OUStringBuffer aStrBuffer; |
| SvXMLUnitConverter::encodeBase64(aStrBuffer, xCert->getEncoded()); |
| |
| maSignatureHelper.SetX509Certificate( nSecurityId, |
| xCert->getIssuerName(), aCertSerial, |
| aStrBuffer.makeStringAndClear()); |
| |
| std::vector< rtl::OUString > aElements = |
| DocumentSignatureHelper::CreateElementList( |
| mxStore, rtl::OUString(), meSignatureMode, OOo3_2Document); |
| |
| sal_Int32 nElements = aElements.size(); |
| for ( sal_Int32 n = 0; n < nElements; n++ ) |
| { |
| bool bBinaryMode = !isXML(aElements[n]); |
| maSignatureHelper.AddForSigning( nSecurityId, aElements[n], aElements[n], bBinaryMode ); |
| } |
| |
| maSignatureHelper.SetDateTime( nSecurityId, Date(), Time() ); |
| |
| // We open a signature stream in which the existing and the new |
| //signature is written. ImplGetSignatureInformation (later in this function) will |
| //then read the stream an will fill maCurrentSignatureInformations. The final signature |
| //is written when the user presses OK. Then only maCurrentSignatureInformation and |
| //a sax writer are used to write the information. |
| SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream( |
| css::embed::ElementModes::WRITE|css::embed::ElementModes::TRUNCATE, true); |
| Reference< css::io::XOutputStream > xOutputStream( |
| aStreamHelper.xSignatureStream, UNO_QUERY_THROW); |
| Reference< css::xml::sax::XDocumentHandler> xDocumentHandler = |
| maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream ); |
| |
| // Export old signatures... |
| int nInfos = maCurrentSignatureInformations.size(); |
| for ( int n = 0; n < nInfos; n++ ) |
| maSignatureHelper.ExportSignature( xDocumentHandler, maCurrentSignatureInformations[n]); |
| |
| // Create a new one... |
| maSignatureHelper.CreateAndWriteSignature( xDocumentHandler ); |
| |
| // That's it... |
| maSignatureHelper.CloseDocumentHandler( xDocumentHandler); |
| |
| maSignatureHelper.EndMission(); |
| |
| aStreamHelper = SignatureStreamHelper(); // release objects... |
| |
| mbSignaturesChanged = true; |
| |
| sal_Int32 nStatus = maSignatureHelper.GetSignatureInformation( nSecurityId ).nStatus; |
| |
| if ( nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ) |
| { |
| mbSignaturesChanged = true; |
| |
| // Can't simply remember current information, need parsing for getting full information :( |
| // We need to verify the signatures again, otherwise the status in the signature information |
| // will not contain |
| // SecurityOperationStatus_OPERATION_SUCCEEDED |
| mbVerifySignatures = true; |
| ImplGetSignatureInformations(true); |
| ImplFillSignaturesBox(); |
| } |
| } |
| } |
| catch ( uno::Exception& ) |
| { |
| DBG_ERROR( "Exception while adding a signature!" ); |
| // Don't keep invalid entries... |
| ImplGetSignatureInformations(true); |
| ImplFillSignaturesBox(); |
| } |
| |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, RemoveButtonHdl, Button*, EMPTYARG ) |
| { |
| if (!canRemove()) |
| return 0; |
| if( maSignaturesLB.FirstSelected() ) |
| { |
| try |
| { |
| sal_uInt16 nSelected = (sal_uInt16) (sal_uIntPtr) maSignaturesLB.FirstSelected()->GetUserData(); |
| maCurrentSignatureInformations.erase( maCurrentSignatureInformations.begin()+nSelected ); |
| |
| // Export all other signatures... |
| SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream( |
| css::embed::ElementModes::WRITE | css::embed::ElementModes::TRUNCATE, true); |
| Reference< css::io::XOutputStream > xOutputStream( |
| aStreamHelper.xSignatureStream, UNO_QUERY_THROW); |
| Reference< css::xml::sax::XDocumentHandler> xDocumentHandler = |
| maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream ); |
| |
| int nInfos = maCurrentSignatureInformations.size(); |
| for( int n = 0 ; n < nInfos ; ++n ) |
| maSignatureHelper.ExportSignature( xDocumentHandler, maCurrentSignatureInformations[ n ] ); |
| |
| maSignatureHelper.CloseDocumentHandler( xDocumentHandler); |
| |
| mbSignaturesChanged = true; |
| |
| aStreamHelper = SignatureStreamHelper(); // release objects... |
| |
| ImplFillSignaturesBox(); |
| } |
| catch ( uno::Exception& ) |
| { |
| DBG_ERROR( "Exception while removing a signature!" ); |
| // Don't keep invalid entries... |
| ImplGetSignatureInformations(true); |
| ImplFillSignaturesBox(); |
| } |
| } |
| |
| return 0; |
| } |
| |
| IMPL_LINK( DigitalSignaturesDialog, StartVerifySignatureHdl, void*, EMPTYARG ) |
| { |
| return mbVerifySignatures ? 1 : 0; |
| } |
| |
| void DigitalSignaturesDialog::ImplFillSignaturesBox() |
| { |
| maSignaturesLB.Clear(); |
| |
| uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecEnv = maSignatureHelper.GetSecurityEnvironment(); |
| uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter = |
| ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); |
| |
| uno::Reference< ::com::sun::star::security::XCertificate > xCert; |
| |
| String aNullStr; |
| int nInfos = maCurrentSignatureInformations.size(); |
| int nValidSigs = 0, nValidCerts = 0; |
| bool bAllNewSignatures = true; |
| |
| if( nInfos ) |
| { |
| for( int n = 0; n < nInfos; ++n ) |
| { |
| DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm( |
| m_sODFVersion, maCurrentSignatureInformations[n]); |
| std::vector< rtl::OUString > aElementsToBeVerified = |
| DocumentSignatureHelper::CreateElementList( |
| mxStore, ::rtl::OUString(), meSignatureMode, mode); |
| |
| const SignatureInformation& rInfo = maCurrentSignatureInformations[n]; |
| //First we try to get the certificate which is embedded in the XML Signature |
| if (rInfo.ouX509Certificate.getLength()) |
| xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate); |
| else { |
| //There must be an embedded certificate because we use it to get the |
| //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName |
| //because it could be modified by an attacker. The issuer is displayed |
| //in the digital signature dialog. |
| //Comparing the X509IssuerName with the one from the X509Certificate in order |
| //to find out if the X509IssuerName was modified does not work. See #i62684 |
| DBG_ASSERT(sal_False, "Could not find embedded certificate!"); |
| } |
| |
| //In case there is no embedded certificate we try to get it from a local store |
| //Todo: This probably could be removed, see above. |
| if (!xCert.is()) |
| xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) ); |
| |
| DBG_ASSERT( xCert.is(), "Certificate not found and can't be created!" ); |
| |
| String aSubject; |
| String aIssuer; |
| String aDateTimeStr; |
| |
| bool bSigValid = false; |
| bool bCertValid = false; |
| if( xCert.is() ) |
| { |
| //check the validity of the cert |
| try { |
| sal_Int32 certResult = xSecEnv->verifyCertificate(xCert, |
| Sequence<css::uno::Reference<css::security::XCertificate> >()); |
| |
| bCertValid = certResult == css::security::CertificateValidity::VALID ? true : false; |
| if ( bCertValid ) |
| nValidCerts++; |
| |
| } catch (css::uno::SecurityException& ) { |
| OSL_ENSURE(0, "Verification of certificate failed"); |
| bCertValid = false; |
| } |
| |
| aSubject = XmlSec::GetContentPart( xCert->getSubjectName() ); |
| aIssuer = XmlSec::GetContentPart( xCert->getIssuerName() ); |
| // --> PB 2004-10-12 #i20172# String with date and time information |
| aDateTimeStr = XmlSec::GetDateTimeString( rInfo.stDateTime ); |
| } |
| bSigValid = ( rInfo.nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ); |
| |
| if ( bSigValid ) |
| { |
| bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned( |
| aElementsToBeVerified, rInfo, mode); |
| |
| if( bSigValid ) |
| nValidSigs++; |
| } |
| |
| Image aImage; |
| if (!bSigValid) |
| { |
| aImage = maSigsInvalidImg.GetImage(); |
| } |
| else if (bSigValid && !bCertValid) |
| { |
| aImage = maSigsNotvalidatedImg.GetImage(); |
| } |
| //Check if the signature is a "old" document signature, that is, which was created |
| //by an version of OOo previous to 3.2 |
| else if (meSignatureMode == SignatureModeDocumentContent |
| && bSigValid && bCertValid && !DocumentSignatureHelper::isOOo3_2_Signature( |
| maCurrentSignatureInformations[n])) |
| { |
| aImage = maSigsNotvalidatedImg.GetImage(); |
| bAllNewSignatures &= false; |
| } |
| else if (meSignatureMode == SignatureModeDocumentContent |
| && bSigValid && bCertValid && DocumentSignatureHelper::isOOo3_2_Signature( |
| maCurrentSignatureInformations[n])) |
| { |
| aImage = maSigsValidImg.GetImage(); |
| } |
| else if (meSignatureMode == SignatureModeMacros |
| && bSigValid && bCertValid) |
| { |
| aImage = aImage = maSigsValidImg.GetImage(); |
| } |
| |
| SvLBoxEntry* pEntry = maSignaturesLB.InsertEntry( aNullStr, aImage, aImage ); |
| maSignaturesLB.SetEntryText( aSubject, pEntry, 1 ); |
| maSignaturesLB.SetEntryText( aIssuer, pEntry, 2 ); |
| maSignaturesLB.SetEntryText( aDateTimeStr, pEntry, 3 ); |
| pEntry->SetUserData( ( void* ) n ); // missuse user data as index |
| } |
| } |
| |
| bool bAllSigsValid = (nValidSigs == nInfos); |
| bool bAllCertsValid = (nValidCerts == nInfos); |
| bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures); |
| |
| bool bShowNotValidatedState = nInfos && (bAllSigsValid && (!bAllCertsValid || !bAllNewSignatures)); |
| bool bShowInvalidState = nInfos && !bAllSigsValid; |
| |
| maSigsValidImg.Show( bShowValidState); |
| maSigsValidFI.Show( bShowValidState ); |
| maSigsInvalidImg.Show( bShowInvalidState ); |
| maSigsInvalidFI.Show( bShowInvalidState ); |
| |
| maSigsNotvalidatedImg.Show(bShowNotValidatedState); |
| //bAllNewSignatures is always true if we are not in document mode |
| maSigsNotvalidatedFI.Show(nInfos && bAllSigsValid && ! bAllCertsValid); |
| maSigsOldSignatureFI.Show(nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures); |
| |
| SignatureHighlightHdl( NULL ); |
| } |
| |
| |
| //If bUseTempStream is true then the temporary signature stream is used. |
| //Otherwise the real signature stream is used. |
| void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream) |
| { |
| maCurrentSignatureInformations.clear(); |
| |
| maSignatureHelper.StartMission(); |
| |
| SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream( |
| css::embed::ElementModes::READ, bUseTempStream); |
| if ( aStreamHelper.xSignatureStream.is() ) |
| { |
| uno::Reference< io::XInputStream > xInputStream( aStreamHelper.xSignatureStream, uno::UNO_QUERY ); |
| maSignatureHelper.ReadAndVerifySignature( xInputStream ); |
| } |
| maSignatureHelper.EndMission(); |
| |
| maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations(); |
| |
| mbVerifySignatures = false; |
| } |
| |
| void DigitalSignaturesDialog::ImplShowSignaturesDetails() |
| { |
| if( maSignaturesLB.FirstSelected() ) |
| { |
| sal_uInt16 nSelected = (sal_uInt16) (sal_uIntPtr) maSignaturesLB.FirstSelected()->GetUserData(); |
| const SignatureInformation& rInfo = maCurrentSignatureInformations[ nSelected ]; |
| css::uno::Reference<css::xml::crypto::XSecurityEnvironment > xSecEnv = |
| maSignatureHelper.GetSecurityEnvironment(); |
| css::uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter = |
| ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); |
| // Use Certificate from doc, not from key store |
| uno::Reference< dcss::security::XCertificate > xCert; |
| if (rInfo.ouX509Certificate.getLength()) |
| xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate); |
| //fallback if no certificate is embedded, get if from store |
| if (!xCert.is()) |
| xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) ); |
| |
| DBG_ASSERT( xCert.is(), "Error getting cCertificate!" ); |
| if ( xCert.is() ) |
| { |
| CertificateViewer aViewer( this, maSignatureHelper.GetSecurityEnvironment(), xCert, sal_False ); |
| aViewer.Execute(); |
| } |
| } |
| } |
| |
| //If bTempStream is true, then a temporary stream is return. If it is false then, the actual |
| //signature stream is used. |
| //Everytime the user presses Add a new temporary stream is created. |
| //We keep the temporary stream as member because ImplGetSignatureInformations |
| //will later access the stream to create DocumentSignatureInformation objects |
| //which are stored in maCurrentSignatureInformations. |
| SignatureStreamHelper DigitalSignaturesDialog::ImplOpenSignatureStream( |
| sal_Int32 nStreamOpenMode, bool bTempStream) |
| { |
| SignatureStreamHelper aHelper; |
| if (bTempStream) |
| { |
| if (nStreamOpenMode & css::embed::ElementModes::TRUNCATE) |
| { |
| //We write always into a new temporary stream. |
| mxTempSignatureStream = Reference < css::io::XStream >( |
| mxCtx->getServiceManager()->createInstanceWithContext( |
| OUSTR( "com.sun.star.io.TempFile" ), mxCtx) , |
| UNO_QUERY_THROW); |
| aHelper.xSignatureStream = mxTempSignatureStream; |
| } |
| else |
| { |
| //When we read from the temp stream, then we must have previously |
| //created one. |
| OSL_ASSERT(mxTempSignatureStream.is()); |
| } |
| aHelper.xSignatureStream = mxTempSignatureStream; |
| } |
| else |
| { |
| //No temporary stream |
| if (!mxSignatureStream.is()) |
| { |
| //We may not have a dedicated stream for writing the signature |
| //So we take one directly from the storage |
| //Or DocumentDigitalSignatures::showDocumentContentSignatures was called, |
| //in which case Add/Remove is not allowed. This is done, for example, if the |
| //document is readonly |
| aHelper = DocumentSignatureHelper::OpenSignatureStream( |
| mxStore, nStreamOpenMode, meSignatureMode ); |
| } |
| else |
| { |
| aHelper.xSignatureStream = mxSignatureStream; |
| } |
| } |
| |
| if (nStreamOpenMode & css::embed::ElementModes::TRUNCATE) |
| { |
| css::uno::Reference < css::io::XTruncate > xTruncate( |
| aHelper.xSignatureStream, UNO_QUERY_THROW); |
| DBG_ASSERT( xTruncate.is(), "ImplOpenSignatureStream - Stream does not support xTruncate!" ); |
| xTruncate->truncate(); |
| } |
| else if ( bTempStream || mxSignatureStream.is()) |
| { |
| //In case we read the signature stream from the storage directly, |
| //which is the case when DocumentDigitalSignatures::showDocumentContentSignatures |
| //then XSeakable is not supported |
| css::uno::Reference < css::io::XSeekable > xSeek( |
| aHelper.xSignatureStream, UNO_QUERY_THROW); |
| DBG_ASSERT( xSeek.is(), "ImplOpenSignatureStream - Stream does not support xSeekable!" ); |
| xSeek->seek( 0 ); |
| } |
| |
| return aHelper; |
| } |
| |