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 <sal/config.h>
23 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
24 #include <com/sun/star/xml/crypto/XXMLSignature.hpp>
26 #include "securityenvironment_mscryptimpl.hxx"
28 #include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
29 #include <xmlelementwrapper_xmlsecimpl.hxx>
30 #include <xmlsec/xmlstreamio.hxx>
31 #include <xmlsec/errorcallback.hxx>
33 #include <xmlsec-wrapper.h>
35 using namespace ::com::sun::star
;
36 using namespace ::com::sun::star::uno
;
37 using namespace ::com::sun::star::lang
;
38 using ::com::sun::star::lang::XMultiServiceFactory
;
39 using ::com::sun::star::lang::XSingleServiceFactory
;
41 using ::com::sun::star::xml::wrapper::XXMLElementWrapper
;
42 using ::com::sun::star::xml::wrapper::XXMLDocumentWrapper
;
43 using ::com::sun::star::xml::crypto::XSecurityEnvironment
;
44 using ::com::sun::star::xml::crypto::XXMLSignature
;
45 using ::com::sun::star::xml::crypto::XXMLSignatureTemplate
;
46 using ::com::sun::star::xml::crypto::XXMLSecurityContext
;
47 using ::com::sun::star::xml::crypto::XUriBinding
;
49 class XMLSignature_MSCryptImpl
: public ::cppu::WeakImplHelper
<
50 css::xml::crypto::XXMLSignature
,
51 css::lang::XServiceInfo
>
54 explicit XMLSignature_MSCryptImpl();
56 //Methods from XXMLSignature
57 virtual css::uno::Reference
< css::xml::crypto::XXMLSignatureTemplate
> SAL_CALL
generate(
58 const css::uno::Reference
< css::xml::crypto::XXMLSignatureTemplate
>& aTemplate
,
59 const css::uno::Reference
< css::xml::crypto::XSecurityEnvironment
>& aEnvironment
62 virtual css::uno::Reference
< css::xml::crypto::XXMLSignatureTemplate
> SAL_CALL
validate(
63 const css::uno::Reference
< css::xml::crypto::XXMLSignatureTemplate
>& aTemplate
,
64 const css::uno::Reference
< css::xml::crypto::XXMLSecurityContext
>& aContext
67 //Methods from XServiceInfo
68 virtual OUString SAL_CALL
getImplementationName() override
;
70 virtual sal_Bool SAL_CALL
supportsService(
71 const OUString
& ServiceName
74 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
77 XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() {
81 Reference
< XXMLSignatureTemplate
>
82 SAL_CALL
XMLSignature_MSCryptImpl::generate(
83 const Reference
< XXMLSignatureTemplate
>& aTemplate
,
84 const Reference
< XSecurityEnvironment
>& aEnvironment
87 xmlSecKeysMngrPtr pMngr
= nullptr ;
88 xmlSecDSigCtxPtr pDsigCtx
= nullptr ;
89 xmlNodePtr pNode
= nullptr ;
92 throw RuntimeException() ;
94 if( !aEnvironment
.is() )
95 throw RuntimeException() ;
98 Reference
< XUnoTunnel
> xSecTunnel( aEnvironment
, UNO_QUERY_THROW
) ;
99 SecurityEnvironment_MSCryptImpl
* pSecEnv
= reinterpret_cast<SecurityEnvironment_MSCryptImpl
*>(xSecTunnel
->getSomething( SecurityEnvironment_MSCryptImpl::getUnoTunnelId() ));
100 if( pSecEnv
== nullptr )
101 throw RuntimeException() ;
104 Reference
< XXMLElementWrapper
> xElement
= aTemplate
->getTemplate() ;
105 if( !xElement
.is() ) {
106 throw RuntimeException() ;
109 Reference
< XUnoTunnel
> xNodTunnel( xElement
, UNO_QUERY_THROW
) ;
110 XMLElementWrapper_XmlSecImpl
* pElement
= reinterpret_cast<XMLElementWrapper_XmlSecImpl
*>(xNodTunnel
->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelId() ));
111 if( pElement
== nullptr ) {
112 throw RuntimeException() ;
115 pNode
= pElement
->getNativeElement() ;
117 //Get the stream/URI binding
118 Reference
< XUriBinding
> xUriBinding
= aTemplate
->getBinding() ;
119 if( xUriBinding
.is() ) {
120 //Register the stream input callbacks into libxml2
121 if( xmlRegisterStreamInputCallbacks( xUriBinding
) < 0 )
122 throw RuntimeException() ;
127 pMngr
= pSecEnv
->createKeysManager();
129 throw RuntimeException() ;
132 //Create Signature context
133 pDsigCtx
= xmlSecDSigCtxCreate( pMngr
) ;
134 if( pDsigCtx
== nullptr )
136 //throw XMLSignatureException() ;
137 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr
);
138 clearErrorRecorder();
143 if( xmlSecDSigCtxSign( pDsigCtx
, pNode
) == 0 )
145 if (pDsigCtx
->status
== xmlSecDSigStatusSucceeded
)
146 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
148 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
152 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
156 xmlSecDSigCtxDestroy( pDsigCtx
) ;
157 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr
);
159 //Unregistered the stream/URI binding
160 if( xUriBinding
.is() )
161 xmlUnregisterStreamInputCallbacks() ;
163 clearErrorRecorder();
168 Reference
< XXMLSignatureTemplate
>
169 SAL_CALL
XMLSignature_MSCryptImpl::validate(
170 const Reference
< XXMLSignatureTemplate
>& aTemplate
,
171 const Reference
< XXMLSecurityContext
>& aSecurityCtx
173 xmlSecKeysMngrPtr pMngr
= nullptr ;
174 xmlSecDSigCtxPtr pDsigCtx
= nullptr ;
175 xmlNodePtr pNode
= nullptr ;
177 if( !aTemplate
.is() )
178 throw RuntimeException() ;
180 if( !aSecurityCtx
.is() )
181 throw RuntimeException() ;
184 Reference
< XSecurityEnvironment
> xSecEnv
185 = aSecurityCtx
->getSecurityEnvironmentByIndex(
186 aSecurityCtx
->getDefaultSecurityEnvironmentIndex());
187 Reference
< XUnoTunnel
> xSecTunnel( xSecEnv
, UNO_QUERY_THROW
) ;
188 SecurityEnvironment_MSCryptImpl
* pSecEnv
= reinterpret_cast<SecurityEnvironment_MSCryptImpl
*>(xSecTunnel
->getSomething( SecurityEnvironment_MSCryptImpl::getUnoTunnelId() ));
189 if( pSecEnv
== nullptr )
190 throw RuntimeException() ;
193 Reference
< XXMLElementWrapper
> xElement
= aTemplate
->getTemplate() ;
195 throw RuntimeException() ;
197 Reference
< XUnoTunnel
> xNodTunnel( xElement
, UNO_QUERY_THROW
) ;
198 XMLElementWrapper_XmlSecImpl
* pElement
= reinterpret_cast<XMLElementWrapper_XmlSecImpl
*>(xNodTunnel
->getSomething( XMLElementWrapper_XmlSecImpl::getUnoTunnelId() ));
199 if( pElement
== nullptr )
200 throw RuntimeException() ;
202 pNode
= pElement
->getNativeElement() ;
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() ;
214 pMngr
= pSecEnv
->createKeysManager();
216 throw RuntimeException() ;
219 //Create Signature context
220 pDsigCtx
= xmlSecDSigCtxCreate( pMngr
) ;
221 if( pDsigCtx
== nullptr )
223 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr
);
224 clearErrorRecorder();
228 // We do certificate verification ourselves.
229 pDsigCtx
->keyInfoReadCtx
.flags
|= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS
;
232 //The documentation says that the signature is only valid if the return value is 0 (that is, not < 0)
233 //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not make any assumptions, if
234 //the return value is < 0. Then we must regard the signature as INVALID. We cannot use the
235 //error recorder feature to get the ONE error that made the verification fail, because there is no
236 //documentation/specification as to how to interpret the number of recorded errors and what is the initial
238 int rs
= xmlSecDSigCtxVerify(pDsigCtx
, pNode
);
240 // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
241 xmlSecSize nReferenceCount
= xmlSecPtrListGetSize(&pDsigCtx
->manifestReferences
);
242 // Require that all manifest references are also good.
243 xmlSecSize nReferenceGood
= 0;
244 for (xmlSecSize nReference
= 0; nReference
< nReferenceCount
; ++nReference
)
246 xmlSecDSigReferenceCtxPtr pReference
= static_cast<xmlSecDSigReferenceCtxPtr
>(xmlSecPtrListGetItem(&pDsigCtx
->manifestReferences
, nReference
));
249 if (pReference
->status
== xmlSecDSigStatusSucceeded
)
254 if (rs
== 0 && nReferenceCount
== nReferenceGood
)
256 if (pDsigCtx
->status
== xmlSecDSigStatusSucceeded
)
257 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
259 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
263 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
266 xmlSecDSigCtxDestroy( pDsigCtx
) ;
267 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr
);
269 //Unregistered the stream/URI binding
270 if( xUriBinding
.is() )
271 xmlUnregisterStreamInputCallbacks() ;
274 clearErrorRecorder();
279 OUString SAL_CALL
XMLSignature_MSCryptImpl::getImplementationName() {
280 return "com.sun.star.xml.crypto.XMLSignature";
284 sal_Bool SAL_CALL
XMLSignature_MSCryptImpl::supportsService( const OUString
& serviceName
) {
285 Sequence
< OUString
> seqServiceNames
= getSupportedServiceNames() ;
286 const OUString
* pArray
= seqServiceNames
.getConstArray() ;
287 for( sal_Int32 i
= 0 ; i
< seqServiceNames
.getLength() ; i
++ ) {
288 if( *( pArray
+ i
) == serviceName
)
295 Sequence
< OUString
> SAL_CALL
XMLSignature_MSCryptImpl::getSupportedServiceNames() {
296 Sequence
<OUString
> seqServiceNames
{ "com.sun.star.xml.crypto.XMLSignature" };
297 return seqServiceNames
;
300 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
301 com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext
* /*pCtx*/,
302 uno::Sequence
<uno::Any
> const& /*rSeq*/)
304 return cppu::acquire(new XMLSignature_MSCryptImpl
);
307 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */