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