1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <xmlsignaturehelper.hxx>
22 #include <documentsignaturehelper.hxx>
23 #include <xsecctl.hxx>
24 #include <biginteger.hxx>
26 #include <UriBindingHelper.hxx>
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>
42 #include <comphelper/attributelist.hxx>
43 #include <comphelper/ofopxmlhelper.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <comphelper/diagnose_ex.hxx>
46 #include <rtl/ustrbuf.hxx>
47 #include <sal/log.hxx>
51 constexpr OUStringLiteral NS_DOCUMENTSIGNATURES
= u
"http://openoffice.org/2004/documentsignatures";
52 constexpr OUStringLiteral NS_DOCUMENTSIGNATURES_ODF_1_2
= u
"urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0";
53 constexpr OUStringLiteral OOXML_SIGNATURE_ORIGIN
= u
"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
54 constexpr OUStringLiteral OOXML_SIGNATURE_SIGNATURE
= u
"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature";
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::graphic
;
58 using namespace ::com::sun::star::uno
;
60 XMLSignatureHelper::XMLSignatureHelper( const uno::Reference
< uno::XComponentContext
>& rxCtx
)
61 : mxCtx(rxCtx
), mbODFPre1_2(false)
63 mpXSecController
= new XSecController(rxCtx
);
67 XMLSignatureHelper::~XMLSignatureHelper()
71 void XMLSignatureHelper::SetStorage(
72 const Reference
< css::embed::XStorage
>& rxStorage
,
73 std::u16string_view sODFVersion
)
75 SAL_WARN_IF( mxUriBinding
.is(), "xmlsecurity.helper", "SetStorage - UriBinding already set!" );
76 mxUriBinding
= new UriBindingHelper( rxStorage
);
77 SAL_WARN_IF(!rxStorage
.is(), "xmlsecurity.helper", "SetStorage - empty storage!");
78 mbODFPre1_2
= DocumentSignatureHelper::isODFPre_1_2(sODFVersion
);
82 void XMLSignatureHelper::SetStartVerifySignatureHdl( const Link
<LinkParamNone
*,bool>& rLink
)
84 maStartVerifySignatureHdl
= rLink
;
88 void XMLSignatureHelper::StartMission(const uno::Reference
<xml::crypto::XXMLSecurityContext
>& xSecurityContext
)
90 if ( !mxUriBinding
.is() )
91 mxUriBinding
= new UriBindingHelper();
93 mpXSecController
->startMission(mxUriBinding
, xSecurityContext
);
96 void XMLSignatureHelper::EndMission()
98 mpXSecController
->endMission();
101 sal_Int32
XMLSignatureHelper::GetNewSecurityId()
103 return mpXSecController
->getNewSecurityId();
106 void XMLSignatureHelper::SetX509Certificate(
107 sal_Int32 nSecurityId
,
108 const OUString
& ouX509IssuerName
,
109 const OUString
& ouX509SerialNumber
,
110 const OUString
& ouX509Cert
,
111 const OUString
& ouX509CertDigest
,
112 svl::crypto::SignatureMethodAlgorithm eAlgorithmID
)
114 mpXSecController
->setX509Certificate(
123 void XMLSignatureHelper::AddEncapsulatedX509Certificate(const OUString
& ouEncapsulatedX509Certificate
)
125 mpXSecController
->addEncapsulatedX509Certificate(ouEncapsulatedX509Certificate
);
128 void XMLSignatureHelper::SetGpgCertificate(sal_Int32 nSecurityId
,
129 const OUString
& ouGpgCertDigest
,
130 const OUString
& ouGpgCert
,
131 const OUString
& ouGpgOwner
)
133 mpXSecController
->setGpgCertificate(
140 void XMLSignatureHelper::SetDateTime( sal_Int32 nSecurityId
, const ::DateTime
& rDateTime
)
142 css::util::DateTime stDateTime
= rDateTime
.GetUNODateTime();
143 mpXSecController
->setDate( nSecurityId
, stDateTime
);
146 void XMLSignatureHelper::SetDescription(sal_Int32 nSecurityId
, const OUString
& rDescription
)
148 mpXSecController
->setDescription(nSecurityId
, rDescription
);
151 void XMLSignatureHelper::SetSignatureLineId(sal_Int32 nSecurityId
, const OUString
& rSignatureLineId
)
153 mpXSecController
->setSignatureLineId(nSecurityId
, rSignatureLineId
);
156 void XMLSignatureHelper::SetSignatureLineValidGraphic(
157 sal_Int32 nSecurityId
, const css::uno::Reference
<XGraphic
>& xValidGraphic
)
159 mpXSecController
->setSignatureLineValidGraphic(nSecurityId
, xValidGraphic
);
162 void XMLSignatureHelper::SetSignatureLineInvalidGraphic(
163 sal_Int32 nSecurityId
, const css::uno::Reference
<XGraphic
>& xInvalidGraphic
)
165 mpXSecController
->setSignatureLineInvalidGraphic(nSecurityId
, xInvalidGraphic
);
168 void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId
, const OUString
& uri
, bool bBinary
, bool bXAdESCompliantIfODF
)
170 mpXSecController
->signAStream( nSecurityId
, uri
, bBinary
, bXAdESCompliantIfODF
);
174 uno::Reference
<xml::sax::XWriter
> XMLSignatureHelper::CreateDocumentHandlerWithHeader(
175 const css::uno::Reference
< css::io::XOutputStream
>& xOutputStream
)
178 * get SAX writer component
180 uno::Reference
< xml::sax::XWriter
> xSaxWriter
= xml::sax::Writer::create(mxCtx
);
183 * connect XML writer to output stream
185 xSaxWriter
->setOutputStream( xOutputStream
);
188 * write the xml context for signatures
190 rtl::Reference
<comphelper::AttributeList
> pAttributeList
= new comphelper::AttributeList();
193 sNamespace
= NS_DOCUMENTSIGNATURES
;
195 sNamespace
= NS_DOCUMENTSIGNATURES_ODF_1_2
;
197 pAttributeList
->AddAttribute(
201 xSaxWriter
->startDocument();
202 xSaxWriter
->startElement(
203 "document-signatures",
209 void XMLSignatureHelper::CloseDocumentHandler( const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
)
211 xDocumentHandler
->endElement( "document-signatures" );
212 xDocumentHandler
->endDocument();
215 void XMLSignatureHelper::ExportSignature(
216 const uno::Reference
< xml::sax::XDocumentHandler
>& xDocumentHandler
,
217 const SignatureInformation
& signatureInfo
,
218 bool bXAdESCompliantIfODF
)
220 XSecController::exportSignature(xDocumentHandler
, signatureInfo
, bXAdESCompliantIfODF
);
223 void XMLSignatureHelper::ExportOOXMLSignature(const uno::Reference
<embed::XStorage
>& xRootStorage
, const uno::Reference
<embed::XStorage
>& xSignatureStorage
, const SignatureInformation
& rInformation
, int nSignatureIndex
)
225 uno::Reference
<io::XOutputStream
> xOutputStream(xSignatureStorage
->openStreamElement("sig" + OUString::number(nSignatureIndex
) + ".xml", embed::ElementModes::READWRITE
), uno::UNO_QUERY
);
227 if (rInformation
.aSignatureBytes
.hasElements())
228 // This is a signature roundtrip, just write back the signature as-is.
229 xOutputStream
->writeBytes(rInformation
.aSignatureBytes
);
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();
242 void XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference
< xml::sax::XDocumentHandler
>& xDocumentHandler
, bool bXAdESCompliantIfODF
)
246 if ( !mpXSecController
->WriteSignature( xDocumentHandler
, bXAdESCompliantIfODF
) )
252 bool XMLSignatureHelper::ReadAndVerifySignature( const css::uno::Reference
< css::io::XInputStream
>& xInputStream
)
256 SAL_WARN_IF(!xInputStream
.is(), "xmlsecurity.helper", "input stream missing");
258 // prepare ParserInputSource
259 xml::sax::InputSource aParserInput
;
260 aParserInput
.aInputStream
= xInputStream
;
262 // get SAX parser component
263 uno::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create(mxCtx
);
265 // create a signature reader
266 uno::Reference
< xml::sax::XDocumentHandler
> xHandler
267 = mpXSecController
->createSignatureReader(*this);
269 // setup the connection:
270 // Parser -> SignatureReader
271 xParser
->setDocumentHandler( xHandler
);
276 xParser
->parseStream( aParserInput
);
278 catch( uno::Exception
& )
280 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
284 // release the signature reader
285 mpXSecController
->releaseSignatureReader( );
290 SignatureInformation
XMLSignatureHelper::GetSignatureInformation( sal_Int32 nSecurityId
) const
292 return mpXSecController
->getSignatureInformation( nSecurityId
);
295 SignatureInformations
XMLSignatureHelper::GetSignatureInformations() const
297 return mpXSecController
->getSignatureInformations();
300 void XMLSignatureHelper::StartVerifySignatureElement()
302 if ( !maStartVerifySignatureHdl
.IsSet() || maStartVerifySignatureHdl
.Call(nullptr) )
304 sal_Int32 nSignatureId
= mpXSecController
->getNewSecurityId();
305 mpXSecController
->addSignature( nSignatureId
);
311 bool lcl_isSignatureType(const beans::StringPair
& rPair
)
313 return rPair
.First
== "Type" && rPair
.Second
== OOXML_SIGNATURE_SIGNATURE
;
315 bool lcl_isSignatureOriginType(const beans::StringPair
& rPair
)
317 return rPair
.First
== "Type" && rPair
.Second
== OOXML_SIGNATURE_ORIGIN
;
321 bool XMLSignatureHelper::ReadAndVerifySignatureStorage(const uno::Reference
<embed::XStorage
>& xStorage
, bool bCacheLastSignature
)
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
);
332 uno::Sequence
< uno::Sequence
<beans::StringPair
> > aRelationsInfo
= comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream
, u
"origin.sigs.rels", mxCtx
);
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
);
349 if (!ReadAndVerifySignatureStorageStream(xInputStream
))
352 // By default, we cache. If it's requested, then we don't cache the last signature.
354 if (!bCacheLastSignature
&& i
== aRelationsInfo
.getLength() - 1)
359 // Store the contents of the stream as is, in case we need to write it back later.
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
;
368 if (nSize
< 0 || nSize
> SAL_MAX_INT32
)
370 SAL_WARN("xmlsecurity.helper", "bogus signature size: " << nSize
);
373 uno::Sequence
<sal_Int8
> aData
;
374 xInputStream
->readBytes(aData
, nSize
);
375 mpXSecController
->setSignatureBytes(aData
);
383 bool XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Reference
<css::io::XInputStream
>& xInputStream
)
387 // Create the input source.
388 xml::sax::InputSource aParserInput
;
389 aParserInput
.aInputStream
= xInputStream
;
391 // Create the sax parser.
392 uno::Reference
<xml::sax::XParser
> xParser
= xml::sax::Parser::create(mxCtx
);
394 // Create the signature reader.
395 uno::Reference
<xml::sax::XDocumentHandler
> xHandler
= mpXSecController
->createSignatureReader(*this, embed::StorageFormats::OFOPXML
);
397 // Parser -> signature reader.
398 xParser
->setDocumentHandler(xHandler
);
403 xParser
->parseStream(aParserInput
);
405 catch(const uno::Exception
&)
407 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
411 // release the signature reader
412 mpXSecController
->releaseSignatureReader();
417 void XMLSignatureHelper::EnsureSignaturesRelation(const css::uno::Reference
<css::embed::XStorage
>& xStorage
, bool bAdd
)
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
);
422 std::vector
< uno::Sequence
<beans::StringPair
> > aRelationsInfo
= comphelper::sequenceToContainer
< std::vector
< uno::Sequence
<beans::StringPair
> > >(comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(xRelStream
, u
".rels", mxCtx
));
424 // Do we have a relation already?
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
)
440 // No, and have to add one.
441 std::vector
<beans::StringPair
> aRelation
;
442 aRelation
.emplace_back("Id", "rId" + OUString::number(++nCount
));
443 aRelation
.emplace_back("Type", OOXML_SIGNATURE_ORIGIN
);
444 aRelation
.emplace_back("Target", "_xmlsignatures/origin.sigs");
445 aRelationsInfo
.push_back(comphelper::containerToSequence(aRelation
));
447 else if (bHaveRelation
&& !bAdd
)
449 // Yes, and need to remove it.
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
);
464 comphelper::OFOPXMLHelper::WriteRelationsInfoSequence(xOutputStream
, comphelper::containerToSequence(aRelationsInfo
), mxCtx
);
467 uno::Reference
<embed::XTransactedObject
> xTransact(xSubStorage
, uno::UNO_QUERY
);
469 xTransact
.set(xStorage
, uno::UNO_QUERY
);
473 void XMLSignatureHelper::ExportSignatureRelations(const css::uno::Reference
<css::embed::XStorage
>& xStorage
, int nSignatureCount
)
475 // Write the empty file, its relations will be the signatures.
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();
482 // Write the relations.
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));
490 aRelation
.emplace_back("Type", OOXML_SIGNATURE_SIGNATURE
);
491 aRelation
.emplace_back("Target", "sig" + OUString::number(i
+ 1) + ".xml");
492 aRelations
.push_back(comphelper::containerToSequence(aRelation
));
494 comphelper::OFOPXMLHelper::WriteRelationsInfoSequence(xRelStream
, comphelper::containerToSequence(aRelations
), mxCtx
);
495 uno::Reference
<embed::XTransactedObject
> xTransact(xSubStorage
, uno::UNO_QUERY
);
499 void XMLSignatureHelper::ExportSignatureContentTypes(const css::uno::Reference
<css::embed::XStorage
>& xStorage
, int nSignatureCount
)
501 uno::Reference
<io::XStream
> xStream
= xStorage
->openStreamElement("[Content_Types].xml", embed::ElementModes::READWRITE
);
502 uno::Reference
<io::XInputStream
> xInputStream
= xStream
->getInputStream();
503 uno::Sequence
< uno::Sequence
<beans::StringPair
> > aContentTypeInfo
= comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream
, mxCtx
);
504 if (aContentTypeInfo
.getLength() < 2)
506 SAL_WARN("xmlsecurity.helper", "no defaults or overrides in aContentTypeInfo");
509 auto pContentTypeInfo
= aContentTypeInfo
.getArray();
511 // Append rels and sigs to defaults, if it's not there already.
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");
519 rDefaults
= comphelper::containerToSequence(aDefaults
);
521 // Remove existing signature overrides.
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());
529 // Add our signature overrides.
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");
533 rOverrides
= comphelper::containerToSequence(aOverrides
);
534 uno::Reference
<io::XOutputStream
> xOutputStream
= xStream
->getOutputStream();
535 uno::Reference
<io::XTruncate
> xTruncate(xOutputStream
, uno::UNO_QUERY
);
536 xTruncate
->truncate();
537 comphelper::OFOPXMLHelper::WriteContentSequence(xOutputStream
, rDefaults
, rOverrides
, mxCtx
);
538 uno::Reference
<embed::XTransactedObject
> xTransact(xStorage
, uno::UNO_QUERY
);
541 void XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference
<embed::XStorage
>& xRootStorage
, const uno::Reference
<embed::XStorage
>& xSignatureStorage
, int nSignatureIndex
)
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();
549 if (!mpXSecController
->WriteOOXMLSignature(xRootStorage
, xSaxWriter
))
552 xSaxWriter
->endDocument();
555 /** check this constraint from xmldsig-core 4.5.4:
557 All certificates appearing in an X509Data element MUST relate to the
558 validation key by either containing it or being part of a certification
559 chain that terminates in a certificate containing the validation key.
561 static auto CheckX509Data(
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
;
575 for (SignatureInformation::X509CertInfo
const& it
: rX509CertInfos
)
577 if (!it
.X509Certificate
.isEmpty())
579 certs
.emplace_back(xSecEnv
->createCertificateFromAscii(it
.X509Certificate
));
583 certs
.emplace_back(xSecEnv
->getCertificate(
585 xmlsecurity::numericStringToBigInteger(it
.X509SerialNumber
)));
587 if (!certs
.back().is())
589 SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
594 // first, search one whose issuer isn't in the list, or a self-signed one
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());
607 start
= i
; // issuer isn't in the list
610 if (xmlsecurity::EqualDistinguishedNames(certs
[i
]->getIssuerName(), certs
[j
]->getSubjectName(), xmlsecurity::NOCOMPAT
))
612 if (i
== j
) // self signed
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
;
628 // this can only be a cycle?
629 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle detected");
632 chain
.emplace_back(*start
);
634 // second, check that there is a chain, no tree or cycle...
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
)
642 if (xmlsecurity::EqualDistinguishedNames(
643 certs
[chain
[i
]]->getSubjectName(), certs
[j
]->getIssuerName(), xmlsecurity::NOCOMPAT
))
645 if (chain
.size() != i
+ 1) // already found issue?
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)
655 { // last one: must be a leaf
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)
663 { // not issuer of another?
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
]);
679 std::vector
<uno::Reference
<security::XCertificate
>>
680 XMLSignatureHelper::CheckAndUpdateSignatureInformation(
681 uno::Reference
<xml::crypto::XSecurityEnvironment
> const& xSecEnv
,
682 SignatureInformation
const& rInfo
)
684 // if the check fails, it's not possible to determine which X509Data
685 // contained the signing certificate - the UI cannot display something
686 // useful in this case, so prevent anything misleading by clearing the
689 std::vector
<uno::Reference
<security::XCertificate
>> certs
;
690 std::vector
<SignatureInformation::X509Data
> datas
;
691 // TODO: for now, just merge all X509Datas together for checking...
692 // (this will probably break round-trip of signature with multiple X509Data,
693 // no idea if that is a problem)
694 SignatureInformation::X509Data temp
;
695 SignatureInformation::X509Data tempResult
;
696 for (auto const& rData
: rInfo
.X509Datas
)
698 for (auto const& it
: rData
)
700 temp
.emplace_back(it
);
703 if (CheckX509Data(xSecEnv
, temp
, certs
, tempResult
))
705 datas
.emplace_back(tempResult
);
708 // rInfo is a copy, update the original
709 mpXSecController
->UpdateSignatureInformation(rInfo
.nSecurityId
, std::move(datas
));
713 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */