tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / xmlsecurity / source / dialogs / digitalsignaturesdialog.cxx
blob4c865aac981747a4ffb7238b68c7f174c165670e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <rtl/ustring.hxx>
21 #include <sal/config.h>
23 #include <string_view>
25 #include <digitalsignaturesdialog.hxx>
26 #include <certificatechooser.hxx>
27 #include <certificateviewer.hxx>
28 #include <biginteger.hxx>
29 #include <comphelper/diagnose_ex.hxx>
30 #include <comphelper/configuration.hxx>
31 #include <officecfg/Office/Common.hxx>
33 #include <com/sun/star/uno/SecurityException.hpp>
34 #include <com/sun/star/embed/XStorage.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/security/CertificateValidity.hpp>
37 #include <com/sun/star/security/CertificateKind.hpp>
38 #include <com/sun/star/system/SystemShellExecute.hpp>
39 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
41 #include <osl/file.hxx>
42 #include <sal/log.hxx>
43 #include <unotools/datetime.hxx>
45 #include <bitmaps.hlst>
46 #include <strings.hrc>
47 #include <resourcemanager.hxx>
48 #include <comphelper/lok.hxx>
49 #include <comphelper/xmlsechelper.hxx>
50 #include <comphelper/processfactory.hxx>
52 #include <utility>
53 #include <vcl/weld.hxx>
54 #include <vcl/svapp.hxx>
55 #include <sfx2/viewsh.hxx>
56 #include <svl/cryptosign.hxx>
58 #ifdef _WIN32
59 #include <o3tl/char16_t2wchar_t.hxx>
60 #include <systools/win32/comtools.hxx>
61 #include <Shlobj.h>
62 #endif
64 #if defined MACOSX
65 #include <sys/stat.h>
66 #endif
68 using namespace comphelper;
69 using namespace css::security;
70 using namespace css::uno;
71 using namespace css;
73 namespace
76 #ifdef _WIN32
77 constexpr std::u16string_view aGUIServers[]
78 = { u"Gpg4win\\kleopatra.exe",
79 u"Gpg4win\\bin\\kleopatra.exe",
80 u"GNU\\GnuPG\\kleopatra.exe",
81 u"GNU\\GnuPG\\launch-gpa.exe",
82 u"GNU\\GnuPG\\gpa.exe",
83 u"GnuPG\\bin\\gpa.exe",
84 u"GNU\\GnuPG\\bin\\kleopatra.exe",
85 u"GNU\\GnuPG\\bin\\launch-gpa.exe",
86 u"GNU\\GnuPG\\bin\\gpa.exe"};
87 #elif defined MACOSX
88 constexpr std::u16string_view aGUIServers[]
89 = { u"/Applications/GPG Keychain.app",
90 u"/Applications/Trusted Key Manager.app", // tdf#147291
91 u"/Applications/SCinterface/scManager.app", // tdf#147291
92 u"/System/Applications/Utilities/Keychain Access.app"};
93 #else
94 constexpr std::u16string_view aGUIServers[]
95 = { u"kleopatra", u"seahorse", u"gpa", u"kgpg"};
96 #endif
98 bool GetPathAllOS(OUString& aPath)
100 #ifdef _WIN32
101 sal::systools::CoTaskMemAllocated<wchar_t> sPath;
102 HRESULT hr
103 = SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, KF_FLAG_DEFAULT, nullptr, &sPath);
105 if (FAILED(hr))
106 return false;
107 aPath = o3tl::toU(sPath);
108 #else
109 const char* cPath = getenv("PATH");
110 if (!cPath)
111 return false;
112 aPath = OUString(cPath, strlen(cPath), osl_getThreadTextEncoding());
113 #endif
114 return (!aPath.isEmpty());
117 void GetCertificateManager(OUString& sExecutable)
119 OUString aPath, aFoundGUIServer;
120 if (!GetPathAllOS(aPath))
121 return;
123 OUString aCetMgrConfig = officecfg::Office::Common::Security::Scripting::CertMgrPath::get();
124 if (!aCetMgrConfig.isEmpty())
126 if (aCetMgrConfig.indexOf('/') != -1
127 #ifdef _WIN32
128 || aCetMgrConfig.indexOf('\\') != -1
129 #endif
132 sExecutable = aCetMgrConfig;
133 return;
135 osl::FileBase::RC searchError = osl::File::searchFileURL(
136 aCetMgrConfig, aPath,
137 aFoundGUIServer);
138 if (searchError == osl::FileBase::E_None)
140 osl::File::getSystemPathFromFileURL(aFoundGUIServer, sExecutable);
141 return;
145 for (const auto& rServer: aGUIServers)
147 bool bSetCertMgrPath = false;
149 #ifdef MACOSX
150 // On macOS, the list of default certificate manager applications
151 // includes absolute paths so check if the path exists and is a
152 // directory
153 if (rServer.starts_with('/'))
155 OString aSysPath = OUString(rServer).toUtf8();
156 if (struct stat st; stat(aSysPath.getStr(), &st) == 0 && S_ISDIR(st.st_mode))
158 bSetCertMgrPath = true;
159 sExecutable = rServer;
162 #endif
164 if (!bSetCertMgrPath)
166 osl::FileBase::RC searchError = osl::File::searchFileURL(
167 OUString(rServer), aPath,
168 aFoundGUIServer);
169 if (searchError == osl::FileBase::E_None && osl::File::getSystemPathFromFileURL(aFoundGUIServer, sExecutable) == osl::FileBase::E_None)
170 bSetCertMgrPath = true;
173 if (bSetCertMgrPath)
175 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
176 comphelper::ConfigurationChanges::create());
177 officecfg::Office::Common::Security::Scripting::CertMgrPath::set(sExecutable,
178 pBatch);
179 pBatch->commit();
181 return;
186 bool IsThereCertificateMgr()
188 OUString sExecutable;
189 GetCertificateManager(sExecutable);
190 return (!sExecutable.isEmpty());
192 }//anonymous namespace
194 DigitalSignaturesDialog::DigitalSignaturesDialog(
195 weld::Window* pParent,
196 const uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode,
197 bool bReadOnly, OUString sODFVersion, bool bHasDocumentSignature,
198 SfxViewShell* pViewShell)
199 : GenericDialogController(pParent, u"xmlsec/ui/digitalsignaturesdialog.ui"_ustr, u"DigitalSignaturesDialog"_ustr)
200 , maSignatureManager(rxCtx, eMode)
201 , m_sODFVersion (std::move(sODFVersion))
202 , m_bHasDocumentSignature(bHasDocumentSignature)
203 , m_bWarningShowSignMacro(false)
204 , m_pViewShell(pViewShell)
205 , m_xHintDocFT(m_xBuilder->weld_label(u"dochint"_ustr))
206 , m_xHintBasicFT(m_xBuilder->weld_label(u"macrohint"_ustr))
207 , m_xSignaturesLB(m_xBuilder->weld_tree_view(u"signatures"_ustr))
208 , m_xSigsValidImg(m_xBuilder->weld_image(u"validimg"_ustr))
209 , m_xSigsValidFI(m_xBuilder->weld_label(u"validft"_ustr))
210 , m_xSigsInvalidImg(m_xBuilder->weld_image(u"invalidimg"_ustr))
211 , m_xSigsInvalidFI(m_xBuilder->weld_label(u"invalidft"_ustr))
212 , m_xSigsNotvalidatedImg(m_xBuilder->weld_image(u"notvalidatedimg"_ustr))
213 , m_xSigsNotvalidatedFI(m_xBuilder->weld_label(u"notvalidatedft"_ustr))
214 , m_xSigsOldSignatureImg(m_xBuilder->weld_image(u"oldsignatureimg"_ustr))
215 , m_xSigsOldSignatureFI(m_xBuilder->weld_label(u"oldsignatureft"_ustr))
216 , m_xViewBtn(m_xBuilder->weld_button(u"view"_ustr))
217 , m_xAddBtn(m_xBuilder->weld_button(u"sign"_ustr))
218 , m_xRemoveBtn(m_xBuilder->weld_button(u"remove"_ustr))
219 , m_xStartCertMgrBtn(m_xBuilder->weld_button(u"start_certmanager"_ustr))
220 , m_xCloseBtn(m_xBuilder->weld_button(u"close"_ustr))
222 auto nControlWidth = m_xSignaturesLB->get_approximate_digit_width() * 105;
223 m_xSignaturesLB->set_size_request(nControlWidth, m_xSignaturesLB->get_height_rows(10));
225 // Give the first column 6 percent, try to distribute the rest equally.
226 std::vector<int> aWidths;
227 aWidths.push_back(6*nControlWidth/100);
228 auto nColWidth = (nControlWidth - aWidths[0]) / 4;
229 aWidths.push_back(nColWidth);
230 aWidths.push_back(nColWidth);
231 aWidths.push_back(nColWidth);
232 m_xSignaturesLB->set_column_fixed_widths(aWidths);
234 mbVerifySignatures = true;
235 mbSignaturesChanged = false;
237 m_xSignaturesLB->connect_selection_changed(
238 LINK(this, DigitalSignaturesDialog, SignatureHighlightHdl));
239 m_xSignaturesLB->connect_row_activated( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );
241 m_xViewBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
242 m_xViewBtn->set_sensitive(false);
244 m_xAddBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) );
245 if ( bReadOnly )
246 m_xAddBtn->set_sensitive(false);
248 m_xRemoveBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) );
249 m_xRemoveBtn->set_sensitive(false);
251 m_xStartCertMgrBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, CertMgrButtonHdl ) );
253 m_xCloseBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, OKButtonHdl) );
255 switch( maSignatureManager.getSignatureMode() )
257 case DocumentSignatureMode::Content:
258 m_xHintDocFT->show();
259 break;
260 case DocumentSignatureMode::Macros:
261 m_xHintBasicFT->show();
262 break;
265 if (comphelper::LibreOfficeKit::isActive())
267 // If the view has a signing certificate, then allow adding a signature.
268 if (!pViewShell || !pViewShell->GetSigningCertificate().is())
270 m_xAddBtn->hide();
272 m_xStartCertMgrBtn->hide();
275 if (!IsThereCertificateMgr())
277 m_xStartCertMgrBtn->set_sensitive(false);
281 DigitalSignaturesDialog::~DigitalSignaturesDialog()
283 if (m_xViewer)
284 m_xViewer->response(RET_OK);
286 if (m_xInfoBox)
287 m_xInfoBox->response(RET_OK);
290 bool DigitalSignaturesDialog::Init()
292 bool bInit = maSignatureManager.init();
294 SAL_WARN_IF( !bInit, "xmlsecurity.dialogs", "Error initializing security context!" );
296 if ( bInit )
298 maSignatureManager.getSignatureHelper().SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) );
301 return bInit;
304 void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore )
306 if (!rxStore.is())
308 // PDF supports AdES.
309 m_bAdESCompliant = true;
310 return;
313 // only ODF 1.1 wants to be non-XAdES (m_sODFVersion="1.0" for OOXML somehow?)
314 m_bAdESCompliant = !rxStore->hasByName(u"META-INF"_ustr) // it's a Zip storage
315 || !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
317 maSignatureManager.setStore(rxStore);
318 maSignatureManager.getSignatureHelper().SetStorage( maSignatureManager.getStore(), m_sODFVersion, {});
321 void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream )
323 maSignatureManager.setSignatureStream(rxStream);
326 void DigitalSignaturesDialog::SetScriptingSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream )
328 if (!rxStream.is())
330 return;
333 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
334 moScriptSignatureManager.emplace(xContext, DocumentSignatureMode::Macros);
335 if (!moScriptSignatureManager->init())
337 return;
339 moScriptSignatureManager->setStore(maSignatureManager.getStore());
340 // This is the storage used by UriBindingHelper::getUriBinding().
341 moScriptSignatureManager->getSignatureHelper().SetStorage(maSignatureManager.getStore(), m_sODFVersion);
342 maSignatureManager.getSignatureHelper().SetStorage(maSignatureManager.getStore(), m_sODFVersion, rxStream);
343 moScriptSignatureManager->setSignatureStream(rxStream);
346 bool DigitalSignaturesDialog::canAddRemove()
348 //FIXME: this func needs some cleanup, such as real split between
349 //'canAdd' and 'canRemove' case
350 uno::Reference<container::XNameAccess> xNameAccess = maSignatureManager.getStore();
351 if (xNameAccess.is() && xNameAccess->hasByName(u"[Content_Types].xml"_ustr))
352 // It's always possible to append an OOXML signature.
353 return true;
355 if (!maSignatureManager.getStore().is())
356 // It's always possible to append a PDF signature.
357 return true;
359 OSL_ASSERT(maSignatureManager.getStore().is());
360 bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
362 // see specification
363 //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw
364 //Paragraph 'Behavior with regard to ODF 1.2'
365 //For both, macro and document
366 if ( bDoc1_1 )
368 //#4
369 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
370 VclMessageType::Warning, VclButtonsType::Ok,
371 XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT)));
372 xBox->run();
373 return false;
376 //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is
377 //adding a macro signature will break an existing document signature.
378 //The sfx2 will remove the documentsignature when the user adds a macro signature
379 if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Macros)
381 if (m_bHasDocumentSignature && !m_bWarningShowSignMacro)
383 //The warning says that the document signatures will be removed if the user
384 //continues. He can then either press 'OK' or 'NO'
385 //It the user presses 'Add' or 'Remove' several times then, then the warning
386 //is shown every time until the user presses 'OK'. From then on, the warning
387 //is not displayed anymore as long as the signatures dialog is alive.
388 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
389 m_xDialog.get(), VclMessageType::Question, VclButtonsType::YesNo,
390 XsResId(STR_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)));
391 if (xBox->run() == RET_NO)
392 return false;
394 m_bWarningShowSignMacro = true;
397 return true;
400 bool DigitalSignaturesDialog::canAdd() { return canAddRemove(); }
402 void DigitalSignaturesDialog::canRemove(const std::function<void(bool)>& rCallback)
404 auto onFinished = [this, rCallback](bool bRet) {
405 rCallback(bRet && canAddRemove());
407 bool bRet = true;
409 if ( maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content )
411 std::shared_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
412 VclMessageType::Question, VclButtonsType::YesNo,
413 XsResId(STR_XMLSECDLG_QUERY_REALLYREMOVE)));
414 xBox->runAsync(xBox, [onFinished](sal_Int32 nDlgRet) {
415 onFinished(nDlgRet == RET_YES);
417 return;
420 onFinished(bRet);
423 void DigitalSignaturesDialog::beforeRun()
425 // Verify Signatures and add certificates to ListBox...
426 mbVerifySignatures = true;
427 ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true);
428 ImplFillSignaturesBox();
430 // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is
431 // enabled, set its initial state based on existing signatures, if any.
433 // If it is OOXML, the checkbox is irrelevant.
435 // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and
436 // check its nStorageFormat as that seems overly complicated and seems to have weird indirect
437 // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant()
438 // (which now is in #if 0).
440 if (!maSignatureManager.getCurrentSignatureInformations().empty())
442 // If the document has only SHA-1 signatures we probably want it to stay that way?
445 // Only verify once, content will not change.
446 // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
447 mbVerifySignatures = false;
450 short DigitalSignaturesDialog::run()
452 beforeRun();
453 return GenericDialogController::run();
456 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureHighlightHdl, weld::TreeView&, void)
458 bool bSel = m_xSignaturesLB->get_selected_index() != -1;
459 m_xViewBtn->set_sensitive( bSel );
460 if ( m_xAddBtn->get_sensitive() ) // not read only
461 m_xRemoveBtn->set_sensitive( bSel );
464 IMPL_LINK_NOARG(DigitalSignaturesDialog, OKButtonHdl, weld::Button&, void)
466 if (mbSignaturesChanged)
467 maSignatureManager.write(m_bAdESCompliant);
469 m_xDialog->response(RET_OK);
472 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, weld::TreeView&, bool)
474 ImplShowSignaturesDetails();
475 return true;
478 IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, weld::Button&, void)
480 ImplShowSignaturesDetails();
483 IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, weld::Button&, void)
485 if( ! canAdd())
486 return;
488 // Separate function, so the function can call itself when the certificate choosing was
489 // successful, but the actual signing was not.
490 AddButtonHdlImpl();
493 void DigitalSignaturesDialog::AddButtonHdlImpl()
495 std::vector<uno::Reference<xml::crypto::XXMLSecurityContext>> xSecContexts
497 maSignatureManager.getSecurityContext()
499 // Gpg signing is only possible with ODF >= 1.2 documents
500 if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.getStore(), m_sODFVersion))
501 xSecContexts.push_back(maSignatureManager.getGpgSecurityContext());
503 std::shared_ptr<CertificateChooser> aChooser = CertificateChooser::getInstance(m_xDialog.get(), m_pViewShell, std::move(xSecContexts), CertificateChooserUserAction::Sign);
504 aChooser->BeforeRun();
505 weld::DialogController::runAsync(aChooser, [this, aChooser](sal_Int32 nRet) {
506 if (nRet != RET_OK)
508 return;
513 sal_Int32 nSecurityId;
515 svl::crypto::SigningContext aSigningContext;
516 aSigningContext.m_xCertificate = aChooser->GetSelectedCertificates()[0];
517 if (moScriptSignatureManager)
519 if (!moScriptSignatureManager->add(aSigningContext,
520 aChooser->GetSelectedSecurityContext(),
521 aChooser->GetDescription(), nSecurityId,
522 m_bAdESCompliant))
524 return;
527 moScriptSignatureManager->read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
528 moScriptSignatureManager->write(m_bAdESCompliant);
530 maSignatureManager.setScriptingSignatureStream(moScriptSignatureManager->getSignatureStream());
533 if (!maSignatureManager.add(aSigningContext, aChooser->GetSelectedSecurityContext(),
534 aChooser->GetDescription(), nSecurityId, m_bAdESCompliant))
535 return;
536 mbSignaturesChanged = true;
538 xml::crypto::SecurityOperationStatus nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
540 if (maSignatureManager.getStore().is())
541 // In the PDF case the signature information is only available after parsing.
542 nStatus = maSignatureManager.getSignatureHelper().GetSignatureInformation( nSecurityId ).nStatus;
544 if ( nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED )
546 mbSignaturesChanged = true;
548 // Can't simply remember current information, need parsing for getting full information :(
549 // We need to verify the signatures again, otherwise the status in the signature information
550 // will not contain
551 // SecurityOperationStatus_OPERATION_SUCCEEDED
552 mbVerifySignatures = true;
553 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
554 ImplFillSignaturesBox();
556 else
558 AddButtonHdlImpl();
561 catch ( uno::Exception& )
563 TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "adding a signature!" );
564 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
565 VclMessageType::Error, VclButtonsType::Ok,
566 XsResId(STR_XMLSECDLG_SIGNING_FAILED)));
567 xBox->run();
568 // Don't keep invalid entries...
569 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
570 ImplFillSignaturesBox();
575 IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, weld::Button&, void)
577 canRemove([this](bool bRet) {
578 if (!bRet)
579 return;
581 int nEntry = m_xSignaturesLB->get_selected_index();
582 if (nEntry == -1)
583 return;
587 sal_uInt16 nSelected = m_xSignaturesLB->get_id(nEntry).toUInt32();
588 maSignatureManager.remove(nSelected);
590 mbSignaturesChanged = true;
592 ImplFillSignaturesBox();
594 catch ( uno::Exception& )
596 TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "Exception while removing a signature!" );
597 // Don't keep invalid entries...
598 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true);
599 ImplFillSignaturesBox();
605 IMPL_LINK_NOARG(DigitalSignaturesDialog, CertMgrButtonHdl, weld::Button&, void)
607 OUString sExecutable;
608 GetCertificateManager(sExecutable);
610 if (!sExecutable.isEmpty())
612 const uno::Reference<uno::XComponentContext>& xContext
613 = ::comphelper::getProcessComponentContext();
614 uno::Reference<css::system::XSystemShellExecute> xSystemShell(
615 css::system::SystemShellExecute::create(xContext));
619 xSystemShell->execute(sExecutable, OUString(),
620 css::system::SystemShellExecuteFlags::DEFAULTS);
622 catch (...)
624 // Related tdf#159307 fix uncloseable windows due to uncaught exception
625 // XSystemShellExecute::execute() throws an exception for a variety
626 // of common error conditions such as files or directories that
627 // are non-existent or non-executable. Failure to catch such
628 // exceptions would cause the document window to be uncloseable
629 // and the application to be unquittable.
630 TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "executable failed!" );
631 sExecutable = OUString();
635 OUString sDialogText = (sExecutable.isEmpty() ?
636 XsResId(STR_XMLSECDLG_NO_CERT_MANAGER) : XsResId(STR_XMLSECDLG_OPENED_CRTMGR) + sExecutable);
638 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(
639 m_xDialog.get(), VclMessageType::Info, VclButtonsType::Ok,
640 sDialogText));
641 xInfoBox->run();
644 IMPL_LINK_NOARG(DigitalSignaturesDialog, StartVerifySignatureHdl, LinkParamNone*, bool)
646 return mbVerifySignatures;
649 void DigitalSignaturesDialog::ImplFillSignaturesBox()
651 m_xSignaturesLB->clear();
653 size_t nInfos = maSignatureManager.getCurrentSignatureInformations().size();
654 size_t nValidSigs = 0, nValidCerts = 0;
655 bool bAllNewSignatures = true;
656 bool bSomePartial = false;
658 if( nInfos )
660 for( size_t n = 0; n < nInfos; ++n )
662 DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
663 m_sODFVersion, maSignatureManager.getCurrentSignatureInformations()[n]);
664 std::vector< OUString > aElementsToBeVerified;
665 if (maSignatureManager.getStore().is())
666 aElementsToBeVerified = DocumentSignatureHelper::CreateElementList(maSignatureManager.getStore(), maSignatureManager.getSignatureMode(), mode);
668 const SignatureInformation& rInfo = maSignatureManager.getCurrentSignatureInformations()[n];
669 uno::Reference< css::security::XCertificate > xCert = getCertificate(rInfo);
671 OUString aSubject;
672 OUString aIssuer;
673 OUString aDateTimeStr;
674 OUString aDescription;
675 OUString aType;
677 bool bCertValid = false;
678 if( xCert.is() )
680 //check the validity of the cert
681 try {
682 sal_Int32 certResult = getSecurityEnvironmentForCertificate(xCert)->verifyCertificate(xCert,
683 Sequence<uno::Reference<security::XCertificate> >());
685 bCertValid = certResult == css::security::CertificateValidity::VALID;
686 if ( bCertValid )
687 nValidCerts++;
689 } catch (css::uno::SecurityException& ) {
690 OSL_FAIL("Verification of certificate failed");
691 bCertValid = false;
694 aSubject = xmlsec::GetContentPart( xCert->getSubjectName(), xCert->getCertificateKind() );
695 aIssuer = xmlsec::GetContentPart( xCert->getIssuerName(), xCert->getCertificateKind() );
697 else if (!rInfo.ouGpgCertificate.isEmpty())
699 // In case we don't have the gpg key locally, get some data from the document
700 aIssuer = rInfo.ouGpgOwner;
703 aDateTimeStr = utl::GetDateTimeString( rInfo.stDateTime );
704 aDescription = rInfo.ouDescription;
706 // Decide type string.
707 if (maSignatureManager.getStore().is())
709 // OpenPGP
710 if (!rInfo.ouGpgCertificate.isEmpty())
711 aType = "OpenPGP";
712 // XML based: XAdES or not.
713 else if (rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->CertDigest.isEmpty())
714 aType = "XAdES";
715 else
716 aType = "XML-DSig";
718 else
720 // Assume PDF: PAdES or not.
721 if (rInfo.bHasSigningCertificate)
722 aType = "PAdES";
723 else
724 aType = "PDF";
727 bool bSigValid = rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
729 if ( bSigValid )
731 if (maSignatureManager.getStore().is())
733 // ZIP based.
734 bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
735 aElementsToBeVerified, rInfo, mode);
737 else
739 // Assume PDF.
740 bSigValid = !rInfo.bPartialDocumentSignature;
743 if( bSigValid )
744 nValidSigs++;
745 else
747 bSomePartial = true;
751 OUString sImage;
752 if (!bSigValid)
754 sImage = BMP_SIG_INVALID;
756 else if (!bCertValid)
758 sImage = BMP_SIG_NOT_VALIDATED;
760 //Check if the signature is a "old" document signature, that is, which was created
761 //by a version of OOo previous to 3.2
762 // If there is no storage, then it's pointless to check storage
763 // stream references.
764 else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content
765 && (maSignatureManager.getStore().is() && !DocumentSignatureHelper::isOOo3_2_Signature(
766 maSignatureManager.getCurrentSignatureInformations()[n])))
768 sImage = BMP_SIG_NOT_VALIDATED;
769 bAllNewSignatures = false;
771 else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content
772 && DocumentSignatureHelper::isOOo3_2_Signature(
773 maSignatureManager.getCurrentSignatureInformations()[n]))
775 sImage = BMP_SIG_VALID;
777 else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Macros)
779 sImage = BMP_SIG_VALID;
782 m_xSignaturesLB->insert(nullptr, n, nullptr, nullptr,
783 &sImage, nullptr, false, nullptr);
784 m_xSignaturesLB->set_text(n, aSubject, 1);
785 m_xSignaturesLB->set_text(n, aIssuer, 2);
786 m_xSignaturesLB->set_text(n, aDateTimeStr, 3);
787 m_xSignaturesLB->set_text(n, aDescription, 4);
788 m_xSignaturesLB->set_text(n, aType, 5);
789 m_xSignaturesLB->set_id(n, OUString::number(n)); // misuse user data as index
793 bool bAllSigsValid = (nValidSigs == nInfos);
794 bool bAllCertsValid = (nValidCerts == nInfos);
795 bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures);
797 m_xSigsValidImg->set_visible( bShowValidState);
798 m_xSigsValidFI->set_visible( bShowValidState );
800 bool bShowInvalidState = nInfos && !bAllSigsValid;
802 m_xSigsInvalidImg->set_visible( bShowInvalidState && !bSomePartial);
803 m_xSigsInvalidFI->set_visible( bShowInvalidState && !bSomePartial);
805 bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid;
807 m_xSigsNotvalidatedImg->set_visible(bShowNotValidatedState);
808 m_xSigsNotvalidatedFI->set_visible(bShowNotValidatedState);
810 //bAllNewSignatures is always true if we are not in document mode
811 bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures;
812 m_xSigsOldSignatureImg->set_visible(bShowOldSignature || bSomePartial);
813 m_xSigsOldSignatureFI->set_visible(bShowOldSignature || bSomePartial);
815 SignatureHighlightHdl(*m_xSignaturesLB);
818 uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(const SignatureInformation& rInfo)
820 uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureManager.getSecurityEnvironment();
821 uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = maSignatureManager.getGpgSecurityEnvironment();
822 uno::Reference<security::XCertificate> xCert;
824 //First we try to get the certificate which is embedded in the XML Signature
825 if (xSecEnv.is() && rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->X509Certificate.isEmpty())
826 xCert = xSecEnv->createCertificateFromAscii(rInfo.GetSigningCertificate()->X509Certificate);
827 else {
828 //There must be an embedded certificate because we use it to get the
829 //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
830 //because it could be modified by an attacker. The issuer is displayed
831 //in the digital signature dialog.
832 //Comparing the X509IssuerName with the one from the X509Certificate in order
833 //to find out if the X509IssuerName was modified does not work. See #i62684
834 SAL_WARN( "xmlsecurity.dialogs", "Could not find embedded certificate!");
837 //In case there is no embedded certificate we try to get it from a local store
838 if (!xCert.is() && xSecEnv.is() && rInfo.GetSigningCertificate())
840 xCert = xSecEnv->getCertificate(rInfo.GetSigningCertificate()->X509IssuerName,
841 xmlsecurity::numericStringToBigInteger(rInfo.GetSigningCertificate()->X509SerialNumber));
843 if (!xCert.is() && xGpgSecEnv.is() && !rInfo.ouGpgKeyID.isEmpty())
844 xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger(u"") );
846 SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );
848 return xCert;
851 uno::Reference<xml::crypto::XSecurityEnvironment> DigitalSignaturesDialog::getSecurityEnvironmentForCertificate(const uno::Reference<security::XCertificate>& xCert)
853 switch(xCert->getCertificateKind())
855 case CertificateKind_OPENPGP:
856 return maSignatureManager.getGpgSecurityEnvironment();
857 case CertificateKind_X509:
858 return maSignatureManager.getSecurityEnvironment();
859 default:
860 throw RuntimeException(u"Unknown certificate kind"_ustr);
864 //If bUseTempStream is true then the temporary signature stream is used.
865 //Otherwise the real signature stream is used.
866 void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature)
868 maSignatureManager.read(bUseTempStream, bCacheLastSignature);
869 mbVerifySignatures = false;
872 void DigitalSignaturesDialog::ImplShowSignaturesDetails()
874 int nEntry = m_xSignaturesLB->get_selected_index();
875 if (nEntry == -1)
876 return;
878 sal_uInt16 nSelected = m_xSignaturesLB->get_id(nEntry).toUInt32();
879 const SignatureInformation& rInfo = maSignatureManager.getCurrentSignatureInformations()[ nSelected ];
880 uno::Reference<security::XCertificate> xCert = getCertificate(rInfo);
882 if ( xCert.is() )
884 if (m_xViewer)
885 m_xViewer->response(RET_OK);
887 uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = getSecurityEnvironmentForCertificate(xCert);
888 m_xViewer = std::make_shared<CertificateViewer>(m_xDialog.get(), xSecEnv, xCert, false, nullptr);
889 weld::DialogController::runAsync(m_xViewer, [this] (sal_Int32) { m_xViewer = nullptr; });
891 else
893 if (m_xInfoBox)
894 m_xInfoBox->response(RET_OK);
896 m_xInfoBox = std::shared_ptr<weld::MessageDialog>(Application::CreateMessageDialog(m_xDialog.get(),
897 VclMessageType::Info, VclButtonsType::Ok,
898 XsResId(STR_XMLSECDLG_NO_CERT_FOUND)));
899 m_xInfoBox->runAsync(m_xInfoBox, [this] (sal_Int32) { m_xInfoBox = nullptr; });
903 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */