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 <digitalsignaturesdialog.hxx>
21 #include <certificatechooser.hxx>
22 #include <certificateviewer.hxx>
23 #include <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/embed/StorageFormats.hpp>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/lang/XComponent.hpp>
31 #include <com/sun/star/security/NoPasswordException.hpp>
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/security/CertificateValidity.hpp>
35 #include <com/sun/star/packages/WrongPasswordException.hpp>
36 #include <com/sun/star/security/CertificateKind.hpp>
37 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
38 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
39 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
40 #include <com/sun/star/system/SystemShellExecute.hpp>
41 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
42 #include <com/sun/star/system/SystemShellExecuteException.hpp>
43 
44 #include <osl/file.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <rtl/uri.hxx>
47 #include <sal/log.hxx>
48 
49 #include <tools/date.hxx>
50 #include <tools/time.hxx>
51 #include <svtools/treelistentry.hxx>
52 
53 #include <strings.hrc>
54 #include <resourcemanager.hxx>
55 
56 #include <vcl/weld.hxx>
57 #include <unotools/configitem.hxx>
58 
59 using namespace css::security;
60 using namespace css::uno;
61 using namespace css;
62 
63 namespace
64 {
65     class SaveODFItem: public utl::ConfigItem
66     {
67     private:
68         sal_Int16 m_nODF;
69 
70         virtual void ImplCommit() override;
71 
72     public:
73     virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override;
74         SaveODFItem();
75         //See group ODF in Common.xcs
76         bool isLessODF1_2()
77         {
78             return m_nODF < 3;
79         }
80     };
81 
82     void SaveODFItem::ImplCommit() {}
83     void SaveODFItem::Notify( const css::uno::Sequence< OUString >& ) {}
84 
85     SaveODFItem::SaveODFItem(): utl::ConfigItem("Office.Common/Save"), m_nODF(0)
86     {
87         OUString sDef("ODF/DefaultVersion");
88         Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) );
89         if ( aValues.getLength() != 1)
90             throw uno::RuntimeException(
91                 "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion",
92                 nullptr);
93 
94         sal_Int16 nTmp = 0;
95         if ( !(aValues[0] >>= nTmp) )
96             throw uno::RuntimeException(
97                 "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!",
98                 nullptr );
99 
100         m_nODF = nTmp;
101     }
102 }
103 
104 DigitalSignaturesDialog::DigitalSignaturesDialog(
105     vcl::Window* pParent,
106     uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode,
107     bool bReadOnly, const OUString& sODFVersion, bool bHasDocumentSignature)
108     : ModalDialog(pParent, "DigitalSignaturesDialog", "xmlsec/ui/digitalsignaturesdialog.ui")
109     , mxCtx(rxCtx)
110     , maSignatureManager(rxCtx, eMode)
111     , m_sODFVersion (sODFVersion)
112     , m_bHasDocumentSignature(bHasDocumentSignature)
113     , m_bWarningShowSignMacro(false)
114 {
115     get(m_pHintDocFT, "dochint");
116     get(m_pHintBasicFT, "macrohint");
117     get(m_pHintPackageFT, "packagehint");
118     get(m_pAdESCompliantCB, "adescompliant");
119     get(m_pViewBtn, "view");
120     get(m_pAddBtn, "sign");
121     get(m_pRemoveBtn, "remove");
122     get(m_pCloseBtn, "close");
123     get(m_pStartCertMgrBtn, "start_certmanager");
124     get(m_pSigsValidImg, "validimg");
125     get(m_pSigsValidFI, "validft");
126     get(m_pSigsInvalidImg, "invalidimg");
127     get(m_pSigsInvalidFI, "invalidft");
128     get(m_pSigsNotvalidatedImg, "notvalidatedimg");
129     get(m_pSigsNotvalidatedFI, "notvalidatedft");
130     get(m_pSigsOldSignatureImg, "oldsignatureimg");
131     get(m_pSigsOldSignatureFI, "oldsignatureft");
132 
133     m_bAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
134 
135     Size aControlSize(375, 109);
136     const long nControlWidth = aControlSize.Width();
137     aControlSize = LogicToPixel(aControlSize, MapMode(MapUnit::MapAppFont));
138     SvSimpleTableContainer *pSignatures = get<SvSimpleTableContainer>("signatures");
139     pSignatures->set_width_request(aControlSize.Width());
140     pSignatures->set_height_request(aControlSize.Height());
141 
142     m_pSignaturesLB = VclPtr<SvSimpleTable>::Create(*pSignatures);
143     // Give the first column 6 percent, try to distribute the rest equally.
144     static long aTabs[] = { 0, 6*nControlWidth/100, 25*nControlWidth/100, 44*nControlWidth/100, 62*nControlWidth/100, 81*nControlWidth/100 };
145     m_pSignaturesLB->SetTabs(SAL_N_ELEMENTS(aTabs), aTabs);
146 
147     m_pSignaturesLB->InsertHeaderEntry("\t" + get<FixedText>("signed")->GetText() + "\t"
148                + get<FixedText>("issued")->GetText() + "\t" + get<FixedText>("date")->GetText() + "\t"
149                + get<FixedText>("description")->GetText() + "\t" + get<FixedText>("type")->GetText());
150 
151     mbVerifySignatures = true;
152     mbSignaturesChanged = false;
153 
154     m_pSignaturesLB->SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) );
155     m_pSignaturesLB->SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );
156 
157     m_pAdESCompliantCB->SetToggleHdl( LINK( this, DigitalSignaturesDialog, AdESCompliantCheckBoxHdl ) );
158     m_pAdESCompliantCB->Check(m_bAdESCompliant);
159 
160     m_pViewBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
161     m_pViewBtn->Disable();
162 
163     m_pAddBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) );
164     if ( bReadOnly  )
165         m_pAddBtn->Disable();
166 
167     m_pRemoveBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) );
168     m_pRemoveBtn->Disable();
169 
170     m_pStartCertMgrBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, CertMgrButtonHdl ) );
171 
172     m_pCloseBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, OKButtonHdl) );
173 
174     switch( maSignatureManager.meSignatureMode )
175     {
176         case DocumentSignatureMode::Content:
177             m_pHintDocFT->Show();
178             break;
179         case DocumentSignatureMode::Macros:
180             m_pHintBasicFT->Show();
181             break;
182         case DocumentSignatureMode::Package:
183             m_pHintPackageFT->Show();
184             break;
185     }
186 }
187 
188 DigitalSignaturesDialog::~DigitalSignaturesDialog()
189 {
190     disposeOnce();
191 }
192 
193 void DigitalSignaturesDialog::dispose()
194 {
195     m_pSignaturesLB.disposeAndClear();
196     m_pHintDocFT.clear();
197     m_pHintBasicFT.clear();
198     m_pHintPackageFT.clear();
199     m_pSigsValidImg.clear();
200     m_pSigsValidFI.clear();
201     m_pSigsInvalidImg.clear();
202     m_pSigsInvalidFI.clear();
203     m_pSigsNotvalidatedImg.clear();
204     m_pSigsNotvalidatedFI.clear();
205     m_pSigsOldSignatureImg.clear();
206     m_pSigsOldSignatureFI.clear();
207     m_pAdESCompliantCB.clear();
208     m_pViewBtn.clear();
209     m_pAddBtn.clear();
210     m_pRemoveBtn.clear();
211     m_pCloseBtn.clear();
212     m_pStartCertMgrBtn.clear();
213     ModalDialog::dispose();
214 }
215 
216 bool DigitalSignaturesDialog::Init()
217 {
218     bool bInit = maSignatureManager.init();
219 
220     SAL_WARN_IF( !bInit, "xmlsecurity.dialogs", "Error initializing security context!" );
221 
222     if ( bInit )
223     {
224         maSignatureManager.maSignatureHelper.SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) );
225     }
226 
227     return bInit;
228 }
229 
230 void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore )
231 {
232     if (!rxStore.is())
233     {
234         // PDF supports AdES.
235         m_bAdESCompliant = true;
236         m_pAdESCompliantCB->Check(m_bAdESCompliant);
237         return;
238     }
239 
240     maSignatureManager.mxStore = rxStore;
241     maSignatureManager.maSignatureHelper.SetStorage( maSignatureManager.mxStore, m_sODFVersion);
242 
243     Reference < css::packages::manifest::XManifestReader > xReader =
244         css::packages::manifest::ManifestReader::create(mxCtx);
245 
246     uno::Reference<container::XNameAccess> xNameAccess(rxStore, uno::UNO_QUERY);
247     if (!xNameAccess.is())
248         return;
249 
250     if (xNameAccess->hasByName("META-INF"))
251     {
252         //Get the manifest.xml
253         Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement(
254                     "META-INF", css::embed::ElementModes::READ), UNO_QUERY_THROW);
255 
256         Reference< css::io::XInputStream > xStream(
257             xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ),
258             UNO_QUERY_THROW);
259 
260         maSignatureManager.m_manifest = xReader->readManifestSequence(xStream);
261     }
262 }
263 
264 void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream )
265 {
266     maSignatureManager.mxSignatureStream = rxStream;
267 }
268 
269 bool DigitalSignaturesDialog::canAddRemove()
270 {
271     //FIXME: this func needs some cleanup, such as real split between
272     //'canAdd' and 'canRemove' case
273     bool ret = true;
274 
275     uno::Reference<container::XNameAccess> xNameAccess(maSignatureManager.mxStore, uno::UNO_QUERY);
276     if (xNameAccess.is() && xNameAccess->hasByName("[Content_Types].xml"))
277         // It's always possible to append an OOXML signature.
278         return ret;
279 
280     if (!maSignatureManager.mxStore.is())
281         // It's always possible to append a PDF signature.
282         return ret;
283 
284     OSL_ASSERT(maSignatureManager.mxStore.is());
285     bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
286     SaveODFItem item;
287     bool bSave1_1 = item.isLessODF1_2();
288 
289     // see specification
290     //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw
291     //Paragraph 'Behavior with regard to ODF 1.2'
292     //For both, macro and document
293     if ( (!bSave1_1  && bDoc1_1) || (bSave1_1 && bDoc1_1) )
294     {
295         //#4
296         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
297                                                   VclMessageType::Warning, VclButtonsType::Ok,
298                                                   XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT)));
299         xBox->run();
300         ret = false;
301     }
302 
303     //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is
304     //adding a macro signature will break an existing document signature.
305     //The sfx2 will remove the documentsignature when the user adds a macro signature
306     if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros
307         && ret)
308     {
309         if (m_bHasDocumentSignature && !m_bWarningShowSignMacro)
310         {
311             //The warning says that the document signatures will be removed if the user
312             //continues. He can then either press 'OK' or 'NO'
313             //It the user presses 'Add' or 'Remove' several times then, then the warning
314             //is shown every time until the user presses 'OK'. From then on, the warning
315             //is not displayed anymore as long as the signatures dialog is alive.
316             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
317                                                       VclMessageType::Question, VclButtonsType::YesNo,
318                                                       XsResId(STR_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)));
319             if (xBox->run() == RET_NO)
320                 ret = false;
321             else
322                 m_bWarningShowSignMacro = true;
323 
324         }
325     }
326     return ret;
327 }
328 
329 bool DigitalSignaturesDialog::canAdd()
330 {
331     return canAddRemove();
332 }
333 
334 bool DigitalSignaturesDialog::canRemove()
335 {
336     bool bRet = true;
337 
338     if ( maSignatureManager.meSignatureMode == DocumentSignatureMode::Content )
339     {
340         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
341                                                   VclMessageType::Question, VclButtonsType::YesNo,
342                                                   XsResId(STR_XMLSECDLG_QUERY_REALLYREMOVE)));
343         short nDlgRet = xBox->run();
344         bRet = ( nDlgRet == RET_YES );
345     }
346 
347     return (bRet && canAddRemove());
348 }
349 
350 short DigitalSignaturesDialog::Execute()
351 {
352     // Verify Signatures and add certificates to ListBox...
353     mbVerifySignatures = true;
354     ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true);
355     ImplFillSignaturesBox();
356 
357     // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is
358     // enabled, set its initial state based on existing signatures, if any.
359 
360     // If it is OOXML, the checkbox is irrelevant.
361 
362     // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and
363     // check its nStorageFormat as that seems overly complicated and seems to have weird indirect
364     // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant()
365     // (which now is in #if 0).
366 
367     if (maSignatureManager.maCurrentSignatureInformations.size() > 0)
368     {
369         // If the document has only SHA-1 signatures we probably want it to stay that way?
370     }
371 
372     // Only verify once, content will not change.
373     // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
374     mbVerifySignatures = false;
375 
376     return Dialog::Execute();
377 }
378 
379 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureHighlightHdl, SvTreeListBox*, void)
380 {
381     bool bSel = m_pSignaturesLB->FirstSelected();
382     m_pViewBtn->Enable( bSel );
383     if ( m_pAddBtn->IsEnabled() ) // not read only
384         m_pRemoveBtn->Enable( bSel );
385 }
386 
387 IMPL_LINK_NOARG(DigitalSignaturesDialog, OKButtonHdl, Button*, void)
388 {
389     if (mbSignaturesChanged)
390         maSignatureManager.write(m_bAdESCompliant);
391 
392     EndDialog(RET_OK);
393 }
394 
395 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, SvTreeListBox*, bool)
396 {
397     ImplShowSignaturesDetails();
398     return false;
399 }
400 
401 IMPL_LINK_NOARG(DigitalSignaturesDialog, AdESCompliantCheckBoxHdl, CheckBox&, void)
402 {
403     m_bAdESCompliant = m_pAdESCompliantCB->IsChecked();
404 }
405 
406 IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, Button*, void)
407 {
408     ImplShowSignaturesDetails();
409 }
410 
411 IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
412 {
413     if( ! canAdd())
414         return;
415     try
416     {
417         std::vector<uno::Reference<xml::crypto::XXMLSecurityContext>> xSecContexts;
418         xSecContexts.push_back(maSignatureManager.getSecurityContext());
419         // Gpg signing is only possible with ODF >= 1.2 documents
420         if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.mxStore, m_sODFVersion))
421             xSecContexts.push_back(maSignatureManager.getGpgSecurityContext());
422 
423         ScopedVclPtrInstance< CertificateChooser > aChooser( this, mxCtx, xSecContexts, UserAction::Sign );
424         if ( aChooser->Execute() == RET_OK )
425         {
426             sal_Int32 nSecurityId;
427             if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(),
428                                         aChooser->GetDescription(), nSecurityId, m_bAdESCompliant))
429                 return;
430             mbSignaturesChanged = true;
431 
432             xml::crypto::SecurityOperationStatus nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
433 
434             if (maSignatureManager.mxStore.is())
435                 // In the PDF case the signature information is only available after parsing.
436                 nStatus = maSignatureManager.maSignatureHelper.GetSignatureInformation( nSecurityId ).nStatus;
437 
438             if ( nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED )
439             {
440                 mbSignaturesChanged = true;
441 
442                 // Can't simply remember current information, need parsing for getting full information :(
443                 // We need to verify the signatures again, otherwise the status in the signature information
444                 // will not contain
445                 // SecurityOperationStatus_OPERATION_SUCCEEDED
446                 mbVerifySignatures = true;
447                 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
448                 ImplFillSignaturesBox();
449             }
450         }
451     }
452     catch ( uno::Exception& )
453     {
454         OSL_FAIL( "Exception while adding a signature!" );
455         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
456                                                   VclMessageType::Error, VclButtonsType::Ok,
457                                                   XsResId(STR_XMLSECDLG_SIGNING_FAILED)));
458         xBox->run();
459         // Don't keep invalid entries...
460         ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
461         ImplFillSignaturesBox();
462     }
463 }
464 
465 IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void)
466 {
467     if (!canRemove())
468         return;
469     if( m_pSignaturesLB->FirstSelected() )
470     {
471         try
472         {
473             sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() ));
474             maSignatureManager.remove(nSelected);
475 
476             mbSignaturesChanged = true;
477 
478             ImplFillSignaturesBox();
479         }
480         catch ( uno::Exception& )
481         {
482             OSL_FAIL( "Exception while removing a signature!" );
483             // Don't keep invalid entries...
484             ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true);
485             ImplFillSignaturesBox();
486         }
487     }
488 }
489 
490 IMPL_STATIC_LINK(DigitalSignaturesDialog, CertMgrButtonHdl, Button*, pButton, void)
491 {
492 #ifdef _WIN32
493     // FIXME: call GpgME::dirInfo("bindir") somewhere in
494     // SecurityEnvironmentGpg or whatnot
495     // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful?
496     const OUString aGUIServers[] = { OUString("kleopatra.exe"), OUString("launch-gpa.exe"), OUString("gpa.exe"),
497                                      OUString("bin\\kleopatra.exe"), OUString("bin\\launch-gpa.exe"), OUString("bin\\gpa.exe") };
498     const char* const cPath = "C:\\Program Files (x86)\\GNU\\GnuPG";
499 #else
500     const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"),  OUString("gpa"), OUString("kgpg") };
501     const char* cPath = getenv("PATH");
502 #endif
503 
504     if (cPath)
505     {
506        OUString aPath(cPath, strlen(cPath), osl_getThreadTextEncoding());
507        OUString sFoundGUIServer, sExecutable;
508 
509        for ( auto const &rServer : aGUIServers )
510        {
511            osl::FileBase::RC searchError = osl::File::searchFileURL(rServer, aPath, sFoundGUIServer );
512            if (searchError == osl::FileBase::E_None)
513            {
514                osl::File::getSystemPathFromFileURL( sFoundGUIServer, sExecutable );
515                break;
516            }
517 
518        }
519 
520        if ( !sExecutable.isEmpty() )
521        {
522            uno::Reference< uno::XComponentContext > xContext =
523                ::comphelper::getProcessComponentContext();
524            uno::Reference< css::system::XSystemShellExecute > xSystemShell(
525                     css::system::SystemShellExecute::create(xContext) );
526 
527            xSystemShell->execute( sExecutable, OUString(),
528                css::system::SystemShellExecuteFlags::DEFAULTS );
529        }
530        else
531        {
532            std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pButton->GetFrameWeld(),
533                                                          VclMessageType::Info, VclButtonsType::Ok,
534                                                          XsResId(STR_XMLSECDLG_NO_CERT_MANAGER)));
535            xInfoBox->run();
536        }
537     }
538 }
539 
540 IMPL_LINK_NOARG(DigitalSignaturesDialog, StartVerifySignatureHdl, LinkParamNone*, bool)
541 {
542     return mbVerifySignatures;
543 }
544 
545 void DigitalSignaturesDialog::ImplFillSignaturesBox()
546 {
547     m_pSignaturesLB->Clear();
548 
549     size_t nInfos = maSignatureManager.maCurrentSignatureInformations.size();
550     size_t nValidSigs = 0, nValidCerts = 0;
551     bool bAllNewSignatures = true;
552 
553     if( nInfos )
554     {
555         for( size_t n = 0; n < nInfos; ++n )
556         {
557             DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
558                 m_sODFVersion, maSignatureManager.maCurrentSignatureInformations[n]);
559             std::vector< OUString > aElementsToBeVerified;
560             if (maSignatureManager.mxStore.is())
561                 aElementsToBeVerified = DocumentSignatureHelper::CreateElementList(maSignatureManager.mxStore, maSignatureManager.meSignatureMode, mode);
562 
563             const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[n];
564             uno::Reference< css::security::XCertificate > xCert = getCertificate(rInfo);
565 
566             OUString aSubject;
567             OUString aIssuer;
568             OUString aDateTimeStr;
569             OUString aDescription;
570             OUString aType;
571 
572             bool bSigValid = false;
573             bool bCertValid = false;
574             if( xCert.is() )
575             {
576                 //check the validity of the cert
577                 try {
578                     sal_Int32 certResult = getSecurityEnvironmentForCertificate(xCert)->verifyCertificate(xCert,
579                                                                                                           Sequence<uno::Reference<security::XCertificate> >());
580 
581                     bCertValid = certResult == css::security::CertificateValidity::VALID;
582                     if ( bCertValid )
583                         nValidCerts++;
584 
585                 } catch (css::uno::SecurityException& ) {
586                     OSL_FAIL("Verification of certificate failed");
587                     bCertValid = false;
588                 }
589 
590                 aSubject = XmlSec::GetContentPart( xCert->getSubjectName() );
591                 aIssuer = XmlSec::GetContentPart( xCert->getIssuerName() );
592             }
593             else if (!rInfo.ouGpgCertificate.isEmpty())
594             {
595                 // In case we don't have the gpg key locally, get some data from the document
596                 aIssuer = rInfo.ouGpgOwner;
597             }
598 
599             aDateTimeStr = XmlSec::GetDateTimeString( rInfo.stDateTime );
600             aDescription = rInfo.ouDescription;
601 
602             // Decide type string.
603             if (maSignatureManager.mxStore.is())
604             {
605                 // OpenPGP
606                 if (!rInfo.ouGpgCertificate.isEmpty())
607                     aType = "OpenPGP";
608                 // XML based: XAdES or not.
609                 else if (!rInfo.ouCertDigest.isEmpty())
610                     aType = "XAdES";
611                 else
612                     aType = "XML-DSig";
613             }
614             else
615             {
616                 // Assume PDF: PAdES or not.
617                 if (rInfo.bHasSigningCertificate)
618                     aType = "PAdES";
619                 else
620                     aType = "PDF";
621             }
622 
623             bSigValid = ( rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED );
624 
625             if ( bSigValid )
626             {
627                  bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
628                       aElementsToBeVerified, rInfo, mode);
629 
630                 if( bSigValid )
631                     nValidSigs++;
632             }
633 
634             Image aImage;
635             if (!bSigValid)
636             {
637                 aImage = m_pSigsInvalidImg->GetImage();
638             }
639             else if (bSigValid && !bCertValid)
640             {
641                 aImage = m_pSigsNotvalidatedImg->GetImage();
642             }
643             //Check if the signature is a "old" document signature, that is, which was created
644             //by an version of OOo previous to 3.2
645             // If there is no storage, then it's pointless to check storage
646             // stream references.
647             else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content
648                 && bSigValid && bCertValid && (maSignatureManager.mxStore.is() && !DocumentSignatureHelper::isOOo3_2_Signature(
649                 maSignatureManager.maCurrentSignatureInformations[n])))
650             {
651                 aImage = m_pSigsNotvalidatedImg->GetImage();
652                 bAllNewSignatures = false;
653             }
654             else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content
655                 && bSigValid && bCertValid && DocumentSignatureHelper::isOOo3_2_Signature(
656                 maSignatureManager.maCurrentSignatureInformations[n]))
657             {
658                 aImage = m_pSigsValidImg->GetImage();
659             }
660             else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros
661                 && bSigValid && bCertValid)
662             {
663                 aImage = m_pSigsValidImg->GetImage();
664             }
665 
666             SvTreeListEntry* pEntry = m_pSignaturesLB->InsertEntry( OUString(), aImage, aImage );
667             m_pSignaturesLB->SetEntryText( aSubject, pEntry, 1 );
668             m_pSignaturesLB->SetEntryText( aIssuer, pEntry, 2 );
669             m_pSignaturesLB->SetEntryText( aDateTimeStr, pEntry, 3 );
670             m_pSignaturesLB->SetEntryText(aDescription, pEntry, 4);
671             m_pSignaturesLB->SetEntryText(aType, pEntry, 5);
672             pEntry->SetUserData( reinterpret_cast<void*>(n) );     // misuse user data as index
673         }
674     }
675 
676     bool bAllSigsValid = (nValidSigs == nInfos);
677     bool bAllCertsValid = (nValidCerts == nInfos);
678     bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures);
679 
680     m_pSigsValidImg->Show( bShowValidState);
681     m_pSigsValidFI->Show( bShowValidState );
682 
683     bool bShowInvalidState = nInfos && !bAllSigsValid;
684 
685     m_pSigsInvalidImg->Show( bShowInvalidState );
686     m_pSigsInvalidFI->Show( bShowInvalidState );
687 
688     bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid;
689 
690     m_pSigsNotvalidatedImg->Show(bShowNotValidatedState);
691     m_pSigsNotvalidatedFI->Show(bShowNotValidatedState);
692 
693     //bAllNewSignatures is always true if we are not in document mode
694     bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures;
695     m_pSigsOldSignatureImg->Show(bShowOldSignature);
696     m_pSigsOldSignatureFI->Show(bShowOldSignature);
697 
698     SignatureHighlightHdl( nullptr );
699 }
700 
701 uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(const SignatureInformation& rInfo)
702 {
703     uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureManager.getSecurityEnvironment();
704     uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = maSignatureManager.getGpgSecurityEnvironment();
705     uno::Reference<security::XCertificate> xCert;
706 
707     //First we try to get the certificate which is embedded in the XML Signature
708     if (xSecEnv.is() && !rInfo.ouX509Certificate.isEmpty())
709         xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
710     else {
711         //There must be an embedded certificate because we use it to get the
712         //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
713         //because it could be modified by an attacker. The issuer is displayed
714         //in the digital signature dialog.
715         //Comparing the X509IssuerName with the one from the X509Certificate in order
716         //to find out if the X509IssuerName was modified does not work. See #i62684
717         SAL_WARN( "xmlsecurity.dialogs", "Could not find embedded certificate!");
718     }
719 
720     //In case there is no embedded certificate we try to get it from a local store
721     if (!xCert.is() && xSecEnv.is())
722         xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
723     if (!xCert.is() && xGpgSecEnv.is())
724         xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") );
725 
726     SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );
727 
728     return xCert;
729 }
730 
731 uno::Reference<xml::crypto::XSecurityEnvironment> DigitalSignaturesDialog::getSecurityEnvironmentForCertificate(const uno::Reference<security::XCertificate>& xCert)
732 {
733     if (xCert->getCertificateKind() == CertificateKind_OPENPGP)
734         return maSignatureManager.getGpgSecurityEnvironment();
735     else if (xCert->getCertificateKind() == CertificateKind_X509)
736         return maSignatureManager.getSecurityEnvironment();
737 
738     throw RuntimeException("Unknown certificate kind");
739 }
740 
741 //If bUseTempStream is true then the temporary signature stream is used.
742 //Otherwise the real signature stream is used.
743 void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature)
744 {
745     maSignatureManager.read(bUseTempStream, bCacheLastSignature);
746     mbVerifySignatures = false;
747 }
748 
749 void DigitalSignaturesDialog::ImplShowSignaturesDetails()
750 {
751     if( m_pSignaturesLB->FirstSelected() )
752     {
753         sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() ));
754         const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[ nSelected ];
755         uno::Reference<security::XCertificate> xCert = getCertificate(rInfo);
756 
757         if ( xCert.is() )
758         {
759             uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = getSecurityEnvironmentForCertificate(xCert);
760             ScopedVclPtrInstance<CertificateViewer> aViewer(this, xSecEnv, xCert, false);
761             aViewer->Execute();
762         }
763         else
764         {
765             std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
766                                                           VclMessageType::Info, VclButtonsType::Ok,
767                                                           XsResId(STR_XMLSECDLG_NO_CERT_FOUND)));
768             xInfoBox->run();
769         }
770     }
771 }
772 
773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
774