1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlsecurity.hxx"
26 #include <xmlsecurity/digitalsignaturesdialog.hxx>
27 #include <xmlsecurity/certificatechooser.hxx>
28 #include <xmlsecurity/certificateviewer.hxx>
29 #include <xmlsecurity/biginteger.hxx>
30 #include <xmloff/xmluconv.hxx>
31 #include <com/sun/star/embed/XStorage.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
33 #include <com/sun/star/io/XSeekable.hpp>
34 #include <com/sun/star/io/XTruncate.hpp>
35 #include <com/sun/star/embed/XTransactedObject.hpp>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/lang/XComponent.hpp>
38 #include <com/sun/star/security/NoPasswordException.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/security/CertificateValidity.hdl>
42 #include <com/sun/star/packages/WrongPasswordException.hpp>
43 #include <com/sun/star/security/SerialNumberAdapter.hpp>
44 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
45 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
46 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
47 
48 
49 #include <rtl/ustrbuf.hxx>
50 #include <rtl/uri.hxx>
51 
52 #include <tools/date.hxx>
53 #include <tools/time.hxx>
54 
55 #include "dialogs.hrc"
56 #include "digitalsignaturesdialog.hrc"
57 #include "helpids.hrc"
58 #include "resourcemanager.hxx"
59 
60 #include <vcl/msgbox.hxx> // Until encrypted docs work...
61 #include <unotools/configitem.hxx>
62 #include <comphelper/componentcontext.hxx>
63 
64 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
65 
66 
67 /* HACK: disable some warnings for MS-C */
68 #ifdef _MSC_VER
69 #pragma warning (disable : 4355)	// 4355: this used in initializer-list
70 #endif
71 
72 using namespace ::com::sun::star::security;
73 using namespace ::com::sun::star::uno;
74 using namespace ::com::sun::star;
75 namespace css = ::com::sun::star;
76 using ::rtl::OUString;
77 
78 namespace
79 {
80     class SaveODFItem: public utl::ConfigItem
81     {
82         sal_Int16 m_nODF;
83     public:
84 	virtual void Commit();
85 	virtual void Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
86         SaveODFItem();
87         //See group ODF in Common.xcs
isLessODF1_2()88         bool isLessODF1_2()
89         {
90             return m_nODF < 3;
91         }
92     };
93 
Commit()94 void SaveODFItem::Commit() {}
Notify(const::com::sun::star::uno::Sequence<rtl::OUString> &)95 void SaveODFItem::Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& ) {}
96 
SaveODFItem()97     SaveODFItem::SaveODFItem(): utl::ConfigItem(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
98         "Office.Common/Save"))), m_nODF(0)
99     {
100         OUString sDef(RTL_CONSTASCII_USTRINGPARAM("ODF/DefaultVersion"));
101         Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) );
102         if ( aValues.getLength() == 1)
103         {
104             sal_Int16 nTmp = 0;
105             if ( aValues[0] >>= nTmp )
106                 m_nODF = nTmp;
107             else
108                 throw uno::RuntimeException(
109                     OUString(RTL_CONSTASCII_USTRINGPARAM(
110                         "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!")), 0 );
111 
112         }
113         else
114             throw uno::RuntimeException(
115                 OUString(RTL_CONSTASCII_USTRINGPARAM(
116                     "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion")), 0);
117     }
118 }
119 
120 /* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted"
121     We use the manifest to find out if a file is xml and if it is encrypted.
122     The parameter is an encoded uri. However, the manifest contains paths. Therefore
123     the path is encoded as uri, so they can be compared.
124 */
isXML(const rtl::OUString & rURI)125 bool DigitalSignaturesDialog::isXML(const rtl::OUString& rURI )
126 {
127     OSL_ASSERT(mxStore.is());
128 
129     bool bIsXML = false;
130     bool bPropsAvailable = false;
131     const OUString sPropFullPath(RTL_CONSTASCII_USTRINGPARAM("FullPath"));
132     const OUString sPropMediaType(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
133     const OUString sPropDigest(RTL_CONSTASCII_USTRINGPARAM("Digest"));
134 
135     for (int i = 0; i < m_manifest.getLength(); i++)
136     {
137         Any digest;
138         const Sequence< css::beans::PropertyValue >& entry = m_manifest[i];
139         OUString sPath, sMediaType;
140         bool bEncrypted = false;
141         for (int j = 0; j < entry.getLength(); j++)
142         {
143             const css::beans::PropertyValue & prop = entry[j];
144 
145             if (prop.Name.equals( sPropFullPath ) )
146                 prop.Value >>= sPath;
147             else if (prop.Name.equals( sPropMediaType ) )
148                 prop.Value >>= sMediaType;
149             else if (prop.Name.equals( sPropDigest ) )
150                 bEncrypted = true;
151         }
152         if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath))
153         {
154             bIsXML = sMediaType.equals(OUSTR("text/xml")) && ! bEncrypted;
155             bPropsAvailable = true;
156             break;
157         }
158     }
159     if (!bPropsAvailable)
160     {
161         //This would be the case for at least mimetype, META-INF/manifest.xml
162         //META-INF/macrosignatures.xml.
163         //Files can only be encrypted if they are in the manifest.xml.
164         //That is, the current file cannot be encrypted, otherwise bPropsAvailable
165         //would be true.
166         OUString aXMLExt( RTL_CONSTASCII_USTRINGPARAM( "XML" ) );
167         sal_Int32 nSep = rURI.lastIndexOf( '.' );
168         if ( nSep != (-1) )
169         {
170             OUString aExt = rURI.copy( nSep+1 );
171             if (aExt.equalsIgnoreAsciiCase(aXMLExt ))
172                 bIsXML = true;
173         }
174      }
175     return bIsXML;
176 }
177 
DigitalSignaturesDialog(Window * pParent,uno::Reference<uno::XComponentContext> & rxCtx,DocumentSignatureMode eMode,sal_Bool bReadOnly,const::rtl::OUString & sODFVersion,bool bHasDocumentSignature)178 DigitalSignaturesDialog::DigitalSignaturesDialog(
179     Window* pParent,
180     uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode,
181     sal_Bool bReadOnly, const ::rtl::OUString& sODFVersion, bool bHasDocumentSignature)
182 	:ModalDialog		( pParent, XMLSEC_RES( RID_XMLSECDLG_DIGSIG ) )
183 	,mxCtx 				( rxCtx )
184 	,maSignatureHelper	( rxCtx )
185 	,meSignatureMode	( eMode )
186 	,maHintDocFT		( this, XMLSEC_RES( FT_HINT_DOC ) )
187 	,maHintBasicFT		( this, XMLSEC_RES( FT_HINT_BASIC ) )
188 	,maHintPackageFT	( this, XMLSEC_RES( FT_HINT_PACK ) )
189 	,maSignaturesLB		( this, XMLSEC_RES( LB_SIGNATURES ) )
190 	,maSigsValidImg		( this, XMLSEC_RES( IMG_STATE_VALID ) )
191 	,maSigsValidFI		( this, XMLSEC_RES( FI_STATE_VALID ) )
192 	,maSigsInvalidImg	( this, XMLSEC_RES( IMG_STATE_BROKEN ) )
193     ,maSigsInvalidFI    ( this, XMLSEC_RES( FI_STATE_BROKEN ) )
194     ,maSigsNotvalidatedImg( this, XMLSEC_RES( IMG_STATE_NOTVALIDATED ) )
195     ,maSigsNotvalidatedFI ( this, XMLSEC_RES( FI_STATE_NOTVALIDATED ) )
196     ,maSigsOldSignatureFI ( this, XMLSEC_RES( FI_STATE_OLDSIGNATURE) )
197     ,maViewBtn          ( this, XMLSEC_RES( BTN_VIEWCERT ) )
198 	,maAddBtn			( this, XMLSEC_RES( BTN_ADDCERT ) )
199 	,maRemoveBtn		( this, XMLSEC_RES( BTN_REMOVECERT ) )
200 	,maBottomSepFL		( this, XMLSEC_RES( FL_BOTTOM_SEP ) )
201 	,maOKBtn			( this, XMLSEC_RES( BTN_OK ) )
202 	,maHelpBtn			( this, XMLSEC_RES( BTN_HELP ) )
203     ,m_sODFVersion (sODFVersion)
204     ,m_bHasDocumentSignature(bHasDocumentSignature)
205     ,m_bWarningShowSignMacro(false)
206 {
207     // --> PB #i48253 the tablistbox needs its own unique id
208     maSignaturesLB.Window::SetUniqueId( HID_XMLSEC_TREE_SIGNATURESDLG );
209     // <--
210     Size aControlSize( maSignaturesLB.GetSizePixel() );
211     aControlSize = maSignaturesLB.PixelToLogic( aControlSize, MapMode( MAP_APPFONT ) );
212     const long nControlWidth = aControlSize.Width();
213     static long nTabs[] = { 4, 0, 6*nControlWidth/100, 36*nControlWidth/100, 74*nControlWidth/100 };
214 	maSignaturesLB.SetTabs( &nTabs[ 0 ] );
215 	maSignaturesLB.InsertHeaderEntry( String( XMLSEC_RES( STR_HEADERBAR ) ) );
216 
217     maSigsNotvalidatedFI.SetText( String( XMLSEC_RES( STR_NO_INFO_TO_VERIFY ) ) );
218 
219     if ( GetSettings().GetStyleSettings().GetHighContrastMode() )
220     {
221         // high contrast mode needs other images
222         maSigsValidImg.SetImage( Image( XMLSEC_RES( IMG_STATE_VALID_HC ) ) );
223         maSigsInvalidImg.SetImage( Image( XMLSEC_RES( IMG_STATE_BROKEN_HC ) ) );
224         maSigsNotvalidatedImg.SetImage( Image( XMLSEC_RES( IMG_STATE_NOTVALIDATED_HC ) ) );
225     }
226 
227     FreeResource();
228 
229 	mbVerifySignatures = true;
230 	mbSignaturesChanged = false;
231 
232 	maSignaturesLB.SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) );
233 	maSignaturesLB.SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );
234 
235 	maViewBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
236 	maViewBtn.Disable();
237 
238 	maAddBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) );
239 	if ( bReadOnly  )
240 	    maAddBtn.Disable();
241 
242 	maRemoveBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) );
243 	maRemoveBtn.Disable();
244 
245     maOKBtn.SetClickHdl( LINK( this, DigitalSignaturesDialog, OKButtonHdl) );
246 
247 	switch( meSignatureMode )
248 	{
249 		case SignatureModeDocumentContent:	maHintDocFT.Show();		break;
250 		case SignatureModeMacros:		    maHintBasicFT.Show();	break;
251 		case SignatureModePackage:	        maHintPackageFT.Show();	break;
252 	}
253 
254 	// adjust fixed text to images
255 	XmlSec::AlignAndFitImageAndControl( maSigsValidImg, maSigsValidFI, 5 );
256 	XmlSec::AlignAndFitImageAndControl( maSigsInvalidImg, maSigsInvalidFI, 5 );
257     XmlSec::AlignAndFitImageAndControl( maSigsNotvalidatedImg, maSigsNotvalidatedFI, 5 );
258     XmlSec::AlignAndFitImageAndControl( maSigsNotvalidatedImg, maSigsOldSignatureFI, 5 );
259 }
260 
~DigitalSignaturesDialog()261 DigitalSignaturesDialog::~DigitalSignaturesDialog()
262 {
263 }
264 
Init()265 sal_Bool DigitalSignaturesDialog::Init()
266 {
267     bool bInit = maSignatureHelper.Init();
268 
269     DBG_ASSERT( bInit, "Error initializing security context!" );
270 
271     if ( bInit )
272     {
273         maSignatureHelper.SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) );
274     }
275 
276     return bInit;
277 }
278 
SetStorage(const com::sun::star::uno::Reference<com::sun::star::embed::XStorage> & rxStore)279 void DigitalSignaturesDialog::SetStorage( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rxStore )
280 {
281     mxStore = rxStore;
282     maSignatureHelper.SetStorage( mxStore, m_sODFVersion);
283 
284     Reference < css::packages::manifest::XManifestReader > xReader(
285         mxCtx->getServiceManager()->createInstanceWithContext(
286         OUSTR("com.sun.star.packages.manifest.ManifestReader"), mxCtx), UNO_QUERY_THROW);
287 
288 	//Get the manifest.xml
289     Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement(
290                 OUSTR("META-INF"), css::embed::ElementModes::READ), UNO_QUERY_THROW);
291 
292     Reference< css::io::XInputStream > xStream(
293         xSubStore->openStreamElement(OUSTR("manifest.xml"), css::embed::ElementModes::READ),
294         UNO_QUERY_THROW);
295 
296     m_manifest = xReader->readManifestSequence(xStream);
297 }
298 
SetSignatureStream(const cssu::Reference<css::io::XStream> & rxStream)299 void DigitalSignaturesDialog::SetSignatureStream( const cssu::Reference < css::io::XStream >& rxStream )
300 {
301     mxSignatureStream = rxStream;
302 }
303 
canAddRemove()304 bool DigitalSignaturesDialog::canAddRemove()
305 {
306     //m56
307     bool ret = true;
308     OSL_ASSERT(mxStore.is());
309     bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
310     SaveODFItem item;
311     bool bSave1_1 = item.isLessODF1_2();
312 
313     // see specification
314     //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw
315     //Paragraph 'Behavior with regard to ODF 1.2'
316     //For both, macro and document
317     if ( (!bSave1_1  && bDoc1_1) || (bSave1_1 && bDoc1_1) )
318     {
319         //#4
320         ErrorBox err(NULL, XMLSEC_RES(RID_XMLSECDLG_OLD_ODF_FORMAT));
321         err.Execute();
322         ret = false;
323     }
324 
325     //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is
326     //adding a macro signature will break an existing document signature.
327     //The sfx2 will remove the documentsignature when the user adds a macro signature
328     if (meSignatureMode == SignatureModeMacros
329         && ret)
330     {
331         if (m_bHasDocumentSignature && !m_bWarningShowSignMacro)
332         {
333             //The warning says that the document signatures will be removed if the user
334             //continues. He can then either press 'OK' or 'NO'
335             //It the user presses 'Add' or 'Remove' several times then, then the warning
336             //is shown every time until the user presses 'OK'. From then on, the warning
337             //is not displayed anymore as long as the signatures dialog is alive.
338             if (QueryBox(
339                 NULL, XMLSEC_RES(MSG_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)).Execute() == RET_NO)
340                 ret = false;
341             else
342                 m_bWarningShowSignMacro = true;
343 
344         }
345     }
346     return ret;
347 }
348 
canAdd()349 bool DigitalSignaturesDialog::canAdd()
350 {
351     if (canAddRemove())
352         return true;
353     return false;
354 }
355 
canRemove()356 bool DigitalSignaturesDialog::canRemove()
357 {
358     if (canAddRemove())
359         return true;
360     return false;
361 }
362 
Execute()363 short DigitalSignaturesDialog::Execute()
364 {
365     // Verify Signatures and add certificates to ListBox...
366     mbVerifySignatures = true;
367     ImplGetSignatureInformations(false);
368     ImplFillSignaturesBox();
369 
370     // Only verify once, content will not change.
371     // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
372     mbVerifySignatures = false;
373 
374     return Dialog::Execute();
375 }
376 
IMPL_LINK(DigitalSignaturesDialog,SignatureHighlightHdl,void *,EMPTYARG)377 IMPL_LINK( DigitalSignaturesDialog, SignatureHighlightHdl, void*, EMPTYARG )
378 {
379 	bool bSel = maSignaturesLB.FirstSelected() ? true : false;
380     maViewBtn.Enable( bSel );
381     if ( maAddBtn.IsEnabled() ) // not read only
382 	    maRemoveBtn.Enable( bSel );
383 
384     return 0;
385 }
386 
IMPL_LINK(DigitalSignaturesDialog,OKButtonHdl,void *,EMPTYARG)387 IMPL_LINK( DigitalSignaturesDialog, OKButtonHdl, void*, EMPTYARG )
388 {
389     // Export all other signatures...
390     SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
391         embed::ElementModes::WRITE|embed::ElementModes::TRUNCATE, false );
392     uno::Reference< io::XOutputStream > xOutputStream(
393         aStreamHelper.xSignatureStream, uno::UNO_QUERY );
394     uno::Reference< com::sun::star::xml::sax::XDocumentHandler> xDocumentHandler =
395         maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream );
396 
397     int nInfos = maCurrentSignatureInformations.size();
398     for( int n = 0 ; n < nInfos ; ++n )
399         maSignatureHelper.ExportSignature(
400         xDocumentHandler, maCurrentSignatureInformations[ n ] );
401 
402     maSignatureHelper.CloseDocumentHandler( xDocumentHandler);
403 
404     // If stream was not provided, we are responsible for committing it....
405     if ( !mxSignatureStream.is() )
406     {
407         uno::Reference< embed::XTransactedObject > xTrans(
408             aStreamHelper.xSignatureStorage, uno::UNO_QUERY );
409         xTrans->commit();
410     }
411 
412     EndDialog(RET_OK);
413     return 0;
414 }
415 
IMPL_LINK(DigitalSignaturesDialog,SignatureSelectHdl,void *,EMPTYARG)416 IMPL_LINK( DigitalSignaturesDialog, SignatureSelectHdl, void*, EMPTYARG )
417 {
418     ImplShowSignaturesDetails();
419     return 0;
420 }
421 
IMPL_LINK(DigitalSignaturesDialog,ViewButtonHdl,Button *,EMPTYARG)422 IMPL_LINK( DigitalSignaturesDialog, ViewButtonHdl, Button*, EMPTYARG )
423 {
424     ImplShowSignaturesDetails();
425     return 0;
426 }
427 
IMPL_LINK(DigitalSignaturesDialog,AddButtonHdl,Button *,EMPTYARG)428 IMPL_LINK( DigitalSignaturesDialog, AddButtonHdl, Button*, EMPTYARG )
429 {
430     if( ! canAdd())
431         return 0;
432     try
433     {
434         uno::Reference<com::sun::star::xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureHelper.GetSecurityEnvironment();
435 
436         uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter =
437 			::com::sun::star::security::SerialNumberAdapter::create(mxCtx);
438         CertificateChooser aChooser( this, mxCtx, xSecEnv, maCurrentSignatureInformations );
439         if ( aChooser.Execute() == RET_OK )
440         {
441             uno::Reference< ::com::sun::star::security::XCertificate > xCert = aChooser.GetSelectedCertificate();
442             if ( !xCert.is() )
443             {
444                 DBG_ERRORFILE( "no certificate selected" );
445                 return -1;
446             }
447             rtl::OUString aCertSerial = xSerialNumberAdapter->toString( xCert->getSerialNumber() );
448             if ( !aCertSerial.getLength() )
449             {
450                 DBG_ERROR( "Error in Certificate, problem with serial number!" );
451                 return -1;
452             }
453 
454             maSignatureHelper.StartMission();
455 
456             sal_Int32 nSecurityId = maSignatureHelper.GetNewSecurityId();
457 
458             rtl::OUStringBuffer aStrBuffer;
459             SvXMLUnitConverter::encodeBase64(aStrBuffer, xCert->getEncoded());
460 
461             maSignatureHelper.SetX509Certificate( nSecurityId,
462                 xCert->getIssuerName(), aCertSerial,
463                 aStrBuffer.makeStringAndClear());
464 
465             std::vector< rtl::OUString > aElements =
466                 DocumentSignatureHelper::CreateElementList(
467                     mxStore, rtl::OUString(), meSignatureMode, OOo3_2Document);
468 
469             sal_Int32 nElements = aElements.size();
470             for ( sal_Int32 n = 0; n < nElements; n++ )
471             {
472                 bool bBinaryMode = !isXML(aElements[n]);
473                 maSignatureHelper.AddForSigning( nSecurityId, aElements[n], aElements[n], bBinaryMode );
474             }
475 
476             maSignatureHelper.SetDateTime( nSecurityId, Date(), Time() );
477 
478             // We open a signature stream in which the existing and the new
479             //signature is written. ImplGetSignatureInformation (later in this function) will
480             //then read the stream an will fill  maCurrentSignatureInformations. The final signature
481             //is written when the user presses OK. Then only maCurrentSignatureInformation and
482             //a sax writer are used to write the information.
483             SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
484                 css::embed::ElementModes::WRITE|css::embed::ElementModes::TRUNCATE, true);
485             Reference< css::io::XOutputStream > xOutputStream(
486                 aStreamHelper.xSignatureStream, UNO_QUERY_THROW);
487             Reference< css::xml::sax::XDocumentHandler> xDocumentHandler =
488                 maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream );
489 
490             // Export old signatures...
491  	        int nInfos = maCurrentSignatureInformations.size();
492             for ( int n = 0; n < nInfos; n++ )
493 	            maSignatureHelper.ExportSignature( xDocumentHandler, maCurrentSignatureInformations[n]);
494 
495             // Create a new one...
496 	        maSignatureHelper.CreateAndWriteSignature( xDocumentHandler );
497 
498             // That's it...
499 	        maSignatureHelper.CloseDocumentHandler( xDocumentHandler);
500 
501             maSignatureHelper.EndMission();
502 
503 			aStreamHelper = SignatureStreamHelper();	// release objects...
504 
505             mbSignaturesChanged = true;
506 
507             sal_Int32 nStatus = maSignatureHelper.GetSignatureInformation( nSecurityId ).nStatus;
508 
509             if ( nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED )
510             {
511                 mbSignaturesChanged = true;
512 
513                 // Can't simply remember current information, need parsing for getting full information :(
514 				// We need to verify the signatures again, otherwise the status in the signature information
515 				// will not contain
516 				// SecurityOperationStatus_OPERATION_SUCCEEDED
517 				mbVerifySignatures = true;
518                 ImplGetSignatureInformations(true);
519                 ImplFillSignaturesBox();
520             }
521         }
522     }
523 	catch ( uno::Exception& )
524 	{
525 	    DBG_ERROR( "Exception while adding a signature!" );
526 		// Don't keep invalid entries...
527 		ImplGetSignatureInformations(true);
528         ImplFillSignaturesBox();
529 	}
530 
531     return 0;
532 }
533 
IMPL_LINK(DigitalSignaturesDialog,RemoveButtonHdl,Button *,EMPTYARG)534 IMPL_LINK( DigitalSignaturesDialog, RemoveButtonHdl, Button*, EMPTYARG )
535 {
536     if (!canRemove())
537         return 0;
538 	if( maSignaturesLB.FirstSelected() )
539 	{
540 	    try
541 	    {
542             sal_uInt16 nSelected = (sal_uInt16) (sal_uIntPtr) maSignaturesLB.FirstSelected()->GetUserData();
543     		maCurrentSignatureInformations.erase( maCurrentSignatureInformations.begin()+nSelected );
544 
545     		// Export all other signatures...
546             SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
547                 css::embed::ElementModes::WRITE | css::embed::ElementModes::TRUNCATE, true);
548             Reference< css::io::XOutputStream > xOutputStream(
549                 aStreamHelper.xSignatureStream, UNO_QUERY_THROW);
550             Reference< css::xml::sax::XDocumentHandler> xDocumentHandler =
551                 maSignatureHelper.CreateDocumentHandlerWithHeader( xOutputStream );
552 
553             int nInfos = maCurrentSignatureInformations.size();
554     		for( int n = 0 ; n < nInfos ; ++n )
555     			maSignatureHelper.ExportSignature( xDocumentHandler, maCurrentSignatureInformations[ n ] );
556 
557     	    maSignatureHelper.CloseDocumentHandler( xDocumentHandler);
558 
559             mbSignaturesChanged = true;
560 
561 			aStreamHelper = SignatureStreamHelper();	// release objects...
562 
563             ImplFillSignaturesBox();
564         }
565     	catch ( uno::Exception& )
566     	{
567     	    DBG_ERROR( "Exception while removing a signature!" );
568 			// Don't keep invalid entries...
569 			ImplGetSignatureInformations(true);
570 			ImplFillSignaturesBox();
571     	}
572 	}
573 
574     return 0;
575 }
576 
IMPL_LINK(DigitalSignaturesDialog,StartVerifySignatureHdl,void *,EMPTYARG)577 IMPL_LINK( DigitalSignaturesDialog, StartVerifySignatureHdl, void*, EMPTYARG )
578 {
579     return mbVerifySignatures ? 1 : 0;
580 }
581 
ImplFillSignaturesBox()582 void DigitalSignaturesDialog::ImplFillSignaturesBox()
583 {
584     maSignaturesLB.Clear();
585 
586     uno::Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecEnv = maSignatureHelper.GetSecurityEnvironment();
587     uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter =
588         ::com::sun::star::security::SerialNumberAdapter::create(mxCtx);
589 
590     uno::Reference< ::com::sun::star::security::XCertificate > xCert;
591 
592 	String aNullStr;
593 	int nInfos = maCurrentSignatureInformations.size();
594     int nValidSigs = 0, nValidCerts = 0;
595     bool bAllNewSignatures = true;
596 
597     if( nInfos )
598     {
599         for( int n = 0; n < nInfos; ++n )
600         {
601             DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
602                 m_sODFVersion, maCurrentSignatureInformations[n]);
603             std::vector< rtl::OUString > aElementsToBeVerified =
604                 DocumentSignatureHelper::CreateElementList(
605                 mxStore, ::rtl::OUString(), meSignatureMode, mode);
606 
607             const SignatureInformation& rInfo = maCurrentSignatureInformations[n];
608 			//First we try to get the certificate which is embedded in the XML Signature
609             if (rInfo.ouX509Certificate.getLength())
610 			    xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
611             else {
612                 //There must be an embedded certificate because we use it to get the
613                 //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
614                 //because it could be modified by an attacker. The issuer is displayed
615                 //in the digital signature dialog.
616                 //Comparing the X509IssuerName with the one from the X509Certificate in order
617                 //to find out if the X509IssuerName was modified does not work. See #i62684
618                 DBG_ASSERT(sal_False, "Could not find embedded certificate!");
619             }
620 
621 			//In case there is no embedded certificate we try to get it from a local store
622             //Todo: This probably could be removed, see above.
623 			if (!xCert.is())
624 				xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) );
625 
626 		    DBG_ASSERT( xCert.is(), "Certificate not found and can't be created!" );
627 
628 		    String	aSubject;
629 		    String	aIssuer;
630 		    String	aDateTimeStr;
631 
632             bool bSigValid = false;
633             bool bCertValid = false;
634             if( xCert.is() )
635 		    {
636                 //check the validity of the cert
637                 try {
638                     sal_Int32 certResult = xSecEnv->verifyCertificate(xCert,
639                         Sequence<css::uno::Reference<css::security::XCertificate> >());
640 
641                     bCertValid = certResult == css::security::CertificateValidity::VALID ? true : false;
642                     if ( bCertValid )
643                         nValidCerts++;
644 
645                 } catch (css::uno::SecurityException& ) {
646                     OSL_ENSURE(0, "Verification of certificate failed");
647                     bCertValid = false;
648                 }
649 
650                 aSubject = XmlSec::GetContentPart( xCert->getSubjectName() );
651                 aIssuer = XmlSec::GetContentPart( xCert->getIssuerName() );
652                 // --> PB 2004-10-12 #i20172# String with date and time information
653                 aDateTimeStr = XmlSec::GetDateTimeString( rInfo.stDateTime );
654             }
655             bSigValid = ( rInfo.nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED );
656 
657             if ( bSigValid )
658             {
659                  bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
660                       aElementsToBeVerified, rInfo, mode);
661 
662                 if( bSigValid )
663 			        nValidSigs++;
664             }
665 
666             Image aImage;
667             if (!bSigValid)
668             {
669                 aImage = maSigsInvalidImg.GetImage();
670             }
671             else if (bSigValid && !bCertValid)
672             {
673                 aImage = maSigsNotvalidatedImg.GetImage();
674             }
675             //Check if the signature is a "old" document signature, that is, which was created
676             //by an version of OOo previous to 3.2
677             else if (meSignatureMode == SignatureModeDocumentContent
678                 && bSigValid && bCertValid && !DocumentSignatureHelper::isOOo3_2_Signature(
679                 maCurrentSignatureInformations[n]))
680             {
681                 aImage = maSigsNotvalidatedImg.GetImage();
682                 bAllNewSignatures &= false;
683             }
684             else if (meSignatureMode == SignatureModeDocumentContent
685                 && bSigValid && bCertValid && DocumentSignatureHelper::isOOo3_2_Signature(
686                 maCurrentSignatureInformations[n]))
687             {
688                 aImage = maSigsValidImg.GetImage();
689             }
690             else if (meSignatureMode == SignatureModeMacros
691                 && bSigValid && bCertValid)
692             {
693                 aImage = aImage = maSigsValidImg.GetImage();
694             }
695 
696             SvLBoxEntry* pEntry = maSignaturesLB.InsertEntry( aNullStr, aImage, aImage );
697 		    maSignaturesLB.SetEntryText( aSubject, pEntry, 1 );
698 		    maSignaturesLB.SetEntryText( aIssuer, pEntry, 2 );
699 		    maSignaturesLB.SetEntryText( aDateTimeStr, pEntry, 3 );
700 		    pEntry->SetUserData( ( void* ) n );		// missuse user data as index
701         }
702     }
703 
704     bool bAllSigsValid = (nValidSigs == nInfos);
705     bool bAllCertsValid = (nValidCerts == nInfos);
706     bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures);
707 
708     bool bShowNotValidatedState = nInfos && (bAllSigsValid && (!bAllCertsValid || !bAllNewSignatures));
709     bool bShowInvalidState = nInfos && !bAllSigsValid;
710 
711 	maSigsValidImg.Show( bShowValidState);
712 	maSigsValidFI.Show( bShowValidState );
713 	maSigsInvalidImg.Show( bShowInvalidState );
714 	maSigsInvalidFI.Show( bShowInvalidState );
715 
716     maSigsNotvalidatedImg.Show(bShowNotValidatedState);
717     //bAllNewSignatures is always true if we are not in document mode
718     maSigsNotvalidatedFI.Show(nInfos && bAllSigsValid && ! bAllCertsValid);
719     maSigsOldSignatureFI.Show(nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures);
720 
721 	SignatureHighlightHdl( NULL );
722 }
723 
724 
725 //If bUseTempStream is true then the temporary signature stream is used.
726 //Otherwise the real signature stream is used.
ImplGetSignatureInformations(bool bUseTempStream)727 void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream)
728 {
729     maCurrentSignatureInformations.clear();
730 
731     maSignatureHelper.StartMission();
732 
733     SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
734         css::embed::ElementModes::READ, bUseTempStream);
735     if ( aStreamHelper.xSignatureStream.is() )
736     {
737         uno::Reference< io::XInputStream > xInputStream( aStreamHelper.xSignatureStream, uno::UNO_QUERY );
738 	    maSignatureHelper.ReadAndVerifySignature( xInputStream );
739     }
740     maSignatureHelper.EndMission();
741 
742     maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
743 
744     mbVerifySignatures = false;
745 }
746 
ImplShowSignaturesDetails()747 void DigitalSignaturesDialog::ImplShowSignaturesDetails()
748 {
749 	if( maSignaturesLB.FirstSelected() )
750 	{
751         sal_uInt16 nSelected = (sal_uInt16) (sal_uIntPtr) maSignaturesLB.FirstSelected()->GetUserData();
752 		const SignatureInformation&	rInfo = maCurrentSignatureInformations[ nSelected ];
753 		css::uno::Reference<css::xml::crypto::XSecurityEnvironment > xSecEnv =
754 			maSignatureHelper.GetSecurityEnvironment();
755         css::uno::Reference<com::sun::star::security::XSerialNumberAdapter> xSerialNumberAdapter =
756             ::com::sun::star::security::SerialNumberAdapter::create(mxCtx);
757 		// Use Certificate from doc, not from key store
758 		uno::Reference< dcss::security::XCertificate > xCert;
759 		if (rInfo.ouX509Certificate.getLength())
760 			xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
761 		//fallback if no certificate is embedded, get if from store
762 		if (!xCert.is())
763 			xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) );
764 
765 		DBG_ASSERT( xCert.is(), "Error getting cCertificate!" );
766 		if ( xCert.is() )
767 		{
768 			CertificateViewer aViewer( this, maSignatureHelper.GetSecurityEnvironment(), xCert, sal_False );
769 			aViewer.Execute();
770 		}
771 	}
772 }
773 
774 //If bTempStream is true, then a temporary stream is return. If it is false then, the actual
775 //signature stream is used.
776 //Everytime the user presses Add a new temporary stream is created.
777 //We keep the temporary stream as member because ImplGetSignatureInformations
778 //will later access the stream to create DocumentSignatureInformation objects
779 //which are stored in maCurrentSignatureInformations.
ImplOpenSignatureStream(sal_Int32 nStreamOpenMode,bool bTempStream)780 SignatureStreamHelper DigitalSignaturesDialog::ImplOpenSignatureStream(
781     sal_Int32 nStreamOpenMode, bool bTempStream)
782 {
783 	SignatureStreamHelper aHelper;
784     if (bTempStream)
785     {
786         if (nStreamOpenMode & css::embed::ElementModes::TRUNCATE)
787         {
788             //We write always into a new temporary stream.
789             mxTempSignatureStream = Reference < css::io::XStream >(
790                 mxCtx->getServiceManager()->createInstanceWithContext(
791                 OUSTR( "com.sun.star.io.TempFile" ), mxCtx) ,
792                 UNO_QUERY_THROW);
793             aHelper.xSignatureStream = mxTempSignatureStream;
794         }
795         else
796         {
797             //When we read from the temp stream, then we must have previously
798             //created one.
799             OSL_ASSERT(mxTempSignatureStream.is());
800         }
801         aHelper.xSignatureStream = mxTempSignatureStream;
802     }
803     else
804     {
805         //No temporary stream
806         if (!mxSignatureStream.is())
807         {
808             //We may not have a dedicated stream for writing the signature
809             //So we take one directly from the storage
810             //Or DocumentDigitalSignatures::showDocumentContentSignatures was called,
811             //in which case Add/Remove is not allowed. This is done, for example, if the
812             //document is readonly
813             aHelper = DocumentSignatureHelper::OpenSignatureStream(
814                 mxStore, nStreamOpenMode, meSignatureMode );
815         }
816         else
817         {
818             aHelper.xSignatureStream = mxSignatureStream;
819         }
820     }
821 
822     if (nStreamOpenMode & css::embed::ElementModes::TRUNCATE)
823     {
824         css::uno::Reference < css::io::XTruncate > xTruncate(
825             aHelper.xSignatureStream, UNO_QUERY_THROW);
826         DBG_ASSERT( xTruncate.is(), "ImplOpenSignatureStream - Stream does not support xTruncate!" );
827         xTruncate->truncate();
828     }
829     else if ( bTempStream || mxSignatureStream.is())
830     {
831         //In case we read the signature stream from the storage directly,
832         //which is the case when DocumentDigitalSignatures::showDocumentContentSignatures
833         //then XSeakable is not supported
834         css::uno::Reference < css::io::XSeekable > xSeek(
835             aHelper.xSignatureStream, UNO_QUERY_THROW);
836         DBG_ASSERT( xSeek.is(), "ImplOpenSignatureStream - Stream does not support xSeekable!" );
837         xSeek->seek( 0 );
838     }
839 
840 	return aHelper;
841 }
842 
843