summaryrefslogtreecommitdiffstats
path: root/xmlsecurity/source/helper
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /xmlsecurity/source/helper
parentInitial commit. (diff)
downloadlibreoffice-upstream/1%7.0.4.tar.xz
libreoffice-upstream/1%7.0.4.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--xmlsecurity/source/helper/documentsignaturehelper.cxx592
-rw-r--r--xmlsecurity/source/helper/documentsignaturemanager.cxx687
-rw-r--r--xmlsecurity/source/helper/ooxmlsecexporter.cxx546
-rw-r--r--xmlsecurity/source/helper/ooxmlsecexporter.hxx59
-rw-r--r--xmlsecurity/source/helper/ooxmlsecparser.cxx293
-rw-r--r--xmlsecurity/source/helper/ooxmlsecparser.hxx87
-rw-r--r--xmlsecurity/source/helper/pdfsignaturehelper.cxx187
-rw-r--r--xmlsecurity/source/helper/xmlsignaturehelper.cxx549
-rw-r--r--xmlsecurity/source/helper/xmlsignaturehelper2.cxx113
-rw-r--r--xmlsecurity/source/helper/xsecctl.cxx986
-rw-r--r--xmlsecurity/source/helper/xsecparser.cxx530
-rw-r--r--xmlsecurity/source/helper/xsecparser.hxx162
-rw-r--r--xmlsecurity/source/helper/xsecsign.cxx447
-rw-r--r--xmlsecurity/source/helper/xsecverify.cxx537
14 files changed, 5775 insertions, 0 deletions
diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx
new file mode 100644
index 000000000..482ae6cc4
--- /dev/null
+++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx
@@ -0,0 +1,592 @@
+/* -*- 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 <documentsignaturehelper.hxx>
+
+#include <algorithm>
+#include <functional>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <comphelper/documentconstants.hxx>
+#include <comphelper/ofopxmlhelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+#include <svx/xoutbmp.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmloff/attrlist.hxx>
+
+#include <xsecctl.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace css::xml::sax;
+
+namespace
+{
+OUString getElement(OUString const & version, ::sal_Int32 * index)
+{
+ while (*index < version.getLength() && version[*index] == '0') {
+ ++*index;
+ }
+ return version.getToken(0, '.', *index);
+}
+
+
+// Return 1 if version1 is greater than version 2, 0 if they are equal
+//and -1 if version1 is less version 2
+int compareVersions(
+ OUString const & version1, OUString const & version2)
+{
+ for (::sal_Int32 i1 = 0, i2 = 0; i1 >= 0 || i2 >= 0;) {
+ OUString e1(getElement(version1, &i1));
+ OUString e2(getElement(version2, &i2));
+ if (e1.getLength() < e2.getLength()) {
+ return -1;
+ } else if (e1.getLength() > e2.getLength()) {
+ return 1;
+ } else if (e1 < e2) {
+ return -1;
+ } else if (e1 > e2) {
+ return 1;
+ }
+ }
+ return 0;
+}
+}
+
+static void ImplFillElementList(
+ std::vector< OUString >& rList, const Reference < css::embed::XStorage >& rxStore,
+ const OUString& rRootStorageName, const bool bRecursive,
+ const DocumentSignatureAlgorithm mode)
+{
+ const Sequence< OUString > aElements = rxStore->getElementNames();
+
+ for ( const auto& rName : aElements )
+ {
+ if (rName == "[Content_Types].xml")
+ // OOXML
+ continue;
+
+ // If the user enabled validating according to OOo 3.0
+ // then mimetype and all content of META-INF must be excluded.
+ if (mode != DocumentSignatureAlgorithm::OOo3_2
+ && (rName == "META-INF" || rName == "mimetype"))
+ {
+ continue;
+ }
+ else
+ {
+ OUString sEncName = ::rtl::Uri::encode(
+ rName, rtl_UriCharClassRelSegment,
+ rtl_UriEncodeStrict, RTL_TEXTENCODING_UTF8);
+ if (sEncName.isEmpty() && !rName.isEmpty())
+ throw css::uno::RuntimeException("Failed to encode element name of XStorage", nullptr);
+
+ if ( rxStore->isStreamElement( rName ) )
+ {
+ //Exclude documentsignatures.xml!
+ if (rName ==
+ DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName())
+ continue;
+ OUString aFullName( rRootStorageName + sEncName );
+ rList.push_back(aFullName);
+ }
+ else if ( bRecursive && rxStore->isStorageElement( rName ) )
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( rName, css::embed::ElementModes::READ );
+ OUString aFullRootName( rRootStorageName + sEncName + "/" );
+ ImplFillElementList(rList, xSubStore, aFullRootName, bRecursive, mode);
+ }
+ }
+ }
+}
+
+
+bool DocumentSignatureHelper::isODFPre_1_2(const OUString & sVersion)
+{
+ //The property version exists only if the document is at least version 1.2
+ //That is, if the document has version 1.1 and sVersion is empty.
+ //The constant is defined in comphelper/documentconstants.hxx
+ return compareVersions(sVersion, ODFVER_012_TEXT) == -1;
+}
+
+bool DocumentSignatureHelper::isOOo3_2_Signature(const SignatureInformation & sigInfo)
+{
+ return std::any_of(sigInfo.vSignatureReferenceInfors.cbegin(),
+ sigInfo.vSignatureReferenceInfors.cend(),
+ [](const SignatureReferenceInformation& info) { return info.ouURI == "META-INF/manifest.xml"; });
+}
+
+DocumentSignatureAlgorithm
+DocumentSignatureHelper::getDocumentAlgorithm(
+ const OUString & sODFVersion, const SignatureInformation & sigInfo)
+{
+ OSL_ASSERT(!sODFVersion.isEmpty());
+ DocumentSignatureAlgorithm mode = DocumentSignatureAlgorithm::OOo3_2;
+ if (!isOOo3_2_Signature(sigInfo))
+ {
+ if (isODFPre_1_2(sODFVersion))
+ mode = DocumentSignatureAlgorithm::OOo2;
+ else
+ mode = DocumentSignatureAlgorithm::OOo3_0;
+ }
+ return mode;
+}
+
+//The function creates a list of files which are to be signed or for which
+//the signature is to be validated. The strings are UTF8 encoded URIs which
+//contain '/' as path separators.
+//
+//The algorithm how document signatures are created and validated has
+//changed over time. The change affects only which files within the document
+//are changed. Document signatures created by OOo 2.x only used particular files. Since
+//OOo 3.0 everything except "mimetype" and "META-INF" are signed. As of OOo 3.2 everything
+//except META-INF/documentsignatures.xml is signed.
+//Signatures are validated according to the algorithm which was then used for validation.
+//That is, when validating a signature which was created by OOo 3.0, then mimetype and
+//META-INF are not used.
+//
+//When a signature is created then we always use the latest algorithm. That is, we use
+//that of OOo 3.2
+std::vector< OUString >
+DocumentSignatureHelper::CreateElementList(
+ const Reference < css::embed::XStorage >& rxStore,
+ DocumentSignatureMode eMode,
+ const DocumentSignatureAlgorithm mode)
+{
+ std::vector< OUString > aElements;
+ OUString aSep( "/" );
+
+ switch ( eMode )
+ {
+ case DocumentSignatureMode::Content:
+ {
+ if (mode == DocumentSignatureAlgorithm::OOo2) //that is, ODF 1.0, 1.1
+ {
+ // 1) Main content
+ ImplFillElementList(aElements, rxStore, OUString(), false, mode);
+
+ // 2) Pictures...
+ OUString aSubStorageName( "Pictures" );
+ try
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
+ }
+ catch(css::io::IOException& )
+ {
+ ; // Doesn't have to exist...
+ }
+ // 3) OLE...
+ aSubStorageName = "ObjectReplacements";
+ try
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
+ xSubStore.clear();
+
+ // Object folders...
+ const Sequence< OUString > aElementNames = rxStore->getElementNames();
+ for ( const auto& rName : aElementNames )
+ {
+ if ( ( rName.match( "Object " ) ) && rxStore->isStorageElement( rName ) )
+ {
+ Reference < css::embed::XStorage > xTmpSubStore = rxStore->openStorageElement( rName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xTmpSubStore, rName+aSep, true, mode);
+ }
+ }
+ }
+ catch( css::io::IOException& )
+ {
+ ; // Doesn't have to exist...
+ }
+ }
+ else
+ {
+ // Everything except META-INF
+ ImplFillElementList(aElements, rxStore, OUString(), true, mode);
+ }
+ }
+ break;
+ case DocumentSignatureMode::Macros:
+ {
+ // 1) Macros
+ OUString aSubStorageName( "Basic" );
+ try
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
+ }
+ catch( css::io::IOException& )
+ {
+ ; // Doesn't have to exist...
+ }
+
+ // 2) Dialogs
+ aSubStorageName = "Dialogs";
+ try
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
+ }
+ catch( css::io::IOException& )
+ {
+ ; // Doesn't have to exist...
+ }
+ // 3) Scripts
+ aSubStorageName = "Scripts";
+ try
+ {
+ Reference < css::embed::XStorage > xSubStore = rxStore->openStorageElement( aSubStorageName, css::embed::ElementModes::READ );
+ ImplFillElementList(aElements, xSubStore, aSubStorageName+aSep, true, mode);
+ }
+ catch( css::io::IOException& )
+ {
+ ; // Doesn't have to exist...
+ }
+ }
+ break;
+ case DocumentSignatureMode::Package:
+ {
+ // Everything except META-INF
+ ImplFillElementList(aElements, rxStore, OUString(), true, mode);
+ }
+ break;
+ }
+
+ return aElements;
+}
+
+void DocumentSignatureHelper::AppendContentTypes(const uno::Reference<embed::XStorage>& xStorage, std::vector<OUString>& rElements)
+{
+ if (!xStorage.is() || !xStorage->hasByName("[Content_Types].xml"))
+ // ODF
+ return;
+
+ uno::Reference<io::XInputStream> xRelStream(xStorage->openStreamElement("[Content_Types].xml", embed::ElementModes::READ), uno::UNO_QUERY);
+ uno::Sequence< uno::Sequence<beans::StringPair> > aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xRelStream, comphelper::getProcessComponentContext());
+ if (aContentTypeInfo.getLength() < 2)
+ {
+ SAL_WARN("xmlsecurity.helper", "no defaults or overrides in aContentTypeInfo");
+ return;
+ }
+ uno::Sequence<beans::StringPair>& rDefaults = aContentTypeInfo[0];
+ uno::Sequence<beans::StringPair>& rOverrides = aContentTypeInfo[1];
+
+ for (OUString& rElement : rElements)
+ {
+ auto it = std::find_if(rOverrides.begin(), rOverrides.end(), [&](const beans::StringPair& rPair)
+ {
+ return rPair.First == "/" + rElement;
+ });
+
+ if (it != rOverrides.end())
+ {
+ rElement = "/" + rElement + "?ContentType=" + it->Second;
+ continue;
+ }
+
+ it = std::find_if(rDefaults.begin(), rDefaults.end(), [&](const beans::StringPair& rPair)
+ {
+ return rElement.endsWith("." + rPair.First);
+ });
+
+ if (it != rDefaults.end())
+ {
+ rElement = "/" + rElement + "?ContentType=" + it->Second;
+ continue;
+ }
+ SAL_WARN("xmlsecurity.helper", "found no content type for " << rElement);
+ }
+
+ std::sort(rElements.begin(), rElements.end());
+}
+
+SignatureStreamHelper DocumentSignatureHelper::OpenSignatureStream(
+ const Reference < css::embed::XStorage >& rxStore, sal_Int32 nOpenMode, DocumentSignatureMode eDocSigMode )
+{
+ sal_Int32 nSubStorageOpenMode = css::embed::ElementModes::READ;
+ if ( nOpenMode & css::embed::ElementModes::WRITE )
+ nSubStorageOpenMode = css::embed::ElementModes::WRITE;
+
+ SignatureStreamHelper aHelper;
+
+ if (!rxStore.is())
+ return aHelper;
+
+ if (rxStore->hasByName("META-INF"))
+ {
+ try
+ {
+ aHelper.xSignatureStorage = rxStore->openStorageElement( "META-INF", nSubStorageOpenMode );
+ if ( aHelper.xSignatureStorage.is() )
+ {
+ OUString aSIGStreamName;
+ if ( eDocSigMode == DocumentSignatureMode::Content )
+ aSIGStreamName = DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
+ else if ( eDocSigMode == DocumentSignatureMode::Macros )
+ aSIGStreamName = DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
+ else
+ aSIGStreamName = DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
+
+ aHelper.xSignatureStream = aHelper.xSignatureStorage->openStreamElement( aSIGStreamName, nOpenMode );
+ }
+ }
+ catch(css::io::IOException& )
+ {
+ // Doesn't have to exist...
+ SAL_WARN_IF( nOpenMode != css::embed::ElementModes::READ, "xmlsecurity.helper", "Error creating signature stream..." );
+ }
+ }
+ else if(rxStore->hasByName("[Content_Types].xml"))
+ {
+ try
+ {
+ if (rxStore->hasByName("_xmlsignatures") && (nOpenMode & embed::ElementModes::TRUNCATE))
+ // Truncate, then all signatures will be written -> remove previous ones.
+ rxStore->removeElement("_xmlsignatures");
+
+ aHelper.xSignatureStorage = rxStore->openStorageElement("_xmlsignatures", nSubStorageOpenMode);
+ aHelper.nStorageFormat = embed::StorageFormats::OFOPXML;
+ }
+ catch (const io::IOException&)
+ {
+ TOOLS_WARN_EXCEPTION_IF(nOpenMode != css::embed::ElementModes::READ, "xmlsecurity.helper", "DocumentSignatureHelper::OpenSignatureStream:");
+ }
+ }
+
+ return aHelper;
+}
+
+/** Check whether the current file can be signed with GPG (only ODF >= 1.2 can currently) */
+bool DocumentSignatureHelper::CanSignWithGPG(
+ const Reference < css::embed::XStorage >& rxStore,
+ const OUString& sOdfVersion)
+{
+ if (!rxStore.is())
+ return false;
+
+ if (rxStore->hasByName("META-INF")) // ODF
+ {
+ return !isODFPre_1_2(sOdfVersion);
+ }
+
+ return false;
+}
+
+
+
+//sElementList contains all files which are expected to be signed. Only those files must me signed,
+//no more, no less.
+//The DocumentSignatureAlgorithm indicates if the document was created with OOo 2.x. Then
+//the uri s in the Reference elements in the signature, were not properly encoded.
+// For example: <Reference URI="ObjectReplacements/Object 1">
+bool DocumentSignatureHelper::checkIfAllFilesAreSigned(
+ const ::std::vector< OUString > & sElementList,
+ const SignatureInformation & sigInfo,
+ const DocumentSignatureAlgorithm alg)
+{
+ // Can only be valid if ALL streams are signed, which means real stream count == signed stream count
+ unsigned int nRealCount = 0;
+ std::function<OUString(const OUString&)> fEncode = [](const OUString& rStr) { return rStr; };
+ if (alg == DocumentSignatureAlgorithm::OOo2)
+ //Comparing URIs is a difficult. Therefore we kind of normalize
+ //it before comparing. We assume that our URI do not have a leading "./"
+ //and fragments at the end (...#...)
+ fEncode = [](const OUString& rStr) {
+ return rtl::Uri::encode(rStr, rtl_UriCharClassPchar, rtl_UriEncodeCheckEscapes, RTL_TEXTENCODING_UTF8);
+ };
+
+ for ( int i = sigInfo.vSignatureReferenceInfors.size(); i; )
+ {
+ const SignatureReferenceInformation& rInf = sigInfo.vSignatureReferenceInfors[--i];
+ // There is also an extra entry of type SignatureReferenceType::SAMEDOCUMENT because of signature date.
+ if ( ( rInf.nType == SignatureReferenceType::BINARYSTREAM ) || ( rInf.nType == SignatureReferenceType::XMLSTREAM ) )
+ {
+ //find the file in the element list
+ if (std::any_of(sElementList.cbegin(), sElementList.cend(),
+ [&fEncode, &rInf](const OUString& rElement) { return fEncode(rElement) == fEncode(rInf.ouURI); }))
+ nRealCount++;
+ }
+ }
+ return sElementList.size() == nRealCount;
+}
+
+/*Compares the Uri which are obtained from CreateElementList with
+ the path obtained from the manifest.xml.
+ Returns true if both strings are equal.
+*/
+bool DocumentSignatureHelper::equalsReferenceUriManifestPath(
+ const OUString & rUri, const OUString & rPath)
+{
+ //split up the uri and path into segments. Both are separated by '/'
+ std::vector<OUString> vUriSegments;
+ for (sal_Int32 nIndex = 0; nIndex >= 0; )
+ vUriSegments.push_back(rUri.getToken( 0, '/', nIndex ));
+
+ std::vector<OUString> vPathSegments;
+ for (sal_Int32 nIndex = 0; nIndex >= 0; )
+ vPathSegments.push_back(rPath.getToken( 0, '/', nIndex ));
+
+ if (vUriSegments.size() != vPathSegments.size())
+ return false;
+
+ //Now compare each segment of the uri with its counterpart from the path
+ return std::equal(
+ vUriSegments.cbegin(), vUriSegments.cend(), vPathSegments.cbegin(),
+ [](const OUString& rUriSegment, const OUString& rPathSegment) {
+ //Decode the uri segment, so that %20 becomes ' ', etc.
+ OUString sDecUri = rtl::Uri::decode(rUriSegment, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
+ return sDecUri == rPathSegment;
+ });
+}
+
+OUString DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName()
+{
+ return "documentsignatures.xml";
+}
+
+OUString DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName()
+{
+ return "macrosignatures.xml";
+}
+
+OUString DocumentSignatureHelper::GetPackageSignatureDefaultStreamName()
+{
+ return "packagesignatures.xml";
+}
+
+void DocumentSignatureHelper::writeDigestMethod(
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler)
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Algorithm", ALGO_XMLDSIGSHA256);
+ xDocumentHandler->startElement("DigestMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ xDocumentHandler->endElement("DigestMethod");
+}
+
+void DocumentSignatureHelper::writeSignedProperties(
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& signatureInfo,
+ const OUString& sDate, const bool bWriteSignatureLineData)
+{
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idSignedProperties");
+ xDocumentHandler->startElement("xd:SignedProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+
+ xDocumentHandler->startElement("xd:SignedSignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("xd:SigningTime", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(sDate);
+ xDocumentHandler->endElement("xd:SigningTime");
+ xDocumentHandler->startElement("xd:SigningCertificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("xd:Cert", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("xd:CertDigest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ writeDigestMethod(xDocumentHandler);
+
+ xDocumentHandler->startElement("DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ // TODO: this is empty for gpg signatures currently
+ //assert(!signatureInfo.ouCertDigest.isEmpty());
+ xDocumentHandler->characters(signatureInfo.ouCertDigest);
+ xDocumentHandler->endElement("DigestValue");
+
+ xDocumentHandler->endElement("xd:CertDigest");
+ xDocumentHandler->startElement("xd:IssuerSerial", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("X509IssuerName", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(signatureInfo.ouX509IssuerName);
+ xDocumentHandler->endElement("X509IssuerName");
+ xDocumentHandler->startElement("X509SerialNumber", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(signatureInfo.ouX509SerialNumber);
+ xDocumentHandler->endElement("X509SerialNumber");
+ xDocumentHandler->endElement("xd:IssuerSerial");
+ xDocumentHandler->endElement("xd:Cert");
+ xDocumentHandler->endElement("xd:SigningCertificate");
+ xDocumentHandler->startElement("xd:SignaturePolicyIdentifier", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->startElement("xd:SignaturePolicyImplied", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->endElement("xd:SignaturePolicyImplied");
+ xDocumentHandler->endElement("xd:SignaturePolicyIdentifier");
+
+ if (bWriteSignatureLineData && !signatureInfo.ouSignatureLineId.isEmpty()
+ && signatureInfo.aValidSignatureImage.is() && signatureInfo.aInvalidSignatureImage.is())
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute(
+ "xmlns:loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0");
+ xDocumentHandler->startElement(
+ "loext:SignatureLine",
+ Reference<XAttributeList>(pAttributeList.get()));
+
+ {
+ // Write SignatureLineId element
+ xDocumentHandler->startElement(
+ "loext:SignatureLineId",
+ Reference<XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(signatureInfo.ouSignatureLineId);
+ xDocumentHandler->endElement("loext:SignatureLineId");
+ }
+
+ {
+ // Write SignatureLineValidImage element
+ xDocumentHandler->startElement(
+ "loext:SignatureLineValidImage",
+ Reference<XAttributeList>(new SvXMLAttributeList()));
+
+ OUString aGraphicInBase64;
+ Graphic aGraphic(signatureInfo.aValidSignatureImage);
+ if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64, false))
+ SAL_WARN("xmlsecurity.helper", "could not convert graphic to base64");
+
+ xDocumentHandler->characters(aGraphicInBase64);
+ xDocumentHandler->endElement("loext:SignatureLineValidImage");
+ }
+
+ {
+ // Write SignatureLineInvalidImage element
+ xDocumentHandler->startElement(
+ "loext:SignatureLineInvalidImage",
+ Reference<XAttributeList>(new SvXMLAttributeList()));
+ OUString aGraphicInBase64;
+ Graphic aGraphic(signatureInfo.aInvalidSignatureImage);
+ if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64, false))
+ SAL_WARN("xmlsecurity.helper", "could not convert graphic to base64");
+ xDocumentHandler->characters(aGraphicInBase64);
+ xDocumentHandler->endElement("loext:SignatureLineInvalidImage");
+ }
+
+ xDocumentHandler->endElement("loext:SignatureLine");
+ }
+
+ xDocumentHandler->endElement("xd:SignedSignatureProperties");
+
+ xDocumentHandler->endElement("xd:SignedProperties");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx
new file mode 100644
index 000000000..79d2cdf26
--- /dev/null
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
@@ -0,0 +1,687 @@
+/* -*- 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 <documentsignaturemanager.hxx>
+#include <config_gpgme.h>
+
+#include <gpg/SEInitializer.hxx>
+
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/xml/crypto/SEInitializer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/packages/manifest/ManifestReader.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/XWriter.hpp>
+
+#include <comphelper/base64.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/datetime.hxx>
+
+#include <certificate.hxx>
+#include <biginteger.hxx>
+
+#include <xmlsec/xmlsec_init.hxx>
+
+#include <pdfsignaturehelper.hxx>
+
+#include <memory>
+
+using namespace css;
+using namespace css::graphic;
+using namespace css::uno;
+
+DocumentSignatureManager::DocumentSignatureManager(
+ const uno::Reference<uno::XComponentContext>& xContext, DocumentSignatureMode eMode)
+ : mxContext(xContext)
+ , maSignatureHelper(xContext)
+ , meSignatureMode(eMode)
+{
+}
+
+DocumentSignatureManager::~DocumentSignatureManager() { deInitXmlSec(); }
+
+bool DocumentSignatureManager::init()
+{
+ SAL_WARN_IF(mxSEInitializer.is(), "xmlsecurity.helper",
+ "DocumentSignatureManager::Init - mxSEInitializer already set!");
+ SAL_WARN_IF(mxSecurityContext.is(), "xmlsecurity.helper",
+ "DocumentSignatureManager::Init - mxSecurityContext already set!");
+ SAL_WARN_IF(mxGpgSEInitializer.is(), "xmlsecurity.helper",
+ "DocumentSignatureManager::Init - mxGpgSEInitializer already set!");
+
+ // xmlsec is needed by both services, so init before those
+ initXmlSec();
+
+ mxSEInitializer = xml::crypto::SEInitializer::create(mxContext);
+#if HAVE_FEATURE_GPGME
+ mxGpgSEInitializer.set(new SEInitializerGpg());
+#endif
+
+ if (mxSEInitializer.is())
+ mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
+
+#if HAVE_FEATURE_GPGME
+ if (mxGpgSEInitializer.is())
+ mxGpgSecurityContext = mxGpgSEInitializer->createSecurityContext(OUString());
+
+ return mxSecurityContext.is() || mxGpgSecurityContext.is();
+#else
+ return mxSecurityContext.is();
+#endif
+}
+
+PDFSignatureHelper& DocumentSignatureManager::getPDFSignatureHelper()
+{
+ bool bInit = true;
+ if (!mxSecurityContext.is())
+ bInit = init();
+
+ SAL_WARN_IF(!bInit, "xmlsecurity.comp", "Error initializing security context!");
+
+ if (!mpPDFSignatureHelper)
+ mpPDFSignatureHelper = std::make_unique<PDFSignatureHelper>();
+
+ return *mpPDFSignatureHelper;
+}
+
+#if 0 // For some reason does not work
+bool DocumentSignatureManager::IsXAdESRelevant()
+{
+ if (mxStore.is())
+ {
+ // ZIP-based: ODF or OOXML.
+ maSignatureHelper.StartMission();
+
+ SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(embed::ElementModes::READ, /*bUseTempStream=*/true);
+ if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
+ {
+ maSignatureHelper.EndMission();
+ return false;
+ }
+ // FIXME: How to figure out if it is ODF 1.2?
+ maSignatureHelper.EndMission();
+ return true;
+ }
+ return false;
+}
+#endif
+
+bool DocumentSignatureManager::readManifest()
+{
+ // Check if manifest was already read
+ if (m_manifest.hasElements())
+ return true;
+
+ if (!mxContext.is())
+ return false;
+
+ if (!mxStore.is())
+ return false;
+
+ uno::Reference<packages::manifest::XManifestReader> xReader
+ = packages::manifest::ManifestReader::create(mxContext);
+
+ if (mxStore->hasByName("META-INF"))
+ {
+ //Get the manifest.xml
+ uno::Reference<embed::XStorage> xSubStore(
+ mxStore->openStorageElement("META-INF", embed::ElementModes::READ), UNO_SET_THROW);
+
+ uno::Reference<io::XInputStream> xStream(
+ xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ),
+ UNO_QUERY_THROW);
+
+ m_manifest = xReader->readManifestSequence(xStream);
+ }
+ return true;
+}
+
+/* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted"
+ We use the manifest to find out if a file is xml and if it is encrypted.
+ The parameter is an encoded uri. However, the manifest contains paths. Therefore
+ the path is encoded as uri, so they can be compared.
+*/
+bool DocumentSignatureManager::isXML(const OUString& rURI)
+{
+ SAL_WARN_IF(!mxStore.is(), "xmlsecurity.helper", "empty storage reference");
+
+ bool bIsXML = false;
+ bool bPropsAvailable = false;
+ const OUString sPropFullPath("FullPath");
+ const OUString sPropMediaType("MediaType");
+ const OUString sPropDigest("Digest");
+
+ if (readManifest())
+ {
+ for (const uno::Sequence<beans::PropertyValue>& entry : std::as_const(m_manifest))
+ {
+ OUString sPath;
+ OUString sMediaType;
+ bool bEncrypted = false;
+ for (const beans::PropertyValue& prop : entry)
+ {
+ if (prop.Name == sPropFullPath)
+ prop.Value >>= sPath;
+ else if (prop.Name == sPropMediaType)
+ prop.Value >>= sMediaType;
+ else if (prop.Name == sPropDigest)
+ bEncrypted = true;
+ }
+ if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath))
+ {
+ bIsXML = sMediaType == "text/xml" && !bEncrypted;
+ bPropsAvailable = true;
+ break;
+ }
+ }
+ }
+ if (!bPropsAvailable)
+ {
+ //This would be the case for at least mimetype, META-INF/manifest.xml
+ //META-INF/macrosignatures.xml.
+ //Files can only be encrypted if they are in the manifest.xml.
+ //That is, the current file cannot be encrypted, otherwise bPropsAvailable
+ //would be true.
+ sal_Int32 nSep = rURI.lastIndexOf('.');
+ if (nSep != -1)
+ {
+ OUString aExt = rURI.copy(nSep + 1);
+ if (aExt.equalsIgnoreAsciiCase("XML"))
+ bIsXML = true;
+ }
+ }
+ return bIsXML;
+}
+
+//If bTempStream is true, then a temporary stream is return. If it is false then, the actual
+//signature stream is used.
+//Every time the user presses Add a new temporary stream is created.
+//We keep the temporary stream as member because ImplGetSignatureInformations
+//will later access the stream to create DocumentSignatureInformation objects
+//which are stored in maCurrentSignatureInformations.
+SignatureStreamHelper DocumentSignatureManager::ImplOpenSignatureStream(sal_Int32 nStreamOpenMode,
+ bool bTempStream)
+{
+ SignatureStreamHelper aHelper;
+ if (mxStore.is() && mxStore->hasByName("[Content_Types].xml"))
+ aHelper.nStorageFormat = embed::StorageFormats::OFOPXML;
+
+ if (bTempStream)
+ {
+ if (nStreamOpenMode & embed::ElementModes::TRUNCATE)
+ {
+ //We write always into a new temporary stream.
+ mxTempSignatureStream.set(io::TempFile::create(mxContext), uno::UNO_QUERY_THROW);
+ if (aHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
+ aHelper.xSignatureStream = mxTempSignatureStream;
+ else
+ {
+ mxTempSignatureStorage = comphelper::OStorageHelper::GetStorageOfFormatFromStream(
+ ZIP_STORAGE_FORMAT_STRING, mxTempSignatureStream);
+ aHelper.xSignatureStorage = mxTempSignatureStorage;
+ }
+ }
+ else
+ {
+ //When we read from the temp stream, then we must have previously
+ //created one.
+ SAL_WARN_IF(!mxTempSignatureStream.is(), "xmlsecurity.helper",
+ "empty temp. signature stream reference");
+ }
+ aHelper.xSignatureStream = mxTempSignatureStream;
+ if (aHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
+ aHelper.xSignatureStorage = mxTempSignatureStorage;
+ }
+ else
+ {
+ //No temporary stream
+ if (!mxSignatureStream.is())
+ {
+ //We may not have a dedicated stream for writing the signature
+ //So we take one directly from the storage
+ //Or DocumentDigitalSignatures::showDocumentContentSignatures was called,
+ //in which case Add/Remove is not allowed. This is done, for example, if the
+ //document is readonly
+ aHelper = DocumentSignatureHelper::OpenSignatureStream(mxStore, nStreamOpenMode,
+ meSignatureMode);
+ }
+ else
+ {
+ aHelper.xSignatureStream = mxSignatureStream;
+ }
+ }
+
+ if (nStreamOpenMode & embed::ElementModes::TRUNCATE)
+ {
+ if (aHelper.xSignatureStream.is()
+ && aHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
+ {
+ uno::Reference<io::XTruncate> xTruncate(aHelper.xSignatureStream, uno::UNO_QUERY_THROW);
+ xTruncate->truncate();
+ }
+ }
+ else if (bTempStream || mxSignatureStream.is())
+ {
+ //In case we read the signature stream from the storage directly,
+ //which is the case when DocumentDigitalSignatures::showDocumentContentSignatures
+ //then XSeakable is not supported
+ uno::Reference<io::XSeekable> xSeek(aHelper.xSignatureStream, uno::UNO_QUERY_THROW);
+ xSeek->seek(0);
+ }
+
+ return aHelper;
+}
+
+bool DocumentSignatureManager::add(
+ const uno::Reference<security::XCertificate>& xCert,
+ const uno::Reference<xml::crypto::XXMLSecurityContext>& xSecurityContext,
+ const OUString& rDescription, sal_Int32& nSecurityId, bool bAdESCompliant,
+ const OUString& rSignatureLineId, const Reference<XGraphic>& xValidGraphic,
+ const Reference<XGraphic>& xInvalidGraphic)
+{
+ if (!xCert.is())
+ {
+ SAL_WARN("xmlsecurity.helper", "no certificate selected");
+ return false;
+ }
+
+ // GPG or X509 key?
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xSecurityContext, uno::UNO_QUERY);
+ if (xServiceInfo->getImplementationName()
+ == "com.sun.star.xml.security.gpg.XMLSecurityContext_GpgImpl")
+ {
+ // GPG keys only really have PGPKeyId and PGPKeyPacket
+ if (!mxStore.is())
+ {
+ SAL_WARN("xmlsecurity.helper", "cannot sign pdfs with GPG keys");
+ return false;
+ }
+
+ maSignatureHelper.StartMission(xSecurityContext);
+
+ nSecurityId = maSignatureHelper.GetNewSecurityId();
+
+ OUStringBuffer aStrBuffer;
+ comphelper::Base64::encode(aStrBuffer, xCert->getEncoded());
+
+ OUString aKeyId;
+ if (auto pCertificate = dynamic_cast<xmlsecurity::Certificate*>(xCert.get()))
+ {
+ OUStringBuffer aBuffer;
+ comphelper::Base64::encode(aBuffer, pCertificate->getSHA256Thumbprint());
+ aKeyId = aBuffer.makeStringAndClear();
+ }
+ else
+ SAL_WARN("xmlsecurity.helper",
+ "XCertificate implementation without an xmlsecurity::Certificate one");
+
+ maSignatureHelper.SetGpgCertificate(nSecurityId, aKeyId, aStrBuffer.makeStringAndClear(),
+ xCert->getIssuerName());
+ }
+ else
+ {
+ OUString aCertSerial = xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber());
+ if (aCertSerial.isEmpty())
+ {
+ SAL_WARN("xmlsecurity.helper", "Error in Certificate, problem with serial number!");
+ return false;
+ }
+
+ if (!mxStore.is())
+ {
+ // Something not ZIP based, try PDF.
+ nSecurityId = getPDFSignatureHelper().GetNewSecurityId();
+ getPDFSignatureHelper().SetX509Certificate(xCert);
+ getPDFSignatureHelper().SetDescription(rDescription);
+ uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
+ if (!getPDFSignatureHelper().Sign(xInputStream, bAdESCompliant))
+ {
+ SAL_WARN("xmlsecurity.helper", "PDFSignatureHelper::Sign() failed");
+ return false;
+ }
+ return true;
+ }
+
+ maSignatureHelper.StartMission(xSecurityContext);
+
+ nSecurityId = maSignatureHelper.GetNewSecurityId();
+
+ OUStringBuffer aStrBuffer;
+ comphelper::Base64::encode(aStrBuffer, xCert->getEncoded());
+
+ OUString aCertDigest;
+ svl::crypto::SignatureMethodAlgorithm eAlgorithmID
+ = svl::crypto::SignatureMethodAlgorithm::RSA;
+ if (auto pCertificate = dynamic_cast<xmlsecurity::Certificate*>(xCert.get()))
+ {
+ OUStringBuffer aBuffer;
+ comphelper::Base64::encode(aBuffer, pCertificate->getSHA256Thumbprint());
+ aCertDigest = aBuffer.makeStringAndClear();
+
+ eAlgorithmID = pCertificate->getSignatureMethodAlgorithm();
+ }
+ else
+ SAL_WARN("xmlsecurity.helper",
+ "XCertificate implementation without an xmlsecurity::Certificate one");
+
+ maSignatureHelper.SetX509Certificate(nSecurityId, xCert->getIssuerName(), aCertSerial,
+ aStrBuffer.makeStringAndClear(), aCertDigest,
+ eAlgorithmID);
+ }
+
+ const uno::Sequence<uno::Reference<security::XCertificate>> aCertPath
+ = xSecurityContext->getSecurityEnvironment()->buildCertificatePath(xCert);
+
+ OUStringBuffer aStrBuffer;
+ for (uno::Reference<security::XCertificate> const& rxCertificate : aCertPath)
+ {
+ comphelper::Base64::encode(aStrBuffer, rxCertificate->getEncoded());
+ OUString aString = aStrBuffer.makeStringAndClear();
+ maSignatureHelper.AddEncapsulatedX509Certificate(aString);
+ }
+
+ std::vector<OUString> aElements = DocumentSignatureHelper::CreateElementList(
+ mxStore, meSignatureMode, DocumentSignatureAlgorithm::OOo3_2);
+ DocumentSignatureHelper::AppendContentTypes(mxStore, aElements);
+
+ for (OUString const& rUri : aElements)
+ {
+ bool bBinaryMode = !isXML(rUri);
+ maSignatureHelper.AddForSigning(nSecurityId, rUri, bBinaryMode, bAdESCompliant);
+ }
+
+ maSignatureHelper.SetDateTime(nSecurityId, DateTime(DateTime::SYSTEM));
+ maSignatureHelper.SetDescription(nSecurityId, rDescription);
+
+ if (!rSignatureLineId.isEmpty())
+ maSignatureHelper.SetSignatureLineId(nSecurityId, rSignatureLineId);
+
+ if (xValidGraphic.is())
+ maSignatureHelper.SetSignatureLineValidGraphic(nSecurityId, xValidGraphic);
+
+ if (xInvalidGraphic.is())
+ maSignatureHelper.SetSignatureLineInvalidGraphic(nSecurityId, xInvalidGraphic);
+
+ // We open a signature stream in which the existing and the new
+ //signature is written. ImplGetSignatureInformation (later in this function) will
+ //then read the stream and fill maCurrentSignatureInformations. The final signature
+ //is written when the user presses OK. Then only maCurrentSignatureInformation and
+ //a sax writer are used to write the information.
+ SignatureStreamHelper aStreamHelper
+ = ImplOpenSignatureStream(embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, true);
+
+ if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
+ {
+ uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<xml::sax::XWriter> xSaxWriter
+ = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
+
+ // Export old signatures...
+ uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
+ uno::UNO_QUERY_THROW);
+ std::size_t nInfos = maCurrentSignatureInformations.size();
+ for (std::size_t n = 0; n < nInfos; n++)
+ XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
+ bAdESCompliant);
+
+ // Create a new one...
+ maSignatureHelper.CreateAndWriteSignature(xDocumentHandler, bAdESCompliant);
+
+ // That's it...
+ XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
+ }
+ else
+ {
+ // OOXML
+
+ // Handle relations.
+ maSignatureHelper.EnsureSignaturesRelation(mxStore, /*bAdd=*/true);
+ // Old signatures + the new one.
+ int nSignatureCount = maCurrentSignatureInformations.size() + 1;
+ maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
+ nSignatureCount);
+
+ // Export old signatures.
+ for (std::size_t i = 0; i < maCurrentSignatureInformations.size(); ++i)
+ maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
+ maCurrentSignatureInformations[i], i + 1);
+
+ // Create a new signature.
+ maSignatureHelper.CreateAndWriteOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
+ nSignatureCount);
+
+ // Flush objects.
+ uno::Reference<embed::XTransactedObject> xTransact(aStreamHelper.xSignatureStorage,
+ uno::UNO_QUERY);
+ xTransact->commit();
+ uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY);
+ xOutputStream->closeOutput();
+
+ uno::Reference<io::XTempFile> xTempFile(aStreamHelper.xSignatureStream, uno::UNO_QUERY);
+ SAL_INFO("xmlsecurity.helper",
+ "DocumentSignatureManager::add temporary storage at " << xTempFile->getUri());
+ }
+
+ maSignatureHelper.EndMission();
+ return true;
+}
+
+void DocumentSignatureManager::remove(sal_uInt16 nPosition)
+{
+ if (!mxStore.is())
+ {
+ // Something not ZIP based, try PDF.
+ uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
+ if (!PDFSignatureHelper::RemoveSignature(xInputStream, nPosition))
+ {
+ SAL_WARN("xmlsecurity.helper", "PDFSignatureHelper::RemoveSignature() failed");
+ return;
+ }
+
+ // Only erase when the removal was successful, it may fail for PDF.
+ // Also, erase the requested and all following signatures, as PDF signatures are always chained.
+ maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition,
+ maCurrentSignatureInformations.end());
+ return;
+ }
+
+ maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition);
+
+ // Export all other signatures...
+ SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, /*bTempStream=*/true);
+
+ if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
+ {
+ uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<xml::sax::XWriter> xSaxWriter
+ = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
+
+ uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
+ uno::UNO_QUERY_THROW);
+ std::size_t nInfos = maCurrentSignatureInformations.size();
+ for (std::size_t n = 0; n < nInfos; ++n)
+ XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
+ false /* ??? */);
+
+ XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
+ }
+ else
+ {
+ // OOXML
+
+ // Handle relations.
+ int nSignatureCount = maCurrentSignatureInformations.size();
+ maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
+ nSignatureCount);
+
+ // Export old signatures.
+ for (std::size_t i = 0; i < maCurrentSignatureInformations.size(); ++i)
+ maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
+ maCurrentSignatureInformations[i], i + 1);
+
+ // Flush objects.
+ uno::Reference<embed::XTransactedObject> xTransact(aStreamHelper.xSignatureStorage,
+ uno::UNO_QUERY);
+ xTransact->commit();
+ uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY);
+ xOutputStream->closeOutput();
+
+ uno::Reference<io::XTempFile> xTempFile(aStreamHelper.xSignatureStream, uno::UNO_QUERY);
+ SAL_INFO("xmlsecurity.helper", "DocumentSignatureManager::remove: temporary storage is at "
+ << xTempFile->getUri());
+ }
+}
+
+void DocumentSignatureManager::read(bool bUseTempStream, bool bCacheLastSignature)
+{
+ maCurrentSignatureInformations.clear();
+
+ if (mxStore.is())
+ {
+ // ZIP-based: ODF or OOXML.
+ maSignatureHelper.StartMission(mxSecurityContext);
+
+ SignatureStreamHelper aStreamHelper
+ = ImplOpenSignatureStream(embed::ElementModes::READ, bUseTempStream);
+ if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML
+ && aStreamHelper.xSignatureStream.is())
+ {
+ uno::Reference<io::XInputStream> xInputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY);
+ maSignatureHelper.ReadAndVerifySignature(xInputStream);
+ }
+ else if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML
+ && aStreamHelper.xSignatureStorage.is())
+ maSignatureHelper.ReadAndVerifySignatureStorage(aStreamHelper.xSignatureStorage,
+ bCacheLastSignature);
+ maSignatureHelper.EndMission();
+
+ maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
+ }
+ else
+ {
+ // Something not ZIP based, try PDF.
+ uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
+ if (getPDFSignatureHelper().ReadAndVerifySignature(xInputStream))
+ maCurrentSignatureInformations = getPDFSignatureHelper().GetSignatureInformations();
+ }
+}
+
+void DocumentSignatureManager::write(bool bXAdESCompliantIfODF)
+{
+ if (!mxStore.is())
+ {
+ // Something not ZIP based, assume PDF, which is written directly in add() already.
+ return;
+ }
+
+ // Export all other signatures...
+ SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, false);
+
+ if (aStreamHelper.xSignatureStream.is()
+ && aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
+ {
+ // ODF
+ uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
+ uno::UNO_QUERY);
+ uno::Reference<xml::sax::XWriter> xSaxWriter
+ = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
+
+ uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
+ uno::UNO_QUERY_THROW);
+ std::size_t nInfos = maCurrentSignatureInformations.size();
+ for (std::size_t n = 0; n < nInfos; ++n)
+ XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
+ bXAdESCompliantIfODF);
+
+ XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
+ }
+ else if (aStreamHelper.xSignatureStorage.is()
+ && aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
+ {
+ // OOXML
+ std::size_t nSignatureCount = maCurrentSignatureInformations.size();
+ maSignatureHelper.ExportSignatureContentTypes(mxStore, nSignatureCount);
+ if (nSignatureCount > 0)
+ maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
+ nSignatureCount);
+ else
+ {
+ // Removing all signatures: then need to remove the signature relation as well.
+ maSignatureHelper.EnsureSignaturesRelation(mxStore, /*bAdd=*/false);
+ // Also remove the whole signature sub-storage: release our read-write reference + remove the element.
+ aStreamHelper = SignatureStreamHelper();
+ mxStore->removeElement("_xmlsignatures");
+ }
+
+ for (std::size_t i = 0; i < nSignatureCount; ++i)
+ maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
+ maCurrentSignatureInformations[i], i + 1);
+ }
+
+ // If stream was not provided, we are responsible for committing it...
+ if (!mxSignatureStream.is() && aStreamHelper.xSignatureStorage.is())
+ {
+ uno::Reference<embed::XTransactedObject> xTrans(aStreamHelper.xSignatureStorage,
+ uno::UNO_QUERY);
+ xTrans->commit();
+ }
+}
+
+uno::Reference<xml::crypto::XSecurityEnvironment> DocumentSignatureManager::getSecurityEnvironment()
+{
+ return mxSecurityContext.is() ? mxSecurityContext->getSecurityEnvironment()
+ : uno::Reference<xml::crypto::XSecurityEnvironment>();
+}
+
+uno::Reference<xml::crypto::XSecurityEnvironment>
+DocumentSignatureManager::getGpgSecurityEnvironment()
+{
+ return mxGpgSecurityContext.is() ? mxGpgSecurityContext->getSecurityEnvironment()
+ : uno::Reference<xml::crypto::XSecurityEnvironment>();
+}
+
+uno::Reference<xml::crypto::XXMLSecurityContext> const&
+DocumentSignatureManager::getSecurityContext() const
+{
+ return mxSecurityContext;
+}
+
+uno::Reference<xml::crypto::XXMLSecurityContext> const&
+DocumentSignatureManager::getGpgSecurityContext() const
+{
+ return mxGpgSecurityContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
new file mode 100644
index 000000000..fe4d0df89
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx
@@ -0,0 +1,546 @@
+/* -*- 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/.
+ */
+
+#include "ooxmlsecexporter.hxx"
+
+#include <algorithm>
+#include <memory>
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <comphelper/ofopxmlhelper.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+#include <svx/xoutbmp.hxx>
+#include <unotools/datetime.hxx>
+#include <vcl/salctype.hxx>
+#include <xmloff/attrlist.hxx>
+
+#include <documentsignaturehelper.hxx>
+#include <xsecctl.hxx>
+
+using namespace com::sun::star;
+using namespace css::xml::sax;
+
+struct OOXMLSecExporter::Impl
+{
+private:
+ const uno::Reference<uno::XComponentContext>& m_xComponentContext;
+ const uno::Reference<embed::XStorage>& m_xRootStorage;
+ const uno::Reference<xml::sax::XDocumentHandler>& m_xDocumentHandler;
+ const SignatureInformation& m_rInformation;
+ OUString m_aSignatureTimeValue;
+
+public:
+ Impl(const uno::Reference<uno::XComponentContext>& xComponentContext,
+ const uno::Reference<embed::XStorage>& xRootStorage,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& rInformation)
+ : m_xComponentContext(xComponentContext)
+ , m_xRootStorage(xRootStorage)
+ , m_xDocumentHandler(xDocumentHandler)
+ , m_rInformation(rInformation)
+ {
+ }
+
+ /// Should we intentionally not sign this stream?
+ static bool isOOXMLBlacklist(const OUString& rStreamName);
+ /// Should we intentionally not sign this relation type?
+ static bool isOOXMLRelationBlacklist(const OUString& rRelationName);
+
+ const uno::Reference<xml::sax::XDocumentHandler>& getDocumentHandler() const
+ {
+ return m_xDocumentHandler;
+ }
+
+ void writeSignedInfo();
+ void writeCanonicalizationMethod();
+ void writeCanonicalizationTransform();
+ void writeSignatureMethod();
+ void writeSignedInfoReferences();
+ void writeSignatureValue();
+ void writeKeyInfo();
+ void writePackageObject();
+ void writeManifest();
+ void writeRelationshipTransform(const OUString& rURI);
+ /// Writes <SignatureProperties> inside idPackageObject.
+ void writePackageObjectSignatureProperties();
+ /// Writes a single <Reference> inside <Manifest>.
+ void writeManifestReference(const SignatureReferenceInformation& rReference);
+ void writeOfficeObject();
+ /// Writes <SignatureInfoV1>.
+ void writeSignatureInfo();
+ void writePackageSignature();
+ void writeSignatureLineImages();
+};
+
+bool OOXMLSecExporter::Impl::isOOXMLBlacklist(const OUString& rStreamName)
+{
+ static const std::initializer_list<OUStringLiteral> vBlacklist
+ = { "/%5BContent_Types%5D.xml", "/docProps/app.xml", "/docProps/core.xml",
+ // Don't attempt to sign other signatures for now.
+ "/_xmlsignatures" };
+ // Just check the prefix, as we don't care about the content type part of the stream name.
+ return std::any_of(vBlacklist.begin(), vBlacklist.end(), [&](const OUStringLiteral& rLiteral) {
+ return rStreamName.startsWith(rLiteral);
+ });
+}
+
+bool OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(const OUString& rRelationName)
+{
+ static const std::initializer_list<OUStringLiteral> vBlacklist = {
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
+ "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
+ "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"
+ };
+ return std::find(vBlacklist.begin(), vBlacklist.end(), rRelationName) != vBlacklist.end();
+}
+
+void OOXMLSecExporter::Impl::writeSignedInfo()
+{
+ m_xDocumentHandler->startElement(
+ "SignedInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+ writeCanonicalizationMethod();
+ writeSignatureMethod();
+ writeSignedInfoReferences();
+
+ m_xDocumentHandler->endElement("SignedInfo");
+}
+
+void OOXMLSecExporter::Impl::writeCanonicalizationMethod()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
+ m_xDocumentHandler->startElement(
+ "CanonicalizationMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ m_xDocumentHandler->endElement("CanonicalizationMethod");
+}
+
+void OOXMLSecExporter::Impl::writeCanonicalizationTransform()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Algorithm", ALGO_C14N);
+ m_xDocumentHandler->startElement(
+ "Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ m_xDocumentHandler->endElement("Transform");
+}
+
+void OOXMLSecExporter::Impl::writeSignatureMethod()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+
+ if (m_rInformation.eAlgorithmID == svl::crypto::SignatureMethodAlgorithm::ECDSA)
+ pAttributeList->AddAttribute("Algorithm", ALGO_ECDSASHA256);
+ else
+ pAttributeList->AddAttribute("Algorithm", ALGO_RSASHA256);
+
+ m_xDocumentHandler->startElement(
+ "SignatureMethod", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ m_xDocumentHandler->endElement("SignatureMethod");
+}
+
+void OOXMLSecExporter::Impl::writeSignedInfoReferences()
+{
+ const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
+ for (const SignatureReferenceInformation& rReference : rReferences)
+ {
+ if (rReference.nType == SignatureReferenceType::SAMEDOCUMENT)
+ {
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ if (rReference.ouURI != "idSignedProperties")
+ pAttributeList->AddAttribute("Type",
+ "http://www.w3.org/2000/09/xmldsig#Object");
+ else
+ pAttributeList->AddAttribute("Type",
+ "http://uri.etsi.org/01903#SignedProperties");
+ pAttributeList->AddAttribute("URI", "#" + rReference.ouURI);
+ m_xDocumentHandler->startElement(
+ "Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+ if (rReference.ouURI == "idSignedProperties")
+ {
+ m_xDocumentHandler->startElement(
+ "Transforms",
+ uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ writeCanonicalizationTransform();
+ m_xDocumentHandler->endElement("Transforms");
+ }
+
+ DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
+ m_xDocumentHandler->startElement(
+ "DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(rReference.ouDigestValue);
+ m_xDocumentHandler->endElement("DigestValue");
+ m_xDocumentHandler->endElement("Reference");
+ }
+ }
+}
+
+void OOXMLSecExporter::Impl::writeSignatureValue()
+{
+ m_xDocumentHandler->startElement(
+ "SignatureValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(m_rInformation.ouSignatureValue);
+ m_xDocumentHandler->endElement("SignatureValue");
+}
+
+void OOXMLSecExporter::Impl::writeKeyInfo()
+{
+ m_xDocumentHandler->startElement(
+ "KeyInfo", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->startElement(
+ "X509Data", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->startElement(
+ "X509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(m_rInformation.ouX509Certificate);
+ m_xDocumentHandler->endElement("X509Certificate");
+ m_xDocumentHandler->endElement("X509Data");
+ m_xDocumentHandler->endElement("KeyInfo");
+}
+
+void OOXMLSecExporter::Impl::writePackageObject()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idPackageObject");
+ m_xDocumentHandler->startElement(
+ "Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+ writeManifest();
+ writePackageObjectSignatureProperties();
+
+ m_xDocumentHandler->endElement("Object");
+}
+
+void OOXMLSecExporter::Impl::writeManifest()
+{
+ m_xDocumentHandler->startElement(
+ "Manifest", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ const SignatureReferenceInformations& rReferences = m_rInformation.vSignatureReferenceInfors;
+ for (const SignatureReferenceInformation& rReference : rReferences)
+ {
+ if (rReference.nType != SignatureReferenceType::SAMEDOCUMENT)
+ {
+ if (OOXMLSecExporter::Impl::isOOXMLBlacklist(rReference.ouURI))
+ continue;
+
+ writeManifestReference(rReference);
+ }
+ }
+ m_xDocumentHandler->endElement("Manifest");
+}
+
+void OOXMLSecExporter::Impl::writeRelationshipTransform(const OUString& rURI)
+{
+ uno::Reference<embed::XHierarchicalStorageAccess> xHierarchicalStorageAccess(m_xRootStorage,
+ uno::UNO_QUERY);
+ uno::Reference<io::XInputStream> xRelStream(
+ xHierarchicalStorageAccess->openStreamElementByHierarchicalName(rURI,
+ embed::ElementModes::READ),
+ uno::UNO_QUERY);
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Algorithm", ALGO_RELATIONSHIP);
+ m_xDocumentHandler->startElement(
+ "Transform", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+
+ const uno::Sequence<uno::Sequence<beans::StringPair>> aRelationsInfo
+ = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, rURI,
+ m_xComponentContext);
+ for (const uno::Sequence<beans::StringPair>& rPairs : aRelationsInfo)
+ {
+ OUString aId;
+ OUString aType;
+ for (const beans::StringPair& rPair : rPairs)
+ {
+ if (rPair.First == "Id")
+ aId = rPair.Second;
+ else if (rPair.First == "Type")
+ aType = rPair.Second;
+ }
+
+ if (OOXMLSecExporter::Impl::isOOXMLRelationBlacklist(aType))
+ continue;
+
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
+ pAttributeList->AddAttribute("SourceId", aId);
+ m_xDocumentHandler->startElement(
+ "mdssi:RelationshipReference",
+ uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ m_xDocumentHandler->endElement("mdssi:RelationshipReference");
+ }
+
+ m_xDocumentHandler->endElement("Transform");
+}
+
+void OOXMLSecExporter::Impl::writePackageObjectSignatureProperties()
+{
+ m_xDocumentHandler->startElement(
+ "SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idSignatureTime");
+ pAttributeList->AddAttribute("Target", "#idPackageSignature");
+ m_xDocumentHandler->startElement(
+ "SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("xmlns:mdssi", NS_MDSSI);
+ m_xDocumentHandler->startElement(
+ "mdssi:SignatureTime", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+ m_xDocumentHandler->startElement(
+ "mdssi:Format", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("YYYY-MM-DDThh:mm:ssTZD");
+ m_xDocumentHandler->endElement("mdssi:Format");
+
+ m_xDocumentHandler->startElement(
+ "mdssi:Value", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ if (!m_rInformation.ouDateTime.isEmpty())
+ m_aSignatureTimeValue = m_rInformation.ouDateTime;
+ else
+ {
+ m_aSignatureTimeValue = utl::toISO8601(m_rInformation.stDateTime);
+ // Ignore sub-seconds.
+ sal_Int32 nCommaPos = m_aSignatureTimeValue.indexOf(',');
+ if (nCommaPos != -1)
+ {
+ m_aSignatureTimeValue = m_aSignatureTimeValue.copy(0, nCommaPos);
+ m_aSignatureTimeValue += "Z";
+ }
+ }
+ m_xDocumentHandler->characters(m_aSignatureTimeValue);
+ m_xDocumentHandler->endElement("mdssi:Value");
+
+ m_xDocumentHandler->endElement("mdssi:SignatureTime");
+ m_xDocumentHandler->endElement("SignatureProperty");
+ m_xDocumentHandler->endElement("SignatureProperties");
+}
+
+void OOXMLSecExporter::Impl::writeManifestReference(const SignatureReferenceInformation& rReference)
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("URI", rReference.ouURI);
+ m_xDocumentHandler->startElement(
+ "Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+ // Transforms
+ if (rReference.ouURI.endsWith(
+ "?ContentType=application/vnd.openxmlformats-package.relationships+xml"))
+ {
+ OUString aURI = rReference.ouURI;
+ // Ignore leading slash.
+ if (aURI.startsWith("/"))
+ aURI = aURI.copy(1);
+ // Ignore query part of the URI.
+ sal_Int32 nQueryPos = aURI.indexOf('?');
+ if (nQueryPos != -1)
+ aURI = aURI.copy(0, nQueryPos);
+
+ m_xDocumentHandler->startElement(
+ "Transforms", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+ writeRelationshipTransform(aURI);
+ writeCanonicalizationTransform();
+
+ m_xDocumentHandler->endElement("Transforms");
+ }
+
+ DocumentSignatureHelper::writeDigestMethod(m_xDocumentHandler);
+ m_xDocumentHandler->startElement(
+ "DigestValue", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(rReference.ouDigestValue);
+ m_xDocumentHandler->endElement("DigestValue");
+ m_xDocumentHandler->endElement("Reference");
+}
+
+void OOXMLSecExporter::Impl::writeOfficeObject()
+{
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idOfficeObject");
+ m_xDocumentHandler->startElement(
+ "Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+ m_xDocumentHandler->startElement(
+ "SignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idOfficeV1Details");
+ pAttributeList->AddAttribute("Target", "#idPackageSignature");
+ m_xDocumentHandler->startElement(
+ "SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+ writeSignatureInfo();
+ m_xDocumentHandler->endElement("SignatureProperty");
+ m_xDocumentHandler->endElement("SignatureProperties");
+ m_xDocumentHandler->endElement("Object");
+}
+
+void OOXMLSecExporter::Impl::writeSignatureInfo()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("xmlns", "http://schemas.microsoft.com/office/2006/digsig");
+ m_xDocumentHandler->startElement(
+ "SignatureInfoV1", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+ m_xDocumentHandler->startElement(
+ "SetupID", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(m_rInformation.ouSignatureLineId);
+ m_xDocumentHandler->endElement("SetupID");
+ m_xDocumentHandler->startElement(
+ "SignatureText", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->endElement("SignatureText");
+ m_xDocumentHandler->startElement(
+ "SignatureImage", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->endElement("SignatureImage");
+ m_xDocumentHandler->startElement(
+ "SignatureComments", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(m_rInformation.ouDescription);
+ m_xDocumentHandler->endElement("SignatureComments");
+ // Just hardcode something valid according to [MS-OFFCRYPTO].
+ m_xDocumentHandler->startElement(
+ "WindowsVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("6.1");
+ m_xDocumentHandler->endElement("WindowsVersion");
+ m_xDocumentHandler->startElement(
+ "OfficeVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("16.0");
+ m_xDocumentHandler->endElement("OfficeVersion");
+ m_xDocumentHandler->startElement(
+ "ApplicationVersion", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("16.0");
+ m_xDocumentHandler->endElement("ApplicationVersion");
+ m_xDocumentHandler->startElement(
+ "Monitors", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("1");
+ m_xDocumentHandler->endElement("Monitors");
+ m_xDocumentHandler->startElement(
+ "HorizontalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("1280");
+ m_xDocumentHandler->endElement("HorizontalResolution");
+ m_xDocumentHandler->startElement(
+ "VerticalResolution", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("800");
+ m_xDocumentHandler->endElement("VerticalResolution");
+ m_xDocumentHandler->startElement(
+ "ColorDepth", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("32");
+ m_xDocumentHandler->endElement("ColorDepth");
+ m_xDocumentHandler->startElement(
+ "SignatureProviderId", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("{00000000-0000-0000-0000-000000000000}");
+ m_xDocumentHandler->endElement("SignatureProviderId");
+ m_xDocumentHandler->startElement(
+ "SignatureProviderUrl", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->endElement("SignatureProviderUrl");
+ m_xDocumentHandler->startElement(
+ "SignatureProviderDetails",
+ uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters(
+ "9"); // This is what MSO 2016 writes, though [MS-OFFCRYPTO] doesn't document what the value means.
+ m_xDocumentHandler->endElement("SignatureProviderDetails");
+ m_xDocumentHandler->startElement(
+ "SignatureType", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ m_xDocumentHandler->characters("2");
+ m_xDocumentHandler->endElement("SignatureType");
+
+ m_xDocumentHandler->endElement("SignatureInfoV1");
+}
+
+void OOXMLSecExporter::Impl::writePackageSignature()
+{
+ m_xDocumentHandler->startElement(
+ "Object", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("xmlns:xd", NS_XD);
+ pAttributeList->AddAttribute("Target", "#idPackageSignature");
+ m_xDocumentHandler->startElement(
+ "xd:QualifyingProperties",
+ uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+
+ DocumentSignatureHelper::writeSignedProperties(m_xDocumentHandler, m_rInformation,
+ m_aSignatureTimeValue, false);
+
+ m_xDocumentHandler->endElement("xd:QualifyingProperties");
+ m_xDocumentHandler->endElement("Object");
+}
+
+void OOXMLSecExporter::Impl::writeSignatureLineImages()
+{
+ if (m_rInformation.aValidSignatureImage.is())
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idValidSigLnImg");
+ m_xDocumentHandler->startElement(
+ "Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ OUString aGraphicInBase64;
+ Graphic aGraphic(m_rInformation.aValidSignatureImage);
+ if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64, false, ConvertDataFormat::EMF))
+ SAL_WARN("xmlsecurity.helper", "could not convert graphic to base64");
+ m_xDocumentHandler->characters(aGraphicInBase64);
+ m_xDocumentHandler->endElement("Object");
+ }
+ if (m_rInformation.aInvalidSignatureImage.is())
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idInvalidSigLnImg");
+ m_xDocumentHandler->startElement(
+ "Object", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ OUString aGraphicInBase64;
+ Graphic aGraphic(m_rInformation.aInvalidSignatureImage);
+ if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64, false, ConvertDataFormat::EMF))
+ SAL_WARN("xmlsecurity.helper", "could not convert graphic to base64");
+ m_xDocumentHandler->characters(aGraphicInBase64);
+ m_xDocumentHandler->endElement("Object");
+ }
+}
+
+OOXMLSecExporter::OOXMLSecExporter(
+ const uno::Reference<uno::XComponentContext>& xComponentContext,
+ const uno::Reference<embed::XStorage>& xRootStorage,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& rInformation)
+ : m_pImpl(
+ std::make_unique<Impl>(xComponentContext, xRootStorage, xDocumentHandler, rInformation))
+{
+}
+
+OOXMLSecExporter::~OOXMLSecExporter() = default;
+
+void OOXMLSecExporter::writeSignature()
+{
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("xmlns", NS_XMLDSIG);
+ pAttributeList->AddAttribute("Id", "idPackageSignature");
+ m_pImpl->getDocumentHandler()->startElement(
+ "Signature", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+
+ m_pImpl->writeSignedInfo();
+ m_pImpl->writeSignatureValue();
+ m_pImpl->writeKeyInfo();
+ m_pImpl->writePackageObject();
+ m_pImpl->writeOfficeObject();
+ m_pImpl->writePackageSignature();
+ m_pImpl->writeSignatureLineImages();
+
+ m_pImpl->getDocumentHandler()->endElement("Signature");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.hxx b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
new file mode 100644
index 000000000..5d94da2fd
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
@@ -0,0 +1,59 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECEXPORTER_HXX
+#define INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECEXPORTER_HXX
+
+#include <memory>
+
+#include <svl/sigstruct.hxx>
+
+namespace com
+{
+namespace sun
+{
+namespace star
+{
+namespace embed
+{
+class XStorage;
+}
+namespace uno
+{
+class XComponentContext;
+}
+namespace xml
+{
+namespace sax
+{
+class XDocumentHandler;
+}
+}
+}
+}
+}
+
+/// Writes a single OOXML digital signature.
+class OOXMLSecExporter
+{
+ struct Impl;
+ std::unique_ptr<Impl> m_pImpl;
+
+public:
+ OOXMLSecExporter(const css::uno::Reference<css::uno::XComponentContext>& xComponentContext,
+ const css::uno::Reference<css::embed::XStorage>& xRootStorage,
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& rInformation);
+ ~OOXMLSecExporter();
+ void writeSignature();
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
new file mode 100644
index 000000000..c22e8c226
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -0,0 +1,293 @@
+/* -*- 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/.
+ */
+
+
+#include "ooxmlsecparser.hxx"
+#include <xmlsignaturehelper.hxx>
+#include <xsecctl.hxx>
+#include <sal/log.hxx>
+
+using namespace com::sun::star;
+
+OOXMLSecParser::OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController)
+ : m_pXSecController(pXSecController)
+ ,m_bInDigestValue(false)
+ ,m_bInSignatureValue(false)
+ ,m_bInX509Certificate(false)
+ ,m_bInMdssiValue(false)
+ ,m_bInSignatureComments(false)
+ ,m_bInX509IssuerName(false)
+ ,m_bInX509SerialNumber(false)
+ ,m_bInCertDigest(false)
+ ,m_bInValidSignatureImage(false)
+ ,m_bInInvalidSignatureImage(false)
+ ,m_bInSignatureLineId(false)
+ ,m_bReferenceUnresolved(false)
+ ,m_rXMLSignatureHelper(rXMLSignatureHelper)
+{
+}
+
+OOXMLSecParser::~OOXMLSecParser()
+{
+}
+
+void SAL_CALL OOXMLSecParser::startDocument()
+{
+ if (m_xNextHandler.is())
+ m_xNextHandler->startDocument();
+}
+
+void SAL_CALL OOXMLSecParser::endDocument()
+{
+ if (m_xNextHandler.is())
+ m_xNextHandler->endDocument();
+}
+
+void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& xAttribs)
+{
+ OUString aId = xAttribs->getValueByName("Id");
+ if (!aId.isEmpty())
+ m_pXSecController->collectToVerify(aId);
+
+ if (rName == "Signature")
+ {
+ m_rXMLSignatureHelper.StartVerifySignatureElement();
+ m_pXSecController->addSignature();
+ if (!aId.isEmpty())
+ m_pXSecController->setId(aId);
+ }
+ else if (rName == "SignatureMethod")
+ {
+ OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
+ if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
+ || ouAlgorithm == ALGO_ECDSASHA512)
+ m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
+ }
+ else if (rName == "Reference")
+ {
+ OUString aURI = xAttribs->getValueByName("URI");
+ if (aURI.startsWith("#"))
+ m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1, OUString());
+ else
+ {
+ m_aReferenceURI = aURI;
+ m_bReferenceUnresolved = true;
+ }
+ }
+ else if (rName == "Transform")
+ {
+ if (m_bReferenceUnresolved)
+ {
+ OUString aAlgorithm = xAttribs->getValueByName("Algorithm");
+ if (aAlgorithm == ALGO_RELATIONSHIP)
+ {
+ m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256);
+ m_bReferenceUnresolved = false;
+ }
+ }
+ }
+ else if (rName == "DigestValue" && !m_bInCertDigest)
+ {
+ m_aDigestValue.clear();
+ m_bInDigestValue = true;
+ }
+ else if (rName == "SignatureValue")
+ {
+ m_aSignatureValue.clear();
+ m_bInSignatureValue = true;
+ }
+ else if (rName == "X509Certificate")
+ {
+ m_aX509Certificate.clear();
+ m_bInX509Certificate = true;
+ }
+ else if (rName == "mdssi:Value")
+ {
+ m_aMdssiValue.clear();
+ m_bInMdssiValue = true;
+ }
+ else if (rName == "SignatureComments")
+ {
+ m_aSignatureComments.clear();
+ m_bInSignatureComments = true;
+ }
+ else if (rName == "X509IssuerName")
+ {
+ m_aX509IssuerName.clear();
+ m_bInX509IssuerName = true;
+ }
+ else if (rName == "X509SerialNumber")
+ {
+ m_aX509SerialNumber.clear();
+ m_bInX509SerialNumber = true;
+ }
+ else if (rName == "xd:CertDigest")
+ {
+ m_aCertDigest.clear();
+ m_bInCertDigest = true;
+ }
+ else if (rName == "Object")
+ {
+ OUString sId = xAttribs->getValueByName("Id");
+ if (sId == "idValidSigLnImg")
+ {
+ m_aValidSignatureImage.clear();
+ m_bInValidSignatureImage = true;
+ }
+ else if (sId == "idInvalidSigLnImg")
+ {
+ m_aInvalidSignatureImage.clear();
+ m_bInInvalidSignatureImage = true;
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.ooxml", "Unknown 'Object' child element: " << rName);
+ }
+ }
+ else if (rName == "SetupID")
+ {
+ m_aSignatureLineId.clear();
+ m_bInSignatureLineId = true;
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.ooxml", "Unknown xml element: " << rName);
+ }
+
+ if (m_xNextHandler.is())
+ m_xNextHandler->startElement(rName, xAttribs);
+}
+
+void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
+{
+ if (rName == "SignedInfo")
+ m_pXSecController->setReferenceCount();
+ else if (rName == "Reference")
+ {
+ if (m_bReferenceUnresolved)
+ {
+ // No transform algorithm found, assume binary.
+ m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256);
+ m_bReferenceUnresolved = false;
+ }
+ m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, m_aDigestValue);
+ }
+ else if (rName == "DigestValue" && !m_bInCertDigest)
+ m_bInDigestValue = false;
+ else if (rName == "SignatureValue")
+ {
+ m_pXSecController->setSignatureValue(m_aSignatureValue);
+ m_bInSignatureValue = false;
+ }
+ else if (rName == "X509Certificate")
+ {
+ m_pXSecController->setX509Certificate(m_aX509Certificate);
+ m_bInX509Certificate = false;
+ }
+ else if (rName == "mdssi:Value")
+ {
+ m_pXSecController->setDate(m_aMdssiValue);
+ m_bInMdssiValue = false;
+ }
+ else if (rName == "SignatureComments")
+ {
+ m_pXSecController->setDescription(m_aSignatureComments);
+ m_bInSignatureComments = false;
+ }
+ else if (rName == "X509IssuerName")
+ {
+ m_pXSecController->setX509IssuerName(m_aX509IssuerName);
+ m_bInX509IssuerName = false;
+ }
+ else if (rName == "X509SerialNumber")
+ {
+ m_pXSecController->setX509SerialNumber(m_aX509SerialNumber);
+ m_bInX509SerialNumber = false;
+ }
+ else if (rName == "xd:CertDigest")
+ {
+ m_pXSecController->setCertDigest(m_aCertDigest);
+ m_bInCertDigest = false;
+ }
+ else if (rName == "Object")
+ {
+ if (m_bInValidSignatureImage)
+ {
+ m_pXSecController->setValidSignatureImage(m_aValidSignatureImage);
+ m_bInValidSignatureImage = false;
+ }
+ else if (m_bInInvalidSignatureImage)
+ {
+ m_pXSecController->setInvalidSignatureImage(m_aInvalidSignatureImage);
+ m_bInInvalidSignatureImage = false;
+ }
+ }
+ else if (rName == "SetupID")
+ {
+ m_pXSecController->setSignatureLineId(m_aSignatureLineId);
+ m_bInSignatureLineId = false;
+ }
+
+ if (m_xNextHandler.is())
+ m_xNextHandler->endElement(rName);
+}
+
+void SAL_CALL OOXMLSecParser::characters(const OUString& rChars)
+{
+ if (m_bInDigestValue && !m_bInCertDigest)
+ m_aDigestValue += rChars;
+ else if (m_bInSignatureValue)
+ m_aSignatureValue += rChars;
+ else if (m_bInX509Certificate)
+ m_aX509Certificate += rChars;
+ else if (m_bInMdssiValue)
+ m_aMdssiValue += rChars;
+ else if (m_bInSignatureComments)
+ m_aSignatureComments += rChars;
+ else if (m_bInX509IssuerName)
+ m_aX509IssuerName += rChars;
+ else if (m_bInX509SerialNumber)
+ m_aX509SerialNumber += rChars;
+ else if (m_bInCertDigest)
+ m_aCertDigest += rChars;
+ else if (m_bInValidSignatureImage)
+ m_aValidSignatureImage += rChars;
+ else if (m_bInInvalidSignatureImage)
+ m_aInvalidSignatureImage += rChars;
+ else if (m_bInSignatureLineId)
+ m_aSignatureLineId += rChars;
+
+ if (m_xNextHandler.is())
+ m_xNextHandler->characters(rChars);
+}
+
+void SAL_CALL OOXMLSecParser::ignorableWhitespace(const OUString& rWhitespace)
+{
+ if (m_xNextHandler.is())
+ m_xNextHandler->ignorableWhitespace(rWhitespace);
+}
+
+void SAL_CALL OOXMLSecParser::processingInstruction(const OUString& rTarget, const OUString& rData)
+{
+ if (m_xNextHandler.is())
+ m_xNextHandler->processingInstruction(rTarget, rData);
+}
+
+void SAL_CALL OOXMLSecParser::setDocumentLocator(const uno::Reference<xml::sax::XLocator>& xLocator)
+{
+ if (m_xNextHandler.is())
+ m_xNextHandler->setDocumentLocator(xLocator);
+}
+
+void SAL_CALL OOXMLSecParser::initialize(const uno::Sequence<uno::Any>& rArguments)
+{
+ rArguments[0] >>= m_xNextHandler;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.hxx b/xmlsecurity/source/helper/ooxmlsecparser.hxx
new file mode 100644
index 000000000..d3c199147
--- /dev/null
+++ b/xmlsecurity/source/helper/ooxmlsecparser.hxx
@@ -0,0 +1,87 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECPARSER_HXX
+#define INCLUDED_XMLSECURITY_SOURCE_HELPER_OOXMLSECPARSER_HXX
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+class XSecController;
+class XMLSignatureHelper;
+
+/// Parses an OOXML digital signature.
+class OOXMLSecParser: public cppu::WeakImplHelper
+ <
+ css::xml::sax::XDocumentHandler,
+ css::lang::XInitialization
+ >
+{
+ XSecController* m_pXSecController;
+ css::uno::Reference<css::xml::sax::XDocumentHandler> m_xNextHandler;
+
+ bool m_bInDigestValue;
+ OUString m_aDigestValue;
+ bool m_bInSignatureValue;
+ OUString m_aSignatureValue;
+ bool m_bInX509Certificate;
+ OUString m_aX509Certificate;
+ bool m_bInMdssiValue;
+ OUString m_aMdssiValue;
+ bool m_bInSignatureComments;
+ OUString m_aSignatureComments;
+ bool m_bInX509IssuerName;
+ OUString m_aX509IssuerName;
+ bool m_bInX509SerialNumber;
+ OUString m_aX509SerialNumber;
+ bool m_bInCertDigest;
+ OUString m_aCertDigest;
+ bool m_bInValidSignatureImage;
+ OUString m_aValidSignatureImage;
+ bool m_bInInvalidSignatureImage;
+ OUString m_aInvalidSignatureImage;
+ bool m_bInSignatureLineId;
+ OUString m_aSignatureLineId;
+
+ /// Last seen <Reference URI="...">.
+ OUString m_aReferenceURI;
+ /// Already called addStreamReference() for this reference.
+ bool m_bReferenceUnresolved;
+ XMLSignatureHelper& m_rXMLSignatureHelper;
+
+public:
+ explicit OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController);
+ virtual ~OOXMLSecParser() override;
+
+ // XDocumentHandler
+ virtual void SAL_CALL startDocument() override;
+
+ virtual void SAL_CALL endDocument() override;
+
+ virtual void SAL_CALL startElement(const OUString& aName, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override;
+
+ virtual void SAL_CALL endElement(const OUString& aName) override;
+
+ virtual void SAL_CALL characters(const OUString& aChars) override;
+
+ virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces) override;
+
+ virtual void SAL_CALL processingInstruction(const OUString& aTarget, const OUString& aData) override;
+
+ virtual void SAL_CALL setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator>& xLocator) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
new file mode 100644
index 000000000..b0795cb8f
--- /dev/null
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
@@ -0,0 +1,187 @@
+/* -*- 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/.
+ */
+
+#include <pdfsignaturehelper.hxx>
+
+#include <memory>
+
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+#include <com/sun/star/uno/SecurityException.hpp>
+#include <com/sun/star/security/DocumentSignatureInformation.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <vcl/filter/pdfdocument.hxx>
+
+#include <pdfio/pdfdocument.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+
+PDFSignatureHelper::PDFSignatureHelper() = default;
+
+bool PDFSignatureHelper::ReadAndVerifySignature(
+ const uno::Reference<io::XInputStream>& xInputStream)
+{
+ if (!xInputStream.is())
+ {
+ SAL_WARN("xmlsecurity.helper", "input stream missing");
+ return false;
+ }
+
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ vcl::filter::PDFDocument aDocument;
+ if (!aDocument.Read(*pStream))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to read the document");
+ return false;
+ }
+
+ std::vector<vcl::filter::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets();
+ if (aSignatures.empty())
+ return true;
+
+ m_aSignatureInfos.clear();
+
+ int nMDPPerm = aDocument.GetMDPPerm();
+
+ for (size_t i = 0; i < aSignatures.size(); ++i)
+ {
+ SignatureInformation aInfo(i);
+
+ if (!xmlsecurity::pdfio::ValidateSignature(*pStream, aSignatures[i], aInfo, aDocument,
+ nMDPPerm))
+ SAL_WARN("xmlsecurity.helper", "failed to determine digest match");
+
+ m_aSignatureInfos.push_back(aInfo);
+ }
+
+ return true;
+}
+
+SignatureInformations const& PDFSignatureHelper::GetSignatureInformations() const
+{
+ return m_aSignatureInfos;
+}
+
+uno::Sequence<security::DocumentSignatureInformation>
+PDFSignatureHelper::GetDocumentSignatureInformations(
+ const uno::Reference<xml::crypto::XSecurityEnvironment>& xSecEnv) const
+{
+ uno::Sequence<security::DocumentSignatureInformation> aRet(m_aSignatureInfos.size());
+
+ for (size_t i = 0; i < m_aSignatureInfos.size(); ++i)
+ {
+ const SignatureInformation& rInternal = m_aSignatureInfos[i];
+ security::DocumentSignatureInformation& rExternal = aRet[i];
+ rExternal.SignatureIsValid
+ = rInternal.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+ if (!rInternal.ouX509Certificate.isEmpty())
+ rExternal.Signer = xSecEnv->createCertificateFromAscii(rInternal.ouX509Certificate);
+ rExternal.PartialDocumentSignature = rInternal.bPartialDocumentSignature;
+
+ // Verify certificate.
+ if (rExternal.Signer.is())
+ {
+ try
+ {
+ rExternal.CertificateStatus = xSecEnv->verifyCertificate(rExternal.Signer, {});
+ }
+ catch (const uno::SecurityException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper", "failed to verify certificate");
+ rExternal.CertificateStatus = security::CertificateValidity::INVALID;
+ }
+ }
+ else
+ rExternal.CertificateStatus = security::CertificateValidity::INVALID;
+ }
+
+ return aRet;
+}
+
+sal_Int32 PDFSignatureHelper::GetNewSecurityId() const { return m_aSignatureInfos.size(); }
+
+void PDFSignatureHelper::SetX509Certificate(
+ const uno::Reference<security::XCertificate>& xCertificate)
+{
+ m_xCertificate = xCertificate;
+}
+
+void PDFSignatureHelper::SetDescription(const OUString& rDescription)
+{
+ m_aDescription = rDescription;
+}
+
+bool PDFSignatureHelper::Sign(const uno::Reference<io::XInputStream>& xInputStream, bool bAdES)
+{
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ vcl::filter::PDFDocument aDocument;
+ if (!aDocument.Read(*pStream))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to read the document");
+ return false;
+ }
+
+ if (!aDocument.Sign(m_xCertificate, m_aDescription, bAdES))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to sign");
+ return false;
+ }
+
+ uno::Reference<io::XStream> xStream(xInputStream, uno::UNO_QUERY);
+ std::unique_ptr<SvStream> pOutStream(utl::UcbStreamHelper::CreateStream(xStream, true));
+ if (!aDocument.Write(*pOutStream))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to write signed data");
+ return false;
+ }
+
+ return true;
+}
+
+bool PDFSignatureHelper::RemoveSignature(const uno::Reference<io::XInputStream>& xInputStream,
+ sal_uInt16 nPosition)
+{
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ vcl::filter::PDFDocument aDocument;
+ if (!aDocument.Read(*pStream))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to read the document");
+ return false;
+ }
+
+ if (!aDocument.RemoveSignature(nPosition))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to remove signature");
+ return false;
+ }
+
+ uno::Reference<io::XStream> xStream(xInputStream, uno::UNO_QUERY);
+ uno::Reference<io::XTruncate> xTruncate(xStream, uno::UNO_QUERY);
+ if (!xTruncate.is())
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to truncate");
+ return false;
+ }
+ xTruncate->truncate();
+ std::unique_ptr<SvStream> pOutStream(utl::UcbStreamHelper::CreateStream(xStream, true));
+ if (!aDocument.Write(*pOutStream))
+ {
+ SAL_WARN("xmlsecurity.helper", "failed to write without signature");
+ return false;
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
new file mode 100644
index 000000000..6ec834053
--- /dev/null
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -0,0 +1,549 @@
+/* -*- 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 <xmlsignaturehelper.hxx>
+#include <documentsignaturehelper.hxx>
+#include <xsecctl.hxx>
+
+#include <xmlsignaturehelper2.hxx>
+
+#include <tools/datetime.hxx>
+
+#include <xmloff/attrlist.hxx>
+
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+
+#include <comphelper/ofopxmlhelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+#define NS_DOCUMENTSIGNATURES "http://openoffice.org/2004/documentsignatures"
+#define NS_DOCUMENTSIGNATURES_ODF_1_2 "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"
+#define OOXML_SIGNATURE_ORIGIN "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"
+#define OOXML_SIGNATURE_SIGNATURE "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::uno;
+
+XMLSignatureHelper::XMLSignatureHelper( const uno::Reference< uno::XComponentContext >& rxCtx)
+ : mxCtx(rxCtx), mbODFPre1_2(false)
+{
+ mpXSecController = new XSecController(rxCtx);
+ mbError = false;
+}
+
+XMLSignatureHelper::~XMLSignatureHelper()
+{
+}
+
+void XMLSignatureHelper::SetStorage(
+ const Reference < css::embed::XStorage >& rxStorage,
+ const OUString& sODFVersion)
+{
+ SAL_WARN_IF( mxUriBinding.is(), "xmlsecurity.helper", "SetStorage - UriBinding already set!" );
+ mxUriBinding = new UriBindingHelper( rxStorage );
+ SAL_WARN_IF(!rxStorage.is(), "xmlsecurity.helper", "SetStorage - empty storage!");
+ mbODFPre1_2 = DocumentSignatureHelper::isODFPre_1_2(sODFVersion);
+}
+
+
+void XMLSignatureHelper::SetStartVerifySignatureHdl( const Link<LinkParamNone*,bool>& rLink )
+{
+ maStartVerifySignatureHdl = rLink;
+}
+
+
+void XMLSignatureHelper::StartMission(const uno::Reference<xml::crypto::XXMLSecurityContext>& xSecurityContext)
+{
+ if ( !mxUriBinding.is() )
+ mxUriBinding = new UriBindingHelper();
+
+ mpXSecController->startMission(mxUriBinding, xSecurityContext);
+}
+
+void XMLSignatureHelper::EndMission()
+{
+ mpXSecController->endMission();
+}
+
+sal_Int32 XMLSignatureHelper::GetNewSecurityId()
+{
+ return mpXSecController->getNewSecurityId();
+}
+
+void XMLSignatureHelper::SetX509Certificate(
+ sal_Int32 nSecurityId,
+ const OUString& ouX509IssuerName,
+ const OUString& ouX509SerialNumber,
+ const OUString& ouX509Cert,
+ const OUString& ouX509CertDigest,
+ svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
+{
+ mpXSecController->setX509Certificate(
+ nSecurityId,
+ ouX509IssuerName,
+ ouX509SerialNumber,
+ ouX509Cert,
+ ouX509CertDigest,
+ eAlgorithmID);
+}
+
+void XMLSignatureHelper::AddEncapsulatedX509Certificate(const OUString& ouEncapsulatedX509Certificate)
+{
+ mpXSecController->addEncapsulatedX509Certificate(ouEncapsulatedX509Certificate);
+}
+
+void XMLSignatureHelper::SetGpgCertificate(sal_Int32 nSecurityId,
+ const OUString& ouGpgCertDigest,
+ const OUString& ouGpgCert,
+ const OUString& ouGpgOwner)
+{
+ mpXSecController->setGpgCertificate(
+ nSecurityId,
+ ouGpgCertDigest,
+ ouGpgCert,
+ ouGpgOwner);
+}
+
+void XMLSignatureHelper::SetDateTime( sal_Int32 nSecurityId, const ::DateTime& rDateTime )
+{
+ css::util::DateTime stDateTime = rDateTime.GetUNODateTime();
+ mpXSecController->setDate( nSecurityId, stDateTime );
+}
+
+void XMLSignatureHelper::SetDescription(sal_Int32 nSecurityId, const OUString& rDescription)
+{
+ mpXSecController->setDescription(nSecurityId, rDescription);
+}
+
+void XMLSignatureHelper::SetSignatureLineId(sal_Int32 nSecurityId, const OUString& rSignatureLineId)
+{
+ mpXSecController->setSignatureLineId(nSecurityId, rSignatureLineId);
+}
+
+void XMLSignatureHelper::SetSignatureLineValidGraphic(
+ sal_Int32 nSecurityId, const css::uno::Reference<XGraphic>& xValidGraphic)
+{
+ mpXSecController->setSignatureLineValidGraphic(nSecurityId, xValidGraphic);
+}
+
+void XMLSignatureHelper::SetSignatureLineInvalidGraphic(
+ sal_Int32 nSecurityId, const css::uno::Reference<XGraphic>& xInvalidGraphic)
+{
+ mpXSecController->setSignatureLineInvalidGraphic(nSecurityId, xInvalidGraphic);
+}
+
+void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, bool bBinary, bool bXAdESCompliantIfODF )
+{
+ mpXSecController->signAStream( nSecurityId, uri, bBinary, bXAdESCompliantIfODF );
+}
+
+
+uno::Reference<xml::sax::XWriter> XMLSignatureHelper::CreateDocumentHandlerWithHeader(
+ const css::uno::Reference< css::io::XOutputStream >& xOutputStream )
+{
+ /*
+ * get SAX writer component
+ */
+ uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(mxCtx);
+
+ /*
+ * connect XML writer to output stream
+ */
+ xSaxWriter->setOutputStream( xOutputStream );
+
+ /*
+ * write the xml context for signatures
+ */
+ SvXMLAttributeList *pAttributeList = new SvXMLAttributeList();
+ OUString sNamespace;
+ if (mbODFPre1_2)
+ sNamespace = NS_DOCUMENTSIGNATURES;
+ else
+ sNamespace = NS_DOCUMENTSIGNATURES_ODF_1_2;
+
+ pAttributeList->AddAttribute(
+ "xmlns",
+ sNamespace);
+
+ xSaxWriter->startDocument();
+ xSaxWriter->startElement(
+ "document-signatures",
+ uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+
+ return xSaxWriter;
+}
+
+void XMLSignatureHelper::CloseDocumentHandler( const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler )
+{
+ xDocumentHandler->endElement( "document-signatures" );
+ xDocumentHandler->endDocument();
+}
+
+void XMLSignatureHelper::ExportSignature(
+ const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler,
+ const SignatureInformation& signatureInfo,
+ bool bXAdESCompliantIfODF )
+{
+ XSecController::exportSignature(xDocumentHandler, signatureInfo, bXAdESCompliantIfODF);
+}
+
+void XMLSignatureHelper::ExportOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<embed::XStorage>& xSignatureStorage, const SignatureInformation& rInformation, int nSignatureIndex)
+{
+ uno::Reference<io::XOutputStream> xOutputStream(xSignatureStorage->openStreamElement("sig" + OUString::number(nSignatureIndex) + ".xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
+
+ if (rInformation.aSignatureBytes.hasElements())
+ // This is a signature roundtrip, just write back the signature as-is.
+ xOutputStream->writeBytes(rInformation.aSignatureBytes);
+ else
+ {
+ uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(mxCtx);
+ xSaxWriter->setOutputStream(xOutputStream);
+ xSaxWriter->startDocument();
+
+ mpXSecController->exportOOXMLSignature(xRootStorage, xSaxWriter, rInformation);
+
+ xSaxWriter->endDocument();
+ }
+}
+
+void XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF )
+{
+ mbError = false;
+
+ if ( !mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) )
+ {
+ mbError = true;
+ }
+}
+
+bool XMLSignatureHelper::ReadAndVerifySignature( const css::uno::Reference< css::io::XInputStream >& xInputStream )
+{
+ mbError = false;
+
+ SAL_WARN_IF(!xInputStream.is(), "xmlsecurity.helper", "input stream missing");
+
+ // prepare ParserInputSrouce
+ xml::sax::InputSource aParserInput;
+ aParserInput.aInputStream = xInputStream;
+
+ // get SAX parser component
+ uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(mxCtx);
+
+ // create a signature reader
+ uno::Reference< xml::sax::XDocumentHandler > xHandler
+ = mpXSecController->createSignatureReader(*this);
+
+ // setup the connection:
+ // Parser -> SignatureReader
+ xParser->setDocumentHandler( xHandler );
+
+ // parser the stream
+ try
+ {
+ xParser->parseStream( aParserInput );
+ }
+ catch( uno::Exception& )
+ {
+ mbError = true;
+ }
+
+ // release the signature reader
+ mpXSecController->releaseSignatureReader( );
+
+ return !mbError;
+}
+
+SignatureInformation XMLSignatureHelper::GetSignatureInformation( sal_Int32 nSecurityId ) const
+{
+ return mpXSecController->getSignatureInformation( nSecurityId );
+}
+
+SignatureInformations XMLSignatureHelper::GetSignatureInformations() const
+{
+ return mpXSecController->getSignatureInformations();
+}
+
+void XMLSignatureHelper::StartVerifySignatureElement()
+{
+ if ( !maStartVerifySignatureHdl.IsSet() || maStartVerifySignatureHdl.Call(nullptr) )
+ {
+ sal_Int32 nSignatureId = mpXSecController->getNewSecurityId();
+ mpXSecController->addSignature( nSignatureId );
+ }
+}
+
+namespace
+{
+bool lcl_isSignatureType(const beans::StringPair& rPair)
+{
+ return rPair.First == "Type" && rPair.Second == OOXML_SIGNATURE_SIGNATURE;
+}
+bool lcl_isSignatureOriginType(const beans::StringPair& rPair)
+{
+ return rPair.First == "Type" && rPair.Second == OOXML_SIGNATURE_ORIGIN;
+}
+}
+
+bool XMLSignatureHelper::ReadAndVerifySignatureStorage(const uno::Reference<embed::XStorage>& xStorage, bool bCacheLastSignature)
+{
+ sal_Int32 nOpenMode = embed::ElementModes::READ;
+ if (xStorage.is() && !xStorage->hasByName("_rels"))
+ {
+ SAL_WARN("xmlsecurity.helper", "expected stream, in signature storage but not found: _rels");
+ return false;
+ }
+
+ uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement("_rels", nOpenMode);
+ uno::Reference<io::XInputStream> xRelStream(xSubStorage->openStreamElement("origin.sigs.rels", nOpenMode), uno::UNO_QUERY);
+ uno::Sequence< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, "origin.sigs.rels", mxCtx);
+
+ for (sal_Int32 i = 0; i < aRelationsInfo.getLength(); ++i)
+ {
+ const uno::Sequence<beans::StringPair>& rRelation = aRelationsInfo[i];
+ auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rRelation);
+ if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureType))
+ {
+ std::vector<beans::StringPair>::iterator it = std::find_if(aRelation.begin(), aRelation.end(), [](const beans::StringPair& rPair) { return rPair.First == "Target"; });
+ if (it != aRelation.end())
+ {
+ if (xStorage.is() && !xStorage->hasByName(it->Second))
+ {
+ SAL_WARN("xmlsecurity.helper", "expected stream, but not found: " << it->Second);
+ continue;
+ }
+
+ uno::Reference<io::XInputStream> xInputStream(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
+ if (!ReadAndVerifySignatureStorageStream(xInputStream))
+ return false;
+
+ // By default, we cache. If it's requested, then we don't cache the last signature.
+ bool bCache = true;
+ if (!bCacheLastSignature && i == aRelationsInfo.getLength() - 1)
+ bCache = false;
+
+ if (!bCache)
+ continue;
+ // Store the contents of the stream as is, in case we need to write it back later.
+ xInputStream.clear();
+ xInputStream.set(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(xInputStream, uno::UNO_QUERY);
+ if (!xPropertySet.is())
+ continue;
+
+ sal_Int64 nSize = 0;
+ xPropertySet->getPropertyValue("Size") >>= nSize;
+ if (nSize < 0 || nSize > SAL_MAX_INT32)
+ {
+ SAL_WARN("xmlsecurity.helper", "bogus signature size: " << nSize);
+ continue;
+ }
+ uno::Sequence<sal_Int8> aData;
+ xInputStream->readBytes(aData, nSize);
+ mpXSecController->setSignatureBytes(aData);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Reference<css::io::XInputStream>& xInputStream)
+{
+ mbError = false;
+
+ // Create the input source.
+ xml::sax::InputSource aParserInput;
+ aParserInput.aInputStream = xInputStream;
+
+ // Create the sax parser.
+ uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(mxCtx);
+
+ // Create the signature reader.
+ uno::Reference<xml::sax::XDocumentHandler> xHandler = mpXSecController->createSignatureReader(*this, embed::StorageFormats::OFOPXML);
+
+ // Parser -> signature reader.
+ xParser->setDocumentHandler(xHandler);
+
+ // Parse the stream.
+ try
+ {
+ xParser->parseStream(aParserInput);
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
+ }
+
+ mpXSecController->releaseSignatureReader();
+
+ return !mbError;
+}
+
+void XMLSignatureHelper::EnsureSignaturesRelation(const css::uno::Reference<css::embed::XStorage>& xStorage, bool bAdd)
+{
+ sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
+ uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement("_rels", nOpenMode);
+ uno::Reference<io::XInputStream> xRelStream(xSubStorage->openStreamElement(".rels", nOpenMode), uno::UNO_QUERY);
+ std::vector< uno::Sequence<beans::StringPair> > aRelationsInfo = comphelper::sequenceToContainer< std::vector< uno::Sequence<beans::StringPair> > >(comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream, ".rels", mxCtx));
+
+ // Do we have a relation already?
+ bool bHaveRelation = false;
+ int nCount = 0;
+ for (const uno::Sequence<beans::StringPair>& rRelation : aRelationsInfo)
+ {
+ auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rRelation);
+ if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureOriginType))
+ {
+ bHaveRelation = true;
+ break;
+ }
+ ++nCount;
+ }
+
+ if (!bHaveRelation && bAdd)
+ {
+ // No, and have to add one.
+ std::vector<beans::StringPair> aRelation;
+ aRelation.emplace_back("Id", "rId" + OUString::number(++nCount));
+ aRelation.emplace_back("Type", OOXML_SIGNATURE_ORIGIN);
+ aRelation.emplace_back("Target", "_xmlsignatures/origin.sigs");
+ aRelationsInfo.push_back(comphelper::containerToSequence(aRelation));
+ }
+ else if (bHaveRelation && !bAdd)
+ {
+ // Yes, and need to remove it.
+ for (std::vector< uno::Sequence<beans::StringPair> >::iterator it = aRelationsInfo.begin(); it != aRelationsInfo.end();)
+ {
+ auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(*it);
+ if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureOriginType))
+ it = aRelationsInfo.erase(it);
+ else
+ ++it;
+ }
+ }
+
+ // Write it back.
+ uno::Reference<io::XTruncate> xTruncate(xRelStream, uno::UNO_QUERY);
+ xTruncate->truncate();
+ uno::Reference<io::XOutputStream> xOutputStream(xRelStream, uno::UNO_QUERY);
+ comphelper::OFOPXMLHelper::WriteRelationsInfoSequence(xOutputStream, comphelper::containerToSequence(aRelationsInfo), mxCtx);
+
+ // Commit it.
+ uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
+ xTransact->commit();
+ xTransact.set(xStorage, uno::UNO_QUERY);
+ xTransact->commit();
+}
+
+void XMLSignatureHelper::ExportSignatureRelations(const css::uno::Reference<css::embed::XStorage>& xStorage, int nSignatureCount)
+{
+ // Write the empty file, its relations will be the signatures.
+ sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
+ uno::Reference<io::XOutputStream> xOriginStream(xStorage->openStreamElement("origin.sigs", nOpenMode), uno::UNO_QUERY);
+ uno::Reference<io::XTruncate> xTruncate(xOriginStream, uno::UNO_QUERY);
+ xTruncate->truncate();
+ xOriginStream->closeOutput();
+
+ // Write the relations.
+ uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement("_rels", nOpenMode);
+ uno::Reference<io::XOutputStream> xRelStream(xSubStorage->openStreamElement("origin.sigs.rels", nOpenMode), uno::UNO_QUERY);
+ std::vector< uno::Sequence<beans::StringPair> > aRelations;
+ for (int i = 0; i < nSignatureCount; ++i)
+ {
+ std::vector<beans::StringPair> aRelation;
+ aRelation.emplace_back("Id", "rId" + OUString::number(i + 1));
+ aRelation.emplace_back("Type", OOXML_SIGNATURE_SIGNATURE);
+ aRelation.emplace_back("Target", "sig" + OUString::number(i + 1) + ".xml");
+ aRelations.push_back(comphelper::containerToSequence(aRelation));
+ }
+ comphelper::OFOPXMLHelper::WriteRelationsInfoSequence(xRelStream, comphelper::containerToSequence(aRelations), mxCtx);
+ uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
+ xTransact->commit();
+}
+
+void XMLSignatureHelper::ExportSignatureContentTypes(const css::uno::Reference<css::embed::XStorage>& xStorage, int nSignatureCount)
+{
+ uno::Reference<io::XStream> xStream = xStorage->openStreamElement("[Content_Types].xml", embed::ElementModes::READWRITE);
+ uno::Reference<io::XInputStream> xInputStream = xStream->getInputStream();
+ uno::Sequence< uno::Sequence<beans::StringPair> > aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, mxCtx);
+ if (aContentTypeInfo.getLength() < 2)
+ {
+ SAL_WARN("xmlsecurity.helper", "no defaults or overrides in aContentTypeInfo");
+ return;
+ }
+
+ // Append rels and sigs to defaults, if it's not there already.
+ uno::Sequence<beans::StringPair>& rDefaults = aContentTypeInfo[0];
+ auto aDefaults = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rDefaults);
+ if (std::none_of(rDefaults.begin(), rDefaults.end(), [](const beans::StringPair& rPair) { return rPair.First == "rels"; }))
+ aDefaults.emplace_back("rels", "application/vnd.openxmlformats-package.relationships+xml");
+
+ if (std::none_of(rDefaults.begin(), rDefaults.end(), [](const beans::StringPair& rPair) { return rPair.First == "sigs"; }))
+ aDefaults.emplace_back("sigs", "application/vnd.openxmlformats-package.digital-signature-origin");
+ rDefaults = comphelper::containerToSequence(aDefaults);
+
+ // Remove existing signature overrides.
+ uno::Sequence<beans::StringPair>& rOverrides = aContentTypeInfo[1];
+ auto aOverrides = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rOverrides);
+ aOverrides.erase(std::remove_if(aOverrides.begin(), aOverrides.end(), [](const beans::StringPair& rPair)
+ {
+ return rPair.First.startsWith("/_xmlsignatures/sig");
+ }), aOverrides.end());
+
+ // Add our signature overrides.
+ for (int i = 1; i <= nSignatureCount; ++i)
+ aOverrides.emplace_back("/_xmlsignatures/sig" + OUString::number(i) + ".xml", "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml");
+
+ rOverrides = comphelper::containerToSequence(aOverrides);
+ uno::Reference<io::XOutputStream> xOutputStream = xStream->getOutputStream();
+ uno::Reference <io::XTruncate> xTruncate(xOutputStream, uno::UNO_QUERY);
+ xTruncate->truncate();
+ comphelper::OFOPXMLHelper::WriteContentSequence(xOutputStream, rDefaults, rOverrides, mxCtx);
+ uno::Reference<embed::XTransactedObject> xTransact(xStorage, uno::UNO_QUERY);
+ xTransact->commit();
+}
+void XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<embed::XStorage>& xSignatureStorage, int nSignatureIndex)
+{
+ uno::Reference<io::XOutputStream> xOutputStream(xSignatureStorage->openStreamElement("sig" + OUString::number(nSignatureIndex) + ".xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
+ uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(mxCtx);
+ xSaxWriter->setOutputStream(xOutputStream);
+ xSaxWriter->startDocument();
+
+ mbError = false;
+ if (!mpXSecController->WriteOOXMLSignature(xRootStorage, xSaxWriter))
+ mbError = true;
+
+ xSaxWriter->endDocument();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper2.cxx b/xmlsecurity/source/helper/xmlsignaturehelper2.cxx
new file mode 100644
index 000000000..1a7a33459
--- /dev/null
+++ b/xmlsecurity/source/helper/xmlsignaturehelper2.cxx
@@ -0,0 +1,113 @@
+/* -*- 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 <xmlsignaturehelper2.hxx>
+
+#include <tools/solar.h>
+#include <unotools/streamhelper.hxx>
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <osl/diagnose.h>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+
+using namespace com::sun::star;
+
+// XUriBinding
+
+UriBindingHelper::UriBindingHelper()
+{
+}
+
+UriBindingHelper::UriBindingHelper( const css::uno::Reference < css::embed::XStorage >& rxStorage )
+{
+ mxStorage = rxStorage;
+}
+
+void SAL_CALL UriBindingHelper::setUriBinding( const OUString& /*uri*/, const uno::Reference< io::XInputStream >&)
+{
+}
+
+uno::Reference< io::XInputStream > SAL_CALL UriBindingHelper::getUriBinding( const OUString& uri )
+{
+ uno::Reference< io::XInputStream > xInputStream;
+ if ( mxStorage.is() )
+ {
+ xInputStream = OpenInputStream( mxStorage, uri );
+ }
+ else
+ {
+ SvFileStream* pStream = new SvFileStream( uri, StreamMode::READ );
+ sal_uInt64 nBytes = pStream->TellEnd();
+ SvLockBytesRef xLockBytes = new SvLockBytes( pStream, true );
+ xInputStream = new utl::OInputStreamHelper( xLockBytes, nBytes );
+ }
+ return xInputStream;
+}
+
+uno::Reference < io::XInputStream > UriBindingHelper::OpenInputStream( const uno::Reference < embed::XStorage >& rxStore, const OUString& rURI )
+{
+ OSL_ASSERT(!rURI.isEmpty());
+ uno::Reference < io::XInputStream > xInStream;
+
+ OUString aURI(rURI);
+ // Ignore leading slash, don't attempt to open a storage with name "".
+ if (aURI.startsWith("/"))
+ aURI = aURI.copy(1);
+ // Ignore query part of the URI.
+ sal_Int32 nQueryPos = aURI.indexOf('?');
+ if (nQueryPos != -1)
+ aURI = aURI.copy(0, nQueryPos);
+
+
+ sal_Int32 nSepPos = aURI.indexOf( '/' );
+ if ( nSepPos == -1 )
+ {
+ // Cloning because of I can't keep all storage references open
+ // MBA with think about a better API...
+ const OUString sName = ::rtl::Uri::decode(
+ aURI, rtl_UriDecodeStrict, rtl_UriCharClassRelSegment);
+ if (sName.isEmpty() && !aURI.isEmpty())
+ throw uno::Exception("Could not decode URI for stream element.", nullptr);
+
+ uno::Reference< io::XStream > xStream;
+ if (!rxStore->hasByName(sName))
+ SAL_WARN("xmlsecurity.helper", "expected stream, but not found: " << sName);
+ else
+ xStream = rxStore->cloneStreamElement( sName );
+ if ( !xStream.is() )
+ throw uno::RuntimeException();
+ xInStream = xStream->getInputStream();
+ }
+ else
+ {
+ const OUString aStoreName = ::rtl::Uri::decode(
+ aURI.copy( 0, nSepPos ), rtl_UriDecodeStrict, rtl_UriCharClassRelSegment);
+ if (aStoreName.isEmpty() && !aURI.isEmpty())
+ throw uno::Exception("Could not decode URI for stream element.", nullptr);
+
+ OUString aElement = aURI.copy( nSepPos+1 );
+ uno::Reference < embed::XStorage > xSubStore = rxStore->openStorageElement( aStoreName, embed::ElementModes::READ );
+ xInStream = OpenInputStream( xSubStore, aElement );
+ }
+ return xInStream;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx
new file mode 100644
index 000000000..cac30006b
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecctl.cxx
@@ -0,0 +1,986 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 <xsecctl.hxx>
+#include <documentsignaturehelper.hxx>
+#include <framework/saxeventkeeperimpl.hxx>
+#include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
+#if HAVE_FEATURE_GPGME
+# include <gpg/xmlsignature_gpgimpl.hxx>
+#endif
+
+#include <com/sun/star/xml/crypto/sax/XMissionTaker.hpp>
+#include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
+
+#include <xmloff/attrlist.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+#include <unotools/datetime.hxx>
+#include "ooxmlsecexporter.hxx"
+#include <xmlsignaturehelper2.hxx>
+
+using namespace com::sun::star;
+
+namespace
+{
+OUString getDigestURI(sal_Int32 nID)
+{
+ switch( nID )
+ {
+ case css::xml::crypto::DigestID::SHA1:
+ return ALGO_XMLDSIGSHA1;
+ case css::xml::crypto::DigestID::SHA256:
+ return ALGO_XMLDSIGSHA256;
+ case css::xml::crypto::DigestID::SHA512:
+ return ALGO_XMLDSIGSHA512;
+ default:
+ return ALGO_XMLDSIGSHA1;
+ }
+}
+OUString getSignatureURI(svl::crypto::SignatureMethodAlgorithm eAlgorithm, sal_Int32 nDigestID)
+{
+ OUString aRet;
+
+ if (eAlgorithm == svl::crypto::SignatureMethodAlgorithm::ECDSA)
+ {
+ switch (nDigestID)
+ {
+ case css::xml::crypto::DigestID::SHA1:
+ aRet = ALGO_ECDSASHA1;
+ break;
+ case css::xml::crypto::DigestID::SHA256:
+ aRet = ALGO_ECDSASHA256;
+ break;
+ case css::xml::crypto::DigestID::SHA512:
+ aRet = ALGO_ECDSASHA512;
+ break;
+ default:
+ aRet = ALGO_ECDSASHA1;
+ break;
+ }
+ }
+ if (!aRet.isEmpty())
+ return aRet;
+
+ switch (nDigestID)
+ {
+ case css::xml::crypto::DigestID::SHA1:
+ return ALGO_RSASHA1;
+ case css::xml::crypto::DigestID::SHA256:
+ return ALGO_RSASHA256;
+ case css::xml::crypto::DigestID::SHA512:
+ return ALGO_RSASHA512;
+ default:
+ return ALGO_RSASHA1;
+ }
+}
+}
+
+XSecController::XSecController( const css::uno::Reference<css::uno::XComponentContext>& rxCtx )
+ : mxCtx(rxCtx)
+ , m_nNextSecurityId(1)
+ , m_bIsPreviousNodeInitializable(false)
+ , m_bIsSAXEventKeeperConnected(false)
+ , m_bIsCollectingElement(false)
+ , m_bIsBlocking(false)
+ , m_eStatusOfSecurityComponents(InitializationState::UNINITIALIZED)
+ , m_bIsSAXEventKeeperSticky(false)
+ , m_nReservedSignatureId(0)
+ , m_bVerifyCurrentSignature(false)
+{
+}
+
+XSecController::~XSecController()
+{
+}
+
+
+/*
+ * private methods
+ */
+int XSecController::findSignatureInfor( sal_Int32 nSecurityId) const
+/****** XSecController/findSignatureInfor *************************************
+ *
+ * NAME
+ * findSignatureInfor -- find SignatureInformation struct for a particular
+ * signature
+ *
+ * SYNOPSIS
+ * index = findSignatureInfor( nSecurityId );
+ *
+ * INPUTS
+ * nSecurityId - the signature's id
+ *
+ * RESULT
+ * index - the index of the signature, or -1 when no such signature
+ * existing
+ ******************************************************************************/
+{
+ int i;
+ int size = m_vInternalSignatureInformations.size();
+
+ for (i=0; i<size; ++i)
+ {
+ if (m_vInternalSignatureInformations[i].signatureInfor.nSecurityId == nSecurityId)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void XSecController::createXSecComponent( )
+/****** XSecController/createXSecComponent ************************************
+ *
+ * NAME
+ * bResult = createXSecComponent -- creates xml security components
+ *
+ * FUNCTION
+ * Creates xml security components, including:
+ * 1. an xml signature bridge component
+ * 2. an XMLDocumentWrapper component
+ * 3. a SAXEventKeeper component
+ ******************************************************************************/
+{
+ /*
+ * marks all security components are not available.
+ */
+ m_eStatusOfSecurityComponents = InitializationState::FAILTOINITIALIZED;
+ m_xXMLSignature = nullptr;
+ m_xXMLDocumentWrapper = nullptr;
+ m_xSAXEventKeeper = nullptr;
+
+ css::uno::Reference< css::lang::XMultiComponentFactory > xMCF( mxCtx->getServiceManager() );
+
+#if HAVE_FEATURE_GPGME
+ uno::Reference< lang::XServiceInfo > xServiceInfo( m_xSecurityContext, css::uno::UNO_QUERY );
+ if (xServiceInfo->getImplementationName() == "com.sun.star.xml.security.gpg.XMLSecurityContext_GpgImpl")
+ m_xXMLSignature.set(new XMLSignature_GpgImpl());
+ else // xmlsec or mscrypt
+#endif
+ m_xXMLSignature.set(xMCF->createInstanceWithContext("com.sun.star.xml.crypto.XMLSignature", mxCtx), css::uno::UNO_QUERY);
+
+ bool bSuccess = m_xXMLSignature.is();
+ if ( bSuccess )
+ /*
+ * XMLSignature created successfully.
+ */
+ m_xXMLDocumentWrapper = new XMLDocumentWrapper_XmlSecImpl();
+
+ bSuccess &= m_xXMLDocumentWrapper.is();
+ if ( bSuccess )
+ m_xSAXEventKeeper = new SAXEventKeeperImpl();
+
+ bSuccess &= m_xSAXEventKeeper.is();
+
+ if (bSuccess)
+ /*
+ * SAXEventKeeper created successfully.
+ */
+ {
+ css::uno::Sequence <css::uno::Any> arg(1);
+ arg[0] <<= uno::Reference<xml::wrapper::XXMLDocumentWrapper>(m_xXMLDocumentWrapper.get());
+ m_xSAXEventKeeper->initialize(arg);
+
+ css::uno::Reference< css::xml::crypto::sax::XSAXEventKeeperStatusChangeListener >
+ xStatusChangeListener = this;
+
+ m_xSAXEventKeeper->addSAXEventKeeperStatusChangeListener( xStatusChangeListener );
+
+ m_eStatusOfSecurityComponents = InitializationState::INITIALIZED;
+ }
+}
+
+bool XSecController::chainOn()
+/****** XSecController/chainOn ************************************************
+ *
+ * NAME
+ * chainOn -- tries to connect the SAXEventKeeper with the SAX chain.
+ *
+ * SYNOPSIS
+ * bJustChainingOn = chainOn();
+ *
+ * FUNCTION
+ * First, checks whether the SAXEventKeeper is on the SAX chain. If not,
+ * creates xml security components, and chains the SAXEventKeeper into
+ * the SAX chain.
+ * Before being chained in, the SAXEventKeeper needs to receive all
+ * missed key SAX events, which can promise the DOM tree buffered by the
+ * SAXEventKeeper has the same structure with the original document.
+ *
+ * RESULT
+ * bJustChainingOn - whether the SAXEventKeeper is just chained into the
+ * SAX chain.
+ *
+ * NOTES
+ * Sometimes, the last key SAX event can't be transferred to the
+ * SAXEventKeeper together.
+ * For instance, at the time a referenced element is detected, the
+ * startElement event has already been reserved by the ElementStackKeeper.
+ * Meanwhile, an ElementCollector needs to be created before the
+ * SAXEventKeeper receives that startElement event.
+ * So for the SAXEventKeeper, it needs to receive all missed key SAX
+ * events except that startElement event, then adds a new
+ * ElementCollector, then receives that startElement event.
+ ******************************************************************************/
+{
+ bool rc = false;
+
+ if (!m_bIsSAXEventKeeperSticky && !m_bIsSAXEventKeeperConnected)
+ {
+ if ( m_eStatusOfSecurityComponents == InitializationState::UNINITIALIZED )
+ {
+ createXSecComponent();
+ }
+
+ if ( m_eStatusOfSecurityComponents == InitializationState::INITIALIZED )
+ /*
+ * if all security components are ready, chains on the SAXEventKeeper
+ */
+ {
+ /*
+ * disconnect the SAXEventKeeper with its current output handler,
+ * to make sure no SAX event is forwarded during the connecting
+ * phase.
+ */
+ m_xSAXEventKeeper->setNextHandler( nullptr );
+
+ css::uno::Reference< css::xml::sax::XDocumentHandler > xSEKHandler(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), css::uno::UNO_QUERY);
+
+ /*
+ * connects the previous document handler on the SAX chain
+ */
+ if ( m_xPreviousNodeOnSAXChain.is() )
+ {
+ if ( m_bIsPreviousNodeInitializable )
+ {
+ css::uno::Reference< css::lang::XInitialization > xInitialization
+ (m_xPreviousNodeOnSAXChain, css::uno::UNO_QUERY);
+
+ css::uno::Sequence<css::uno::Any> aArgs( 1 );
+ aArgs[0] <<= xSEKHandler;
+ xInitialization->initialize(aArgs);
+ }
+ else
+ {
+ css::uno::Reference< css::xml::sax::XParser > xParser
+ (m_xPreviousNodeOnSAXChain, css::uno::UNO_QUERY);
+ xParser->setDocumentHandler( xSEKHandler );
+ }
+ }
+
+ /*
+ * connects the next document handler on the SAX chain
+ */
+ m_xSAXEventKeeper->setNextHandler(uno::Reference<xml::sax::XDocumentHandler>());
+
+ m_bIsSAXEventKeeperConnected = true;
+
+ rc = true;
+ }
+ }
+
+ return rc;
+}
+
+void XSecController::chainOff()
+/****** XSecController/chainOff ***********************************************
+ *
+ * NAME
+ * chainOff -- disconnects the SAXEventKeeper from the SAX chain.
+ ******************************************************************************/
+{
+ if (!m_bIsSAXEventKeeperSticky )
+ {
+ if (m_bIsSAXEventKeeperConnected)
+ {
+ m_xSAXEventKeeper->setNextHandler( nullptr );
+
+ if ( m_xPreviousNodeOnSAXChain.is() )
+ {
+ if ( m_bIsPreviousNodeInitializable )
+ {
+ css::uno::Reference< css::lang::XInitialization > xInitialization
+ (m_xPreviousNodeOnSAXChain, css::uno::UNO_QUERY);
+
+ css::uno::Sequence<css::uno::Any> aArgs( 1 );
+ aArgs[0] <<= uno::Reference<xml::sax::XDocumentHandler>();
+ xInitialization->initialize(aArgs);
+ }
+ else
+ {
+ css::uno::Reference< css::xml::sax::XParser > xParser(m_xPreviousNodeOnSAXChain, css::uno::UNO_QUERY);
+ xParser->setDocumentHandler(uno::Reference<xml::sax::XDocumentHandler>());
+ }
+ }
+
+ m_bIsSAXEventKeeperConnected = false;
+ }
+ }
+}
+
+void XSecController::checkChainingStatus()
+/****** XSecController/checkChainingStatus ************************************
+ *
+ * NAME
+ * checkChainingStatus -- connects or disconnects the SAXEventKeeper
+ * according to the current situation.
+ *
+ * SYNOPSIS
+ * checkChainingStatus( );
+ *
+ * FUNCTION
+ * The SAXEventKeeper is chained into the SAX chain, when:
+ * 1. some element is being collected, or
+ * 2. the SAX event stream is blocking.
+ * Otherwise, chain off the SAXEventKeeper.
+ ******************************************************************************/
+{
+ if ( m_bIsCollectingElement || m_bIsBlocking )
+ {
+ chainOn();
+ }
+ else
+ {
+ chainOff();
+ }
+}
+
+void XSecController::initializeSAXChain()
+/****** XSecController/initializeSAXChain *************************************
+ *
+ * NAME
+ * initializeSAXChain -- initializes the SAX chain according to the
+ * current setting.
+ *
+ * FUNCTION
+ * Initializes the SAX chain, if the SAXEventKeeper is asked to be always
+ * on the SAX chain, chains it on. Otherwise, starts the
+ * ElementStackKeeper to reserve key SAX events.
+ ******************************************************************************/
+{
+ m_bIsSAXEventKeeperConnected = false;
+ m_bIsCollectingElement = false;
+ m_bIsBlocking = false;
+
+ chainOff();
+}
+
+css::uno::Reference< css::io::XInputStream >
+ XSecController::getObjectInputStream( const OUString& objectURL )
+/****** XSecController/getObjectInputStream ************************************
+ *
+ * NAME
+ * getObjectInputStream -- get a XInputStream interface from a SotStorage
+ *
+ * SYNOPSIS
+ * xInputStream = getObjectInputStream( objectURL );
+ *
+ * INPUTS
+ * objectURL - the object uri
+ *
+ * RESULT
+ * xInputStream - the XInputStream interface
+ ******************************************************************************/
+{
+ css::uno::Reference< css::io::XInputStream > xObjectInputStream;
+
+ SAL_WARN_IF( !m_xUriBinding.is(), "xmlsecurity.helper", "Need XUriBinding!" );
+
+ xObjectInputStream = m_xUriBinding->getUriBinding(objectURL);
+
+ return xObjectInputStream;
+}
+
+/*
+ * public methods
+ */
+
+sal_Int32 XSecController::getNewSecurityId( )
+{
+ sal_Int32 nId = m_nNextSecurityId;
+ m_nNextSecurityId++;
+ return nId;
+}
+
+void XSecController::startMission(const rtl::Reference<UriBindingHelper>& xUriBinding, const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& xSecurityContext )
+/****** XSecController/startMission *******************************************
+ *
+ * NAME
+ * startMission -- starts a new security mission.
+ *
+ * FUNCTION
+ * get ready for a new mission.
+ *
+ * INPUTS
+ * xUriBinding - the Uri binding that provide maps between uris and
+ * XInputStreams
+ * xSecurityContext - the security context component which can provide
+ * cryptoken
+ ******************************************************************************/
+{
+ m_xUriBinding = xUriBinding;
+
+ m_eStatusOfSecurityComponents = InitializationState::UNINITIALIZED;
+ m_xSecurityContext = xSecurityContext;
+
+ m_vInternalSignatureInformations.clear();
+
+ m_bVerifyCurrentSignature = false;
+}
+
+void XSecController::setSAXChainConnector(const css::uno::Reference< css::lang::XInitialization >& xInitialization)
+/****** XSecController/setSAXChainConnector ***********************************
+ *
+ * NAME
+ * setSAXChainConnector -- configures the components which will
+ * collaborate with the SAXEventKeeper on the SAX chain.
+ *
+ * SYNOPSIS
+ * setSAXChainConnector(xInitialization);
+ *
+ * INPUTS
+ * xInitialization - the previous node on the SAX chain
+ ******************************************************************************/
+{
+ m_bIsPreviousNodeInitializable = true;
+ m_xPreviousNodeOnSAXChain = xInitialization;
+
+ initializeSAXChain( );
+}
+
+void XSecController::clearSAXChainConnector()
+/****** XSecController/clearSAXChainConnector *********************************
+ *
+ * NAME
+ * clearSAXChainConnector -- resets the collaborating components.
+ ******************************************************************************/
+{
+ chainOff();
+
+ m_xPreviousNodeOnSAXChain = nullptr;
+}
+
+void XSecController::endMission()
+/****** XSecController/endMission *********************************************
+ *
+ * NAME
+ * endMission -- forces to end all missions
+ *
+ * FUNCTION
+ * Deletes all signature information and forces all missions to an end.
+ ******************************************************************************/
+{
+ sal_Int32 size = m_vInternalSignatureInformations.size();
+
+ for (int i=0; i<size; ++i)
+ {
+ if ( m_eStatusOfSecurityComponents == InitializationState::INITIALIZED )
+ /*
+ * ResolvedListener only exist when the security components are created.
+ */
+ {
+ css::uno::Reference< css::xml::crypto::sax::XMissionTaker > xMissionTaker
+ ( m_vInternalSignatureInformations[i].xReferenceResolvedListener, css::uno::UNO_QUERY );
+
+ /*
+ * asks the SignatureCreator/SignatureVerifier to release
+ * all resources it uses.
+ */
+ xMissionTaker->endMission();
+ }
+ }
+
+ m_xUriBinding = nullptr;
+ m_xSecurityContext = nullptr;
+
+ /*
+ * free the status change listener reference to this object
+ */
+ if (m_xSAXEventKeeper.is())
+ m_xSAXEventKeeper->addSAXEventKeeperStatusChangeListener( nullptr );
+}
+
+namespace
+{
+void writeUnsignedProperties(
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& signatureInfo)
+{
+ {
+ rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList());
+ pAttributeList->AddAttribute("Id", "idUnsignedProperties");
+ xDocumentHandler->startElement("xd:UnsignedProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList.get()));
+ }
+
+ {
+ xDocumentHandler->startElement("xd:UnsignedSignatureProperties", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+ {
+ xDocumentHandler->startElement("xd:CertificateValues", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+
+ {
+ for (const auto& i: signatureInfo.maEncapsulatedX509Certificates)
+ {
+ xDocumentHandler->startElement("xd:EncapsulatedX509Certificate", uno::Reference<xml::sax::XAttributeList>(new SvXMLAttributeList()));
+ xDocumentHandler->characters(i);
+ xDocumentHandler->endElement("xd:EncapsulatedX509Certificate");
+ }
+ }
+
+ xDocumentHandler->endElement("xd:CertificateValues");
+ }
+
+ xDocumentHandler->endElement("xd:UnsignedSignatureProperties");
+ }
+
+ xDocumentHandler->endElement("xd:UnsignedProperties");
+}
+
+}
+
+void XSecController::exportSignature(
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
+ const SignatureInformation& signatureInfo,
+ bool bXAdESCompliantIfODF )
+/****** XSecController/exportSignature ****************************************
+ *
+ * NAME
+ * exportSignature -- export a signature structure to an XDocumentHandler
+ *
+ * SYNOPSIS
+ * exportSignature( xDocumentHandler, signatureInfo);
+ *
+ * INPUTS
+ * xDocumentHandler - the document handler to receive the signature
+ * signatureInfo - signature to be exported
+ ******************************************************************************/
+{
+ const SignatureReferenceInformations& vReferenceInfors = signatureInfo.vSignatureReferenceInfors;
+ SvXMLAttributeList *pAttributeList;
+
+ /*
+ * Write Signature element
+ */
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "xmlns",
+ NS_XMLDSIG);
+
+ if (!signatureInfo.ouSignatureId.isEmpty())
+ {
+ pAttributeList->AddAttribute(
+ "Id",
+ signatureInfo.ouSignatureId);
+ }
+
+ xDocumentHandler->startElement( "Signature", css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+ {
+ /* Write SignedInfo element */
+ xDocumentHandler->startElement(
+ "SignedInfo",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write CanonicalizationMethod element */
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "Algorithm",
+ ALGO_C14N);
+ xDocumentHandler->startElement( "CanonicalizationMethod", css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList) );
+ xDocumentHandler->endElement( "CanonicalizationMethod" );
+
+ /* Write SignatureMethod element */
+ pAttributeList = new SvXMLAttributeList();
+
+ // TODO: actually roundtrip this value from parsing documentsignatures.xml - entirely
+ // broken to assume this would in any way relate to the 1st reference's digest algo
+
+ // Assume that all Reference elements use the same DigestMethod:Algorithm, and that the
+ // SignatureMethod:Algorithm should be the corresponding one.
+ pAttributeList->AddAttribute(
+ "Algorithm",
+ getSignatureURI(signatureInfo.eAlgorithmID, vReferenceInfors[0].nDigestID));
+ xDocumentHandler->startElement( "SignatureMethod", css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList) );
+ xDocumentHandler->endElement( "SignatureMethod" );
+
+ /* Write Reference element */
+ int j;
+ int refNum = vReferenceInfors.size();
+
+ for(j=0; j<refNum; ++j)
+ {
+ const SignatureReferenceInformation& refInfor = vReferenceInfors[j];
+
+ pAttributeList = new SvXMLAttributeList();
+ if ( refInfor.nType != SignatureReferenceType::SAMEDOCUMENT )
+ /*
+ * stream reference
+ */
+ {
+ pAttributeList->AddAttribute(
+ "URI",
+ refInfor.ouURI);
+ }
+ else
+ /*
+ * same-document reference
+ */
+ {
+ pAttributeList->AddAttribute(
+ "URI",
+ "#" + refInfor.ouURI);
+
+ if (bXAdESCompliantIfODF && refInfor.ouURI == "idSignedProperties" && !refInfor.ouType.isEmpty())
+ {
+ // The reference which points to the SignedProperties
+ // shall have this specific type.
+ pAttributeList->AddAttribute("Type",
+ refInfor.ouType);
+ }
+ }
+
+ xDocumentHandler->startElement( "Reference", css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList) );
+ {
+ /* Write Transforms element */
+ if (refInfor.nType == SignatureReferenceType::XMLSTREAM)
+ /*
+ * xml stream, so c14n transform is needed
+ */
+ {
+ xDocumentHandler->startElement(
+ "Transforms",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "Algorithm",
+ ALGO_C14N);
+ xDocumentHandler->startElement(
+ "Transform",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList) );
+ xDocumentHandler->endElement( "Transform" );
+ }
+ xDocumentHandler->endElement( "Transforms" );
+ }
+
+ /* Write DigestMethod element */
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "Algorithm",
+ getDigestURI(refInfor.nDigestID));
+ xDocumentHandler->startElement(
+ "DigestMethod",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList) );
+ xDocumentHandler->endElement( "DigestMethod" );
+
+ /* Write DigestValue element */
+ xDocumentHandler->startElement(
+ "DigestValue",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( refInfor.ouDigestValue );
+ xDocumentHandler->endElement( "DigestValue" );
+ }
+ xDocumentHandler->endElement( "Reference" );
+ }
+ }
+ xDocumentHandler->endElement( "SignedInfo" );
+
+ /* Write SignatureValue element */
+ xDocumentHandler->startElement(
+ "SignatureValue",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouSignatureValue );
+ xDocumentHandler->endElement( "SignatureValue" );
+
+ /* Write KeyInfo element */
+ xDocumentHandler->startElement(
+ "KeyInfo",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ // GPG or X509 key?
+ if (!signatureInfo.ouGpgCertificate.isEmpty())
+ {
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute("xmlns:loext", NS_LOEXT);
+ /* Write PGPData element */
+ xDocumentHandler->startElement(
+ "PGPData",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+ {
+ /* Write keyid element */
+ xDocumentHandler->startElement(
+ "PGPKeyID",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouCertDigest );
+ xDocumentHandler->endElement( "PGPKeyID" );
+
+ /* Write PGPKeyPacket element */
+ if (!signatureInfo.ouGpgCertificate.isEmpty())
+ {
+ xDocumentHandler->startElement(
+ "PGPKeyPacket",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouGpgCertificate );
+ xDocumentHandler->endElement( "PGPKeyPacket" );
+ }
+
+ /* Write PGPOwner element */
+ xDocumentHandler->startElement(
+ "loext:PGPOwner",
+ css::uno::Reference< css::xml::sax::XAttributeList >(new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouGpgOwner );
+ xDocumentHandler->endElement( "loext:PGPOwner" );
+ }
+ xDocumentHandler->endElement( "PGPData" );
+ }
+ else
+ {
+ /* Write X509Data element */
+ xDocumentHandler->startElement(
+ "X509Data",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write X509IssuerSerial element */
+ xDocumentHandler->startElement(
+ "X509IssuerSerial",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write X509IssuerName element */
+ xDocumentHandler->startElement(
+ "X509IssuerName",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouX509IssuerName );
+ xDocumentHandler->endElement( "X509IssuerName" );
+
+ /* Write X509SerialNumber element */
+ xDocumentHandler->startElement(
+ "X509SerialNumber",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouX509SerialNumber );
+ xDocumentHandler->endElement( "X509SerialNumber" );
+ }
+ xDocumentHandler->endElement( "X509IssuerSerial" );
+
+ /* Write X509Certificate element */
+ if (!signatureInfo.ouX509Certificate.isEmpty())
+ {
+ xDocumentHandler->startElement(
+ "X509Certificate",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ xDocumentHandler->characters( signatureInfo.ouX509Certificate );
+ xDocumentHandler->endElement( "X509Certificate" );
+ }
+ }
+ xDocumentHandler->endElement( "X509Data" );
+ }
+ }
+ xDocumentHandler->endElement( "KeyInfo" );
+
+ OUString sDate;
+
+ /* Write Object element */
+ xDocumentHandler->startElement(
+ "Object",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write SignatureProperties element */
+ xDocumentHandler->startElement(
+ "SignatureProperties",
+ css::uno::Reference< css::xml::sax::XAttributeList > (new SvXMLAttributeList()));
+ {
+ /* Write SignatureProperty element */
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "Id",
+ signatureInfo.ouPropertyId);
+ pAttributeList->AddAttribute(
+ "Target",
+ "#" + signatureInfo.ouSignatureId);
+ xDocumentHandler->startElement(
+ "SignatureProperty",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+ {
+ /* Write timestamp element */
+
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute(
+ "xmlns:dc",
+ NS_DC);
+
+ xDocumentHandler->startElement(
+ "dc:date",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+
+ OUStringBuffer buffer;
+ //If the xml signature was already contained in the document,
+ //then we use the original date and time string, rather than the
+ //converted one. This avoids writing a different string due to
+ //e.g. rounding issues and thus breaking the signature.
+ if (!signatureInfo.ouDateTime.isEmpty())
+ buffer = signatureInfo.ouDateTime;
+ else
+ {
+ buffer = utl::toISO8601(signatureInfo.stDateTime);
+ // xsd:dateTime must use period as separator for fractional seconds, while
+ // utl::toISO8601 uses comma (as allowed, and even recommended, by ISO8601).
+ buffer.replace(',', '.');
+ }
+ sDate = buffer.makeStringAndClear();
+ xDocumentHandler->characters( sDate );
+
+ xDocumentHandler->endElement(
+ "dc:date");
+ }
+ xDocumentHandler->endElement( "SignatureProperty" );
+ }
+
+ // Write signature description.
+ if (!signatureInfo.ouDescription.isEmpty())
+ {
+ // SignatureProperty element.
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute("Id", signatureInfo.ouDescriptionPropertyId);
+ pAttributeList->AddAttribute("Target", "#" + signatureInfo.ouSignatureId);
+ xDocumentHandler->startElement("SignatureProperty", uno::Reference<xml::sax::XAttributeList>(pAttributeList));
+
+ {
+ // Description element.
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute("xmlns:dc", NS_DC);
+
+ xDocumentHandler->startElement("dc:description", uno::Reference<xml::sax::XAttributeList>(pAttributeList));
+ xDocumentHandler->characters(signatureInfo.ouDescription);
+ xDocumentHandler->endElement("dc:description");
+ }
+
+ xDocumentHandler->endElement("SignatureProperty");
+ }
+
+ xDocumentHandler->endElement( "SignatureProperties" );
+ }
+ xDocumentHandler->endElement( "Object" );
+
+ // In XAdES, write another Object element for the QualifyingProperties
+ if (bXAdESCompliantIfODF)
+ {
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute("xmlns:xd", NS_XD);
+ xDocumentHandler->startElement(
+ "Object",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+ {
+ pAttributeList = new SvXMLAttributeList();
+ pAttributeList->AddAttribute("Target", "#" + signatureInfo.ouSignatureId);
+ xDocumentHandler->startElement(
+ "xd:QualifyingProperties",
+ css::uno::Reference< css::xml::sax::XAttributeList > (pAttributeList));
+ DocumentSignatureHelper::writeSignedProperties(xDocumentHandler, signatureInfo, sDate, true);
+ writeUnsignedProperties(xDocumentHandler, signatureInfo);
+ xDocumentHandler->endElement( "xd:QualifyingProperties" );
+ }
+ xDocumentHandler->endElement( "Object" );
+ }
+ }
+ xDocumentHandler->endElement( "Signature" );
+}
+
+void XSecController::exportOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler, const SignatureInformation& rInformation)
+{
+ OOXMLSecExporter aExporter(mxCtx, xRootStorage, xDocumentHandler, rInformation);
+ aExporter.writeSignature();
+}
+
+SignatureInformation XSecController::getSignatureInformation( sal_Int32 nSecurityId ) const
+{
+ SignatureInformation aInf( 0 );
+ int nIndex = findSignatureInfor(nSecurityId);
+ SAL_WARN_IF( nIndex == -1, "xmlsecurity.helper", "getSignatureInformation - SecurityId is invalid!" );
+ if ( nIndex != -1)
+ {
+ aInf = m_vInternalSignatureInformations[nIndex].signatureInfor;
+ }
+ return aInf;
+}
+
+SignatureInformations XSecController::getSignatureInformations() const
+{
+ SignatureInformations vInfors;
+ int sigNum = m_vInternalSignatureInformations.size();
+
+ for (int i=0; i<sigNum; ++i)
+ {
+ SignatureInformation si = m_vInternalSignatureInformations[i].signatureInfor;
+ vInfors.push_back(si);
+ }
+
+ return vInfors;
+}
+
+/*
+ * XSAXEventKeeperStatusChangeListener
+ */
+
+void SAL_CALL XSecController::blockingStatusChanged( sal_Bool isBlocking )
+{
+ m_bIsBlocking = isBlocking;
+ checkChainingStatus();
+}
+
+void SAL_CALL XSecController::collectionStatusChanged(
+ sal_Bool isInsideCollectedElement )
+{
+ m_bIsCollectingElement = isInsideCollectedElement;
+ checkChainingStatus();
+}
+
+void SAL_CALL XSecController::bufferStatusChanged( sal_Bool /*isBufferEmpty*/)
+{
+
+}
+
+/*
+ * XSignatureCreationResultListener
+ */
+void SAL_CALL XSecController::signatureCreated( sal_Int32 securityId, css::xml::crypto::SecurityOperationStatus nResult )
+{
+ int index = findSignatureInfor(securityId);
+ assert(index != -1 && "Signature Not Found!");
+ SignatureInformation& signatureInfor = m_vInternalSignatureInformations.at(index).signatureInfor;
+ signatureInfor.nStatus = nResult;
+}
+
+/*
+ * XSignatureVerifyResultListener
+ */
+void SAL_CALL XSecController::signatureVerified( sal_Int32 securityId, css::xml::crypto::SecurityOperationStatus nResult )
+{
+ int index = findSignatureInfor(securityId);
+ assert(index != -1 && "Signature Not Found!");
+ SignatureInformation& signatureInfor = m_vInternalSignatureInformations.at(index).signatureInfor;
+ signatureInfor.nStatus = nResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx
new file mode 100644
index 000000000..9f2bbe074
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecparser.cxx
@@ -0,0 +1,530 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 "xsecparser.hxx"
+#include <xsecctl.hxx>
+#include <xmlsignaturehelper.hxx>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <sal/log.hxx>
+
+
+XSecParser::XSecParser(XMLSignatureHelper& rXMLSignatureHelper,
+ XSecController* pXSecController)
+ : m_bInX509IssuerName(false)
+ , m_bInX509SerialNumber(false)
+ , m_bInX509Certificate(false)
+ , m_bInGpgCertificate(false)
+ , m_bInGpgKeyID(false)
+ , m_bInGpgOwner(false)
+ , m_bInCertDigest(false)
+ , m_bInEncapsulatedX509Certificate(false)
+ , m_bInSigningTime(false)
+ , m_bInDigestValue(false)
+ , m_bInSignatureValue(false)
+ , m_bInDate(false)
+ , m_bInDescription(false)
+ , m_bInSignatureLineId(false)
+ , m_bInSignatureLineValidImage(false)
+ , m_bInSignatureLineInvalidImage(false)
+ , m_pXSecController(pXSecController)
+ , m_bReferenceUnresolved(false)
+ , m_nReferenceDigestID(css::xml::crypto::DigestID::SHA1)
+ , m_rXMLSignatureHelper(rXMLSignatureHelper)
+{
+}
+
+OUString XSecParser::getIdAttr(const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs )
+{
+ OUString ouIdAttr = xAttribs->getValueByName("id");
+
+ if (ouIdAttr.isEmpty())
+ {
+ ouIdAttr = xAttribs->getValueByName("Id");
+ }
+
+ return ouIdAttr;
+}
+
+/*
+ * XDocumentHandler
+ */
+void SAL_CALL XSecParser::startDocument( )
+{
+ m_bInX509IssuerName = false;
+ m_bInX509SerialNumber = false;
+ m_bInX509Certificate = false;
+ m_bInGpgCertificate = false;
+ m_bInGpgKeyID = false;
+ m_bInGpgOwner = false;
+ m_bInSignatureValue = false;
+ m_bInDigestValue = false;
+ m_bInDate = false;
+ m_bInDescription = false;
+
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->startDocument();
+ }
+}
+
+void SAL_CALL XSecParser::endDocument( )
+{
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->endDocument();
+ }
+}
+
+void SAL_CALL XSecParser::startElement(
+ const OUString& aName,
+ const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs )
+{
+ try
+ {
+ OUString ouIdAttr = getIdAttr(xAttribs);
+ if (!ouIdAttr.isEmpty())
+ {
+ m_pXSecController->collectToVerify( ouIdAttr );
+ }
+
+ if ( aName == "Signature" )
+ {
+ m_rXMLSignatureHelper.StartVerifySignatureElement();
+ m_pXSecController->addSignature();
+ if (!ouIdAttr.isEmpty())
+ {
+ m_pXSecController->setId( ouIdAttr );
+ }
+ }
+ else if (aName == "SignatureMethod")
+ {
+ OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
+ if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
+ || ouAlgorithm == ALGO_ECDSASHA512)
+ m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
+ }
+ else if ( aName == "Reference" )
+ {
+ OUString ouUri = xAttribs->getValueByName("URI");
+ SAL_WARN_IF( ouUri.isEmpty(), "xmlsecurity.helper", "URI is empty" );
+ // Remember the type of this reference.
+ OUString ouType = xAttribs->getValueByName("Type");
+ if (ouUri.startsWith("#"))
+ {
+ /*
+ * remove the first character '#' from the attribute value
+ */
+ m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID, ouType );
+ }
+ else
+ {
+ /*
+ * remember the uri
+ */
+ m_currentReferenceURI = ouUri;
+ m_bReferenceUnresolved = true;
+ }
+ }
+ else if (aName == "DigestMethod")
+ {
+ OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
+
+ SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" );
+ if (!ouAlgorithm.isEmpty())
+ {
+ SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1
+ && ouAlgorithm != ALGO_XMLDSIGSHA256
+ && ouAlgorithm != ALGO_XMLDSIGSHA512,
+ "xmlsecurity.helper", "Algorithm neither SHA1, SHA256 nor SHA512");
+ if (ouAlgorithm == ALGO_XMLDSIGSHA1)
+ m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+ else if (ouAlgorithm == ALGO_XMLDSIGSHA256)
+ m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+ else if (ouAlgorithm == ALGO_XMLDSIGSHA512)
+ m_nReferenceDigestID = css::xml::crypto::DigestID::SHA512;
+ else
+ m_nReferenceDigestID = 0;
+ }
+ }
+ else if (aName == "Transform")
+ {
+ if ( m_bReferenceUnresolved )
+ {
+ OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
+
+ if (ouAlgorithm == ALGO_C14N)
+ /*
+ * a xml stream
+ */
+ {
+ m_pXSecController->addStreamReference( m_currentReferenceURI, false, m_nReferenceDigestID );
+ m_bReferenceUnresolved = false;
+ }
+ }
+ }
+ else if (aName == "X509IssuerName")
+ {
+ m_ouX509IssuerName.clear();
+ m_bInX509IssuerName = true;
+ }
+ else if (aName == "X509SerialNumber")
+ {
+ m_ouX509SerialNumber.clear();
+ m_bInX509SerialNumber = true;
+ }
+ else if (aName == "X509Certificate")
+ {
+ m_ouX509Certificate.clear();
+ m_bInX509Certificate = true;
+ }
+ else if (aName == "PGPData")
+ {
+ m_pXSecController->switchGpgSignature();
+ }
+ else if (aName == "PGPKeyID")
+ {
+ m_ouGpgKeyID.clear();
+ m_bInGpgKeyID = true;
+ }
+ else if (aName == "PGPKeyPacket")
+ {
+ m_ouGpgCertificate.clear();
+ m_bInGpgCertificate = true;
+ }
+ else if (aName == "loext:PGPOwner")
+ {
+ m_ouGpgOwner.clear();
+ m_bInGpgOwner = true;
+ }
+ else if (aName == "SignatureValue")
+ {
+ m_ouSignatureValue.clear();
+ m_bInSignatureValue = true;
+ }
+ else if (aName == "DigestValue" && !m_bInCertDigest)
+ {
+ m_ouDigestValue.clear();
+ m_bInDigestValue = true;
+ }
+ else if (aName == "xd:CertDigest")
+ {
+ m_ouCertDigest.clear();
+ m_bInCertDigest = true;
+ }
+ // FIXME: Existing code here in xmlsecurity uses "xd" as the namespace prefix for XAdES,
+ // while the sample document attached to tdf#76142 uses "xades". So accept either here. Of
+ // course this is idiotic and wrong, the right thing would be to use a proper way to parse
+ // XML that would handle namespaces correctly. I have no idea how substantial re-plumbing of
+ // this code that would require.
+ else if (aName == "xd:EncapsulatedX509Certificate" || aName == "xades:EncapsulatedX509Certificate")
+ {
+ m_ouEncapsulatedX509Certificate.clear();
+ m_bInEncapsulatedX509Certificate = true;
+ }
+ else if (aName == "xd:SigningTime" || aName == "xades:SigningTime")
+ {
+ m_ouDate.clear();
+ m_bInSigningTime = true;
+ }
+ else if ( aName == "SignatureProperty" )
+ {
+ if (!ouIdAttr.isEmpty())
+ {
+ m_pXSecController->setPropertyId( ouIdAttr );
+ }
+ }
+ else if (aName == "dc:date")
+ {
+ if (m_ouDate.isEmpty())
+ m_bInDate = true;
+ }
+ else if (aName == "dc:description")
+ {
+ m_ouDescription.clear();
+ m_bInDescription = true;
+ }
+ else if (aName == "loext:SignatureLineId")
+ {
+ m_ouSignatureLineId.clear();
+ m_bInSignatureLineId = true;
+ }
+ else if (aName == "loext:SignatureLineValidImage")
+ {
+ m_ouSignatureLineValidImage.clear();
+ m_bInSignatureLineValidImage = true;
+ }
+ else if (aName == "loext:SignatureLineInvalidImage")
+ {
+ m_ouSignatureLineInvalidImage.clear();
+ m_bInSignatureLineInvalidImage = true;
+ }
+
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->startElement(aName, xAttribs);
+ }
+ }
+ catch (css::uno::Exception& )
+ {//getCaughtException MUST be the first line in the catch block
+ css::uno::Any exc = cppu::getCaughtException();
+ throw css::xml::sax::SAXException(
+ "xmlsecurity: Exception in XSecParser::startElement",
+ nullptr, exc);
+ }
+ catch (...)
+ {
+ throw css::xml::sax::SAXException(
+ "xmlsecurity: unexpected exception in XSecParser::startElement", nullptr,
+ css::uno::Any());
+ }
+}
+
+void SAL_CALL XSecParser::endElement( const OUString& aName )
+{
+ try
+ {
+ if (aName == "DigestValue" && !m_bInCertDigest)
+ {
+ m_bInDigestValue = false;
+ }
+ else if ( aName == "Reference" )
+ {
+ if ( m_bReferenceUnresolved )
+ /*
+ * it must be an octet stream
+ */
+ {
+ m_pXSecController->addStreamReference( m_currentReferenceURI, true, m_nReferenceDigestID );
+ m_bReferenceUnresolved = false;
+ }
+
+ m_pXSecController->setDigestValue( m_nReferenceDigestID, m_ouDigestValue );
+ }
+ else if ( aName == "SignedInfo" )
+ {
+ m_pXSecController->setReferenceCount();
+ }
+ else if ( aName == "SignatureValue" )
+ {
+ m_pXSecController->setSignatureValue( m_ouSignatureValue );
+ m_bInSignatureValue = false;
+ }
+ else if (aName == "X509IssuerName")
+ {
+ m_pXSecController->setX509IssuerName( m_ouX509IssuerName );
+ m_bInX509IssuerName = false;
+ }
+ else if (aName == "X509SerialNumber")
+ {
+ m_pXSecController->setX509SerialNumber( m_ouX509SerialNumber );
+ m_bInX509SerialNumber = false;
+ }
+ else if (aName == "X509Certificate")
+ {
+ m_pXSecController->setX509Certificate( m_ouX509Certificate );
+ m_bInX509Certificate = false;
+ }
+ else if (aName == "PGPKeyID")
+ {
+ m_pXSecController->setGpgKeyID( m_ouGpgKeyID );
+ m_bInGpgKeyID = false;
+ }
+ else if (aName == "PGPKeyPacket")
+ {
+ m_pXSecController->setGpgCertificate( m_ouGpgCertificate );
+ m_bInGpgCertificate = false;
+ }
+ else if (aName == "loext:PGPOwner")
+ {
+ m_pXSecController->setGpgOwner( m_ouGpgOwner );
+ m_bInGpgOwner = false;
+ }
+ else if (aName == "xd:CertDigest")
+ {
+ m_pXSecController->setCertDigest( m_ouCertDigest );
+ m_bInCertDigest = false;
+ }
+ else if (aName == "xd:EncapsulatedX509Certificate" || aName == "xades:EncapsulatedX509Certificate")
+ {
+ m_pXSecController->addEncapsulatedX509Certificate( m_ouEncapsulatedX509Certificate );
+ m_bInEncapsulatedX509Certificate = false;
+ }
+ else if (aName == "xd:SigningTime" || aName == "xades:SigningTime")
+ {
+ m_pXSecController->setDate( m_ouDate );
+ m_bInSigningTime = false;
+ }
+ else if (aName == "dc:date")
+ {
+ if (m_bInDate)
+ {
+ m_pXSecController->setDate( m_ouDate );
+ m_bInDate = false;
+ }
+ }
+ else if (aName == "dc:description")
+ {
+ m_pXSecController->setDescription( m_ouDescription );
+ m_bInDescription = false;
+ }
+ else if (aName == "loext:SignatureLineId")
+ {
+ m_pXSecController->setSignatureLineId( m_ouSignatureLineId );
+ m_bInSignatureLineId = false;
+ }
+ else if (aName == "loext:SignatureLineValidImage")
+ {
+ m_pXSecController->setValidSignatureImage( m_ouSignatureLineValidImage );
+ m_bInSignatureLineValidImage = false;
+ }
+ else if (aName == "loext:SignatureLineInvalidImage")
+ {
+ m_pXSecController->setInvalidSignatureImage( m_ouSignatureLineInvalidImage );
+ m_bInSignatureLineInvalidImage = false;
+ }
+
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->endElement(aName);
+ }
+ }
+ catch (css::uno::Exception& )
+ {//getCaughtException MUST be the first line in the catch block
+ css::uno::Any exc = cppu::getCaughtException();
+ throw css::xml::sax::SAXException(
+ "xmlsecurity: Exception in XSecParser::endElement",
+ nullptr, exc);
+ }
+ catch (...)
+ {
+ throw css::xml::sax::SAXException(
+ "xmlsecurity: unexpected exception in XSecParser::endElement", nullptr,
+ css::uno::Any());
+ }
+}
+
+void SAL_CALL XSecParser::characters( const OUString& aChars )
+{
+ if (m_bInX509IssuerName)
+ {
+ m_ouX509IssuerName += aChars;
+ }
+ else if (m_bInX509SerialNumber)
+ {
+ m_ouX509SerialNumber += aChars;
+ }
+ else if (m_bInX509Certificate)
+ {
+ m_ouX509Certificate += aChars;
+ }
+ else if (m_bInGpgCertificate)
+ {
+ m_ouGpgCertificate += aChars;
+ }
+ else if (m_bInGpgKeyID)
+ {
+ m_ouGpgKeyID += aChars;
+ }
+ else if (m_bInGpgOwner)
+ {
+ m_ouGpgOwner += aChars;
+ }
+ else if (m_bInSignatureValue)
+ {
+ m_ouSignatureValue += aChars;
+ }
+ else if (m_bInDigestValue && !m_bInCertDigest)
+ {
+ m_ouDigestValue += aChars;
+ }
+ else if (m_bInDate)
+ {
+ m_ouDate += aChars;
+ }
+ else if (m_bInDescription)
+ {
+ m_ouDescription += aChars;
+ }
+ else if (m_bInCertDigest)
+ {
+ m_ouCertDigest += aChars;
+ }
+ else if (m_bInEncapsulatedX509Certificate)
+ {
+ m_ouEncapsulatedX509Certificate += aChars;
+ }
+ else if (m_bInSigningTime)
+ {
+ m_ouDate += aChars;
+ }
+ else if (m_bInSignatureLineId)
+ {
+ m_ouSignatureLineId += aChars;
+ }
+ else if (m_bInSignatureLineValidImage)
+ {
+ m_ouSignatureLineValidImage += aChars;
+ }
+ else if (m_bInSignatureLineInvalidImage)
+ {
+ m_ouSignatureLineInvalidImage += aChars;
+ }
+
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->characters(aChars);
+ }
+}
+
+void SAL_CALL XSecParser::ignorableWhitespace( const OUString& aWhitespaces )
+{
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->ignorableWhitespace( aWhitespaces );
+ }
+}
+
+void SAL_CALL XSecParser::processingInstruction( const OUString& aTarget, const OUString& aData )
+{
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->processingInstruction(aTarget, aData);
+ }
+}
+
+void SAL_CALL XSecParser::setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >& xLocator )
+{
+ if (m_xNextHandler.is())
+ {
+ m_xNextHandler->setDocumentLocator( xLocator );
+ }
+}
+
+/*
+ * XInitialization
+ */
+void SAL_CALL XSecParser::initialize(
+ const css::uno::Sequence< css::uno::Any >& aArguments )
+{
+ aArguments[0] >>= m_xNextHandler;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecparser.hxx b/xmlsecurity/source/helper/xsecparser.hxx
new file mode 100644
index 000000000..d9b079aa3
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecparser.hxx
@@ -0,0 +1,162 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_XMLSECURITY_SOURCE_HELPER_XSECPARSER_HXX
+#define INCLUDED_XMLSECURITY_SOURCE_HELPER_XSECPARSER_HXX
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+class XMLSignatureHelper;
+class XSecController;
+
+class XSecParser: public cppu::WeakImplHelper
+<
+ css::xml::sax::XDocumentHandler,
+ css::lang::XInitialization
+>
+/****** XSecController.hxx/CLASS XSecParser ***********************************
+ *
+ * NAME
+ * XSecParser -- a SAX parser that can detect security elements
+ *
+ * FUNCTION
+ * The XSecParser object is connected on the SAX chain and detects
+ * security elements in the SAX event stream, then notifies
+ * the XSecController.
+ *
+ * NOTES
+ * This class is used when importing a document.
+ ******************************************************************************/
+{
+ friend class XSecController;
+private:
+ /*
+ * the following members are used to reserve the signature information,
+ * including X509IssuerName, X509SerialNumber, and X509Certificate,etc.
+ */
+ OUString m_ouX509IssuerName;
+ OUString m_ouX509SerialNumber;
+ OUString m_ouX509Certificate;
+ OUString m_ouGpgCertificate;
+ OUString m_ouGpgKeyID;
+ OUString m_ouGpgOwner;
+ OUString m_ouCertDigest;
+ OUString m_ouEncapsulatedX509Certificate;
+ OUString m_ouDigestValue;
+ OUString m_ouSignatureValue;
+ OUString m_ouDate;
+ /// Characters of a <dc:description> element, as just read from XML.
+ OUString m_ouDescription;
+ OUString m_ouSignatureLineId;
+ OUString m_ouSignatureLineValidImage;
+ OUString m_ouSignatureLineInvalidImage;
+
+ /*
+ * whether inside a particular element
+ */
+ bool m_bInX509IssuerName;
+ bool m_bInX509SerialNumber;
+ bool m_bInX509Certificate;
+ bool m_bInGpgCertificate;
+ bool m_bInGpgKeyID;
+ bool m_bInGpgOwner;
+ bool m_bInCertDigest;
+ bool m_bInEncapsulatedX509Certificate;
+ bool m_bInSigningTime;
+ bool m_bInDigestValue;
+ bool m_bInSignatureValue;
+ bool m_bInDate;
+ bool m_bInDescription;
+ bool m_bInSignatureLineId;
+ bool m_bInSignatureLineValidImage;
+ bool m_bInSignatureLineInvalidImage;
+
+ /*
+ * the XSecController collaborating with XSecParser
+ */
+ XSecController* m_pXSecController;
+
+ /*
+ * the next XDocumentHandler on the SAX chain
+ */
+ css::uno::Reference<
+ css::xml::sax::XDocumentHandler > m_xNextHandler;
+
+ /*
+ * this string is used to remember the current handled reference's URI,
+ *
+ * because it can be decided whether a stream reference is xml based or binary based
+ * only after the Transforms element is read in, so we have to reserve the reference's
+ * URI when the startElement event is met.
+ */
+ OUString m_currentReferenceURI;
+ bool m_bReferenceUnresolved;
+
+ // Relevant for ODF. The digest algorithm selected by the current DigestMethod element's
+ // Algorithm attribute in the current Reference element. From css::xml::crypto::DigestID.
+ sal_Int32 m_nReferenceDigestID;
+ XMLSignatureHelper& m_rXMLSignatureHelper;
+
+private:
+ static OUString getIdAttr(const css::uno::Reference<
+ css::xml::sax::XAttributeList >& xAttribs );
+
+public:
+ XSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController);
+
+ /*
+ * XDocumentHandler
+ */
+ virtual void SAL_CALL startDocument( ) override;
+
+ virtual void SAL_CALL endDocument( ) override;
+
+ virtual void SAL_CALL startElement(
+ const OUString& aName,
+ const css::uno::Reference<
+ css::xml::sax::XAttributeList >& xAttribs ) override;
+
+ virtual void SAL_CALL endElement( const OUString& aName ) override;
+
+ virtual void SAL_CALL characters( const OUString& aChars ) override;
+
+ virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
+
+ virtual void SAL_CALL processingInstruction(
+ const OUString& aTarget,
+ const OUString& aData ) override;
+
+ virtual void SAL_CALL setDocumentLocator(
+ const css::uno::Reference<
+ css::xml::sax::XLocator >& xLocator ) override;
+
+ /*
+ * XInitialization
+ */
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+};
+
+#endif
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
new file mode 100644
index 000000000..b9648ed64
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecsign.cxx
@@ -0,0 +1,447 @@
+/* -*- 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 <xsecctl.hxx>
+
+#include <com/sun/star/xml/crypto/sax/ElementMarkPriority.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <rtl/uuid.h>
+#include <sal/log.hxx>
+
+#include <framework/signaturecreatorimpl.hxx>
+#include <framework/saxeventkeeperimpl.hxx>
+
+namespace com::sun::star::graphic { class XGraphic; }
+
+using namespace css;
+using namespace css::uno;
+using namespace css::graphic;
+
+/* protected: for signature generation */
+OUString XSecController::createId()
+{
+ sal_uInt8 aSeq[16];
+ rtl_createUuid( aSeq, nullptr, true );
+
+ char str[68]="ID_";
+ int length = 3;
+ for (sal_uInt8 i : aSeq)
+ {
+ length += sprintf(str+length, "%04x", i);
+ }
+
+ return OUString::createFromAscii(str);
+}
+
+css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecController::prepareSignatureToWrite(
+ InternalSignatureInformation& internalSignatureInfor,
+ sal_Int32 nStorageFormat,
+ bool bXAdESCompliantIfODF)
+{
+ sal_Int32 nSecurityId = internalSignatureInfor.signatureInfor.nSecurityId;
+ SignatureReferenceInformations& vReferenceInfors = internalSignatureInfor.signatureInfor.vSignatureReferenceInfors;
+
+ sal_Int32 nIdOfSignatureElementCollector;
+
+ nIdOfSignatureElementCollector =
+ m_xSAXEventKeeper->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_AFTERMODIFY, true );
+
+ m_xSAXEventKeeper->setSecurityId(nIdOfSignatureElementCollector, nSecurityId);
+
+ rtl::Reference<SignatureCreatorImpl> xSignatureCreator(new SignatureCreatorImpl);
+
+ css::uno::Sequence<css::uno::Any> args(5);
+ args[0] <<= OUString::number(nSecurityId);
+ args[1] <<= uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), uno::UNO_QUERY);
+ args[2] <<= OUString::number(nIdOfSignatureElementCollector);
+
+ //for nss, the internal module is used for signing, which needs to be improved later
+ args[3] <<= m_xSecurityContext->getSecurityEnvironment();
+
+ args[4] <<= m_xXMLSignature;
+ xSignatureCreator->initialize(args);
+
+ sal_Int32 nBlockerId = m_xSAXEventKeeper->addBlocker();
+ m_xSAXEventKeeper->setSecurityId(nBlockerId, nSecurityId);
+
+ xSignatureCreator->setBlockerId(nBlockerId);
+
+ xSignatureCreator->addSignatureCreationResultListener(this);
+
+ m_xSAXEventKeeper->addReferenceResolvedListener(nIdOfSignatureElementCollector, xSignatureCreator.get());
+
+ int size = vReferenceInfors.size();
+ sal_Int32 nReferenceCount = 0;
+
+ for(int i=0; i<size; ++i)
+ {
+ sal_Int32 keeperId = internalSignatureInfor.vKeeperIds[i];
+
+ if ( keeperId != -1)
+ {
+ m_xSAXEventKeeper->setSecurityId(keeperId, nSecurityId);
+ m_xSAXEventKeeper->addReferenceResolvedListener( keeperId, xSignatureCreator.get());
+ xSignatureCreator->setReferenceId( keeperId );
+ nReferenceCount++;
+ }
+ }
+
+ xSignatureCreator->setReferenceCount( nReferenceCount );
+
+ /*
+ * adds all URI binding
+ */
+ for(int i=0; i<size; ++i)
+ {
+ const SignatureReferenceInformation& refInfor = vReferenceInfors[i];
+
+ css::uno::Reference< css::io::XInputStream > xInputStream
+ = getObjectInputStream( refInfor.ouURI );
+
+ if (xInputStream.is())
+ xSignatureCreator->setUriBinding(refInfor.ouURI,xInputStream);
+ }
+
+ xSignatureCreator->setKeyId(0);
+
+ // use sha512 for gpg signing unconditionally
+ const sal_Int32 digestID = !internalSignatureInfor.signatureInfor.ouGpgCertificate.isEmpty()?
+ css::xml::crypto::DigestID::SHA512 : (bXAdESCompliantIfODF ? css::xml::crypto::DigestID::SHA256 : css::xml::crypto::DigestID::SHA1);
+
+ if (nStorageFormat != embed::StorageFormats::OFOPXML)
+ {
+ internalSignatureInfor.signatureInfor.ouSignatureId = createId();
+ internalSignatureInfor.signatureInfor.ouPropertyId = createId();
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1, OUString() );
+ size++;
+
+ if (bXAdESCompliantIfODF)
+ {
+ // We write a new reference, so it's possible to use the correct type URI.
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, "http://uri.etsi.org/01903#SignedProperties");
+ size++;
+ }
+
+ if (!internalSignatureInfor.signatureInfor.ouDescription.isEmpty())
+ {
+ // Only mention the hash of the description in the signature if it's non-empty.
+ internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId();
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1, OUString());
+ size++;
+ }
+ }
+ else
+ {
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1, OUString());
+ size++;
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1, OUString());
+ size++;
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, OUString());
+ size++;
+ }
+
+ /*
+ * replace both digestValues and signatureValue to " "
+ */
+ for(int i=0; i<size; ++i)
+ {
+ SignatureReferenceInformation& refInfor = vReferenceInfors[i];
+ refInfor.ouDigestValue = " ";
+ }
+
+ internalSignatureInfor.signatureInfor.ouSignatureValue = " ";
+
+ return xSignatureCreator.get();
+}
+
+void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, bool isBinary, bool bXAdESCompliantIfODF)
+{
+ const SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM;
+ sal_Int32 digestID = bXAdESCompliantIfODF ? css::xml::crypto::DigestID::SHA256 : css::xml::crypto::DigestID::SHA1;
+
+ int index = findSignatureInfor( securityId );
+
+ if (index == -1)
+ {
+ InternalSignatureInformation isi(securityId, nullptr);
+ isi.addReference(type, digestID, uri, -1, OUString());
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ // use sha512 for gpg signing unconditionally
+ if (!m_vInternalSignatureInformations[index].signatureInfor.ouGpgCertificate.isEmpty())
+ digestID = css::xml::crypto::DigestID::SHA512;
+ m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1, OUString());
+ }
+}
+
+void XSecController::setX509Certificate(
+ sal_Int32 nSecurityId,
+ const OUString& ouX509IssuerName,
+ const OUString& ouX509SerialNumber,
+ const OUString& ouX509Cert,
+ const OUString& ouX509CertDigest,
+ svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
+{
+ int index = findSignatureInfor( nSecurityId );
+
+ if ( index == -1 )
+ {
+ InternalSignatureInformation isi(nSecurityId, nullptr);
+ isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
+ isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
+ isi.signatureInfor.ouX509Certificate = ouX509Cert;
+ isi.signatureInfor.ouCertDigest = ouX509CertDigest;
+ isi.signatureInfor.eAlgorithmID = eAlgorithmID;
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ SignatureInformation &si
+ = m_vInternalSignatureInformations[index].signatureInfor;
+ si.ouX509IssuerName = ouX509IssuerName;
+ si.ouX509SerialNumber = ouX509SerialNumber;
+ si.ouX509Certificate = ouX509Cert;
+ si.ouCertDigest = ouX509CertDigest;
+ }
+}
+
+void XSecController::setGpgCertificate(
+ sal_Int32 nSecurityId,
+ const OUString& ouCertDigest,
+ const OUString& ouCert,
+ const OUString& ouOwner)
+{
+ int index = findSignatureInfor( nSecurityId );
+
+ if ( index == -1 )
+ {
+ InternalSignatureInformation isi(nSecurityId, nullptr);
+ isi.signatureInfor.ouGpgCertificate = ouCert;
+ isi.signatureInfor.ouGpgOwner = ouOwner;
+ isi.signatureInfor.ouCertDigest = ouCertDigest;
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ SignatureInformation &si
+ = m_vInternalSignatureInformations[index].signatureInfor;
+ si.ouGpgCertificate = ouCert;
+ si.ouGpgOwner = ouOwner;
+ si.ouCertDigest = ouCertDigest;
+ }
+}
+
+void XSecController::setDate(
+ sal_Int32 nSecurityId,
+ const css::util::DateTime& rDateTime )
+{
+ int index = findSignatureInfor( nSecurityId );
+
+ if ( index == -1 )
+ {
+ InternalSignatureInformation isi(nSecurityId, nullptr);
+ isi.signatureInfor.stDateTime = rDateTime;
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ SignatureInformation &si
+ = m_vInternalSignatureInformations[index].signatureInfor;
+ si.stDateTime = rDateTime;
+ }
+}
+
+void XSecController::setDescription(sal_Int32 nSecurityId, const OUString& rDescription)
+{
+ int nIndex = findSignatureInfor(nSecurityId);
+
+ if (nIndex == -1)
+ {
+ InternalSignatureInformation aInformation(nSecurityId, nullptr);
+ aInformation.signatureInfor.ouDescription = rDescription;
+ m_vInternalSignatureInformations.push_back(aInformation);
+ }
+ else
+ {
+ SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
+ rInformation.ouDescription = rDescription;
+ }
+}
+
+void XSecController::setSignatureLineId(sal_Int32 nSecurityId, const OUString& rSignatureLineId)
+{
+ int nIndex = findSignatureInfor(nSecurityId);
+
+ if (nIndex == -1)
+ {
+ InternalSignatureInformation aInformation(nSecurityId, nullptr);
+ aInformation.signatureInfor.ouSignatureLineId = rSignatureLineId;
+ m_vInternalSignatureInformations.push_back(aInformation);
+ }
+ else
+ {
+ SignatureInformation& rInformation = m_vInternalSignatureInformations[nIndex].signatureInfor;
+ rInformation.ouSignatureLineId = rSignatureLineId;
+ }
+}
+
+void XSecController::setSignatureLineValidGraphic(sal_Int32 nSecurityId,
+ const Reference<XGraphic>& xValidGraphic)
+{
+ int nIndex = findSignatureInfor(nSecurityId);
+
+ if (nIndex == -1)
+ {
+ InternalSignatureInformation aInformation(nSecurityId, nullptr);
+ aInformation.signatureInfor.aValidSignatureImage = xValidGraphic;
+ m_vInternalSignatureInformations.push_back(aInformation);
+ }
+ else
+ {
+ SignatureInformation& rInformation
+ = m_vInternalSignatureInformations[nIndex].signatureInfor;
+ rInformation.aValidSignatureImage = xValidGraphic;
+ }
+}
+
+void XSecController::setSignatureLineInvalidGraphic(
+ sal_Int32 nSecurityId, const Reference<XGraphic>& xInvalidGraphic)
+{
+ int nIndex = findSignatureInfor(nSecurityId);
+
+ if (nIndex == -1)
+ {
+ InternalSignatureInformation aInformation(nSecurityId, nullptr);
+ aInformation.signatureInfor.aInvalidSignatureImage = xInvalidGraphic;
+ m_vInternalSignatureInformations.push_back(aInformation);
+ }
+ else
+ {
+ SignatureInformation& rInformation
+ = m_vInternalSignatureInformations[nIndex].signatureInfor;
+ rInformation.aInvalidSignatureImage = xInvalidGraphic;
+ }
+}
+
+bool XSecController::WriteSignature(
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& xDocumentHandler,
+ bool bXAdESCompliantIfODF )
+{
+ bool rc = false;
+
+ SAL_WARN_IF( !xDocumentHandler.is(), "xmlsecurity.helper", "I really need a document handler!" );
+
+ /*
+ * chain the SAXEventKeeper to the SAX chain
+ */
+ chainOn();
+
+ if ( m_eStatusOfSecurityComponents == InitializationState::INITIALIZED )
+ /*
+ * if all security components are ready, add the signature
+ * stream.
+ */
+ {
+ m_bIsSAXEventKeeperSticky = true;
+ m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
+
+ try
+ {
+ /*
+ * export the signature template
+ */
+ css::uno::Reference<css::xml::sax::XDocumentHandler> xSEKHandler(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()),css::uno::UNO_QUERY);
+
+ int i;
+ int sigNum = m_vInternalSignatureInformations.size();
+
+ for (i=0; i<sigNum; ++i)
+ {
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations[i];
+
+ // Prepare the signature creator.
+ // 0 is not a documented value of embed::StorageFormats, ugh
+ isi.xReferenceResolvedListener = prepareSignatureToWrite( isi, 0, bXAdESCompliantIfODF );
+
+ exportSignature( xSEKHandler, isi.signatureInfor, bXAdESCompliantIfODF );
+ }
+
+ m_bIsSAXEventKeeperSticky = false;
+ chainOff();
+
+ rc = true;
+ }
+ catch( css::uno::Exception& )
+ {
+ }
+
+ m_xSAXEventKeeper->setNextHandler( nullptr );
+ m_bIsSAXEventKeeperSticky = false;
+ }
+
+ return rc;
+}
+
+bool XSecController::WriteOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler)
+{
+ bool bRet = false;
+
+ SAL_WARN_IF(!xDocumentHandler.is(), "xmlsecurity.helper", "empty xDocumentHandler reference");
+
+ // Chain the SAXEventKeeper to the SAX chain.
+ chainOn();
+
+ if (m_eStatusOfSecurityComponents == InitializationState::INITIALIZED)
+ {
+ m_bIsSAXEventKeeperSticky = true;
+ m_xSAXEventKeeper->setNextHandler(xDocumentHandler);
+
+ try
+ {
+ // Export the signature template.
+ css::uno::Reference<xml::sax::XDocumentHandler> xSEKHandler(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), uno::UNO_QUERY);
+
+ for (InternalSignatureInformation & rInformation : m_vInternalSignatureInformations)
+ {
+ // Prepare the signature creator.
+ rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML, false);
+
+ exportOOXMLSignature(xRootStorage, xSEKHandler, rInformation.signatureInfor);
+ }
+
+ m_bIsSAXEventKeeperSticky = false;
+ chainOff();
+
+ bRet = true;
+ }
+ catch(const uno::Exception&)
+ {
+ }
+
+ m_xSAXEventKeeper->setNextHandler(nullptr);
+ m_bIsSAXEventKeeperSticky = false;
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/helper/xsecverify.cxx b/xmlsecurity/source/helper/xsecverify.cxx
new file mode 100644
index 000000000..c826971b1
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecverify.cxx
@@ -0,0 +1,537 @@
+/* -*- 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 <xsecctl.hxx>
+#include "xsecparser.hxx"
+#include "ooxmlsecparser.hxx"
+#include <framework/signatureverifierimpl.hxx>
+#include <framework/saxeventkeeperimpl.hxx>
+#include <gpg/xmlsignature_gpgimpl.hxx>
+#include <gpg/SEInitializer.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/xml/crypto/sax/XKeyCollector.hpp>
+#include <com/sun/star/xml/crypto/sax/ElementMarkPriority.hpp>
+#include <com/sun/star/xml/crypto/sax/XReferenceCollector.hpp>
+#include <com/sun/star/xml/crypto/sax/XSignatureVerifyResultBroadcaster.hpp>
+#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/embed/StorageFormats.hpp>
+#include <sal/log.hxx>
+#include <unotools/datetime.hxx>
+#include <comphelper/base64.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/seqstream.hxx>
+
+namespace com::sun::star::graphic { class XGraphic; }
+
+using namespace css;
+using namespace css::uno;
+using namespace css::beans;
+
+/* protected: for signature verify */
+css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecController::prepareSignatureToRead(
+ sal_Int32 nSecurityId)
+{
+ if ( m_eStatusOfSecurityComponents != InitializationState::INITIALIZED )
+ {
+ return nullptr;
+ }
+
+ sal_Int32 nIdOfSignatureElementCollector;
+ css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > xReferenceResolvedListener;
+
+ nIdOfSignatureElementCollector =
+ m_xSAXEventKeeper->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY, false);
+
+ m_xSAXEventKeeper->setSecurityId(nIdOfSignatureElementCollector, nSecurityId);
+
+ /*
+ * create a SignatureVerifier
+ */
+ xReferenceResolvedListener = new SignatureVerifierImpl;
+
+ css::uno::Reference<css::lang::XInitialization> xInitialization(xReferenceResolvedListener, css::uno::UNO_QUERY);
+
+ css::uno::Sequence<css::uno::Any> args(5);
+ args[0] <<= OUString::number(nSecurityId);
+ args[1] <<= uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(static_cast<cppu::OWeakObject*>(m_xSAXEventKeeper.get()), uno::UNO_QUERY);
+ args[2] <<= OUString::number(nIdOfSignatureElementCollector);
+ args[3] <<= m_xSecurityContext;
+ args[4] <<= m_xXMLSignature;
+ xInitialization->initialize(args);
+
+ css::uno::Reference< css::xml::crypto::sax::XSignatureVerifyResultBroadcaster >
+ signatureVerifyResultBroadcaster(xReferenceResolvedListener, css::uno::UNO_QUERY);
+
+ signatureVerifyResultBroadcaster->addSignatureVerifyResultListener( this );
+
+ m_xSAXEventKeeper->addReferenceResolvedListener(
+ nIdOfSignatureElementCollector,
+ xReferenceResolvedListener);
+
+ css::uno::Reference<css::xml::crypto::sax::XKeyCollector> keyCollector (xReferenceResolvedListener, css::uno::UNO_QUERY);
+ keyCollector->setKeyId(0);
+
+ return xReferenceResolvedListener;
+}
+
+void XSecController::addSignature()
+{
+ css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > xReferenceResolvedListener;
+ sal_Int32 nSignatureId = 0;
+
+
+ if (m_bVerifyCurrentSignature)
+ {
+ chainOn();
+ xReferenceResolvedListener = prepareSignatureToRead( m_nReservedSignatureId );
+ m_bVerifyCurrentSignature = false;
+ nSignatureId = m_nReservedSignatureId;
+ }
+
+ InternalSignatureInformation isi( nSignatureId, xReferenceResolvedListener );
+ m_vInternalSignatureInformations.push_back( isi );
+}
+
+void XSecController::setSignatureMethod(svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ m_vInternalSignatureInformations.back().signatureInfor.eAlgorithmID = eAlgorithmID;
+}
+
+void XSecController::switchGpgSignature()
+{
+#if HAVE_FEATURE_GPGME
+ // swap signature verifier for the Gpg one
+ m_xXMLSignature.set(new XMLSignature_GpgImpl());
+ if (!m_vInternalSignatureInformations.empty())
+ {
+ SignatureVerifierImpl* pImpl=
+ dynamic_cast<SignatureVerifierImpl*>(
+ m_vInternalSignatureInformations.back().xReferenceResolvedListener.get());
+ if (pImpl)
+ {
+ css::uno::Reference<css::xml::crypto::XSEInitializer> xGpgSEInitializer(
+ new SEInitializerGpg());
+ pImpl->updateSignature(new XMLSignature_GpgImpl(),
+ xGpgSEInitializer->createSecurityContext(OUString()));
+ }
+ }
+#else
+ (void) this;
+#endif
+}
+
+void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID, const OUString& ouType )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::addReference: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1, ouType );
+}
+
+void XSecController::addStreamReference(
+ const OUString& ouUri,
+ bool isBinary,
+ sal_Int32 nDigestID )
+{
+ SignatureReferenceType type = (isBinary?SignatureReferenceType::BINARYSTREAM:SignatureReferenceType::XMLSTREAM);
+
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::addStreamReference: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+
+ if ( isi.xReferenceResolvedListener.is() )
+ {
+ /*
+ * get the input stream
+ */
+ css::uno::Reference< css::io::XInputStream > xObjectInputStream
+ = getObjectInputStream( ouUri );
+
+ if ( xObjectInputStream.is() )
+ {
+ css::uno::Reference<css::xml::crypto::XUriBinding> xUriBinding
+ (isi.xReferenceResolvedListener, css::uno::UNO_QUERY);
+ xUriBinding->setUriBinding(ouUri, xObjectInputStream);
+ }
+ }
+
+ isi.addReference(type, nDigestID, ouUri, -1, OUString());
+}
+
+void XSecController::setReferenceCount() const
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setReferenceCount: no signature");
+ return;
+ }
+ const InternalSignatureInformation &isi =
+ m_vInternalSignatureInformations.back();
+
+ if ( isi.xReferenceResolvedListener.is() )
+ {
+ const SignatureReferenceInformations &refInfors = isi.signatureInfor.vSignatureReferenceInfors;
+
+ int refNum = refInfors.size();
+ sal_Int32 referenceCount = 0;
+
+ for(int i=0 ; i<refNum; ++i)
+ {
+ if (refInfors[i].nType == SignatureReferenceType::SAMEDOCUMENT )
+ /*
+ * same-document reference
+ */
+ {
+ referenceCount++;
+ }
+ }
+
+ css::uno::Reference<css::xml::crypto::sax::XReferenceCollector> xReferenceCollector
+ (isi.xReferenceResolvedListener, css::uno::UNO_QUERY);
+ xReferenceCollector->setReferenceCount( referenceCount );
+ }
+}
+
+void XSecController::setX509IssuerName( OUString const & ouX509IssuerName )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setX509IssuerName: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouX509IssuerName = ouX509IssuerName;
+}
+
+void XSecController::setX509SerialNumber( OUString const & ouX509SerialNumber )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setX509SerialNumber: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouX509SerialNumber = ouX509SerialNumber;
+}
+
+void XSecController::setX509Certificate( OUString const & ouX509Certificate )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setX509Certificate: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouX509Certificate = ouX509Certificate;
+}
+
+void XSecController::setSignatureValue( OUString const & ouSignatureValue )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setSignatureValue: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouSignatureValue = ouSignatureValue;
+}
+
+void XSecController::setDigestValue( sal_Int32 nDigestID, OUString const & ouDigestValue )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setDigestValue: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ if (isi.signatureInfor.vSignatureReferenceInfors.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setDigestValue: no signature reference");
+ return;
+ }
+ SignatureReferenceInformation &reference =
+ isi.signatureInfor.vSignatureReferenceInfors.back();
+ reference.nDigestID = nDigestID;
+ reference.ouDigestValue = ouDigestValue;
+}
+
+void XSecController::setGpgKeyID( OUString const & ouKeyID )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setGpgKeyID: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouGpgKeyID = ouKeyID;
+}
+
+void XSecController::setGpgCertificate( OUString const & ouGpgCert )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setGpgCertificate: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouGpgCertificate = ouGpgCert;
+}
+
+void XSecController::setGpgOwner( OUString const & ouGpgOwner )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setGpgOwner: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouGpgOwner = ouGpgOwner;
+}
+
+void XSecController::setDate( OUString const & ouDate )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setDate: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ (void)utl::ISO8601parseDateTime( ouDate, isi.signatureInfor.stDateTime);
+ isi.signatureInfor.ouDateTime = ouDate;
+}
+
+void XSecController::setDescription(const OUString& rDescription)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.ouDescription = rDescription;
+}
+
+void XSecController::setSignatureBytes(const uno::Sequence<sal_Int8>& rBytes)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.aSignatureBytes = rBytes;
+}
+
+void XSecController::setCertDigest(const OUString& rCertDigest)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.ouCertDigest = rCertDigest;
+}
+
+namespace {
+Reference<css::graphic::XGraphic> lcl_getGraphicFromString(const OUString& rImage)
+{
+ Sequence<sal_Int8> seq;
+ comphelper::Base64::decode(seq, rImage);
+
+ Reference< graphic::XGraphic > xGraphic;
+ if( !seq.hasElements() )
+ return Reference<css::graphic::XGraphic>();
+
+ Reference< graphic::XGraphicProvider > xGraphicProvider(
+ graphic::GraphicProvider::create(comphelper::getProcessComponentContext()) );
+ Reference< io::XInputStream > xInputStream( new ::comphelper::SequenceInputStream( seq ) );
+
+ Sequence< PropertyValue > aArgs( 1 );
+ aArgs[ 0 ].Name = "InputStream";
+ aArgs[ 0 ].Value <<= xInputStream;
+ xGraphic = xGraphicProvider->queryGraphic(aArgs);
+
+ return xGraphic;
+}
+}
+
+void XSecController::setValidSignatureImage(const OUString& rValidSigImg)
+{
+ if (m_vInternalSignatureInformations.empty() || rValidSigImg.isEmpty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.aValidSignatureImage = lcl_getGraphicFromString(rValidSigImg);
+}
+
+void XSecController::setInvalidSignatureImage(const OUString& rInvalidSigImg)
+{
+ if (m_vInternalSignatureInformations.empty() || rInvalidSigImg.isEmpty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.aInvalidSignatureImage = lcl_getGraphicFromString(rInvalidSigImg);
+}
+
+void XSecController::setSignatureLineId(const OUString& rSignatureLineId)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.ouSignatureLineId = rSignatureLineId;
+}
+
+void XSecController::addEncapsulatedX509Certificate(const OUString& rEncapsulatedX509Certificate)
+{
+ if (m_vInternalSignatureInformations.empty())
+ return;
+
+ if (rEncapsulatedX509Certificate.isEmpty())
+ return;
+
+ InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
+ rInformation.signatureInfor.maEncapsulatedX509Certificates.insert(rEncapsulatedX509Certificate);
+}
+
+void XSecController::setId( OUString const & ouId )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setId: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+ isi.signatureInfor.ouSignatureId = ouId;
+}
+
+void XSecController::setPropertyId( OUString const & ouPropertyId )
+{
+ if (m_vInternalSignatureInformations.empty())
+ {
+ SAL_INFO("xmlsecurity.helper","XSecController::setPropertyId: no signature");
+ return;
+ }
+ InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
+
+ if (isi.signatureInfor.ouPropertyId.isEmpty())
+ {
+ // <SignatureProperty> ID attribute is for the date.
+ isi.signatureInfor.ouPropertyId = ouPropertyId;
+ }
+ else
+ {
+ // <SignatureProperty> ID attribute is for the description.
+ isi.signatureInfor.ouDescriptionPropertyId = ouPropertyId;
+ }
+}
+
+/* public: for signature verify */
+void XSecController::collectToVerify( const OUString& referenceId )
+{
+ /* SAL_WARN_IF( !m_xSAXEventKeeper.is(), "xmlsecurity", "the SAXEventKeeper is NULL" ); */
+
+ if ( m_eStatusOfSecurityComponents == InitializationState::INITIALIZED )
+ /*
+ * if all security components are ready, verify the signature.
+ */
+ {
+ bool bJustChainingOn = false;
+ css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler;
+
+ int i,j;
+ int sigNum = m_vInternalSignatureInformations.size();
+
+ for (i=0; i<sigNum; ++i)
+ {
+ InternalSignatureInformation& isi = m_vInternalSignatureInformations[i];
+ SignatureReferenceInformations& vReferenceInfors = isi.signatureInfor.vSignatureReferenceInfors;
+ int refNum = vReferenceInfors.size();
+
+ for (j=0; j<refNum; ++j)
+ {
+ SignatureReferenceInformation &refInfor = vReferenceInfors[j];
+
+ if (refInfor.ouURI == referenceId)
+ {
+ if (chainOn())
+ {
+ bJustChainingOn = true;
+ xHandler = m_xSAXEventKeeper->setNextHandler(nullptr);
+ }
+
+ sal_Int32 nKeeperId = m_xSAXEventKeeper->addSecurityElementCollector(
+ css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY, false );
+
+ css::uno::Reference<css::xml::crypto::sax::XReferenceCollector> xReferenceCollector
+ ( isi.xReferenceResolvedListener, css::uno::UNO_QUERY );
+
+ m_xSAXEventKeeper->setSecurityId(nKeeperId, isi.signatureInfor.nSecurityId);
+ m_xSAXEventKeeper->addReferenceResolvedListener( nKeeperId, isi.xReferenceResolvedListener);
+ xReferenceCollector->setReferenceId( nKeeperId );
+
+ isi.vKeeperIds[j] = nKeeperId;
+ break;
+ }
+ }
+ }
+
+ if ( bJustChainingOn )
+ {
+ m_xSAXEventKeeper->setNextHandler(xHandler);
+ }
+ }
+}
+
+void XSecController::addSignature( sal_Int32 nSignatureId )
+{
+ SAL_WARN_IF( !m_xSecParser.is(), "xmlsecurity.helper", "No XSecParser initialized" );
+
+ m_nReservedSignatureId = nSignatureId;
+ m_bVerifyCurrentSignature = true;
+}
+
+css::uno::Reference< css::xml::sax::XDocumentHandler > const & XSecController::createSignatureReader(XMLSignatureHelper& rXMLSignatureHelper, sal_Int32 nType)
+{
+ if (nType == embed::StorageFormats::OFOPXML)
+ m_xSecParser = new OOXMLSecParser(rXMLSignatureHelper, this);
+ else
+ m_xSecParser = new XSecParser(rXMLSignatureHelper, this);
+ css::uno::Reference< css::lang::XInitialization > xInitialization(m_xSecParser, uno::UNO_QUERY);
+
+ setSAXChainConnector(xInitialization);
+
+ return m_xSecParser;
+}
+
+void XSecController::releaseSignatureReader()
+{
+ clearSAXChainConnector( );
+ m_xSecParser.clear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */