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