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