cool#10630 doc electronic sign: fix insertion of the signature line

Have electronic signing configured in the LOK client, try to insert a
signature line, you'll get a certificate picker, while we don't have a
cert during esign.

What's in fact needed for creating the signature line is just a name
(previously extracted from the certificate), we can survive the lack of
actual certificate.

Fix the problem by adding a new External parameter to
.uno:InsertSignatureLine to hint that the certificate chooser should not
be opened, instead the editor name (used for comments already) should be
used. Add a new CertificateOrName in svl/ and use that in all places
where previously we wanted a certificate but in fact it's enough to have
a certificate or a name to create the signature line.

The name on the signature line is just visual feedback, the actual name
on the crypto signature is still not based on untrusted used input.

Change-Id: Ib7008112a8e28a9e7d9649745e6021dd6b6b9c39
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180193
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
Miklos Vajna
2025-01-13 17:53:43 +01:00
parent fe1a096573
commit 7d4222d008
19 changed files with 128 additions and 43 deletions
@@ -163,8 +163,10 @@ IMPL_LINK_NOARG(SignSignatureLineDialog, chooseCertificate, weld::Button&, void)
if (xSignCertificate.is())
{
m_xSelectedCertifate = xSignCertificate;
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = xSignCertificate;
m_xBtnChooseCertificate->set_label(
svx::SignatureLineHelper::getSignerName(xSignCertificate));
svx::SignatureLineHelper::getSignerName(aCertificateOrName));
}
ValidateFields();
}
@@ -210,9 +212,11 @@ css::uno::Reference<css::graphic::XGraphic> SignSignatureLineDialog::getSignedGr
aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", getCDataString(m_aSuggestedSignerName));
aSvgImage = aSvgImage.replaceAll("[SIGNER_TITLE]", getCDataString(m_aSuggestedSignerTitle));
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = m_xSelectedCertifate;
OUString aIssuerLine
= CuiResId(RID_CUISTR_SIGNATURELINE_SIGNED_BY)
.replaceFirst("%1", svx::SignatureLineHelper::getSignerName(m_xSelectedCertifate));
.replaceFirst("%1", svx::SignatureLineHelper::getSignerName(aCertificateOrName));
aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", getCDataString(aIssuerLine));
if (bValid)
aSvgImage = aSvgImage.replaceAll("[INVALID_SIGNATURE]", "");
+3 -1
View File
@@ -4744,7 +4744,9 @@ static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
uno::Reference<security::XCertificate> xCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
if (SfxViewShell* pViewShell = SfxViewShell::Current())
{
pViewShell->SetSigningCertificate(xCertificate);
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = xCertificate;
pViewShell->SetSigningCertificate(aCertificateOrName);
}
}
+3 -2
View File
@@ -72,6 +72,7 @@ namespace com::sun::star::ui { struct ContextMenuExecuteEvent; }
namespace com::sun::star::view { class XRenderable; }
namespace com::sun::star::security { class XCertificate; }
namespace svtools { enum ColorConfigEntry : int; }
namespace svl::crypto { class CertificateOrName; }
enum class SfxPrinterChangeFlags
{
@@ -492,8 +493,8 @@ public:
OUString getA11yFocusedParagraph() const;
int getA11yCaretPosition() const;
void SetSigningCertificate(const css::uno::Reference<css::security::XCertificate>& xCertificate);
const css::uno::Reference<css::security::XCertificate> & GetSigningCertificate() const;
void SetSigningCertificate(const svl::crypto::CertificateOrName& rCertificateOrName);
svl::crypto::CertificateOrName GetSigningCertificate() const;
};
#endif // INCLUDED_SFX2_VIEWSH_HXX
+13
View File
@@ -7,6 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <sal/types.h>
#include <utility>
@@ -116,6 +118,17 @@ public:
std::vector<unsigned char> m_aSignatureValue;
};
/// Used for visual signing: an XCertificate or a signer name.
class SVL_DLLPUBLIC CertificateOrName
{
public:
/// If set, the certificate used for signing.
css::uno::Reference<css::security::XCertificate> m_xCertificate;
/// Otherwise we don't have a certificate but have a name to be featured on the visual
/// signature.
OUString m_aName;
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+4 -5
View File
@@ -16,6 +16,7 @@
#include <rtl/ustring.hxx>
#include <svx/svxdllapi.h>
#include <svl/cryptosign.hxx>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/security/XCertificate.hpp>
@@ -45,8 +46,7 @@ getSignatureCertificate(SfxObjectShell* pShell, SfxViewShell* pViewShell, weld::
/**
* Get a signer name out of a certificate.
*/
SVX_DLLPUBLIC OUString
getSignerName(const css::uno::Reference<css::security::XCertificate>& xCertificate);
SVX_DLLPUBLIC OUString getSignerName(const svl::crypto::CertificateOrName& rCertificateOrName);
/**
* Gets a localized date string.
@@ -61,9 +61,8 @@ SVX_DLLPUBLIC css::uno::Reference<css::graphic::XGraphic> importSVG(std::u16stri
/**
* Sets xCertificate as the signing certificate of the selected shape on pView.
*/
SVX_DLLPUBLIC void
setShapeCertificate(const SdrView* pView,
const css::uno::Reference<css::security::XCertificate>& xCertificate);
SVX_DLLPUBLIC void setShapeCertificate(const SdrView* pView,
const svl::crypto::CertificateOrName& rCertificateOrName);
}
#endif
Binary file not shown.
@@ -11,6 +11,11 @@
#include <sfx2/sidebar/Sidebar.hxx>
#include <vcl/scheduler.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSidebarSwitchDeck)
{
@@ -36,6 +41,33 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSidebarSwitchDeck)
CPPUNIT_ASSERT(it != aView.m_aStateChanges.end());
}
CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testInsertSignatureLineExternal)
{
// Given a PDF to be signed:
uno::Sequence<beans::PropertyValue> aArgs = { comphelper::makePropertyValue("ReadOnly", true) };
loadWithParams(createFileURL(u"empty.pdf"), aArgs);
SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
sd::View* pView = pViewShell->GetView();
pView->SetAuthor("myauthor");
// When insrerting a signature line for electronic (extrenal) signing:
aArgs = {
comphelper::makePropertyValue("External", true),
};
// Without the accompanying fix in place, this test would hang here in the certificate chooser
// dialog.
dispatchCommand(mxComponent, ".uno:InsertSignatureLine", aArgs);
// Then make sure the shape is marked as a signature line:
std::vector<SdrObject*> aMarkedObjects = pView->GetMarkedObjects();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMarkedObjects.size());
uno::Any aAny;
aMarkedObjects[0]->GetGrabBagItem(aAny);
comphelper::SequenceAsHashMap aMap(aAny);
CPPUNIT_ASSERT(aMap.contains("SignatureCertificate"));
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+10 -7
View File
@@ -512,16 +512,19 @@ void FuConstructRectangle::Deactivate()
return;
}
uno::Reference<security::XCertificate> xCertificate
= svx::SignatureLineHelper::getSignatureCertificate(mpViewShell->GetObjectShell(),
mpViewShell->GetViewShell(),
mpViewShell->GetFrameWeld());
if (!xCertificate.is())
svl::crypto::CertificateOrName aCertificateOrName = mpViewShell->GetViewShell()->GetSigningCertificate();
if (aCertificateOrName.m_aName.isEmpty())
{
return;
aCertificateOrName.m_xCertificate = svx::SignatureLineHelper::getSignatureCertificate(
mpViewShell->GetObjectShell(), mpViewShell->GetViewShell(),
mpViewShell->GetFrameWeld());
if (!aCertificateOrName.m_xCertificate.is())
{
return;
}
}
svx::SignatureLineHelper::setShapeCertificate(mpView, xCertificate);
svx::SignatureLineHelper::setShapeCertificate(mpView, aCertificateOrName);
// Update infobar to offer "finish signing".
SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
+14 -3
View File
@@ -61,6 +61,7 @@
#include <sfx2/docfile.hxx>
#include <sfx2/notebookbar/SfxNotebookBar.hxx>
#include <osl/diagnose.h>
#include <svl/cryptosign.hxx>
#include <DrawViewShell.hxx>
#include <slideshow.hxx>
@@ -471,18 +472,28 @@ void DrawViewShell::FuPermanent(SfxRequest& rReq)
{
aSignatureKey = pSignatureKey->GetValue().toUtf8();
}
bool bExternal = false;
const SfxBoolItem* pExternal = rReq.GetArg<SfxBoolItem>(FN_PARAM_3);
if (pExternal)
{
bExternal = pExternal->GetValue();
}
SfxViewFrame* pFrame = GetFrame();
SfxViewShell* pViewShell = pFrame ? pFrame->GetViewShell() : nullptr;
if (pViewShell)
{
uno::Reference<security::XCertificate> xSigningCertificate;
svl::crypto::CertificateOrName aCertificateOrName;
if (!aSignatureCert.empty() && !aSignatureKey.empty())
{
xSigningCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
aCertificateOrName.m_xCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
}
else if (bExternal)
{
aCertificateOrName.m_aName = mpDrawView->GetAuthor();
}
// Always set the signing certificate, to clear data from a previous dispatch.
pViewShell->SetSigningCertificate(xSigningCertificate);
pViewShell->SetSigningCertificate(aCertificateOrName);
}
}
+3 -3
View File
@@ -665,13 +665,13 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
SfxViewShell* pViewShell = pFrame ? pFrame->GetViewShell() : nullptr;
if (pViewShell)
{
uno::Reference<security::XCertificate> xSigningCertificate;
svl::crypto::CertificateOrName aCertificateOrName;
if (!aSignatureCert.empty() && !aSignatureKey.empty())
{
xSigningCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
aCertificateOrName.m_xCertificate = SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
}
// Always set the signing certificate, to clear data from a previous dispatch.
pViewShell->SetSigningCertificate(xSigningCertificate);
pViewShell->SetSigningCertificate(aCertificateOrName);
}
// Async, all code before return has to go into the callback.
+2 -1
View File
@@ -28,6 +28,7 @@
#include <svtools/acceleratorexecute.hxx>
#include <rtl/ref.hxx>
#include <vcl/print.hxx>
#include <svl/cryptosign.hxx>
#include <chrono>
#include <vector>
@@ -59,7 +60,7 @@ struct SfxViewShell_Impl
static sal_uInt32 m_nLastViewShellId;
const ViewShellId m_nViewShellId;
const ViewShellDocId m_nDocId;
css::uno::Reference<css::security::XCertificate> m_xSigningCertificate;
svl::crypto::CertificateOrName m_aSigningCertificate;
explicit SfxViewShell_Impl(SfxViewShellFlags const nFlags, ViewShellDocId nDocId);
~SfxViewShell_Impl();
+4 -4
View File
@@ -2807,14 +2807,14 @@ int SfxViewShell::getA11yCaretPosition() const
return rDocFocusListener.getCaretPosition();
}
void SfxViewShell::SetSigningCertificate(const uno::Reference<security::XCertificate>& xCertificate)
void SfxViewShell::SetSigningCertificate(const svl::crypto::CertificateOrName& rCertificate)
{
pImpl->m_xSigningCertificate = xCertificate;
pImpl->m_aSigningCertificate = rCertificate;
}
const uno::Reference<security::XCertificate> & SfxViewShell::GetSigningCertificate() const
svl::crypto::CertificateOrName SfxViewShell::GetSigningCertificate() const
{
return pImpl->m_xSigningCertificate;
return pImpl->m_aSigningCertificate;
}
bool SfxViewShell::PrepareClose
+3 -1
View File
@@ -863,7 +863,9 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testVisualSignResize)
return;
}
SdrView* pView = SfxViewShell::Current()->GetDrawView();
svx::SignatureLineHelper::setShapeCertificate(pView, xCert);
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = xCert;
svx::SignatureLineHelper::setShapeCertificate(pView, aCertificateOrName);
pObjectShell->SetModified(false);
// When resizing the shape by moving the bottom right (last) handle towards top right:
+1 -1
View File
@@ -12416,7 +12416,7 @@ SfxVoidItem AnchorMenu SID_ANCHOR_MENU
]
SfxVoidItem InsertSignatureLine SID_INSERT_SIGNATURELINE
(SfxStringItem SignatureCert FN_PARAM_1, SfxStringItem SignatureKey FN_PARAM_2)
(SfxStringItem SignatureCert FN_PARAM_1, SfxStringItem SignatureKey FN_PARAM_2, SfxBoolItem External FN_PARAM_3)
[
AutoUpdate = FALSE,
FastCall = FALSE,
+20 -8
View File
@@ -99,10 +99,16 @@ getSignatureCertificate(SfxObjectShell* pShell, SfxViewShell* pViewShell, weld::
return xSignCertificate;
}
OUString getSignerName(const css::uno::Reference<css::security::XCertificate>& xCertificate)
OUString getSignerName(const svl::crypto::CertificateOrName& rCertificateOrName)
{
return comphelper::xmlsec::GetContentPart(xCertificate->getSubjectName(),
xCertificate->getCertificateKind());
if (rCertificateOrName.m_xCertificate.is())
{
return comphelper::xmlsec::GetContentPart(
rCertificateOrName.m_xCertificate->getSubjectName(),
rCertificateOrName.m_xCertificate->getCertificateKind());
}
return rCertificateOrName.m_aName;
}
OUString getLocalizedDate()
@@ -130,7 +136,7 @@ uno::Reference<graphic::XGraphic> importSVG(std::u16string_view rSVG)
}
void setShapeCertificate(const SdrView* pView,
const css::uno::Reference<css::security::XCertificate>& xCertificate)
const svl::crypto::CertificateOrName& rCertificateOrName)
{
const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
if (rMarkList.GetMarkCount() < 1)
@@ -149,15 +155,21 @@ void setShapeCertificate(const SdrView* pView,
uno::Reference<drawing::XShape> xShape = pSignatureLine->getUnoShape();
uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
comphelper::SequenceAsHashMap aMap(xShapeProps->getPropertyValue(u"InteropGrabBag"_ustr));
aMap[u"SignatureCertificate"_ustr] <<= xCertificate;
xShapeProps->setPropertyValue(u"InteropGrabBag"_ustr,
uno::Any(aMap.getAsConstPropertyValueList()));
if (rCertificateOrName.m_xCertificate.is())
{
aMap[u"SignatureCertificate"_ustr] <<= rCertificateOrName.m_xCertificate;
}
else
{
aMap[u"SignatureCertificate"_ustr] <<= rCertificateOrName.m_aName;
}
xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aMap.getAsConstPropertyValueList()));
// Read svg and replace placeholder texts.
OUString aSvgImage(
svx::SignatureLineHelper::getSignatureImage(u"signature-line-draw.svg"_ustr));
aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", SvxResId(RID_SVXSTR_SIGNATURELINE_DSIGNED_BY));
OUString aSignerName = svx::SignatureLineHelper::getSignerName(xCertificate);
OUString aSignerName = svx::SignatureLineHelper::getSignerName(rCertificateOrName);
aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", aSignerName);
OUString aDate = svx::SignatureLineHelper::getLocalizedDate();
aDate = SvxResId(RID_SVXSTR_SIGNATURELINE_DATE).replaceFirst("%1", aDate);
+3 -1
View File
@@ -103,7 +103,9 @@ CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testPDFAddVisibleSignatureLastPage)
SfxViewShell* pCurrent = SfxViewShell::Current();
CPPUNIT_ASSERT(pCurrent);
SdrView* pView = pCurrent->GetDrawView();
svx::SignatureLineHelper::setShapeCertificate(pView, xCert);
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = xCert;
svx::SignatureLineHelper::setShapeCertificate(pView, aCertificateOrName);
// the document is modified now, but Sign function can't show SaveAs dialog
// in unit test, so just clear the modified
+3 -1
View File
@@ -774,7 +774,9 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testPDFAddVisibleSignature)
SfxViewShell* pCurrent = SfxViewShell::Current();
CPPUNIT_ASSERT(pCurrent);
SdrView* pView = pCurrent->GetDrawView();
svx::SignatureLineHelper::setShapeCertificate(pView, xCert);
svl::crypto::CertificateOrName aCertificateOrName;
aCertificateOrName.m_xCertificate = xCert;
svx::SignatureLineHelper::setShapeCertificate(pView, aCertificateOrName);
// the document is modified now, but Sign function can't show SaveAs dialog
// in unit test, so just clear the modified
@@ -28,6 +28,7 @@
#include <comphelper/xmlsechelper.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/viewsh.hxx>
#include <svl/cryptosign.hxx>
#include <com/sun/star/security/NoPasswordException.hpp>
#include <com/sun/star/security/CertificateCharacters.hpp>
@@ -227,9 +228,9 @@ void CertificateChooser::ImplInitialize(bool mbSearch)
if (comphelper::LibreOfficeKit::isActive())
{
// The LOK case takes the signing certificate from the view.
if (m_pViewShell && m_pViewShell->GetSigningCertificate().is())
if (m_pViewShell && m_pViewShell->GetSigningCertificate().m_xCertificate.is())
{
xCerts = { m_pViewShell->GetSigningCertificate() };
xCerts = { m_pViewShell->GetSigningCertificate().m_xCertificate };
}
}
else
@@ -265,7 +265,7 @@ DigitalSignaturesDialog::DigitalSignaturesDialog(
if (comphelper::LibreOfficeKit::isActive())
{
// If the view has a signing certificate, then allow adding a signature.
if (!pViewShell || !pViewShell->GetSigningCertificate().is())
if (!pViewShell || !pViewShell->GetSigningCertificate().m_xCertificate.is())
{
m_xAddBtn->hide();
}