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