LibreOffice Module xmlsecurity (master) 1
xmlsignaturehelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
23#include <xsecctl.hxx>
24#include <biginteger.hxx>
25
26#include <UriBindingHelper.hxx>
27
28#include <tools/datetime.hxx>
29
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>
41
46#include <rtl/ustrbuf.hxx>
47#include <sal/log.hxx>
48
49#include <optional>
50
51constexpr OUStringLiteral NS_DOCUMENTSIGNATURES = u"http://openoffice.org/2004/documentsignatures";
52constexpr OUStringLiteral NS_DOCUMENTSIGNATURES_ODF_1_2 = u"urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0";
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";
55
56using namespace ::com::sun::star;
57using namespace ::com::sun::star::graphic;
58using namespace ::com::sun::star::uno;
59
60XMLSignatureHelper::XMLSignatureHelper( const uno::Reference< uno::XComponentContext >& rxCtx)
61 : mxCtx(rxCtx), mbODFPre1_2(false)
62{
63 mpXSecController = new XSecController(rxCtx);
64 mbError = false;
65}
66
68{
69}
70
72 const Reference < css::embed::XStorage >& rxStorage,
73 std::u16string_view sODFVersion)
74{
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!");
79}
80
81
83{
85}
86
87
88void XMLSignatureHelper::StartMission(const uno::Reference<xml::crypto::XXMLSecurityContext>& xSecurityContext)
89{
90 if ( !mxUriBinding.is() )
92
93 mpXSecController->startMission(mxUriBinding, xSecurityContext);
94}
95
97{
98 mpXSecController->endMission();
99}
100
102{
103 return mpXSecController->getNewSecurityId();
104}
105
107 sal_Int32 nSecurityId,
108 const OUString& ouX509IssuerName,
109 const OUString& ouX509SerialNumber,
110 const OUString& ouX509Cert,
111 const OUString& ouX509CertDigest,
113{
114 mpXSecController->setX509Certificate(
115 nSecurityId,
116 ouX509IssuerName,
117 ouX509SerialNumber,
118 ouX509Cert,
119 ouX509CertDigest,
120 eAlgorithmID);
121}
122
123void XMLSignatureHelper::AddEncapsulatedX509Certificate(const OUString& ouEncapsulatedX509Certificate)
124{
125 mpXSecController->addEncapsulatedX509Certificate(ouEncapsulatedX509Certificate);
126}
127
128void XMLSignatureHelper::SetGpgCertificate(sal_Int32 nSecurityId,
129 const OUString& ouGpgCertDigest,
130 const OUString& ouGpgCert,
131 const OUString& ouGpgOwner)
132{
133 mpXSecController->setGpgCertificate(
134 nSecurityId,
135 ouGpgCertDigest,
136 ouGpgCert,
137 ouGpgOwner);
138}
139
140void XMLSignatureHelper::SetDateTime( sal_Int32 nSecurityId, const ::DateTime& rDateTime )
141{
142 css::util::DateTime stDateTime = rDateTime.GetUNODateTime();
143 mpXSecController->setDate( nSecurityId, stDateTime );
144}
145
146void XMLSignatureHelper::SetDescription(sal_Int32 nSecurityId, const OUString& rDescription)
147{
148 mpXSecController->setDescription(nSecurityId, rDescription);
149}
150
151void XMLSignatureHelper::SetSignatureLineId(sal_Int32 nSecurityId, const OUString& rSignatureLineId)
152{
153 mpXSecController->setSignatureLineId(nSecurityId, rSignatureLineId);
154}
155
157 sal_Int32 nSecurityId, const css::uno::Reference<XGraphic>& xValidGraphic)
158{
159 mpXSecController->setSignatureLineValidGraphic(nSecurityId, xValidGraphic);
160}
161
163 sal_Int32 nSecurityId, const css::uno::Reference<XGraphic>& xInvalidGraphic)
164{
165 mpXSecController->setSignatureLineInvalidGraphic(nSecurityId, xInvalidGraphic);
166}
167
168void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, bool bBinary, bool bXAdESCompliantIfODF )
169{
170 mpXSecController->signAStream( nSecurityId, uri, bBinary, bXAdESCompliantIfODF );
171}
172
173
175 const css::uno::Reference< css::io::XOutputStream >& xOutputStream )
176{
177 /*
178 * get SAX writer component
179 */
180 uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(mxCtx);
181
182 /*
183 * connect XML writer to output stream
184 */
185 xSaxWriter->setOutputStream( xOutputStream );
186
187 /*
188 * write the xml context for signatures
189 */
191 OUString sNamespace;
192 if (mbODFPre1_2)
193 sNamespace = NS_DOCUMENTSIGNATURES;
194 else
196
197 pAttributeList->AddAttribute(
198 "xmlns",
199 sNamespace);
200
201 xSaxWriter->startDocument();
202 xSaxWriter->startElement(
203 "document-signatures",
204 pAttributeList);
205
206 return xSaxWriter;
207}
208
209void XMLSignatureHelper::CloseDocumentHandler( const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler )
210{
211 xDocumentHandler->endElement( "document-signatures" );
212 xDocumentHandler->endDocument();
213}
214
216 const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler,
217 const SignatureInformation& signatureInfo,
218 bool bXAdESCompliantIfODF )
219{
220 XSecController::exportSignature(xDocumentHandler, signatureInfo, bXAdESCompliantIfODF);
221}
222
223void XMLSignatureHelper::ExportOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<embed::XStorage>& xSignatureStorage, const SignatureInformation& rInformation, int nSignatureIndex)
224{
225 uno::Reference<io::XOutputStream> xOutputStream(xSignatureStorage->openStreamElement("sig" + OUString::number(nSignatureIndex) + ".xml", embed::ElementModes::READWRITE), uno::UNO_QUERY);
226
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
231 {
232 uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(mxCtx);
233 xSaxWriter->setOutputStream(xOutputStream);
234 xSaxWriter->startDocument();
235
236 mpXSecController->exportOOXMLSignature(xRootStorage, xSaxWriter, rInformation);
237
238 xSaxWriter->endDocument();
239 }
240}
241
242void XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF )
243{
244 mbError = false;
245
246 if ( !mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) )
247 {
248 mbError = true;
249 }
250}
251
252bool XMLSignatureHelper::ReadAndVerifySignature( const css::uno::Reference< css::io::XInputStream >& xInputStream )
253{
254 mbError = false;
255
256 SAL_WARN_IF(!xInputStream.is(), "xmlsecurity.helper", "input stream missing");
257
258 // prepare ParserInputSource
259 xml::sax::InputSource aParserInput;
260 aParserInput.aInputStream = xInputStream;
261
262 // get SAX parser component
263 uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(mxCtx);
264
265 // create a signature reader
266 uno::Reference< xml::sax::XDocumentHandler > xHandler
267 = mpXSecController->createSignatureReader(*this);
268
269 // setup the connection:
270 // Parser -> SignatureReader
271 xParser->setDocumentHandler( xHandler );
272
273 // Parse the stream.
274 try
275 {
276 xParser->parseStream( aParserInput );
277 }
278 catch( uno::Exception& )
279 {
280 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
281 mbError = true;
282 }
283
284 // release the signature reader
285 mpXSecController->releaseSignatureReader( );
286
287 return !mbError;
288}
289
291{
292 return mpXSecController->getSignatureInformation( nSecurityId );
293}
294
296{
297 return mpXSecController->getSignatureInformations();
298}
299
301{
303 {
304 sal_Int32 nSignatureId = mpXSecController->getNewSecurityId();
305 mpXSecController->addSignature( nSignatureId );
306 }
307}
308
309namespace
310{
311bool lcl_isSignatureType(const beans::StringPair& rPair)
312{
313 return rPair.First == "Type" && rPair.Second == OOXML_SIGNATURE_SIGNATURE;
314}
315bool lcl_isSignatureOriginType(const beans::StringPair& rPair)
316{
317 return rPair.First == "Type" && rPair.Second == OOXML_SIGNATURE_ORIGIN;
318}
319}
320
321bool XMLSignatureHelper::ReadAndVerifySignatureStorage(const uno::Reference<embed::XStorage>& xStorage, bool bCacheLastSignature)
322{
323 sal_Int32 nOpenMode = embed::ElementModes::READ;
324 if (xStorage.is() && !xStorage->hasByName("_rels"))
325 {
326 SAL_WARN("xmlsecurity.helper", "expected stream, in signature storage but not found: _rels");
327 return false;
328 }
329
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);
333
334 for (sal_Int32 i = 0; i < aRelationsInfo.getLength(); ++i)
335 {
336 const uno::Sequence<beans::StringPair>& rRelation = aRelationsInfo[i];
337 if (std::any_of(rRelation.begin(), rRelation.end(), lcl_isSignatureType))
338 {
339 auto it = std::find_if(rRelation.begin(), rRelation.end(), [](const beans::StringPair& rPair) { return rPair.First == "Target"; });
340 if (it != rRelation.end())
341 {
342 if (xStorage.is() && !xStorage->hasByName(it->Second))
343 {
344 SAL_WARN("xmlsecurity.helper", "expected stream, but not found: " << it->Second);
345 continue;
346 }
347
348 uno::Reference<io::XInputStream> xInputStream(xStorage->openStreamElement(it->Second, nOpenMode), uno::UNO_QUERY);
349 if (!ReadAndVerifySignatureStorageStream(xInputStream))
350 return false;
351
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;
356
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;
365
366 sal_Int64 nSize = 0;
367 xPropertySet->getPropertyValue("Size") >>= nSize;
368 if (nSize < 0 || nSize > SAL_MAX_INT32)
369 {
370 SAL_WARN("xmlsecurity.helper", "bogus signature size: " << nSize);
371 continue;
372 }
373 uno::Sequence<sal_Int8> aData;
374 xInputStream->readBytes(aData, nSize);
375 mpXSecController->setSignatureBytes(aData);
376 }
377 }
378 }
379
380 return true;
381}
382
383bool XMLSignatureHelper::ReadAndVerifySignatureStorageStream(const css::uno::Reference<css::io::XInputStream>& xInputStream)
384{
385 mbError = false;
386
387 // Create the input source.
388 xml::sax::InputSource aParserInput;
389 aParserInput.aInputStream = xInputStream;
390
391 // Create the sax parser.
392 uno::Reference<xml::sax::XParser> xParser = xml::sax::Parser::create(mxCtx);
393
394 // Create the signature reader.
395 uno::Reference<xml::sax::XDocumentHandler> xHandler = mpXSecController->createSignatureReader(*this, embed::StorageFormats::OFOPXML);
396
397 // Parser -> signature reader.
398 xParser->setDocumentHandler(xHandler);
399
400 // Parse the stream.
401 try
402 {
403 xParser->parseStream(aParserInput);
404 }
405 catch(const uno::Exception&)
406 {
407 DBG_UNHANDLED_EXCEPTION("xmlsecurity.helper");
408 mbError = true;
409 }
410
411 // release the signature reader
412 mpXSecController->releaseSignatureReader();
413
414 return !mbError;
415}
416
417void XMLSignatureHelper::EnsureSignaturesRelation(const css::uno::Reference<css::embed::XStorage>& xStorage, bool bAdd)
418{
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));
423
424 // Do we have a relation already?
425 bool bHaveRelation = false;
426 int nCount = 0;
427 for (const uno::Sequence<beans::StringPair>& rRelation : aRelationsInfo)
428 {
429 auto aRelation = comphelper::sequenceToContainer< std::vector<beans::StringPair> >(rRelation);
430 if (std::any_of(aRelation.begin(), aRelation.end(), lcl_isSignatureOriginType))
431 {
432 bHaveRelation = true;
433 break;
434 }
435 ++nCount;
436 }
437
438 if (!bHaveRelation && bAdd)
439 {
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));
446 }
447 else if (bHaveRelation && !bAdd)
448 {
449 // Yes, and need to remove it.
450 for (std::vector< uno::Sequence<beans::StringPair> >::iterator it = aRelationsInfo.begin(); it != aRelationsInfo.end();)
451 {
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;
457 }
458 }
459
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);
465
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();
471}
472
473void XMLSignatureHelper::ExportSignatureRelations(const css::uno::Reference<css::embed::XStorage>& xStorage, int nSignatureCount)
474{
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();
481
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)
487 {
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));
493 }
495 uno::Reference<embed::XTransactedObject> xTransact(xSubStorage, uno::UNO_QUERY);
496 xTransact->commit();
497}
498
499void XMLSignatureHelper::ExportSignatureContentTypes(const css::uno::Reference<css::embed::XStorage>& xStorage, int nSignatureCount)
500{
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)
505 {
506 SAL_WARN("xmlsecurity.helper", "no defaults or overrides in aContentTypeInfo");
507 return;
508 }
509 auto pContentTypeInfo = aContentTypeInfo.getArray();
510
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");
516
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);
520
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)
525 {
526 return rPair.First.startsWith("/_xmlsignatures/sig");
527 }), aOverrides.end());
528
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");
532
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();
540}
541void XMLSignatureHelper::CreateAndWriteOOXMLSignature(const uno::Reference<embed::XStorage>& xRootStorage, const uno::Reference<embed::XStorage>& xSignatureStorage, int nSignatureIndex)
542{
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();
547
548 mbError = false;
549 if (!mpXSecController->WriteOOXMLSignature(xRootStorage, xSaxWriter))
550 mbError = true;
551
552 xSaxWriter->endDocument();
553}
554
561static 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
566{
567 assert(rCerts.empty());
568 assert(rSorted.empty());
569 if (rX509CertInfos.empty())
570 {
571 SAL_WARN("xmlsecurity.comp", "no X509Data");
572 return false;
573 }
574 std::vector<uno::Reference<security::XCertificate>> certs;
575 for (SignatureInformation::X509CertInfo const& it : rX509CertInfos)
576 {
577 if (!it.X509Certificate.isEmpty())
578 {
579 certs.emplace_back(xSecEnv->createCertificateFromAscii(it.X509Certificate));
580 }
581 else
582 {
583 certs.emplace_back(xSecEnv->getCertificate(
584 it.X509IssuerName,
585 xmlsecurity::numericStringToBigInteger(it.X509SerialNumber)));
586 }
587 if (!certs.back().is())
588 {
589 SAL_WARN("xmlsecurity.comp", "X509Data cannot be parsed");
590 return false;
591 }
592 }
593
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)
597 {
598 for (size_t j = 0; ; ++j)
599 {
600 if (j == certs.size())
601 {
602 if (start)
603 {
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;
606 }
607 start = i; // issuer isn't in the list
608 break;
609 }
610 if (xmlsecurity::EqualDistinguishedNames(certs[i]->getIssuerName(), certs[j]->getSubjectName(), xmlsecurity::NOCOMPAT))
611 {
612 if (i == j) // self signed
613 {
614 if (start)
615 {
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;
618 }
619 start = i;
620 }
621 break;
622 }
623 }
624 }
625 std::vector<size_t> chain;
626 if (!start)
627 {
628 // this can only be a cycle?
629 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: cycle detected");
630 return false;
631 }
632 chain.emplace_back(*start);
633
634 // second, check that there is a chain, no tree or cycle...
635 for (size_t i = 0; i < certs.size(); ++i)
636 {
637 assert(chain.size() == i + 1);
638 for (size_t j = 0; j < certs.size(); ++j)
639 {
640 if (chain[i] != j)
641 {
643 certs[chain[i]]->getSubjectName(), certs[j]->getIssuerName(), xmlsecurity::NOCOMPAT))
644 {
645 if (chain.size() != i + 1) // already found issue?
646 {
647 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate issued 2 others: " << certs[chain[i]]->getSubjectName());
648 return false;
649 }
650 chain.emplace_back(j);
651 }
652 }
653 }
654 if (i == certs.size() - 1)
655 { // last one: must be a leaf
656 if (chain.size() != i + 1)
657 {
658 SAL_WARN("xmlsecurity.comp", "X509Data do not form a chain: certificate in cycle: " << certs[chain[i]]->getSubjectName());
659 return false;
660 }
661 }
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;
666 }
667 }
668
669 // success
670 assert(chain.size() == rX509CertInfos.size());
671 for (auto const& it : chain)
672 {
673 rSorted.emplace_back(rX509CertInfos[it]);
674 rCerts.emplace_back(certs[it]);
675 }
676 return true;
677}
678
679std::vector<uno::Reference<security::XCertificate>>
681 uno::Reference<xml::crypto::XSecurityEnvironment> const& xSecEnv,
682 SignatureInformation const& rInfo)
683{
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.
688
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)
696 for (auto const& rData : rInfo.X509Datas)
697 {
698 for (auto const& it : rData)
699 {
700 temp.emplace_back(it);
701 }
702 }
703 if (CheckX509Data(xSecEnv, temp, certs, tempResult))
704 {
705 datas.emplace_back(tempResult);
706 }
707
708 // rInfo is a copy, update the original
709 mpXSecController->UpdateSignatureInformation(rInfo.nSecurityId, std::move(datas));
710 return certs;
711}
712
713/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
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)
SignatureInformation GetSignatureInformation(sal_Int32 nSecurityId) const
void SetStorage(const css::uno::Reference< css::embed::XStorage > &rxStorage, std::u16string_view sODFVersion)
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)
Definition: xsecctl.cxx:564
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
float u
bool mbError
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)
int i
Sequence< sal_Int8 > numericStringToBigInteger(std::u16string_view numeral)
Definition: biginteger.cxx:32
bool EqualDistinguishedNames(std::u16string_view const rName1, std::u16string_view const rName2, EqualMode const eMode)
::std::vector< SignatureInformation > SignatureInformations
std::vector< X509Data > X509Datas
std::vector< X509CertInfo > X509Data
css::uno::Sequence< sal_Int8 > aSignatureBytes
#define SAL_MAX_INT32
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