6e26799069
Change-Id: Ifb936c230f68447b3bb5993705adb5e5b790371f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167668 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Jenkins
462 lines
16 KiB
C++
462 lines
16 KiB
C++
/* -*- 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)
|
|
{
|
|
SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
|
|
length += sprintf(str+length, "%04x", i);
|
|
SAL_WNODEPRECATED_DECLARATIONS_POP
|
|
}
|
|
|
|
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, u"http://uri.etsi.org/01903#SignedProperties"_ustr);
|
|
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: */
|