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>
22 #include <xmlsec/nss/x509.h>
24 #include <xmlelementwrapper_xmlsecimpl.hxx>
25 #include <xmlsec/xmlstreamio.hxx>
26 #include <xmlsec/errorcallback.hxx>
28 #include "securityenvironment_nssimpl.hxx"
30 #include <xmlsec/xmldsig.h>
31 #include <sal/log.hxx>
33 #include <com/sun/star/xml/crypto/XXMLSignature.hpp>
36 namespace com::sun::star::uno
{ class XComponentContext
; }
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::lang
;
42 using ::com::sun::star::xml::wrapper::XXMLElementWrapper
;
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
;
51 template <> struct default_delete
<xmlSecKeysMngr
>
53 void operator()(xmlSecKeysMngrPtr ptr
) { SecurityEnvironment_NssImpl::destroyKeysManager(ptr
); }
55 template <> struct default_delete
<xmlSecDSigCtx
>
57 void operator()(xmlSecDSigCtxPtr ptr
) { xmlSecDSigCtxDestroy(ptr
); }
63 class XMLSignature_NssImpl
64 : public ::cppu::WeakImplHelper
<xml::crypto::XXMLSignature
, lang::XServiceInfo
>
67 explicit XMLSignature_NssImpl();
69 //Methods from XXMLSignature
70 virtual uno::Reference
<xml::crypto::XXMLSignatureTemplate
> SAL_CALL
71 generate(const uno::Reference
<xml::crypto::XXMLSignatureTemplate
>& aTemplate
,
72 const uno::Reference
<xml::crypto::XSecurityEnvironment
>& aEnvironment
) override
;
74 virtual uno::Reference
<xml::crypto::XXMLSignatureTemplate
> SAL_CALL
75 validate(const uno::Reference
<xml::crypto::XXMLSignatureTemplate
>& aTemplate
,
76 const uno::Reference
<xml::crypto::XXMLSecurityContext
>& aContext
) override
;
78 //Methods from XServiceInfo
79 virtual OUString SAL_CALL
getImplementationName() override
;
81 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
83 virtual uno::Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
;
88 XMLSignature_NssImpl::XMLSignature_NssImpl() {
92 Reference
< XXMLSignatureTemplate
>
93 SAL_CALL
XMLSignature_NssImpl::generate(
94 const Reference
< XXMLSignatureTemplate
>& aTemplate
,
95 const Reference
< XSecurityEnvironment
>& aEnvironment
98 xmlNodePtr pNode
= nullptr ;
100 if( !aTemplate
.is() )
101 throw RuntimeException() ;
103 if( !aEnvironment
.is() )
104 throw RuntimeException() ;
107 Reference
< XXMLElementWrapper
> xElement
= aTemplate
->getTemplate() ;
108 if( !xElement
.is() ) {
109 throw RuntimeException() ;
112 XMLElementWrapper_XmlSecImpl
* pElement
113 = 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 // the key manager should be retrieved from SecurityEnvironment, instead of SecurityContext
131 SecurityEnvironment_NssImpl
* pSecEnv
132 = dynamic_cast<SecurityEnvironment_NssImpl
*>(aEnvironment
.get());
133 if( pSecEnv
== nullptr )
134 throw RuntimeException() ;
138 std::unique_ptr
<xmlSecKeysMngr
> pMngr(pSecEnv
->createKeysManager());
140 throw RuntimeException() ;
143 //Create Signature context
144 std::unique_ptr
<xmlSecDSigCtx
> pDsigCtx(xmlSecDSigCtxCreate(pMngr
.get()));
145 if( pDsigCtx
== nullptr )
147 //throw XMLSignatureException() ;
148 clearErrorRecorder();
153 if( xmlSecDSigCtxSign( pDsigCtx
.get() , pNode
) == 0 )
155 if (pDsigCtx
->status
== xmlSecDSigStatusSucceeded
)
156 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
158 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
162 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
165 //Unregistered the stream/URI binding
166 if( xUriBinding
.is() )
167 xmlUnregisterStreamInputCallbacks() ;
169 clearErrorRecorder();
174 Reference
< XXMLSignatureTemplate
>
175 SAL_CALL
XMLSignature_NssImpl::validate(
176 const Reference
< XXMLSignatureTemplate
>& aTemplate
,
177 const Reference
< XXMLSecurityContext
>& aSecurityCtx
179 xmlNodePtr pNode
= nullptr ;
182 if( !aTemplate
.is() )
183 throw RuntimeException() ;
185 if( !aSecurityCtx
.is() )
186 throw RuntimeException() ;
189 Reference
< XXMLElementWrapper
> xElement
= aTemplate
->getTemplate() ;
191 throw RuntimeException() ;
193 XMLElementWrapper_XmlSecImpl
* pElement
194 = dynamic_cast<XMLElementWrapper_XmlSecImpl
*>(xElement
.get());
195 if( pElement
== nullptr )
196 throw RuntimeException() ;
198 pNode
= pElement
->getNativeElement() ;
200 //Get the stream/URI binding
201 Reference
< XUriBinding
> xUriBinding
= aTemplate
->getBinding() ;
202 if( xUriBinding
.is() ) {
203 //Register the stream input callbacks into libxml2
204 if( xmlRegisterStreamInputCallbacks( xUriBinding
) < 0 )
205 throw RuntimeException() ;
210 sal_Int32 nSecurityEnvironment
= aSecurityCtx
->getSecurityEnvironmentNumber();
213 for (i
=0; i
<nSecurityEnvironment
; ++i
)
215 Reference
< XSecurityEnvironment
> aEnvironment
= aSecurityCtx
->getSecurityEnvironmentByIndex(i
);
218 SecurityEnvironment_NssImpl
* pSecEnv
219 = dynamic_cast<SecurityEnvironment_NssImpl
*>(aEnvironment
.get());
220 if( pSecEnv
== nullptr )
221 throw RuntimeException() ;
223 std::unique_ptr
<xmlSecKeysMngr
> pMngr(pSecEnv
->createKeysManager());
225 throw RuntimeException() ;
228 //Create Signature context
229 std::unique_ptr
<xmlSecDSigCtx
> pDsigCtx(xmlSecDSigCtxCreate(pMngr
.get()));
230 if( pDsigCtx
== nullptr )
232 clearErrorRecorder();
236 // We do certificate verification ourselves.
237 pDsigCtx
->keyInfoReadCtx
.flags
|= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS
;
239 // limit possible key data to valid X509 certificates only, no KeyValues
240 if (xmlSecPtrListAdd(&(pDsigCtx
->keyInfoReadCtx
.enabledKeyData
), BAD_CAST
xmlSecNssKeyDataX509GetKlass()) < 0)
241 throw RuntimeException(u
"failed to limit allowed key data"_ustr
);
243 xmlBufferPtr pBuf
= xmlBufferCreate();
244 xmlNodeDump(pBuf
, nullptr, pNode
, 0, 0);
245 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify input XML node is '"
246 << reinterpret_cast<const char*>(xmlBufferContent(pBuf
))
251 int rs
= xmlSecDSigCtxVerify( pDsigCtx
.get() , pNode
);
253 // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
254 xmlSecSize nReferenceCount
= xmlSecPtrListGetSize(&pDsigCtx
->manifestReferences
);
255 // Require that all manifest references are also good.
256 xmlSecSize nReferenceGood
= 0;
257 for (xmlSecSize nReference
= 0; nReference
< nReferenceCount
; ++nReference
)
259 xmlSecDSigReferenceCtxPtr pReference
= static_cast<xmlSecDSigReferenceCtxPtr
>(xmlSecPtrListGetItem(&pDsigCtx
->manifestReferences
, nReference
));
262 if (pReference
->status
== xmlSecDSigStatusSucceeded
)
266 SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx
->status
<< ", references good " << nReferenceGood
<< " of " << nReferenceCount
);
268 if (rs
== 0 && pDsigCtx
->status
== xmlSecDSigStatusSucceeded
&& nReferenceCount
== nReferenceGood
)
270 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
275 aTemplate
->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN
);
280 //Unregistered the stream/URI binding
281 if( xUriBinding
.is() )
282 xmlUnregisterStreamInputCallbacks() ;
285 clearErrorRecorder();
290 OUString SAL_CALL
XMLSignature_NssImpl::getImplementationName()
292 return u
"com.sun.star.xml.crypto.XMLSignature"_ustr
;
296 sal_Bool SAL_CALL
XMLSignature_NssImpl::supportsService(const OUString
& rServiceName
)
298 const css::uno::Sequence
<OUString
> aServiceNames
= getSupportedServiceNames();
299 for (OUString
const & rCurrentServiceName
: aServiceNames
)
301 if (rCurrentServiceName
== rServiceName
)
308 Sequence
<OUString
> SAL_CALL
XMLSignature_NssImpl::getSupportedServiceNames()
310 return { u
"com.sun.star.xml.crypto.XMLSignature"_ustr
};
313 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
314 com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext
* /*pCtx*/,
315 uno::Sequence
<uno::Any
> const& /*rSeq*/)
317 return cppu::acquire(new XMLSignature_NssImpl
);
320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */