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 .
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
; }
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
)
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
),
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
)
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())
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())
135 SignatureVerifierImpl
* pImpl
=
136 dynamic_cast<SignatureVerifierImpl
*>(
137 m_vInternalSignatureInformations
.back().xReferenceResolvedListener
.get());
140 css::uno::Reference
<css::xml::crypto::XSEInitializer
> xGpgSEInitializer(
141 new SEInitializerGpg());
142 pImpl
->updateSignature(new XMLSignature_GpgImpl(),
143 xGpgSEInitializer
->createSecurityContext(OUString()));
150 bool XSecController::haveReferenceForId(std::u16string_view rId
) const
152 if (m_vInternalSignatureInformations
.empty())
154 SAL_INFO("xmlsecurity.helper","XSecController::haveReferenceForId: no signature");
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
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");
176 InternalSignatureInformation
&isi
= m_vInternalSignatureInformations
.back();
177 isi
.addReference(SignatureReferenceType::SAMEDOCUMENT
, nDigestID
, ouUri
, -1, ouType
);
180 void XSecController::addStreamReference(
181 const OUString
& ouUri
,
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");
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");
220 const InternalSignatureInformation
&isi
=
221 m_vInternalSignatureInformations
.back();
223 if ( !isi
.xReferenceResolvedListener
.is() )
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
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");
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
)
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
));
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
)
296 data
.back().X509IssuerName
= it
.first
;
297 data
.back().X509SerialNumber
= it
.second
;
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");
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");
323 InternalSignatureInformation
&isi
= m_vInternalSignatureInformations
.back();
324 if (isi
.signatureInfor
.vSignatureReferenceInfors
.empty())
326 SAL_INFO("xmlsecurity.helper","XSecController::setDigestValue: no signature reference");
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");
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");
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");
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");
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
;
386 isi
.signatureInfor
.ouDateTimePropertyId
= rId
;
390 void XSecController::setDescription(OUString
const& rId
, OUString
const& rDescription
)
392 if (m_vInternalSignatureInformations
.empty())
395 InternalSignatureInformation
& rInformation
= m_vInternalSignatureInformations
.back();
396 rInformation
.signatureInfor
.ouDescription
= rDescription
;
399 rInformation
.signatureInfor
.ouDescriptionPropertyId
= rId
;
403 void XSecController::setSignatureBytes(const uno::Sequence
<sal_Int8
>& rBytes
)
405 if (m_vInternalSignatureInformations
.empty())
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())
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
;
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
));
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
;
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");
471 SAL_INFO("xmlsecurity.helper", "cannot find X509Data for CertDigest");
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
);
496 void XSecController::setValidSignatureImage(std::u16string_view rValidSigImg
)
498 if (m_vInternalSignatureInformations
.empty() || rValidSigImg
.empty())
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())
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())
519 InternalSignatureInformation
& rInformation
= m_vInternalSignatureInformations
.back();
520 rInformation
.signatureInfor
.ouSignatureLineId
= rSignatureLineId
;
523 void XSecController::addEncapsulatedX509Certificate(const OUString
& rEncapsulatedX509Certificate
)
525 if (m_vInternalSignatureInformations
.empty())
528 if (rEncapsulatedX509Certificate
.isEmpty())
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");
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.
557 bool bJustChainingOn
= false;
558 css::uno::Reference
< css::xml::sax::XDocumentHandler
> xHandler
;
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
)
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
;
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);
616 m_xSecParser
= new XSecParser(rXMLSignatureHelper
, this);
617 css::uno::Reference
< css::lang::XInitialization
> xInitialization(m_xSecParser
, uno::UNO_QUERY
);
619 setSAXChainConnector(xInitialization
);
624 void XSecController::releaseSignatureReader()
626 clearSAXChainConnector( );
627 m_xSecParser
.clear();
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */