summaryrefslogtreecommitdiffstats
path: root/xmlsecurity/source/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'xmlsecurity/source/dialogs')
-rw-r--r--xmlsecurity/source/dialogs/certificatechooser.cxx332
-rw-r--r--xmlsecurity/source/dialogs/certificateviewer.cxx377
-rw-r--r--xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx801
-rw-r--r--xmlsecurity/source/dialogs/macrosecurity.cxx446
4 files changed, 1956 insertions, 0 deletions
diff --git a/xmlsecurity/source/dialogs/certificatechooser.cxx b/xmlsecurity/source/dialogs/certificatechooser.cxx
new file mode 100644
index 000000000..3ac503521
--- /dev/null
+++ b/xmlsecurity/source/dialogs/certificatechooser.cxx
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_gpgme.h>
+#include <certificatechooser.hxx>
+#include <certificateviewer.hxx>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/xmlsechelper.hxx>
+
+#include <com/sun/star/security/NoPasswordException.hpp>
+#include <com/sun/star/security/CertificateCharacters.hpp>
+
+#include <o3tl/safeint.hxx>
+#include <unotools/datetime.hxx>
+#include <unotools/useroptions.hxx>
+
+#include <resourcemanager.hxx>
+#include <strings.hrc>
+
+using namespace comphelper;
+using namespace css;
+
+CertificateChooser::CertificateChooser(weld::Window* _pParent,
+ std::vector< css::uno::Reference< css::xml::crypto::XXMLSecurityContext > > && rxSecurityContexts,
+ UserAction eAction)
+ : GenericDialogController(_pParent, "xmlsec/ui/selectcertificatedialog.ui", "SelectCertificateDialog")
+ , meAction(eAction)
+ , m_xFTSign(m_xBuilder->weld_label("sign"))
+ , m_xFTEncrypt(m_xBuilder->weld_label("encrypt"))
+ , m_xCertLB(m_xBuilder->weld_tree_view("signatures"))
+ , m_xViewBtn(m_xBuilder->weld_button("viewcert"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ , m_xFTDescription(m_xBuilder->weld_label("description-label"))
+ , m_xDescriptionED(m_xBuilder->weld_entry("description"))
+{
+ auto nControlWidth = m_xCertLB->get_approximate_digit_width() * 105;
+ m_xCertLB->set_size_request(nControlWidth, m_xCertLB->get_height_rows(12));
+
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(30*nControlWidth/100),
+ o3tl::narrowing<int>(30*nControlWidth/100),
+ o3tl::narrowing<int>(10*nControlWidth/100),
+ o3tl::narrowing<int>(20*nControlWidth/100)
+ };
+ m_xCertLB->set_column_fixed_widths(aWidths);
+ m_xCertLB->connect_changed( LINK( this, CertificateChooser, CertificateHighlightHdl ) );
+ m_xCertLB->connect_row_activated( LINK( this, CertificateChooser, CertificateSelectHdl ) );
+ m_xViewBtn->connect_clicked( LINK( this, CertificateChooser, ViewButtonHdl ) );
+
+ mxSecurityContexts = std::move(rxSecurityContexts);
+ mbInitialized = false;
+
+ // disable buttons
+ CertificateHighlightHdl(*m_xCertLB);
+}
+
+CertificateChooser::~CertificateChooser()
+{
+}
+
+short CertificateChooser::run()
+{
+ // #i48432#
+ // We can't check for personal certificates before raising this dialog,
+ // because the mozilla implementation throws a NoPassword exception,
+ // if the user pressed cancel, and also if the database does not exist!
+ // But in the later case, the is no password query, and the user is confused
+ // that nothing happens when pressing "Add..." in the SignatureDialog.
+
+ // PostUserEvent( LINK( this, CertificateChooser, Initialize ) );
+
+ // PostUserLink behavior is too slow, so do it directly before Execute().
+ // Problem: This Dialog should be visible right now, and the parent should not be accessible.
+ // Show, Update, DisableInput...
+
+ m_xDialog->show();
+ ImplInitialize();
+ return GenericDialogController::run();
+}
+
+void CertificateChooser::HandleOneUsageBit(OUString& string, int& bits, int bit, TranslateId pResId)
+{
+ if (bits & bit)
+ {
+ if (!string.isEmpty())
+ string += ", ";
+ string += XsResId(pResId);
+ bits &= ~bit;
+ }
+}
+
+OUString CertificateChooser::UsageInClearText(int bits)
+{
+ OUString result;
+
+ HandleOneUsageBit(result, bits, 0x80, STR_DIGITAL_SIGNATURE);
+ HandleOneUsageBit(result, bits, 0x40, STR_NON_REPUDIATION);
+ HandleOneUsageBit(result, bits, 0x20, STR_KEY_ENCIPHERMENT);
+ HandleOneUsageBit(result, bits, 0x10, STR_DATA_ENCIPHERMENT);
+ HandleOneUsageBit(result, bits, 0x08, STR_KEY_AGREEMENT);
+ HandleOneUsageBit(result, bits, 0x04, STR_KEY_CERT_SIGN);
+ HandleOneUsageBit(result, bits, 0x02, STR_CRL_SIGN);
+ HandleOneUsageBit(result, bits, 0x01, STR_ENCIPHER_ONLY);
+
+ // Check for mystery leftover bits
+ if (bits != 0)
+ {
+ if (!result.isEmpty())
+ result += ", ";
+ result += "0x" + OUString::number(bits, 16);
+ }
+
+ return result;
+}
+
+void CertificateChooser::ImplInitialize()
+{
+ if ( mbInitialized )
+ return;
+
+ SvtUserOptions aUserOpts;
+
+ switch (meAction)
+ {
+ case UserAction::Sign:
+ m_xFTSign->show();
+ m_xOKBtn->set_label(XsResId(STR_SIGN));
+ msPreferredKey = aUserOpts.GetSigningKey();
+ break;
+
+ case UserAction::SelectSign:
+ m_xFTSign->show();
+ m_xOKBtn->set_label(XsResId(STR_SELECTSIGN));
+ msPreferredKey = aUserOpts.GetSigningKey();
+ break;
+
+ case UserAction::Encrypt:
+ m_xFTEncrypt->show();
+ m_xFTDescription->hide();
+ m_xDescriptionED->hide();
+ m_xCertLB->set_selection_mode(SelectionMode::Multiple);
+ m_xOKBtn->set_label(XsResId(STR_ENCRYPT));
+ msPreferredKey = aUserOpts.GetEncryptionKey();
+ break;
+
+ }
+
+ for (auto &secContext : mxSecurityContexts)
+ {
+ if (!secContext.is())
+ continue;
+ auto secEnvironment = secContext->getSecurityEnvironment();
+ if (!secEnvironment.is())
+ continue;
+
+ uno::Sequence< uno::Reference< security::XCertificate > > xCerts;
+ try
+ {
+ if ( meAction == UserAction::Sign || meAction == UserAction::SelectSign)
+ xCerts = secEnvironment->getPersonalCertificates();
+ else
+ xCerts = secEnvironment->getAllCertificates();
+ }
+ catch (security::NoPasswordException&)
+ {
+ }
+
+ for( sal_Int32 nCert = xCerts.getLength(); nCert; )
+ {
+ uno::Reference< security::XCertificate > xCert = xCerts[ --nCert ];
+ // Check if we have a private key for this...
+ tools::Long nCertificateCharacters = secEnvironment->getCertificateCharacters(xCert);
+
+ if (!(nCertificateCharacters & security::CertificateCharacters::HAS_PRIVATE_KEY))
+ {
+ ::comphelper::removeElementAt( xCerts, nCert );
+ }
+ }
+
+
+ // fill list of certificates; the first entry will be selected
+ for ( const auto& xCert : std::as_const(xCerts) )
+ {
+ std::shared_ptr<UserData> userData = std::make_shared<UserData>();
+ userData->xCertificate = xCert;
+ userData->xSecurityContext = secContext;
+ userData->xSecurityEnvironment = secEnvironment;
+ mvUserData.push_back(userData);
+
+ OUString sIssuer = xmlsec::GetContentPart( xCert->getIssuerName(), xCert->getCertificateKind());
+
+ m_xCertLB->append();
+ int nRow = m_xCertLB->n_children() - 1;
+ m_xCertLB->set_text(nRow, xmlsec::GetContentPart(xCert->getSubjectName(), xCert->getCertificateKind()), 0);
+ m_xCertLB->set_text(nRow, sIssuer, 1);
+ m_xCertLB->set_text(nRow, xmlsec::GetCertificateKind(xCert->getCertificateKind()), 2);
+ m_xCertLB->set_text(nRow, utl::GetDateString(xCert->getNotValidAfter()), 3);
+ m_xCertLB->set_text(nRow, UsageInClearText(xCert->getCertificateUsage()), 4);
+ OUString sId(weld::toId(userData.get()));
+ m_xCertLB->set_id(nRow, sId);
+
+#if HAVE_FEATURE_GPGME
+ // only GPG has preferred keys
+ if ( !sIssuer.isEmpty() && !msPreferredKey.isEmpty() ) {
+ if ( sIssuer == msPreferredKey )
+ {
+ if ( meAction == UserAction::Sign || meAction == UserAction::SelectSign )
+ m_xCertLB->select(nRow);
+ else if ( meAction == UserAction::Encrypt &&
+ aUserOpts.GetEncryptToSelf() )
+ mxEncryptToSelf = xCert;
+ }
+ }
+#endif
+ }
+ }
+
+ // enable/disable buttons
+ CertificateHighlightHdl(*m_xCertLB);
+ mbInitialized = true;
+}
+
+uno::Sequence<uno::Reference< css::security::XCertificate > > CertificateChooser::GetSelectedCertificates()
+{
+ std::vector< uno::Reference< css::security::XCertificate > > aRet;
+ if (meAction == UserAction::Encrypt)
+ {
+ // for encryption, multiselection is enabled
+ m_xCertLB->selected_foreach([this, &aRet](weld::TreeIter& rEntry){
+ UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(rEntry));
+ aRet.push_back( userData->xCertificate );
+ return false;
+ });
+ }
+ else
+ {
+ uno::Reference< css::security::XCertificate > xCert;
+ int nSel = m_xCertLB->get_selected_index();
+ if (nSel != -1)
+ {
+ UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
+ xCert = userData->xCertificate;
+ }
+ aRet.push_back( xCert );
+ }
+
+#if HAVE_FEATURE_GPGME
+ if ( mxEncryptToSelf.is())
+ aRet.push_back( mxEncryptToSelf );
+#endif
+
+ return comphelper::containerToSequence(aRet);
+}
+
+uno::Reference<xml::crypto::XXMLSecurityContext> CertificateChooser::GetSelectedSecurityContext() const
+{
+ int nSel = m_xCertLB->get_selected_index();
+ if (nSel == -1)
+ return uno::Reference<xml::crypto::XXMLSecurityContext>();
+
+ UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
+ uno::Reference<xml::crypto::XXMLSecurityContext> xCert = userData->xSecurityContext;
+ return xCert;
+}
+
+OUString CertificateChooser::GetDescription() const
+{
+ return m_xDescriptionED->get_text();
+}
+
+OUString CertificateChooser::GetUsageText()
+{
+ uno::Sequence< uno::Reference<css::security::XCertificate> > xCerts =
+ GetSelectedCertificates();
+ return (xCerts.hasElements() && xCerts[0].is()) ?
+ UsageInClearText(xCerts[0]->getCertificateUsage()) : OUString();
+}
+
+IMPL_LINK_NOARG(CertificateChooser, CertificateHighlightHdl, weld::TreeView&, void)
+{
+ bool bEnable = m_xCertLB->get_selected_index() != -1;
+ m_xViewBtn->set_sensitive(bEnable);
+ m_xOKBtn->set_sensitive(bEnable);
+ m_xDescriptionED->set_sensitive(bEnable);
+}
+
+IMPL_LINK_NOARG(CertificateChooser, CertificateSelectHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+IMPL_LINK_NOARG(CertificateChooser, ViewButtonHdl, weld::Button&, void)
+{
+ ImplShowCertificateDetails();
+}
+
+void CertificateChooser::ImplShowCertificateDetails()
+{
+ int nSel = m_xCertLB->get_selected_index();
+ if (nSel == -1)
+ return;
+
+ UserData* userData = weld::fromId<UserData*>(m_xCertLB->get_id(nSel));
+
+ if (!userData->xSecurityEnvironment.is() || !userData->xCertificate.is())
+ return;
+
+ CertificateViewer aViewer(m_xDialog.get(), userData->xSecurityEnvironment, userData->xCertificate, true, this);
+ aViewer.run();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/dialogs/certificateviewer.cxx b/xmlsecurity/source/dialogs/certificateviewer.cxx
new file mode 100644
index 000000000..1801cdf53
--- /dev/null
+++ b/xmlsecurity/source/dialogs/certificateviewer.cxx
@@ -0,0 +1,377 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <certificatechooser.hxx>
+#include <certificateviewer.hxx>
+#include <com/sun/star/security/XCertificate.hpp>
+
+#include <com/sun/star/security/CertificateCharacters.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/datetime.hxx>
+
+#include <strings.hrc>
+#include <resourcemanager.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <tools/datetime.hxx>
+#include <bitmaps.hlst>
+
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+CertificateViewer::CertificateViewer(weld::Window* _pParent,
+ const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& _rxSecurityEnvironment,
+ const css::uno::Reference< css::security::XCertificate >& _rXCert, bool bCheckForPrivateKey,
+ CertificateChooser* pParentChooser)
+ : GenericDialogController(_pParent, "xmlsec/ui/viewcertdialog.ui", "ViewCertDialog")
+ , mbCheckForPrivateKey(bCheckForPrivateKey)
+ , mpParentChooser(pParentChooser)
+ , mxTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+{
+ mxTabCtrl->connect_enter_page(LINK(this, CertificateViewer, ActivatePageHdl));
+
+ mxSecurityEnvironment = _rxSecurityEnvironment;
+ mxCert = _rXCert;
+
+ mxGeneralPage.reset(new CertificateViewerGeneralTP(mxTabCtrl->get_page("general"), this));
+ mxDetailsPage.reset(new CertificateViewerDetailsTP(mxTabCtrl->get_page("details"), this));
+ if (!mxSecurityEnvironment->buildCertificatePath(mxCert).hasElements())
+ mxTabCtrl->remove_page("path");
+ else
+ mxPathId.reset(new CertificateViewerCertPathTP(mxTabCtrl->get_page("path"), this));
+ mxTabCtrl->set_current_page("general");
+}
+
+IMPL_LINK(CertificateViewer, ActivatePageHdl, const OString&, rPage, void)
+{
+ if (rPage == "path")
+ mxPathId->ActivatePage();
+}
+
+CertificateViewerTP::CertificateViewerTP(weld::Container* pParent, const OUString& rUIXMLDescription,
+ const OString& rID, CertificateViewer* pDlg)
+ : mxBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , mxContainer(mxBuilder->weld_container(rID))
+ , mpDlg(pDlg)
+{
+}
+
+CertificateViewerGeneralTP::CertificateViewerGeneralTP(weld::Container* pParent, CertificateViewer* pDlg)
+ : CertificateViewerTP(pParent, "xmlsec/ui/certgeneral.ui", "CertGeneral", pDlg)
+ , m_xCertImg(mxBuilder->weld_image("certimage"))
+ , m_xHintNotTrustedFT(mxBuilder->weld_label("hintnotrust"))
+ , m_xIssuedToLabelFT(mxBuilder->weld_label("issued_to"))
+ , m_xIssuedToFT(mxBuilder->weld_label("issued_to_value"))
+ , m_xIssuedByLabelFT(mxBuilder->weld_label("issued_by"))
+ , m_xIssuedByFT(mxBuilder->weld_label("issued_by_value"))
+ , m_xValidFromDateFT(mxBuilder->weld_label("valid_from_value"))
+ , m_xValidToDateFT(mxBuilder->weld_label("valid_to_value"))
+ , m_xKeyImg(mxBuilder->weld_image("keyimage"))
+ , m_xHintCorrespPrivKeyFT(mxBuilder->weld_label("privatekey"))
+{
+ //Verify the certificate
+ sal_Int32 certStatus = mpDlg->mxSecurityEnvironment->verifyCertificate(mpDlg->mxCert,
+ Sequence<Reference<css::security::XCertificate> >());
+
+ bool bCertValid = certStatus == css::security::CertificateValidity::VALID;
+
+ if ( !bCertValid )
+ {
+ m_xCertImg->set_from_icon_name(BMP_STATE_NOT_VALIDATED);
+ m_xHintNotTrustedFT->set_label(XsResId(STR_CERTIFICATE_NOT_VALIDATED));
+ }
+
+ // insert data
+ css::uno::Reference< css::security::XCertificate > xCert = mpDlg->mxCert;
+
+ OUString sSubjectName(xmlsec::GetContentPart(xCert->getSubjectName(), xCert->getCertificateKind()));
+ if (!sSubjectName.isEmpty())
+ m_xIssuedToFT->set_label(sSubjectName);
+ else
+ m_xIssuedToLabelFT->hide();
+ OUString sIssuerName(xmlsec::GetContentPart(xCert->getIssuerName(), xCert->getCertificateKind()));
+ if (!sIssuerName.isEmpty())
+ m_xIssuedByFT->set_label(sIssuerName);
+ else
+ m_xIssuedByLabelFT->hide();
+
+ DateTime aDateTimeStart( DateTime::EMPTY );
+ DateTime aDateTimeEnd( DateTime::EMPTY );
+ utl::typeConvert( xCert->getNotValidBefore(), aDateTimeStart );
+ utl::typeConvert( xCert->getNotValidAfter(), aDateTimeEnd );
+
+ OUString sValidFromDate = Application::GetSettings().GetUILocaleDataWrapper().getDate(Date(aDateTimeStart.GetDate()));
+ OUString sValidToDate = Application::GetSettings().GetUILocaleDataWrapper().getDate(Date(aDateTimeEnd.GetDate()));
+
+ m_xValidFromDateFT->set_label(sValidFromDate);
+ m_xValidToDateFT->set_label(sValidToDate);
+
+ // Check if we have the private key...
+ bool bHasPrivateKey = false;
+ // #i41270# Check only if we have that certificate in our security environment
+ if (pDlg->mbCheckForPrivateKey)
+ {
+ tools::Long nCertificateCharacters = pDlg->mxSecurityEnvironment->getCertificateCharacters(xCert);
+ bHasPrivateKey = (nCertificateCharacters & security::CertificateCharacters::HAS_PRIVATE_KEY);
+ }
+ if (!bHasPrivateKey)
+ {
+ m_xKeyImg->hide();
+ m_xHintCorrespPrivKeyFT->hide();
+ }
+}
+
+void CertificateViewerDetailsTP::InsertElement(const OUString& rField, const OUString& rValue,
+ const OUString& rDetails, bool bFixedWidthFont)
+{
+ m_aUserData.emplace_back(std::make_unique<Details_UserDatat>(rDetails, bFixedWidthFont));
+ OUString sId(weld::toId(m_aUserData.back().get()));
+ m_xElementsLB->append(sId, rField);
+ m_xElementsLB->set_text(m_xElementsLB->n_children() -1, rValue, 1);
+}
+
+CertificateViewerDetailsTP::CertificateViewerDetailsTP(weld::Container* pParent, CertificateViewer* pDlg)
+ : CertificateViewerTP(pParent, "xmlsec/ui/certdetails.ui", "CertDetails", pDlg)
+ , m_xElementsLB(mxBuilder->weld_tree_view("tablecontainer"))
+ , m_xValueDetails(mxBuilder->weld_text_view("valuedetails"))
+{
+ const int nWidth = m_xElementsLB->get_approximate_digit_width() * 60;
+ const int nHeight = m_xElementsLB->get_height_rows(8);
+ m_xElementsLB->set_size_request(nWidth, nHeight);
+ m_xValueDetails->set_size_request(nWidth, nHeight);
+ m_xElementsLB->set_column_fixed_widths( { nWidth / 2 } );
+
+ // fill list box
+ Reference< security::XCertificate > xCert = mpDlg->mxCert;
+ sal_uInt16 nLineBreak = 16;
+ const char* const pHexSep = " ";
+ OUString aLBEntry;
+ OUString aDetails;
+ // Certificate Versions are reported wrong (#i35107#) - 0 == "V1", 1 == "V2", ..., n = "V(n+1)"
+ aLBEntry = "V" + OUString::number( xCert->getVersion() + 1 );
+ InsertElement( XsResId( STR_VERSION ), aLBEntry, aLBEntry );
+ Sequence< sal_Int8 > aSeq = xCert->getSerialNumber();
+ aLBEntry = xmlsec::GetHexString( aSeq, pHexSep );
+ aDetails = xmlsec::GetHexString( aSeq, pHexSep, nLineBreak );
+ InsertElement( XsResId( STR_SERIALNUM ), aLBEntry, aDetails, true );
+
+ std::pair< OUString, OUString> pairIssuer =
+ xmlsec::GetDNForCertDetailsView(xCert->getIssuerName());
+ aLBEntry = pairIssuer.first;
+ aDetails = pairIssuer.second;
+ InsertElement( XsResId( STR_ISSUER ), aLBEntry, aDetails );
+
+ DateTime aDateTime( DateTime::EMPTY );
+ utl::typeConvert( xCert->getNotValidBefore(), aDateTime );
+ aLBEntry = Application::GetSettings().GetUILocaleDataWrapper().getDate(Date(aDateTime.GetDate())) + " ";
+ aLBEntry += Application::GetSettings().GetUILocaleDataWrapper().getTime(tools::Time(aDateTime.GetTime()));
+ InsertElement( XsResId( STR_VALIDFROM ), aLBEntry, aLBEntry );
+ utl::typeConvert( xCert->getNotValidAfter(), aDateTime );
+ aLBEntry = Application::GetSettings().GetUILocaleDataWrapper().getDate(Date(aDateTime.GetDate()) ) + " ";
+ aLBEntry += Application::GetSettings().GetUILocaleDataWrapper().getTime(tools::Time(aDateTime.GetTime()));
+ InsertElement( XsResId( STR_VALIDTO ), aLBEntry, aLBEntry );
+
+ std::pair< OUString, OUString > pairSubject =
+ xmlsec::GetDNForCertDetailsView(xCert->getSubjectName());
+ aLBEntry = pairSubject.first;
+ aDetails = pairSubject.second;
+ InsertElement( XsResId( STR_SUBJECT ), aLBEntry, aDetails );
+
+ aLBEntry = aDetails = xCert->getSubjectPublicKeyAlgorithm();
+ InsertElement( XsResId( STR_SUBJECT_PUBKEY_ALGO ), aLBEntry, aDetails );
+ aSeq = xCert->getSubjectPublicKeyValue();
+ aLBEntry = xmlsec::GetHexString( aSeq, pHexSep );
+ aDetails = xmlsec::GetHexString( aSeq, pHexSep, nLineBreak );
+ InsertElement( XsResId( STR_SUBJECT_PUBKEY_VAL ), aLBEntry, aDetails, true );
+
+ aLBEntry = aDetails = xCert->getSignatureAlgorithm();
+ InsertElement( XsResId( STR_SIGNATURE_ALGO ), aLBEntry, aDetails );
+
+ CertificateChooser* pChooser = mpDlg->GetParentChooser();
+ if (pChooser)
+ {
+ aLBEntry = CertificateChooser::UsageInClearText( mpDlg->mxCert->getCertificateUsage() );
+ InsertElement( XsResId( STR_USE ), aLBEntry, aLBEntry );
+ }
+
+ aSeq = xCert->getSHA1Thumbprint();
+ aLBEntry = xmlsec::GetHexString( aSeq, pHexSep );
+ aDetails = xmlsec::GetHexString( aSeq, pHexSep, nLineBreak );
+ InsertElement( XsResId( STR_THUMBPRINT_SHA1 ), aLBEntry, aDetails, true );
+
+ aSeq = xCert->getMD5Thumbprint();
+ aLBEntry = xmlsec::GetHexString( aSeq, pHexSep );
+ aDetails = xmlsec::GetHexString( aSeq, pHexSep, nLineBreak );
+ InsertElement( XsResId( STR_THUMBPRINT_MD5 ), aLBEntry, aDetails, true );
+
+ m_xElementsLB->connect_changed(LINK(this, CertificateViewerDetailsTP, ElementSelectHdl));
+}
+
+IMPL_LINK_NOARG(CertificateViewerDetailsTP, ElementSelectHdl, weld::TreeView&, void)
+{
+ int nEntry = m_xElementsLB->get_selected_index();
+ OUString aElementText;
+ bool bFixedWidthFont;
+ if (nEntry != -1)
+ {
+ const Details_UserDatat* p = weld::fromId<Details_UserDatat*>(m_xElementsLB->get_id(nEntry));
+ aElementText = p->maTxt;
+ bFixedWidthFont = p->mbFixedWidthFont;
+ }
+ else
+ bFixedWidthFont = false;
+
+ m_xValueDetails->set_monospace(bFixedWidthFont);
+ m_xValueDetails->set_text(aElementText);
+}
+
+CertificateViewerCertPathTP::CertificateViewerCertPathTP(weld::Container* pParent, CertificateViewer* pDlg)
+ : CertificateViewerTP(pParent, "xmlsec/ui/certpage.ui", "CertPage", pDlg)
+ , mpParent(pDlg)
+ , mbFirstActivateDone(false)
+ , mxCertPathLB(mxBuilder->weld_tree_view("signatures"))
+ , mxScratchIter(mxCertPathLB->make_iterator())
+ , mxViewCertPB(mxBuilder->weld_button("viewcert"))
+ , mxCertStatusML(mxBuilder->weld_text_view("status"))
+ , mxCertOK(mxBuilder->weld_label("certok"))
+ , mxCertNotValidated(mxBuilder->weld_label("certnotok"))
+{
+ const int nWidth = mxCertPathLB->get_approximate_digit_width() * 60;
+ const int nHeight = mxCertPathLB->get_height_rows(6);
+ mxCertPathLB->set_size_request(nWidth, nHeight);
+ mxCertStatusML->set_size_request(nWidth, nHeight);
+
+ mxCertPathLB->connect_changed( LINK( this, CertificateViewerCertPathTP, CertSelectHdl ) );
+ mxViewCertPB->connect_clicked( LINK( this, CertificateViewerCertPathTP, ViewCertHdl ) );
+}
+
+CertificateViewerCertPathTP::~CertificateViewerCertPathTP()
+{
+ if (mxCertificateViewer)
+ mxCertificateViewer->response(RET_OK);
+}
+
+void CertificateViewerCertPathTP::ActivatePage()
+{
+ if ( mbFirstActivateDone )
+ return;
+
+ mbFirstActivateDone = true;
+ Sequence< Reference< security::XCertificate > > aCertPath =
+ mpParent->mxSecurityEnvironment->buildCertificatePath( mpParent->mxCert );
+ const Reference< security::XCertificate >* pCertPath = aCertPath.getConstArray();
+
+ sal_Int32 i, nCnt = aCertPath.getLength();
+ std::unique_ptr<weld::TreeIter> xParent;
+ for (i = nCnt-1; i >= 0; i--)
+ {
+ const Reference< security::XCertificate > rCert = pCertPath[ i ];
+ OUString sName = xmlsec::GetContentPart( rCert->getSubjectName(), rCert->getCertificateKind() );
+ //Verify the certificate
+ sal_Int32 certStatus = mpDlg->mxSecurityEnvironment->verifyCertificate(rCert,
+ Sequence<Reference<css::security::XCertificate> >());
+ bool bCertValid = certStatus == css::security::CertificateValidity::VALID;
+ InsertCert(xParent.get(), sName, rCert, bCertValid);
+ if (!xParent)
+ {
+ xParent = mxCertPathLB->make_iterator();
+ (void)mxCertPathLB->get_iter_first(*xParent);
+ }
+ else
+ {
+ (void)mxCertPathLB->iter_children(*xParent);
+ }
+ }
+
+ if (xParent)
+ mxCertPathLB->select(*xParent);
+ mxViewCertPB->set_sensitive(false); // Own certificate selected
+
+ while (xParent)
+ {
+ mxCertPathLB->expand_row(*xParent);
+ if (!mxCertPathLB->iter_parent(*xParent))
+ xParent.reset();
+ }
+
+ CertSelectHdl(*mxCertPathLB);
+}
+
+IMPL_LINK_NOARG(CertificateViewerCertPathTP, ViewCertHdl, weld::Button&, void)
+{
+ std::unique_ptr<weld::TreeIter> xIter = mxCertPathLB->make_iterator();
+ if (mxCertPathLB->get_selected(xIter.get()))
+ {
+ if (mxCertificateViewer)
+ mxCertificateViewer->response(RET_OK);
+
+ CertPath_UserData* pData = weld::fromId<CertPath_UserData*>(mxCertPathLB->get_id(*xIter));
+ mxCertificateViewer = std::make_shared<CertificateViewer>(mpDlg->getDialog(), mpDlg->mxSecurityEnvironment,
+ pData->mxCert, false, nullptr);
+ weld::DialogController::runAsync(mxCertificateViewer, [this] (sal_Int32) { mxCertificateViewer = nullptr; });
+ }
+}
+
+IMPL_LINK_NOARG(CertificateViewerCertPathTP, CertSelectHdl, weld::TreeView&, void)
+{
+ OUString sStatus;
+
+ std::unique_ptr<weld::TreeIter> xIter = mxCertPathLB->make_iterator();
+ bool bEntry = mxCertPathLB->get_selected(xIter.get());
+ if (bEntry)
+ {
+ CertPath_UserData* pData = weld::fromId<CertPath_UserData*>(mxCertPathLB->get_id(*xIter));
+ if (pData)
+ sStatus = pData->mbValid ? mxCertOK->get_label() : mxCertNotValidated->get_label();
+ }
+
+ mxCertStatusML->set_text(sStatus);
+
+ bool bSensitive = false;
+ if (bEntry)
+ {
+ // if has children, so not the last one in the chain
+ if (mxCertPathLB->iter_children(*xIter))
+ bSensitive = true;
+ }
+ mxViewCertPB->set_sensitive(bSensitive);
+}
+
+void CertificateViewerCertPathTP::InsertCert(const weld::TreeIter* pParent, const OUString& rName,
+ const css::uno::Reference< css::security::XCertificate >& rxCert,
+ bool bValid)
+{
+ auto const sImage = bValid ? std::u16string_view(u"" BMP_CERT_OK) : std::u16string_view(u"" BMP_CERT_NOT_OK);
+ maUserData.emplace_back(std::make_unique<CertPath_UserData>(rxCert, bValid));
+ OUString sId(weld::toId(maUserData.back().get()));
+ mxCertPathLB->insert(pParent, -1, &rName, &sId, nullptr, nullptr, false, mxScratchIter.get());
+ mxCertPathLB->set_image(*mxScratchIter, OUString(sImage));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
new file mode 100644
index 000000000..1d40e7562
--- /dev/null
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -0,0 +1,801 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <digitalsignaturesdialog.hxx>
+#include <certificatechooser.hxx>
+#include <certificateviewer.hxx>
+#include <biginteger.hxx>
+#include <sax/tools/converter.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/security/NoPasswordException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/security/CertificateKind.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
+#include <com/sun/star/system/SystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/system/SystemShellExecuteException.hpp>
+
+#include <osl/file.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <unotools/datetime.hxx>
+
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <resourcemanager.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <vcl/weld.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/configitem.hxx>
+
+#ifdef _WIN32
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <prewin.h>
+#include <Shlobj.h>
+#endif
+
+using namespace comphelper;
+using namespace css::security;
+using namespace css::uno;
+using namespace css;
+
+namespace
+{
+ class SaveODFItem: public utl::ConfigItem
+ {
+ private:
+ sal_Int16 m_nODF;
+
+ virtual void ImplCommit() override;
+
+ public:
+ virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override;
+ SaveODFItem();
+ //See group ODF in Common.xcs
+ bool isLessODF1_2() const
+ {
+ return m_nODF < 3;
+ }
+ };
+
+ void SaveODFItem::ImplCommit() {}
+ void SaveODFItem::Notify( const css::uno::Sequence< OUString >& ) {}
+
+ SaveODFItem::SaveODFItem(): utl::ConfigItem("Office.Common/Save"), m_nODF(0)
+ {
+ OUString sDef("ODF/DefaultVersion");
+ Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) );
+ if ( aValues.getLength() != 1)
+ throw uno::RuntimeException(
+ "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion",
+ nullptr);
+
+ sal_Int16 nTmp = 0;
+ if ( !(aValues[0] >>= nTmp) )
+ throw uno::RuntimeException(
+ "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!",
+ nullptr );
+
+ m_nODF = nTmp;
+ }
+}
+
+DigitalSignaturesDialog::DigitalSignaturesDialog(
+ weld::Window* pParent,
+ const uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode,
+ bool bReadOnly, const OUString& sODFVersion, bool bHasDocumentSignature)
+ : GenericDialogController(pParent, "xmlsec/ui/digitalsignaturesdialog.ui", "DigitalSignaturesDialog")
+ , maSignatureManager(rxCtx, eMode)
+ , m_sODFVersion (sODFVersion)
+ , m_bHasDocumentSignature(bHasDocumentSignature)
+ , m_bWarningShowSignMacro(false)
+ , m_xHintDocFT(m_xBuilder->weld_label("dochint"))
+ , m_xHintBasicFT(m_xBuilder->weld_label("macrohint"))
+ , m_xHintPackageFT(m_xBuilder->weld_label("packagehint"))
+ , m_xSignaturesLB(m_xBuilder->weld_tree_view("signatures"))
+ , m_xSigsValidImg(m_xBuilder->weld_image("validimg"))
+ , m_xSigsValidFI(m_xBuilder->weld_label("validft"))
+ , m_xSigsInvalidImg(m_xBuilder->weld_image("invalidimg"))
+ , m_xSigsInvalidFI(m_xBuilder->weld_label("invalidft"))
+ , m_xSigsNotvalidatedImg(m_xBuilder->weld_image("notvalidatedimg"))
+ , m_xSigsNotvalidatedFI(m_xBuilder->weld_label("notvalidatedft"))
+ , m_xSigsOldSignatureImg(m_xBuilder->weld_image("oldsignatureimg"))
+ , m_xSigsOldSignatureFI(m_xBuilder->weld_label("oldsignatureft"))
+ , m_xAdESCompliantCB(m_xBuilder->weld_check_button("adescompliant"))
+ , m_xViewBtn(m_xBuilder->weld_button("view"))
+ , m_xAddBtn(m_xBuilder->weld_button("sign"))
+ , m_xRemoveBtn(m_xBuilder->weld_button("remove"))
+ , m_xStartCertMgrBtn(m_xBuilder->weld_button("start_certmanager"))
+ , m_xCloseBtn(m_xBuilder->weld_button("close"))
+{
+ m_bAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
+
+ auto nControlWidth = m_xSignaturesLB->get_approximate_digit_width() * 105;
+ m_xSignaturesLB->set_size_request(nControlWidth, m_xSignaturesLB->get_height_rows(10));
+
+ // Give the first column 6 percent, try to distribute the rest equally.
+ std::vector<int> aWidths;
+ aWidths.push_back(6*nControlWidth/100);
+ auto nColWidth = (nControlWidth - aWidths[0]) / 4;
+ aWidths.push_back(nColWidth);
+ aWidths.push_back(nColWidth);
+ aWidths.push_back(nColWidth);
+ m_xSignaturesLB->set_column_fixed_widths(aWidths);
+
+ mbVerifySignatures = true;
+ mbSignaturesChanged = false;
+
+ m_xSignaturesLB->connect_changed( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) );
+ m_xSignaturesLB->connect_row_activated( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );
+
+ m_xAdESCompliantCB->connect_toggled( LINK( this, DigitalSignaturesDialog, AdESCompliantCheckBoxHdl ) );
+ m_xAdESCompliantCB->set_active(m_bAdESCompliant);
+
+ m_xViewBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
+ m_xViewBtn->set_sensitive(false);
+
+ m_xAddBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) );
+ if ( bReadOnly )
+ m_xAddBtn->set_sensitive(false);
+
+ m_xRemoveBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) );
+ m_xRemoveBtn->set_sensitive(false);
+
+ m_xStartCertMgrBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, CertMgrButtonHdl ) );
+
+ m_xCloseBtn->connect_clicked( LINK( this, DigitalSignaturesDialog, OKButtonHdl) );
+
+ switch( maSignatureManager.getSignatureMode() )
+ {
+ case DocumentSignatureMode::Content:
+ m_xHintDocFT->show();
+ break;
+ case DocumentSignatureMode::Macros:
+ m_xHintBasicFT->show();
+ break;
+ case DocumentSignatureMode::Package:
+ m_xHintPackageFT->show();
+ break;
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ m_xAddBtn->hide();
+ m_xRemoveBtn->hide();
+ m_xStartCertMgrBtn->hide();
+ }
+}
+
+DigitalSignaturesDialog::~DigitalSignaturesDialog()
+{
+ if (m_xViewer)
+ m_xViewer->response(RET_OK);
+
+ if (m_xInfoBox)
+ m_xInfoBox->response(RET_OK);
+}
+
+bool DigitalSignaturesDialog::Init()
+{
+ bool bInit = maSignatureManager.init();
+
+ SAL_WARN_IF( !bInit, "xmlsecurity.dialogs", "Error initializing security context!" );
+
+ if ( bInit )
+ {
+ maSignatureManager.getSignatureHelper().SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) );
+ }
+
+ return bInit;
+}
+
+void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore )
+{
+ if (!rxStore.is())
+ {
+ // PDF supports AdES.
+ m_bAdESCompliant = true;
+ m_xAdESCompliantCB->set_active(m_bAdESCompliant);
+ return;
+ }
+
+ maSignatureManager.setStore(rxStore);
+ maSignatureManager.getSignatureHelper().SetStorage( maSignatureManager.getStore(), m_sODFVersion);
+}
+
+void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream )
+{
+ maSignatureManager.setSignatureStream(rxStream);
+}
+
+bool DigitalSignaturesDialog::canAddRemove()
+{
+ //FIXME: this func needs some cleanup, such as real split between
+ //'canAdd' and 'canRemove' case
+ bool ret = true;
+
+ uno::Reference<container::XNameAccess> xNameAccess = maSignatureManager.getStore();
+ if (xNameAccess.is() && xNameAccess->hasByName("[Content_Types].xml"))
+ // It's always possible to append an OOXML signature.
+ return ret;
+
+ if (!maSignatureManager.getStore().is())
+ // It's always possible to append a PDF signature.
+ return ret;
+
+ OSL_ASSERT(maSignatureManager.getStore().is());
+ bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
+ SaveODFItem item;
+ bool bSave1_1 = item.isLessODF1_2();
+
+ // see specification
+ //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw
+ //Paragraph 'Behavior with regard to ODF 1.2'
+ //For both, macro and document
+ if ( (!bSave1_1 && bDoc1_1) || (bSave1_1 && bDoc1_1) )
+ {
+ //#4
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT)));
+ xBox->run();
+ ret = false;
+ }
+
+ //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is
+ //adding a macro signature will break an existing document signature.
+ //The sfx2 will remove the documentsignature when the user adds a macro signature
+ if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Macros
+ && ret)
+ {
+ if (m_bHasDocumentSignature && !m_bWarningShowSignMacro)
+ {
+ //The warning says that the document signatures will be removed if the user
+ //continues. He can then either press 'OK' or 'NO'
+ //It the user presses 'Add' or 'Remove' several times then, then the warning
+ //is shown every time until the user presses 'OK'. From then on, the warning
+ //is not displayed anymore as long as the signatures dialog is alive.
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ XsResId(STR_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)));
+ if (xBox->run() == RET_NO)
+ ret = false;
+ else
+ m_bWarningShowSignMacro = true;
+
+ }
+ }
+ return ret;
+}
+
+bool DigitalSignaturesDialog::canAdd()
+{
+ return canAddRemove();
+}
+
+bool DigitalSignaturesDialog::canRemove()
+{
+ bool bRet = true;
+
+ if ( maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ XsResId(STR_XMLSECDLG_QUERY_REALLYREMOVE)));
+ short nDlgRet = xBox->run();
+ bRet = ( nDlgRet == RET_YES );
+ }
+
+ return (bRet && canAddRemove());
+}
+
+void DigitalSignaturesDialog::beforeRun()
+{
+ // Verify Signatures and add certificates to ListBox...
+ mbVerifySignatures = true;
+ ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true);
+ ImplFillSignaturesBox();
+
+ // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is
+ // enabled, set its initial state based on existing signatures, if any.
+
+ // If it is OOXML, the checkbox is irrelevant.
+
+ // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and
+ // check its nStorageFormat as that seems overly complicated and seems to have weird indirect
+ // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant()
+ // (which now is in #if 0).
+
+ if (!maSignatureManager.getCurrentSignatureInformations().empty())
+ {
+ // If the document has only SHA-1 signatures we probably want it to stay that way?
+ }
+
+ // Only verify once, content will not change.
+ // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
+ mbVerifySignatures = false;
+}
+
+short DigitalSignaturesDialog::run()
+{
+ beforeRun();
+ return GenericDialogController::run();
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureHighlightHdl, weld::TreeView&, void)
+{
+ bool bSel = m_xSignaturesLB->get_selected_index() != -1;
+ m_xViewBtn->set_sensitive( bSel );
+ if ( m_xAddBtn->get_sensitive() ) // not read only
+ m_xRemoveBtn->set_sensitive( bSel );
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, OKButtonHdl, weld::Button&, void)
+{
+ if (mbSignaturesChanged)
+ maSignatureManager.write(m_bAdESCompliant);
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, weld::TreeView&, bool)
+{
+ ImplShowSignaturesDetails();
+ return true;
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, AdESCompliantCheckBoxHdl, weld::Toggleable&, void)
+{
+ m_bAdESCompliant = m_xAdESCompliantCB->get_active();
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, weld::Button&, void)
+{
+ ImplShowSignaturesDetails();
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, weld::Button&, void)
+{
+ if( ! canAdd())
+ return;
+ try
+ {
+ std::vector<uno::Reference<xml::crypto::XXMLSecurityContext>> xSecContexts
+ {
+ maSignatureManager.getSecurityContext()
+ };
+ // Gpg signing is only possible with ODF >= 1.2 documents
+ if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.getStore(), m_sODFVersion))
+ xSecContexts.push_back(maSignatureManager.getGpgSecurityContext());
+
+ CertificateChooser aChooser(m_xDialog.get(), std::move(xSecContexts), UserAction::Sign);
+ if (aChooser.run() == RET_OK)
+ {
+ sal_Int32 nSecurityId;
+ if (!maSignatureManager.add(aChooser.GetSelectedCertificates()[0], aChooser.GetSelectedSecurityContext(),
+ aChooser.GetDescription(), nSecurityId, m_bAdESCompliant))
+ return;
+ mbSignaturesChanged = true;
+
+ xml::crypto::SecurityOperationStatus nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+
+ if (maSignatureManager.getStore().is())
+ // In the PDF case the signature information is only available after parsing.
+ nStatus = maSignatureManager.getSignatureHelper().GetSignatureInformation( nSecurityId ).nStatus;
+
+ if ( nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED )
+ {
+ mbSignaturesChanged = true;
+
+ // Can't simply remember current information, need parsing for getting full information :(
+ // We need to verify the signatures again, otherwise the status in the signature information
+ // will not contain
+ // SecurityOperationStatus_OPERATION_SUCCEEDED
+ mbVerifySignatures = true;
+ ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
+ ImplFillSignaturesBox();
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "adding a signature!" );
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Error, VclButtonsType::Ok,
+ XsResId(STR_XMLSECDLG_SIGNING_FAILED)));
+ xBox->run();
+ // Don't keep invalid entries...
+ ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
+ ImplFillSignaturesBox();
+ }
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, weld::Button&, void)
+{
+ if (!canRemove())
+ return;
+ int nEntry = m_xSignaturesLB->get_selected_index();
+ if (nEntry == -1)
+ return;
+
+ try
+ {
+ sal_uInt16 nSelected = m_xSignaturesLB->get_id(nEntry).toUInt32();
+ maSignatureManager.remove(nSelected);
+
+ mbSignaturesChanged = true;
+
+ ImplFillSignaturesBox();
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "Exception while removing a signature!" );
+ // Don't keep invalid entries...
+ ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true);
+ ImplFillSignaturesBox();
+ }
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, CertMgrButtonHdl, weld::Button&, void)
+{
+#ifdef _WIN32
+ // FIXME: call GpgME::dirInfo("bindir") somewhere in
+ // SecurityEnvironmentGpg or whatnot
+ // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful?
+ static const std::u16string_view aGUIServers[] = { u"Gpg4win\\kleopatra.exe",
+ u"Gpg4win\\bin\\kleopatra.exe",
+ u"GNU\\GnuPG\\kleopatra.exe",
+ u"GNU\\GnuPG\\launch-gpa.exe",
+ u"GNU\\GnuPG\\gpa.exe",
+ u"GnuPG\\bin\\gpa.exe",
+ u"GNU\\GnuPG\\bin\\kleopatra.exe",
+ u"GNU\\GnuPG\\bin\\launch-gpa.exe",
+ u"GNU\\GnuPG\\bin\\gpa.exe",
+ };
+ static const OUString aPath = [] {
+ OUString sRet;
+ PWSTR sPath = nullptr;
+ HRESULT hr
+ = SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, KF_FLAG_DEFAULT, nullptr, &sPath);
+ if (SUCCEEDED(hr))
+ {
+ sRet = o3tl::toU(sPath);
+ CoTaskMemFree(sPath);
+ }
+ return sRet;
+ }();
+ if (aPath.isEmpty())
+ return;
+#else
+ static const std::u16string_view aGUIServers[] = { u"kleopatra", u"seahorse", u"gpa", u"kgpg" };
+ const char* cPath = getenv("PATH");
+ if (!cPath)
+ return;
+ OUString aPath(cPath, strlen(cPath), osl_getThreadTextEncoding());
+#endif
+
+ OUString sFoundGUIServer, sExecutable;
+
+ for ( auto const &rServer : aGUIServers )
+ {
+ osl::FileBase::RC searchError = osl::File::searchFileURL(OUString(rServer), aPath, sFoundGUIServer );
+ if (searchError == osl::FileBase::E_None)
+ {
+ osl::File::getSystemPathFromFileURL( sFoundGUIServer, sExecutable );
+ break;
+ }
+
+ }
+
+ if ( !sExecutable.isEmpty() )
+ {
+ uno::Reference< uno::XComponentContext > xContext =
+ ::comphelper::getProcessComponentContext();
+ uno::Reference< css::system::XSystemShellExecute > xSystemShell(
+ css::system::SystemShellExecute::create(xContext) );
+
+ xSystemShell->execute( sExecutable, OUString(),
+ css::system::SystemShellExecuteFlags::DEFAULTS );
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ XsResId(STR_XMLSECDLG_NO_CERT_MANAGER)));
+ xInfoBox->run();
+ }
+}
+
+IMPL_LINK_NOARG(DigitalSignaturesDialog, StartVerifySignatureHdl, LinkParamNone*, bool)
+{
+ return mbVerifySignatures;
+}
+
+void DigitalSignaturesDialog::ImplFillSignaturesBox()
+{
+ m_xSignaturesLB->clear();
+
+ size_t nInfos = maSignatureManager.getCurrentSignatureInformations().size();
+ size_t nValidSigs = 0, nValidCerts = 0;
+ bool bAllNewSignatures = true;
+ bool bSomePartial = false;
+
+ if( nInfos )
+ {
+ for( size_t n = 0; n < nInfos; ++n )
+ {
+ DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
+ m_sODFVersion, maSignatureManager.getCurrentSignatureInformations()[n]);
+ std::vector< OUString > aElementsToBeVerified;
+ if (maSignatureManager.getStore().is())
+ aElementsToBeVerified = DocumentSignatureHelper::CreateElementList(maSignatureManager.getStore(), maSignatureManager.getSignatureMode(), mode);
+
+ const SignatureInformation& rInfo = maSignatureManager.getCurrentSignatureInformations()[n];
+ uno::Reference< css::security::XCertificate > xCert = getCertificate(rInfo);
+
+ OUString aSubject;
+ OUString aIssuer;
+ OUString aDateTimeStr;
+ OUString aDescription;
+ OUString aType;
+
+ bool bCertValid = false;
+ if( xCert.is() )
+ {
+ //check the validity of the cert
+ try {
+ sal_Int32 certResult = getSecurityEnvironmentForCertificate(xCert)->verifyCertificate(xCert,
+ Sequence<uno::Reference<security::XCertificate> >());
+
+ bCertValid = certResult == css::security::CertificateValidity::VALID;
+ if ( bCertValid )
+ nValidCerts++;
+
+ } catch (css::uno::SecurityException& ) {
+ OSL_FAIL("Verification of certificate failed");
+ bCertValid = false;
+ }
+
+ aSubject = xmlsec::GetContentPart( xCert->getSubjectName(), xCert->getCertificateKind() );
+ aIssuer = xmlsec::GetContentPart( xCert->getIssuerName(), xCert->getCertificateKind() );
+ }
+ else if (!rInfo.ouGpgCertificate.isEmpty())
+ {
+ // In case we don't have the gpg key locally, get some data from the document
+ aIssuer = rInfo.ouGpgOwner;
+ }
+
+ aDateTimeStr = utl::GetDateTimeString( rInfo.stDateTime );
+ aDescription = rInfo.ouDescription;
+
+ // Decide type string.
+ if (maSignatureManager.getStore().is())
+ {
+ // OpenPGP
+ if (!rInfo.ouGpgCertificate.isEmpty())
+ aType = "OpenPGP";
+ // XML based: XAdES or not.
+ else if (rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->CertDigest.isEmpty())
+ aType = "XAdES";
+ else
+ aType = "XML-DSig";
+ }
+ else
+ {
+ // Assume PDF: PAdES or not.
+ if (rInfo.bHasSigningCertificate)
+ aType = "PAdES";
+ else
+ aType = "PDF";
+ }
+
+ bool bSigValid = rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+
+ if ( bSigValid )
+ {
+ if (maSignatureManager.getStore().is())
+ {
+ // ZIP based.
+ bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
+ aElementsToBeVerified, rInfo, mode);
+ }
+ else
+ {
+ // Assume PDF.
+ bSigValid = !rInfo.bPartialDocumentSignature;
+ }
+
+ if( bSigValid )
+ nValidSigs++;
+ else
+ {
+ bSomePartial = true;
+ }
+ }
+
+ OUString sImage;
+ if (!bSigValid)
+ {
+ sImage = BMP_SIG_INVALID;
+ }
+ else if (!bCertValid)
+ {
+ sImage = BMP_SIG_NOT_VALIDATED;
+ }
+ //Check if the signature is a "old" document signature, that is, which was created
+ //by a version of OOo previous to 3.2
+ // If there is no storage, then it's pointless to check storage
+ // stream references.
+ else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content
+ && (maSignatureManager.getStore().is() && !DocumentSignatureHelper::isOOo3_2_Signature(
+ maSignatureManager.getCurrentSignatureInformations()[n])))
+ {
+ sImage = BMP_SIG_NOT_VALIDATED;
+ bAllNewSignatures = false;
+ }
+ else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Content
+ && DocumentSignatureHelper::isOOo3_2_Signature(
+ maSignatureManager.getCurrentSignatureInformations()[n]))
+ {
+ sImage = BMP_SIG_VALID;
+ }
+ else if (maSignatureManager.getSignatureMode() == DocumentSignatureMode::Macros)
+ {
+ sImage = BMP_SIG_VALID;
+ }
+
+ m_xSignaturesLB->insert(nullptr, n, nullptr, nullptr,
+ &sImage, nullptr, false, nullptr);
+ m_xSignaturesLB->set_text(n, aSubject, 1);
+ m_xSignaturesLB->set_text(n, aIssuer, 2);
+ m_xSignaturesLB->set_text(n, aDateTimeStr, 3);
+ m_xSignaturesLB->set_text(n, aDescription, 4);
+ m_xSignaturesLB->set_text(n, aType, 5);
+ m_xSignaturesLB->set_id(n, OUString::number(n)); // misuse user data as index
+ }
+ }
+
+ bool bAllSigsValid = (nValidSigs == nInfos);
+ bool bAllCertsValid = (nValidCerts == nInfos);
+ bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures);
+
+ m_xSigsValidImg->set_visible( bShowValidState);
+ m_xSigsValidFI->set_visible( bShowValidState );
+
+ bool bShowInvalidState = nInfos && !bAllSigsValid;
+
+ m_xSigsInvalidImg->set_visible( bShowInvalidState && !bSomePartial);
+ m_xSigsInvalidFI->set_visible( bShowInvalidState && !bSomePartial);
+
+ bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid;
+
+ m_xSigsNotvalidatedImg->set_visible(bShowNotValidatedState);
+ m_xSigsNotvalidatedFI->set_visible(bShowNotValidatedState);
+
+ //bAllNewSignatures is always true if we are not in document mode
+ bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures;
+ m_xSigsOldSignatureImg->set_visible(bShowOldSignature || bSomePartial);
+ m_xSigsOldSignatureFI->set_visible(bShowOldSignature || bSomePartial);
+
+ SignatureHighlightHdl(*m_xSignaturesLB);
+}
+
+uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(const SignatureInformation& rInfo)
+{
+ uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureManager.getSecurityEnvironment();
+ uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = maSignatureManager.getGpgSecurityEnvironment();
+ uno::Reference<security::XCertificate> xCert;
+
+ //First we try to get the certificate which is embedded in the XML Signature
+ if (xSecEnv.is() && rInfo.GetSigningCertificate() && !rInfo.GetSigningCertificate()->X509Certificate.isEmpty())
+ xCert = xSecEnv->createCertificateFromAscii(rInfo.GetSigningCertificate()->X509Certificate);
+ else {
+ //There must be an embedded certificate because we use it to get the
+ //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
+ //because it could be modified by an attacker. The issuer is displayed
+ //in the digital signature dialog.
+ //Comparing the X509IssuerName with the one from the X509Certificate in order
+ //to find out if the X509IssuerName was modified does not work. See #i62684
+ SAL_WARN( "xmlsecurity.dialogs", "Could not find embedded certificate!");
+ }
+
+ //In case there is no embedded certificate we try to get it from a local store
+ if (!xCert.is() && xSecEnv.is() && rInfo.GetSigningCertificate())
+ {
+ xCert = xSecEnv->getCertificate(rInfo.GetSigningCertificate()->X509IssuerName,
+ xmlsecurity::numericStringToBigInteger(rInfo.GetSigningCertificate()->X509SerialNumber));
+ }
+ if (!xCert.is() && xGpgSecEnv.is() && !rInfo.ouGpgKeyID.isEmpty())
+ xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger(u"") );
+
+ SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );
+
+ return xCert;
+}
+
+uno::Reference<xml::crypto::XSecurityEnvironment> DigitalSignaturesDialog::getSecurityEnvironmentForCertificate(const uno::Reference<security::XCertificate>& xCert)
+{
+ if (xCert->getCertificateKind() == CertificateKind_OPENPGP)
+ return maSignatureManager.getGpgSecurityEnvironment();
+ else if (xCert->getCertificateKind() == CertificateKind_X509)
+ return maSignatureManager.getSecurityEnvironment();
+
+ throw RuntimeException("Unknown certificate kind");
+}
+
+//If bUseTempStream is true then the temporary signature stream is used.
+//Otherwise the real signature stream is used.
+void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature)
+{
+ maSignatureManager.read(bUseTempStream, bCacheLastSignature);
+ mbVerifySignatures = false;
+}
+
+void DigitalSignaturesDialog::ImplShowSignaturesDetails()
+{
+ int nEntry = m_xSignaturesLB->get_selected_index();
+ if (nEntry == -1)
+ return;
+
+ sal_uInt16 nSelected = m_xSignaturesLB->get_id(nEntry).toUInt32();
+ const SignatureInformation& rInfo = maSignatureManager.getCurrentSignatureInformations()[ nSelected ];
+ uno::Reference<security::XCertificate> xCert = getCertificate(rInfo);
+
+ if ( xCert.is() )
+ {
+ if (m_xViewer)
+ m_xViewer->response(RET_OK);
+
+ uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = getSecurityEnvironmentForCertificate(xCert);
+ m_xViewer = std::make_shared<CertificateViewer>(m_xDialog.get(), xSecEnv, xCert, false, nullptr);
+ weld::DialogController::runAsync(m_xViewer, [this] (sal_Int32) { m_xViewer = nullptr; });
+ }
+ else
+ {
+ if (m_xInfoBox)
+ m_xInfoBox->response(RET_OK);
+
+ m_xInfoBox = std::shared_ptr<weld::MessageDialog>(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ XsResId(STR_XMLSECDLG_NO_CERT_FOUND)));
+ m_xInfoBox->runAsync(m_xInfoBox, [this] (sal_Int32) { m_xInfoBox = nullptr; });
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/dialogs/macrosecurity.cxx b/xmlsecurity/source/dialogs/macrosecurity.cxx
new file mode 100644
index 000000000..bf82606f4
--- /dev/null
+++ b/xmlsecurity/source/dialogs/macrosecurity.cxx
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <macrosecurity.hxx>
+#include <certificateviewer.hxx>
+#include <biginteger.hxx>
+#include <resourcemanager.hxx>
+#include <strings.hrc>
+
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <sfx2/filedlghelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <unotools/datetime.hxx>
+
+#include <vcl/svapp.hxx>
+
+using namespace comphelper;
+using namespace ::com::sun::star;
+
+
+IMPL_LINK_NOARG(MacroSecurity, OkBtnHdl, weld::Button&, void)
+{
+ m_xLevelTP->ClosePage();
+ m_xTrustSrcTP->ClosePage();
+ m_xDialog->response(RET_OK);
+}
+
+MacroSecurity::MacroSecurity(weld::Window* pParent,
+ const css::uno::Reference<css::xml::crypto::XSecurityEnvironment>& rxSecurityEnvironment)
+ : GenericDialogController(pParent, "xmlsec/ui/macrosecuritydialog.ui", "MacroSecurityDialog")
+ , m_xSecurityEnvironment(rxSecurityEnvironment)
+ , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_xResetBtn(m_xBuilder->weld_button("reset"))
+{
+ m_xTabCtrl->connect_enter_page(LINK(this, MacroSecurity, ActivatePageHdl));
+
+ m_xLevelTP.reset(new MacroSecurityLevelTP(m_xTabCtrl->get_page("SecurityLevelPage"), this));
+ m_xTrustSrcTP.reset(new MacroSecurityTrustedSourcesTP(m_xTabCtrl->get_page("SecurityTrustPage"), this));
+
+ m_xTabCtrl->set_current_page("SecurityLevelPage");
+ m_xOkBtn->connect_clicked(LINK(this, MacroSecurity, OkBtnHdl));
+}
+
+IMPL_LINK(MacroSecurity, ActivatePageHdl, const OString&, rPage, void)
+{
+ if (rPage == "SecurityLevelPage")
+ m_xLevelTP->ActivatePage();
+ else if (rPage == "SecurityTrustPage")
+ m_xTrustSrcTP->ActivatePage();
+}
+
+MacroSecurityTP::MacroSecurityTP(weld::Container* pParent, const OUString& rUIXMLDescription,
+ const OString& rID, MacroSecurity* pDlg)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+ , m_pDlg(pDlg)
+{
+}
+
+void MacroSecurityTP::ActivatePage()
+{
+}
+
+MacroSecurityTP::~MacroSecurityTP()
+{
+}
+
+MacroSecurityLevelTP::MacroSecurityLevelTP(weld::Container* pParent, MacroSecurity* pDlg)
+ : MacroSecurityTP(pParent, "xmlsec/ui/securitylevelpage.ui", "SecurityLevelPage", pDlg)
+ , m_xVeryHighRB(m_xBuilder->weld_radio_button("vhigh"))
+ , m_xHighRB(m_xBuilder->weld_radio_button("high"))
+ , m_xMediumRB(m_xBuilder->weld_radio_button("med"))
+ , m_xLowRB(m_xBuilder->weld_radio_button("low"))
+ , m_xVHighImg(m_xBuilder->weld_widget("vhighimg"))
+ , m_xHighImg(m_xBuilder->weld_widget("highimg"))
+ , m_xMedImg(m_xBuilder->weld_widget("medimg"))
+ , m_xLowImg(m_xBuilder->weld_widget("lowimg"))
+{
+ m_xLowRB->connect_toggled( LINK( this, MacroSecurityLevelTP, RadioButtonHdl ) );
+ m_xMediumRB->connect_toggled( LINK( this, MacroSecurityLevelTP, RadioButtonHdl ) );
+ m_xHighRB->connect_toggled( LINK( this, MacroSecurityLevelTP, RadioButtonHdl ) );
+ m_xVeryHighRB->connect_toggled( LINK( this, MacroSecurityLevelTP, RadioButtonHdl ) );
+
+ int nPrefWidth(std::max({m_xVeryHighRB->get_preferred_size().Width(),
+ m_xHighRB->get_preferred_size().Width(),
+ m_xMediumRB->get_preferred_size().Width(),
+ m_xLowRB->get_preferred_size().Width()}));
+ int nMaxWidth = m_xLowRB->get_approximate_digit_width() * 60;
+ if (nPrefWidth > nMaxWidth)
+ {
+ m_xLowRB->set_label_wrap(true);
+ m_xLowRB->set_size_request(nMaxWidth, -1);
+ m_xMediumRB->set_label_wrap(true);
+ m_xMediumRB->set_size_request(nMaxWidth, -1);
+ m_xHighRB->set_label_wrap(true);
+ m_xHighRB->set_size_request(nMaxWidth, -1);
+ m_xVeryHighRB->set_label_wrap(true);
+ m_xVeryHighRB->set_size_request(nMaxWidth, -1);
+ }
+
+ mnCurLevel = static_cast<sal_uInt16>(SvtSecurityOptions::GetMacroSecurityLevel());
+ bool bReadonly = SvtSecurityOptions::IsReadOnly( SvtSecurityOptions::EOption::MacroSecLevel );
+
+ weld::RadioButton* pCheck = nullptr;
+ weld::Widget* pImage = nullptr;
+ switch (mnCurLevel)
+ {
+ case 3:
+ pCheck = m_xVeryHighRB.get();
+ pImage = m_xVHighImg.get();
+ break;
+ case 2:
+ pCheck = m_xHighRB.get();
+ pImage = m_xHighImg.get();
+ break;
+ case 1:
+ pCheck = m_xMediumRB.get();
+ pImage = m_xMedImg.get();
+ break;
+ case 0:
+ pCheck = m_xLowRB.get();
+ pImage = m_xLowImg.get();
+ break;
+ }
+ if (pCheck)
+ pCheck->set_active(true);
+ else
+ {
+ OSL_FAIL("illegal macro security level");
+ }
+ if (bReadonly && pImage)
+ {
+ pImage->show();
+ m_xVeryHighRB->set_sensitive(false);
+ m_xHighRB->set_sensitive(false);
+ m_xMediumRB->set_sensitive(false);
+ m_xLowRB->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(MacroSecurityLevelTP, RadioButtonHdl, weld::Toggleable&, void)
+{
+ sal_uInt16 nNewLevel = 0;
+ if( m_xVeryHighRB->get_active() )
+ nNewLevel = 3;
+ else if( m_xHighRB->get_active() )
+ nNewLevel = 2;
+ else if( m_xMediumRB->get_active() )
+ nNewLevel = 1;
+
+ if ( nNewLevel != mnCurLevel )
+ {
+ mnCurLevel = nNewLevel;
+ m_pDlg->EnableReset();
+ }
+}
+
+void MacroSecurityLevelTP::ClosePage()
+{
+ SvtSecurityOptions::SetMacroSecurityLevel( mnCurLevel );
+}
+
+void MacroSecurityTrustedSourcesTP::ImplCheckButtons()
+{
+ bool bCertSelected = m_xTrustCertLB->get_selected_index() != -1;
+ m_xViewCertPB->set_sensitive( bCertSelected );
+ m_xRemoveCertPB->set_sensitive( bCertSelected && !mbAuthorsReadonly);
+
+ bool bLocationSelected = m_xTrustFileLocLB->get_selected_index() != -1;
+ m_xRemoveLocPB->set_sensitive( bLocationSelected && !mbURLsReadonly);
+}
+
+void MacroSecurityTrustedSourcesTP::ShowBrokenCertificateError(std::u16string_view rData)
+{
+ OUString aMsg = XsResId(STR_BROKEN_MACRO_CERTIFICATE_DATA);
+ aMsg = aMsg.replaceFirst("%{data}", rData);
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDlg->getDialog(),
+ VclMessageType::Error, VclButtonsType::Ok, aMsg));
+ xErrorBox->run();
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, ViewCertPBHdl, weld::Button&, void)
+{
+ int nEntry = m_xTrustCertLB->get_selected_index();
+ if (nEntry == -1)
+ return;
+
+ const sal_uInt16 nSelected = m_xTrustCertLB->get_id(nEntry).toUInt32();
+ uno::Reference< css::security::XCertificate > xCert;
+ try
+ {
+ xCert = m_pDlg->m_xSecurityEnvironment->getCertificate(m_aTrustedAuthors[nSelected].SubjectName,
+ xmlsecurity::numericStringToBigInteger(m_aTrustedAuthors[nSelected].SerialNumber));
+ }
+ catch (...)
+ {
+ TOOLS_WARN_EXCEPTION("xmlsecurity.dialogs", "matching certificate not found for: " << m_aTrustedAuthors[nSelected].SubjectName);
+ }
+
+ if (!xCert.is())
+ {
+ try
+ {
+ xCert = m_pDlg->m_xSecurityEnvironment->createCertificateFromAscii(m_aTrustedAuthors[nSelected].RawData);
+ }
+ catch (...)
+ {
+ TOOLS_WARN_EXCEPTION("xmlsecurity.dialogs", "certificate data couldn't be parsed: " << m_aTrustedAuthors[nSelected].RawData);
+ }
+ }
+
+ if ( xCert.is() )
+ {
+ CertificateViewer aViewer(m_pDlg->getDialog(), m_pDlg->m_xSecurityEnvironment, xCert, false, nullptr);
+ aViewer.run();
+ }
+ else
+ // should never happen, as we parsed the certificate data when we added it!
+ ShowBrokenCertificateError(m_aTrustedAuthors[nSelected].RawData);
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, RemoveCertPBHdl, weld::Button&, void)
+{
+ int nEntry = m_xTrustCertLB->get_selected_index();
+ if (nEntry != -1)
+ {
+ sal_uInt16 nAuthor = m_xTrustCertLB->get_id(nEntry).toUInt32();
+ m_aTrustedAuthors.erase(m_aTrustedAuthors.begin() + nAuthor);
+
+ FillCertLB();
+ ImplCheckButtons();
+ }
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, AddLocPBHdl, weld::Button&, void)
+{
+ try
+ {
+ uno::Reference < uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference < ui::dialogs::XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(xContext, m_pDlg->getDialog());
+
+ short nRet = xFolderPicker->execute();
+
+ if( ui::dialogs::ExecutableDialogResults::OK != nRet )
+ return;
+
+ OUString aPathStr = xFolderPicker->getDirectory();
+ INetURLObject aNewObj( aPathStr );
+ aNewObj.removeFinalSlash();
+
+ // then the new path also a URL else system path
+ OUString aSystemFileURL = ( aNewObj.GetProtocol() != INetProtocol::NotValid ) ?
+ aPathStr : aNewObj.getFSysPath( FSysStyle::Detect );
+
+ OUString aNewPathStr(aSystemFileURL);
+
+ if ( osl::FileBase::getSystemPathFromFileURL( aSystemFileURL, aSystemFileURL ) == osl::FileBase::E_None )
+ aNewPathStr = aSystemFileURL;
+
+ if (m_xTrustFileLocLB->find_text(aNewPathStr) == -1)
+ m_xTrustFileLocLB->append_text(aNewPathStr);
+
+ ImplCheckButtons();
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "xmlsecurity.dialogs", "MacroSecurityTrustedSourcesTP::AddLocPBHdl(): exception from folder picker" );
+ }
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, RemoveLocPBHdl, weld::Button&, void)
+{
+ sal_Int32 nSel = m_xTrustFileLocLB->get_selected_index();
+ if (nSel == -1)
+ return;
+
+ m_xTrustFileLocLB->remove(nSel);
+ // Trusted Path could not be removed (#i33584#)
+ // after remove an entry, select another one if exists
+ int nNewCount = m_xTrustFileLocLB->n_children();
+ if (nNewCount > 0)
+ {
+ if (nSel >= nNewCount)
+ nSel = nNewCount - 1;
+ m_xTrustFileLocLB->select(nSel);
+ }
+ ImplCheckButtons();
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, TrustCertLBSelectHdl, weld::TreeView&, void)
+{
+ ImplCheckButtons();
+}
+
+IMPL_LINK_NOARG(MacroSecurityTrustedSourcesTP, TrustFileLocLBSelectHdl, weld::TreeView&, void)
+{
+ ImplCheckButtons();
+}
+
+void MacroSecurityTrustedSourcesTP::FillCertLB(const bool bShowWarnings)
+{
+ m_xTrustCertLB->clear();
+
+ sal_uInt32 nEntries = m_aTrustedAuthors.size();
+
+ if ( !(nEntries && m_pDlg->m_xSecurityEnvironment.is()) )
+ return;
+
+ for( sal_uInt32 nEntry = 0 ; nEntry < nEntries ; ++nEntry )
+ {
+ SvtSecurityOptions::Certificate& rEntry = m_aTrustedAuthors[ nEntry ];
+
+ try
+ {
+ // create from RawData
+ uno::Reference< css::security::XCertificate > xCert = m_pDlg->m_xSecurityEnvironment->createCertificateFromAscii(rEntry.RawData);
+ m_xTrustCertLB->append(OUString::number(nEntry), xmlsec::GetContentPart(xCert->getSubjectName(), xCert->getCertificateKind()));
+ m_xTrustCertLB->set_text(nEntry, xmlsec::GetContentPart(xCert->getIssuerName(), xCert->getCertificateKind()), 1);
+ m_xTrustCertLB->set_text(nEntry, utl::GetDateTimeString(xCert->getNotValidAfter()), 2);
+ }
+ catch (...)
+ {
+ if (bShowWarnings)
+ {
+ TOOLS_WARN_EXCEPTION("xmlsecurity.dialogs", "certificate data couldn't be parsed: " << rEntry.RawData);
+ OUString sData = rEntry.RawData;
+ css::uno::Any tools_warn_exception(DbgGetCaughtException());
+ OUString sException = OStringToOUString(exceptionToString(tools_warn_exception), RTL_TEXTENCODING_UTF8);
+ if (!sException.isEmpty())
+ sData += " / " + sException;
+ ShowBrokenCertificateError(sData);
+ }
+ }
+ }
+}
+
+MacroSecurityTrustedSourcesTP::MacroSecurityTrustedSourcesTP(weld::Container* pParent, MacroSecurity* pDlg)
+ : MacroSecurityTP(pParent, "xmlsec/ui/securitytrustpage.ui", "SecurityTrustPage", pDlg)
+ , m_xTrustCertROFI(m_xBuilder->weld_image("lockcertimg"))
+ , m_xTrustCertLB(m_xBuilder->weld_tree_view("certificates"))
+ , m_xViewCertPB(m_xBuilder->weld_button("viewcert"))
+ , m_xRemoveCertPB(m_xBuilder->weld_button("removecert"))
+ , m_xTrustFileROFI(m_xBuilder->weld_image("lockfileimg"))
+ , m_xTrustFileLocLB(m_xBuilder->weld_tree_view("locations"))
+ , m_xAddLocPB(m_xBuilder->weld_button("addfile"))
+ , m_xRemoveLocPB(m_xBuilder->weld_button("removefile"))
+{
+ auto nColWidth = m_xTrustCertLB->get_approximate_digit_width() * 12;
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nColWidth * 2),
+ o3tl::narrowing<int>(nColWidth * 2)
+ };
+ m_xTrustCertLB->set_column_fixed_widths(aWidths);
+ m_xTrustCertLB->set_size_request(nColWidth * 5.5, m_xTrustCertLB->get_height_rows(5));
+
+ m_xTrustCertLB->connect_changed( LINK( this, MacroSecurityTrustedSourcesTP, TrustCertLBSelectHdl ) );
+ m_xViewCertPB->connect_clicked( LINK( this, MacroSecurityTrustedSourcesTP, ViewCertPBHdl ) );
+ m_xViewCertPB->set_sensitive(false);
+ m_xRemoveCertPB->connect_clicked( LINK( this, MacroSecurityTrustedSourcesTP, RemoveCertPBHdl ) );
+ m_xRemoveCertPB->set_sensitive(false);
+
+ m_xTrustFileLocLB->connect_changed( LINK( this, MacroSecurityTrustedSourcesTP, TrustFileLocLBSelectHdl ) );
+ m_xTrustFileLocLB->set_size_request(nColWidth * 5, m_xTrustFileLocLB->get_height_rows(5));
+ m_xAddLocPB->connect_clicked( LINK( this, MacroSecurityTrustedSourcesTP, AddLocPBHdl ) );
+ m_xRemoveLocPB->connect_clicked( LINK( this, MacroSecurityTrustedSourcesTP, RemoveLocPBHdl ) );
+ m_xRemoveLocPB->set_sensitive(false);
+
+ m_aTrustedAuthors = SvtSecurityOptions::GetTrustedAuthors();
+ mbAuthorsReadonly = SvtSecurityOptions::IsReadOnly( SvtSecurityOptions::EOption::MacroTrustedAuthors );
+ m_xTrustCertROFI->set_visible(mbAuthorsReadonly);
+
+ FillCertLB(true);
+
+ std::vector< OUString > aSecureURLs = SvtSecurityOptions::GetSecureURLs();
+ mbURLsReadonly = SvtSecurityOptions::IsReadOnly( SvtSecurityOptions::EOption::SecureUrls );
+ m_xTrustFileROFI->set_visible(mbURLsReadonly);
+ m_xAddLocPB->set_sensitive(!mbURLsReadonly);
+
+ for (const auto& rSecureURL : aSecureURLs)
+ {
+ OUString aSystemFileURL( rSecureURL );
+ osl::FileBase::getSystemPathFromFileURL( aSystemFileURL, aSystemFileURL );
+ m_xTrustFileLocLB->append_text(aSystemFileURL);
+ }
+}
+
+void MacroSecurityTrustedSourcesTP::ActivatePage()
+{
+ m_pDlg->EnableReset( false );
+ FillCertLB();
+}
+
+void MacroSecurityTrustedSourcesTP::ClosePage()
+{
+ sal_Int32 nEntryCnt = m_xTrustFileLocLB->n_children();
+ if( nEntryCnt )
+ {
+ std::vector< OUString > aSecureURLs;
+ for (sal_Int32 i = 0; i < nEntryCnt; ++i)
+ {
+ OUString aURL(m_xTrustFileLocLB->get_text(i));
+ osl::FileBase::getFileURLFromSystemPath( aURL, aURL );
+ aSecureURLs.push_back(aURL);
+ }
+
+ SvtSecurityOptions::SetSecureURLs( std::move(aSecureURLs) );
+ }
+ // Trusted Path could not be removed (#i33584#)
+ // don't forget to remove the old saved SecureURLs
+ else
+ SvtSecurityOptions::SetSecureURLs( std::vector< OUString >() );
+
+ SvtSecurityOptions::SetTrustedAuthors( m_aTrustedAuthors );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */