android: Update app-specific/MIME type icons
[LibreOffice.git] / xmlsecurity / source / helper / xmlsignaturehelper.cxx
blobfe363858522db18fb3e924b378ea15e464a4088e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
49 #include <optional>
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);
64 mbError = false;
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(
115 nSecurityId,
116 ouX509IssuerName,
117 ouX509SerialNumber,
118 ouX509Cert,
119 ouX509CertDigest,
120 eAlgorithmID);
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(
134 nSecurityId,
135 ouGpgCertDigest,
136 ouGpgCert,
137 ouGpgOwner);
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();
191 OUString sNamespace;
192 if (mbODFPre1_2)
193 sNamespace = NS_DOCUMENTSIGNATURES;
194 else
195 sNamespace = NS_DOCUMENTSIGNATURES_ODF_1_2;
197 pAttributeList->AddAttribute(
198 "xmlns",
199 sNamespace);
201 xSaxWriter->startDocument();
202 xSaxWriter->startElement(
203 "document-signatures",
204 pAttributeList);
206 return xSaxWriter;
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);
230 else
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 )
244 mbError = false;
246 if ( !mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) )
248 mbError = true;
252 bool XMLSignatureHelper::ReadAndVerifySignature( const css::uno::Reference< css::io::XInputStream >& xInputStream )
254 mbError = false;
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 );
273 // Parse the stream.
276 xParser->parseStream( aParserInput );
278 catch( uno::Exception& )
280 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
281 mbError = true;
284 // release the signature reader
285 mpXSecController->releaseSignatureReader( );
287 return !mbError;
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 );
309 namespace
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");
327 return false;
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);
345 continue;
348 uno::Reference<io::XInputStream> xInputStream(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
349 if (!ReadAndVerifySignatureStorageStream(xInputStream))
350 return false;
352 // By default, we cache. If it's requested, then we don't cache the last signature.
353 bool bCache = true;
354 if (!bCacheLastSignature && i == aRelationsInfo.getLength() - 1)
355 bCache = false;
357 if (!bCache)
358 continue;
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())
364 continue;
366 sal_Int64 nSize = 0;
367 xPropertySet->getPropertyValue("Size") >>= nSize;
368 if (nSize < 0 || nSize > SAL_MAX_INT32)
370 SAL_WARN("xmlsecurity.helper", "bogus signature size: " << nSize);
371 continue;
373 uno::Sequence<sal_Int8> aData;
374 xInputStream->readBytes(aData, nSize);
375 mpXSecController->setSignatureBytes(aData);
380 return true;
383 bool XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Reference<css::io::XInputStream>& xInputStream)
385 mbError = false;
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);
400 // Parse the stream.
403 xParser->parseStream(aParserInput);
405 catch(const uno::Exception&)
407 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
408 mbError = true;
411 // release the signature reader
412 mpXSecController->releaseSignatureReader();
414 return !mbError;
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;
426 int nCount = 0;
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;
433 break;
435 ++nCount;
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);
455 else
456 ++it;
460 // Write it back.
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);
466 // Commit it.
467 uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
468 xTransact->commit();
469 xTransact.set(xStorage, uno::UNO_QUERY);
470 xTransact->commit();
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);
496 xTransact->commit();
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");
507 return;
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);
539 xTransact->commit();
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();
548 mbError = false;
549 if (!mpXSecController->WriteOOXMLSignature(xRootStorage, xSaxWriter))
550 mbError = true;
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");
572 return false;
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));
581 else
583 certs.emplace_back(xSecEnv->getCertificate(
584 it.X509IssuerName,
585 xmlsecurity::numericStringToBigInteger(it.X509SerialNumber)));
587 if (!certs.back().is())
589 SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
590 return false;
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())
602 if (start)
604 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate has no issuer but already have start of chain: " << certs[i]->getSubjectName());
605 return false;
607 start = i; // issuer isn't in the list
608 break;
610 if (xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), certs[j]->getSubjectName(), xmlsecurity::NOCOMPAT))
612 if (i == j) // self signed
614 if (start)
616 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate is self-signed but already have start of chain: " << certs[i]->getSubjectName());
617 return false;
619 start = i;
621 break;
625 std::vector<size_t> chain;
626 if (!start)
628 // this can only be a cycle?
629 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle detected");
630 return false;
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)
640 if (chain[i] != 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());
648 return false;
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());
659 return false;
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());
665 return false;
669 // success
670 assert(chain.size() == rX509CertInfos.size());
671 for (auto const& it : chain)
673 rSorted.emplace_back(rX509CertInfos[it]);
674 rCerts.emplace_back(certs[it]);
676 return true;
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
687 // X509Datas.
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));
710 return certs;
713 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */