Get the style color and number just once
[LibreOffice.git] / xmlsecurity / source / helper / xsecverify.cxx
blob553486ca8d36f08d3325af444e1babc1b4264ba8
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 .
20 #include <config_gpgme.h>
22 #include <xsecctl.hxx>
23 #include "xsecparser.hxx"
24 #include "ooxmlsecparser.hxx"
25 #include <biginteger.hxx>
26 #include <framework/signatureverifierimpl.hxx>
27 #include <framework/saxeventkeeperimpl.hxx>
28 #include <gpg/xmlsignature_gpgimpl.hxx>
29 #include <gpg/SEInitializer.hxx>
31 #include <com/sun/star/uno/Sequence.hxx>
32 #include <com/sun/star/xml/crypto/sax/XKeyCollector.hpp>
33 #include <com/sun/star/xml/crypto/sax/ElementMarkPriority.hpp>
34 #include <com/sun/star/xml/crypto/sax/XReferenceCollector.hpp>
35 #include <com/sun/star/xml/crypto/sax/XSignatureVerifyResultBroadcaster.hpp>
36 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
37 #include <com/sun/star/graphic/GraphicProvider.hpp>
38 #include <com/sun/star/embed/StorageFormats.hpp>
39 #include <sal/log.hxx>
40 #include <unotools/datetime.hxx>
41 #include <comphelper/base64.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/propertyvalue.hxx>
44 #include <comphelper/seqstream.hxx>
46 namespace com::sun::star::graphic { class XGraphic; }
48 using namespace css;
49 using namespace css::uno;
50 using namespace css::beans;
52 /* protected: for signature verify */
53 css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecController::prepareSignatureToRead(
54 sal_Int32 nSecurityId)
56 if ( m_eStatusOfSecurityComponents != InitializationState::INITIALIZED )
58 return nullptr;
61 sal_Int32 nIdOfSignatureElementCollector;
62 css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > xReferenceResolvedListener;
64 nIdOfSignatureElementCollector =
65 m_xSAXEventKeeper->addSecurityElementCollector( css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY, false);
67 m_xSAXEventKeeper->setSecurityId(nIdOfSignatureElementCollector, nSecurityId);
70 * create a SignatureVerifier
72 xReferenceResolvedListener = new SignatureVerifierImpl;
74 css::uno::Reference<css::lang::XInitialization> xInitialization(xReferenceResolvedListener, css::uno::UNO_QUERY);
76 css::uno::Sequence<css::uno::Any> args
78 Any(OUString::number(nSecurityId)),
79 Any(uno::Reference<xml::crypto::sax::XSecuritySAXEventKeeper>(m_xSAXEventKeeper)),
80 Any(OUString::number(nIdOfSignatureElementCollector)),
81 Any(m_xSecurityContext),
82 Any(m_xXMLSignature)
84 xInitialization->initialize(args);
86 css::uno::Reference< css::xml::crypto::sax::XSignatureVerifyResultBroadcaster >
87 signatureVerifyResultBroadcaster(xReferenceResolvedListener, css::uno::UNO_QUERY);
89 signatureVerifyResultBroadcaster->addSignatureVerifyResultListener( this );
91 m_xSAXEventKeeper->addReferenceResolvedListener(
92 nIdOfSignatureElementCollector,
93 xReferenceResolvedListener);
95 css::uno::Reference<css::xml::crypto::sax::XKeyCollector> keyCollector (xReferenceResolvedListener, css::uno::UNO_QUERY);
96 keyCollector->setKeyId(0);
98 return xReferenceResolvedListener;
101 void XSecController::addSignature()
103 css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > xReferenceResolvedListener;
104 sal_Int32 nSignatureId = 0;
107 if (m_bVerifyCurrentSignature)
109 chainOn();
110 xReferenceResolvedListener = prepareSignatureToRead( m_nReservedSignatureId );
111 m_bVerifyCurrentSignature = false;
112 nSignatureId = m_nReservedSignatureId;
115 InternalSignatureInformation isi( nSignatureId, xReferenceResolvedListener );
116 m_vInternalSignatureInformations.push_back( isi );
119 void XSecController::setSignatureMethod(svl::crypto::SignatureMethodAlgorithm eAlgorithmID)
121 if (m_vInternalSignatureInformations.empty())
122 return;
124 m_vInternalSignatureInformations.back().signatureInfor.eAlgorithmID = eAlgorithmID;
127 void XSecController::switchGpgSignature()
129 #if HAVE_FEATURE_GPGME
130 // swap signature verifier for the Gpg one
131 m_xXMLSignature.set(new XMLSignature_GpgImpl());
132 if (m_vInternalSignatureInformations.empty())
133 return;
135 SignatureVerifierImpl* pImpl=
136 dynamic_cast<SignatureVerifierImpl*>(
137 m_vInternalSignatureInformations.back().xReferenceResolvedListener.get());
138 if (pImpl)
140 css::uno::Reference<css::xml::crypto::XSEInitializer> xGpgSEInitializer(
141 new SEInitializerGpg());
142 pImpl->updateSignature(new XMLSignature_GpgImpl(),
143 xGpgSEInitializer->createSecurityContext(OUString()));
145 #else
146 (void) this;
147 #endif
150 bool XSecController::haveReferenceForId(std::u16string_view rId) const
152 if (m_vInternalSignatureInformations.empty())
154 SAL_INFO("xmlsecurity.helper","XSecController::haveReferenceForId: no signature");
155 return false;
157 InternalSignatureInformation const& rIsi(m_vInternalSignatureInformations.back());
158 for (SignatureReferenceInformation const& rSri : rIsi.signatureInfor.vSignatureReferenceInfors)
160 if (rSri.nType == SignatureReferenceType::SAMEDOCUMENT
161 && rSri.ouURI == rId) // ouUri has # stripped
163 return true;
166 return false;
169 void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID, const OUString& ouType )
171 if (m_vInternalSignatureInformations.empty())
173 SAL_INFO("xmlsecurity.helper","XSecController::addReference: no signature");
174 return;
176 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
177 isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1, ouType );
180 void XSecController::addStreamReference(
181 const OUString& ouUri,
182 bool isBinary,
183 sal_Int32 nDigestID )
185 SignatureReferenceType type = (isBinary?SignatureReferenceType::BINARYSTREAM:SignatureReferenceType::XMLSTREAM);
187 if (m_vInternalSignatureInformations.empty())
189 SAL_INFO("xmlsecurity.helper","XSecController::addStreamReference: no signature");
190 return;
192 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
194 if ( isi.xReferenceResolvedListener.is() )
197 * get the input stream
199 css::uno::Reference< css::io::XInputStream > xObjectInputStream
200 = getObjectInputStream( ouUri );
202 if ( xObjectInputStream.is() )
204 css::uno::Reference<css::xml::crypto::XUriBinding> xUriBinding
205 (isi.xReferenceResolvedListener, css::uno::UNO_QUERY);
206 xUriBinding->setUriBinding(ouUri, xObjectInputStream);
210 isi.addReference(type, nDigestID, ouUri, -1, OUString());
213 void XSecController::setReferenceCount() const
215 if (m_vInternalSignatureInformations.empty())
217 SAL_INFO("xmlsecurity.helper","XSecController::setReferenceCount: no signature");
218 return;
220 const InternalSignatureInformation &isi =
221 m_vInternalSignatureInformations.back();
223 if ( !isi.xReferenceResolvedListener.is() )
224 return;
226 const SignatureReferenceInformations &refInfors = isi.signatureInfor.vSignatureReferenceInfors;
228 int refNum = refInfors.size();
229 sal_Int32 referenceCount = 0;
231 for(int i=0 ; i<refNum; ++i)
233 if (refInfors[i].nType == SignatureReferenceType::SAMEDOCUMENT )
235 * same-document reference
238 referenceCount++;
242 css::uno::Reference<css::xml::crypto::sax::XReferenceCollector> xReferenceCollector
243 (isi.xReferenceResolvedListener, css::uno::UNO_QUERY);
244 xReferenceCollector->setReferenceCount( referenceCount );
247 void XSecController::setX509Data(
248 std::vector<std::pair<OUString, OUString>> & rX509IssuerSerials,
249 std::vector<OUString> const& rX509Certificates)
251 if (m_vInternalSignatureInformations.empty())
253 SAL_INFO("xmlsecurity.helper","XSecController::setX509IssuerName: no signature");
254 return;
256 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
257 SignatureInformation::X509Data data;
258 // due to the excessive flexibility of the spec it's possible that there
259 // is both a reference to a cert and the cert itself in one X509Data
260 for (OUString const& it : rX509Certificates)
264 data.emplace_back();
265 data.back().X509Certificate = it;
266 uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
267 uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it));
268 if (!xCert.is())
270 SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
271 continue; // will be handled in CheckX509Data
273 OUString const issuerName(xCert->getIssuerName());
274 OUString const serialNumber(xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()));
275 auto const iter = std::find_if(rX509IssuerSerials.begin(), rX509IssuerSerials.end(),
276 [&](auto const& rX509IssuerSerial) {
277 return xmlsecurity::EqualDistinguishedNames(issuerName, rX509IssuerSerial.first, xmlsecurity::COMPAT_2ND)
278 && serialNumber == rX509IssuerSerial.second;
280 if (iter != rX509IssuerSerials.end())
282 data.back().X509IssuerName = iter->first;
283 data.back().X509SerialNumber = iter->second;
284 rX509IssuerSerials.erase(iter);
287 catch (uno::Exception const&)
289 SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
292 // now handle any that are left...
293 for (auto const& it : rX509IssuerSerials)
295 data.emplace_back();
296 data.back().X509IssuerName = it.first;
297 data.back().X509SerialNumber = it.second;
299 if (!data.empty())
301 isi.signatureInfor.X509Datas.push_back(data);
305 void XSecController::setSignatureValue( OUString const & ouSignatureValue )
307 if (m_vInternalSignatureInformations.empty())
309 SAL_INFO("xmlsecurity.helper","XSecController::setSignatureValue: no signature");
310 return;
312 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
313 isi.signatureInfor.ouSignatureValue = ouSignatureValue;
316 void XSecController::setDigestValue( sal_Int32 nDigestID, OUString const & ouDigestValue )
318 if (m_vInternalSignatureInformations.empty())
320 SAL_INFO("xmlsecurity.helper","XSecController::setDigestValue: no signature");
321 return;
323 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
324 if (isi.signatureInfor.vSignatureReferenceInfors.empty())
326 SAL_INFO("xmlsecurity.helper","XSecController::setDigestValue: no signature reference");
327 return;
329 SignatureReferenceInformation &reference =
330 isi.signatureInfor.vSignatureReferenceInfors.back();
331 reference.nDigestID = nDigestID;
332 reference.ouDigestValue = ouDigestValue;
335 void XSecController::setGpgKeyID( OUString const & ouKeyID )
337 if (m_vInternalSignatureInformations.empty())
339 SAL_INFO("xmlsecurity.helper","XSecController::setGpgKeyID: no signature");
340 return;
342 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
343 isi.signatureInfor.ouGpgKeyID = ouKeyID;
346 void XSecController::setGpgCertificate( OUString const & ouGpgCert )
348 if (m_vInternalSignatureInformations.empty())
350 SAL_INFO("xmlsecurity.helper","XSecController::setGpgCertificate: no signature");
351 return;
353 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
354 isi.signatureInfor.ouGpgCertificate = ouGpgCert;
357 void XSecController::setGpgOwner( OUString const & ouGpgOwner )
359 if (m_vInternalSignatureInformations.empty())
361 SAL_INFO("xmlsecurity.helper","XSecController::setGpgOwner: no signature");
362 return;
364 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
365 isi.signatureInfor.ouGpgOwner = ouGpgOwner;
368 void XSecController::setDate(OUString const& rId, OUString const& ouDate)
370 if (m_vInternalSignatureInformations.empty())
372 SAL_INFO("xmlsecurity.helper","XSecController::setDate: no signature");
373 return;
375 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
376 // there may be multiple timestamps in a signature - check them for consistency
377 if (!isi.signatureInfor.ouDateTime.isEmpty()
378 && isi.signatureInfor.ouDateTime != ouDate)
380 isi.signatureInfor.hasInconsistentSigningTime = true;
382 (void)utl::ISO8601parseDateTime( ouDate, isi.signatureInfor.stDateTime);
383 isi.signatureInfor.ouDateTime = ouDate;
384 if (!rId.isEmpty())
386 isi.signatureInfor.ouDateTimePropertyId = rId;
390 void XSecController::setDescription(OUString const& rId, OUString const& rDescription)
392 if (m_vInternalSignatureInformations.empty())
393 return;
395 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
396 rInformation.signatureInfor.ouDescription = rDescription;
397 if (!rId.isEmpty())
399 rInformation.signatureInfor.ouDescriptionPropertyId = rId;
403 void XSecController::setSignatureBytes(const uno::Sequence<sal_Int8>& rBytes)
405 if (m_vInternalSignatureInformations.empty())
406 return;
408 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
409 rInformation.signatureInfor.aSignatureBytes = rBytes;
412 void XSecController::setX509CertDigest(
413 OUString const& rCertDigest, sal_Int32 const /*TODO nReferenceDigestID*/,
414 std::u16string_view const& rX509IssuerName, std::u16string_view const& rX509SerialNumber)
416 if (m_vInternalSignatureInformations.empty())
417 return;
419 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
420 for (auto & rData : rInformation.signatureInfor.X509Datas)
422 for (auto & it : rData)
424 if (xmlsecurity::EqualDistinguishedNames(it.X509IssuerName, rX509IssuerName, xmlsecurity::COMPAT_BOTH)
425 && it.X509SerialNumber == rX509SerialNumber)
427 it.CertDigest = rCertDigest;
428 return;
432 // fall-back: read the actual certificates
433 for (auto & rData : rInformation.signatureInfor.X509Datas)
435 for (auto & it : rData)
437 if (!it.X509Certificate.isEmpty())
441 uno::Reference<xml::crypto::XSecurityEnvironment> const xSecEnv(m_xSecurityContext->getSecurityEnvironment());
442 uno::Reference<security::XCertificate> const xCert(xSecEnv->createCertificateFromAscii(it.X509Certificate));
443 if (!xCert.is())
445 SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
447 else if (xmlsecurity::EqualDistinguishedNames(xCert->getIssuerName(), rX509IssuerName, xmlsecurity::COMPAT_2ND)
448 && xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber()) == rX509SerialNumber)
450 it.CertDigest = rCertDigest;
451 // note: testInsertCertificate_PEM_DOCX requires these!
452 it.X509SerialNumber = rX509SerialNumber;
453 it.X509IssuerName = rX509IssuerName;
454 return;
457 catch (uno::Exception const&)
459 SAL_INFO("xmlsecurity.helper", "cannot parse X509Certificate");
464 if (!rInformation.signatureInfor.ouGpgCertificate.isEmpty())
466 SAL_INFO_IF(rCertDigest != rInformation.signatureInfor.ouGpgKeyID,
467 "xmlsecurity.helper", "PGPKeyID vs CertDigest mismatch");
469 else
471 SAL_INFO("xmlsecurity.helper", "cannot find X509Data for CertDigest");
475 namespace {
476 Reference<css::graphic::XGraphic> lcl_getGraphicFromString(std::u16string_view rImage)
478 Sequence<sal_Int8> seq;
479 comphelper::Base64::decode(seq, rImage);
481 Reference< graphic::XGraphic > xGraphic;
482 if( !seq.hasElements() )
483 return Reference<css::graphic::XGraphic>();
485 Reference< graphic::XGraphicProvider > xGraphicProvider(
486 graphic::GraphicProvider::create(comphelper::getProcessComponentContext()) );
487 Reference< io::XInputStream > xInputStream( new ::comphelper::SequenceInputStream( seq ) );
489 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(u"InputStream"_ustr, xInputStream) };
490 xGraphic = xGraphicProvider->queryGraphic(aArgs);
492 return xGraphic;
496 void XSecController::setValidSignatureImage(std::u16string_view rValidSigImg)
498 if (m_vInternalSignatureInformations.empty() || rValidSigImg.empty())
499 return;
501 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
502 rInformation.signatureInfor.aValidSignatureImage = lcl_getGraphicFromString(rValidSigImg);
505 void XSecController::setInvalidSignatureImage(std::u16string_view rInvalidSigImg)
507 if (m_vInternalSignatureInformations.empty() || rInvalidSigImg.empty())
508 return;
510 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
511 rInformation.signatureInfor.aInvalidSignatureImage = lcl_getGraphicFromString(rInvalidSigImg);
514 void XSecController::setSignatureLineId(const OUString& rSignatureLineId)
516 if (m_vInternalSignatureInformations.empty())
517 return;
519 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
520 rInformation.signatureInfor.ouSignatureLineId = rSignatureLineId;
523 void XSecController::addEncapsulatedX509Certificate(const OUString& rEncapsulatedX509Certificate)
525 if (m_vInternalSignatureInformations.empty())
526 return;
528 if (rEncapsulatedX509Certificate.isEmpty())
529 return;
531 InternalSignatureInformation& rInformation = m_vInternalSignatureInformations.back();
532 rInformation.signatureInfor.maEncapsulatedX509Certificates.insert(rEncapsulatedX509Certificate);
535 void XSecController::setId( OUString const & ouId )
537 if (m_vInternalSignatureInformations.empty())
539 SAL_INFO("xmlsecurity.helper","XSecController::setId: no signature");
540 return;
542 InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
543 isi.signatureInfor.ouSignatureId = ouId;
546 /* public: for signature verify */
547 void XSecController::collectToVerify( std::u16string_view referenceId )
549 /* SAL_WARN_IF( !m_xSAXEventKeeper.is(), "xmlsecurity", "the SAXEventKeeper is NULL" ); */
551 if ( m_eStatusOfSecurityComponents != InitializationState::INITIALIZED )
553 * if all security components are ready, verify the signature.
555 return;
557 bool bJustChainingOn = false;
558 css::uno::Reference< css::xml::sax::XDocumentHandler > xHandler;
560 int i,j;
561 int sigNum = m_vInternalSignatureInformations.size();
563 for (i=0; i<sigNum; ++i)
565 InternalSignatureInformation& isi = m_vInternalSignatureInformations[i];
566 SignatureReferenceInformations& vReferenceInfors = isi.signatureInfor.vSignatureReferenceInfors;
567 int refNum = vReferenceInfors.size();
569 for (j=0; j<refNum; ++j)
571 SignatureReferenceInformation &refInfor = vReferenceInfors[j];
573 if (refInfor.ouURI == referenceId)
575 if (chainOn())
577 bJustChainingOn = true;
578 xHandler = m_xSAXEventKeeper->setNextHandler(nullptr);
581 sal_Int32 nKeeperId = m_xSAXEventKeeper->addSecurityElementCollector(
582 css::xml::crypto::sax::ElementMarkPriority_BEFOREMODIFY, false );
584 css::uno::Reference<css::xml::crypto::sax::XReferenceCollector> xReferenceCollector
585 ( isi.xReferenceResolvedListener, css::uno::UNO_QUERY );
587 m_xSAXEventKeeper->setSecurityId(nKeeperId, isi.signatureInfor.nSecurityId);
588 m_xSAXEventKeeper->addReferenceResolvedListener( nKeeperId, isi.xReferenceResolvedListener);
589 xReferenceCollector->setReferenceId( nKeeperId );
591 isi.vKeeperIds[j] = nKeeperId;
592 break;
597 if ( bJustChainingOn )
599 m_xSAXEventKeeper->setNextHandler(xHandler);
603 void XSecController::addSignature( sal_Int32 nSignatureId )
605 SAL_WARN_IF( !m_xSecParser.is(), "xmlsecurity.helper", "No XSecParser initialized" );
607 m_nReservedSignatureId = nSignatureId;
608 m_bVerifyCurrentSignature = true;
611 css::uno::Reference< css::xml::sax::XDocumentHandler > const & XSecController::createSignatureReader(XMLSignatureHelper& rXMLSignatureHelper, sal_Int32 nType)
613 if (nType == embed::StorageFormats::OFOPXML)
614 m_xSecParser = new OOXMLSecParser(rXMLSignatureHelper, this);
615 else
616 m_xSecParser = new XSecParser(rXMLSignatureHelper, this);
617 css::uno::Reference< css::lang::XInitialization > xInitialization(m_xSecParser, uno::UNO_QUERY);
619 setSAXChainConnector(xInitialization);
621 return m_xSecParser;
624 void XSecController::releaseSignatureReader()
626 clearSAXChainConnector( );
627 m_xSecParser.clear();
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */