LibreOffice Module xmlsecurity (master) 1
xmlsignature_mscryptimpl.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#include <sal/config.h>
21#include <sal/log.hxx>
22#include <rtl/uuid.h>
23#include <xmlsec-wrapper.h>
24
25#include <xmlsec/mscng/x509.h>
26
27#include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
28#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
29
31
37
38using namespace ::com::sun::star;
39using namespace ::com::sun::star::uno ;
40using namespace ::com::sun::star::lang ;
41
42using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
43using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
44using ::com::sun::star::xml::crypto::XXMLSignature ;
45using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ;
46using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
47using ::com::sun::star::xml::crypto::XUriBinding ;
48
49namespace {
50
51class XMLSignature_MSCryptImpl : public ::cppu::WeakImplHelper<
52 css::xml::crypto::XXMLSignature ,
53 css::lang::XServiceInfo >
54{
55 public:
56 explicit XMLSignature_MSCryptImpl();
57
58 //Methods from XXMLSignature
59 virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL generate(
60 const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
61 const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aEnvironment
62 ) override;
63
64 virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL validate(
65 const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
66 const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& aContext
67 ) override;
68
69 //Methods from XServiceInfo
70 virtual OUString SAL_CALL getImplementationName() override;
71
72 virtual sal_Bool SAL_CALL supportsService(
73 const OUString& ServiceName
74 ) override;
75
76 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
77} ;
78
79}
80
81XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() {
82}
83
84/* XXMLSignature */
85Reference< XXMLSignatureTemplate >
86SAL_CALL XMLSignature_MSCryptImpl::generate(
87 const Reference< XXMLSignatureTemplate >& aTemplate ,
88 const Reference< XSecurityEnvironment >& aEnvironment
89)
90{
91 xmlSecKeysMngrPtr pMngr = nullptr ;
92 xmlSecDSigCtxPtr pDsigCtx = nullptr ;
93 xmlNodePtr pNode = nullptr ;
94
95 if( !aTemplate.is() )
96 throw RuntimeException() ;
97
98 if( !aEnvironment.is() )
99 throw RuntimeException() ;
100
101 //Get Keys Manager
102 SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(aEnvironment.get());
103 if( pSecEnv == nullptr )
104 throw RuntimeException() ;
105
106 //Get the xml node
107 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
108 if( !xElement.is() ) {
109 throw RuntimeException() ;
110 }
111
112 XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
113 if( pElement == nullptr ) {
114 throw RuntimeException() ;
115 }
116
117 pNode = pElement->getNativeElement() ;
118
119 //Get the stream/URI binding
120 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
121 if( xUriBinding.is() ) {
122 //Register the stream input callbacks into libxml2
123 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
124 throw RuntimeException() ;
125 }
126
128
129 pMngr = pSecEnv->createKeysManager();
130 if( !pMngr ) {
131 throw RuntimeException() ;
132 }
133
134 //Create Signature context
135 pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
136 if( pDsigCtx == nullptr )
137 {
138 //throw XMLSignatureException() ;
141 return aTemplate;
142 }
143
144 //Sign the template
145 if( xmlSecDSigCtxSign( pDsigCtx , pNode ) == 0 )
146 {
147 if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
148 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
149 else
150 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
151 }
152 else
153 {
154 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
155 }
156
157
158 xmlSecDSigCtxDestroy( pDsigCtx ) ;
160
161 //Unregistered the stream/URI binding
162 if( xUriBinding.is() )
164
166 return aTemplate ;
167}
168
169/* XXMLSignature */
170Reference< XXMLSignatureTemplate >
171SAL_CALL XMLSignature_MSCryptImpl::validate(
172 const Reference< XXMLSignatureTemplate >& aTemplate ,
173 const Reference< XXMLSecurityContext >& aSecurityCtx
174) {
175 xmlSecKeysMngrPtr pMngr = nullptr ;
176 xmlSecDSigCtxPtr pDsigCtx = nullptr ;
177 xmlNodePtr pNode = nullptr ;
178
179 if( !aTemplate.is() )
180 throw RuntimeException() ;
181
182 if( !aSecurityCtx.is() )
183 throw RuntimeException() ;
184
185 //Get Keys Manager
186 Reference< XSecurityEnvironment > xSecEnv
187 = aSecurityCtx->getSecurityEnvironmentByIndex(
188 aSecurityCtx->getDefaultSecurityEnvironmentIndex());
189 SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(xSecEnv.get());
190 if( pSecEnv == nullptr )
191 throw RuntimeException() ;
192
193 //Get the xml node
194 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
195 if( !xElement.is() )
196 throw RuntimeException() ;
197
198 XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
199 if( pElement == nullptr )
200 throw RuntimeException() ;
201
202 pNode = pElement->getNativeElement() ;
203
204 //Get the stream/URI binding
205 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
206 if( xUriBinding.is() ) {
207 //Register the stream input callbacks into libxml2
208 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
209 throw RuntimeException() ;
210 }
211
213
214 pMngr = pSecEnv->createKeysManager();
215 if( !pMngr ) {
216 throw RuntimeException() ;
217 }
218
219 //Create Signature context
220 pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
221 if( pDsigCtx == nullptr )
222 {
225 return aTemplate;
226 }
227
228 // We do certificate verification ourselves.
229 pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
230
231 // limit possible key data to valid X509 certificates only, no KeyValues
232 if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecMSCngKeyDataX509GetKlass()) < 0)
233 throw RuntimeException("failed to limit allowed key data");
234
235 //Verify signature
236 //The documentation says that the signature is only valid if the return value is 0 (that is, not < 0)
237 //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not make any assumptions, if
238 //the return value is < 0. Then we must regard the signature as INVALID. We cannot use the
239 //error recorder feature to get the ONE error that made the verification fail, because there is no
240 //documentation/specification as to how to interpret the number of recorded errors and what is the initial
241 //error.
242 int rs = xmlSecDSigCtxVerify(pDsigCtx , pNode);
243
244 // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
245 xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences);
246 // Require that all manifest references are also good.
247 xmlSecSize nReferenceGood = 0;
248 for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference)
249 {
250 xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference));
251 if (pReference)
252 {
253 if (pReference->status == xmlSecDSigStatusSucceeded)
254 ++nReferenceGood;
255 }
256 }
257 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
258
259 if (rs == 0 && nReferenceCount == nReferenceGood)
260 {
261 if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
262 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
263 else
264 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
265 }
266 else
267 {
268 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
269 }
270
271 xmlSecDSigCtxDestroy( pDsigCtx ) ;
273
274 //Unregistered the stream/URI binding
275 if( xUriBinding.is() )
277
278
280 return aTemplate;
281}
282
283/* XServiceInfo */
284OUString SAL_CALL XMLSignature_MSCryptImpl::getImplementationName() {
285 return "com.sun.star.xml.crypto.XMLSignature";
286}
287
288/* XServiceInfo */
289sal_Bool SAL_CALL XMLSignature_MSCryptImpl::supportsService( const OUString& serviceName) {
290return cppu::supportsService(this, serviceName);
291}
292
293/* XServiceInfo */
294Sequence< OUString > SAL_CALL XMLSignature_MSCryptImpl::getSupportedServiceNames() {
295 return { "com.sun.star.xml.crypto.XMLSignature" };
296}
297
298extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
300 uno::Sequence<uno::Any> const& /*rSeq*/)
301{
302 return cppu::acquire(new XMLSignature_MSCryptImpl);
303}
304
305/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr)
void setErrorRecorder()
void clearErrorRecorder()
#define SAL_INFO(area, stream)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
unsigned char sal_Bool
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext *, uno::Sequence< uno::Any > const &)
int xmlRegisterStreamInputCallbacks(css::uno::Reference< css::xml::crypto::XUriBinding > const &aUriBinding)
int xmlUnregisterStreamInputCallbacks()