summaryrefslogtreecommitdiffstats
path: root/xmlsecurity/source/helper/xsecsign.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xmlsecurity/source/helper/xsecsign.cxx460
1 files changed, 460 insertions, 0 deletions
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
new file mode 100644
index 000000000..5634ed502
--- /dev/null
+++ b/xmlsecurity/source/helper/xsecsign.cxx
@@ -0,0 +1,460 @@
+/* -*- 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
+ {
+ Any(OUString::number(nSecurityId)),
+ Any(uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(m_xSAXEventKeeper)),
+ Any(OUString::number(nIdOfSignatureElementCollector)),
+
+ //for nss, the internal module is used for signing, which needs to be improved later
+ Any(m_xSecurityContext->getSecurityEnvironment()),
+ Any(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);
+
+ 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);
+ 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.ouDateTimePropertyId = createId();
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDateTimePropertyId, -1, OUString() );
+ size++;
+
+ if (bXAdESCompliantIfODF)
+ {
+ OUString aId = "idSignedProperties_" + internalSignatureInfor.signatureInfor.ouSignatureId;
+ // We write a new reference, so it's possible to use the correct type URI.
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, aId, -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 // OOXML
+ {
+ OUString aID = createId();
+ internalSignatureInfor.signatureInfor.ouSignatureId = aID;
+
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject_" + aID, -1, OUString());
+ size++;
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject_" + aID, -1, OUString());
+ size++;
+ internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties_" + aID, -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;
+}
+
+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());
+ }
+}
+
+// note: this is called when creating a new signature from scratch
+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.X509Datas.clear();
+ isi.signatureInfor.X509Datas.emplace_back();
+ isi.signatureInfor.X509Datas.back().emplace_back();
+ isi.signatureInfor.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
+ isi.signatureInfor.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
+ isi.signatureInfor.X509Datas.back().back().X509Certificate = ouX509Cert;
+ isi.signatureInfor.X509Datas.back().back().CertDigest = ouX509CertDigest;
+ isi.signatureInfor.eAlgorithmID = eAlgorithmID;
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ SignatureInformation &si
+ = m_vInternalSignatureInformations[index].signatureInfor;
+ si.X509Datas.clear();
+ si.X509Datas.emplace_back();
+ si.X509Datas.back().emplace_back();
+ si.X509Datas.back().back().X509IssuerName = ouX509IssuerName;
+ si.X509Datas.back().back().X509SerialNumber = ouX509SerialNumber;
+ si.X509Datas.back().back().X509Certificate = ouX509Cert;
+ si.X509Datas.back().back().CertDigest = ouX509CertDigest;
+ }
+}
+
+void XSecController::setGpgCertificate(
+ sal_Int32 nSecurityId,
+ const OUString& ouKeyDigest,
+ 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.ouGpgKeyID = ouKeyDigest;
+ m_vInternalSignatureInformations.push_back( isi );
+ }
+ else
+ {
+ SignatureInformation &si
+ = m_vInternalSignatureInformations[index].signatureInfor;
+ si.X509Datas.clear(); // it is a PGP signature now
+ si.ouGpgCertificate = ouCert;
+ si.ouGpgOwner = ouOwner;
+ si.ouGpgKeyID = ouKeyDigest;
+ }
+}
+
+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(m_xSAXEventKeeper);
+
+ 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(m_xSAXEventKeeper);
+
+ 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: */