cid#1640468 Dereference after null check
[LibreOffice.git] / xmlsecurity / source / xmlsec / mscrypt / xmlsignature_mscryptimpl.cxx
blob581249292f1a684240dcd9e3c345aa7d5f15e8f8
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 <sal/config.h>
21 #include <sal/log.hxx>
22 #include <rtl/uuid.h>
24 #include <xmlsec/xmldsig.h>
25 #include <xmlsec/xmltree.h> // this MUST precede the mscng/x509.h for some reason
26 #include <xmlsec/mscng/x509.h>
28 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
29 #include <com/sun/star/xml/crypto/XXMLSignature.hpp>
31 #include "securityenvironment_mscryptimpl.hxx"
33 #include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
34 #include <xmlelementwrapper_xmlsecimpl.hxx>
35 #include <xmlsec/xmlstreamio.hxx>
36 #include <xmlsec/errorcallback.hxx>
37 #include <cppuhelper/supportsservice.hxx>
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno ;
41 using namespace ::com::sun::star::lang ;
43 using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
44 using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
45 using ::com::sun::star::xml::crypto::XXMLSignature ;
46 using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ;
47 using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
48 using ::com::sun::star::xml::crypto::XUriBinding ;
50 namespace {
52 class XMLSignature_MSCryptImpl : public ::cppu::WeakImplHelper<
53 css::xml::crypto::XXMLSignature ,
54 css::lang::XServiceInfo >
56 public:
57 explicit XMLSignature_MSCryptImpl();
59 //Methods from XXMLSignature
60 virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL generate(
61 const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
62 const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aEnvironment
63 ) override;
65 virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL validate(
66 const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
67 const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& aContext
68 ) override;
70 //Methods from XServiceInfo
71 virtual OUString SAL_CALL getImplementationName() override;
73 virtual sal_Bool SAL_CALL supportsService(
74 const OUString& ServiceName
75 ) override;
77 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
78 } ;
82 XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() {
85 /* XXMLSignature */
86 Reference< XXMLSignatureTemplate >
87 SAL_CALL XMLSignature_MSCryptImpl::generate(
88 const Reference< XXMLSignatureTemplate >& aTemplate ,
89 const Reference< XSecurityEnvironment >& aEnvironment
92 xmlSecKeysMngrPtr pMngr = nullptr ;
93 xmlSecDSigCtxPtr pDsigCtx = nullptr ;
94 xmlNodePtr pNode = nullptr ;
96 if( !aTemplate.is() )
97 throw RuntimeException() ;
99 if( !aEnvironment.is() )
100 throw RuntimeException() ;
102 //Get Keys Manager
103 SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(aEnvironment.get());
104 if( pSecEnv == nullptr )
105 throw RuntimeException() ;
107 //Get the xml node
108 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
109 if( !xElement.is() ) {
110 throw RuntimeException() ;
113 XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
114 if( pElement == nullptr ) {
115 throw RuntimeException() ;
118 pNode = pElement->getNativeElement() ;
120 //Get the stream/URI binding
121 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
122 if( xUriBinding.is() ) {
123 //Register the stream input callbacks into libxml2
124 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
125 throw RuntimeException() ;
128 setErrorRecorder( );
130 pMngr = pSecEnv->createKeysManager();
131 if( !pMngr ) {
132 throw RuntimeException() ;
135 //Create Signature context
136 pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
137 if( pDsigCtx == nullptr )
139 //throw XMLSignatureException() ;
140 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
141 clearErrorRecorder();
142 return aTemplate;
145 //Sign the template
146 if( xmlSecDSigCtxSign( pDsigCtx , pNode ) == 0 )
148 if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
149 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
150 else
151 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
153 else
155 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
159 xmlSecDSigCtxDestroy( pDsigCtx ) ;
160 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
162 //Unregistered the stream/URI binding
163 if( xUriBinding.is() )
164 xmlUnregisterStreamInputCallbacks() ;
166 clearErrorRecorder();
167 return aTemplate ;
170 /* XXMLSignature */
171 Reference< XXMLSignatureTemplate >
172 SAL_CALL XMLSignature_MSCryptImpl::validate(
173 const Reference< XXMLSignatureTemplate >& aTemplate ,
174 const Reference< XXMLSecurityContext >& aSecurityCtx
176 xmlSecKeysMngrPtr pMngr = nullptr ;
177 xmlSecDSigCtxPtr pDsigCtx = nullptr ;
178 xmlNodePtr pNode = nullptr ;
180 if( !aTemplate.is() )
181 throw RuntimeException() ;
183 if( !aSecurityCtx.is() )
184 throw RuntimeException() ;
186 //Get Keys Manager
187 Reference< XSecurityEnvironment > xSecEnv
188 = aSecurityCtx->getSecurityEnvironmentByIndex(
189 aSecurityCtx->getDefaultSecurityEnvironmentIndex());
190 SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(xSecEnv.get());
191 if( pSecEnv == nullptr )
192 throw RuntimeException() ;
194 //Get the xml node
195 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
196 if( !xElement.is() )
197 throw RuntimeException() ;
199 XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
200 if( pElement == nullptr )
201 throw RuntimeException() ;
203 pNode = pElement->getNativeElement() ;
205 //Get the stream/URI binding
206 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
207 if( xUriBinding.is() ) {
208 //Register the stream input callbacks into libxml2
209 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
210 throw RuntimeException() ;
213 setErrorRecorder( );
215 pMngr = pSecEnv->createKeysManager();
216 if( !pMngr ) {
217 throw RuntimeException() ;
220 //Create Signature context
221 pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
222 if( pDsigCtx == nullptr )
224 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
225 clearErrorRecorder();
226 return aTemplate;
229 // We do certificate verification ourselves.
230 pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
232 // limit possible key data to valid X509 certificates only, no KeyValues
233 if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecMSCngKeyDataX509GetKlass()) < 0)
234 throw RuntimeException("failed to limit allowed key data");
236 //Verify signature
237 //The documentation says that the signature is only valid if the return value is 0 (that is, not < 0)
238 //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not make any assumptions, if
239 //the return value is < 0. Then we must regard the signature as INVALID. We cannot use the
240 //error recorder feature to get the ONE error that made the verification fail, because there is no
241 //documentation/specification as to how to interpret the number of recorded errors and what is the initial
242 //error.
243 int rs = xmlSecDSigCtxVerify(pDsigCtx , pNode);
245 // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
246 xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences);
247 // Require that all manifest references are also good.
248 xmlSecSize nReferenceGood = 0;
249 for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference)
251 xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference));
252 if (pReference)
254 if (pReference->status == xmlSecDSigStatusSucceeded)
255 ++nReferenceGood;
258 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
260 if (rs == 0 && nReferenceCount == nReferenceGood)
262 if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
263 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
264 else
265 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
267 else
269 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
272 xmlSecDSigCtxDestroy( pDsigCtx ) ;
273 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
275 //Unregistered the stream/URI binding
276 if( xUriBinding.is() )
277 xmlUnregisterStreamInputCallbacks() ;
280 clearErrorRecorder();
281 return aTemplate;
284 /* XServiceInfo */
285 OUString SAL_CALL XMLSignature_MSCryptImpl::getImplementationName() {
286 return "com.sun.star.xml.crypto.XMLSignature";
289 /* XServiceInfo */
290 sal_Bool SAL_CALL XMLSignature_MSCryptImpl::supportsService( const OUString& serviceName) {
291 return cppu::supportsService(this, serviceName);
294 /* XServiceInfo */
295 Sequence< OUString > SAL_CALL XMLSignature_MSCryptImpl::getSupportedServiceNames() {
296 return { "com.sun.star.xml.crypto.XMLSignature" };
299 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
300 com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext* /*pCtx*/,
301 uno::Sequence<uno::Any> const& /*rSeq*/)
303 return cppu::acquire(new XMLSignature_MSCryptImpl);
306 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */