LibreOffice Module xmlsecurity (master) 1
xmlsignature_nssimpl.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 <xmlsec-wrapper.h>
22
23#include <xmlsec/nss/x509.h>
24
28
30
32#include <sal/log.hxx>
33
34#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
35#include <memory>
36
37namespace com::sun::star::uno { class XComponentContext; }
38
39using namespace ::com::sun::star;
40using namespace ::com::sun::star::uno ;
41using namespace ::com::sun::star::lang ;
42
43using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
44using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
45using ::com::sun::star::xml::crypto::XXMLSignature ;
46using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ;
47using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
48using ::com::sun::star::xml::crypto::XUriBinding ;
49
50namespace std
51{
52template <> struct default_delete<xmlSecKeysMngr>
53{
54 void operator()(xmlSecKeysMngrPtr ptr) { SecurityEnvironment_NssImpl::destroyKeysManager(ptr); }
55};
56template <> struct default_delete<xmlSecDSigCtx>
57{
58 void operator()(xmlSecDSigCtxPtr ptr) { xmlSecDSigCtxDestroy(ptr); }
59};
60}
61
62namespace {
63
64class XMLSignature_NssImpl
65 : public ::cppu::WeakImplHelper<xml::crypto::XXMLSignature, lang::XServiceInfo>
66{
67public:
68 explicit XMLSignature_NssImpl();
69
70 //Methods from XXMLSignature
71 virtual uno::Reference<xml::crypto::XXMLSignatureTemplate> SAL_CALL
72 generate(const uno::Reference<xml::crypto::XXMLSignatureTemplate>& aTemplate,
73 const uno::Reference<xml::crypto::XSecurityEnvironment>& aEnvironment) override;
74
75 virtual uno::Reference<xml::crypto::XXMLSignatureTemplate> SAL_CALL
76 validate(const uno::Reference<xml::crypto::XXMLSignatureTemplate>& aTemplate,
77 const uno::Reference<xml::crypto::XXMLSecurityContext>& aContext) override;
78
79 //Methods from XServiceInfo
80 virtual OUString SAL_CALL getImplementationName() override;
81
82 virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
83
84 virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
85};
86
87}
88
89XMLSignature_NssImpl::XMLSignature_NssImpl() {
90}
91
92/* XXMLSignature */
93Reference< XXMLSignatureTemplate >
94SAL_CALL XMLSignature_NssImpl::generate(
95 const Reference< XXMLSignatureTemplate >& aTemplate ,
96 const Reference< XSecurityEnvironment >& aEnvironment
97)
98{
99 xmlNodePtr pNode = nullptr ;
100
101 if( !aTemplate.is() )
102 throw RuntimeException() ;
103
104 if( !aEnvironment.is() )
105 throw RuntimeException() ;
106
107 //Get the xml node
108 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
109 if( !xElement.is() ) {
110 throw RuntimeException() ;
111 }
112
114 = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
115 if( pElement == nullptr ) {
116 throw RuntimeException() ;
117 }
118
119 pNode = pElement->getNativeElement() ;
120
121 //Get the stream/URI binding
122 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
123 if( xUriBinding.is() ) {
124 //Register the stream input callbacks into libxml2
125 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
126 throw RuntimeException() ;
127 }
128
129 //Get Keys Manager
130
131 // the key manager should be retrieved from SecurityEnvironment, instead of SecurityContext
133 = dynamic_cast<SecurityEnvironment_NssImpl*>(aEnvironment.get());
134 if( pSecEnv == nullptr )
135 throw RuntimeException() ;
136
138
139 std::unique_ptr<xmlSecKeysMngr> pMngr(pSecEnv->createKeysManager());
140 if( !pMngr ) {
141 throw RuntimeException() ;
142 }
143
144 //Create Signature context
145 std::unique_ptr<xmlSecDSigCtx> pDsigCtx(xmlSecDSigCtxCreate(pMngr.get()));
146 if( pDsigCtx == nullptr )
147 {
148 //throw XMLSignatureException() ;
150 return aTemplate;
151 }
152
153 //Sign the template
154 if( xmlSecDSigCtxSign( pDsigCtx.get() , pNode ) == 0 )
155 {
156 if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
157 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
158 else
159 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
160 }
161 else
162 {
163 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
164 }
165
166 //Unregistered the stream/URI binding
167 if( xUriBinding.is() )
169
171 return aTemplate ;
172}
173
174/* XXMLSignature */
175Reference< XXMLSignatureTemplate >
176SAL_CALL XMLSignature_NssImpl::validate(
177 const Reference< XXMLSignatureTemplate >& aTemplate ,
178 const Reference< XXMLSecurityContext >& aSecurityCtx
179) {
180 xmlNodePtr pNode = nullptr ;
181 //sal_Bool valid ;
182
183 if( !aTemplate.is() )
184 throw RuntimeException() ;
185
186 if( !aSecurityCtx.is() )
187 throw RuntimeException() ;
188
189 //Get the xml node
190 Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
191 if( !xElement.is() )
192 throw RuntimeException() ;
193
195 = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
196 if( pElement == nullptr )
197 throw RuntimeException() ;
198
199 pNode = pElement->getNativeElement() ;
200
201 //Get the stream/URI binding
202 Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
203 if( xUriBinding.is() ) {
204 //Register the stream input callbacks into libxml2
205 if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
206 throw RuntimeException() ;
207 }
208
210
211 sal_Int32 nSecurityEnvironment = aSecurityCtx->getSecurityEnvironmentNumber();
212 sal_Int32 i;
213
214 for (i=0; i<nSecurityEnvironment; ++i)
215 {
216 Reference< XSecurityEnvironment > aEnvironment = aSecurityCtx->getSecurityEnvironmentByIndex(i);
217
218 //Get Keys Manager
220 = dynamic_cast<SecurityEnvironment_NssImpl*>(aEnvironment.get());
221 if( pSecEnv == nullptr )
222 throw RuntimeException() ;
223
224 std::unique_ptr<xmlSecKeysMngr> pMngr(pSecEnv->createKeysManager());
225 if( !pMngr ) {
226 throw RuntimeException() ;
227 }
228
229 //Create Signature context
230 std::unique_ptr<xmlSecDSigCtx> pDsigCtx(xmlSecDSigCtxCreate(pMngr.get()));
231 if( pDsigCtx == nullptr )
232 {
234 return aTemplate;
235 }
236
237 // We do certificate verification ourselves.
238 pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
239
240 // limit possible key data to valid X509 certificates only, no KeyValues
241 if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecNssKeyDataX509GetKlass()) < 0)
242 throw RuntimeException("failed to limit allowed key data");
243
244 xmlBufferPtr pBuf = xmlBufferCreate();
245 xmlNodeDump(pBuf, nullptr, pNode, 0, 0);
246 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify input XML node is '"
247 << reinterpret_cast<const char*>(xmlBufferContent(pBuf))
248 << "'");
249 xmlBufferFree(pBuf);
250
251 //Verify signature
252 int rs = xmlSecDSigCtxVerify( pDsigCtx.get() , pNode );
253
254 // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
255 xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences);
256 // Require that all manifest references are also good.
257 xmlSecSize nReferenceGood = 0;
258 for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference)
259 {
260 xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference));
261 if (pReference)
262 {
263 if (pReference->status == xmlSecDSigStatusSucceeded)
264 ++nReferenceGood;
265 }
266 }
267 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
268
269 if (rs == 0 && pDsigCtx->status == xmlSecDSigStatusSucceeded && nReferenceCount == nReferenceGood)
270 {
271 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
272 break;
273 }
274 else
275 {
276 aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
277 }
278 }
279
280
281 //Unregistered the stream/URI binding
282 if( xUriBinding.is() )
284
285 //return valid ;
287 return aTemplate;
288}
289
290/* XServiceInfo */
291OUString SAL_CALL XMLSignature_NssImpl::getImplementationName()
292{
293 return "com.sun.star.xml.crypto.XMLSignature";
294}
295
296/* XServiceInfo */
297sal_Bool SAL_CALL XMLSignature_NssImpl::supportsService(const OUString& rServiceName)
298{
299 const css::uno::Sequence<OUString> aServiceNames = getSupportedServiceNames();
300 for (OUString const & rCurrentServiceName : aServiceNames)
301 {
302 if (rCurrentServiceName == rServiceName)
303 return true;
304 }
305 return false;
306}
307
308/* XServiceInfo */
309Sequence<OUString> SAL_CALL XMLSignature_NssImpl::getSupportedServiceNames()
310{
311 return { "com.sun.star.xml.crypto.XMLSignature" };
312}
313
314extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
316 uno::Sequence<uno::Any> const& /*rSeq*/)
317{
318 return cppu::acquire(new XMLSignature_NssImpl);
319}
320
321/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr)
void setErrorRecorder()
void clearErrorRecorder()
Sequence< OUString > aServiceNames
#define SAL_INFO(area, stream)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
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()