28#include <tools/datetime.hxx>
30#include <com/sun/star/io/XOutputStream.hpp>
31#include <com/sun/star/io/XInputStream.hpp>
32#include <com/sun/star/io/XTruncate.hpp>
33#include <com/sun/star/beans/XPropertySet.hpp>
34#include <com/sun/star/beans/StringPair.hpp>
35#include <com/sun/star/xml/sax/Parser.hpp>
36#include <com/sun/star/xml/sax/Writer.hpp>
37#include <com/sun/star/embed/ElementModes.hpp>
38#include <com/sun/star/embed/XStorage.hpp>
39#include <com/sun/star/embed/StorageFormats.hpp>
40#include <com/sun/star/embed/XTransactedObject.hpp>
46#include <rtl/ustrbuf.hxx>
53constexpr OUStringLiteral
OOXML_SIGNATURE_ORIGIN =
u"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
54constexpr OUStringLiteral
OOXML_SIGNATURE_SIGNATURE =
u"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature";
61 :
mxCtx(rxCtx), mbODFPre1_2(false)
72 const Reference < css::embed::XStorage >& rxStorage,
73 std::u16string_view sODFVersion)
77 SAL_WARN_IF(!rxStorage.is(),
"xmlsecurity.helper",
"SetStorage - empty storage!");
107 sal_Int32 nSecurityId,
108 const OUString& ouX509IssuerName,
109 const OUString& ouX509SerialNumber,
110 const OUString& ouX509Cert,
111 const OUString& ouX509CertDigest,
125 mpXSecController->addEncapsulatedX509Certificate(ouEncapsulatedX509Certificate);
129 const OUString& ouGpgCertDigest,
130 const OUString& ouGpgCert,
131 const OUString& ouGpgOwner)
142 css::util::DateTime stDateTime = rDateTime.GetUNODateTime();
157 sal_Int32 nSecurityId,
const css::uno::Reference<XGraphic>& xValidGraphic)
163 sal_Int32 nSecurityId,
const css::uno::Reference<XGraphic>& xInvalidGraphic)
165 mpXSecController->setSignatureLineInvalidGraphic(nSecurityId, xInvalidGraphic);
170 mpXSecController->signAStream( nSecurityId, uri, bBinary, bXAdESCompliantIfODF );
175 const css::uno::Reference< css::io::XOutputStream >& xOutputStream )
180 uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(
mxCtx);
185 xSaxWriter->setOutputStream( xOutputStream );
197 pAttributeList->AddAttribute(
201 xSaxWriter->startDocument();
202 xSaxWriter->startElement(
203 "document-signatures",
211 xDocumentHandler->endElement(
"document-signatures" );
212 xDocumentHandler->endDocument();
216 const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler,
218 bool bXAdESCompliantIfODF )
225 uno::Reference<io::XOutputStream> xOutputStream(xSignatureStorage->openStreamElement(
"sig" + OUString::number(nSignatureIndex) +
".xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
232 uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(
mxCtx);
233 xSaxWriter->setOutputStream(xOutputStream);
234 xSaxWriter->startDocument();
236 mpXSecController->exportOOXMLSignature(xRootStorage, xSaxWriter, rInformation);
238 xSaxWriter->endDocument();
246 if ( !
mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) )
256 SAL_WARN_IF(!xInputStream.is(),
"xmlsecurity.helper",
"input stream missing");
259 xml::sax::InputSource aParserInput;
260 aParserInput.aInputStream = xInputStream;
263 uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(
mxCtx);
266 uno::Reference< xml::sax::XDocumentHandler > xHandler
271 xParser->setDocumentHandler( xHandler );
276 xParser->parseStream( aParserInput );
278 catch( uno::Exception& )
311bool lcl_isSignatureType(
const beans::StringPair& rPair)
315bool lcl_isSignatureOriginType(
const beans::StringPair& rPair)
323 sal_Int32 nOpenMode = embed::ElementModes::READ;
324 if (xStorage.is() && !xStorage->hasByName(
"_rels"))
326 SAL_WARN(
"xmlsecurity.helper",
"expected stream, in signature storage but not found: _rels");
330 uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement(
"_rels", nOpenMode);
331 uno::Reference<io::XInputStream> xRelStream(xSubStorage->openStreamElement(
"origin.sigs.rels", nOpenMode), uno::UNO_QUERY);
334 for (sal_Int32
i = 0;
i < aRelationsInfo.getLength(); ++
i)
336 const uno::Sequence<beans::StringPair>& rRelation = aRelationsInfo[
i];
337 if (std::any_of(rRelation.begin(), rRelation.end(), lcl_isSignatureType))
339 auto it = std::find_if(rRelation.begin(), rRelation.end(), [](
const beans::StringPair& rPair) { return rPair.First ==
"Target"; });
340 if (it != rRelation.end())
342 if (xStorage.is() && !xStorage->hasByName(it->Second))
344 SAL_WARN(
"xmlsecurity.helper",
"expected stream, but not found: " << it->Second);
348 uno::Reference<io::XInputStream> xInputStream(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
354 if (!bCacheLastSignature &&
i == aRelationsInfo.getLength() - 1)
360 xInputStream.clear();
361 xInputStream.set(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
362 uno::Reference<beans::XPropertySet> xPropertySet(xInputStream, uno::UNO_QUERY);
363 if (!xPropertySet.is())
367 xPropertySet->getPropertyValue(
"Size") >>= nSize;
370 SAL_WARN(
"xmlsecurity.helper",
"bogus signature size: " << nSize);
373 uno::Sequence<sal_Int8>
aData;
374 xInputStream->readBytes(
aData, nSize);
388 xml::sax::InputSource aParserInput;
389 aParserInput.aInputStream = xInputStream;
392 uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(
mxCtx);
395 uno::Reference<xml::sax::XDocumentHandler> xHandler =
mpXSecController->createSignatureReader(*
this, embed::StorageFormats::OFOPXML);
398 xParser->setDocumentHandler(xHandler);
403 xParser->parseStream(aParserInput);
405 catch(
const uno::Exception&)
419 sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
420 uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement(
"_rels", nOpenMode);
421 uno::Reference<io::XInputStream> xRelStream(xSubStorage->openStreamElement(
".rels", nOpenMode), uno::UNO_QUERY);
425 bool bHaveRelation =
false;
427 for (
const uno::Sequence<beans::StringPair>& rRelation : aRelationsInfo)
429 auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rRelation);
430 if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureOriginType))
432 bHaveRelation =
true;
438 if (!bHaveRelation && bAdd)
441 std::vector<beans::StringPair> aRelation;
442 aRelation.emplace_back(
"Id",
"rId" + OUString::number(++
nCount));
444 aRelation.emplace_back(
"Target",
"_xmlsignatures/origin.sigs");
447 else if (bHaveRelation && !bAdd)
450 for (std::vector< uno::Sequence<beans::StringPair> >::iterator it = aRelationsInfo.begin(); it != aRelationsInfo.end();)
452 auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(*it);
453 if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureOriginType))
454 it = aRelationsInfo.erase(it);
461 uno::Reference<io::XTruncate> xTruncate(xRelStream, uno::UNO_QUERY);
462 xTruncate->truncate();
463 uno::Reference<io::XOutputStream> xOutputStream(xRelStream, uno::UNO_QUERY);
467 uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
469 xTransact.set(xStorage, uno::UNO_QUERY);
476 sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
477 uno::Reference<io::XOutputStream> xOriginStream(xStorage->openStreamElement(
"origin.sigs", nOpenMode), uno::UNO_QUERY);
478 uno::Reference<io::XTruncate> xTruncate(xOriginStream, uno::UNO_QUERY);
479 xTruncate->truncate();
480 xOriginStream->closeOutput();
483 uno::Reference<embed::XStorage> xSubStorage = xStorage->openStorageElement(
"_rels", nOpenMode);
484 uno::Reference<io::XOutputStream> xRelStream(xSubStorage->openStreamElement(
"origin.sigs.rels", nOpenMode), uno::UNO_QUERY);
485 std::vector< uno::Sequence<beans::StringPair> > aRelations;
486 for (
int i = 0;
i < nSignatureCount; ++
i)
488 std::vector<beans::StringPair> aRelation;
489 aRelation.emplace_back(
"Id",
"rId" + OUString::number(
i + 1));
491 aRelation.emplace_back(
"Target",
"sig" + OUString::number(
i + 1) +
".xml");
495 uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
501 uno::Reference<io::XStream>
xStream = xStorage->openStreamElement(
"[Content_Types].xml", embed::ElementModes::READWRITE);
502 uno::Reference<io::XInputStream> xInputStream =
xStream->getInputStream();
504 if (aContentTypeInfo.getLength() < 2)
506 SAL_WARN(
"xmlsecurity.helper",
"no defaults or overrides in aContentTypeInfo");
509 auto pContentTypeInfo = aContentTypeInfo.getArray();
512 uno::Sequence<beans::StringPair>& rDefaults = pContentTypeInfo[0];
513 auto aDefaults = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rDefaults);
514 if (std::none_of(std::cbegin(rDefaults), std::cend(rDefaults), [](
const beans::StringPair& rPair) {
return rPair.First ==
"rels"; }))
515 aDefaults.emplace_back(
"rels",
"application/vnd.openxmlformats-package.relationships+xml");
517 if (std::none_of(std::cbegin(rDefaults), std::cend(rDefaults), [](
const beans::StringPair& rPair) {
return rPair.First ==
"sigs"; }))
518 aDefaults.emplace_back(
"sigs",
"application/vnd.openxmlformats-package.digital-signature-origin");
522 uno::Sequence<beans::StringPair>& rOverrides = pContentTypeInfo[1];
523 auto aOverrides = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rOverrides);
524 aOverrides.erase(std::remove_if(aOverrides.begin(), aOverrides.end(), [](
const beans::StringPair& rPair)
526 return rPair.First.startsWith(
"/_xmlsignatures/sig");
527 }), aOverrides.end());
530 for (
int i = 1;
i <= nSignatureCount; ++
i)
531 aOverrides.emplace_back(
"/_xmlsignatures/sig" + OUString::number(
i) +
".xml",
"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml");
534 uno::Reference<io::XOutputStream> xOutputStream =
xStream->getOutputStream();
535 uno::Reference <io::XTruncate> xTruncate(xOutputStream, uno::UNO_QUERY);
536 xTruncate->truncate();
538 uno::Reference<embed::XTransactedObject> xTransact(xStorage, uno::UNO_QUERY);
543 uno::Reference<io::XOutputStream> xOutputStream(xSignatureStorage->openStreamElement(
"sig" + OUString::number(nSignatureIndex) +
".xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
544 uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(
mxCtx);
545 xSaxWriter->setOutputStream(xOutputStream);
546 xSaxWriter->startDocument();
552 xSaxWriter->endDocument();
562 uno::Reference<xml::crypto::XSecurityEnvironment>
const& xSecEnv,
563 std::vector<SignatureInformation::X509CertInfo>
const& rX509CertInfos,
564 std::vector<uno::Reference<security::XCertificate>> & rCerts,
565 std::vector<SignatureInformation::X509CertInfo> & rSorted) ->
bool
567 assert(rCerts.empty());
568 assert(rSorted.empty());
569 if (rX509CertInfos.empty())
571 SAL_WARN(
"xmlsecurity.comp",
"no X509Data");
574 std::vector<uno::Reference<security::XCertificate>> certs;
577 if (!it.X509Certificate.isEmpty())
579 certs.emplace_back(xSecEnv->createCertificateFromAscii(it.X509Certificate));
583 certs.emplace_back(xSecEnv->getCertificate(
587 if (!certs.back().is())
589 SAL_WARN(
"xmlsecurity.comp",
"X509Data cannot be parsed");
595 std::optional<size_t>
start;
596 for (
size_t i = 0;
i < certs.size(); ++
i)
598 for (
size_t j = 0; ; ++j)
600 if (j == certs.size())
604 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: certificate has no issuer but already have start of chain: " << certs[
i]->getSubjectName());
616 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: certificate is self-signed but already have start of chain: " << certs[
i]->getSubjectName());
625 std::vector<size_t> chain;
629 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: cycle detected");
632 chain.emplace_back(*
start);
635 for (
size_t i = 0;
i < certs.size(); ++
i)
637 assert(chain.size() ==
i + 1);
638 for (
size_t j = 0; j < certs.size(); ++j)
645 if (chain.size() !=
i + 1)
647 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: certificate issued 2 others: " << certs[chain[
i]]->getSubjectName());
650 chain.emplace_back(j);
654 if (
i == certs.size() - 1)
656 if (chain.size() !=
i + 1)
658 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: certificate in cycle: " << certs[chain[
i]]->getSubjectName());
662 else if (chain.size() !=
i + 2)
664 SAL_WARN(
"xmlsecurity.comp",
"X509Data do not form a chain: certificate issued 0 others: " << certs[chain[
i]]->getSubjectName());
670 assert(chain.size() == rX509CertInfos.size());
671 for (
auto const& it : chain)
673 rSorted.emplace_back(rX509CertInfos[it]);
674 rCerts.emplace_back(certs[it]);
679std::vector<uno::Reference<security::XCertificate>>
681 uno::Reference<xml::crypto::XSecurityEnvironment>
const& xSecEnv,
689 std::vector<uno::Reference<security::XCertificate>> certs;
690 std::vector<SignatureInformation::X509Data> datas;
696 for (
auto const& rData : rInfo.
X509Datas)
698 for (
auto const& it : rData)
700 temp.emplace_back(it);
705 datas.emplace_back(tempResult);
bool ReadAndVerifySignatureStorage(const css::uno::Reference< css::embed::XStorage > &xStorage, bool bCacheLastSignature=true)
Read and verify OOXML signatures.
rtl::Reference< XSecController > mpXSecController
void SetGpgCertificate(sal_Int32 nSecurityId, const OUString &ouGpgCertDigest, const OUString &ouGpgCert, const OUString &ouGpgOwner)
void AddEncapsulatedX509Certificate(const OUString &ouEncapsulatedX509Certificate)
SignatureInformations GetSignatureInformations() const
bool ReadAndVerifySignature(const css::uno::Reference< css::io::XInputStream > &xInputStream)
css::uno::Reference< css::uno::XComponentContext > mxCtx
void StartMission(const css::uno::Reference< css::xml::crypto::XXMLSecurityContext > &xSecurityContext)
void SetSignatureLineInvalidGraphic(sal_Int32 nSecurityId, const css::uno::Reference< css::graphic::XGraphic > &xInvalidGraphic)
void SetX509Certificate(sal_Int32 nSecurityId, const OUString &ouX509IssuerName, const OUString &ouX509SerialNumber, const OUString &ouX509Cert, const OUString &ouX509CertDigest, svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
sets data that describes the certificate.
void CreateAndWriteOOXMLSignature(const css::uno::Reference< css::embed::XStorage > &xRootStorage, const css::uno::Reference< css::embed::XStorage > &xSignatureStorage, int nSignatureIndex)
Given that xSignatureStorage is an OOXML _xmlsignatures storage, create and write a new signature.
void ExportSignatureContentTypes(const css::uno::Reference< css::embed::XStorage > &xStorage, int nSignatureCount)
Given that xStorage is an OOXML root storage, advertise signatures in its [Content_Types]....
bool ReadAndVerifySignatureStorageStream(const css::uno::Reference< css::io::XInputStream > &xInputStream)
Read and verify a single OOXML signature.
XMLSignatureHelper(const XMLSignatureHelper &)=delete
void SetStartVerifySignatureHdl(const Link< LinkParamNone *, bool > &rLink)
void SetSignatureLineValidGraphic(sal_Int32 nSecurityId, const css::uno::Reference< css::graphic::XGraphic > &xValidGraphic)
sal_Int32 GetNewSecurityId()
SignatureInformation GetSignatureInformation(sal_Int32 nSecurityId) const
void SetStorage(const css::uno::Reference< css::embed::XStorage > &rxStorage, std::u16string_view sODFVersion)
void StartVerifySignatureElement()
std::vector< css::uno::Reference< css::security::XCertificate > > CheckAndUpdateSignatureInformation(css::uno::Reference< css::xml::crypto::XSecurityEnvironment > const &xSecEnv, SignatureInformation const &rInfo)
ImplVerifySignature calls this to figure out which X509Data is the signing certificate and update the...
void SetDescription(sal_Int32 nSecurityId, const OUString &rDescription)
static void ExportSignature(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, const SignatureInformation &signatureInfo, bool bXAdESCompliantIfODF)
void SetSignatureLineId(sal_Int32 nSecurityId, const OUString &rSignatureLineId)
rtl::Reference< UriBindingHelper > mxUriBinding
void CreateAndWriteSignature(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, bool bXAdESCompliantIfODF)
static void CloseDocumentHandler(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler)
void ExportOOXMLSignature(const css::uno::Reference< css::embed::XStorage > &xRootStorage, const css::uno::Reference< css::embed::XStorage > &xSignatureStorage, const SignatureInformation &rInformation, int nSignatureIndex)
Similar to CreateAndWriteOOXMLSignature(), but used to write the signature to the persistent storage,...
void AddForSigning(sal_Int32 securityId, const OUString &uri, bool bBinary, bool bXAdESCompliantIfODF)
void ExportSignatureRelations(const css::uno::Reference< css::embed::XStorage > &xStorage, int nSignatureCount)
Given that xStorage is an OOXML _xmlsignatures storage, create origin.sigs and its relations.
css::uno::Reference< css::xml::sax::XWriter > CreateDocumentHandlerWithHeader(const css::uno::Reference< css::io::XOutputStream > &xOutputStream)
void EnsureSignaturesRelation(const css::uno::Reference< css::embed::XStorage > &xStorage, bool bAdd)
Adds or removes an OOXML digital signature relation to _rels/.rels if there wasn't any before.
void SetDateTime(sal_Int32 nSecurityId, const DateTime &rDateTime)
Link< LinkParamNone *, bool > maStartVerifySignatureHdl
static void exportSignature(const css::uno::Reference< css::xml::sax::XDocumentHandler > &xDocumentHandler, const SignatureInformation &signatureInfo, bool bXAdESCompliantIfODF)
#define DBG_UNHANDLED_EXCEPTION(...)
Reference< XComponentContext > mxCtx
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
bool isODFPre_1_2(std::u16string_view sODFVersion)
constexpr OUStringLiteral aData
uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence(const uno::Reference< io::XInputStream > &xInStream, const uno::Reference< uno::XComponentContext > &rContext)
void WriteContentSequence(const uno::Reference< io::XOutputStream > &xOutStream, const uno::Sequence< beans::StringPair > &aDefaultsSequence, const uno::Sequence< beans::StringPair > &aOverridesSequence, const uno::Reference< uno::XComponentContext > &rContext)
uno::Sequence< uno::Sequence< beans::StringPair > > ReadRelationsInfoSequence(const uno::Reference< io::XInputStream > &xInStream, std::u16string_view aStreamName, const uno::Reference< uno::XComponentContext > &rContext)
void WriteRelationsInfoSequence(const uno::Reference< io::XOutputStream > &xOutStream, const uno::Sequence< uno::Sequence< beans::StringPair > > &aSequence, const uno::Reference< uno::XComponentContext > &rContext)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Sequence< sal_Int8 > numericStringToBigInteger(std::u16string_view numeral)
bool EqualDistinguishedNames(std::u16string_view const rName1, std::u16string_view const rName2, EqualMode const eMode)
::std::vector< SignatureInformation > SignatureInformations
static auto CheckX509Data(uno::Reference< xml::crypto::XSecurityEnvironment > const &xSecEnv, std::vector< SignatureInformation::X509CertInfo > const &rX509CertInfos, std::vector< uno::Reference< security::XCertificate > > &rCerts, std::vector< SignatureInformation::X509CertInfo > &rSorted) -> bool
check this constraint from xmldsig-core 4.5.4:
constexpr OUStringLiteral NS_DOCUMENTSIGNATURES
constexpr OUStringLiteral NS_DOCUMENTSIGNATURES_ODF_1_2
constexpr OUStringLiteral OOXML_SIGNATURE_ORIGIN
constexpr OUStringLiteral OOXML_SIGNATURE_SIGNATURE