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>
21 #include <sal/log.hxx>
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
;
52 class XMLSignature_MSCryptImpl
: public ::cppu::WeakImplHelper
<
53 css::xml::crypto::XXMLSignature
,
54 css::lang::XServiceInfo
>
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
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
70 //Methods from XServiceInfo
71 virtual OUString SAL_CALL
getImplementationName() override
;
73 virtual sal_Bool SAL_CALL
supportsService(
74 const OUString
& ServiceName
77 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
82 XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() {
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 ;
97 throw RuntimeException() ;
99 if( !aEnvironment
.is() )
100 throw RuntimeException() ;
103 SecurityEnvironment_MSCryptImpl
* pSecEnv
= dynamic_cast<SecurityEnvironment_MSCryptImpl
*>(aEnvironment
.get());
104 if( pSecEnv
== nullptr )
105 throw RuntimeException() ;
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() ;
130 pMngr
= pSecEnv
->createKeysManager();
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();
146 if( xmlSecDSigCtxSign( pDsigCtx
, pNode
) == 0 )
148 if (pDsigCtx
->status
== xmlSecDSigStatusSucceeded
)
149 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
151 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
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();
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() ;
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() ;
195 Reference
< XXMLElementWrapper
> xElement
= aTemplate
->getTemplate() ;
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() ;
215 pMngr
= pSecEnv
->createKeysManager();
217 throw RuntimeException() ;
220 //Create Signature context
221 pDsigCtx
= xmlSecDSigCtxCreate( pMngr
) ;
222 if( pDsigCtx
== nullptr )
224 SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr
);
225 clearErrorRecorder();
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");
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
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
));
254 if (pReference
->status
== xmlSecDSigStatusSucceeded
)
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
);
265 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
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();
285 OUString SAL_CALL
XMLSignature_MSCryptImpl::getImplementationName() {
286 return "com.sun.star.xml.crypto.XMLSignature";
290 sal_Bool SAL_CALL
XMLSignature_MSCryptImpl::supportsService( const OUString
& serviceName
) {
291 return cppu::supportsService(this, serviceName
);
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: */