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