1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
53 #include <vcl/weld.hxx>
54 #include <vcl/svapp.hxx>
55 #include <sfx2/viewsh.hxx>
56 #include <svl/cryptosign.hxx>
59 #include <o3tl/char16_t2wchar_t.hxx>
60 #include <systools/win32/comtools.hxx>
68 using namespace comphelper
;
69 using namespace css::security
;
70 using namespace css::uno
;
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"};
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"};
94 constexpr std::u16string_view aGUIServers
[]
95 = { u
"kleopatra", u
"seahorse", u
"gpa", u
"kgpg"};
98 bool GetPathAllOS(OUString
& aPath
)
101 sal::systools::CoTaskMemAllocated
<wchar_t> sPath
;
103 = SHGetKnownFolderPath(FOLDERID_ProgramFilesX86
, KF_FLAG_DEFAULT
, nullptr, &sPath
);
107 aPath
= o3tl::toU(sPath
);
109 const char* cPath
= getenv("PATH");
112 aPath
= OUString(cPath
, strlen(cPath
), osl_getThreadTextEncoding());
114 return (!aPath
.isEmpty());
117 void GetCertificateManager(OUString
& sExecutable
)
119 OUString aPath
, aFoundGUIServer
;
120 if (!GetPathAllOS(aPath
))
123 OUString aCetMgrConfig
= officecfg::Office::Common::Security::Scripting::CertMgrPath::get();
124 if (!aCetMgrConfig
.isEmpty())
126 if (aCetMgrConfig
.indexOf('/') != -1
128 || aCetMgrConfig
.indexOf('\\') != -1
132 sExecutable
= aCetMgrConfig
;
135 osl::FileBase::RC searchError
= osl::File::searchFileURL(
136 aCetMgrConfig
, aPath
,
138 if (searchError
== osl::FileBase::E_None
)
140 osl::File::getSystemPathFromFileURL(aFoundGUIServer
, sExecutable
);
145 for (const auto& rServer
: aGUIServers
)
147 bool bSetCertMgrPath
= false;
150 // On macOS, the list of default certificate manager applications
151 // includes absolute paths so check if the path exists and is a
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
;
164 if (!bSetCertMgrPath
)
166 osl::FileBase::RC searchError
= osl::File::searchFileURL(
167 OUString(rServer
), aPath
,
169 if (searchError
== osl::FileBase::E_None
&& osl::File::getSystemPathFromFileURL(aFoundGUIServer
, sExecutable
) == osl::FileBase::E_None
)
170 bSetCertMgrPath
= true;
175 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
176 comphelper::ConfigurationChanges::create());
177 officecfg::Office::Common::Security::Scripting::CertMgrPath::set(sExecutable
,
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
) );
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();
260 case DocumentSignatureMode::Macros
:
261 m_xHintBasicFT
->show();
265 if (comphelper::LibreOfficeKit::isActive())
267 // If the view has a signing certificate, then allow adding a signature.
268 if (!pViewShell
|| !pViewShell
->GetSigningCertificate().is())
272 m_xStartCertMgrBtn
->hide();
275 if (!IsThereCertificateMgr())
277 m_xStartCertMgrBtn
->set_sensitive(false);
281 DigitalSignaturesDialog::~DigitalSignaturesDialog()
284 m_xViewer
->response(RET_OK
);
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!" );
298 maSignatureManager
.getSignatureHelper().SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog
, StartVerifySignatureHdl
) );
304 void DigitalSignaturesDialog::SetStorage( const css::uno::Reference
< css::embed::XStorage
>& rxStore
)
308 // PDF supports AdES.
309 m_bAdESCompliant
= true;
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
)
333 uno::Reference
<uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
334 moScriptSignatureManager
.emplace(xContext
, DocumentSignatureMode::Macros
);
335 if (!moScriptSignatureManager
->init())
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.
355 if (!maSignatureManager
.getStore().is())
356 // It's always possible to append a PDF signature.
359 OSL_ASSERT(maSignatureManager
.getStore().is());
360 bool bDoc1_1
= DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion
);
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
369 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(m_xDialog
.get(),
370 VclMessageType::Warning
, VclButtonsType::Ok
,
371 XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT
)));
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
)
394 m_bWarningShowSignMacro
= 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());
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
);
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()
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();
478 IMPL_LINK_NOARG(DigitalSignaturesDialog
, ViewButtonHdl
, weld::Button
&, void)
480 ImplShowSignaturesDetails();
483 IMPL_LINK_NOARG(DigitalSignaturesDialog
, AddButtonHdl
, weld::Button
&, void)
488 // Separate function, so the function can call itself when the certificate choosing was
489 // successful, but the actual signing was not.
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
) {
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
,
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
))
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
551 // SecurityOperationStatus_OPERATION_SUCCEEDED
552 mbVerifySignatures
= true;
553 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
554 ImplFillSignaturesBox();
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
)));
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
) {
581 int nEntry
= m_xSignaturesLB
->get_selected_index();
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
);
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
,
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;
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
);
673 OUString aDateTimeStr
;
674 OUString aDescription
;
677 bool bCertValid
= false;
680 //check the validity of the cert
682 sal_Int32 certResult
= getSecurityEnvironmentForCertificate(xCert
)->verifyCertificate(xCert
,
683 Sequence
<uno::Reference
<security::XCertificate
> >());
685 bCertValid
= certResult
== css::security::CertificateValidity::VALID
;
689 } catch (css::uno::SecurityException
& ) {
690 OSL_FAIL("Verification of certificate failed");
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())
710 if (!rInfo
.ouGpgCertificate
.isEmpty())
712 // XML based: XAdES or not.
713 else if (rInfo
.GetSigningCertificate() && !rInfo
.GetSigningCertificate()->CertDigest
.isEmpty())
720 // Assume PDF: PAdES or not.
721 if (rInfo
.bHasSigningCertificate
)
727 bool bSigValid
= rInfo
.nStatus
== css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
;
731 if (maSignatureManager
.getStore().is())
734 bSigValid
= DocumentSignatureHelper::checkIfAllFilesAreSigned(
735 aElementsToBeVerified
, rInfo
, mode
);
740 bSigValid
= !rInfo
.bPartialDocumentSignature
;
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
);
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!" );
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();
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();
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
);
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; });
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: */