summaryrefslogtreecommitdiffstats
path: root/xmlsecurity/source/xmlsec
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /xmlsecurity/source/xmlsec
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xmlsecurity/source/xmlsec')
-rw-r--r--xmlsecurity/source/xmlsec/biginteger.cxx106
-rw-r--r--xmlsecurity/source/xmlsec/certificateextension_certextn.cxx47
-rw-r--r--xmlsecurity/source/xmlsec/certificateextension_certextn.hxx36
-rw-r--r--xmlsecurity/source/xmlsec/certificateextension_xmlsecimpl.hxx56
-rw-r--r--xmlsecurity/source/xmlsec/errorcallback.cxx68
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx229
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx56
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/oid.hxx153
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx131
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx66
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx1110
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx168
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx172
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx71
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx783
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx91
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx153
-rw-r--r--xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx305
-rw-r--r--xmlsecurity/source/xmlsec/nss/certerrors.h385
-rw-r--r--xmlsecurity/source/xmlsec/nss/ciphercontext.cxx389
-rw-r--r--xmlsecurity/source/xmlsec/nss/ciphercontext.hxx81
-rw-r--r--xmlsecurity/source/xmlsec/nss/digestcontext.cxx94
-rw-r--r--xmlsecurity/source/xmlsec/nss/digestcontext.hxx59
-rw-r--r--xmlsecurity/source/xmlsec/nss/nssinitializer.cxx647
-rw-r--r--xmlsecurity/source/xmlsec/nss/nssinitializer.hxx68
-rw-r--r--xmlsecurity/source/xmlsec/nss/nssrenam.h41
-rw-r--r--xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.cxx164
-rw-r--r--xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.hxx65
-rw-r--r--xmlsecurity/source/xmlsec/nss/secerror.cxx152
-rw-r--r--xmlsecurity/source/xmlsec/nss/secerror.hxx31
-rw-r--r--xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx878
-rw-r--r--xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.hxx139
-rw-r--r--xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.cxx144
-rw-r--r--xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.hxx55
-rw-r--r--xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx602
-rw-r--r--xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx97
-rw-r--r--xmlsecurity/source/xmlsec/nss/xmlsecuritycontext_nssimpl.cxx150
-rw-r--r--xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx321
-rw-r--r--xmlsecurity/source/xmlsec/saxhelper.cxx364
-rw-r--r--xmlsecurity/source/xmlsec/xmldocumentwrapper_xmlsecimpl.cxx900
-rw-r--r--xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.cxx58
-rw-r--r--xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.hxx72
-rw-r--r--xmlsecurity/source/xmlsec/xmlsec_init.cxx73
-rw-r--r--xmlsecurity/source/xmlsec/xmlstreamio.cxx251
44 files changed, 10081 insertions, 0 deletions
diff --git a/xmlsecurity/source/xmlsec/biginteger.cxx b/xmlsecurity/source/xmlsec/biginteger.cxx
new file mode 100644
index 0000000000..1a4ab6fd9d
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/biginteger.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <biginteger.hxx>
+
+#include <xmlsec-wrapper.h>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <comphelper/sequence.hxx>
+
+using namespace ::com::sun::star::uno ;
+
+namespace xmlsecurity
+{
+Sequence< sal_Int8 > numericStringToBigInteger ( std::u16string_view numeral )
+{
+ xmlChar* chNumeral ;
+ const xmlSecByte* bnInteger ;
+ xmlSecSize length ;
+ xmlSecBn bn ;
+
+ OString onumeral = OUStringToOString( numeral , RTL_TEXTENCODING_ASCII_US ) ;
+
+ chNumeral = xmlStrndup( reinterpret_cast<const xmlChar*>(onumeral.getStr()), static_cast<int>(onumeral.getLength()) ) ;
+
+ if( xmlSecBnInitialize( &bn, 0 ) < 0 ) {
+ xmlFree( chNumeral ) ;
+ return Sequence< sal_Int8 >();
+ }
+
+ if( xmlSecBnFromDecString( &bn, chNumeral ) < 0 ) {
+ xmlFree( chNumeral ) ;
+ xmlSecBnFinalize( &bn ) ;
+ return Sequence< sal_Int8 >();
+ }
+
+ xmlFree( chNumeral ) ;
+
+ length = xmlSecBnGetSize( &bn ) ;
+ if( length <= 0 ) {
+ xmlSecBnFinalize( &bn ) ;
+ return Sequence< sal_Int8 >();
+ }
+
+ bnInteger = xmlSecBnGetData( &bn ) ;
+ if( bnInteger == nullptr ) {
+ xmlSecBnFinalize( &bn ) ;
+ return Sequence< sal_Int8 >();
+ }
+
+ Sequence< sal_Int8 > integer = comphelper::arrayToSequence<sal_Int8>(bnInteger, length);
+
+ xmlSecBnFinalize( &bn ) ;
+ return integer ;
+}
+
+OUString bigIntegerToNumericString ( const Sequence< sal_Int8 >& integer )
+{
+ OUString aRet ;
+
+ if( integer.hasElements() ) {
+ xmlSecBn bn ;
+ xmlChar* chNumeral ;
+
+ if( xmlSecBnInitialize( &bn, 0 ) < 0 )
+ return aRet ;
+
+ if( xmlSecBnSetData( &bn, reinterpret_cast<const unsigned char*>(integer.getConstArray()), integer.getLength() ) < 0 ) {
+ xmlSecBnFinalize( &bn ) ;
+ return aRet ;
+ }
+
+ chNumeral = xmlSecBnToDecString( &bn ) ;
+ if( chNumeral == nullptr ) {
+ xmlSecBnFinalize( &bn ) ;
+ return aRet ;
+ }
+
+ aRet = OUString::createFromAscii( reinterpret_cast<char*>(chNumeral) ) ;
+
+ xmlSecBnFinalize( &bn ) ;
+ xmlFree( chNumeral ) ;
+ }
+
+ return aRet ;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/certificateextension_certextn.cxx b/xmlsecurity/source/xmlsec/certificateextension_certextn.cxx
new file mode 100644
index 0000000000..d7325759de
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/certificateextension_certextn.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "certificateextension_certextn.hxx"
+
+#include <comphelper/sequence.hxx>
+
+CertificateExtension_CertExtn::CertificateExtension_CertExtn()
+ : m_critical(false)
+{
+}
+
+void CertificateExtension_CertExtn::setCertExtn(const unsigned char* value, unsigned int vlen,
+ const unsigned char* id, unsigned int idlen, bool critical)
+{
+ if( value != nullptr && vlen != 0 ) {
+ m_xExtnValue = comphelper::arrayToSequence<sal_Int8>(value, vlen);
+ } else {
+ m_xExtnValue = css::uno::Sequence<sal_Int8>();
+ }
+
+ if( id != nullptr && idlen != 0 ) {
+ m_xExtnId = comphelper::arrayToSequence<sal_Int8>(id, idlen);
+ } else {
+ m_xExtnId = css::uno::Sequence<sal_Int8>();
+ }
+
+ m_critical = critical ;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/certificateextension_certextn.hxx b/xmlsecurity/source/xmlsec/certificateextension_certextn.hxx
new file mode 100644
index 0000000000..ac84596c83
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/certificateextension_certextn.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <com/sun/star/uno/Sequence.hxx>
+
+struct CertificateExtension_CertExtn
+{
+ bool m_critical;
+ css::uno::Sequence<sal_Int8> m_xExtnId;
+ css::uno::Sequence<sal_Int8> m_xExtnValue;
+
+ CertificateExtension_CertExtn();
+ void setCertExtn(unsigned char const* value, unsigned int vlen, unsigned char const* id,
+ unsigned int idlen, bool critical);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/certificateextension_xmlsecimpl.hxx b/xmlsecurity/source/xmlsec/certificateextension_xmlsecimpl.hxx
new file mode 100644
index 0000000000..9db5867fc7
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/certificateextension_xmlsecimpl.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/security/XCertificateExtension.hpp>
+#include "certificateextension_certextn.hxx"
+
+class CertificateExtension_XmlSecImpl : public ::cppu::WeakImplHelper<
+ css::security::XCertificateExtension >
+{
+ private:
+ CertificateExtension_CertExtn m_Extn;
+
+ public:
+ //Methods from XCertificateExtension
+ virtual sal_Bool SAL_CALL isCritical() override
+ {
+ return m_Extn.m_critical;
+ }
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionId() override
+ {
+ return m_Extn.m_xExtnId;
+ }
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionValue() override
+ {
+ return m_Extn.m_xExtnValue;
+ }
+
+ void setCertExtn(unsigned char const * value, unsigned int vlen, unsigned char const * id, unsigned int idlen, bool critical)
+ {
+ m_Extn.setCertExtn(value, vlen, id, idlen, critical);
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/errorcallback.cxx b/xmlsecurity/source/xmlsec/errorcallback.cxx
new file mode 100644
index 0000000000..a535ffa770
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/errorcallback.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include <xmlsec/errorcallback.hxx>
+
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#ifdef _WIN32
+#include <prewin.h>
+#include <postwin.h>
+#include <comphelper/windowserrorstring.hxx>
+#endif
+
+extern "C" {
+
+static void errorCallback(const char* file,
+ int line,
+ const char* func,
+ const char* errorObject,
+ const char* errorSubject,
+ int reason,
+ const char* msg)
+{
+ const char* pErrorObject = errorObject ? errorObject : "";
+ const char* pErrorSubject = errorSubject ? errorSubject : "";
+ const char* pMsg = msg ? msg : "";
+ OUString systemErrorString;
+
+#ifdef _WIN32
+ systemErrorString = " " + WindowsErrorString(GetLastError());
+#endif
+
+ SAL_WARN("xmlsecurity.xmlsec", file << ":" << line << ": " << func << "() '" << pErrorObject << "' '" << pErrorSubject << "' " << reason << " '" << pMsg << "'" << systemErrorString);
+}
+
+}
+
+void setErrorRecorder()
+{
+ xmlSecErrorsSetCallback(errorCallback);
+}
+
+void clearErrorRecorder()
+{
+ xmlSecErrorsSetCallback(nullptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx b/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx
new file mode 100644
index 0000000000..ec3cecd4a7
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include "akmngr.hxx"
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keysmngr.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/mscng/crypto.h>
+#include <xmlsec/mscng/keysstore.h>
+#include <xmlsec/mscng/x509.h>
+#include <svl/cryptosign.hxx>
+
+namespace xmlsecurity
+{
+
+/**
+ * MSCryptoAppliedKeysMngrCreate:
+ *
+ * Create and load key store and certificate database into keys manager
+ *
+ * Returns keys manager pointer on success or NULL otherwise.
+ */
+xmlSecKeysMngrPtr MSCryptoAppliedKeysMngrCreate()
+{
+ xmlSecKeysMngrPtr keyMngr = nullptr ;
+ xmlSecKeyStorePtr keyStore = nullptr ;
+
+ keyStore = xmlSecKeyStoreCreate(xmlSecMSCngKeysStoreId);
+ if (keyStore == nullptr)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecKeyStoreCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+ return nullptr ;
+ }
+
+ keyMngr = xmlSecKeysMngrCreate() ;
+ if (keyMngr == nullptr)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecKeysMngrCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+
+ xmlSecKeyStoreDestroy(keyStore) ;
+ return nullptr ;
+ }
+
+ /*-
+ * Add key store to manager, from now on keys manager destroys the store if
+ * needed
+ */
+ if (xmlSecKeysMngrAdoptKeysStore(keyMngr, keyStore) < 0)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyStoreGetName(keyStore)),
+ "xmlSecKeysMngrAdoptKeyStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+
+ xmlSecKeyStoreDestroy(keyStore) ;
+ xmlSecKeysMngrDestroy(keyMngr) ;
+ return nullptr ;
+ }
+
+ /*-
+ * Initialize crypto library specific data in keys manager
+ */
+ if (xmlSecMSCngKeysMngrInit(keyMngr) < 0)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecMSCngKeysMngrInit",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+
+ xmlSecKeysMngrDestroy(keyMngr);
+ return nullptr;
+ }
+
+ /*-
+ * Set certificate database to X509 key data store
+ */
+ /*-
+ * At present, MS Crypto engine do not provide a way to setup a cert store.
+ */
+
+ /*-
+ * Set the getKey callback
+ */
+ keyMngr->getKey = xmlSecKeysMngrGetKey ;
+
+ return keyMngr ;
+}
+
+int
+MSCryptoAppliedKeysMngrAdoptKeyStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE keyStore
+)
+{
+ xmlSecKeyDataStorePtr x509Store ;
+
+ xmlSecAssert2(mngr != nullptr, -1) ;
+ xmlSecAssert2(keyStore != nullptr, -1) ;
+
+ x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId);
+ if (x509Store == nullptr)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+ return -1 ;
+ }
+
+ if (xmlSecMSCngX509StoreAdoptKeyStore(x509Store, keyStore) < 0)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)),
+ "xmlSecMSCngX509StoreAdoptKeyStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return -1;
+ }
+
+ return 0 ;
+}
+
+int
+MSCryptoAppliedKeysMngrAdoptTrustedStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE trustedStore
+)
+{
+ xmlSecKeyDataStorePtr x509Store ;
+
+ xmlSecAssert2(mngr != nullptr, -1) ;
+ xmlSecAssert2(trustedStore != nullptr, -1) ;
+
+ x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId);
+ if (x509Store == nullptr)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+ return -1 ;
+ }
+
+ if (xmlSecMSCngX509StoreAdoptTrustedStore(x509Store, trustedStore) < 0)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)),
+ "xmlSecMSCngX509StoreAdoptKeyStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return -1;
+ }
+
+ return 0 ;
+}
+
+int
+MSCryptoAppliedKeysMngrAdoptUntrustedStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE untrustedStore
+)
+{
+ xmlSecKeyDataStorePtr x509Store ;
+
+ xmlSecAssert2(mngr != nullptr, -1) ;
+ xmlSecAssert2(untrustedStore != nullptr, -1) ;
+
+ x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId);
+ if (x509Store == nullptr)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ nullptr,
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE) ;
+ return -1 ;
+ }
+
+ if (xmlSecMSCngX509StoreAdoptUntrustedStore(x509Store, untrustedStore) < 0)
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)),
+ "xmlSecMSCngX509StoreAdoptKeyStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return -1;
+ }
+
+ return 0 ;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx b/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx
new file mode 100644
index 0000000000..e5942ba2af
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <wincrypt.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/transforms.h>
+
+namespace xmlsecurity
+{
+
+xmlSecKeysMngrPtr MSCryptoAppliedKeysMngrCreate();
+
+int
+MSCryptoAppliedKeysMngrAdoptKeyStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE keyStore
+) ;
+
+int
+MSCryptoAppliedKeysMngrAdoptTrustedStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE trustedStore
+) ;
+
+int
+MSCryptoAppliedKeysMngrAdoptUntrustedStore(
+ xmlSecKeysMngrPtr mngr,
+ HCERTSTORE untrustedStore
+) ;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/oid.hxx b/xmlsecurity/source/xmlsec/mscrypt/oid.hxx
new file mode 100644
index 0000000000..ce573d8827
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/oid.hxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/macros.h>
+
+typedef struct {
+ char const *oid;
+ char const *desc;
+} OIDItem;
+
+OIDItem OIDs[] = {
+ {"1.2.840.113549", "RSA Data Security Inc."},
+ {"1.2.840.113549.1", "PKCS"},
+ {"1.2.840.113549.2", "RSA digest algorithm"},
+ {"1.2.840.113549.3", "RSA cipher algorithm"},
+ {"1.2.840.113549.1.1", "PKCS #1"},
+ {"1.2.840.113549.1.2", "Unknown"},
+ {"1.2.840.113549.1.3", "Unknown"},
+ {"1.2.840.113549.1.4", "Unknown"},
+ {"1.2.840.113549.1.5", "PKCS #5"},
+ {"1.2.840.113549.1.6", "Unknown"},
+ {"1.2.840.113549.1.7", "PKCS #7"},
+ {"1.2.840.113549.1.8", "Unknown"},
+ {"1.2.840.113549.1.9", "PKCS #9"},
+ {"1.2.840.113549.1.10", "Unknown"},
+ {"1.2.840.113549.1.12", "PKCS #12"},
+ {"1.2.840.113549.1.1.2", "PKCS #1 MD2 With RSA Encryption"},
+ {"1.2.840.113549.1.1.3", "PKCS #1 MD4 With RSA Encryption"},
+ {"1.2.840.113549.1.1.4", "PKCS #1 MD5 With RSA Encryption"},
+ {"1.2.840.113549.1.1.1", "PKCS #1 RSA Encryption"},
+ {"1.2.840.113549.1.1.2", "PKCS #1 MD2 With RSA Encryption"},
+ {"1.2.840.113549.1.1.3", "PKCS #1 MD4 With RSA Encryption"},
+ {"1.2.840.113549.1.1.4", "PKCS #1 MD5 With RSA Encryption"},
+ {"1.2.840.113549.1.1.5", "PKCS #1 SHA-1 With RSA Encryption"},
+ {"1.2.840.113549.1.1.5", "PKCS #1 SHA-1 With RSA Encryption"},
+ {"1.2.840.113549.1.3.1", "Unknown"},
+ {"1.2.840.113549.1.7.1", "PKCS #7 Data"},
+ {"1.2.840.113549.1.7.2", "PKCS #7 Signed Data"},
+ {"1.2.840.113549.1.7.3", "PKCS #7 Enveloped Data"},
+ {"1.2.840.113549.1.7.4", "PKCS #7 Signed and Enveloped Data"},
+ {"1.2.840.113549.1.7.5", "PKCS #7 Digested Data"},
+ {"1.2.840.113549.1.7.6", "PKCS #7 Encrypted Data"},
+ {"1.2.840.113549.1.9.1", "PKCS #9 Email Address"},
+ {"1.2.840.113549.1.9.2", "PKCS #9 Unstructured Name"},
+ {"1.2.840.113549.1.9.3", "PKCS #9 Content Type"},
+ {"1.2.840.113549.1.9.4", "PKCS #9 Message Digest"},
+ {"1.2.840.113549.1.9.5", "PKCS #9 Signing Time"},
+ {"1.2.840.113549.1.9.6", "PKCS #9 Counter Signature"},
+ {"1.2.840.113549.1.9.7", "PKCS #9 Challenge Password"},
+ {"1.2.840.113549.1.9.8", "PKCS #9 Unstructured Address"},
+ {"1.2.840.113549.1.9.9", "PKCS #9 Extended Certificate Attributes"},
+ {"1.2.840.113549.1.9.15", "PKCS #9 S/MIME Capabilities"},
+ {"1.2.840.113549.1.9.15.1", "Unknown"},
+ {"1.2.840.113549.3.2", "RC2-CBC"},
+ {"1.2.840.113549.3.4", "RC4"},
+ {"1.2.840.113549.3.7", "DES-EDE3-CBC"},
+ {"1.2.840.113549.3.9", "RC5-CBCPad"},
+ {"1.2.840.10046", "ANSI X9.42"},
+ {"1.2.840.10046.2.1", "Diffie-Hellman Public Key Algorithm"},
+ {"1.2.840.10040", "ANSI X9.57"},
+ {"1.2.840.10040.4.1", "ANSI X9.57 DSA Signature"},
+ {"1.2.840.10040.4.3", "ANSI X9.57 Algorithm DSA Signature with SHA-1 Digest"},
+ {"2.5", "Directory"},
+ {"2.5.8", "X.500-defined algorithms"},
+ {"2.5.8.1", "X.500-defined encryption algorithms"},
+ {"2.5.8.2", "Unknown"},
+ {"2.5.8.3", "Unknown"},
+ {"2.5.8.1.1", "RSA Encryption Algorithm"},
+ {"1.3.14", "Open Systems Implementors Workshop"},
+ {"1.3.14.3.2", "OIW SECSIG Algorithm"},
+ {"1.3.14.3.2.2", "Unknown"},
+ {"1.3.14.3.2.3", "Unknown"},
+ {"1.3.14.3.2.4", "Unknown"},
+ {"1.3.14.3.2.6", "DES-ECB"},
+ {"1.3.14.3.2.7", "DES-CBC"},
+ {"1.3.14.3.2.8", "DES-OFB"},
+ {"1.3.14.3.2.9", "DES-CFB"},
+ {"1.3.14.3.2.10", "DES-MAC"},
+ {"1.3.14.3.2.11", "Unknown"},
+ {"1.3.14.3.2.12", "Unknown"},
+ {"1.3.14.3.2.13", "Unknown"},
+ {"1.3.14.3.2.14", "Unknown"},
+ {"1.3.14.3.2.15", "ISO SHA with RSA Signature"},
+ {"1.3.14.3.2.16", "Unknown"},
+ {"1.3.14.3.2.17", "DES-EDE"},
+ {"1.3.14.3.2.18", "Unknown"},
+ {"1.3.14.3.2.19", "Unknown"},
+ {"1.3.14.3.2.20", "Unknown"},
+ {"1.3.14.3.2.21", "Unknown"},
+ {"1.3.14.3.2.22", "Unknown"},
+ {"1.3.14.3.2.23", "Unknown"},
+ {"1.3.14.3.2.24", "Unknown"},
+ {"1.3.14.3.2.25", "Unknown"},
+ {"1.3.14.3.2.26", "SHA-1"},
+ {"1.3.14.3.2.27", "Forgezza DSA Signature with SHA-1 Digest"},
+ {"1.3.14.3.2.28", "Unknown"},
+ {"1.3.14.3.2.29", "Unknown"},
+ {"1.3.14.7.2", "Unknown"},
+ {"1.3.14.7.2.1", "Unknown"},
+ {"1.3.14.7.2.2", "Unknown"},
+ {"1.3.14.7.2.3", "Unknown"},
+ {"1.3.14.7.2.2.1", "Unknown"},
+ {"1.3.14.7.2.3.1", "Unknown"},
+ {"2.16.840.1.101.2.1", "US DOD Infosec"},
+ {"2.16.840.1.101.2.1.1.1", "Unknown"},
+ {"2.16.840.1.101.2.1.1.2", "MISSI DSS Algorithm (Old)"},
+ {"2.16.840.1.101.2.1.1.3", "Unknown"},
+ {"2.16.840.1.101.2.1.1.4", "Skipjack CBC64"},
+ {"2.16.840.1.101.2.1.1.5", "Unknown"},
+ {"2.16.840.1.101.2.1.1.6", "Unknown"},
+ {"2.16.840.1.101.2.1.1.7", "Unknown"},
+ {"2.16.840.1.101.2.1.1.8", "Unknown"},
+ {"2.16.840.1.101.2.1.1.9", "Unknown"},
+ {"2.16.840.1.101.2.1.1.10", "MISSI KEA Algorithm"},
+ {"2.16.840.1.101.2.1.1.11", "Unknown"},
+ {"2.16.840.1.101.2.1.1.12", "MISSI KEA and DSS Algorithm (Old)"},
+ {"2.16.840.1.101.2.1.1.13", "Unknown"},
+ {"2.16.840.1.101.2.1.1.14", "Unknown"},
+ {"2.16.840.1.101.2.1.1.15", "Unknown"},
+ {"2.16.840.1.101.2.1.1.16", "Unknown"},
+ {"2.16.840.1.101.2.1.1.17", "Unknown"},
+ {"2.16.840.1.101.2.1.1.18", "Unknown"},
+ {"2.16.840.1.101.2.1.1.19", "MISSI DSS Algorithm"},
+ {"2.16.840.1.101.2.1.1.20", "MISSI KEA and DSS Algorithm"},
+ {"2.16.840.1.101.2.1.1.21", "Unknown"},
+ {"1.2.643.2.2.35.0", "GOST_R_34.10-2001_Test"},
+ {"1.2.643.2.2.35.1", "GOST_R_34.10-2001_Sign_DH_PRO"},
+ {"1.2.643.2.2.35.2", "GOST_R_34.10-2001_Sign_DH_CARD"},
+ {"1.2.643.2.2.35.3", "GOST_R_34.10-2001_Sign_DH"},
+ {"1.2.643.2.2.36.0", "GOST_R_34.10-2001_Sign_DH_PRO"}
+};
+
+const int nOID = SAL_N_ELEMENTS(OIDs);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx
new file mode 100644
index 0000000000..6ded5fa0cb
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <rtl/uuid.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/security/ExtAltNameType.hpp>
+#include <com/sun/star/security/CertAltNameEntry.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <comphelper/sequence.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#include "sanextension_mscryptimpl.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::security ;
+
+using ::com::sun::star::security::XCertificateExtension ;
+
+
+SanExtensionImpl::SanExtensionImpl() :
+ m_critical( false )
+{
+}
+
+SanExtensionImpl::~SanExtensionImpl() {
+}
+
+
+//Methods from XCertificateExtension
+sal_Bool SAL_CALL SanExtensionImpl::isCritical() {
+ return m_critical ;
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL SanExtensionImpl::getExtensionId() {
+ return m_xExtnId ;
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL SanExtensionImpl::getExtensionValue() {
+ return m_xExtnValue ;
+}
+
+//Methods from XSanExtension
+css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL SanExtensionImpl::getAlternativeNames(){
+
+ if (!m_Entries.hasElements())
+ {
+ CERT_ALT_NAME_INFO *subjectName;
+ DWORD size;
+ CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, reinterpret_cast<unsigned char*>(m_xExtnValue.getArray()), m_xExtnValue.getLength(), CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, nullptr,&subjectName, &size);
+
+ auto arrCertAltNameEntry = std::make_unique<CertAltNameEntry[]>(subjectName->cAltEntry);
+
+ for (unsigned int i = 0; i < static_cast<unsigned int>(subjectName->cAltEntry); i++){
+ PCERT_ALT_NAME_ENTRY pEntry = &subjectName->rgAltEntry[i];
+
+ switch(pEntry->dwAltNameChoice) {
+ case CERT_ALT_NAME_OTHER_NAME :
+ {
+ arrCertAltNameEntry[i].Type = ExtAltNameType_OTHER_NAME;
+ PCERT_OTHER_NAME pOtherName = pEntry->pOtherName;
+
+ css::beans::NamedValue otherNameProp;
+ otherNameProp.Name = OUString::createFromAscii(pOtherName->pszObjId);
+
+ Sequence< sal_Int8 > otherName( comphelper::arrayToSequence<sal_Int8>(
+ pOtherName->Value.pbData, pOtherName->Value.cbData) );
+ otherNameProp.Value <<= otherName;
+
+ arrCertAltNameEntry[i].Value <<= otherNameProp;
+ break;
+ }
+ case CERT_ALT_NAME_RFC822_NAME :
+ arrCertAltNameEntry[i].Type = ExtAltNameType_RFC822_NAME;
+ arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszRfc822Name));
+ break;
+ case CERT_ALT_NAME_DNS_NAME :
+ arrCertAltNameEntry[i].Type = ExtAltNameType_DNS_NAME;
+ arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszDNSName));
+ break;
+ case CERT_ALT_NAME_DIRECTORY_NAME :
+ {
+ arrCertAltNameEntry[i].Type = ExtAltNameType_DIRECTORY_NAME;
+ break;
+ }
+ case CERT_ALT_NAME_URL :
+ arrCertAltNameEntry[i].Type = ExtAltNameType_URL;
+ arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszURL));
+ break;
+ case CERT_ALT_NAME_IP_ADDRESS :
+ {
+ arrCertAltNameEntry[i].Type = ExtAltNameType_IP_ADDRESS;
+
+ Sequence< sal_Int8 > ipAddress( comphelper::arrayToSequence<sal_Int8>(
+ pEntry->IPAddress.pbData, pEntry->IPAddress.cbData) );
+ arrCertAltNameEntry[i].Value <<= ipAddress;
+ break;
+ }
+ case CERT_ALT_NAME_REGISTERED_ID :
+ arrCertAltNameEntry[i].Type = ExtAltNameType_REGISTERED_ID;
+ arrCertAltNameEntry[i].Value <<= OUString::createFromAscii(pEntry->pszRegisteredID);
+ break;
+ }
+ }
+ m_Entries = ::comphelper::arrayToSequence< css::security::CertAltNameEntry >(arrCertAltNameEntry.get(), subjectName->cAltEntry);
+ }
+
+ return m_Entries;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx
new file mode 100644
index 0000000000..6c65c84f86
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <Windows.h>
+#include <WinCrypt.h>
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/SecurityException.hpp>
+#include <com/sun/star/security/XCertificateExtension.hpp>
+#include <com/sun/star/security/XSanExtension.hpp>
+#include <com/sun/star/security/CertAltNameEntry.hpp>
+
+class SanExtensionImpl : public ::cppu::WeakImplHelper<
+ css::security::XSanExtension >
+{
+ private:
+ bool m_critical ;
+ css::uno::Sequence< sal_Int8 > m_xExtnId ;
+ css::uno::Sequence< sal_Int8 > m_xExtnValue ;
+
+ css::uno::Sequence< css::security::CertAltNameEntry > m_Entries;
+
+ public:
+ SanExtensionImpl() ;
+ virtual ~SanExtensionImpl() override;
+
+ //Methods from XCertificateExtension
+ virtual sal_Bool SAL_CALL isCritical() override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionId() override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionValue() override;
+
+ //Methods from XSanExtension
+
+ virtual css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL getAlternativeNames() override;
+
+ //Helper method
+ void setCertExtn( unsigned char* value, unsigned int vlen, unsigned char* id, unsigned int idlen, bool critical ) ;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
new file mode 100644
index 0000000000..cd3d40eb14
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx
@@ -0,0 +1,1110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <string.h>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <Windows.h>
+#include <WinCrypt.h>
+#include <sal/macros.h>
+#include <osl/thread.h>
+#include "securityenvironment_mscryptimpl.hxx"
+
+#include "x509certificate_mscryptimpl.hxx"
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <xmlsec-wrapper.h>
+#include "akmngr.hxx"
+
+#include <biginteger.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <sal/log.hxx>
+#include <rtl/locale.h>
+#include <rtl/ref.hxx>
+#include <osl/nlsupport.h>
+#include <osl/process.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <svl/cryptosign.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
+using ::com::sun::star::security::XCertificate ;
+
+static rtl::Reference<X509Certificate_MSCryptImpl> MswcryCertContextToXCert( PCCERT_CONTEXT cert ) ;
+
+namespace {
+
+struct CertErrorToString{
+ DWORD error;
+ char const * name;
+};
+
+}
+
+CertErrorToString const arErrStrings[] =
+{
+ { 0x00000000, "CERT_TRUST_NO_ERROR"},
+ { 0x00000001, "CERT_TRUST_IS_NOT_TIME_VALID"},
+ { 0x00000002, "CERT_TRUST_IS_NOT_TIME_NESTED"},
+ { 0x00000004, "CERT_TRUST_IS_REVOKED" },
+ { 0x00000008, "CERT_TRUST_IS_NOT_SIGNATURE_VALID" },
+ { 0x00000010, "CERT_TRUST_IS_NOT_SIGNATURE_VALID"},
+ { 0x00000020, "CERT_TRUST_IS_UNTRUSTED_ROOT"},
+ { 0x00000040, "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"},
+ { 0x00000080, "CERT_TRUST_IS_CYCLIC"},
+ { 0x00000100, "CERT_TRUST_INVALID_EXTENSION"},
+ { 0x00000200, "CERT_TRUST_INVALID_POLICY_CONSTRAINTS"},
+ { 0x00000400, "CERT_TRUST_INVALID_BASIC_CONSTRAINTS"},
+ { 0x00000800, "CERT_TRUST_INVALID_NAME_CONSTRAINTS"},
+ { 0x00001000, "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT"},
+ { 0x00002000, "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT"},
+ { 0x00004000, "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT"},
+ { 0x00008000, "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT"},
+ { 0x01000000, "CERT_TRUST_IS_OFFLINE_REVOCATION"},
+ { 0x02000000, "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY"},
+ { 0x04000000, "CERT_TRUST_IS_EXPLICIT_DISTRUST"},
+ { 0x08000000, "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT"},
+ //Chain errors
+ { 0x00010000, "CERT_TRUST_IS_PARTIAL_CHAIN"},
+ { 0x00020000, "CERT_TRUST_CTL_IS_NOT_TIME_VALID"},
+ { 0x00040000, "CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID"},
+ { 0x00080000, "CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE"}
+};
+
+static void traceTrustStatus(DWORD err)
+{
+ if (err == 0)
+ SAL_INFO("xmlsecurity.xmlsec", " " << arErrStrings[0].name);
+ for (auto const & arErrStringIter : arErrStrings)
+ {
+ if (arErrStringIter.error & err)
+ SAL_INFO("xmlsecurity.xmlsec", " " << arErrStringIter.name);
+ }
+}
+
+SecurityEnvironment_MSCryptImpl::SecurityEnvironment_MSCryptImpl( const uno::Reference< uno::XComponentContext >& xContext ) : m_hProv( 0 ) , m_pszContainer( nullptr ) , m_hKeyStore( nullptr ), m_hCertStore( nullptr ), m_hMySystemStore(nullptr), m_hRootSystemStore(nullptr), m_hTrustSystemStore(nullptr), m_hCaSystemStore(nullptr), m_bEnableDefault( false ){
+
+ m_xServiceManager.set(xContext, uno::UNO_QUERY);
+}
+
+SecurityEnvironment_MSCryptImpl::~SecurityEnvironment_MSCryptImpl() {
+
+ if( m_hProv != 0 ) {
+ CryptReleaseContext( m_hProv, 0 ) ;
+ m_hProv = 0 ;
+ }
+
+ if( m_pszContainer != nullptr ) {
+ //TODO: Don't know whether or not it should be released now.
+ m_pszContainer = nullptr ;
+ }
+
+ if( m_hCertStore != nullptr ) {
+ CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ m_hCertStore = nullptr ;
+ }
+
+ if( m_hKeyStore != nullptr ) {
+ CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ m_hKeyStore = nullptr ;
+ }
+
+ //i120675, close the store handles
+ if( m_hMySystemStore != nullptr ) {
+ CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hMySystemStore = nullptr ;
+ }
+
+ if( m_hRootSystemStore != nullptr ) {
+ CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hRootSystemStore = nullptr ;
+ }
+
+ if( m_hTrustSystemStore != nullptr ) {
+ CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hTrustSystemStore = nullptr ;
+ }
+
+ if( m_hCaSystemStore != nullptr ) {
+ CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hCaSystemStore = nullptr ;
+ }
+}
+
+/* XServiceInfo */
+OUString SAL_CALL SecurityEnvironment_MSCryptImpl::getImplementationName() {
+ return "com.sun.star.xml.crypto.SecurityEnvironment";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL SecurityEnvironment_MSCryptImpl::supportsService( const OUString& serviceName) {
+ return cppu::supportsService(this, serviceName);
+}
+/* XServiceInfo */
+uno::Sequence< OUString > SAL_CALL SecurityEnvironment_MSCryptImpl::getSupportedServiceNames() {
+ return { "com.sun.star.xml.crypto.SecurityEnvironment" };
+}
+
+HCRYPTPROV SecurityEnvironment_MSCryptImpl::getCryptoProvider() {
+ return m_hProv ;
+}
+
+void SecurityEnvironment_MSCryptImpl::setCryptoProvider( HCRYPTPROV aProv ) {
+ if( m_hProv != 0 ) {
+ CryptReleaseContext( m_hProv, 0 ) ;
+ m_hProv = 0 ;
+ }
+
+ if( aProv != 0 ) {
+ m_hProv = aProv ;
+ }
+}
+
+LPCTSTR SecurityEnvironment_MSCryptImpl::getKeyContainer() {
+ return m_pszContainer ;
+}
+
+void SecurityEnvironment_MSCryptImpl::setKeyContainer( LPCTSTR aKeyContainer ) {
+ //TODO: Don't know whether or not it should be copied.
+ m_pszContainer = aKeyContainer ;
+}
+
+
+HCERTSTORE SecurityEnvironment_MSCryptImpl::getCryptoSlot() {
+ return m_hKeyStore ;
+}
+
+void SecurityEnvironment_MSCryptImpl::setCryptoSlot( HCERTSTORE aSlot) {
+ if( m_hKeyStore != nullptr ) {
+ CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ m_hKeyStore = nullptr ;
+ }
+
+ if( aSlot != nullptr ) {
+ m_hKeyStore = CertDuplicateStore( aSlot ) ;
+ }
+}
+
+HCERTSTORE SecurityEnvironment_MSCryptImpl::getCertDb() {
+ return m_hCertStore ;
+}
+
+void SecurityEnvironment_MSCryptImpl::setCertDb( HCERTSTORE aCertDb ) {
+ if( m_hCertStore != nullptr ) {
+ CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ m_hCertStore = nullptr ;
+ }
+
+ if( aCertDb != nullptr ) {
+ m_hCertStore = CertDuplicateStore( aCertDb ) ;
+ }
+}
+
+#ifdef SAL_LOG_INFO
+
+// Based on sample code from MSDN
+
+static OUString get_system_name(const void *pvSystemStore,
+ DWORD dwFlags)
+{
+ LPCWSTR ppwszSystemName;
+ if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
+ {
+ _CERT_SYSTEM_STORE_RELOCATE_PARA const * pRelocatePara;
+ pRelocatePara = static_cast<_CERT_SYSTEM_STORE_RELOCATE_PARA const *>(pvSystemStore);
+ ppwszSystemName = pRelocatePara->pwszSystemStore;
+ }
+ else
+ {
+ ppwszSystemName = static_cast<LPCWSTR>(pvSystemStore);
+ }
+ return OUString(o3tl::toU(ppwszSystemName));
+}
+
+extern "C" {
+
+static BOOL WINAPI cert_enum_physical_store_callback(const void *,
+ DWORD dwFlags,
+ LPCWSTR pwszStoreName,
+ PCERT_PHYSICAL_STORE_INFO,
+ void *,
+ void *)
+{
+ OUString name(o3tl::toU(pwszStoreName));
+ if (dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG)
+ name += " (implicitly created)";
+ SAL_INFO("xmlsecurity.xmlsec", " Physical store: " << name);
+
+ return TRUE;
+}
+
+static BOOL WINAPI cert_enum_system_store_callback(const void *pvSystemStore,
+ DWORD dwFlags,
+ PCERT_SYSTEM_STORE_INFO,
+ void *,
+ void *)
+{
+ SAL_INFO("xmlsecurity.xmlsec", "System store: " << get_system_name(pvSystemStore, dwFlags));
+
+ if (!CertEnumPhysicalStore(pvSystemStore,
+ dwFlags,
+ nullptr,
+ cert_enum_physical_store_callback))
+ {
+ DWORD dwErr = GetLastError();
+ if (!(ERROR_FILE_NOT_FOUND == dwErr ||
+ ERROR_NOT_SUPPORTED == dwErr))
+ {
+ SAL_WARN("xmlsecurity.xmlsec", "CertEnumPhysicalStore failed:" << WindowsErrorString(GetLastError()));
+ }
+ }
+ return TRUE;
+}
+
+}
+
+#endif
+
+//Methods from XSecurityEnvironment
+uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::getPersonalCertificates()
+{
+ sal_Int32 length ;
+ rtl::Reference<X509Certificate_MSCryptImpl> xcert ;
+ std::vector< rtl::Reference<X509Certificate_MSCryptImpl> > certsList ;
+ PCCERT_CONTEXT pCertContext = nullptr;
+
+ //firstly, we try to find private keys in given key store.
+ if( m_hKeyStore != nullptr ) {
+ pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
+ while (pCertContext)
+ {
+ xcert = MswcryCertContextToXCert( pCertContext ) ;
+ if( xcert.is() )
+ certsList.push_back( xcert ) ;
+ pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
+ }
+ }
+
+ //Thirdly, we try to find certificate from system default key store.
+ if( m_bEnableDefault ) {
+ HCERTSTORE hSystemKeyStore ;
+ DWORD dwKeySpec;
+ NCRYPT_KEY_HANDLE hCryptKey;
+
+#ifdef SAL_LOG_INFO
+ CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, nullptr, nullptr, cert_enum_system_store_callback);
+#endif
+
+ hSystemKeyStore = CertOpenSystemStoreW( 0, L"MY" ) ;
+ if( hSystemKeyStore != nullptr ) {
+ pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
+ while (pCertContext)
+ {
+ // for checking whether the certificate is a personal certificate or not.
+ DWORD dwFlags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
+ HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey;
+ if(!(CryptAcquireCertificatePrivateKey(pCertContext,
+ dwFlags,
+ nullptr,
+ phCryptProvOrNCryptKey,
+ &dwKeySpec,
+ nullptr)))
+ {
+ // Not Privatekey found. SKIP this one.
+ pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
+ continue;
+ }
+ // then TODO : Check the personal cert is valid or not.
+
+ xcert = MswcryCertContextToXCert( pCertContext ) ;
+ if( xcert.is() )
+ certsList.push_back( xcert ) ;
+ pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
+ }
+ }
+
+ CertCloseStore( hSystemKeyStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ }
+
+ length = certsList.size() ;
+ if( length != 0 ) {
+ int i = 0;
+ uno::Sequence< uno::Reference< XCertificate > > certSeq( length ) ;
+ auto pcertSeq = certSeq.getArray();
+
+ for( const auto& rXCert : certsList ) {
+ pcertSeq[i] = rXCert ;
+ ++i;
+ }
+
+ return certSeq ;
+ }
+
+ return uno::Sequence< uno::Reference< XCertificate > >() ;
+}
+
+
+uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const uno::Sequence< sal_Int8 >& serialNumber ) {
+ unsigned int i ;
+ rtl::Reference<X509Certificate_MSCryptImpl> xcert ;
+ PCCERT_CONTEXT pCertContext = nullptr ;
+ HCERTSTORE hCertStore = nullptr ;
+ CRYPT_INTEGER_BLOB cryptSerialNumber ;
+ CERT_INFO certInfo ;
+
+ // for correct encoding
+ rtl_Locale *pLocale = nullptr ;
+ osl_getProcessLocale( &pLocale ) ;
+
+ //Create cert info from issue and serial
+ LPCWSTR pszName = o3tl::toW( issuerName.getStr() );
+
+ if( ! ( CertStrToNameW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ pszName ,
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
+ nullptr ,
+ nullptr ,
+ &certInfo.Issuer.cbData, nullptr ) )
+ ) {
+ return nullptr ;
+ }
+
+ certInfo.Issuer.pbData = static_cast<BYTE*>(malloc( certInfo.Issuer.cbData ));
+ if(!certInfo.Issuer.pbData)
+ throw uno::RuntimeException() ;
+
+ if( ! ( CertStrToNameW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ pszName ,
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
+ nullptr ,
+ certInfo.Issuer.pbData ,
+ &certInfo.Issuer.cbData, nullptr ) )
+ ) {
+ free( certInfo.Issuer.pbData ) ;
+ return nullptr ;
+ }
+
+ //Get the SerialNumber
+ cryptSerialNumber.cbData = serialNumber.getLength() ;
+ cryptSerialNumber.pbData = static_cast<BYTE*>(malloc( cryptSerialNumber.cbData));
+ if (!cryptSerialNumber.pbData)
+ {
+ free( certInfo.Issuer.pbData ) ;
+ throw uno::RuntimeException() ;
+ }
+ for( i = 0; i < cryptSerialNumber.cbData; i ++ )
+ cryptSerialNumber.pbData[i] = serialNumber[ cryptSerialNumber.cbData - i - 1 ] ;
+
+ certInfo.SerialNumber.cbData = cryptSerialNumber.cbData ;
+ certInfo.SerialNumber.pbData = cryptSerialNumber.pbData ;
+
+ // Get the Cert from all store.
+ for( i = 0 ; i < 6 ; i ++ )
+ {
+ switch(i)
+ {
+ case 0:
+ if(m_hKeyStore == nullptr) continue ;
+ hCertStore = m_hKeyStore ;
+ break;
+ case 1:
+ if(m_hCertStore == nullptr) continue ;
+ hCertStore = m_hCertStore ;
+ break;
+ case 2:
+ hCertStore = CertOpenSystemStoreW( 0, L"MY" ) ;
+ if(hCertStore == nullptr || !m_bEnableDefault) continue ;
+ break;
+ case 3:
+ hCertStore = CertOpenSystemStoreW( 0, L"Root" ) ;
+ if(hCertStore == nullptr || !m_bEnableDefault) continue ;
+ break;
+ case 4:
+ hCertStore = CertOpenSystemStoreW( 0, L"Trust" ) ;
+ if(hCertStore == nullptr || !m_bEnableDefault) continue ;
+ break;
+ case 5:
+ hCertStore = CertOpenSystemStoreW( 0, L"CA" ) ;
+ if(hCertStore == nullptr || !m_bEnableDefault) continue ;
+ break;
+ default:
+ i=6;
+ continue;
+ }
+
+/*******************************************************************************
+ * This code reserved for remind us there are another way to find one cert by
+ * IssuerName&serialnumber. You can use the code to replaced the function
+ * CertFindCertificateInStore IF and ONLY IF you must find one special cert in
+ * certStore but can not be found by CertFindCertificateInStore , then , you
+ * should also change the same part in libxmlsec/.../src/mscrypto/x509vfy.c#875.
+ * By Chandler Peng(chandler.peng@sun.com)
+ *****/
+/*******************************************************************************
+ pCertContext = NULL ;
+ found = 0;
+ do{
+ // 1. enum the certs has same string in the issuer string.
+ pCertContext = CertEnumCertificatesInStore( hCertStore , pCertContext ) ;
+ if( pCertContext != NULL )
+ {
+ // 2. check the cert's issuer name .
+ char* issuer = NULL ;
+ DWORD cbIssuer = 0 ;
+
+ cbIssuer = CertNameToStr(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( pCertContext->pCertInfo->Issuer ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ NULL, 0
+ ) ;
+
+ if( cbIssuer == 0 ) continue ; // discard this cert;
+
+ issuer = (char *)malloc( cbIssuer ) ;
+ if( issuer == NULL ) // discard this cert;
+ {
+ free( cryptSerialNumber.pbData) ;
+ free( certInfo.Issuer.pbData ) ;
+ CertFreeCertificateContext( pCertContext ) ;
+ if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ throw RuntimeException() ;
+ }
+
+ cbIssuer = CertNameToStr(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( pCertContext->pCertInfo->Issuer ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ issuer, cbIssuer
+ ) ;
+
+ if( cbIssuer <= 0 )
+ {
+ free( issuer ) ;
+ continue ;// discard this cert;
+ }
+
+ if(strncmp(pszName , issuer , cbIssuer) != 0)
+ {
+ free( issuer ) ;
+ continue ;// discard this cert;
+ }
+ free( issuer ) ;
+
+ // 3. check the serial number.
+ if( memcmp( cryptSerialNumber.pbData , pCertContext->pCertInfo->SerialNumber.pbData , cryptSerialNumber.cbData ) != 0 )
+ {
+ continue ;// discard this cert;
+ }
+
+ // 4. confirm and break;
+ found = 1;
+ break ;
+ }
+
+ }while(pCertContext);
+
+ if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ if( found != 0 ) break; // Found the certificate.
+********************************************************************************/
+
+ pCertContext = CertFindCertificateInStore(
+ hCertStore,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_CERT,
+ &certInfo,
+ nullptr
+ ) ;
+
+ if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ if( pCertContext != nullptr ) break ; // Found the certificate.
+
+ }
+
+ free(cryptSerialNumber.pbData);
+ free(certInfo.Issuer.pbData);
+
+ if( pCertContext != nullptr ) {
+ xcert = MswcryCertContextToXCert(pCertContext);
+ CertFreeCertificateContext(pCertContext);
+ }
+
+ return xcert ;
+}
+
+uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const OUString& serialNumber ) {
+ uno::Sequence< sal_Int8 > serial = xmlsecurity::numericStringToBigInteger( serialNumber ) ;
+ return getCertificate( issuerName, serial ) ;
+}
+
+uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::buildCertificatePath( const uno::Reference< XCertificate >& begin ) {
+ PCCERT_CHAIN_CONTEXT pChainContext ;
+ PCCERT_CONTEXT pCertContext ;
+
+ CERT_ENHKEY_USAGE enhKeyUsage ;
+ CERT_USAGE_MATCH certUsage ;
+ CERT_CHAIN_PARA chainPara ;
+
+ enhKeyUsage.cUsageIdentifier = 0 ;
+ enhKeyUsage.rgpszUsageIdentifier = nullptr ;
+ certUsage.dwType = USAGE_MATCH_TYPE_AND ;
+ certUsage.Usage = enhKeyUsage ;
+ chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
+ chainPara.RequestedUsage = certUsage ;
+
+ const auto* xcert = dynamic_cast<X509Certificate_MSCryptImpl*>(begin.get());
+ if( xcert == nullptr ) {
+ throw uno::RuntimeException() ;
+ }
+
+ pCertContext = xcert->getMswcryCert() ;
+
+ pChainContext = nullptr ;
+
+ bool bChain = false;
+ if( pCertContext != nullptr )
+ {
+ HCERTSTORE hAdditionalStore = nullptr;
+ HCERTSTORE hCollectionStore = nullptr;
+ if (m_hCertStore && m_hKeyStore)
+ {
+ //Merge m_hCertStore and m_hKeyStore into one store.
+ hCollectionStore = CertOpenStore(
+ CERT_STORE_PROV_COLLECTION ,
+ 0 ,
+ 0 ,
+ 0 ,
+ nullptr
+ ) ;
+ if (hCollectionStore != nullptr)
+ {
+ CertAddStoreToCollection (
+ hCollectionStore ,
+ m_hCertStore ,
+ CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
+ 0) ;
+ CertAddStoreToCollection (
+ hCollectionStore ,
+ m_hKeyStore,
+ CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
+ 0) ;
+ hAdditionalStore = hCollectionStore;
+ }
+
+ }
+
+ //if the merge of both stores failed then we add only m_hCertStore
+ if (hAdditionalStore == nullptr && m_hCertStore)
+ hAdditionalStore = m_hCertStore;
+ else if (hAdditionalStore == nullptr && m_hKeyStore)
+ hAdditionalStore = m_hKeyStore;
+ else
+ hAdditionalStore = nullptr;
+
+ //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
+ bChain = CertGetCertificateChain(
+ nullptr ,
+ pCertContext ,
+ nullptr , //use current system time
+ hAdditionalStore,
+ &chainPara ,
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_TIMESTAMP_TIME ,
+ nullptr ,
+ &pChainContext);
+ if (!bChain)
+ pChainContext = nullptr;
+
+ //Close the additional store
+ CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ }
+
+ if(bChain && pChainContext != nullptr && pChainContext->cChain > 0 )
+ {
+ PCCERT_CONTEXT pCertInChain ;
+ PCERT_SIMPLE_CHAIN pCertChain ;
+ rtl::Reference<X509Certificate_MSCryptImpl> pCert ;
+
+ pCertChain = pChainContext->rgpChain[0] ;
+ if( pCertChain->cElement ) {
+ uno::Sequence< uno::Reference< XCertificate > > xCertChain( pCertChain->cElement ) ;
+ auto pxCertChain = xCertChain.getArray();
+
+ for( unsigned int i = 0 ; i < pCertChain->cElement ; i ++ ) {
+ if( pCertChain->rgpElement[i] )
+ pCertInChain = pCertChain->rgpElement[i]->pCertContext ;
+ else
+ pCertInChain = nullptr ;
+
+ if( pCertInChain != nullptr ) {
+ pCert = MswcryCertContextToXCert( pCertInChain ) ;
+ if( pCert.is() )
+ pxCertChain[i] = pCert ;
+ }
+ }
+
+ CertFreeCertificateChain( pChainContext ) ;
+ pChainContext = nullptr ;
+
+ return xCertChain ;
+ }
+ }
+ if (pChainContext)
+ CertFreeCertificateChain(pChainContext);
+
+ return uno::Sequence< uno::Reference < XCertificate > >();
+}
+
+uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromRaw( const uno::Sequence< sal_Int8 >& rawCertificate ) {
+ rtl::Reference<X509Certificate_MSCryptImpl> xcert ;
+
+ if( rawCertificate.getLength() > 0 ) {
+ xcert = new X509Certificate_MSCryptImpl() ;
+ xcert->setRawCert( rawCertificate ) ;
+ }
+
+ return xcert ;
+}
+
+uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromAscii( const OUString& asciiCertificate )
+{
+ OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;
+ xmlChar* chCert = xmlStrndup( reinterpret_cast<const xmlChar*>(oscert.getStr()), static_cast<int>(oscert.getLength()) ) ;
+ xmlSecSize certSize;
+ int nRet = xmlSecBase64Decode_ex( chCert, reinterpret_cast<xmlSecByte*>(chCert), xmlStrlen( chCert ), &certSize ) ;
+ if (nRet < 0 || certSize == 0)
+ {
+ xmlFree(chCert);
+ return nullptr;
+ }
+
+ uno::Sequence<sal_Int8> rawCert(comphelper::arrayToSequence<sal_Int8>(chCert, certSize));
+
+ xmlFree( chCert ) ;
+
+ return createCertificateFromRaw( rawCert ) ;
+}
+
+static HCERTSTORE getCertStoreForIntermediatCerts(
+ const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts)
+{
+ HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nullptr);
+ if (store == nullptr)
+ return nullptr;
+
+ for (int i = 0; i < seqCerts.getLength(); i++)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " << seqCerts[i]->getSubjectName());
+
+ uno::Sequence<sal_Int8> data = seqCerts[i]->getEncoded();
+ PCCERT_CONTEXT cert = CertCreateCertificateContext(
+ X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(&data[0]), data.getLength());
+ //Adding the certificate creates a copy and not just increases the ref count
+ //Therefore we free later the certificate that we now add
+ CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_ALWAYS, nullptr);
+ CertFreeCertificateContext(cert);
+ }
+ return store;
+}
+
+static bool CheckUnitTestStore(PCCERT_CHAIN_CONTEXT const pChainContext, DWORD ignoreFlags)
+{
+ bool ret = false;
+ static char const*const pVar = getenv("LIBO_TEST_CRYPTOAPI_PKCS7");
+ if (!pVar)
+ {
+ return ret;
+ }
+ if (pChainContext->cChain == 0)
+ {
+ return ret;
+ }
+ PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
+ // check if untrusted root is the only problem
+ if (pSimpleChain->TrustStatus.dwErrorStatus & ~(CERT_TRUST_IS_UNTRUSTED_ROOT | ignoreFlags))
+ {
+ return ret;
+ }
+
+ // leak this store, re-opening is a waste of time in tests
+ static HCERTSTORE const hExtra = CertOpenStore(
+ CERT_STORE_PROV_FILENAME_A,
+ PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+ 0,
+ CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
+ OString(OString::Concat(pVar) + "/test.p7b").getStr());
+ assert(hExtra != nullptr);
+ if (pSimpleChain->cElement < 1)
+ {
+ SAL_WARN("xmlsecurity.xmlsec", "unexpected empty chain");
+ return ret;
+ }
+ PCCERT_CONTEXT const pRoot(pSimpleChain->rgpElement[pSimpleChain->cElement-1]->pCertContext);
+ PCCERT_CONTEXT const pIssuerCert = CertFindCertificateInStore(
+ hExtra,
+ PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+ 0,
+ CERT_FIND_SUBJECT_NAME,
+ &pRoot->pCertInfo->Subject,
+ nullptr);
+ if (pIssuerCert)
+ {
+ // check that it signed itself
+ DWORD flags = CERT_STORE_SIGNATURE_FLAG;
+ bool result = CertVerifySubjectCertificateContext(pRoot, pIssuerCert, &flags);
+ if (result && flags == 0)
+ {
+ ret = true;
+ }
+ }
+ CertFreeCertificateContext(pIssuerCert);
+ return ret;
+}
+
+//We return only valid or invalid, as long as the API documentation expresses
+//explicitly that all validation steps are carried out even if one or several
+//errors occur. See also
+//http://wiki.openoffice.org/wiki/Certificate_Path_Validation#Validation_status
+sal_Int32 SecurityEnvironment_MSCryptImpl::verifyCertificate(
+ const uno::Reference< css::security::XCertificate >& aCert,
+ const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts)
+{
+ sal_Int32 validity = css::security::CertificateValidity::INVALID;
+ PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
+ PCCERT_CONTEXT pCertContext = nullptr;
+
+ SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName());
+
+ const auto* xcert = dynamic_cast<X509Certificate_MSCryptImpl*>(aCert.get());
+ if( xcert == nullptr ) {
+ throw uno::RuntimeException() ;
+ }
+
+ pCertContext = xcert->getMswcryCert() ;
+
+ CERT_ENHKEY_USAGE enhKeyUsage ;
+ CERT_USAGE_MATCH certUsage ;
+ CERT_CHAIN_PARA chainPara = {};
+
+ //Prepare parameter for CertGetCertificateChain
+ enhKeyUsage.cUsageIdentifier = 0 ;
+ enhKeyUsage.rgpszUsageIdentifier = nullptr ;
+ certUsage.dwType = USAGE_MATCH_TYPE_AND ;
+ certUsage.Usage = enhKeyUsage ;
+ chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
+ chainPara.RequestedUsage = certUsage ;
+
+
+ HCERTSTORE hCollectionStore = nullptr;
+ HCERTSTORE hIntermediateCertsStore = nullptr;
+ bool bChain = false;
+ if( pCertContext != nullptr )
+ {
+ hIntermediateCertsStore =
+ getCertStoreForIntermediatCerts(seqCerts);
+
+ //Merge m_hCertStore and m_hKeyStore and the store of the intermediate
+ //certificates into one store.
+ hCollectionStore = CertOpenStore(
+ CERT_STORE_PROV_COLLECTION ,
+ 0 ,
+ 0 ,
+ 0 ,
+ nullptr
+ ) ;
+ if (hCollectionStore != nullptr)
+ {
+ CertAddStoreToCollection (
+ hCollectionStore ,
+ m_hCertStore ,
+ CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
+ 0) ;
+ CertAddStoreToCollection (
+ hCollectionStore ,
+ m_hKeyStore,
+ CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
+ 0) ;
+ CertAddStoreToCollection (
+ hCollectionStore,
+ hIntermediateCertsStore,
+ CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
+ 0);
+
+ }
+
+ //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
+ //We do not check revocation of the root. In most cases there are none.
+ //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN
+ SAL_INFO("xmlsecurity.xmlsec", "Verifying cert using revocation information.");
+ bChain = CertGetCertificateChain(
+ nullptr ,
+ pCertContext ,
+ nullptr , //use current system time
+ hCollectionStore,
+ &chainPara ,
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
+ nullptr ,
+ &pChainContext);
+
+ if (bChain && pChainContext->cChain > 0)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Overall error status (all chains):");
+ traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus);
+ //highest quality chains come first
+ PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
+ SAL_INFO("xmlsecurity.xmlsec", "Error status of first chain:");
+ traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus);
+
+ //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate
+ //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed.
+ DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+ CERT_TRUST_IS_OFFLINE_REVOCATION;
+ DWORD otherErrorsMask = ~revocationFlags;
+ if (!(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask)
+ || CheckUnitTestStore(pChainContext, revocationFlags))
+
+ {
+ //No errors except maybe those caused by missing revocation information
+ //Check if there are errors
+ if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags)
+ {
+ //No revocation information. Because MSDN documentation is not
+ //clear about if all other tests are performed if an error occurs,
+ //we test again, without requiring revocation checking.
+ CertFreeCertificateChain(pChainContext);
+ pChainContext = nullptr;
+ SAL_INFO("xmlsecurity.xmlsec", "Checking again but without requiring revocation information.");
+ bChain = CertGetCertificateChain(
+ nullptr ,
+ pCertContext ,
+ nullptr , //use current system time
+ hCollectionStore,
+ &chainPara ,
+ 0,
+ nullptr ,
+ &pChainContext);
+ if (bChain
+ && pChainContext->cChain > 0
+ && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
+ validity = css::security::CertificateValidity::VALID;
+ }
+ else if (CheckUnitTestStore(pChainContext, 0))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "root certificate found in extra test store");
+ validity = css::security::CertificateValidity::VALID;
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
+ }
+ }
+ else
+ {
+ //valid and revocation information available
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
+ validity = css::security::CertificateValidity::VALID;
+ }
+ }
+ else
+ {
+ //invalid
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
+ validity = css::security::CertificateValidity::INVALID ;
+ }
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChain failed.");
+ }
+ }
+
+ if (pChainContext)
+ {
+ CertFreeCertificateChain(pChainContext);
+ pChainContext = nullptr;
+ }
+
+ //Close the additional store, do not destroy the contained certs
+ CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ //Close the temporary store containing the intermediate certificates and make
+ //sure all certificates are deleted.
+ CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG);
+
+ return validity ;
+}
+
+sal_Int32 SecurityEnvironment_MSCryptImpl::getCertificateCharacters( const css::uno::Reference< css::security::XCertificate >& aCert ) {
+ sal_Int32 characters ;
+ PCCERT_CONTEXT pCertContext ;
+
+ const auto* xcert = dynamic_cast<X509Certificate_MSCryptImpl*>(aCert.get());
+ if( xcert == nullptr ) {
+ throw uno::RuntimeException() ;
+ }
+
+ pCertContext = xcert->getMswcryCert() ;
+
+ characters = 0x00000000 ;
+
+ //Firstly, make sentence whether or not the cert is self-signed.
+ if( CertCompareCertificateName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pCertContext->pCertInfo->Subject), &(pCertContext->pCertInfo->Issuer) ) ) {
+ characters |= css::security::CertificateCharacters::SELF_SIGNED ;
+ } else {
+ characters &= ~ css::security::CertificateCharacters::SELF_SIGNED ;
+ }
+
+ //Secondly, make sentence whether or not the cert has a private key.
+ {
+ BOOL fCallerFreeProv ;
+ DWORD dwKeySpec ;
+ NCRYPT_KEY_HANDLE hKey = 0;
+ DWORD dwFlags = CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
+ HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hKey;
+ if( CryptAcquireCertificatePrivateKey( pCertContext ,
+ dwFlags,
+ nullptr ,
+ phCryptProvOrNCryptKey,
+ &dwKeySpec,
+ &fCallerFreeProv )
+ ) {
+ characters |= css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
+
+ if (hKey && fCallerFreeProv)
+ NCryptFreeObject(hKey);
+ } else {
+ characters &= ~ css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
+ }
+ }
+ return characters ;
+}
+
+void SecurityEnvironment_MSCryptImpl::enableDefaultCrypt( bool enable ) {
+ m_bEnableDefault = enable ;
+}
+
+bool SecurityEnvironment_MSCryptImpl::defaultEnabled() {
+ return m_bEnableDefault ;
+}
+
+static rtl::Reference<X509Certificate_MSCryptImpl> MswcryCertContextToXCert( PCCERT_CONTEXT cert )
+{
+ rtl::Reference<X509Certificate_MSCryptImpl> xcert ;
+
+ if( cert != nullptr ) {
+ xcert = new X509Certificate_MSCryptImpl() ;
+ xcert->setMswcryCert( cert ) ;
+ }
+
+ return xcert ;
+}
+
+OUString SecurityEnvironment_MSCryptImpl::getSecurityEnvironmentInformation()
+{
+ return "Microsoft Crypto API";
+}
+
+xmlSecKeysMngrPtr SecurityEnvironment_MSCryptImpl::createKeysManager() {
+
+ /*-
+ * The following lines is based on the of xmlsec-mscrypto crypto engine
+ */
+ xmlSecKeysMngrPtr pKeysMngr = xmlsecurity::MSCryptoAppliedKeysMngrCreate() ;
+ if( pKeysMngr == nullptr )
+ throw uno::RuntimeException() ;
+
+ /*-
+ * Adopt system default certificate store.
+ */
+ if( defaultEnabled() ) {
+ //Add system key store into the keys manager.
+ m_hMySystemStore = CertOpenSystemStoreW( 0, L"MY" ) ;
+ if( m_hMySystemStore != nullptr ) {
+ if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptKeyStore( pKeysMngr, m_hMySystemStore ) < 0 ) {
+ CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hMySystemStore = nullptr;
+ throw uno::RuntimeException() ;
+ }
+ m_hMySystemStore = nullptr;
+ }
+
+ //Add system root store into the keys manager.
+ m_hRootSystemStore = CertOpenSystemStoreW( 0, L"Root" ) ;
+ if( m_hRootSystemStore != nullptr ) {
+ if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptTrustedStore( pKeysMngr, m_hRootSystemStore ) < 0 ) {
+ CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hRootSystemStore = nullptr;
+ throw uno::RuntimeException() ;
+ }
+ m_hRootSystemStore = nullptr;
+ }
+
+ //Add system trusted store into the keys manager.
+ m_hTrustSystemStore = CertOpenSystemStoreW( 0, L"Trust" ) ;
+ if( m_hTrustSystemStore != nullptr ) {
+ if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hTrustSystemStore ) < 0 ) {
+ CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hTrustSystemStore = nullptr;
+ throw uno::RuntimeException() ;
+ }
+ m_hTrustSystemStore = nullptr;
+ }
+
+ //Add system CA store into the keys manager.
+ m_hCaSystemStore = CertOpenSystemStoreW( 0, L"CA" ) ;
+ if( m_hCaSystemStore != nullptr ) {
+ if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hCaSystemStore ) < 0 ) {
+ CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
+ m_hCaSystemStore = nullptr;
+ throw uno::RuntimeException() ;
+ }
+ m_hCaSystemStore = nullptr;
+ }
+ }
+
+ return pKeysMngr ;
+}
+void SecurityEnvironment_MSCryptImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) {
+ if( pKeysMngr != nullptr ) {
+ xmlSecKeysMngrDestroy( pKeysMngr ) ;
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_SecurityEnvironment_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new SecurityEnvironment_MSCryptImpl(pCtx));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx
new file mode 100644
index 0000000000..5867b2b462
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <wincrypt.h>
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+#include <com/sun/star/security/CertificateCharacters.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+
+#include <vector>
+#include <xmlsec-wrapper.h>
+
+#include <sal/types.h>
+
+
+class SecurityEnvironment_MSCryptImpl : public ::cppu::WeakImplHelper<
+ css::xml::crypto::XSecurityEnvironment ,
+ css::lang::XServiceInfo >
+{
+ private:
+ //crypto provider and key container
+ HCRYPTPROV m_hProv ;
+ LPCTSTR m_pszContainer ;
+
+ //Key store
+ HCERTSTORE m_hKeyStore ;
+
+ //Certificate store
+ HCERTSTORE m_hCertStore ;
+
+ // i120675, save the store handles
+ HCERTSTORE m_hMySystemStore;
+ HCERTSTORE m_hRootSystemStore;
+ HCERTSTORE m_hTrustSystemStore;
+ HCERTSTORE m_hCaSystemStore;
+
+ //Enable default system cryptography setting
+ bool m_bEnableDefault ;
+
+ //Service manager
+ css::uno::Reference< css::lang::XMultiServiceFactory > m_xServiceManager ;
+
+ public:
+ explicit SecurityEnvironment_MSCryptImpl( const css::uno::Reference< css::uno::XComponentContext >& xContext ) ;
+ virtual ~SecurityEnvironment_MSCryptImpl() override;
+
+ //Methods from XSecurityEnvironment
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getPersonalCertificates() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getAllCertificates() override
+ { return css::uno::Sequence< css::uno::Reference< css::security::XCertificate > >(); }
+
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL getCertificate(
+ const OUString& issuerName,
+ const css::uno::Sequence< sal_Int8 >& serialNumber ) override;
+
+ /// @throws css::uno::SecurityException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Reference< css::security::XCertificate > getCertificate(
+ const OUString& issuerName,
+ const OUString& serialNumber ) ;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL buildCertificatePath(
+ const css::uno::Reference< css::security::XCertificate >& beginCert ) override;
+
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromRaw(
+ const css::uno::Sequence< sal_Int8 >& rawCertificate ) override;
+
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromAscii(
+ const OUString& asciiCertificate ) override;
+
+ virtual ::sal_Int32 SAL_CALL verifyCertificate(
+ const css::uno::Reference< css::security::XCertificate >& xCert,
+ const css::uno::Sequence< css::uno::Reference<
+ css::security::XCertificate > >& intermediateCertificates) override;
+
+ virtual ::sal_Int32 SAL_CALL getCertificateCharacters(
+ const css::uno::Reference< css::security::XCertificate >& xCert ) override;
+
+ virtual OUString SAL_CALL getSecurityEnvironmentInformation( ) override;
+
+
+ //Methods from XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(
+ const OUString& ServiceName
+ ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ HCRYPTPROV getCryptoProvider() ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void setCryptoProvider( HCRYPTPROV aProv ) ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ LPCTSTR getKeyContainer() ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void setKeyContainer( LPCTSTR aKeyContainer ) ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ HCERTSTORE getCryptoSlot() ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void setCryptoSlot( HCERTSTORE aKeyStore ) ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ HCERTSTORE getCertDb() ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void setCertDb( HCERTSTORE aCertDb ) ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void enableDefaultCrypt( bool enable ) ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ bool defaultEnabled() ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ xmlSecKeysMngrPtr createKeysManager() ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ static void destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) ;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx
new file mode 100644
index 0000000000..99381e5e25
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include "seinitializer_mscryptimpl.hxx"
+
+#include "securityenvironment_mscryptimpl.hxx"
+
+#include <xmlsec/mscng/app.h>
+#include <com/sun/star/xml/crypto/SecurityEnvironment.hpp>
+#include <com/sun/star/xml/crypto/XMLSecurityContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <svl/cryptosign.hxx>
+
+using namespace com::sun::star;
+namespace cssl = com::sun::star::lang;
+namespace cssxc = com::sun::star::xml::crypto;
+
+SEInitializer_MSCryptImpl::SEInitializer_MSCryptImpl(
+ const uno::Reference< uno::XComponentContext > &rxContext)
+ :mxContext( rxContext )
+{
+}
+
+SEInitializer_MSCryptImpl::~SEInitializer_MSCryptImpl()
+{
+}
+
+/* XSEInitializer */
+uno::Reference< cssxc::XXMLSecurityContext > SAL_CALL
+ SEInitializer_MSCryptImpl::createSecurityContext(
+ const OUString& sCertDB )
+{
+ const char* n_pCertStore ;
+ HCERTSTORE n_hStoreHandle ;
+ OString sCertDir;
+
+ //Initialize the crypto engine
+ if( sCertDB.getLength() > 0 )
+ {
+ sCertDir = OUStringToOString(sCertDB, RTL_TEXTENCODING_ASCII_US);
+ n_pCertStore = sCertDir.getStr();
+ n_hStoreHandle = CertOpenSystemStoreW( 0, o3tl::toW(sCertDB.getStr())) ;
+ if( n_hStoreHandle == nullptr )
+ {
+ return nullptr;
+ }
+ }
+ else
+ {
+ n_pCertStore = nullptr ;
+ n_hStoreHandle = nullptr ;
+ }
+
+ xmlSecMSCngAppInit(n_pCertStore);
+
+ try {
+ /* Build Security Environment */
+ uno::Reference< cssxc::XSecurityEnvironment > xSecEnv = cssxc::SecurityEnvironment::create( mxContext );
+
+ /* Setup key slot and certDb */
+ SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(xSecEnv.get());
+ if( pSecEnv == nullptr )
+ {
+ if( n_hStoreHandle != nullptr )
+ {
+ CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ }
+
+ xmlSecMSCngAppShutdown();
+ return nullptr;
+ }
+
+ if( n_hStoreHandle != nullptr )
+ {
+ pSecEnv->setCryptoSlot( n_hStoreHandle ) ;
+ pSecEnv->setCertDb( n_hStoreHandle ) ;
+ }
+ else
+ {
+ pSecEnv->enableDefaultCrypt( true ) ;
+ }
+
+ /* Build XML Security Context */
+ uno::Reference< cssxc::XXMLSecurityContext > xSecCtx = cssxc::XMLSecurityContext::create( mxContext );
+
+ xSecCtx->setDefaultSecurityEnvironmentIndex(xSecCtx->addSecurityEnvironment( xSecEnv )) ;
+ return xSecCtx;
+ }
+ catch( uno::Exception& )
+ {
+ if( n_hStoreHandle != nullptr )
+ {
+ CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ }
+
+ xmlSecMSCngAppShutdown();
+ return nullptr;
+ }
+}
+
+void SAL_CALL SEInitializer_MSCryptImpl::freeSecurityContext( const uno::Reference< cssxc::XXMLSecurityContext >&)
+{
+ /*
+ uno::Reference< cssxc::XSecurityEnvironment > xSecEnv
+ = securityContext->getSecurityEnvironment();
+
+ if( xSecEnv.is() )
+ {
+ uno::Reference< cssl::XUnoTunnel > xEnvTunnel( xSecEnv , uno::UNO_QUERY ) ;
+ if (auto pSecEnv = comphelper::getFromUnoTunnel<SecurityEnvironment_MSCryptImpl>(xEnvTunnel))
+ {
+ HCERTSTORE n_hStoreHandle = pSecEnv->getCryptoSlot();
+
+ if( n_hStoreHandle != NULL )
+ {
+ CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ;
+ pSecEnv->setCryptoSlot( NULL ) ;
+ pSecEnv->setCertDb( NULL ) ;
+ }
+
+ xmlSecMSCryptoAppShutdown() ;
+ }
+ }
+ */
+
+ xmlSecMSCngAppShutdown();
+}
+
+/* XServiceInfo */
+OUString SAL_CALL SEInitializer_MSCryptImpl::getImplementationName()
+{
+ return "com.sun.star.xml.crypto.SEInitializer";
+}
+
+sal_Bool SAL_CALL SEInitializer_MSCryptImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL SEInitializer_MSCryptImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.xml.crypto.SEInitializer" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_SEInitializer_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new SEInitializer_MSCryptImpl(pCtx));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx
new file mode 100644
index 0000000000..182ba5e5af
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
+#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <libxml/tree.h>
+
+class SEInitializer_MSCryptImpl : public cppu::WeakImplHelper
+<
+ css::xml::crypto::XSEInitializer,
+ css::lang::XServiceInfo
+>
+/****** SEInitializer_MSCryptImpl.hxx/CLASS SEInitializer_MSCryptImpl ***********
+ *
+ * NAME
+ * SEInitializer_MSCryptImpl -- Class to initialize a Security Context
+ * instance
+ *
+ * FUNCTION
+ * Use this class to initialize a XmlSec based Security Context
+ * instance. After this instance is used up, use this class to free this
+ * instance.
+ ******************************************************************************/
+{
+private:
+ css::uno::Reference< css::uno::XComponentContext > mxContext;
+
+public:
+ explicit SEInitializer_MSCryptImpl(const css::uno::Reference< css::uno::XComponentContext > &rxContext);
+ virtual ~SEInitializer_MSCryptImpl() override;
+
+ /* XSEInitializer */
+ virtual css::uno::Reference< css::xml::crypto::XXMLSecurityContext >
+ SAL_CALL createSecurityContext( const OUString& certDB ) override;
+
+ virtual void SAL_CALL freeSecurityContext( const css::uno::Reference<
+ css::xml::crypto::XXMLSecurityContext >& securityContext ) override;
+
+ /* XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
new file mode 100644
index 0000000000..bd4ef701e6
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx
@@ -0,0 +1,783 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include "x509certificate_mscryptimpl.hxx"
+#include <certificateextension_xmlsecimpl.hxx>
+#include <biginteger.hxx>
+#include "sanextension_mscryptimpl.hxx"
+
+#include "oid.hxx"
+
+#include <rtl/locale.h>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/nlsupport.h>
+#include <osl/process.h>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <memory>
+#include <string_view>
+#include <utility>
+#include <vector>
+#include <tools/time.hxx>
+#include <svl/sigstruct.hxx>
+
+using namespace com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::security ;
+
+using ::com::sun::star::security::XCertificate ;
+using ::com::sun::star::util::DateTime ;
+
+/*Returns the index within rRawString where sTypeName starts and where it ends.
+ The starting index is pair.first. The ending index in pair.second points
+ one char after the last character of the type.
+ sTypeName can be
+ "S" or "CN" (without ""). Do not use spaces at the beginning of the type name.
+ If the type name is not found then pair.first and pair.second are -1.
+*/
+static std::pair< sal_Int32, sal_Int32 >
+findTypeInDN(const OUString& rRawString, std::u16string_view sTypeName)
+{
+ std::pair< sal_Int32, sal_Int32 > retVal;
+ bool bInEscape = false;
+ bool bInValue = false;
+ bool bFound = false;
+ sal_Int32 nTypeNameStart = 0;
+ sal_Int32 length = rRawString.getLength();
+
+ for (sal_Int32 i = 0; i < length; i++)
+ {
+ sal_Unicode c = rRawString[i];
+
+ if (c == '=')
+ {
+ if (! bInValue)
+ {
+ std::u16string_view sType = rRawString.subView(nTypeNameStart, i - nTypeNameStart);
+ sType = o3tl::trim(sType);
+ if (o3tl::equalsIgnoreAsciiCase(sType, sTypeName))
+ {
+ bFound = true;
+ break;
+ }
+ }
+ }
+ else if (c == '"')
+ {
+ if (!bInEscape)
+ {
+ //If this is the quote is the first of the couple which enclose the
+ //whole value, because the value contains special characters
+ //then we just drop it. That is, this character must be followed by
+ //a character which is not '"'.
+ if ( i + 1 < length && rRawString[i+1] == '"')
+ bInEscape = true;
+ else
+ bInValue = !bInValue; //value is enclosed in " "
+ }
+ else
+ {
+ //This quote is escaped by a preceding quote and therefore is
+ //part of the value
+ bInEscape = false;
+ }
+ }
+ else if (c == ',' || c == '+')
+ {
+ //The comma separate the attribute value pairs.
+ //If the comma is not part of a value (the value would then be enclosed in '"'),
+ //then we have reached the end of the value
+ if (!bInValue)
+ {
+ //The next char is the start of the new type
+ nTypeNameStart = i + 1;
+ }
+ }
+ }
+
+ //Found the Type Name, but there can still be spaces after the last comma
+ //and the beginning of the type.
+ if (bFound)
+ {
+ while (true)
+ {
+ sal_Unicode c = rRawString[nTypeNameStart];
+ if (c != ' ' && c != '\t')
+ //found
+ break;
+ nTypeNameStart ++;
+ }
+ // search end (one after last letter)
+ sal_Int32 nTypeNameEnd = nTypeNameStart;
+ nTypeNameEnd++;
+ while (true)
+ {
+ sal_Unicode c = rRawString[nTypeNameEnd];
+ if (c == ' ' || c == '\t' || c == '=')
+ break;
+ nTypeNameEnd++;
+ }
+ retVal = std::make_pair(nTypeNameStart, nTypeNameEnd);
+ }
+ else
+ {
+ retVal = std::make_pair(-1, -1);
+ }
+ return retVal;
+}
+
+
+/*
+ MS Crypto uses the 'S' tag (equal to the 'ST' tag in NSS), but the NSS can't recognise
+ it, so the 'S' tag should be changed to 'ST' tag. However I am not sure if this is necessary
+ anymore, because we provide always the signers certificate when signing. So libmlsec can find
+ the private key based on the provided certificate (X509Certificate element) and does not need
+ the issuer name (X509IssuerName element). The issuer name in the xml signature has also no
+ effect for the signature nor the certificate validation.
+ In many RFCs, for example 4519, on speaks of 'ST'. However, the certificate does not contain
+ strings for type names. Instead it uses OIDs.
+ */
+
+static OUString replaceTagSWithTagST(OUString const & oldDN)
+{
+ std::pair<sal_Int32, sal_Int32 > pairIndex = findTypeInDN(oldDN, u"S");
+
+ if (pairIndex.first != -1)
+ {
+ return OUString::Concat(oldDN.subView(0, pairIndex.first))+"ST"
+ +oldDN.subView(pairIndex.second);
+ }
+ return oldDN;
+}
+/* end */
+
+X509Certificate_MSCryptImpl::X509Certificate_MSCryptImpl() :
+ m_pCertContext( nullptr )
+{
+}
+
+X509Certificate_MSCryptImpl::~X509Certificate_MSCryptImpl() {
+ if( m_pCertContext != nullptr ) {
+ CertFreeCertificateContext( m_pCertContext ) ;
+ }
+}
+
+//Methods from XCertificate
+sal_Int16 SAL_CALL X509Certificate_MSCryptImpl::getVersion() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ return static_cast<char>(m_pCertContext->pCertInfo->dwVersion) ;
+ } else {
+ return -1 ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSerialNumber() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ Sequence< sal_Int8 > serial( m_pCertContext->pCertInfo->SerialNumber.cbData ) ;
+ auto serialRange = asNonConstRange(serial);
+ for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SerialNumber.cbData ; i ++ )
+ serialRange[i] = *( m_pCertContext->pCertInfo->SerialNumber.pbData + m_pCertContext->pCertInfo->SerialNumber.cbData - i - 1 ) ;
+
+ return serial ;
+ } else {
+ return Sequence< sal_Int8 >();
+ }
+}
+
+OUString SAL_CALL X509Certificate_MSCryptImpl::getIssuerName() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ DWORD cchIssuer = CertNameToStrW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( m_pCertContext->pCertInfo->Issuer ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ nullptr, 0
+ ) ;
+
+ // Here the cbIssuer count the last 0x00 , take care.
+ if( cchIssuer != 0 ) {
+ auto issuer = std::make_unique<wchar_t[]>(cchIssuer);
+
+ cchIssuer = CertNameToStrW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( m_pCertContext->pCertInfo->Issuer ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ issuer.get(), cchIssuer
+ ) ;
+
+ if( cchIssuer <= 0 ) {
+ throw RuntimeException() ;
+ }
+
+ if(issuer.get()[cchIssuer -1] == 0) cchIssuer--; //delimit the last 0x00;
+ OUString xIssuer(o3tl::toU(issuer.get()), cchIssuer) ;
+
+ return replaceTagSWithTagST(xIssuer);
+ } else {
+ return OUString() ;
+ }
+ } else {
+ return OUString() ;
+ }
+}
+
+OUString SAL_CALL X509Certificate_MSCryptImpl::getSubjectName()
+{
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
+ {
+ DWORD cchSubject = CertNameToStrW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( m_pCertContext->pCertInfo->Subject ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ nullptr, 0
+ ) ;
+
+ if( cchSubject != 0 )
+ {
+ auto subject = std::make_unique<wchar_t[]>(cchSubject);
+
+ cchSubject = CertNameToStrW(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
+ &( m_pCertContext->pCertInfo->Subject ),
+ CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
+ subject.get(), cchSubject
+ ) ;
+
+ if( cchSubject <= 0 ) {
+ throw RuntimeException() ;
+ }
+
+ OUString xSubject(o3tl::toU(subject.get()));
+
+ return replaceTagSWithTagST(xSubject);
+ } else
+ {
+ return OUString() ;
+ }
+ }
+ else
+ {
+ return OUString() ;
+ }
+}
+
+css::util::DateTime SAL_CALL X509Certificate_MSCryptImpl::getNotValidBefore() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ SYSTEMTIME explTime ;
+ DateTime dateTime ;
+ FILETIME localFileTime;
+
+ if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotBefore ), &localFileTime))
+ {
+ if( FileTimeToSystemTime( &localFileTime, &explTime ) ) {
+ //Convert the time to readable local time
+ dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ;
+ dateTime.Seconds = explTime.wSecond ;
+ dateTime.Minutes = explTime.wMinute ;
+ dateTime.Hours = explTime.wHour ;
+ dateTime.Day = explTime.wDay ;
+ dateTime.Month = explTime.wMonth ;
+ dateTime.Year = explTime.wYear ;
+ }
+ }
+
+ return dateTime ;
+ } else {
+ return DateTime() ;
+ }
+}
+
+css::util::DateTime SAL_CALL X509Certificate_MSCryptImpl::getNotValidAfter() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ SYSTEMTIME explTime ;
+ DateTime dateTime ;
+ FILETIME localFileTime;
+
+ if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotAfter ), &localFileTime))
+ {
+ if( FileTimeToSystemTime( &localFileTime, &explTime ) ) {
+ //Convert the time to readable local time
+ dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ;
+ dateTime.Seconds = explTime.wSecond ;
+ dateTime.Minutes = explTime.wMinute ;
+ dateTime.Hours = explTime.wHour ;
+ dateTime.Day = explTime.wDay ;
+ dateTime.Month = explTime.wMonth ;
+ dateTime.Year = explTime.wYear ;
+ }
+ }
+
+ return dateTime ;
+ } else {
+ return DateTime() ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getIssuerUniqueID() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ Sequence< sal_Int8 > issuerUid( m_pCertContext->pCertInfo->IssuerUniqueId.cbData ) ;
+ auto issuerUidRange = asNonConstRange(issuerUid);
+ for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->IssuerUniqueId.cbData; i ++ )
+ issuerUidRange[i] = *( m_pCertContext->pCertInfo->IssuerUniqueId.pbData + i ) ;
+
+ return issuerUid ;
+ } else {
+ return Sequence< sal_Int8 >();
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectUniqueID() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
+ Sequence< sal_Int8 > subjectUid( m_pCertContext->pCertInfo->SubjectUniqueId.cbData ) ;
+ auto subjectUidRange = asNonConstRange(subjectUid);
+ for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SubjectUniqueId.cbData; i ++ )
+ subjectUidRange[i] = *( m_pCertContext->pCertInfo->SubjectUniqueId.pbData + i ) ;
+
+ return subjectUid ;
+ } else {
+ return Sequence< sal_Int8 >();
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL X509Certificate_MSCryptImpl::getExtensions() {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 ) {
+ rtl::Reference<CertificateExtension_XmlSecImpl> xExtn ;
+ Sequence< Reference< XCertificateExtension > > xExtns( m_pCertContext->pCertInfo->cExtension ) ;
+ auto pExtns = xExtns.getArray();
+
+ for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
+ CERT_EXTENSION* pExtn = &(m_pCertContext->pCertInfo->rgExtension[i]) ;
+
+
+ OUString objId = OUString::createFromAscii( pExtn->pszObjId );
+
+ if ( objId == "2.5.29.17" )
+ xExtn = reinterpret_cast<CertificateExtension_XmlSecImpl*>(new SanExtensionImpl());
+ else
+ xExtn = new CertificateExtension_XmlSecImpl;
+
+ xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
+
+ pExtns[i] = xExtn ;
+ }
+
+ return xExtns ;
+ } else {
+ return Sequence< Reference< XCertificateExtension > >();
+ }
+}
+
+css::uno::Reference< css::security::XCertificateExtension > SAL_CALL X509Certificate_MSCryptImpl::findCertificateExtension( const css::uno::Sequence< sal_Int8 >& /*oid*/ ) {
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 ) {
+ rtl::Reference<CertificateExtension_XmlSecImpl> xExtn ;
+
+ for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
+ CERT_EXTENSION* pExtn = &( m_pCertContext->pCertInfo->rgExtension[i] ) ;
+
+ //TODO: Compare the oid
+ if( false ) {
+ xExtn = new CertificateExtension_XmlSecImpl;
+ xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
+ }
+ }
+
+ return xExtn ;
+ } else {
+ return nullptr ;
+ }
+}
+
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getEncoded() {
+ if( m_pCertContext != nullptr && m_pCertContext->cbCertEncoded > 0 ) {
+ Sequence< sal_Int8 > rawCert( m_pCertContext->cbCertEncoded ) ;
+ auto prawCert = rawCert.getArray();
+
+ for( unsigned int i = 0 ; i < m_pCertContext->cbCertEncoded ; i ++ )
+ prawCert[i] = *( m_pCertContext->pbCertEncoded + i ) ;
+
+ return rawCert ;
+ } else {
+ return Sequence< sal_Int8 >();
+ }
+}
+
+//Helper methods
+void X509Certificate_MSCryptImpl::setMswcryCert( const CERT_CONTEXT* cert ) {
+ if( m_pCertContext != nullptr ) {
+ CertFreeCertificateContext( m_pCertContext ) ;
+ m_pCertContext = nullptr ;
+ }
+
+ if( cert != nullptr ) {
+ m_pCertContext = CertDuplicateCertificateContext( cert ) ;
+ }
+}
+
+const CERT_CONTEXT* X509Certificate_MSCryptImpl::getMswcryCert() const {
+ if( m_pCertContext != nullptr ) {
+ return m_pCertContext ;
+ } else {
+ return nullptr ;
+ }
+}
+
+void X509Certificate_MSCryptImpl::setRawCert( Sequence< sal_Int8 > const & rawCert ) {
+ if( m_pCertContext != nullptr ) {
+ CertFreeCertificateContext( m_pCertContext ) ;
+ m_pCertContext = nullptr ;
+ }
+
+ if( rawCert.getLength() != 0 ) {
+ m_pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING, reinterpret_cast<const sal_uInt8*>(&rawCert[0]), rawCert.getLength() ) ;
+ }
+}
+
+static OUString findOIDDescription(char const *oid)
+{
+ OUString ouOID = OUString::createFromAscii( oid );
+ for (int i=0; i<nOID; i++)
+ {
+ OUString item = OUString::createFromAscii( OIDs[i].oid );
+ if (ouOID == item)
+ {
+ return OUString::createFromAscii( OIDs[i].desc );
+ }
+ }
+
+ return OUString() ;
+}
+
+static css::uno::Sequence< sal_Int8 > getThumbprint(const CERT_CONTEXT* pCertContext, DWORD dwPropId)
+{
+ if( pCertContext != nullptr )
+ {
+ DWORD cbData = dwPropId == CERT_SHA256_HASH_PROP_ID ? 32 : 20;
+ unsigned char fingerprint[32];
+ if (CertGetCertificateContextProperty(pCertContext, dwPropId, fingerprint, &cbData))
+ {
+ Sequence< sal_Int8 > thumbprint( cbData ) ;
+ auto pthumbprint = thumbprint.getArray();
+ for( unsigned int i = 0 ; i < cbData ; i ++ )
+ {
+ pthumbprint[i] = fingerprint[i];
+ }
+
+ return thumbprint;
+ }
+ else
+ {
+ DWORD e = GetLastError();
+ cbData = e;
+ }
+ }
+
+ return Sequence< sal_Int8 >();
+}
+
+OUString SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyAlgorithm()
+{
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
+ {
+ CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm;
+ return findOIDDescription( algorithm.pszObjId ) ;
+ }
+ else
+ {
+ return OUString() ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyValue()
+{
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
+ {
+ CRYPT_BIT_BLOB publicKey = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey;
+
+ Sequence< sal_Int8 > key( publicKey.cbData ) ;
+ auto keyRange = asNonConstRange(key);
+ for( unsigned int i = 0 ; i < publicKey.cbData ; i++ )
+ {
+ keyRange[i] = *(publicKey.pbData + i) ;
+ }
+
+ return key;
+ }
+ else
+ {
+ return Sequence< sal_Int8 >();
+ }
+}
+
+OUString SAL_CALL X509Certificate_MSCryptImpl::getSignatureAlgorithm()
+{
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
+ {
+ CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SignatureAlgorithm;
+ return findOIDDescription( algorithm.pszObjId ) ;
+ }
+ else
+ {
+ return OUString() ;
+ }
+}
+
+uno::Sequence<sal_Int8> X509Certificate_MSCryptImpl::getSHA256Thumbprint()
+{
+ return getThumbprint(m_pCertContext, CERT_SHA256_HASH_PROP_ID);
+}
+
+svl::crypto::SignatureMethodAlgorithm X509Certificate_MSCryptImpl::getSignatureMethodAlgorithm()
+{
+ svl::crypto::SignatureMethodAlgorithm nRet = svl::crypto::SignatureMethodAlgorithm::RSA;
+
+ if (!m_pCertContext || !m_pCertContext->pCertInfo)
+ return nRet;
+
+ CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm;
+ OString aObjId(algorithm.pszObjId);
+ if (aObjId == szOID_ECC_PUBLIC_KEY)
+ nRet = svl::crypto::SignatureMethodAlgorithm::ECDSA;
+
+ return nRet;
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSHA1Thumbprint()
+{
+ return getThumbprint(m_pCertContext, CERT_SHA1_HASH_PROP_ID);
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getMD5Thumbprint()
+{
+ return getThumbprint(m_pCertContext, CERT_MD5_HASH_PROP_ID);
+}
+
+CertificateKind SAL_CALL X509Certificate_MSCryptImpl::getCertificateKind()
+{
+ return CertificateKind_X509;
+}
+
+sal_Int32 SAL_CALL X509Certificate_MSCryptImpl::getCertificateUsage( )
+{
+ sal_Int32 usage =
+ CERT_DATA_ENCIPHERMENT_KEY_USAGE |
+ CERT_DIGITAL_SIGNATURE_KEY_USAGE |
+ CERT_KEY_AGREEMENT_KEY_USAGE |
+ CERT_KEY_CERT_SIGN_KEY_USAGE |
+ CERT_KEY_ENCIPHERMENT_KEY_USAGE |
+ CERT_NON_REPUDIATION_KEY_USAGE |
+ CERT_OFFLINE_CRL_SIGN_KEY_USAGE;
+
+ if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 )
+ {
+ CERT_EXTENSION* pExtn = CertFindExtension(
+ szOID_KEY_USAGE,
+ m_pCertContext->pCertInfo->cExtension,
+ m_pCertContext->pCertInfo->rgExtension);
+
+ if (pExtn != nullptr)
+ {
+ DWORD length = 0;
+ bool rc = CryptDecodeObject(
+ X509_ASN_ENCODING,
+ X509_KEY_USAGE,
+ pExtn->Value.pbData,
+ pExtn->Value.cbData,
+ 0,
+ nullptr,
+ &length);
+
+ if (!rc)
+ SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
+ else
+ {
+ std::vector<char>buffer(length);
+
+ rc = CryptDecodeObject(
+ X509_ASN_ENCODING,
+ X509_KEY_USAGE,
+ pExtn->Value.pbData,
+ pExtn->Value.cbData,
+ 0,
+ buffer.data(),
+ &length);
+
+ CRYPT_BIT_BLOB *blob = reinterpret_cast<CRYPT_BIT_BLOB*>(buffer.data());
+ if (!rc)
+ SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
+ else if (blob->cbData == 1)
+ usage = blob->pbData[0];
+ else
+ SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject(X509_KEY_USAGE) returned unexpected amount of data: " << blob->cbData);
+ }
+ }
+ }
+
+ return usage;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL X509Certificate_MSCryptImpl::getImplementationName()
+{
+ return "com.sun.star.xml.security.gpg.XCertificate_MsCryptImpl";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL X509Certificate_MSCryptImpl::supportsService(const OUString& serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+Sequence<OUString> SAL_CALL X509Certificate_MSCryptImpl::getSupportedServiceNames()
+{
+ return { OUString() };
+}
+
+namespace xmlsecurity {
+
+// based on some guesswork and:
+// https://datatracker.ietf.org/doc/html/rfc1485
+// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
+// the main problem appears to be that in values NSS uses \ escapes but CryptoAPI requires " quotes around value
+static OUString CompatDNNSS(OUString const& rDN)
+{
+ OUStringBuffer buf(rDN.getLength());
+ enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT);
+ for (sal_Int32 i = 0; i < rDN.getLength(); ++i)
+ {
+ if (state == DEFAULT)
+ {
+ buf.append(rDN[i]);
+ if (rDN[i] == '=')
+ {
+ if (rDN.getLength() == i+1)
+ {
+ break; // invalid?
+ }
+ else
+ {
+ buf.append('"');
+ state = INVALUE;
+ }
+ }
+ }
+ else if (state == INVALUE)
+ {
+ if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';')
+ {
+ buf.append("\"" + OUStringChar(rDN[i]));
+ state = DEFAULT;
+ }
+ else if (rDN[i] == '\\')
+ {
+ if (rDN.getLength() == i+1)
+ {
+ break; // invalid?
+ }
+ if (rDN[i+1] == '"')
+ {
+ buf.append('"');
+ }
+ buf.append(rDN[i+1]);
+ ++i;
+ }
+ else
+ {
+ buf.append(rDN[i]);
+ }
+ if (i+1 == rDN.getLength())
+ {
+ buf.append('"');
+ state = DEFAULT;
+ }
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+static bool EncodeDistinguishedName(std::u16string_view const rName, CERT_NAME_BLOB & rBlob)
+{
+ LPCWSTR pszError;
+ if (!CertStrToNameW(X509_ASN_ENCODING,
+ reinterpret_cast<LPCWSTR>(rName.data()), CERT_X500_NAME_STR,
+ nullptr, nullptr, &rBlob.cbData, &pszError))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError)));
+ return false;
+ }
+ rBlob.pbData = new BYTE[rBlob.cbData];
+ if (!CertStrToNameW(X509_ASN_ENCODING,
+ reinterpret_cast<LPCWSTR>(rName.data()), CERT_X500_NAME_STR,
+ nullptr, rBlob.pbData, &rBlob.cbData, &pszError))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError)));
+ return false;
+ }
+ return true;
+}
+
+bool EqualDistinguishedNames(
+ std::u16string_view const rName1, std::u16string_view const rName2,
+ EqualMode const eMode)
+{
+ if (eMode == COMPAT_BOTH && !rName1.empty() && rName1 == rName2)
+ { // handle case where both need to be converted
+ return true;
+ }
+ CERT_NAME_BLOB blob1;
+ if (!EncodeDistinguishedName(rName1, blob1))
+ {
+ return false;
+ }
+ CERT_NAME_BLOB blob2;
+ bool ret(false);
+ if (EncodeDistinguishedName(rName2, blob2))
+ {
+ ret = CertCompareCertificateName(X509_ASN_ENCODING,
+ &blob1, &blob2) == TRUE;
+ delete[] blob2.pbData;
+ }
+ if (!ret && eMode == COMPAT_2ND)
+ {
+ CERT_NAME_BLOB blob2compat;
+ if (!EncodeDistinguishedName(CompatDNNSS(OUString(rName2)), blob2compat))
+ {
+ delete[] blob1.pbData;
+ return false;
+ }
+ ret = CertCompareCertificateName(X509_ASN_ENCODING,
+ &blob1, &blob2compat) == TRUE;
+ delete[] blob2compat.pbData;
+ }
+ delete[] blob1.pbData;
+ return ret;
+}
+
+} // namespace xmlsecurity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx
new file mode 100644
index 0000000000..ba02281794
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <Windows.h>
+#include <WinCrypt.h>
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/SecurityException.hpp>
+#include <com/sun/star/security/CertificateKind.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+#include <certificate.hxx>
+
+class X509Certificate_MSCryptImpl : public ::cppu::WeakImplHelper<
+ css::security::XCertificate ,
+ css::lang::XServiceInfo > , public xmlsecurity::Certificate
+{
+ private:
+ const CERT_CONTEXT* m_pCertContext ;
+
+ public:
+ X509Certificate_MSCryptImpl() ;
+ virtual ~X509Certificate_MSCryptImpl() override;
+
+ //Methods from XCertificate
+ virtual sal_Int16 SAL_CALL getVersion() override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSerialNumber() override;
+ virtual OUString SAL_CALL getIssuerName() override;
+ virtual OUString SAL_CALL getSubjectName() override;
+ virtual css::util::DateTime SAL_CALL getNotValidBefore() override;
+ virtual css::util::DateTime SAL_CALL getNotValidAfter() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getIssuerUniqueID() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectUniqueID() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL getExtensions() override;
+ virtual css::uno::Reference< css::security::XCertificateExtension > SAL_CALL findCertificateExtension( const css::uno::Sequence< sal_Int8 >& oid ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getEncoded() override;
+ virtual OUString SAL_CALL getSubjectPublicKeyAlgorithm() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectPublicKeyValue() override;
+ virtual OUString SAL_CALL getSignatureAlgorithm() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSHA1Thumbprint() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getMD5Thumbprint() override;
+ virtual css::security::CertificateKind SAL_CALL getCertificateKind() override;
+
+
+ virtual sal_Int32 SAL_CALL getCertificateUsage( ) override;
+
+ /// @see xmlsecurity::Certificate::getSHA256Thumbprint().
+ virtual css::uno::Sequence<sal_Int8> getSHA256Thumbprint() override;
+
+ /// @see xmlsecurity::Certificate::getSignatureMethodAlgorithm().
+ virtual svl::crypto::SignatureMethodAlgorithm getSignatureMethodAlgorithm() override;
+
+ //Helper methods
+ void setMswcryCert( const CERT_CONTEXT* cert ) ;
+ const CERT_CONTEXT* getMswcryCert() const ;
+ /// @throws css::uno::RuntimeException
+ void setRawCert( css::uno::Sequence< sal_Int8 > const & rawCert ) ;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx
new file mode 100644
index 0000000000..f024a39b47
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
+#include "securityenvironment_mscryptimpl.hxx"
+
+#include <xmlsec/xmlstreamio.hxx>
+#include "akmngr.hxx"
+
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
+using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
+
+namespace {
+
+class XMLSecurityContext_MSCryptImpl : public ::cppu::WeakImplHelper<
+ css::xml::crypto::XXMLSecurityContext ,
+ css::lang::XServiceInfo >
+{
+ private:
+ //xmlSecKeysMngrPtr m_pKeysMngr ;
+ css::uno::Reference< css::xml::crypto::XSecurityEnvironment > m_xSecurityEnvironment ;
+
+ public:
+ XMLSecurityContext_MSCryptImpl();
+
+ //Methods from XXMLSecurityContext
+ virtual sal_Int32 SAL_CALL addSecurityEnvironment(
+ const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aSecurityEnvironment
+ ) override;
+
+ virtual ::sal_Int32 SAL_CALL getSecurityEnvironmentNumber( ) override;
+
+ virtual css::uno::Reference<
+ css::xml::crypto::XSecurityEnvironment > SAL_CALL
+ getSecurityEnvironmentByIndex( ::sal_Int32 index ) override;
+
+ virtual css::uno::Reference<
+ css::xml::crypto::XSecurityEnvironment > SAL_CALL
+ getSecurityEnvironment( ) override;
+
+ virtual ::sal_Int32 SAL_CALL getDefaultSecurityEnvironmentIndex( ) override;
+
+ virtual void SAL_CALL setDefaultSecurityEnvironmentIndex( sal_Int32 nDefaultEnvIndex ) override;
+
+
+ //Methods from XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(
+ const OUString& ServiceName
+ ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+XMLSecurityContext_MSCryptImpl::XMLSecurityContext_MSCryptImpl()
+{
+}
+
+sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::addSecurityEnvironment(
+ const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aSecurityEnvironment)
+{
+ if( !aSecurityEnvironment.is() )
+ {
+ throw uno::RuntimeException() ;
+ }
+
+ m_xSecurityEnvironment = aSecurityEnvironment;
+
+ return 0;
+}
+
+
+sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::getSecurityEnvironmentNumber( )
+{
+ return 1;
+}
+
+css::uno::Reference< css::xml::crypto::XSecurityEnvironment > SAL_CALL
+ XMLSecurityContext_MSCryptImpl::getSecurityEnvironmentByIndex( sal_Int32 index )
+{
+ if (index != 0)
+ {
+ throw uno::RuntimeException() ;
+ }
+ return m_xSecurityEnvironment;
+}
+
+css::uno::Reference< css::xml::crypto::XSecurityEnvironment > SAL_CALL
+ XMLSecurityContext_MSCryptImpl::getSecurityEnvironment( )
+{
+ return m_xSecurityEnvironment;
+}
+
+sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::getDefaultSecurityEnvironmentIndex( )
+{
+ return 0;
+}
+
+void SAL_CALL XMLSecurityContext_MSCryptImpl::setDefaultSecurityEnvironmentIndex( sal_Int32 /*nDefaultEnvIndex*/ )
+{
+ //dummy
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLSecurityContext_MSCryptImpl::getImplementationName() {
+ return "com.sun.star.xml.crypto.XMLSecurityContext" ;
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL XMLSecurityContext_MSCryptImpl::supportsService( const OUString& serviceName) {
+ return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+uno::Sequence< OUString > SAL_CALL XMLSecurityContext_MSCryptImpl::getSupportedServiceNames() {
+ return { "com.sun.star.xml.crypto.XMLSecurityContext" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_XMLSecurityContext_get_implementation(
+ uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLSecurityContext_MSCryptImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
new file mode 100644
index 0000000000..2a3709938a
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <rtl/uuid.h>
+#include <xmlsec-wrapper.h>
+
+#include <xmlsec/mscng/x509.h>
+
+#include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
+#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
+
+#include "securityenvironment_mscryptimpl.hxx"
+
+#include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
+#include <xmlelementwrapper_xmlsecimpl.hxx>
+#include <xmlsec/xmlstreamio.hxx>
+#include <xmlsec/errorcallback.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
+using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
+using ::com::sun::star::xml::crypto::XXMLSignature ;
+using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ;
+using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
+using ::com::sun::star::xml::crypto::XUriBinding ;
+
+namespace {
+
+class XMLSignature_MSCryptImpl : public ::cppu::WeakImplHelper<
+ css::xml::crypto::XXMLSignature ,
+ css::lang::XServiceInfo >
+{
+ public:
+ explicit XMLSignature_MSCryptImpl();
+
+ //Methods from XXMLSignature
+ virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL generate(
+ const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
+ const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aEnvironment
+ ) override;
+
+ virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL validate(
+ const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate ,
+ const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& aContext
+ ) override;
+
+ //Methods from XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(
+ const OUString& ServiceName
+ ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+} ;
+
+}
+
+XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() {
+}
+
+/* XXMLSignature */
+Reference< XXMLSignatureTemplate >
+SAL_CALL XMLSignature_MSCryptImpl::generate(
+ const Reference< XXMLSignatureTemplate >& aTemplate ,
+ const Reference< XSecurityEnvironment >& aEnvironment
+)
+{
+ xmlSecKeysMngrPtr pMngr = nullptr ;
+ xmlSecDSigCtxPtr pDsigCtx = nullptr ;
+ xmlNodePtr pNode = nullptr ;
+
+ if( !aTemplate.is() )
+ throw RuntimeException() ;
+
+ if( !aEnvironment.is() )
+ throw RuntimeException() ;
+
+ //Get Keys Manager
+ SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(aEnvironment.get());
+ if( pSecEnv == nullptr )
+ throw RuntimeException() ;
+
+ //Get the xml node
+ Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
+ if( !xElement.is() ) {
+ throw RuntimeException() ;
+ }
+
+ XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
+ if( pElement == nullptr ) {
+ throw RuntimeException() ;
+ }
+
+ pNode = pElement->getNativeElement() ;
+
+ //Get the stream/URI binding
+ Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
+ if( xUriBinding.is() ) {
+ //Register the stream input callbacks into libxml2
+ if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
+ throw RuntimeException() ;
+ }
+
+ setErrorRecorder( );
+
+ pMngr = pSecEnv->createKeysManager();
+ if( !pMngr ) {
+ throw RuntimeException() ;
+ }
+
+ //Create Signature context
+ pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
+ if( pDsigCtx == nullptr )
+ {
+ //throw XMLSignatureException() ;
+ SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
+ clearErrorRecorder();
+ return aTemplate;
+ }
+
+ //Sign the template
+ if( xmlSecDSigCtxSign( pDsigCtx , pNode ) == 0 )
+ {
+ if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
+ else
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+ else
+ {
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+
+
+ xmlSecDSigCtxDestroy( pDsigCtx ) ;
+ SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
+
+ //Unregistered the stream/URI binding
+ if( xUriBinding.is() )
+ xmlUnregisterStreamInputCallbacks() ;
+
+ clearErrorRecorder();
+ return aTemplate ;
+}
+
+/* XXMLSignature */
+Reference< XXMLSignatureTemplate >
+SAL_CALL XMLSignature_MSCryptImpl::validate(
+ const Reference< XXMLSignatureTemplate >& aTemplate ,
+ const Reference< XXMLSecurityContext >& aSecurityCtx
+) {
+ xmlSecKeysMngrPtr pMngr = nullptr ;
+ xmlSecDSigCtxPtr pDsigCtx = nullptr ;
+ xmlNodePtr pNode = nullptr ;
+
+ if( !aTemplate.is() )
+ throw RuntimeException() ;
+
+ if( !aSecurityCtx.is() )
+ throw RuntimeException() ;
+
+ //Get Keys Manager
+ Reference< XSecurityEnvironment > xSecEnv
+ = aSecurityCtx->getSecurityEnvironmentByIndex(
+ aSecurityCtx->getDefaultSecurityEnvironmentIndex());
+ SecurityEnvironment_MSCryptImpl* pSecEnv = dynamic_cast<SecurityEnvironment_MSCryptImpl*>(xSecEnv.get());
+ if( pSecEnv == nullptr )
+ throw RuntimeException() ;
+
+ //Get the xml node
+ Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
+ if( !xElement.is() )
+ throw RuntimeException() ;
+
+ XMLElementWrapper_XmlSecImpl* pElement = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
+ if( pElement == nullptr )
+ throw RuntimeException() ;
+
+ pNode = pElement->getNativeElement() ;
+
+ //Get the stream/URI binding
+ Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
+ if( xUriBinding.is() ) {
+ //Register the stream input callbacks into libxml2
+ if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
+ throw RuntimeException() ;
+ }
+
+ setErrorRecorder( );
+
+ pMngr = pSecEnv->createKeysManager();
+ if( !pMngr ) {
+ throw RuntimeException() ;
+ }
+
+ //Create Signature context
+ pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ;
+ if( pDsigCtx == nullptr )
+ {
+ SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
+ clearErrorRecorder();
+ return aTemplate;
+ }
+
+ // We do certificate verification ourselves.
+ pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
+
+ // limit possible key data to valid X509 certificates only, no KeyValues
+ if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecMSCngKeyDataX509GetKlass()) < 0)
+ throw RuntimeException("failed to limit allowed key data");
+
+ //Verify signature
+ //The documentation says that the signature is only valid if the return value is 0 (that is, not < 0)
+ //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not make any assumptions, if
+ //the return value is < 0. Then we must regard the signature as INVALID. We cannot use the
+ //error recorder feature to get the ONE error that made the verification fail, because there is no
+ //documentation/specification as to how to interpret the number of recorded errors and what is the initial
+ //error.
+ int rs = xmlSecDSigCtxVerify(pDsigCtx , pNode);
+
+ // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
+ xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences);
+ // Require that all manifest references are also good.
+ xmlSecSize nReferenceGood = 0;
+ for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference)
+ {
+ xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference));
+ if (pReference)
+ {
+ if (pReference->status == xmlSecDSigStatusSucceeded)
+ ++nReferenceGood;
+ }
+ }
+ SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
+
+ if (rs == 0 && nReferenceCount == nReferenceGood)
+ {
+ if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
+ else
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+ else
+ {
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+
+ xmlSecDSigCtxDestroy( pDsigCtx ) ;
+ SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr );
+
+ //Unregistered the stream/URI binding
+ if( xUriBinding.is() )
+ xmlUnregisterStreamInputCallbacks() ;
+
+
+ clearErrorRecorder();
+ return aTemplate;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLSignature_MSCryptImpl::getImplementationName() {
+ return "com.sun.star.xml.crypto.XMLSignature";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL XMLSignature_MSCryptImpl::supportsService( const OUString& serviceName) {
+return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+Sequence< OUString > SAL_CALL XMLSignature_MSCryptImpl::getSupportedServiceNames() {
+ return { "com.sun.star.xml.crypto.XMLSignature" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext* /*pCtx*/,
+ uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLSignature_MSCryptImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/certerrors.h b/xmlsecurity/source/xmlsec/nss/certerrors.h
new file mode 100644
index 0000000000..e8b7b38737
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/certerrors.h
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+{SEC_ERROR_IO, "An I/O error occurred during security authorization."},
+
+{SEC_ERROR_LIBRARY_FAILURE, "security library failure."},
+
+{SEC_ERROR_BAD_DATA, "security library: received bad data."},
+
+{SEC_ERROR_OUTPUT_LEN, "security library: output length error."},
+
+{SEC_ERROR_INPUT_LEN, "security library has experienced an input length error."},
+
+{SEC_ERROR_INVALID_ARGS, "security library: invalid arguments."},
+
+{SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm."},
+
+{SEC_ERROR_INVALID_AVA, "security library: invalid AVA."},
+
+{SEC_ERROR_INVALID_TIME, "Improperly formatted time string."},
+
+{SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message."},
+
+{SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature."},
+
+{SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired."},
+
+{SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked."},
+
+{SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized."},
+
+{SEC_ERROR_BAD_KEY, "Peer's public key is invalid."},
+
+{SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect."},
+
+{SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly. Please try again."},
+
+{SEC_ERROR_NO_NODELOCK, "security library: no nodelock."},
+
+{SEC_ERROR_BAD_DATABASE, "security library: bad database."},
+
+{SEC_ERROR_NO_MEMORY, "security library: memory allocation failure."},
+
+{SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user."},
+
+{SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user."},
+
+{SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database."},
+
+{SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database."},
+
+{SEC_ERROR_ADDING_CERT, "Error adding certificate to database."},
+
+{SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate."},
+
+{SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database"},
+
+{SEC_ERROR_CERT_VALID, "This certificate is valid."},
+
+{SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid."},
+
+{SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response"},
+
+{SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired. Check your system date and time."},
+
+{SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired. Update it or check your system date and time."},
+
+{SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature."},
+
+{SEC_ERROR_CRL_INVALID, "New CRL has an invalid format."},
+
+{SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid."},
+
+{SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found."},
+
+{SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid."},
+
+{SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid."},
+
+{SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid."},
+
+{SEC_INTERNAL_ONLY, "**Internal ONLY module**"},
+
+{SEC_ERROR_INVALID_KEY, "The key does not support the requested operation."},
+
+{SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension."},
+
+{SEC_ERROR_OLD_CRL, "New CRL is not later than the current one."},
+
+{SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate."},
+
+{SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients."},
+
+{SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and \
+private key not found."},
+
+{SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate."},
+
+{SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, \
+or improper or corrupted data."},
+
+{SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm."},
+
+{SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size."},
+
+
+/* Fortezza Alerts */
+{XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized. \
+Please remove it and return it to your issuer."},
+
+{XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found"},
+
+{XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected"},
+
+{XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on"},
+
+{XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found"},
+
+{XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality"},
+
+{XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin"},
+
+{XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities."},
+/* end fortezza alerts. */
+
+{SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found."},
+
+{SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired."},
+
+{SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature."},
+
+{SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked."},
+
+{SEC_ERROR_KRL_INVALID, "New KRL has an invalid format."},
+
+{SEC_ERROR_NEED_RANDOM, "security library: need random data."},
+
+{SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation."},
+
+{SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed."},
+
+{SEC_ERROR_READ_ONLY, "security library: read-only database."},
+
+{SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected."},
+
+{SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists."},
+
+{SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists."},
+
+{SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object"},
+
+{SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object"},
+
+{XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal"},
+
+{XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege"},
+
+{XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate"},
+
+{SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed."},
+
+{SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates."},
+
+{SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates."},
+
+{SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import. Decoding error. File not valid."},
+
+{SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import. Invalid MAC. Incorrect password or corrupt file."},
+
+{SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import. MAC algorithm not supported."},
+
+{SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import. Only password integrity and privacy modes supported."},
+
+{SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import. File structure is corrupt."},
+
+{SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import. Encryption algorithm not supported."},
+
+{SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import. File version not supported."},
+
+{SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import. Incorrect privacy password."},
+
+{SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import. Same nickname already exists in database."},
+
+{SEC_ERROR_USER_CANCELLED, "The user pressed cancel."},
+
+{SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database."},
+
+{SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent."},
+
+{SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation."},
+
+{SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application."},
+
+{SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers."},
+
+{SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import. Error attempting to import private key."},
+
+{SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import. Error attempting to import certificate chain."},
+
+{SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export. Unable to locate certificate or key by nickname."},
+
+{SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export. Private Key could not be located and exported."},
+
+{SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export. Unable to write the export file."},
+
+{SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import. Unable to read the import file."},
+
+{SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export. Key database corrupt or deleted."},
+
+{SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair."},
+
+{SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid. Please pick a different one."},
+
+{SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly. Please try again."},
+
+{SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use."},
+
+{SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate."},
+
+{SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed."},
+
+{SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name."},
+
+{SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename"},
+
+{SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module"},
+
+{SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module"},
+
+{SEC_ERROR_OLD_KRL, "New KRL is not later than the current one."},
+
+{SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL. Delete current CKL."},
+
+{SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a \
+certificate with this name."},
+
+{SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid."},
+
+{SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid."},
+
+{SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found."},
+
+{SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found."},
+
+{SEC_ERROR_CERT_BAD_ACCESS_LOCATION, "The location for the certificate status server has invalid format."},
+
+{SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type."},
+
+{SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data."},
+
+{SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed."},
+
+{SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error."},
+
+{SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later."},
+
+{SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request."},
+
+{SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized."},
+
+{SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status."},
+
+{SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate."},
+
+{SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation."},
+
+{SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation."},
+
+{SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed."},
+
+{SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for \
+this certificate."},
+
+{SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future},."},
+
+{SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information."},
+
+{SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message."},
+
+{SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported."},
+
+{SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use."},
+
+{SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid."},
+
+{SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found."},
+
+{SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as \
+an existing cert, but that is not the same cert."},
+
+{SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use."},
+
+{SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data."},
+
+{SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve."},
+
+{SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form."},
+
+{SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier."},
+
+{SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response."},
+
+{SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list."},
+
+{SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked."},
+
+{SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number."},
+
+{SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension."},
+
+{SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension."},
+
+{SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified."},
+
+{SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way."},
+
+{SEC_ERROR_NO_EVENT, "No new slot event is available at this time."},
+
+{SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists."},
+
+{SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized."},
+
+{SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in."},
+
+{SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid."},
+
+{SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature."},
+
+{SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits"},
+
+{SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy"},
+
+{SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation"},
+
+{SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension"},
+
+{SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response"},
+
+{SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response"},
+
+{SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder"},
+
+{SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension"},
+
+{SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occurred during cert validation."},
+
+#if ( NSS_VMAJOR > 3 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR > 12 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH > 2 )
+// following 3 errors got first used in NSS 3.12.3
+// they were in the header even in 3.12.2 but there was missing the mapping in pk11err.c
+// see also https://bugzilla.mozilla.org/show_bug.cgi?id=453364
+
+{SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred."},
+
+{SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed."},
+
+{SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot."},
+
+#endif
+
+#if ( NSS_VMAJOR > 3 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR > 12 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH > 3 )
+// following 2 errors got added in NSS 3.12.4
+
+{SEC_ERROR_BAD_INFO_ACCESS_METHOD, "Unknown information access method in certificate extension."},
+
+{SEC_ERROR_CRL_IMPORT_FAILED, "Error attempting to import a CRL."},
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx
new file mode 100644
index 0000000000..c3bbfdb0f2
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/ciphercontext.cxx
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <rtl/random.h>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+
+#include "ciphercontext.hxx"
+#include <nss.h> // for NSS_VMINOR
+#include <pk11pub.h>
+
+constexpr size_t nAESGCMIVSize = 12;
+constexpr size_t nAESGCMTagSize = 16;
+
+using namespace ::com::sun::star;
+
+uno::Reference< xml::crypto::XCipherContext > OCipherContext::Create( CK_MECHANISM_TYPE nNSSCipherID, const uno::Sequence< ::sal_Int8 >& aKey, const uno::Sequence< ::sal_Int8 >& aInitializationVector, bool bEncryption, bool bW3CPadding )
+{
+ ::rtl::Reference< OCipherContext > xResult = new OCipherContext;
+
+ xResult->m_pSlot = PK11_GetBestSlot( nNSSCipherID, nullptr );
+ if (!xResult->m_pSlot)
+ {
+ SAL_WARN("xmlsecurity.nss", "PK11_GetBestSlot failed");
+ throw uno::RuntimeException("PK11_GetBestSlot failed");
+ }
+
+ SECItem aKeyItem = { siBuffer,
+ const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(aKey.getConstArray())),
+ sal::static_int_cast<unsigned>(aKey.getLength()) };
+ xResult->m_pSymKey = PK11_ImportSymKey(xResult->m_pSlot, nNSSCipherID,
+ PK11_OriginDerive, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, &aKeyItem, nullptr);
+ if (!xResult->m_pSymKey)
+ {
+ SAL_WARN("xmlsecurity.nss", "PK11_ImportSymKey failed");
+ throw uno::RuntimeException("PK11_ImportSymKey failed");
+ }
+
+ if (nNSSCipherID == CKM_AES_GCM)
+ {
+ // TODO: when runtime requirements are raised to NSS 3.52,
+ // cleanup according to
+ // https://fedoraproject.org/wiki/Changes/NssGCMParams
+#if NSS_VMINOR >= 52
+ xResult->m_pSecParam = SECITEM_AllocItem(nullptr, nullptr, sizeof(CK_NSS_GCM_PARAMS));
+#else
+ xResult->m_pSecParam = SECITEM_AllocItem(nullptr, nullptr, sizeof(CK_GCM_PARAMS));
+#endif
+ if (!xResult->m_pSecParam)
+ {
+ SAL_WARN("xmlsecurity.nss", "SECITEM_AllocItem failed");
+ throw uno::RuntimeException("SECITEM_AllocItem failed");
+ }
+ assert(aInitializationVector.getLength() == nAESGCMIVSize);
+ xResult->m_AESGCMIV = aInitializationVector;
+#if NSS_VMINOR >= 52
+ auto *const pParams = reinterpret_cast<CK_NSS_GCM_PARAMS*>(xResult->m_pSecParam->data);
+#else
+ auto *const pParams = reinterpret_cast<CK_GCM_PARAMS*>(xResult->m_pSecParam->data);
+#endif
+ pParams->pIv = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(xResult->m_AESGCMIV.getConstArray()));
+ pParams->ulIvLen = sal::static_int_cast<unsigned>(xResult->m_AESGCMIV.getLength());
+ pParams->pAAD = nullptr;
+ pParams->ulAADLen = 0;
+ pParams->ulTagBits = nAESGCMTagSize * 8;
+ }
+ else
+ {
+ SECItem aIVItem = { siBuffer,
+ const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(aInitializationVector.getConstArray())),
+ sal::static_int_cast<unsigned>(aInitializationVector.getLength()) };
+ xResult->m_pSecParam = PK11_ParamFromIV(nNSSCipherID, &aIVItem);
+ if (!xResult->m_pSecParam)
+ {
+ SAL_WARN("xmlsecurity.nss", "PK11_ParamFromIV failed");
+ throw uno::RuntimeException("PK11_ParamFromIV failed");
+ }
+
+ xResult->m_pContext = PK11_CreateContextBySymKey( nNSSCipherID, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, xResult->m_pSymKey, xResult->m_pSecParam);
+ if (!xResult->m_pContext)
+ {
+ SAL_WARN("xmlsecurity.nss", "PK11_CreateContextBySymKey failed");
+ throw uno::RuntimeException("PK11_CreateContextBySymKey failed");
+ }
+ }
+
+ xResult->m_bEncryption = bEncryption;
+ xResult->m_bW3CPadding = bW3CPadding;
+ xResult->m_bPadding = bW3CPadding || ( PK11_GetPadMechanism( nNSSCipherID ) == nNSSCipherID );
+ // in NSS 3.94, a global default value of 8 is returned for CKM_AES_GCM
+ xResult->m_nBlockSize = nNSSCipherID == CKM_AES_GCM ? 16 : PK11_GetBlockSize(nNSSCipherID, xResult->m_pSecParam);
+ if (SAL_MAX_INT8 < xResult->m_nBlockSize)
+ {
+ SAL_WARN("xmlsecurity.nss", "PK11_GetBlockSize unexpected result");
+ throw uno::RuntimeException("PK11_GetBlockSize unexpected result");
+ }
+ return xResult;
+}
+
+void OCipherContext::Dispose()
+{
+ if ( m_pContext )
+ {
+ PK11_DestroyContext( m_pContext, PR_TRUE );
+ m_pContext = nullptr;
+ }
+
+ if ( m_pSecParam )
+ {
+ SECITEM_FreeItem( m_pSecParam, PR_TRUE );
+ m_pSecParam = nullptr;
+ }
+
+ if ( m_pSymKey )
+ {
+ PK11_FreeSymKey( m_pSymKey );
+ m_pSymKey = nullptr;
+ }
+
+ if ( m_pSlot )
+ {
+ PK11_FreeSlot( m_pSlot );
+ m_pSlot = nullptr;
+ }
+
+ m_bDisposed = true;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::convertWithCipherContext( const uno::Sequence< ::sal_Int8 >& aData )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bBroken )
+ throw uno::RuntimeException();
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if (m_AESGCMIV.getLength())
+ {
+ if (SAL_MAX_INT32 - nAESGCMIVSize - nAESGCMTagSize <= static_cast<size_t>(m_aLastBlock.getLength()) + static_cast<size_t>(aData.getLength()))
+ {
+ m_bBroken = true;
+ throw uno::RuntimeException("overflow");
+ }
+ m_aLastBlock.realloc(m_aLastBlock.getLength() + aData.getLength());
+ memcpy(m_aLastBlock.getArray() + m_aLastBlock.getLength() - aData.getLength(), aData.getConstArray(), aData.getLength());
+ return {};
+ }
+
+ uno::Sequence< sal_Int8 > aToConvert;
+ if ( aData.hasElements() )
+ {
+ sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength();
+
+ sal_Int32 nAvailableData = nOldLastBlockLen + aData.getLength();
+ sal_Int32 nToConvertLen;
+ if ( m_bEncryption || !m_bW3CPadding )
+ {
+ assert(nOldLastBlockLen < m_nBlockSize);
+ if ( nAvailableData % m_nBlockSize == 0 )
+ nToConvertLen = nAvailableData;
+ else if ( nAvailableData < m_nBlockSize )
+ nToConvertLen = 0;
+ else
+ nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize;
+ }
+ else
+ {
+ assert(nOldLastBlockLen < m_nBlockSize * 2);
+ // decryption with W3C padding needs at least one block for finalizing
+ if ( nAvailableData < m_nBlockSize * 2 )
+ nToConvertLen = 0;
+ else
+ nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize - m_nBlockSize;
+ }
+
+ aToConvert.realloc( nToConvertLen );
+ if ( nToConvertLen == 0 )
+ {
+ m_aLastBlock.realloc( nOldLastBlockLen + aData.getLength() );
+ memcpy( m_aLastBlock.getArray() + nOldLastBlockLen, aData.getConstArray(), aData.getLength() );
+ // aToConvert stays empty
+ }
+ else if ( nToConvertLen < nOldLastBlockLen )
+ {
+ memcpy( aToConvert.getArray(), m_aLastBlock.getConstArray(), nToConvertLen );
+ memcpy( m_aLastBlock.getArray(), m_aLastBlock.getConstArray() + nToConvertLen, nOldLastBlockLen - nToConvertLen );
+ m_aLastBlock.realloc( nOldLastBlockLen - nToConvertLen + aData.getLength() );
+ memcpy( m_aLastBlock.getArray() + nOldLastBlockLen - nToConvertLen, aData.getConstArray(), aData.getLength() );
+ }
+ else
+ {
+ memcpy( aToConvert.getArray(), m_aLastBlock.getConstArray(), nOldLastBlockLen );
+ if ( nToConvertLen > nOldLastBlockLen )
+ memcpy( aToConvert.getArray() + nOldLastBlockLen, aData.getConstArray(), nToConvertLen - nOldLastBlockLen );
+ m_aLastBlock.realloc( nAvailableData - nToConvertLen );
+ memcpy( m_aLastBlock.getArray(), aData.getConstArray() + nToConvertLen - nOldLastBlockLen, nAvailableData - nToConvertLen );
+ }
+ }
+
+ uno::Sequence< sal_Int8 > aResult;
+ assert(aToConvert.getLength() % m_nBlockSize == 0);
+ if ( aToConvert.hasElements() )
+ {
+ int nResultLen = 0;
+ aResult.realloc( aToConvert.getLength() + m_nBlockSize );
+ if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nResultLen, aResult.getLength(), reinterpret_cast< const unsigned char* >( aToConvert.getConstArray() ), aToConvert.getLength() ) != SECSuccess )
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("PK11_CipherOp failed");
+ }
+
+ m_nConverted += aToConvert.getLength();
+ aResult.realloc( nResultLen );
+ }
+
+ return aResult;
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::finalizeCipherContextAndDispose()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bBroken )
+ throw uno::RuntimeException();
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if (m_AESGCMIV.getLength())
+ {
+ uno::Sequence<sal_Int8> aResult;
+ unsigned outLen;
+ if (m_bEncryption)
+ {
+ assert(sal::static_int_cast<size_t>(m_aLastBlock.getLength()) <= SAL_MAX_INT32 - nAESGCMIVSize - nAESGCMTagSize);
+ // add space for IV and tag
+ aResult.realloc(m_aLastBlock.getLength() + nAESGCMIVSize + nAESGCMTagSize);
+ // W3C xmlenc-core1 requires the IV preceding the ciphertext,
+ // but NSS doesn't do it, so copy it manually
+ memcpy(aResult.getArray(), m_AESGCMIV.getConstArray(), nAESGCMIVSize);
+ if (PK11_Encrypt(m_pSymKey, CKM_AES_GCM, m_pSecParam,
+ reinterpret_cast<unsigned char*>(aResult.getArray() + nAESGCMIVSize),
+ &outLen, aResult.getLength() - nAESGCMIVSize,
+ reinterpret_cast<unsigned char const*>(m_aLastBlock.getConstArray()),
+ m_aLastBlock.getLength()) != SECSuccess)
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("PK11_Encrypt failed");
+ }
+ assert(outLen == sal::static_int_cast<unsigned>(aResult.getLength() - nAESGCMIVSize));
+ }
+ else if (nAESGCMIVSize + nAESGCMTagSize < sal::static_int_cast<size_t>(m_aLastBlock.getLength()))
+ {
+ if (0 != memcmp(m_AESGCMIV.getConstArray(), m_aLastBlock.getConstArray(), nAESGCMIVSize))
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("inconsistent IV");
+ }
+ aResult.realloc(m_aLastBlock.getLength() - nAESGCMIVSize - nAESGCMTagSize);
+ if (PK11_Decrypt(m_pSymKey, CKM_AES_GCM, m_pSecParam,
+ reinterpret_cast<unsigned char*>(aResult.getArray()),
+ &outLen, aResult.getLength(),
+ reinterpret_cast<unsigned char const*>(m_aLastBlock.getConstArray() + nAESGCMIVSize),
+ m_aLastBlock.getLength() - nAESGCMIVSize) != SECSuccess)
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("PK11_Decrypt failed");
+ }
+ assert(outLen == sal::static_int_cast<unsigned>(aResult.getLength()));
+ }
+ else
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("incorrect size of input");
+ }
+ Dispose();
+ return aResult;
+ }
+
+ assert(m_nBlockSize <= SAL_MAX_INT8);
+ assert(m_nConverted % m_nBlockSize == 0); // whole blocks are converted
+ sal_Int32 nSizeForPadding = ( m_nConverted + m_aLastBlock.getLength() ) % m_nBlockSize;
+
+ // if it is decryption, the amount of data should be rounded to the block size even in case of padding
+ if ( ( !m_bPadding || !m_bEncryption ) && nSizeForPadding )
+ throw uno::RuntimeException("The data should contain complete blocks only." );
+
+ if ( m_bW3CPadding && m_bEncryption )
+ {
+ // in this case the last block should be smaller than standard block
+ // it will be increased with the padding
+ assert(m_aLastBlock.getLength() < m_nBlockSize);
+
+ // W3CPadding handling for encryption
+ sal_Int32 nPaddingSize = m_nBlockSize - nSizeForPadding;
+ sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength();
+ m_aLastBlock.realloc( nOldLastBlockLen + nPaddingSize );
+ auto pLastBlock = m_aLastBlock.getArray();
+
+ if ( nPaddingSize > 1 )
+ {
+ rtlRandomPool aRandomPool = rtl_random_createPool();
+ rtl_random_getBytes( aRandomPool, pLastBlock + nOldLastBlockLen, nPaddingSize - 1 );
+ rtl_random_destroyPool ( aRandomPool );
+ }
+ pLastBlock[m_aLastBlock.getLength() - 1] = static_cast< sal_Int8 >( nPaddingSize );
+ }
+
+ // finally should the last block be smaller than two standard blocks
+ assert(m_aLastBlock.getLength() < m_nBlockSize * 2);
+
+ uno::Sequence< sal_Int8 > aResult;
+ if ( m_aLastBlock.hasElements() )
+ {
+ int nPrefResLen = 0;
+ aResult.realloc( m_aLastBlock.getLength() + m_nBlockSize );
+ if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nPrefResLen, aResult.getLength(), reinterpret_cast< const unsigned char* >( m_aLastBlock.getConstArray() ), m_aLastBlock.getLength() ) != SECSuccess )
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("PK11_CipherOp failed");
+ }
+
+ aResult.realloc( nPrefResLen );
+ m_aLastBlock.realloc( 0 );
+ }
+
+ sal_Int32 nPrefixLen = aResult.getLength();
+ aResult.realloc( nPrefixLen + m_nBlockSize * 2 );
+ unsigned nFinalLen = 0;
+ if ( PK11_DigestFinal( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() + nPrefixLen ), &nFinalLen, aResult.getLength() - nPrefixLen ) != SECSuccess )
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("PK11_DigestFinal failed");
+ }
+
+ aResult.realloc( nPrefixLen + nFinalLen );
+
+ if ( m_bW3CPadding && !m_bEncryption )
+ {
+ // W3CPadding handling for decryption
+ // aResult should have enough data, except if the input was completely empty
+
+ // see https://www.w3.org/TR/xmlenc-core1/#sec-Alg-Block
+ if (aResult.getLength() < m_nBlockSize
+ || aResult[aResult.getLength()-1] <= 0
+ || m_nBlockSize < aResult[aResult.getLength()-1])
+ {
+ m_bBroken = true;
+ Dispose();
+ throw uno::RuntimeException("incorrect size of padding");
+ }
+
+ aResult.realloc(aResult.getLength() - aResult[aResult.getLength()-1]);
+ }
+
+ Dispose();
+
+ return aResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/ciphercontext.hxx b/xmlsecurity/source/xmlsec/nss/ciphercontext.hxx
new file mode 100644
index 0000000000..d2c002ec46
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/ciphercontext.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/crypto/XCipherContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <mutex>
+#include <seccomon.h>
+#include <secmodt.h>
+
+class OCipherContext : public cppu::WeakImplHelper< css::xml::crypto::XCipherContext >
+{
+private:
+ std::mutex m_aMutex;
+
+ PK11SlotInfo* m_pSlot;
+ PK11SymKey* m_pSymKey;
+ SECItem* m_pSecParam;
+ PK11Context* m_pContext;
+
+ sal_Int32 m_nBlockSize;
+ css::uno::Sequence< sal_Int8 > m_aLastBlock;
+ css::uno::Sequence<sal_Int8> m_AESGCMIV;
+
+ bool m_bEncryption;
+ bool m_bPadding;
+ bool m_bW3CPadding;
+ sal_Int64 m_nConverted;
+
+ bool m_bDisposed;
+ bool m_bBroken;
+
+ void Dispose();
+
+ OCipherContext()
+ : m_pSlot( nullptr )
+ , m_pSymKey( nullptr )
+ , m_pSecParam( nullptr )
+ , m_pContext( nullptr )
+ , m_nBlockSize( 0 )
+ , m_bEncryption( false )
+ , m_bPadding( false )
+ , m_bW3CPadding( false )
+ , m_nConverted( 0 )
+ , m_bDisposed( false )
+ , m_bBroken( false )
+ {}
+
+public:
+
+ virtual ~OCipherContext() override
+ {
+ Dispose();
+ }
+
+ static css::uno::Reference< css::xml::crypto::XCipherContext > Create( CK_MECHANISM_TYPE nNSSCipherID, const css::uno::Sequence< ::sal_Int8 >& aKey, const css::uno::Sequence< ::sal_Int8 >& aInitializationVector, bool bEncryption, bool bW3CPadding );
+
+ // XCipherContext
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL convertWithCipherContext( const css::uno::Sequence< ::sal_Int8 >& aData ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL finalizeCipherContextAndDispose( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/digestcontext.cxx b/xmlsecurity/source/xmlsec/nss/digestcontext.cxx
new file mode 100644
index 0000000000..63c128e702
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/digestcontext.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <pk11pub.h>
+#include "digestcontext.hxx"
+
+using namespace ::com::sun::star;
+
+ODigestContext::~ODigestContext()
+{
+ if ( m_pContext )
+ {
+ PK11_DestroyContext( m_pContext, PR_TRUE );
+ m_pContext = nullptr;
+ }
+}
+
+void SAL_CALL ODigestContext::updateDigest( const uno::Sequence< ::sal_Int8 >& aData )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bBroken )
+ throw uno::RuntimeException();
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if (m_b1KData && m_nDigested >= 1024)
+ return;
+
+ uno::Sequence< sal_Int8 > aToDigest = aData;
+ if ( m_b1KData && m_nDigested + aData.getLength() > 1024 )
+ aToDigest.realloc( 1024 - m_nDigested );
+
+ if ( PK11_DigestOp( m_pContext, reinterpret_cast< const unsigned char* >( aToDigest.getConstArray() ), aToDigest.getLength() ) != SECSuccess )
+ {
+ PK11_DestroyContext( m_pContext, PR_TRUE );
+ m_pContext = nullptr;
+ m_bBroken = true;
+ throw uno::RuntimeException();
+ }
+
+ m_nDigested += aToDigest.getLength();
+}
+
+uno::Sequence< ::sal_Int8 > SAL_CALL ODigestContext::finalizeDigestAndDispose()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bBroken )
+ throw uno::RuntimeException();
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ uno::Sequence< sal_Int8 > aResult( m_nDigestLength );
+ unsigned int nResultLen = 0;
+ if ( PK11_DigestFinal( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nResultLen, aResult.getLength() ) != SECSuccess )
+ {
+ PK11_DestroyContext( m_pContext, PR_TRUE );
+ m_pContext = nullptr;
+ m_bBroken = true;
+ throw uno::RuntimeException();
+ }
+
+ PK11_DestroyContext( m_pContext, PR_TRUE );
+ m_pContext = nullptr;
+ m_bDisposed = true;
+
+ aResult.realloc( nResultLen );
+ return aResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/digestcontext.hxx b/xmlsecurity/source/xmlsec/nss/digestcontext.hxx
new file mode 100644
index 0000000000..72e1864851
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/digestcontext.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/crypto/XDigestContext.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <mutex>
+#include <secmodt.h>
+
+class ODigestContext : public cppu::WeakImplHelper< css::xml::crypto::XDigestContext >
+{
+private:
+ std::mutex m_aMutex;
+
+ PK11Context* m_pContext;
+ sal_Int32 const m_nDigestLength;
+ bool const m_b1KData;
+ sal_Int32 m_nDigested;
+
+ bool m_bDisposed;
+ bool m_bBroken;
+
+public:
+ ODigestContext( PK11Context* pContext, sal_Int32 nDigestLength, bool b1KData )
+ : m_pContext( pContext )
+ , m_nDigestLength( nDigestLength )
+ , m_b1KData( b1KData )
+ , m_nDigested( 0 )
+ , m_bDisposed( false )
+ , m_bBroken( false )
+ {}
+
+ virtual ~ODigestContext() override;
+
+
+ // XDigestContext
+ virtual void SAL_CALL updateDigest( const css::uno::Sequence< ::sal_Int8 >& aData ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL finalizeDigestAndDispose() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx
new file mode 100644
index 0000000000..bf74fa04ce
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx
@@ -0,0 +1,647 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
+#include <com/sun/star/xml/crypto/DigestID.hpp>
+#include <com/sun/star/xml/crypto/CipherID.hpp>
+#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <sal/types.h>
+#include <rtl/bootstrap.hxx>
+#include <rtl/string.hxx>
+#include <osl/file.hxx>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/tempfile.hxx>
+#include <comphelper/singletonref.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <nss/nssinitializer.hxx>
+
+#include "digestcontext.hxx"
+#include "ciphercontext.hxx"
+
+#include <cstddef>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <secmod.h>
+#include <prerror.h>
+#include <prinit.h>
+
+namespace cssu = css::uno;
+namespace cssl = css::lang;
+
+using namespace com::sun::star;
+
+#define ROOT_CERTS "Root Certs for OpenOffice.org"
+
+extern "C" {
+
+static void nsscrypto_finalize();
+
+}
+
+namespace
+{
+
+class InitNSSPrivate
+{
+private:
+ std::optional<utl::TempFileNamed> m_oTempFileDatabaseDirectory;
+
+public:
+ OUString getTempDatabasePath()
+ {
+ if (!m_oTempFileDatabaseDirectory)
+ {
+ m_oTempFileDatabaseDirectory.emplace(nullptr, true);
+ m_oTempFileDatabaseDirectory->EnableKillingFile();
+ }
+ return m_oTempFileDatabaseDirectory->GetFileName();
+ }
+
+ void reset()
+ {
+ if (m_oTempFileDatabaseDirectory)
+ {
+ m_oTempFileDatabaseDirectory.reset();
+ }
+ }
+};
+
+comphelper::SingletonRef<InitNSSPrivate>* getInitNSSPrivate()
+{
+ static comphelper::SingletonRef<InitNSSPrivate> aInitNSSPrivate;
+ return &aInitNSSPrivate;
+}
+
+bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init );
+
+#ifdef XMLSEC_CRYPTO_NSS
+
+void deleteRootsModule()
+{
+ SECMODModule *RootsModule = nullptr;
+ SECMODModuleList *list = SECMOD_GetDefaultModuleList();
+ SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
+ SECMOD_GetReadLock(lock);
+
+ while (!RootsModule && list)
+ {
+ SECMODModule *module = list->module;
+
+ for (int i=0; i < module->slotCount; i++)
+ {
+ PK11SlotInfo *slot = module->slots[i];
+ if (PK11_IsPresent(slot))
+ {
+ if (PK11_HasRootCerts(slot))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "The root certificates module \"" << module->commonName << "\" is already loaded: " << module->dllName);
+
+ RootsModule = SECMOD_ReferenceModule(module);
+ break;
+ }
+ }
+ }
+ list = list->next;
+ }
+ SECMOD_ReleaseReadLock(lock);
+
+ if (!RootsModule)
+ return;
+
+ PRInt32 modType;
+ if (SECSuccess == SECMOD_DeleteModule(RootsModule->commonName, &modType))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Deleted module \"" << RootsModule->commonName << "\".");
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Failed to delete \"" << RootsModule->commonName << "\": " << RootsModule->dllName);
+ }
+ SECMOD_DestroyModule(RootsModule);
+ RootsModule = nullptr;
+}
+
+#endif
+
+bool lcl_pathExists(const OUString& sPath)
+{
+ if (sPath.isEmpty())
+ return false;
+
+ ::osl::DirectoryItem aPathItem;
+ OUString sURL;
+ osl::FileBase::getFileURLFromSystemPath(sPath, sURL);
+ if (::osl::FileBase::E_None == ::osl::DirectoryItem::get(sURL, aPathItem))
+ {
+ ::osl::FileStatus aStatus = osl_FileStatus_Mask_Validate;
+ if (::osl::FileBase::E_None == aPathItem.getFileStatus(aStatus))
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+const OUString & ONSSInitializer::getMozillaCurrentProfile(const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool bSetActive)
+{
+ if (m_bIsNSSinitialized)
+ return m_sNSSPath;
+ if (bSetActive)
+ m_bIsNSSinitialized = true;
+
+ // first, try to get the profile from "MOZILLA_CERTIFICATE_FOLDER"
+ const char* pEnv = getenv("MOZILLA_CERTIFICATE_FOLDER");
+ if (pEnv)
+ {
+ SAL_INFO(
+ "xmlsecurity.xmlsec",
+ "Using Mozilla profile from MOZILLA_CERTIFICATE_FOLDER=" << pEnv);
+ m_sNSSPath = OStringToOUString(pEnv, osl_getThreadTextEncoding());
+ }
+
+ // second, try to get saved user-preference
+ if (m_sNSSPath.isEmpty())
+ {
+ try
+ {
+ OUString sUserSetCertPath =
+ officecfg::Office::Common::Security::Scripting::CertDir::get().value_or(OUString());
+
+ if (lcl_pathExists(sUserSetCertPath))
+ {
+ SAL_INFO(
+ "xmlsecurity.xmlsec",
+ "Using Mozilla profile from /org.openoffice.Office.Common/"
+ "Security/Scripting/CertDir: " << sUserSetCertPath);
+ m_sNSSPath = sUserSetCertPath;
+ }
+ }
+ catch (const uno::Exception &)
+ {
+ TOOLS_WARN_EXCEPTION("xmlsecurity.xmlsec", "getMozillaCurrentProfile:");
+ }
+ }
+
+ // third, dig around to see if there's one default available
+ mozilla::MozillaProductType productTypes[3] = {
+ mozilla::MozillaProductType_Thunderbird,
+ mozilla::MozillaProductType_Firefox,
+ mozilla::MozillaProductType_Mozilla };
+
+ uno::Reference<uno::XInterface> xInstance = rxContext->getServiceManager()->createInstanceWithContext("com.sun.star.mozilla.MozillaBootstrap", rxContext);
+ OSL_ENSURE( xInstance.is(), "failed to create instance" );
+
+ uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap(xInstance,uno::UNO_QUERY);
+ OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" );
+
+ if (xMozillaBootstrap.is())
+ {
+ for (auto const productTypeIter : productTypes)
+ {
+ OUString profile = xMozillaBootstrap->getDefaultProfile(productTypeIter);
+
+ if (!profile.isEmpty())
+ {
+ OUString sProfilePath = xMozillaBootstrap->getProfilePath(productTypeIter, profile);
+ if (m_sNSSPath.isEmpty())
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Using Mozilla profile " << sProfilePath);
+ m_sNSSPath = sProfilePath;
+ }
+ break;
+ }
+ }
+ }
+
+ SAL_INFO_IF(m_sNSSPath.isEmpty(), "xmlsecurity.xmlsec", "No Mozilla profile found");
+ return m_sNSSPath;
+}
+
+css::uno::Sequence<css::xml::crypto::NSSProfile> SAL_CALL ONSSInitializer::getNSSProfiles()
+{
+ ONSSInitializer::getMozillaCurrentProfile(m_xContext);
+
+ std::vector<xml::crypto::NSSProfile> aProfileList;
+ aProfileList.reserve(10);
+
+ mozilla::MozillaProductType productTypes[3] = {
+ mozilla::MozillaProductType_Thunderbird,
+ mozilla::MozillaProductType_Firefox,
+ mozilla::MozillaProductType_Mozilla };
+
+ uno::Reference<uno::XInterface> xInstance = m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.mozilla.MozillaBootstrap", m_xContext);
+ OSL_ENSURE(xInstance.is(), "failed to create instance" );
+
+ uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap(xInstance,uno::UNO_QUERY);
+
+ if (xMozillaBootstrap.is())
+ {
+ for (auto const productTypeIter : productTypes)
+ {
+ uno::Sequence<OUString> aProductProfileList;
+ xMozillaBootstrap->getProfileList(productTypeIter, aProductProfileList);
+ for (const auto& sProfile : std::as_const(aProductProfileList))
+ aProfileList.push_back({sProfile, xMozillaBootstrap->getProfilePath(productTypeIter, sProfile), productTypeIter});
+ }
+ }
+
+ OUString sUserSelect;
+ try
+ {
+ sUserSelect = officecfg::Office::Common::Security::Scripting::CertDir::get().value_or(OUString());;
+ if (!lcl_pathExists(sUserSelect))
+ sUserSelect = OUString();
+ }
+ catch (const uno::Exception &)
+ {
+ TOOLS_WARN_EXCEPTION("xmlsecurity.xmlsec", "getMozillaCurrentProfile:");
+ }
+ aProfileList.push_back({"MANUAL", sUserSelect, mozilla::MozillaProductType_Default});
+
+ const char* pEnv = getenv("MOZILLA_CERTIFICATE_FOLDER");
+ aProfileList.push_back({"MOZILLA_CERTIFICATE_FOLDER",
+ pEnv ? OStringToOUString(pEnv, osl_getThreadTextEncoding()) : OUString(),
+ mozilla::MozillaProductType_Default});
+
+ return comphelper::containerToSequence(aProfileList);
+}
+
+bool ONSSInitializer::m_bIsNSSinitialized = false;
+OUString ONSSInitializer::m_sNSSPath;
+
+OUString SAL_CALL ONSSInitializer::getNSSPath()
+{
+ ONSSInitializer::getMozillaCurrentProfile(m_xContext);
+ return m_sNSSPath;
+};
+
+sal_Bool SAL_CALL ONSSInitializer::getIsNSSinitialized()
+{
+ return m_bIsNSSinitialized;
+}
+
+ONSSInitializer::ONSSInitializer(css::uno::Reference< css::uno::XComponentContext > xContext)
+ : m_xContext(std::move(xContext))
+{
+}
+
+ONSSInitializer::ONSSInitializer()
+{
+}
+
+namespace
+{
+
+//Older versions of Firefox (FF), for example FF2, and Thunderbird (TB) 2 write
+//the roots certificate module (libnssckbi.so), which they use, into the
+//profile. This module will then already be loaded during NSS_Init (and the
+//other init functions). This fails in two cases. First, FF3 was used to create
+//the profile, or possibly used that profile before, and second the profile was
+//used on a different platform.
+//
+//Then one needs to add the roots module oneself. This should be done with
+//SECMOD_LoadUserModule rather than SECMOD_AddNewModule. The latter would write
+//the location of the roots module to the profile, which makes FF2 and TB2 use
+//it instead of their own module.
+//
+//When using SYSTEM_NSS then the libnss3.so lib is typically found in /usr/lib.
+//This folder may, however, NOT contain the roots certificate module. That is,
+//just providing the library name in SECMOD_LoadUserModule or
+//SECMOD_AddNewModule will FAIL to load the mozilla unless the LD_LIBRARY_PATH
+//contains an FF or TB installation.
+//ATTENTION: DO NOT call this function directly instead use initNSS
+//return true - whole initialization was successful
+//param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite
+//was successful and therefore NSS_Shutdown should be called when terminating.
+bool nsscrypto_initialize(css::uno::Reference<css::uno::XComponentContext> const & rxContext, bool & out_nss_init)
+{
+ // this method must be called only once, no need for additional lock
+ OString sCertDir;
+
+#ifdef XMLSEC_CRYPTO_NSS
+ sCertDir = OUStringToOString(ONSSInitializer::getMozillaCurrentProfile(rxContext, true), osl_getThreadTextEncoding());
+#else
+ (void) rxContext;
+#endif
+ SAL_INFO("xmlsecurity.xmlsec", "Using profile: " << sCertDir );
+
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
+
+ bool bSuccess = false;
+ // there might be no profile
+ if (!sCertDir.isEmpty())
+ {
+ if (sCertDir.indexOf(':') == -1) //might be env var with explicit prefix
+ {
+ OUString sCertDirURL;
+ osl::FileBase::getFileURLFromSystemPath(
+ OStringToOUString(sCertDir, osl_getThreadTextEncoding()),
+ sCertDirURL);
+ osl::DirectoryItem item;
+ if (osl::FileBase::E_NOENT != osl::DirectoryItem::get(sCertDirURL + "/cert8.db", item) &&
+ osl::FileBase::E_NOENT == osl::DirectoryItem::get(sCertDirURL + "/cert9.db", item))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "nsscrypto_initialize: trying to avoid profile migration");
+ sCertDir = "dbm:" + sCertDir;
+ }
+ }
+ if (NSS_InitReadWrite(sCertDir.getStr()) != SECSuccess)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with profile failed.");
+ int errlen = PR_GetErrorTextLength();
+ if (errlen > 0)
+ {
+ std::unique_ptr<char[]> const error(new char[errlen + 1]);
+ PR_GetErrorText(error.get());
+ SAL_INFO("xmlsecurity.xmlsec", error.get());
+ }
+ }
+ else
+ {
+ bSuccess = true;
+ }
+ }
+
+ if (!bSuccess) // Try to create a database in temp dir
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile.");
+ OUString rString = (*getInitNSSPrivate())->getTempDatabasePath();
+
+ if (NSS_InitReadWrite(rString.toUtf8().getStr()) != SECSuccess)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile.");
+ int errlen = PR_GetErrorTextLength();
+ if(errlen > 0)
+ {
+ std::unique_ptr<char[]> const error(new char[errlen + 1]);
+ PR_GetErrorText(error.get());
+ SAL_INFO("xmlsecurity.xmlsec", error.get());
+ }
+ return false;
+ }
+ }
+
+ // Initialize and set empty password if needed
+ // note: it's possible that the first NSS_InitReadWrite() succeeds by
+ // creating a new DB; in this case it may also be necessary to call
+ // PK11_InitPin()
+ PK11SlotInfo* pSlot = PK11_GetInternalKeySlot();
+ if (pSlot)
+ {
+ if (PK11_NeedUserInit(pSlot))
+ PK11_InitPin(pSlot, nullptr, nullptr);
+ PK11_FreeSlot(pSlot);
+ }
+
+ out_nss_init = true;
+
+#ifdef XMLSEC_CRYPTO_NSS
+ bool return_value = true;
+
+#if defined SYSTEM_NSS || defined IOS // The statically linked nss on iOS acts as a "system" nss in this regards
+ if (!SECMOD_HasRootCerts())
+#endif
+ {
+ deleteRootsModule();
+
+#ifdef IOS // Use statically linked NSS
+ OUString rootModulePath("NSSCKBI");
+
+ if (true)
+#else
+#if defined SYSTEM_NSS || defined ANDROID
+ OUString rootModule("libnssckbi" SAL_DLLEXTENSION);
+#else
+ OUString rootModule("${LO_LIB_DIR}/libnssckbi" SAL_DLLEXTENSION);
+#endif
+ ::rtl::Bootstrap::expandMacros(rootModule);
+
+ OUString rootModulePath;
+ if (::osl::File::E_None == ::osl::File::getSystemPathFromFileURL(rootModule, rootModulePath))
+#endif
+ {
+ OString ospath = OUStringToOString(rootModulePath, osl_getThreadTextEncoding());
+ OString aStr = "name=\"" ROOT_CERTS "\" library=\"" + ospath + "\"";
+
+ SECMODModule * RootsModule =
+ SECMOD_LoadUserModule(
+ const_cast<char*>(aStr.getStr()),
+ nullptr, // no parent
+ PR_FALSE); // do not recurse
+
+ if (RootsModule)
+ {
+
+ bool found = RootsModule->loaded;
+
+ SECMOD_DestroyModule(RootsModule);
+ RootsModule = nullptr;
+ if (found)
+ SAL_INFO("xmlsecurity.xmlsec", "Added new root certificate module " ROOT_CERTS " contained in " << ospath);
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "FAILED to load the new root certificate module " ROOT_CERTS "contained in " << ospath);
+ return_value = false;
+ }
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "FAILED to add new root certificate module " ROOT_CERTS " contained in " << ospath);
+ return_value = false;
+
+ }
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Adding new root certificate module failed.");
+ return_value = false;
+ }
+ }
+
+ return return_value;
+#else
+ return true;
+#endif
+}
+
+} // namespace
+
+// must be extern "C" because we pass the function pointer to atexit
+extern "C" void nsscrypto_finalize()
+{
+ SECMODModule *RootsModule = SECMOD_FindModule(ROOT_CERTS);
+
+ if (RootsModule)
+ {
+
+ if (SECSuccess == SECMOD_UnloadUserModule(RootsModule))
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Unloaded module \"" ROOT_CERTS "\".");
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Failed unloading module \"" ROOT_CERTS "\".");
+ }
+ SECMOD_DestroyModule(RootsModule);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Unloading module \"" ROOT_CERTS "\" failed because it was not found.");
+ }
+ PK11_LogoutAll();
+ (void)NSS_Shutdown();
+
+ (*getInitNSSPrivate())->reset();
+}
+
+
+ONSSInitializer::~ONSSInitializer()
+{
+}
+
+bool ONSSInitializer::initNSS( const css::uno::Reference< css::uno::XComponentContext > &rxContext )
+{
+ static bool gbInitialized = [&rxContext]()
+ {
+ bool bNSSInit = false;
+ bool bInitialized = nsscrypto_initialize( rxContext, bNSSInit );
+ if (bNSSInit)
+ atexit(nsscrypto_finalize);
+ return bInitialized;
+ }();
+ return gbInitialized;
+}
+
+css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL ONSSInitializer::getDigestContext( ::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue >& aParams )
+{
+ SECOidTag nNSSDigestID = SEC_OID_UNKNOWN;
+ sal_Int32 nDigestLength = 0;
+ bool b1KData = false;
+ if ( nDigestID == css::xml::crypto::DigestID::SHA256
+ || nDigestID == css::xml::crypto::DigestID::SHA256_1K )
+ {
+ nNSSDigestID = SEC_OID_SHA256;
+ nDigestLength = 32;
+ b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA256_1K );
+ }
+ else if ( nDigestID == css::xml::crypto::DigestID::SHA1
+ || nDigestID == css::xml::crypto::DigestID::SHA1_1K )
+ {
+ nNSSDigestID = SEC_OID_SHA1;
+ nDigestLength = 20;
+ b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA1_1K );
+ }
+ else if ( nDigestID == css::xml::crypto::DigestID::SHA512
+ || nDigestID == css::xml::crypto::DigestID::SHA512_1K )
+ {
+ nNSSDigestID = SEC_OID_SHA512;
+ nDigestLength = 64;
+ b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA512_1K );
+ }
+ else
+ throw css::lang::IllegalArgumentException("Unexpected digest requested.", css::uno::Reference< css::uno::XInterface >(), 1 );
+
+ if ( aParams.hasElements() )
+ throw css::lang::IllegalArgumentException("Unexpected arguments provided for digest creation.", css::uno::Reference< css::uno::XInterface >(), 2 );
+
+ css::uno::Reference< css::xml::crypto::XDigestContext > xResult;
+ if( initNSS( m_xContext ) )
+ {
+ PK11Context* pContext = PK11_CreateDigestContext( nNSSDigestID );
+ if ( pContext && PK11_DigestBegin( pContext ) == SECSuccess )
+ xResult = new ODigestContext( pContext, nDigestLength, b1KData );
+ }
+
+ return xResult;
+}
+
+css::uno::Reference< css::xml::crypto::XCipherContext > SAL_CALL ONSSInitializer::getCipherContext( ::sal_Int32 nCipherID, const css::uno::Sequence< ::sal_Int8 >& aKey, const css::uno::Sequence< ::sal_Int8 >& aInitializationVector, sal_Bool bEncryption, const css::uno::Sequence< css::beans::NamedValue >& aParams )
+{
+ CK_MECHANISM_TYPE nNSSCipherID = 0;
+ bool bW3CPadding = false;
+ switch (nCipherID)
+ {
+ case css::xml::crypto::CipherID::AES_CBC_W3C_PADDING:
+ nNSSCipherID = CKM_AES_CBC;
+ bW3CPadding = true;
+ break;
+ case css::xml::crypto::CipherID::AES_GCM_W3C:
+ nNSSCipherID = CKM_AES_GCM;
+ break;
+ default:
+ throw css::lang::IllegalArgumentException("Unexpected cipher requested.", css::uno::Reference< css::uno::XInterface >(), 1);
+ }
+
+ if ( aKey.getLength() != 16 && aKey.getLength() != 24 && aKey.getLength() != 32 )
+ throw css::lang::IllegalArgumentException("Unexpected key length.", css::uno::Reference< css::uno::XInterface >(), 2 );
+
+ if ( aParams.hasElements() )
+ throw css::lang::IllegalArgumentException("Unexpected arguments provided for cipher creation.", css::uno::Reference< css::uno::XInterface >(), 5 );
+
+ css::uno::Reference< css::xml::crypto::XCipherContext > xResult;
+ if( initNSS( m_xContext ) )
+ {
+ if ( aInitializationVector.getLength() != PK11_GetIVLength( nNSSCipherID ) )
+ throw css::lang::IllegalArgumentException("Unexpected length of initialization vector.", css::uno::Reference< css::uno::XInterface >(), 3 );
+
+ xResult = OCipherContext::Create( nNSSCipherID, aKey, aInitializationVector, bEncryption, bW3CPadding );
+ assert(xResult.is());
+ }
+
+ return xResult;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL ONSSInitializer::getImplementationName()
+{
+ return "com.sun.star.xml.crypto.NSSInitializer";
+}
+
+sal_Bool SAL_CALL ONSSInitializer::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+cssu::Sequence< OUString > SAL_CALL ONSSInitializer::getSupportedServiceNames( )
+{
+ return { NSS_SERVICE_NAME };
+}
+
+#ifndef XMLSEC_CRYPTO_NSS
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_NSSInitializer_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new ONSSInitializer(pCtx));
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/nssinitializer.hxx b/xmlsecurity/source/xmlsec/nss/nssinitializer.hxx
new file mode 100644
index 0000000000..c461dd5c97
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/nssinitializer.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/crypto/XNSSInitializer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+inline constexpr OUString NSS_SERVICE_NAME = u"com.sun.star.xml.crypto.NSSInitializer"_ustr;
+
+class ONSSInitializer : public cppu::WeakImplHelper
+<
+ css::xml::crypto::XNSSInitializer,
+ css::lang::XServiceInfo
+>
+{
+protected:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ static OUString m_sNSSPath;
+ static bool m_bIsNSSinitialized;
+
+ ONSSInitializer();
+
+public:
+ explicit ONSSInitializer(css::uno::Reference<css::uno::XComponentContext> xContext);
+ virtual ~ONSSInitializer() override;
+
+ static bool initNSS( const css::uno::Reference< css::uno::XComponentContext > &rxContext );
+ static const OUString & getMozillaCurrentProfile(const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool bSetActive = false);
+
+ /* XNSSInitializer */
+ virtual OUString SAL_CALL getNSSPath() override;
+ virtual sal_Bool SAL_CALL getIsNSSinitialized() override;
+ virtual css::uno::Sequence<css::xml::crypto::NSSProfile> SAL_CALL getNSSProfiles() override;
+
+ /* XDigestContextSupplier */
+ virtual css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL getDigestContext( ::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue >& aParams ) override;
+
+ /* XCipherContextSupplier */
+ virtual css::uno::Reference< css::xml::crypto::XCipherContext > SAL_CALL getCipherContext( ::sal_Int32 nCipherID, const css::uno::Sequence< ::sal_Int8 >& aKey, const css::uno::Sequence< ::sal_Int8 >& aInitializationVector, sal_Bool bEncryption, const css::uno::Sequence< css::beans::NamedValue >& aParams ) override;
+
+ /* XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/nssrenam.h b/xmlsecurity/source/xmlsec/nss/nssrenam.h
new file mode 100644
index 0000000000..47280408b7
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/nssrenam.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 2001 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#pragma once
+
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+#define PK11_GetKeyData __PK11_GetKeyData
+#define CERT_DecodeDERCertificate __CERT_DecodeDERCertificate
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.cxx
new file mode 100644
index 0000000000..1395cb2e8a
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/security/ExtAltNameType.hpp>
+#include <com/sun/star/security/CertAltNameEntry.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/sequence.hxx>
+#include <seccomon.h>
+#include <cert.h>
+#include <certt.h>
+
+#include "sanextension_nssimpl.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::security ;
+
+namespace {
+ // Helper functions from nss/lib/certdb/genname.c
+ int GetNamesLength(CERTGeneralName *names)
+ {
+ int length = 0;
+ CERTGeneralName *first;
+
+ first = names;
+ if (names != nullptr) {
+ do {
+ length++;
+ names = CERT_GetNextGeneralName(names);
+ } while (names != first);
+ }
+ return length;
+ }
+
+}
+
+//Methods from XSanExtension
+css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL SanExtensionImpl::getAlternativeNames()
+{
+ if (m_Entries.empty())
+ {
+ SECItem item;
+
+ item.type = siDERCertBuffer;
+ item.data = reinterpret_cast<unsigned char*>(m_Extn.m_xExtnValue.getArray());
+ item.len = m_Extn.m_xExtnValue.getLength();
+
+ PRArenaPool *arena;
+ CERTGeneralName *nameList;
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if (!arena)
+ return css::uno::Sequence<css::security::CertAltNameEntry>();
+
+ nameList = CERT_DecodeAltNameExtension(arena, &item);
+
+ CERTGeneralName* current = nameList;
+
+ int size = GetNamesLength(nameList);
+ m_Entries.resize(size);
+ for(int i = 0; i < size; ++i){
+ switch (current->type) {
+ case certOtherName: {
+ m_Entries[i].Type = ExtAltNameType_OTHER_NAME;
+ css::beans::PropertyValue otherNameProp;
+ otherNameProp.Name = OUString::createFromAscii(CERT_GetOidString(&current->name.OthName.oid));
+
+ Sequence< sal_Int8 > otherName( current->name.OthName.name.len ) ;
+ auto otherNameRange = asNonConstRange(otherName);
+ for( unsigned int r = 0; r < current->name.OthName.name.len ; r ++ )
+ otherNameRange[r] = *( current->name.OthName.name.data + r ) ;
+
+ otherNameProp.Value <<= otherName;
+
+ m_Entries[i].Value <<= otherNameProp;
+ break;
+ }
+ case certRFC822Name:
+ m_Entries[i].Type = ExtAltNameType_RFC822_NAME;
+ m_Entries[i].Value <<= OUString(reinterpret_cast<char*>(current->name.other.data), current->name.other.len, RTL_TEXTENCODING_ASCII_US);
+ break;
+ case certDNSName:
+ m_Entries[i].Type = ExtAltNameType_DNS_NAME;
+ m_Entries[i].Value <<= OUString(reinterpret_cast<char*>(current->name.other.data), current->name.other.len, RTL_TEXTENCODING_ASCII_US);
+ break;
+ case certX400Address: {
+ // unsupported
+ m_Entries[i].Type = ExtAltNameType_X400_ADDRESS;
+ break;
+ }
+ case certDirectoryName: {
+ // unsupported
+ m_Entries[i].Type = ExtAltNameType_DIRECTORY_NAME;
+ break;
+ }
+ case certEDIPartyName: {
+ // unsupported
+ m_Entries[i].Type = ExtAltNameType_EDI_PARTY_NAME;
+ break;
+ }
+ case certURI:
+ m_Entries[i].Type = ExtAltNameType_URL;
+ m_Entries[i].Value <<= OUString(reinterpret_cast<char*>(current->name.other.data), current->name.other.len, RTL_TEXTENCODING_ASCII_US);
+ break;
+ case certIPAddress: {
+ m_Entries[i].Type = ExtAltNameType_IP_ADDRESS;
+
+ Sequence< sal_Int8 > ipAddress( current->name.other.len ) ;
+ auto ipAddressRange = asNonConstRange(ipAddress);
+ for( unsigned int r = 0; r < current->name.other.len ; r ++ )
+ ipAddressRange[r] = *( current->name.other.data + r ) ;
+
+ m_Entries[i].Value <<= ipAddress;
+ break;
+ }
+ case certRegisterID:
+ m_Entries[i].Type = ExtAltNameType_REGISTERED_ID;
+
+
+ OString nssOid(CERT_GetOidString(&current->name.other));
+ OString unoOid = removeOIDFromString(nssOid);
+ m_Entries[i].Value <<= OStringToOUString( unoOid, RTL_TEXTENCODING_ASCII_US );
+ break;
+ }
+ current = CERT_GetNextGeneralName(current);
+ }
+
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return comphelper::containerToSequence<css::security::CertAltNameEntry>(m_Entries);
+}
+
+OString SanExtensionImpl::removeOIDFromString( const OString &oidString)
+{
+ OString objID;
+ constexpr std::string_view oid("OID.");
+ if (oidString.match(oid))
+ objID = oidString.copy(oid.size());
+ else
+ objID = oidString;
+ return objID;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.hxx
new file mode 100644
index 0000000000..3716d414e5
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/sanextension_nssimpl.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/security/XSanExtension.hpp>
+#include <com/sun/star/security/CertAltNameEntry.hpp>
+#include <certificateextension_certextn.hxx>
+#include <vector>
+
+class SanExtensionImpl : public ::cppu::WeakImplHelper<
+ css::security::XSanExtension >
+{
+ private:
+ CertificateExtension_CertExtn m_Extn;
+ std::vector<css::security::CertAltNameEntry> m_Entries;
+
+ static OString removeOIDFromString( const OString &oid);
+
+ public:
+ //Methods from XCertificateExtension
+ virtual sal_Bool SAL_CALL isCritical() override
+ {
+ return m_Extn.m_critical;
+ }
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionId() override
+ {
+ return m_Extn.m_xExtnId;
+ }
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionValue() override
+ {
+ return m_Extn.m_xExtnValue;
+ }
+
+ void setCertExtn(unsigned char const * value, unsigned int vlen, unsigned char const * id, unsigned int idlen, bool critical)
+ {
+ m_Extn.setCertExtn(value, vlen, id, idlen, critical);
+ }
+
+ //Methods from XSanExtension
+
+ virtual css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL getAlternativeNames() override ;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/secerror.cxx b/xmlsecurity/source/xmlsec/nss/secerror.cxx
new file mode 100644
index 0000000000..b7e623ce00
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/secerror.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <secerr.h>
+#include "secerror.hxx"
+#include <nss.h>
+#include <certt.h>
+#include <sal/log.hxx>
+
+namespace {
+
+struct ErrDesc {
+ PRErrorCode const errNum;
+ const char * errString;
+};
+
+}
+
+const ErrDesc allDesc[] = {
+
+#include "certerrors.h"
+
+};
+
+
+/* Returns a UTF-8 encoded constant error string for "errNum".
+ * Returns NULL of errNum is unknown.
+ */
+const char *
+getCertError(PRErrorCode errNum)
+{
+ for (const ErrDesc& i : allDesc)
+ {
+ if (i.errNum == errNum)
+ return i.errString;
+ }
+
+ return "";
+}
+
+void
+printChainFailure(CERTVerifyLog *log)
+{
+ unsigned int depth = static_cast<unsigned int>(-1);
+ CERTVerifyLogNode *node = nullptr;
+
+ if (log->count > 0)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Bad certification path:");
+ unsigned long errorFlags = 0;
+ for (node = log->head; node; node = node->next)
+ {
+ if (depth != node->depth)
+ {
+ depth = node->depth;
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate: " << depth <<
+ node->cert->subjectName << ": " <<
+ (depth ? "[Certificate Authority]": ""));
+ }
+ SAL_INFO("xmlsecurity.xmlsec", " ERROR " << node->error << ": " <<
+ getCertError(node->error));
+ const char * specificError = nullptr;
+ const char * issuer = nullptr;
+ switch (node->error)
+ {
+ case SEC_ERROR_INADEQUATE_KEY_USAGE:
+ errorFlags = reinterpret_cast<unsigned long>(node->arg);
+ switch (errorFlags)
+ {
+ case KU_DIGITAL_SIGNATURE:
+ specificError = "Certificate cannot sign.";
+ break;
+ case KU_KEY_ENCIPHERMENT:
+ specificError = "Certificate cannot encrypt.";
+ break;
+ case KU_KEY_CERT_SIGN:
+ specificError = "Certificate cannot sign other certs.";
+ break;
+ default:
+ specificError = "[unknown usage].";
+ break;
+ }
+ break;
+ case SEC_ERROR_INADEQUATE_CERT_TYPE:
+ errorFlags = reinterpret_cast<unsigned long>(node->arg);
+ switch (errorFlags)
+ {
+ case NS_CERT_TYPE_SSL_CLIENT:
+ case NS_CERT_TYPE_SSL_SERVER:
+ specificError = "Certificate cannot be used for SSL.";
+ break;
+ case NS_CERT_TYPE_SSL_CA:
+ specificError = "Certificate cannot be used as an SSL CA.";
+ break;
+ case NS_CERT_TYPE_EMAIL:
+ specificError = "Certificate cannot be used for SMIME.";
+ break;
+ case NS_CERT_TYPE_EMAIL_CA:
+ specificError = "Certificate cannot be used as an SMIME CA.";
+ break;
+ case NS_CERT_TYPE_OBJECT_SIGNING:
+ specificError = "Certificate cannot be used for object signing.";
+ break;
+ case NS_CERT_TYPE_OBJECT_SIGNING_CA:
+ specificError = "Certificate cannot be used as an object signing CA.";
+ break;
+ default:
+ specificError = "[unknown usage].";
+ break;
+ }
+ break;
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ specificError = "Unknown issuer:";
+ issuer = node->cert->issuerName;
+ break;
+ case SEC_ERROR_UNTRUSTED_ISSUER:
+ specificError = "Untrusted issuer:";
+ issuer = node->cert->issuerName;
+ break;
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ specificError = "Expired issuer certificate:";
+ issuer = node->cert->issuerName;
+ break;
+ default:
+ break;
+ }
+ if (specificError)
+ SAL_INFO("xmlsecurity.xmlsec", specificError);
+ if (issuer)
+ SAL_INFO("xmlsecurity.xmlsec", issuer);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/secerror.hxx b/xmlsecurity/source/xmlsec/nss/secerror.hxx
new file mode 100644
index 0000000000..bd59078262
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/secerror.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <certt.h>
+#include <prerror.h>
+
+const char* getCertError(PRErrorCode errNum);
+
+void printChainFailure(CERTVerifyLog* log);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx
new file mode 100644
index 0000000000..2ab5b011e2
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx
@@ -0,0 +1,878 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "nssrenam.h"
+#include <cert.h>
+#include <secerr.h>
+#include <ocsp.h>
+
+#include <sal/config.h>
+#include <sal/macros.h>
+#include <osl/diagnose.h>
+#include "securityenvironment_nssimpl.hxx"
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <xmlsec-wrapper.h>
+
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/docpasswordrequest.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <vector>
+#include <memory>
+#include <osl/thread.h>
+#include <comphelper/sequence.hxx>
+
+#include "x509certificate_nssimpl.hxx"
+#include "secerror.hxx"
+#include <prerror.h>
+#include <keyhi.h>
+
+// added for password exception
+#include <com/sun/star/security/NoPasswordException.hpp>
+#include <com/sun/star/security/CertificateCharacters.hpp>
+#include <com/sun/star/security/CertificateValidity.hpp>
+
+namespace csss = ::com::sun::star::security;
+using namespace ::com::sun::star::security;
+using namespace com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::security::XCertificate ;
+
+namespace std
+{
+template <> struct default_delete<PRArenaPool>
+{
+ void operator()(PRArenaPool* ptr) { PORT_FreeArena(ptr, PR_FALSE); }
+};
+}
+
+static rtl::Reference<X509Certificate_NssImpl> NssCertToXCert( CERTCertificate* cert ) ;
+static rtl::Reference<X509Certificate_NssImpl> NssPrivKeyToXCert( SECKEYPrivateKey* ) ;
+
+namespace {
+
+struct UsageDescription
+{
+ SECCertificateUsage usage;
+ char const* description;
+
+ UsageDescription()
+ : usage( certificateUsageCheckAllUsages )
+ , description( nullptr )
+ {}
+
+ UsageDescription( SECCertificateUsage i_usage, char const* i_description )
+ : usage( i_usage )
+ , description( i_description )
+ {}
+};
+
+}
+
+static char* GetPasswordFunction( PK11SlotInfo* pSlot, PRBool bRetry, void* /*arg*/ )
+{
+ uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference < task::XInteractionHandler2 > xInteractionHandler(
+ task::InteractionHandler::createWithParent(xContext, nullptr) );
+
+ task::PasswordRequestMode eMode = bRetry ? task::PasswordRequestMode_PASSWORD_REENTER : task::PasswordRequestMode_PASSWORD_ENTER;
+ rtl::Reference<::comphelper::DocPasswordRequest> pPasswordRequest = new ::comphelper::DocPasswordRequest(
+ ::comphelper::DocPasswordRequestType::Standard, eMode, OUString::createFromAscii(PK11_GetTokenName(pSlot)) );
+
+ xInteractionHandler->handle( pPasswordRequest );
+
+ if ( pPasswordRequest->isPassword() )
+ {
+ OString aPassword(OUStringToOString(
+ pPasswordRequest->getPassword(),
+ osl_getThreadTextEncoding()));
+ sal_Int32 nLen = aPassword.getLength();
+ char* pPassword = static_cast<char*>(PORT_Alloc( nLen+1 ) );
+ pPassword[nLen] = 0;
+ memcpy( pPassword, aPassword.getStr(), nLen );
+ return pPassword;
+ }
+ return nullptr;
+}
+
+SecurityEnvironment_NssImpl::SecurityEnvironment_NssImpl() :
+m_pHandler( nullptr ) {
+ PK11_SetPasswordFunc( GetPasswordFunction ) ;
+}
+
+SecurityEnvironment_NssImpl::~SecurityEnvironment_NssImpl() {
+
+ PK11_SetPasswordFunc( nullptr ) ;
+
+ for (auto& slot : m_Slots)
+ {
+ PK11_FreeSlot(slot);
+ }
+
+ for( auto& symKey : m_tSymKeyList )
+ PK11_FreeSymKey( symKey ) ;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL SecurityEnvironment_NssImpl::getImplementationName() {
+ return "com.sun.star.xml.crypto.SecurityEnvironment";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL SecurityEnvironment_NssImpl::supportsService( const OUString& serviceName) {
+ return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+Sequence< OUString > SAL_CALL SecurityEnvironment_NssImpl::getSupportedServiceNames() {
+ Sequence<OUString> seqServiceNames{ "com.sun.star.xml.crypto.SecurityEnvironment" };
+ return seqServiceNames;
+}
+
+OUString SecurityEnvironment_NssImpl::getSecurityEnvironmentInformation()
+{
+ OUStringBuffer buff;
+ for (auto& slot : m_Slots)
+ {
+ buff.appendAscii(PK11_GetTokenName(slot));
+ buff.append("\n");
+ }
+ return buff.makeStringAndClear();
+}
+
+void SecurityEnvironment_NssImpl::addCryptoSlot( PK11SlotInfo* aSlot)
+{
+ PK11_ReferenceSlot(aSlot);
+ m_Slots.push_back(aSlot);
+}
+
+//Could we have multiple cert dbs?
+void SecurityEnvironment_NssImpl::setCertDb( CERTCertDBHandle* aCertDb ) {
+ m_pHandler = aCertDb ;
+}
+
+void SecurityEnvironment_NssImpl::adoptSymKey( PK11SymKey* aSymKey ) {
+ if( aSymKey == nullptr ) return;
+
+ //First try to find the key in the list
+ if (std::find(m_tSymKeyList.begin(), m_tSymKeyList.end(), aSymKey) != m_tSymKeyList.end())
+ return;
+
+ //If we do not find the key in the list, add a new node
+ PK11SymKey* symkey = PK11_ReferenceSymKey( aSymKey ) ;
+ if( symkey == nullptr )
+ throw RuntimeException() ;
+
+ try {
+ m_tSymKeyList.push_back( symkey ) ;
+ } catch ( Exception& ) {
+ PK11_FreeSymKey( symkey ) ;
+ }
+}
+
+void SecurityEnvironment_NssImpl::updateSlots()
+{
+ //In case new tokens are present then we can obtain the corresponding slot
+ std::scoped_lock guard(m_mutex);
+
+ m_Slots.clear();
+ m_tSymKeyList.clear();
+
+ PK11SlotList * slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, nullptr ) ;
+ if( slotList == nullptr )
+ return;
+
+ for (PK11SlotListElement* slotEle = slotList->head ; slotEle != nullptr; slotEle = slotEle->next)
+ {
+ PK11SlotInfo * pSlot = slotEle->slot ;
+
+ if(pSlot != nullptr)
+ {
+ SAL_INFO(
+ "xmlsecurity.xmlsec",
+ "Found a slot: SlotName=" << PK11_GetSlotName(pSlot)
+ << ", TokenName=" << PK11_GetTokenName(pSlot));
+
+//The following code which is commented out checks if a slot, that is a smart card for example, is
+// able to generate a symmetric key of type CKM_DES3_CBC. If this fails then this token
+// will not be used. This key is possibly used for the encryption service. However, all
+// interfaces and services used for public key signature and encryption are not published
+// and the encryption is not used in OOo. Therefore it does not do any harm to remove
+// this code, hence allowing smart cards which cannot generate this type of key.
+//
+// By doing this, the encryption may fail if a smart card is being used which does not
+// support this key generation.
+//
+ PK11SymKey * pSymKey = PK11_KeyGen( pSlot , CKM_DES3_CBC, nullptr, 128, nullptr ) ;
+// if( pSymKey == NULL )
+// {
+// PK11_FreeSlot( pSlot ) ;
+// SAL_INFO( "xmlsecurity", "XMLSEC: Error - pSymKey is NULL" );
+// continue;
+// }
+ addCryptoSlot(pSlot);
+
+ if (pSymKey != nullptr)
+ {
+ adoptSymKey( pSymKey ) ;
+ PK11_FreeSymKey( pSymKey ) ;
+ pSymKey = nullptr;
+ }
+
+ }// end of if(pSlot != NULL)
+ }// end of for
+
+ PK11_FreeSlotList(slotList);
+}
+
+Sequence< Reference < XCertificate > >
+SecurityEnvironment_NssImpl::getPersonalCertificates()
+{
+ std::vector< rtl::Reference<X509Certificate_NssImpl> > certsList ;
+
+ updateSlots();
+ //firstly, we try to find private keys in slot
+ for (auto& slot : m_Slots)
+ {
+ SECKEYPrivateKeyList* priKeyList ;
+
+ if( PK11_NeedLogin(slot ) ) {
+ SECStatus nRet = PK11_Authenticate(slot, PR_TRUE, nullptr);
+ //PK11_Authenticate may fail in case the a slot has not been initialized.
+ //this is the case if the user has a new profile, so that they have never
+ //added a personal certificate.
+ if( nRet != SECSuccess && PORT_GetError() != SEC_ERROR_IO) {
+ throw NoPasswordException();
+ }
+ }
+
+ priKeyList = PK11_ListPrivateKeysInSlot(slot) ;
+ if( priKeyList != nullptr )
+ {
+ for (SECKEYPrivateKeyListNode* curPri = PRIVKEY_LIST_HEAD(priKeyList);
+ !PRIVKEY_LIST_END( curPri, priKeyList ) && curPri != nullptr;
+ curPri = PRIVKEY_LIST_NEXT(curPri))
+ {
+ rtl::Reference<X509Certificate_NssImpl> xcert = NssPrivKeyToXCert( curPri->key ) ;
+ if( xcert != nullptr )
+ certsList.push_back( xcert ) ;
+ }
+ SECKEY_DestroyPrivateKeyList( priKeyList ) ;
+ }
+
+
+ }
+
+ if( certsList.size() != 0 ) {
+ return comphelper::containerToSequence<Reference< XCertificate >>(certsList) ;
+ }
+
+ return Sequence< Reference < XCertificate > > ();
+}
+
+Reference< XCertificate > SecurityEnvironment_NssImpl::getCertificate( const OUString& issuerName, const Sequence< sal_Int8 >& serialNumber )
+{
+ if( !m_pHandler )
+ return nullptr;
+
+ rtl::Reference<X509Certificate_NssImpl> xcert;
+ CERTIssuerAndSN issuerAndSN ;
+ CERTCertificate* cert ;
+ CERTName* nmIssuer ;
+ char* chIssuer ;
+ SECItem* derIssuer ;
+ std::unique_ptr<PRArenaPool> arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if( arena == nullptr )
+ throw RuntimeException() ;
+
+ // Create cert info from issue and serial
+ OString ostr = OUStringToOString( issuerName , RTL_TEXTENCODING_UTF8 ) ;
+ chIssuer = PL_strndup( ostr.getStr(), static_cast<int>(ostr.getLength()) ) ;
+ nmIssuer = CERT_AsciiToName( chIssuer ) ;
+ if( nmIssuer == nullptr ) {
+ PL_strfree( chIssuer ) ;
+ return nullptr; // no need for exception cf. i40394
+ }
+
+ derIssuer = SEC_ASN1EncodeItem( arena.get(), nullptr, static_cast<void*>(nmIssuer), SEC_ASN1_GET( CERT_NameTemplate ) ) ;
+ if( derIssuer == nullptr ) {
+ PL_strfree( chIssuer ) ;
+ CERT_DestroyName( nmIssuer ) ;
+ throw RuntimeException() ;
+ }
+
+ memset( &issuerAndSN, 0, sizeof( issuerAndSN ) ) ;
+
+ issuerAndSN.derIssuer.data = derIssuer->data ;
+ issuerAndSN.derIssuer.len = derIssuer->len ;
+
+ issuerAndSN.serialNumber.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(serialNumber.getConstArray()));
+ issuerAndSN.serialNumber.len = serialNumber.getLength() ;
+
+ cert = CERT_FindCertByIssuerAndSN( m_pHandler, &issuerAndSN ) ;
+ if( cert != nullptr ) {
+ xcert = NssCertToXCert( cert ) ;
+ }
+
+ PL_strfree( chIssuer ) ;
+ CERT_DestroyName( nmIssuer ) ;
+ //SECITEM_FreeItem( derIssuer, PR_FALSE ) ;
+ CERT_DestroyCertificate( cert ) ;
+
+ return xcert ;
+}
+
+Sequence< Reference < XCertificate > > SecurityEnvironment_NssImpl::buildCertificatePath( const Reference< XCertificate >& begin ) {
+
+ X509Certificate_NssImpl* xcert = dynamic_cast<X509Certificate_NssImpl*>(begin.get());
+ if( xcert == nullptr ) {
+ throw RuntimeException() ;
+ }
+
+ // Remember the signing certificate.
+ m_xSigningCertificate = xcert;
+
+ const CERTCertificate* cert = xcert->getNssCert() ;
+ if (!cert)
+ return {};
+
+ //Get the system clock time
+ int64 timeboundary = PR_Now() ;
+ CERTCertList* certChain = CERT_GetCertChainFromCert( const_cast<CERTCertificate*>(cert), timeboundary, certUsageAnyCA ) ;
+
+ if( !certChain )
+ return {};
+
+ std::vector<uno::Reference<security::XCertificate>> aCertChain;
+
+ for (CERTCertListNode* node = CERT_LIST_HEAD(certChain); !CERT_LIST_END(node, certChain); node = CERT_LIST_NEXT(node)) {
+ rtl::Reference<X509Certificate_NssImpl> pCert = new X509Certificate_NssImpl();
+ if( pCert == nullptr ) {
+ CERT_DestroyCertList( certChain ) ;
+ throw RuntimeException() ;
+ }
+
+ pCert->setCert( node->cert ) ;
+
+ aCertChain.push_back(pCert);
+ }
+
+ CERT_DestroyCertList( certChain ) ;
+
+ return comphelper::containerToSequence(aCertChain);
+}
+
+rtl::Reference<X509Certificate_NssImpl> SecurityEnvironment_NssImpl::createAndAddCertificateFromPackage(
+ const css::uno::Sequence<sal_Int8>& raDERCertificate,
+ std::u16string_view raString)
+{
+ auto pCertificateBytes = reinterpret_cast<char *>(const_cast<sal_Int8 *>(raDERCertificate.getConstArray()));
+ CERTCertificate* pCERTCertificate = CERT_DecodeCertFromPackage(pCertificateBytes, raDERCertificate.getLength());
+
+ if (!pCERTCertificate)
+ return nullptr;
+
+ SECStatus aStatus;
+
+ OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US);
+ CERTCertTrust aTrust;
+
+ aStatus = CERT_DecodeTrustString(&aTrust, aTrustString.getStr());
+
+ if (aStatus != SECSuccess)
+ {
+ PRIntn err = PR_GetError();
+ SAL_WARN("xmlsecurity.xmlsec", "Error: " << err << ": " << getCertError(err));
+ return nullptr;
+ }
+
+ PK11SlotInfo* pSlot = PK11_GetInternalKeySlot();
+
+ if (!pSlot)
+ return nullptr;
+
+ aStatus = PK11_ImportCert(pSlot, pCERTCertificate, CK_INVALID_HANDLE, nullptr, PR_FALSE);
+
+ if (aStatus != SECSuccess)
+ {
+ PRIntn err = PR_GetError();
+ SAL_WARN("xmlsecurity.xmlsec", "Error: " << err << ": " << getCertError(err));
+ return nullptr;
+ }
+
+ aStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust);
+
+ if (aStatus != SECSuccess)
+ {
+ PRIntn err = PR_GetError();
+ SAL_WARN("xmlsecurity.xmlsec", "Error: " << err << ": " << getCertError(err));
+ return nullptr;
+ }
+
+ PK11_FreeSlot(pSlot);
+
+ rtl::Reference<X509Certificate_NssImpl> pX509Certificate = new X509Certificate_NssImpl();
+ pX509Certificate->setCert(pCERTCertificate);
+ return pX509Certificate;
+}
+
+rtl::Reference<X509Certificate_NssImpl> SecurityEnvironment_NssImpl::createX509CertificateFromDER(const css::uno::Sequence<sal_Int8>& aDerCertificate)
+{
+ rtl::Reference<X509Certificate_NssImpl> pX509Certificate;
+
+ if (aDerCertificate.hasElements())
+ {
+ pX509Certificate = new X509Certificate_NssImpl();
+ if (pX509Certificate == nullptr)
+ throw RuntimeException();
+ pX509Certificate->setRawCert(aDerCertificate);
+ }
+ return pX509Certificate;
+}
+
+Reference<XCertificate> SecurityEnvironment_NssImpl::createCertificateFromRaw(const Sequence< sal_Int8 >& rawCertificate)
+{
+ return createX509CertificateFromDER(rawCertificate);
+}
+
+Reference< XCertificate > SecurityEnvironment_NssImpl::createCertificateFromAscii( const OUString& asciiCertificate )
+{
+ OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;
+ xmlChar* chCert = xmlStrndup( reinterpret_cast<const xmlChar*>(oscert.getStr()), static_cast<int>(oscert.getLength()) ) ;
+ xmlSecSize certSize;
+ int nRet = xmlSecBase64Decode_ex( chCert, reinterpret_cast<xmlSecByte*>(chCert), xmlStrlen( chCert ), &certSize ) ;
+ if (nRet < 0 || certSize == 0)
+ {
+ xmlFree(chCert);
+ return nullptr;
+ }
+
+ Sequence< sal_Int8 > rawCert(comphelper::arrayToSequence<sal_Int8>(chCert, certSize)) ;
+
+ xmlFree( chCert ) ;
+
+ return createCertificateFromRaw( rawCert ) ;
+}
+
+sal_Int32 SecurityEnvironment_NssImpl ::
+verifyCertificate( const Reference< csss::XCertificate >& aCert,
+ const Sequence< Reference< csss::XCertificate > >& intermediateCerts )
+{
+ sal_Int32 validity = csss::CertificateValidity::INVALID;
+ const CERTCertificate* cert ;
+
+ SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName());
+
+ const X509Certificate_NssImpl* xcert = dynamic_cast<X509Certificate_NssImpl*>(aCert.get());
+ if( xcert == nullptr ) {
+ throw RuntimeException() ;
+ }
+
+ //CERT_PKIXVerifyCert does not take a db as argument. It will therefore
+ //internally use CERT_GetDefaultCertDB
+ //Make sure m_pHandler is the default DB
+ OSL_ASSERT(m_pHandler == CERT_GetDefaultCertDB());
+ CERTCertDBHandle * certDb = m_pHandler != nullptr ? m_pHandler : CERT_GetDefaultCertDB();
+ cert = xcert->getNssCert() ;
+ if( !cert )
+ return css::security::CertificateValidity::INVALID;
+
+
+ ::std::vector<CERTCertificate*> vecTmpNSSCertificates;
+
+ //prepare the intermediate certificates
+ for (const auto& rIntermediateCert : intermediateCerts)
+ {
+ Sequence<sal_Int8> der = rIntermediateCert->getEncoded();
+ SECItem item;
+ item.type = siBuffer;
+ item.data = reinterpret_cast<unsigned char*>(der.getArray());
+ item.len = der.getLength();
+
+ CERTCertificate* certTmp = CERT_NewTempCertificate(certDb, &item,
+ nullptr /* nickname */,
+ PR_FALSE /* isPerm */,
+ PR_TRUE /* copyDER */);
+ if (!certTmp)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Failed to add a temporary certificate: " << rIntermediateCert->getIssuerName());
+
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " <<
+ (certTmp->subjectName ? certTmp->subjectName : ""));
+ vecTmpNSSCertificates.push_back(certTmp);
+ }
+ }
+
+
+ SECStatus status ;
+
+ CERTVerifyLog log;
+ log.arena = PORT_NewArena(512);
+ log.head = log.tail = nullptr;
+ log.count = 0;
+
+ CERT_EnableOCSPChecking(certDb);
+ CERT_DisableOCSPDefaultResponder(certDb);
+ CERTValOutParam cvout[5];
+ CERTValInParam cvin[3];
+ int ncvinCount=0;
+
+#if ( NSS_VMAJOR > 3 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR > 12 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH > 0 )
+ cvin[ncvinCount].type = cert_pi_useAIACertFetch;
+ cvin[ncvinCount].value.scalar.b = PR_TRUE;
+ ncvinCount++;
+#endif
+
+ PRUint64 revFlagsLeaf[2];
+ PRUint64 revFlagsChain[2];
+ CERTRevocationFlags rev;
+ rev.leafTests.number_of_defined_methods = 2;
+ rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf;
+ //the flags are defined in cert.h
+ //We check both leaf and chain.
+ //It is enough if one revocation method has fresh info,
+ //but at least one must have some. Otherwise validation fails.
+ //!!! using leaf test and CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE
+ // when validating a root certificate will result in "revoked". Usually
+ //there is no revocation information available for the root cert because
+ //it must be trusted anyway and it does itself issue revocation information.
+ //When we use the flag here and OOo shows the certification path then the root
+ //cert is invalid while all other can be valid. It would probably best if
+ //this interface method returned the whole chain.
+ //Otherwise we need to check if the certificate is self-signed and if it is
+ //then not use the flag when doing the leaf-test.
+ rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
+ CERT_REV_M_TEST_USING_THIS_METHOD
+ | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
+ rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
+ CERT_REV_M_TEST_USING_THIS_METHOD
+ | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
+ rev.leafTests.number_of_preferred_methods = 0;
+ rev.leafTests.preferred_methods = nullptr;
+ rev.leafTests.cert_rev_method_independent_flags =
+ CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
+
+ rev.chainTests.number_of_defined_methods = 2;
+ rev.chainTests.cert_rev_flags_per_method = revFlagsChain;
+ rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
+ CERT_REV_M_TEST_USING_THIS_METHOD
+ | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
+ rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
+ CERT_REV_M_TEST_USING_THIS_METHOD
+ | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
+ rev.chainTests.number_of_preferred_methods = 0;
+ rev.chainTests.preferred_methods = nullptr;
+ rev.chainTests.cert_rev_method_independent_flags =
+ CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
+
+
+ cvin[ncvinCount].type = cert_pi_revocationFlags;
+ cvin[ncvinCount].value.pointer.revocation = &rev;
+ ncvinCount++;
+ // does not work, not implemented yet in 3.12.4
+// cvin[ncvinCount].type = cert_pi_keyusage;
+// cvin[ncvinCount].value.scalar.ui = KU_DIGITAL_SIGNATURE;
+// ncvinCount++;
+ cvin[ncvinCount].type = cert_pi_end;
+
+ cvout[0].type = cert_po_trustAnchor;
+ cvout[0].value.pointer.cert = nullptr;
+ cvout[1].type = cert_po_errorLog;
+ cvout[1].value.pointer.log = &log;
+ cvout[2].type = cert_po_end;
+
+ // We check SSL server certificates, CA certificates and signing certificates.
+ //
+ // ToDo check keyusage, looking at CERT_KeyUsageAndTypeForCertUsage (
+ // mozilla/security/nss/lib/certdb/certdb.c indicates that
+ // certificateUsageSSLClient, certificateUsageSSLServer and certificateUsageSSLCA
+ // are sufficient. They cover the key usages for digital signature, key agreement
+ // and encipherment and certificate signature
+
+ //never use the following usages because they are not checked properly
+ // certificateUsageUserCertImport
+ // certificateUsageVerifyCA
+ // certificateUsageAnyCA
+ // certificateUsageProtectedObjectSigner
+
+ UsageDescription arUsages[5];
+ arUsages[0] = UsageDescription( certificateUsageSSLClient, "certificateUsageSSLClient" );
+ arUsages[1] = UsageDescription( certificateUsageSSLServer, "certificateUsageSSLServer" );
+ arUsages[2] = UsageDescription( certificateUsageSSLCA, "certificateUsageSSLCA" );
+ arUsages[3] = UsageDescription( certificateUsageEmailSigner, "certificateUsageEmailSigner" );
+ arUsages[4] = UsageDescription( certificateUsageEmailRecipient, "certificateUsageEmailRecipient" );
+
+ int numUsages = std::size(arUsages);
+ for (int i = 0; i < numUsages; i++)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Testing usage " << i+1 <<
+ " of " << numUsages << ": " <<
+ arUsages[i].description <<
+ " (0x" << std::hex << static_cast<int>(arUsages[i].usage) << ")" << std::dec);
+
+ status = CERT_PKIXVerifyCert(const_cast<CERTCertificate *>(cert), arUsages[i].usage,
+ cvin, cvout, nullptr);
+ if( status == SECSuccess )
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "CERT_PKIXVerifyCert returned SECSuccess.");
+ //When an intermediate or root certificate is checked then we expect the usage
+ //certificateUsageSSLCA. This, however, will be only set when in the trust settings dialog
+ //the button "This certificate can identify websites" is checked. If for example only
+ //"This certificate can identify mail users" is set then the end certificate can
+ //be validated and the returned usage will contain certificateUsageEmailRecipient.
+ //But checking directly the root or intermediate certificate will fail. In the
+ //certificate path view the end certificate will be shown as valid but the others
+ //will be displayed as invalid.
+
+ validity = csss::CertificateValidity::VALID;
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
+ CERTCertificate * issuerCert = cvout[0].value.pointer.cert;
+ if (issuerCert)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Root certificate: " << issuerCert->subjectName);
+ CERT_DestroyCertificate(issuerCert);
+ };
+
+ break;
+ }
+ else
+ {
+ PRIntn err = PR_GetError();
+ SAL_INFO("xmlsecurity.xmlsec", "Error: " << err << ": " << getCertError(err));
+
+ /* Display validation results */
+ if ( log.count > 0)
+ {
+ CERTVerifyLogNode *node = nullptr;
+ printChainFailure(&log);
+
+ for (node = log.head; node; node = node->next) {
+ if (node->cert)
+ CERT_DestroyCertificate(node->cert);
+ }
+ log.head = log.tail = nullptr;
+ log.count = 0;
+ }
+ SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
+ }
+ }
+
+ //Destroying the temporary certificates
+ for (auto& tmpCert : vecTmpNSSCertificates)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "Destroying temporary certificate");
+ CERT_DestroyCertificate(tmpCert);
+ }
+ PORT_FreeArena(log.arena, true);
+ return validity ;
+}
+
+sal_Int32 SecurityEnvironment_NssImpl::getCertificateCharacters(
+ const css::uno::Reference< css::security::XCertificate >& aCert ) {
+ sal_Int32 characters ;
+ const CERTCertificate* cert ;
+
+ const X509Certificate_NssImpl* xcert = dynamic_cast<X509Certificate_NssImpl*>(aCert.get());
+ if( xcert == nullptr ) {
+ throw RuntimeException() ;
+ }
+
+ cert = xcert->getNssCert() ;
+
+ characters = 0x00000000 ;
+
+ //Firstly, find out whether or not the cert is self-signed.
+ if( SECITEM_CompareItem( &(cert->derIssuer), &(cert->derSubject) ) == SECEqual ) {
+ characters |= css::security::CertificateCharacters::SELF_SIGNED ;
+ } else {
+ characters &= ~ css::security::CertificateCharacters::SELF_SIGNED ;
+ }
+
+ //Secondly, find out whether or not the cert has a private key.
+
+ /*
+ * i40394
+ *
+ * mmi : need to check whether the cert's slot is valid first
+ */
+ SECKEYPrivateKey* priKey = nullptr;
+
+ if (cert->slot != nullptr)
+ {
+ priKey = PK11_FindPrivateKeyFromCert( cert->slot, const_cast<CERTCertificate*>(cert), nullptr ) ;
+ }
+ if(priKey == nullptr)
+ {
+ for (auto& slot : m_Slots)
+ {
+ priKey = PK11_FindPrivateKeyFromCert(slot, const_cast<CERTCertificate*>(cert), nullptr);
+ if (priKey)
+ break;
+ }
+ }
+ if( priKey != nullptr ) {
+ characters |= css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
+
+ SECKEY_DestroyPrivateKey( priKey ) ;
+ } else {
+ characters &= ~ css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
+ }
+
+ return characters ;
+}
+
+rtl::Reference<X509Certificate_NssImpl> NssCertToXCert( CERTCertificate* cert )
+{
+ if( cert != nullptr ) {
+ rtl::Reference<X509Certificate_NssImpl> xcert = new X509Certificate_NssImpl() ;
+ xcert->setCert( cert ) ;
+ return xcert;
+ }
+
+ return nullptr;
+}
+
+rtl::Reference<X509Certificate_NssImpl> NssPrivKeyToXCert( SECKEYPrivateKey* priKey )
+{
+ if( priKey != nullptr ) {
+ rtl::Reference<X509Certificate_NssImpl> xcert;
+ CERTCertificate* cert = PK11_GetCertFromPrivateKey( priKey ) ;
+
+ if( cert != nullptr ) {
+ xcert = NssCertToXCert( cert ) ;
+ }
+
+ CERT_DestroyCertificate( cert ) ;
+ return xcert;
+ }
+
+ return nullptr;
+}
+
+xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() {
+
+ /*-
+ * The following lines is based on the private version of xmlSec-NSS
+ * crypto engine
+ */
+ int cSlots = m_Slots.size();
+ std::unique_ptr<PK11SlotInfo*[]> sarSlots(new PK11SlotInfo*[cSlots]);
+ PK11SlotInfo** slots = sarSlots.get();
+ int count = 0;
+ for (const auto& slot : m_Slots)
+ {
+ slots[count] = slot;
+ ++count;
+ }
+
+ xmlSecKeysMngrPtr pKeysMngr = xmlSecKeysMngrCreate();
+ if (!pKeysMngr)
+ throw RuntimeException();
+
+ if (xmlSecNssAppDefaultKeysMngrInit(pKeysMngr) < 0)
+ throw RuntimeException();
+
+ // Adopt the private key of the signing certificate, if it has any.
+ if (m_xSigningCertificate)
+ {
+ SECKEYPrivateKey* pPrivateKey = SECKEY_CopyPrivateKey(m_xSigningCertificate->getPrivateKey());
+ if (pPrivateKey)
+ {
+ xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(pPrivateKey, nullptr);
+ xmlSecKeyPtr pKey = xmlSecKeyCreate();
+ xmlSecKeySetValue(pKey, pKeyData);
+ xmlSecNssAppDefaultKeysMngrAdoptKey(pKeysMngr, pKey);
+ }
+ else
+ {
+ SAL_WARN("xmlsecurity.xmlsec", "Can't get the private key from the certificate.");
+ }
+ }
+
+ return pKeysMngr;
+}
+
+void SecurityEnvironment_NssImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) {
+ if( pKeysMngr != nullptr ) {
+ xmlSecKeysMngrDestroy( pKeysMngr ) ;
+ }
+}
+
+SECKEYPrivateKey* SecurityEnvironment_NssImpl::insertPrivateKey(css::uno::Sequence<sal_Int8> const & raPrivateKey)
+{
+ PK11SlotInfo* pSlot = PK11_GetInternalKeySlot();
+
+ if (!pSlot)
+ return nullptr;
+
+ SECItem aDerPrivateKeyInfo;
+ aDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray()));
+ aDerPrivateKeyInfo.len = raPrivateKey.getLength();
+
+ const unsigned int aKeyUsage = KU_ALL;
+ SECKEYPrivateKey* pPrivateKey = nullptr;
+
+ bool bPermanent = PR_FALSE;
+ bool bPrivate = PR_TRUE;
+
+ SECStatus nStatus = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ pSlot, &aDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bPrivate,
+ aKeyUsage, &pPrivateKey, nullptr);
+
+ if (nStatus != SECSuccess)
+ return nullptr;
+
+ PK11_FreeSlot(pSlot);
+
+ return pPrivateKey;
+}
+
+uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::createDERCertificateWithPrivateKey(
+ Sequence<sal_Int8> const & raDERCertificate, Sequence<sal_Int8> const & raPrivateKey)
+{
+ SECKEYPrivateKey* pPrivateKey = insertPrivateKey(raPrivateKey);
+
+ if (!pPrivateKey)
+ return uno::Reference<security::XCertificate>();
+
+ return createAndAddCertificateFromPackage(raDERCertificate, u"TCu,TCu,TCu");
+}
+
+uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::addDERCertificateToTheDatabase(
+ uno::Sequence<sal_Int8> const & raDERCertificate, OUString const & raTrustString)
+{
+ return createAndAddCertificateFromPackage(raDERCertificate, raTrustString);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_SecurityEnvironment_get_implementation(
+ uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new SecurityEnvironment_NssImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.hxx
new file mode 100644
index 0000000000..c0e4698998
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp>
+#include <com/sun/star/xml/crypto/XCertificateCreator.hpp>
+
+#include <mutex>
+
+#include <keythi.h>
+#include <certt.h>
+
+#include <string_view>
+#include <vector>
+
+#include <xmlsec-wrapper.h>
+
+namespace com::sun::star::security { class XCertificate; }
+class X509Certificate_NssImpl;
+
+class SecurityEnvironment_NssImpl : public ::cppu::WeakImplHelper<
+ css::xml::crypto::XSecurityEnvironment,
+ css::xml::crypto::XCertificateCreator,
+ css::lang::XServiceInfo >
+{
+private:
+
+ std::vector< PK11SlotInfo* > m_Slots;
+ /// The last used certificate which has the private key for signing.
+ rtl::Reference<X509Certificate_NssImpl> m_xSigningCertificate;
+
+ std::mutex m_mutex;
+
+ CERTCertDBHandle* m_pHandler ;
+ std::vector< PK11SymKey* > m_tSymKeyList ;
+
+ public:
+ SecurityEnvironment_NssImpl();
+ virtual ~SecurityEnvironment_NssImpl() override;
+
+ //Methods from XSecurityEnvironment
+
+ //Methods from XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override ;
+
+ virtual sal_Bool SAL_CALL supportsService(
+ const OUString& ServiceName
+ ) override ;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override ;
+
+ virtual ::sal_Int32 SAL_CALL verifyCertificate(
+ const css::uno::Reference<
+ css::security::XCertificate >& xCert,
+ const css::uno::Sequence<
+ css::uno::Reference< css::security::XCertificate > > &
+ intermediateCerts) override ;
+
+ virtual ::sal_Int32 SAL_CALL getCertificateCharacters( const css::uno::Reference< css::security::XCertificate >& xCert ) override ;
+
+ virtual OUString SAL_CALL getSecurityEnvironmentInformation( ) override;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void setCertDb( CERTCertDBHandle* aCertDb ) ;
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void adoptSymKey( PK11SymKey* aSymKey ) ;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getPersonalCertificates() override ;
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getAllCertificates() override
+ { return css::uno::Sequence< css::uno::Reference< css::security::XCertificate > >(); }
+
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL getCertificate( const OUString& issuerName, const css::uno::Sequence< sal_Int8 >& serialNumber ) override ;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL buildCertificatePath( const css::uno::Reference< css::security::XCertificate >& beginCert ) override ;
+
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromRaw( const css::uno::Sequence< sal_Int8 >& rawCertificate ) override ;
+ virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromAscii( const OUString& asciiCertificate ) override ;
+
+ // Methods of XCertificateCreator
+ css::uno::Reference<css::security::XCertificate> SAL_CALL addDERCertificateToTheDatabase(
+ css::uno::Sequence<sal_Int8> const & raDERCertificate,
+ OUString const & raTrustString) override;
+
+ css::uno::Reference<css::security::XCertificate> SAL_CALL createDERCertificateWithPrivateKey(
+ css::uno::Sequence<sal_Int8> const & raDERCertificate,
+ css::uno::Sequence<sal_Int8> const & raPrivateKey) override;
+
+ //Native methods
+ /// @throws css::uno::RuntimeException
+ xmlSecKeysMngrPtr createKeysManager() ;
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ static void destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) ;
+
+private:
+
+ void updateSlots();
+
+ static rtl::Reference<X509Certificate_NssImpl> createAndAddCertificateFromPackage(
+ const css::uno::Sequence<sal_Int8>& raDerCertificate,
+ std::u16string_view raString);
+ static SECKEYPrivateKey* insertPrivateKey(css::uno::Sequence<sal_Int8> const & raPrivateKey);
+
+ static rtl::Reference<X509Certificate_NssImpl> createX509CertificateFromDER(const css::uno::Sequence<sal_Int8>& raDerCertificate);
+
+ /// @throws css::uno::Exception
+ /// @throws css::uno::RuntimeException
+ void addCryptoSlot( PK11SlotInfo* aSlot ) ;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.cxx
new file mode 100644
index 0000000000..6b5c3d6c5b
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/types.h>
+#include <com/sun/star/xml/crypto/SecurityEnvironment.hpp>
+#include <com/sun/star/xml/crypto/XMLSecurityContext.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include "seinitializer_nssimpl.hxx"
+#include "securityenvironment_nssimpl.hxx"
+
+#include <cert.h>
+
+
+using namespace com::sun::star;
+
+
+SEInitializer_NssImpl::SEInitializer_NssImpl( const css::uno::Reference< css::uno::XComponentContext > &rxContext )
+{
+ m_xContext = rxContext;
+}
+
+SEInitializer_NssImpl::~SEInitializer_NssImpl()
+{
+}
+
+/* XSEInitializer */
+uno::Reference< css::xml::crypto::XXMLSecurityContext > SAL_CALL
+ SEInitializer_NssImpl::createSecurityContext( const OUString& )
+{
+ CERTCertDBHandle *pCertHandle = nullptr ;
+
+ if( !initNSS( m_xContext ) )
+ return nullptr;
+
+ pCertHandle = CERT_GetDefaultCertDB() ;
+
+ try
+ {
+ /* Build XML Security Context */
+ uno::Reference< css::xml::crypto::XXMLSecurityContext > xSecCtx = css::xml::crypto::XMLSecurityContext::create( m_xContext );
+
+ uno::Reference< css::xml::crypto::XSecurityEnvironment > xSecEnv = css::xml::crypto::SecurityEnvironment::create( m_xContext );
+ SecurityEnvironment_NssImpl* pSecEnv = dynamic_cast<SecurityEnvironment_NssImpl*>(xSecEnv.get());
+ assert(pSecEnv && "can only succeed");
+ pSecEnv->setCertDb(pCertHandle);
+
+ sal_Int32 n = xSecCtx->addSecurityEnvironment(xSecEnv);
+ //originally the SecurityEnvironment with the internal slot was set as default
+ xSecCtx->setDefaultSecurityEnvironmentIndex( n );
+ return xSecCtx;
+ }
+ catch( const uno::Exception& )
+ {
+ //PK11_LogoutAll();
+ //NSS_Shutdown();
+ return nullptr;
+ }
+}
+
+void SAL_CALL SEInitializer_NssImpl::freeSecurityContext( const uno::Reference< css::xml::crypto::XXMLSecurityContext >& )
+{
+ /*
+ * because the security context will free all its content when it
+ * is destructed, so here no free process for the security context
+ * is needed.
+ */
+ //PK11_LogoutAll();
+ //NSS_Shutdown();
+}
+
+/* XServiceInfo */
+OUString SAL_CALL SEInitializer_NssImpl::getImplementationName( )
+{
+ return "com.sun.star.xml.crypto.SEInitializer";
+}
+sal_Bool SAL_CALL SEInitializer_NssImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+uno::Sequence< OUString > SAL_CALL SEInitializer_NssImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.xml.crypto.SEInitializer" };
+}
+
+namespace {
+
+class NSSInitializer_NssImpl : public SEInitializer_NssImpl
+{
+public:
+ explicit NSSInitializer_NssImpl(const uno::Reference<uno::XComponentContext>& xContext);
+ OUString SAL_CALL getImplementationName() override;
+ uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+NSSInitializer_NssImpl::NSSInitializer_NssImpl(const uno::Reference<uno::XComponentContext>& xContext)
+ : SEInitializer_NssImpl(xContext)
+{
+}
+
+OUString NSSInitializer_NssImpl::getImplementationName()
+{
+ return "com.sun.star.xml.crypto.NSSInitializer";
+}
+
+uno::Sequence<OUString> SAL_CALL NSSInitializer_NssImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.xml.crypto.NSSInitializer" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_NSSInitializer_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new NSSInitializer_NssImpl(pCtx));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_SEInitializer_get_implementation(
+ uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new SEInitializer_NssImpl(pCtx));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.hxx
new file mode 100644
index 0000000000..f078f387af
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/seinitializer_nssimpl.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include "nssinitializer.hxx"
+
+namespace com::sun::star::xml::crypto { class XXMLSecurityContext; }
+
+class SEInitializer_NssImpl : public cppu::ImplInheritanceHelper
+<
+ ONSSInitializer,
+ css::xml::crypto::XSEInitializer
+>
+{
+public:
+ explicit SEInitializer_NssImpl(const css::uno::Reference<css::uno::XComponentContext > &rxContext);
+ virtual ~SEInitializer_NssImpl() override;
+
+ /* XSEInitializer */
+ virtual css::uno::Reference< css::xml::crypto::XXMLSecurityContext >
+ SAL_CALL createSecurityContext( const OUString& ) override;
+
+ virtual void SAL_CALL freeSecurityContext( const css::uno::Reference<
+ css::xml::crypto::XXMLSecurityContext >& securityContext ) override;
+
+ /* XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
new file mode 100644
index 0000000000..e1526ea90d
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx
@@ -0,0 +1,602 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "nssrenam.h"
+#include <secder.h>
+
+#include <cert.h>
+#include <pk11pub.h>
+#include <hasht.h>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include "x509certificate_nssimpl.hxx"
+
+#include <biginteger.hxx>
+#include <certificateextension_xmlsecimpl.hxx>
+
+#include "sanextension_nssimpl.hxx"
+#include <o3tl/string_view.hxx>
+#include <tools/time.hxx>
+#include <svl/sigstruct.hxx>
+
+using ::css::util::DateTime;
+
+X509Certificate_NssImpl::X509Certificate_NssImpl() :
+ m_pCert(nullptr)
+{
+}
+
+X509Certificate_NssImpl::~X509Certificate_NssImpl() {
+ if( m_pCert != nullptr ) {
+ CERT_DestroyCertificate( m_pCert ) ;
+ }
+}
+
+//Methods from XCertificate
+sal_Int16 SAL_CALL X509Certificate_NssImpl::getVersion() {
+ if( m_pCert != nullptr ) {
+ if( m_pCert->version.len > 0 ) {
+ return static_cast<char>(*( m_pCert->version.data )) ;
+ } else
+ return 0 ;
+ } else {
+ return -1 ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSerialNumber() {
+ if( m_pCert != nullptr && m_pCert->serialNumber.len > 0 ) {
+ return comphelper::arrayToSequence<sal_Int8>(m_pCert->serialNumber.data,
+ m_pCert->serialNumber.len) ;
+ } else {
+ return css::uno::Sequence< sal_Int8 >();
+ }
+}
+
+OUString SAL_CALL X509Certificate_NssImpl::getIssuerName() {
+ if( m_pCert != nullptr ) {
+ return OUString(m_pCert->issuerName , PL_strlen(m_pCert->issuerName) , RTL_TEXTENCODING_UTF8) ;
+ } else {
+ return OUString() ;
+ }
+}
+
+OUString SAL_CALL X509Certificate_NssImpl::getSubjectName() {
+ if( m_pCert != nullptr ) {
+ return OUString(m_pCert->subjectName , PL_strlen(m_pCert->subjectName) , RTL_TEXTENCODING_UTF8);
+ } else {
+ return OUString() ;
+ }
+}
+
+css::util::DateTime SAL_CALL X509Certificate_NssImpl::getNotValidBefore() {
+ if( m_pCert != nullptr ) {
+ SECStatus rv ;
+ PRTime notBefore ;
+ PRExplodedTime explTime ;
+ DateTime dateTime ;
+
+ rv = DER_DecodeTimeChoice( &notBefore, &m_pCert->validity.notBefore ) ;
+ if( rv != SECStatus::SECSuccess ) {
+ return DateTime() ;
+ }
+
+ //Convert the time to readable local time
+ PR_ExplodeTime( notBefore, PR_LocalTimeParameters, &explTime ) ;
+
+ dateTime.NanoSeconds = static_cast< sal_Int32 >( explTime.tm_usec * ::tools::Time::nanoPerMicro );
+ dateTime.Seconds = static_cast< sal_Int16 >( explTime.tm_sec );
+ dateTime.Minutes = static_cast< sal_Int16 >( explTime.tm_min );
+ dateTime.Hours = static_cast< sal_Int16 >( explTime.tm_hour );
+ dateTime.Day = static_cast< sal_Int16 >( explTime.tm_mday );
+ dateTime.Month = static_cast< sal_Int16 >( explTime.tm_month+1 );
+ dateTime.Year = static_cast< sal_Int16 >( explTime.tm_year );
+
+ return dateTime ;
+ } else {
+ return DateTime() ;
+ }
+}
+
+css::util::DateTime SAL_CALL X509Certificate_NssImpl::getNotValidAfter() {
+ if( m_pCert != nullptr ) {
+ SECStatus rv ;
+ PRTime notAfter ;
+ PRExplodedTime explTime ;
+ DateTime dateTime ;
+
+ rv = DER_DecodeTimeChoice( &notAfter, &m_pCert->validity.notAfter ) ;
+ if( rv != SECStatus::SECSuccess ) {
+ return DateTime() ;
+ }
+
+ //Convert the time to readable local time
+ PR_ExplodeTime( notAfter, PR_LocalTimeParameters, &explTime ) ;
+
+ dateTime.NanoSeconds = static_cast< sal_Int16 >( explTime.tm_usec * ::tools::Time::nanoPerMicro );
+ dateTime.Seconds = static_cast< sal_Int16 >( explTime.tm_sec );
+ dateTime.Minutes = static_cast< sal_Int16 >( explTime.tm_min );
+ dateTime.Hours = static_cast< sal_Int16 >( explTime.tm_hour );
+ dateTime.Day = static_cast< sal_Int16 >( explTime.tm_mday );
+ dateTime.Month = static_cast< sal_Int16 >( explTime.tm_month+1 );
+ dateTime.Year = static_cast< sal_Int16 >( explTime.tm_year );
+
+ return dateTime ;
+ } else {
+ return DateTime() ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getIssuerUniqueID() {
+ if( m_pCert != nullptr && m_pCert->issuerID.len > 0 ) {
+ return comphelper::arrayToSequence<sal_Int8>(m_pCert->issuerID.data, m_pCert->issuerID.len) ;
+ } else {
+ return css::uno::Sequence< sal_Int8 >();
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSubjectUniqueID() {
+ if( m_pCert != nullptr && m_pCert->subjectID.len > 0 ) {
+ return comphelper::arrayToSequence<sal_Int8>(m_pCert->subjectID.data,
+ m_pCert->subjectID.len) ;
+ } else {
+ return css::uno::Sequence< sal_Int8 >();
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL X509Certificate_NssImpl::getExtensions() {
+ if( m_pCert != nullptr && m_pCert->extensions != nullptr ) {
+ CERTCertExtension** extns ;
+ int len ;
+
+ for( len = 0, extns = m_pCert->extensions; *extns != nullptr; len ++, extns ++ ) ;
+ css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > xExtns( len ) ;
+ auto xExtnsRange = asNonConstRange(xExtns);
+
+ for( extns = m_pCert->extensions, len = 0; *extns != nullptr; extns ++, len ++ ) {
+ const SECItem id = (*extns)->id;
+ OString oidString(CERT_GetOidString(&id));
+
+ bool crit;
+ if( (*extns)->critical.data == nullptr )
+ crit = false ;
+ else
+ crit = (*extns)->critical.data[0] == 0xFF;
+
+ // remove "OID." prefix if existing
+ OString objID;
+ constexpr std::string_view oid("OID.");
+ if (oidString.match(oid))
+ objID = oidString.copy(oid.size());
+ else
+ objID = oidString;
+
+ unsigned char* value = (*extns)->value.data;
+ unsigned int vlen = (*extns)->value.len;
+ unsigned char* objid = reinterpret_cast<unsigned char *>(const_cast<char *>(objID.getStr()));
+ unsigned int objidlen = objID.getLength();
+
+ if (objID == "2.5.29.17")
+ {
+ rtl::Reference<SanExtensionImpl> pExtn = new SanExtensionImpl;
+ pExtn->setCertExtn(value, vlen, objid, objidlen, crit);
+ xExtnsRange[len] = pExtn ;
+ }
+ else
+ {
+ rtl::Reference<CertificateExtension_XmlSecImpl> pExtn = new CertificateExtension_XmlSecImpl;
+ pExtn->setCertExtn(value, vlen, objid, objidlen, crit);
+ xExtnsRange[len] = pExtn;
+ }
+ }
+
+ return xExtns ;
+ } else {
+ return css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > ();
+ }
+}
+
+css::uno::Reference< css::security::XCertificateExtension > SAL_CALL X509Certificate_NssImpl::findCertificateExtension( const css::uno::Sequence< sal_Int8 >& oid ) {
+ if( m_pCert != nullptr && m_pCert->extensions != nullptr ) {
+ CERTCertExtension** extns ;
+ SECItem idItem ;
+
+ idItem.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(oid.getConstArray()));
+ idItem.len = oid.getLength() ;
+
+ css::uno::Reference<css::security::XCertificateExtension> xExtn;
+ for( extns = m_pCert->extensions; *extns != nullptr; extns ++ ) {
+ if( SECITEM_CompareItem( &idItem, &(*extns)->id ) == SECEqual ) {
+ const SECItem id = (*extns)->id;
+ OString objId(CERT_GetOidString(&id));
+
+ bool crit;
+ if( (*extns)->critical.data == nullptr )
+ crit = false ;
+ else
+ crit = (*extns)->critical.data[0] == 0xFF;
+
+ unsigned char* value = (*extns)->value.data;
+ unsigned int vlen = (*extns)->value.len;
+ unsigned char* objid = (*extns)->id.data;
+ unsigned int objidlen = (*extns)->id.len;
+
+ if ( objId == "OID.2.5.29.17" )
+ {
+ rtl::Reference<SanExtensionImpl> xSanImpl(
+ new SanExtensionImpl);
+ xSanImpl->setCertExtn(value, vlen, objid, objidlen, crit);
+ xExtn = xSanImpl.get();
+ }
+ else
+ {
+ rtl::Reference<CertificateExtension_XmlSecImpl> xSecImpl(
+ new CertificateExtension_XmlSecImpl);
+ xSecImpl->setCertExtn(value, vlen, objid, objidlen, crit);
+ xExtn = xSecImpl.get();
+ }
+ break;
+ }
+ }
+
+ return xExtn;
+ } else {
+ return nullptr ;
+ }
+}
+
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getEncoded() {
+ if( m_pCert != nullptr && m_pCert->derCert.len > 0 ) {
+ return comphelper::arrayToSequence<sal_Int8>(m_pCert->derCert.data, m_pCert->derCert.len) ;
+ } else {
+ return css::uno::Sequence< sal_Int8 >();
+ }
+}
+
+//Helper methods
+void X509Certificate_NssImpl::setCert( CERTCertificate* cert ) {
+ if( m_pCert != nullptr ) {
+ CERT_DestroyCertificate( m_pCert ) ;
+ m_pCert = nullptr ;
+ }
+
+ if( cert != nullptr ) {
+ m_pCert = CERT_DupCertificate( cert ) ;
+ }
+}
+
+const CERTCertificate* X509Certificate_NssImpl::getNssCert() const {
+ if( m_pCert != nullptr ) {
+ return m_pCert ;
+ } else {
+ return nullptr ;
+ }
+}
+
+void X509Certificate_NssImpl::setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) {
+ CERTCertificate* cert ;
+ SECItem certItem ;
+
+ certItem.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(rawCert.getConstArray()));
+ certItem.len = rawCert.getLength() ;
+
+ cert = CERT_DecodeDERCertificate( &certItem, PR_TRUE, nullptr ) ;
+ if( cert == nullptr )
+ throw css::uno::RuntimeException() ;
+
+ if( m_pCert != nullptr ) {
+ CERT_DestroyCertificate( m_pCert ) ;
+ m_pCert = nullptr ;
+ }
+
+ m_pCert = cert ;
+}
+
+SECKEYPrivateKey* X509Certificate_NssImpl::getPrivateKey()
+{
+ if (m_pCert && m_pCert->slot)
+ {
+ SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr);
+ if (pPrivateKey)
+ return pPrivateKey;
+ pPrivateKey = PK11_FindKeyByDERCert(m_pCert->slot, m_pCert, nullptr);
+ if (pPrivateKey)
+ {
+ SAL_INFO("xmlsecurity.xmlsec", "fallback from PK11_FindPrivateKeyFromCert to PK11_FindKeyByDERCert needed");
+ return pPrivateKey;
+ }
+ SAL_WARN("xmlsecurity.xmlsec", "X509Certificate_NssImpl::getPrivateKey() cannot find private key");
+ }
+ return nullptr;
+}
+
+static OUString getAlgorithmDescription(SECAlgorithmID const *aid)
+{
+ SECOidTag tag;
+ tag = SECOID_GetAlgorithmTag(aid);
+
+ const char *pDesc = SECOID_FindOIDTagDescription(tag);
+
+ return OUString::createFromAscii( pDesc ) ;
+}
+
+static css::uno::Sequence< sal_Int8 > getThumbprint(CERTCertificate const *pCert, SECOidTag id)
+{
+ if( pCert != nullptr )
+ {
+ SECStatus rv;
+ unsigned char fingerprint[32];
+ int length = 0;
+ switch (id)
+ {
+ case SEC_OID_MD5:
+ length = MD5_LENGTH;
+ break;
+ case SEC_OID_SHA1:
+ length = SHA1_LENGTH;
+ break;
+ case SEC_OID_SHA256:
+ length = SHA256_LENGTH;
+ break;
+ default:
+ break;
+ }
+
+ memset(fingerprint, 0, sizeof fingerprint);
+ rv = PK11_HashBuf(id, fingerprint, pCert->derCert.data, pCert->derCert.len);
+ if(rv == SECStatus::SECSuccess)
+ {
+ return comphelper::arrayToSequence<sal_Int8>(fingerprint, length);
+ }
+ }
+ return css::uno::Sequence< sal_Int8 >();
+}
+
+OUString SAL_CALL X509Certificate_NssImpl::getSubjectPublicKeyAlgorithm()
+{
+ if( m_pCert != nullptr )
+ {
+ return getAlgorithmDescription(&(m_pCert->subjectPublicKeyInfo.algorithm));
+ }
+ else
+ {
+ return OUString() ;
+ }
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSubjectPublicKeyValue()
+{
+ if( m_pCert != nullptr )
+ {
+ SECItem spk = m_pCert->subjectPublicKeyInfo.subjectPublicKey;
+ DER_ConvertBitString(&spk);
+
+ if ( spk.len>0)
+ {
+ return comphelper::arrayToSequence<sal_Int8>(spk.data, spk.len) ;
+ }
+ }
+
+ return css::uno::Sequence< sal_Int8 >();
+}
+
+OUString SAL_CALL X509Certificate_NssImpl::getSignatureAlgorithm()
+{
+ if( m_pCert != nullptr )
+ {
+ return getAlgorithmDescription(&(m_pCert->signature));
+ }
+ else
+ {
+ return OUString() ;
+ }
+}
+
+svl::crypto::SignatureMethodAlgorithm X509Certificate_NssImpl::getSignatureMethodAlgorithm()
+{
+ svl::crypto::SignatureMethodAlgorithm nRet = svl::crypto::SignatureMethodAlgorithm::RSA;
+
+ if (!m_pCert)
+ return nRet;
+
+ SECOidTag eTag = SECOID_GetAlgorithmTag(&m_pCert->subjectPublicKeyInfo.algorithm);
+ if (eTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY)
+ nRet = svl::crypto::SignatureMethodAlgorithm::ECDSA;
+
+ return nRet;
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSHA1Thumbprint()
+{
+ return getThumbprint(m_pCert, SEC_OID_SHA1);
+}
+
+css::uno::Sequence<sal_Int8> X509Certificate_NssImpl::getSHA256Thumbprint()
+{
+ return getThumbprint(m_pCert, SEC_OID_SHA256);
+}
+
+css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getMD5Thumbprint()
+{
+ return getThumbprint(m_pCert, SEC_OID_MD5);
+}
+
+css::security::CertificateKind SAL_CALL X509Certificate_NssImpl::getCertificateKind()
+{
+ return css::security::CertificateKind_X509;
+}
+
+sal_Int32 SAL_CALL X509Certificate_NssImpl::getCertificateUsage( )
+{
+ SECStatus rv;
+ SECItem tmpitem;
+ sal_Int32 usage;
+
+ rv = CERT_FindKeyUsageExtension(m_pCert, &tmpitem);
+ if ( rv == SECStatus::SECSuccess )
+ {
+ usage = tmpitem.data[0];
+ PORT_Free(tmpitem.data);
+ tmpitem.data = nullptr;
+ }
+ else
+ {
+ usage = KU_ALL;
+ }
+
+ /*
+ * to make the nss implementation compatible with MSCrypto,
+ * the following usage is ignored
+ *
+ *
+ if ( CERT_GovtApprovedBitSet(m_pCert) )
+ {
+ usage |= KU_NS_GOVT_APPROVED;
+ }
+ */
+
+ return usage;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL X509Certificate_NssImpl::getImplementationName()
+{
+ return "com.sun.star.xml.security.gpg.XCertificate_NssImpl";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL X509Certificate_NssImpl::supportsService(const OUString& serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+css::uno::Sequence<OUString> SAL_CALL X509Certificate_NssImpl::getSupportedServiceNames() { return { OUString() }; }
+
+namespace xmlsecurity {
+
+// based on some guesswork and:
+// https://datatracker.ietf.org/doc/html/rfc1485
+// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
+// the main problem appears to be that in values " is escaped as "" vs. \"
+static OUString CompatDNCryptoAPI(std::u16string_view rDN)
+{
+ OUStringBuffer buf(rDN.size());
+ enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT);
+ for (size_t i = 0; i < rDN.size(); ++i)
+ {
+ if (state == DEFAULT)
+ {
+ buf.append(rDN[i]);
+ if (rDN[i] == '=')
+ {
+ if (rDN.size() == i+1)
+ {
+ break; // invalid?
+ }
+ else if (rDN[i+1] == '"')
+ {
+ buf.append(rDN[i+1]);
+ ++i;
+ state = INQUOTE;
+ }
+ else
+ {
+ state = INVALUE;
+ }
+ }
+ }
+ else if (state == INVALUE)
+ {
+ if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';')
+ {
+ state = DEFAULT;
+ }
+ buf.append(rDN[i]);
+ }
+ else
+ {
+ assert(state == INQUOTE);
+ if (rDN[i] == '"')
+ {
+ if (rDN.size() != i+1 && rDN[i+1] == '"')
+ {
+ buf.append(OUString::Concat("\\") + OUStringChar(rDN[i+1]));
+ ++i;
+ }
+ else
+ {
+ buf.append(rDN[i]);
+ state = DEFAULT;
+ }
+ }
+ else
+ {
+ buf.append(rDN[i]);
+ }
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+bool EqualDistinguishedNames(
+ std::u16string_view const rName1, std::u16string_view const rName2,
+ EqualMode const eMode)
+{
+ if (eMode == COMPAT_BOTH && !rName1.empty() && rName1 == rName2)
+ { // handle case where both need to be converted
+ return true;
+ }
+ CERTName *const pName1(CERT_AsciiToName(OUStringToOString(rName1, RTL_TEXTENCODING_UTF8).getStr()));
+ if (pName1 == nullptr)
+ {
+ return false;
+ }
+ CERTName *const pName2(CERT_AsciiToName(OUStringToOString(rName2, RTL_TEXTENCODING_UTF8).getStr()));
+ bool ret(false);
+ if (pName2)
+ {
+ ret = (CERT_CompareName(pName1, pName2) == SECEqual);
+ CERT_DestroyName(pName2);
+ }
+ if (!ret && eMode == COMPAT_2ND)
+ {
+ CERTName *const pName2Compat(CERT_AsciiToName(OUStringToOString(
+ CompatDNCryptoAPI(rName2), RTL_TEXTENCODING_UTF8).getStr()));
+ if (pName2Compat == nullptr)
+ {
+ CERT_DestroyName(pName1);
+ return false;
+ }
+ ret = CERT_CompareName(pName1, pName2Compat) == SECEqual;
+ CERT_DestroyName(pName2Compat);
+ }
+ CERT_DestroyName(pName1);
+ return ret;
+}
+
+} // namespace xmlsecurity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx
new file mode 100644
index 0000000000..9ad50f12ba
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/security/CertificateKind.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+
+#include <certificate.hxx>
+#include <certt.h>
+#include <keythi.h>
+
+class X509Certificate_NssImpl : public ::cppu::WeakImplHelper<
+ css::security::XCertificate ,
+ css::lang::XServiceInfo > , public xmlsecurity::Certificate
+{
+ private:
+ CERTCertificate* m_pCert;
+
+ public:
+ X509Certificate_NssImpl() ;
+ virtual ~X509Certificate_NssImpl() override ;
+
+ //Methods from XCertificate
+ virtual sal_Int16 SAL_CALL getVersion( ) override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSerialNumber( ) override ;
+
+ virtual OUString SAL_CALL getIssuerName( ) override ;
+ virtual OUString SAL_CALL getSubjectName( ) override ;
+
+ virtual css::util::DateTime SAL_CALL getNotValidBefore( ) override ;
+ virtual css::util::DateTime SAL_CALL getNotValidAfter( ) override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getIssuerUniqueID( ) override ;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectUniqueID( ) override ;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL getExtensions( ) override ;
+
+ virtual css::uno::Reference< css::security::XCertificateExtension > SAL_CALL findCertificateExtension( const css::uno::Sequence< sal_Int8 >& oid ) override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getEncoded( ) override ;
+
+ virtual OUString SAL_CALL getSubjectPublicKeyAlgorithm() override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectPublicKeyValue() override ;
+
+ virtual OUString SAL_CALL getSignatureAlgorithm() override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSHA1Thumbprint() override ;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getMD5Thumbprint() override ;
+ virtual css::security::CertificateKind SAL_CALL getCertificateKind() override;
+
+ virtual sal_Int32 SAL_CALL getCertificateUsage( ) override ;
+
+ /// @see xmlsecurity::Certificate::getSHA256Thumbprint().
+ virtual css::uno::Sequence<sal_Int8> getSHA256Thumbprint() override;
+
+ /// @see xmlsecurity::Certificate::getSignatureMethodAlgorithm().
+ virtual svl::crypto::SignatureMethodAlgorithm getSignatureMethodAlgorithm() override;
+
+ //Helper methods
+ void setCert( CERTCertificate* cert ) ;
+ const CERTCertificate* getNssCert() const ;
+
+ /// @throws css::uno::RuntimeException
+ void setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) ;
+ SECKEYPrivateKey* getPrivateKey();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+} ;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsecuritycontext_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/xmlsecuritycontext_nssimpl.cxx
new file mode 100644
index 0000000000..9ccf0ab982
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/xmlsecuritycontext_nssimpl.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <vector>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
+#include <o3tl/safeint.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
+using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
+
+namespace {
+
+class XMLSecurityContext_NssImpl
+ : public ::cppu::WeakImplHelper<xml::crypto::XXMLSecurityContext, lang::XServiceInfo>
+{
+private:
+ std::vector<uno::Reference<xml::crypto::XSecurityEnvironment>> m_vSecurityEnvironments;
+
+ sal_Int32 m_nDefaultEnvIndex;
+
+public:
+ XMLSecurityContext_NssImpl();
+
+ //XXMLSecurityContext
+ virtual sal_Int32 SAL_CALL addSecurityEnvironment(
+ const uno::Reference<xml::crypto::XSecurityEnvironment>& aSecurityEnvironment) override;
+
+ virtual ::sal_Int32 SAL_CALL getSecurityEnvironmentNumber() override;
+
+ virtual uno::Reference<xml::crypto::XSecurityEnvironment>
+ SAL_CALL getSecurityEnvironmentByIndex(::sal_Int32 index) override;
+
+ virtual uno::Reference<xml::crypto::XSecurityEnvironment>
+ SAL_CALL getSecurityEnvironment() override;
+
+ virtual ::sal_Int32 SAL_CALL getDefaultSecurityEnvironmentIndex() override;
+
+ virtual void SAL_CALL setDefaultSecurityEnvironmentIndex(sal_Int32 nDefaultEnvIndex) override;
+
+ //XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+ virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+XMLSecurityContext_NssImpl::XMLSecurityContext_NssImpl()
+ : m_nDefaultEnvIndex(-1)
+{
+}
+
+sal_Int32 SAL_CALL XMLSecurityContext_NssImpl::addSecurityEnvironment(
+ const uno::Reference< xml::crypto::XSecurityEnvironment >& aSecurityEnvironment)
+{
+ if( !aSecurityEnvironment.is() )
+ {
+ throw uno::RuntimeException() ;
+ }
+
+ m_vSecurityEnvironments.push_back( aSecurityEnvironment );
+
+ return m_vSecurityEnvironments.size() - 1 ;
+}
+
+
+sal_Int32 SAL_CALL XMLSecurityContext_NssImpl::getSecurityEnvironmentNumber( )
+{
+ return m_vSecurityEnvironments.size();
+}
+
+uno::Reference< xml::crypto::XSecurityEnvironment > SAL_CALL
+ XMLSecurityContext_NssImpl::getSecurityEnvironmentByIndex( sal_Int32 index )
+{
+ if (index < 0 || o3tl::make_unsigned(index) >= m_vSecurityEnvironments.size())
+ throw uno::RuntimeException();
+
+ uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnvironment = m_vSecurityEnvironments[index];
+ return xSecurityEnvironment;
+}
+
+uno::Reference< xml::crypto::XSecurityEnvironment > SAL_CALL
+ XMLSecurityContext_NssImpl::getSecurityEnvironment( )
+{
+ if (m_nDefaultEnvIndex < 0 || o3tl::make_unsigned(m_nDefaultEnvIndex) >= m_vSecurityEnvironments.size())
+ throw uno::RuntimeException();
+
+ return getSecurityEnvironmentByIndex(m_nDefaultEnvIndex);
+}
+
+sal_Int32 SAL_CALL XMLSecurityContext_NssImpl::getDefaultSecurityEnvironmentIndex( )
+{
+ return m_nDefaultEnvIndex ;
+}
+
+void SAL_CALL XMLSecurityContext_NssImpl::setDefaultSecurityEnvironmentIndex( sal_Int32 nDefaultEnvIndex )
+{
+ m_nDefaultEnvIndex = nDefaultEnvIndex;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLSecurityContext_NssImpl::getImplementationName() {
+ return "com.sun.star.xml.crypto.XMLSecurityContext";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL XMLSecurityContext_NssImpl::supportsService( const OUString& serviceName) {
+ return cppu::supportsService(this, serviceName);
+}
+
+/* XServiceInfo */
+uno::Sequence< OUString > SAL_CALL XMLSecurityContext_NssImpl::getSupportedServiceNames() {
+ return { "com.sun.star.xml.crypto.XMLSecurityContext" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_XMLSecurityContext_get_implementation(
+ uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLSecurityContext_NssImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
new file mode 100644
index 0000000000..4c5cc4b418
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/nss/xmlsignature_nssimpl.cxx
@@ -0,0 +1,321 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include <xmlsec/nss/x509.h>
+
+#include <xmlelementwrapper_xmlsecimpl.hxx>
+#include <xmlsec/xmlstreamio.hxx>
+#include <xmlsec/errorcallback.hxx>
+
+#include "securityenvironment_nssimpl.hxx"
+
+#include <comphelper/servicehelper.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/crypto/XXMLSignature.hpp>
+#include <memory>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::lang ;
+
+using ::com::sun::star::xml::wrapper::XXMLElementWrapper ;
+using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
+using ::com::sun::star::xml::crypto::XXMLSignature ;
+using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ;
+using ::com::sun::star::xml::crypto::XXMLSecurityContext ;
+using ::com::sun::star::xml::crypto::XUriBinding ;
+
+namespace std
+{
+template <> struct default_delete<xmlSecKeysMngr>
+{
+ void operator()(xmlSecKeysMngrPtr ptr) { SecurityEnvironment_NssImpl::destroyKeysManager(ptr); }
+};
+template <> struct default_delete<xmlSecDSigCtx>
+{
+ void operator()(xmlSecDSigCtxPtr ptr) { xmlSecDSigCtxDestroy(ptr); }
+};
+}
+
+namespace {
+
+class XMLSignature_NssImpl
+ : public ::cppu::WeakImplHelper<xml::crypto::XXMLSignature, lang::XServiceInfo>
+{
+public:
+ explicit XMLSignature_NssImpl();
+
+ //Methods from XXMLSignature
+ virtual uno::Reference<xml::crypto::XXMLSignatureTemplate> SAL_CALL
+ generate(const uno::Reference<xml::crypto::XXMLSignatureTemplate>& aTemplate,
+ const uno::Reference<xml::crypto::XSecurityEnvironment>& aEnvironment) override;
+
+ virtual uno::Reference<xml::crypto::XXMLSignatureTemplate> SAL_CALL
+ validate(const uno::Reference<xml::crypto::XXMLSignatureTemplate>& aTemplate,
+ const uno::Reference<xml::crypto::XXMLSecurityContext>& aContext) override;
+
+ //Methods from XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+ virtual uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+
+}
+
+XMLSignature_NssImpl::XMLSignature_NssImpl() {
+}
+
+/* XXMLSignature */
+Reference< XXMLSignatureTemplate >
+SAL_CALL XMLSignature_NssImpl::generate(
+ const Reference< XXMLSignatureTemplate >& aTemplate ,
+ const Reference< XSecurityEnvironment >& aEnvironment
+)
+{
+ xmlNodePtr pNode = nullptr ;
+
+ if( !aTemplate.is() )
+ throw RuntimeException() ;
+
+ if( !aEnvironment.is() )
+ throw RuntimeException() ;
+
+ //Get the xml node
+ Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
+ if( !xElement.is() ) {
+ throw RuntimeException() ;
+ }
+
+ XMLElementWrapper_XmlSecImpl* pElement
+ = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
+ if( pElement == nullptr ) {
+ throw RuntimeException() ;
+ }
+
+ pNode = pElement->getNativeElement() ;
+
+ //Get the stream/URI binding
+ Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
+ if( xUriBinding.is() ) {
+ //Register the stream input callbacks into libxml2
+ if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
+ throw RuntimeException() ;
+ }
+
+ //Get Keys Manager
+
+ // the key manager should be retrieved from SecurityEnvironment, instead of SecurityContext
+ SecurityEnvironment_NssImpl* pSecEnv
+ = dynamic_cast<SecurityEnvironment_NssImpl*>(aEnvironment.get());
+ if( pSecEnv == nullptr )
+ throw RuntimeException() ;
+
+ setErrorRecorder();
+
+ std::unique_ptr<xmlSecKeysMngr> pMngr(pSecEnv->createKeysManager());
+ if( !pMngr ) {
+ throw RuntimeException() ;
+ }
+
+ //Create Signature context
+ std::unique_ptr<xmlSecDSigCtx> pDsigCtx(xmlSecDSigCtxCreate(pMngr.get()));
+ if( pDsigCtx == nullptr )
+ {
+ //throw XMLSignatureException() ;
+ clearErrorRecorder();
+ return aTemplate;
+ }
+
+ //Sign the template
+ if( xmlSecDSigCtxSign( pDsigCtx.get() , pNode ) == 0 )
+ {
+ if (pDsigCtx->status == xmlSecDSigStatusSucceeded)
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
+ else
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+ else
+ {
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+
+ //Unregistered the stream/URI binding
+ if( xUriBinding.is() )
+ xmlUnregisterStreamInputCallbacks() ;
+
+ clearErrorRecorder();
+ return aTemplate ;
+}
+
+/* XXMLSignature */
+Reference< XXMLSignatureTemplate >
+SAL_CALL XMLSignature_NssImpl::validate(
+ const Reference< XXMLSignatureTemplate >& aTemplate ,
+ const Reference< XXMLSecurityContext >& aSecurityCtx
+) {
+ xmlNodePtr pNode = nullptr ;
+ //sal_Bool valid ;
+
+ if( !aTemplate.is() )
+ throw RuntimeException() ;
+
+ if( !aSecurityCtx.is() )
+ throw RuntimeException() ;
+
+ //Get the xml node
+ Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ;
+ if( !xElement.is() )
+ throw RuntimeException() ;
+
+ XMLElementWrapper_XmlSecImpl* pElement
+ = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xElement.get());
+ if( pElement == nullptr )
+ throw RuntimeException() ;
+
+ pNode = pElement->getNativeElement() ;
+
+ //Get the stream/URI binding
+ Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ;
+ if( xUriBinding.is() ) {
+ //Register the stream input callbacks into libxml2
+ if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 )
+ throw RuntimeException() ;
+ }
+
+ setErrorRecorder();
+
+ sal_Int32 nSecurityEnvironment = aSecurityCtx->getSecurityEnvironmentNumber();
+ sal_Int32 i;
+
+ for (i=0; i<nSecurityEnvironment; ++i)
+ {
+ Reference< XSecurityEnvironment > aEnvironment = aSecurityCtx->getSecurityEnvironmentByIndex(i);
+
+ //Get Keys Manager
+ SecurityEnvironment_NssImpl* pSecEnv
+ = dynamic_cast<SecurityEnvironment_NssImpl*>(aEnvironment.get());
+ if( pSecEnv == nullptr )
+ throw RuntimeException() ;
+
+ std::unique_ptr<xmlSecKeysMngr> pMngr(pSecEnv->createKeysManager());
+ if( !pMngr ) {
+ throw RuntimeException() ;
+ }
+
+ //Create Signature context
+ std::unique_ptr<xmlSecDSigCtx> pDsigCtx(xmlSecDSigCtxCreate(pMngr.get()));
+ if( pDsigCtx == nullptr )
+ {
+ clearErrorRecorder();
+ return aTemplate;
+ }
+
+ // We do certificate verification ourselves.
+ pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
+
+ // limit possible key data to valid X509 certificates only, no KeyValues
+ if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecNssKeyDataX509GetKlass()) < 0)
+ throw RuntimeException("failed to limit allowed key data");
+
+ xmlBufferPtr pBuf = xmlBufferCreate();
+ xmlNodeDump(pBuf, nullptr, pNode, 0, 0);
+ SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify input XML node is '"
+ << reinterpret_cast<const char*>(xmlBufferContent(pBuf))
+ << "'");
+ xmlBufferFree(pBuf);
+
+ //Verify signature
+ int rs = xmlSecDSigCtxVerify( pDsigCtx.get() , pNode );
+
+ // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML.
+ xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences);
+ // Require that all manifest references are also good.
+ xmlSecSize nReferenceGood = 0;
+ for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference)
+ {
+ xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference));
+ if (pReference)
+ {
+ if (pReference->status == xmlSecDSigStatusSucceeded)
+ ++nReferenceGood;
+ }
+ }
+ SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount);
+
+ if (rs == 0 && pDsigCtx->status == xmlSecDSigStatusSucceeded && nReferenceCount == nReferenceGood)
+ {
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED);
+ break;
+ }
+ else
+ {
+ aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN);
+ }
+ }
+
+
+ //Unregistered the stream/URI binding
+ if( xUriBinding.is() )
+ xmlUnregisterStreamInputCallbacks() ;
+
+ //return valid ;
+ clearErrorRecorder();
+ return aTemplate;
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLSignature_NssImpl::getImplementationName()
+{
+ return "com.sun.star.xml.crypto.XMLSignature";
+}
+
+/* XServiceInfo */
+sal_Bool SAL_CALL XMLSignature_NssImpl::supportsService(const OUString& rServiceName)
+{
+ const css::uno::Sequence<OUString> aServiceNames = getSupportedServiceNames();
+ for (OUString const & rCurrentServiceName : aServiceNames)
+ {
+ if (rCurrentServiceName == rServiceName)
+ return true;
+ }
+ return false;
+}
+
+/* XServiceInfo */
+Sequence<OUString> SAL_CALL XMLSignature_NssImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.xml.crypto.XMLSignature" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext* /*pCtx*/,
+ uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLSignature_NssImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/saxhelper.cxx b/xmlsecurity/source/xmlsec/saxhelper.cxx
new file mode 100644
index 0000000000..ff576db496
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/saxhelper.cxx
@@ -0,0 +1,364 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <rtl/ustring.hxx>
+
+#include <xmlsec/saxhelper.hxx>
+#include <libxml/parserInternals.h>
+
+#include <com/sun/star/xml/csax/XMLAttribute.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#ifndef XMLSEC_NO_XSLT
+#include "libxslt/xslt.h"
+#endif
+
+/**
+ * The return value is NULL terminated. The application has the responsibility to
+ * deallocate the return value.
+ */
+static xmlChar* ous_to_xmlstr( std::u16string_view oustr )
+{
+ OString ostr = OUStringToOString( oustr , RTL_TEXTENCODING_UTF8 ) ;
+ return xmlStrndup( reinterpret_cast<xmlChar const *>(ostr.getStr()), static_cast<int>(ostr.getLength()) ) ;
+}
+
+/**
+ * The return value is NULL terminated. The application has the responsibility to
+ * deallocate the return value.
+ */
+static xmlChar* ous_to_nxmlstr( std::u16string_view oustr, int& length )
+{
+ OString ostr = OUStringToOString( oustr , RTL_TEXTENCODING_UTF8 ) ;
+ length = ostr.getLength();
+
+ return xmlStrndup( reinterpret_cast<xmlChar const *>(ostr.getStr()), length ) ;
+}
+
+/**
+ * The return value and the referenced value must be NULL terminated.
+ * The application has the responsibility to deallocate the return value.
+ */
+static const xmlChar** attrlist_to_nxmlstr( const css::uno::Sequence< css::xml::csax::XMLAttribute >& aAttributes )
+{
+ xmlChar* attname = nullptr ;
+ xmlChar* attvalue = nullptr ;
+ const xmlChar** attrs = nullptr ;
+
+ sal_Int32 nLength = aAttributes.getLength();
+
+ if( nLength != 0 )
+ {
+ attrs = static_cast<const xmlChar**>(xmlMalloc( ( nLength * 2 + 2 ) * sizeof( xmlChar* ) ));
+ }
+ else
+ {
+ return nullptr ;
+ }
+
+ int i = 0;
+ for( const auto& rAttr : aAttributes )
+ {
+ attname = ous_to_xmlstr( rAttr.sName ) ;
+ attvalue = ous_to_xmlstr( rAttr.sValue ) ;
+
+ if( attname != nullptr && attvalue != nullptr )
+ {
+ attrs[i++] = attname ;
+ attrs[i++] = attvalue ;
+ attrs[i] = nullptr ;
+ attrs[i+1] = nullptr ;
+ }
+ else
+ {
+ if( attname != nullptr )
+ xmlFree( attname ) ;
+ if( attvalue != nullptr )
+ xmlFree( attvalue ) ;
+ }
+ }
+
+ return attrs ;
+}
+
+/**
+ * Constructor
+ *
+ * In this constructor, a libxml sax parser context is initialized. a libxml
+ * default sax handler is initialized with the context.
+ */
+SAXHelper::SAXHelper( )
+ : m_pParserCtxt( nullptr ),
+ m_pSaxHandler( nullptr )
+{
+ xmlInitParser() ;
+ LIBXML_TEST_VERSION ;
+
+ /*
+ * compile error:
+ * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS ;
+ */
+ xmlSubstituteEntitiesDefault(0) ;
+
+#ifndef XMLSEC_NO_XSLT
+ xmlIndentTreeOutput = 1 ;
+#endif /* XMLSEC_NO_XSLT */
+
+ m_pParserCtxt = xmlNewParserCtxt() ;
+
+ if( m_pParserCtxt == nullptr )
+ {
+// see issue i74334, we cannot call xmlCleanupParser when libxml is still used
+// in other parts of the office.
+// xmlCleanupParser() ;
+// and neither can we call xsltCleanupGlobals()
+ throw css::uno::RuntimeException() ;
+ }
+
+ xmlSAXVersion(m_pParserCtxt->sax, 1);
+
+ if (m_pParserCtxt->inputTab != nullptr)
+ {
+ m_pParserCtxt->inputTab[0] = nullptr ;
+ }
+
+ if( m_pParserCtxt->sax == nullptr )
+ {
+ xmlFreeParserCtxt( m_pParserCtxt ) ;
+
+// see issue i74334, we cannot call xmlCleanupParser when libxml is still used
+// in other parts of the office.
+// xmlCleanupParser() ;
+// and neither can we call xsltCleanupGlobals()
+ m_pParserCtxt = nullptr ;
+ throw css::uno::RuntimeException() ;
+ }
+ else
+ {
+ m_pSaxHandler = m_pParserCtxt->sax ;
+
+ //Adjust the context
+ m_pParserCtxt->recovery = 1 ;
+ }
+}
+
+/**
+ * Destructor
+ *
+ * In this destructor, a libxml sax parser context is destructed. The XML tree
+ * in the context is not deallocated because the tree is bind with a document
+ * model by the setTargetDocument method, which delegate the target document to
+ * destruct the xml tree.
+ */
+SAXHelper::~SAXHelper() {
+ if( m_pParserCtxt != nullptr )
+ {
+ /*
+ * In the situation that no object refer the Document, this destructor
+ * must deallocate the Document memory
+ */
+ if( m_pSaxHandler == m_pParserCtxt->sax )
+ {
+ m_pSaxHandler = nullptr ;
+ }
+
+ xmlFreeParserCtxt( m_pParserCtxt ) ;
+ m_pParserCtxt = nullptr ;
+ }
+
+ if( m_pSaxHandler != nullptr )
+ {
+ xmlFree( m_pSaxHandler ) ;
+ m_pSaxHandler = nullptr ;
+ }
+// see issue i74334, we cannot call xmlCleanupParser when libxml is still used
+// in other parts of the office.
+// xmlCleanupParser() ;
+}
+
+
+void SAXHelper::setCurrentNode(const xmlNodePtr pNode)
+{
+ /*
+ * This is really a black trick.
+ * When the current node is replaced, the nodeTab
+ * stack's top has to been replaced with the same
+ * node, in order to make compatibility.
+ */
+ m_pParserCtxt->nodeTab[m_pParserCtxt->nodeNr - 1]
+ = m_pParserCtxt->node
+ = pNode;
+}
+
+
+/**
+ * XDocumentHandler -- start an xml document
+ */
+void SAXHelper::startDocument()
+{
+ if( m_pParserCtxt == nullptr)
+ {
+ throw css::uno::RuntimeException() ;
+ }
+ /*
+ * Adjust inputTab
+ */
+ xmlParserInputPtr pInput = xmlNewInputStream( m_pParserCtxt ) ;
+
+ if( m_pParserCtxt->inputTab != nullptr && m_pParserCtxt->inputMax != 0 )
+ {
+ m_pParserCtxt->inputTab[0] = pInput ;
+ m_pParserCtxt->input = pInput ;
+ }
+
+ m_pSaxHandler->startDocument( m_pParserCtxt ) ;
+
+ if( m_pParserCtxt->myDoc == nullptr )
+ {
+ throw css::uno::RuntimeException() ;
+ }
+}
+
+/**
+ * XDocumentHandler -- end an xml document
+ */
+void SAXHelper::endDocument()
+{
+ m_pSaxHandler->endDocument( m_pParserCtxt ) ;
+}
+
+/**
+ * XDocumentHandler -- start an xml element
+ */
+void SAXHelper::startElement(
+ std::u16string_view aName,
+ const css::uno::Sequence< css::xml::csax::XMLAttribute >& aAttributes )
+{
+ const xmlChar* fullName = nullptr ;
+ const xmlChar** attrs = nullptr ;
+
+ fullName = ous_to_xmlstr( aName ) ;
+ attrs = attrlist_to_nxmlstr( aAttributes ) ;
+
+ if( fullName != nullptr || attrs != nullptr )
+ {
+ m_pSaxHandler->startElement( m_pParserCtxt , fullName , attrs ) ;
+ }
+
+ if( fullName != nullptr )
+ {
+ xmlFree( const_cast<xmlChar*>(fullName) ) ;
+ fullName = nullptr ;
+ }
+
+ if( attrs != nullptr )
+ {
+ for( int i = 0 ; attrs[i] != nullptr ; ++i )
+ {
+ xmlFree( const_cast<xmlChar*>(attrs[i]) ) ;
+ attrs[i] = nullptr ;
+ }
+
+ xmlFree( static_cast<void*>(attrs) ) ;
+ attrs = nullptr ;
+ }
+}
+
+/**
+ * XDocumentHandler -- end an xml element
+ */
+void SAXHelper::endElement( std::u16string_view aName )
+{
+ xmlChar* fullname = ous_to_xmlstr( aName ) ;
+ m_pSaxHandler->endElement( m_pParserCtxt , fullname ) ;
+
+ if( fullname != nullptr )
+ {
+ xmlFree( fullname ) ;
+ fullname = nullptr ;
+ }
+}
+
+/**
+ * XDocumentHandler -- an xml element or cdata characters
+ */
+void SAXHelper::characters( std::u16string_view aChars )
+{
+ const xmlChar* chars = nullptr ;
+ int length = 0 ;
+
+ chars = ous_to_nxmlstr( aChars, length ) ;
+ m_pSaxHandler->characters( m_pParserCtxt , chars , length ) ;
+
+ if( chars != nullptr )
+ {
+ xmlFree( const_cast<xmlChar*>(chars) ) ;
+ }
+}
+
+/**
+ * XDocumentHandler -- ignorable xml white space
+ */
+void SAXHelper::ignorableWhitespace( std::u16string_view aWhitespaces )
+{
+ const xmlChar* chars = nullptr ;
+ int length = 0 ;
+
+ chars = ous_to_nxmlstr( aWhitespaces, length ) ;
+ m_pSaxHandler->ignorableWhitespace( m_pParserCtxt , chars , length ) ;
+
+ if( chars != nullptr )
+ {
+ xmlFree( const_cast<xmlChar*>(chars) ) ;
+ }
+}
+
+/**
+ * XDocumentHandler -- preprocessing instruction
+ */
+void SAXHelper::processingInstruction(
+ std::u16string_view aTarget,
+ std::u16string_view aData )
+{
+ xmlChar* target = nullptr ;
+ xmlChar* data = nullptr ;
+
+ target = ous_to_xmlstr( aTarget ) ;
+ data = ous_to_xmlstr( aData ) ;
+
+ m_pSaxHandler->processingInstruction( m_pParserCtxt , target , data ) ;
+
+ if( target != nullptr )
+ {
+ xmlFree( target ) ;
+ target = nullptr ;
+ }
+
+ if( data != nullptr )
+ {
+ xmlFree( data ) ;
+ data = nullptr ;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/xmldocumentwrapper_xmlsecimpl.cxx b/xmlsecurity/source/xmlsec/xmldocumentwrapper_xmlsecimpl.cxx
new file mode 100644
index 0000000000..918735d380
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/xmldocumentwrapper_xmlsecimpl.cxx
@@ -0,0 +1,900 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <osl/diagnose.h>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/crypto/sax/XSAXEventKeeper.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx>
+#include "xmlelementwrapper_xmlsecimpl.hxx"
+#include <comphelper/attributelist.hxx>
+#include <rtl/ref.hxx>
+
+#ifdef UNX
+#define stricmp strcasecmp
+#endif
+
+using namespace com::sun::star;
+
+#define STRXMLNS "xmlns"
+
+/* used by the recursiveDelete method */
+#define NODE_REMOVED 0
+#define NODE_NOTREMOVED 1
+#define NODE_STOPPED 2
+
+XMLDocumentWrapper_XmlSecImpl::XMLDocumentWrapper_XmlSecImpl()
+ : m_nCurrentPosition(0)
+ , m_pStopAtNode(nullptr)
+ , m_pCurrentReservedNode(nullptr)
+ , m_nReservedNodeIndex(0)
+{
+ saxHelper.startDocument();
+ m_pDocument = saxHelper.getDocument();
+
+ /*
+ * creates the virtual root element
+ */
+ saxHelper.startElement(u"root", uno::Sequence<css::xml::csax::XMLAttribute>());
+
+ m_pRootElement = saxHelper.getCurrentNode();
+ m_pCurrentElement = m_pRootElement;
+}
+
+XMLDocumentWrapper_XmlSecImpl::~XMLDocumentWrapper_XmlSecImpl()
+{
+ saxHelper.endDocument();
+ xmlFreeDoc(m_pDocument);
+}
+
+void XMLDocumentWrapper_XmlSecImpl::getNextSAXEvent()
+/****** XMLDocumentWrapper_XmlSecImpl/getNextSAXEvent *************************
+ *
+ * NAME
+ * getNextSAXEvent -- Prepares the next SAX event to be manipulate
+ *
+ * FUNCTION
+ * When converting the document into SAX events, this method is used to
+ * decide the next SAX event to be generated.
+ * Two member variables are checked to make the decision, the
+ * m_pCurrentElement and the m_nCurrentPosition.
+ * The m_pCurrentElement represents the node which have been covered, and
+ * the m_nCurrentPosition represents the event which have been sent.
+ * For example, suppose that the m_pCurrentElement
+ * points to element A, and the m_nCurrentPosition equals to
+ * NODEPOSITION_STARTELEMENT, then the next SAX event should be the
+ * endElement for element A if A has no child, or startElement for the
+ * first child element of element A otherwise.
+ * The m_nCurrentPosition can be one of following values:
+ * NODEPOSITION_STARTELEMENT for startElement;
+ * NODEPOSITION_ENDELEMENT for endElement;
+ * NODEPOSITION_NORMAL for other SAX events;
+ ******************************************************************************/
+{
+ OSL_ASSERT( m_pCurrentElement != nullptr );
+
+ /*
+ * Get the next event through tree order.
+ *
+ * if the current event is a startElement, then the next
+ * event depends on whether or not the current node has
+ * children.
+ */
+ if (m_nCurrentPosition == NODEPOSITION_STARTELEMENT)
+ {
+ /*
+ * If the current node has children, then its first child
+ * should be next current node, and the next event will be
+ * startElement or characters(PI) based on that child's node
+ * type. Otherwise, the endElement of current node is the
+ * next event.
+ */
+ if (m_pCurrentElement->children != nullptr)
+ {
+ m_pCurrentElement = m_pCurrentElement->children;
+ m_nCurrentPosition
+ = (m_pCurrentElement->type == XML_ELEMENT_NODE)?
+ NODEPOSITION_STARTELEMENT:NODEPOSITION_NORMAL;
+ }
+ else
+ {
+ m_nCurrentPosition = NODEPOSITION_ENDELEMENT;
+ }
+ }
+ /*
+ * if the current event is a not startElement, then the next
+ * event depends on whether or not the current node has
+ * following sibling.
+ */
+ else if (m_nCurrentPosition == NODEPOSITION_ENDELEMENT || m_nCurrentPosition == NODEPOSITION_NORMAL)
+ {
+ xmlNodePtr pNextSibling = m_pCurrentElement->next;
+
+ /*
+ * If the current node has following sibling, that sibling
+ * should be next current node, and the next event will be
+ * startElement or characters(PI) based on that sibling's node
+ * type. Otherwise, the endElement of current node's parent
+ * becomes the next event.
+ */
+ if (pNextSibling != nullptr)
+ {
+ m_pCurrentElement = pNextSibling;
+ m_nCurrentPosition
+ = (m_pCurrentElement->type == XML_ELEMENT_NODE)?
+ NODEPOSITION_STARTELEMENT:NODEPOSITION_NORMAL;
+ }
+ else
+ {
+ m_pCurrentElement = m_pCurrentElement->parent;
+ m_nCurrentPosition = NODEPOSITION_ENDELEMENT;
+ }
+ }
+}
+
+void XMLDocumentWrapper_XmlSecImpl::sendStartElement(
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler,
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler2,
+ const xmlNodePtr pNode)
+/****** XMLDocumentWrapper_XmlSecImpl/sendStartElement ************************
+ *
+ * NAME
+ * sendStartElement -- Constructs a startElement SAX event
+ *
+ * FUNCTION
+ * Used when converting the document into SAX event stream.
+ * This method constructs a startElement SAX event for a particular
+ * element, then calls the startElement methods of the XDocumentHandlers.
+ *
+ * INPUTS
+ * xHandler - the first XDocumentHandler interface to receive the
+ * startElement SAX event. It can be NULL.
+ * xHandler2 - the second XDocumentHandler interface to receive the
+ * startElement SAX event. It can't be NULL.
+ * pNode - the node on which the startElement should be generated.
+ * This node must be an element type.
+ ******************************************************************************/
+{
+ rtl::Reference<comphelper::AttributeList> pAttributeList = new comphelper::AttributeList();
+
+ xmlNsPtr pNsDef = pNode->nsDef;
+
+ while (pNsDef != nullptr)
+ {
+ const xmlChar* pNsPrefix = pNsDef->prefix;
+ const xmlChar* pNsHref = pNsDef->href;
+
+ if (pNsDef->prefix == nullptr)
+ {
+ pAttributeList->AddAttribute(
+ STRXMLNS,
+ OUString::fromUtf8(reinterpret_cast<char const *>(pNsHref)));
+ }
+ else
+ {
+ pAttributeList->AddAttribute(
+ STRXMLNS ":"
+ +OUString::fromUtf8(reinterpret_cast<char const *>(pNsPrefix)),
+ OUString::fromUtf8(reinterpret_cast<char const *>(pNsHref)));
+ }
+
+ pNsDef = pNsDef->next;
+ }
+
+ xmlAttrPtr pAttr = pNode->properties;
+
+ while (pAttr != nullptr)
+ {
+ const xmlChar* pAttrName = pAttr->name;
+ xmlNsPtr pAttrNs = pAttr->ns;
+
+ OUString ouAttrName;
+ if (pAttrNs == nullptr)
+ {
+ ouAttrName = OUString::fromUtf8(reinterpret_cast<char const *>(pAttrName));
+ }
+ else
+ {
+ ouAttrName = OUString::fromUtf8(reinterpret_cast<char const *>(pAttrNs->prefix))
+ + ":" + OUString::fromUtf8(reinterpret_cast<char const *>(pAttrName));
+ }
+
+ pAttributeList->AddAttribute(
+ ouAttrName,
+ OUString::fromUtf8(reinterpret_cast<char*>(pAttr->children->content)));
+ pAttr = pAttr->next;
+ }
+
+ OString sNodeName = getNodeQName(pNode);
+
+ if (xHandler.is())
+ {
+ xHandler->startElement(
+ OUString::fromUtf8(sNodeName),
+ pAttributeList);
+ }
+
+ xHandler2->startElement(
+ OUString::fromUtf8(sNodeName),
+ pAttributeList);
+}
+
+void XMLDocumentWrapper_XmlSecImpl::sendEndElement(
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler,
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler2,
+ const xmlNodePtr pNode)
+/****** XMLDocumentWrapper_XmlSecImpl/sendEndElement **************************
+ *
+ * NAME
+ * sendEndElement -- Constructs an endElement SAX event
+ *
+ * FUNCTION
+ * Used when converting the document into SAX event stream.
+ * This method constructs an endElement SAX event for a particular
+ * element, then calls the endElement methods of the XDocumentHandlers.
+ *
+ * INPUTS
+ * xHandler - the first XDocumentHandler interface to receive the
+ * endElement SAX event. It can be NULL.
+ * xHandler2 - the second XDocumentHandler interface to receive the
+ * endElement SAX event. It can't be NULL.
+ * pNode - the node on which the endElement should be generated.
+ * This node must be an element type.
+ ******************************************************************************/
+{
+ OString sNodeName = getNodeQName(pNode);
+
+ if (xHandler.is())
+ {
+ xHandler->endElement(OUString::fromUtf8(sNodeName));
+ }
+
+ xHandler2->endElement(OUString::fromUtf8(sNodeName));
+}
+
+void XMLDocumentWrapper_XmlSecImpl::sendNode(
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler,
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xHandler2,
+ const xmlNodePtr pNode)
+/****** XMLDocumentWrapper_XmlSecImpl/sendNode ********************************
+ *
+ * NAME
+ * sendNode -- Constructs a characters SAX event or a
+ * processingInstruction SAX event
+ *
+ * FUNCTION
+ * Used when converting the document into SAX event stream.
+ * This method constructs a characters SAX event or a
+ * processingInstructionfor SAX event based on the type of a particular
+ * element, then calls the corresponding methods of the XDocumentHandlers.
+ *
+ * INPUTS
+ * xHandler - the first XDocumentHandler interface to receive the
+ * SAX event. It can be NULL.
+ * xHandler2 - the second XDocumentHandler interface to receive the
+ * SAX event. It can't be NULL.
+ * pNode - the node on which the endElement should be generated.
+ * If it is a text node, then a characters SAX event is
+ * generated; if it is a PI node, then a
+ * processingInstructionfor SAX event is generated.
+ ******************************************************************************/
+{
+ xmlElementType type = pNode->type;
+
+ if (type == XML_TEXT_NODE)
+ {
+ if (xHandler.is())
+ {
+ xHandler->characters(OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
+ }
+
+ xHandler2->characters(OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
+ }
+ else if (type == XML_PI_NODE)
+ {
+ if (xHandler.is())
+ {
+ xHandler->processingInstruction(
+ OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name)),
+ OUString::fromUtf8(reinterpret_cast<char const *>(pNode->content)));
+ }
+
+ xHandler2->processingInstruction(
+ OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name)),
+ OUString::fromUtf8(reinterpret_cast<char*>(pNode->content)));
+ }
+}
+
+OString XMLDocumentWrapper_XmlSecImpl::getNodeQName(const xmlNodePtr pNode)
+/****** XMLDocumentWrapper_XmlSecImpl/getNodeQName ****************************
+ *
+ * NAME
+ * getNodeQName -- Retrieves the qualified name of a node
+ *
+ * INPUTS
+ * pNode - the node whose name will be retrieved
+ *
+ * RESULT
+ * name - the node's qualified name
+ ******************************************************************************/
+{
+ OString sNodeName(reinterpret_cast<const char*>(pNode->name));
+ if (pNode->ns != nullptr)
+ {
+ xmlNsPtr pNs = pNode->ns;
+
+ if (pNs->prefix != nullptr)
+ {
+ OString sPrefix(reinterpret_cast<const char*>(pNs->prefix));
+ sNodeName = sPrefix + ":" + sNodeName;
+ }
+ }
+
+ return sNodeName;
+}
+
+xmlNodePtr XMLDocumentWrapper_XmlSecImpl::checkElement( const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& xXMLElement)
+/****** XMLDocumentWrapper_XmlSecImpl/checkElement ****************************
+ *
+ * NAME
+ * checkElement -- Retrieves the node wrapped by an XXMLElementWrapper
+ * interface
+ *
+ * INPUTS
+ * xXMLElement - the XXMLElementWrapper interface wrapping a node
+ *
+ * RESULT
+ * node - the node wrapped in the XXMLElementWrapper interface
+ ******************************************************************************/
+{
+ xmlNodePtr rc = nullptr;
+
+ if (xXMLElement.is())
+ {
+ XMLElementWrapper_XmlSecImpl* pElement
+ = dynamic_cast<XMLElementWrapper_XmlSecImpl*>(xXMLElement.get());
+
+ if( pElement == nullptr ) {
+ throw uno::RuntimeException() ;
+ }
+
+ rc = pElement->getNativeElement();
+ }
+
+ return rc;
+}
+
+sal_Int32 XMLDocumentWrapper_XmlSecImpl::recursiveDelete(
+ const xmlNodePtr pNode)
+/****** XMLDocumentWrapper_XmlSecImpl/recursiveDelete *************************
+ *
+ * NAME
+ * recursiveDelete -- Deletes a particular node with its branch.
+ *
+ * FUNCTION
+ * Deletes a particular node with its branch, while reserving the nodes
+ * (and their branches) listed in the m_aReservedNodes.
+ * The deletion process is performed in the tree order, that is, a node
+ * is deleted after its previous sibling node is deleted, a parent node
+ * is deleted after its branch is deleted.
+ * During the deletion process when the m_pStopAtNode is reached, the
+ * progress is interrupted at once.
+ *
+ * INPUTS
+ * pNode - the node to be deleted
+ *
+ * RESULT
+ * result - the result of the deletion process, can be one of following
+ * values:
+ * NODE_STOPPED - the process is interrupted by meeting the
+ * m_pStopAtNode
+ * NODE_NOTREMOVED - the pNode is not completely removed
+ * because there is its descendant in the
+ * m_aReservedNodes list
+ * NODE_REMOVED - the pNode and its branch are completely
+ * removed
+ *
+ * NOTES
+ * The node in the m_aReservedNodes list must be in the tree order, otherwise
+ * the result is unpredictable.
+ ******************************************************************************/
+{
+ if (pNode == m_pStopAtNode)
+ {
+ return NODE_STOPPED;
+ }
+
+ if (pNode != m_pCurrentReservedNode)
+ {
+ xmlNodePtr pChild = pNode->children;
+
+ xmlNodePtr pNextSibling;
+ bool bIsRemoved = true;
+ sal_Int32 nResult;
+
+ while( pChild != nullptr )
+ {
+ pNextSibling = pChild->next;
+ nResult = recursiveDelete(pChild);
+
+ switch (nResult)
+ {
+ case NODE_STOPPED:
+ return NODE_STOPPED;
+ case NODE_NOTREMOVED:
+ bIsRemoved = false;
+ break;
+ case NODE_REMOVED:
+ removeNode(pChild);
+ break;
+ default:
+ throw uno::RuntimeException();
+ }
+
+ pChild = pNextSibling;
+ }
+
+ if (pNode == m_pCurrentElement)
+ {
+ bIsRemoved = false;
+ }
+
+ return bIsRemoved?NODE_REMOVED:NODE_NOTREMOVED;
+ }
+ else
+ {
+ getNextReservedNode();
+ return NODE_NOTREMOVED;
+ }
+}
+
+void XMLDocumentWrapper_XmlSecImpl::getNextReservedNode()
+/****** XMLDocumentWrapper_XmlSecImpl/getNextReservedNode *********************
+ *
+ * NAME
+ * getNextReservedNode -- Highlights the next reserved node in the
+ * reserved node list
+ *
+ * FUNCTION
+ * The m_aReservedNodes array holds a node list, while the
+ * m_pCurrentReservedNode points to the one currently highlighted.
+ * This method is used to highlight the next node in the node list.
+ * This method is called at the time when the current highlighted node
+ * has been already processed, and the next node should be ready.
+ ******************************************************************************/
+{
+ if (m_nReservedNodeIndex < m_aReservedNodes.getLength())
+ {
+ m_pCurrentReservedNode = checkElement( m_aReservedNodes[m_nReservedNodeIndex] );
+ m_nReservedNodeIndex ++;
+ }
+ else
+ {
+ m_pCurrentReservedNode = nullptr;
+ }
+}
+
+void XMLDocumentWrapper_XmlSecImpl::removeNode(const xmlNodePtr pNode) const
+/****** XMLDocumentWrapper_XmlSecImpl/removeNode ******************************
+ *
+ * NAME
+ * removeNode -- Deletes a node with its branch unconditionally
+ *
+ * FUNCTION
+ * Delete the node along with its branch from the document.
+ *
+ * INPUTS
+ * pNode - the node to be deleted
+ ******************************************************************************/
+{
+ /* you can't remove the current node */
+ OSL_ASSERT( m_pCurrentElement != pNode );
+
+ xmlAttrPtr pAttr = pNode->properties;
+
+ while (pAttr != nullptr)
+ {
+ if (!stricmp(reinterpret_cast<char const *>(pAttr->name), "id"))
+ {
+ xmlRemoveID(m_pDocument, pAttr);
+ }
+
+ pAttr = pAttr->next;
+ }
+
+ xmlUnlinkNode(pNode);
+ xmlFreeNode(pNode);
+}
+
+void XMLDocumentWrapper_XmlSecImpl::buildIDAttr(xmlNodePtr pNode) const
+/****** XMLDocumentWrapper_XmlSecImpl/buildIDAttr *****************************
+ *
+ * NAME
+ * buildIDAttr -- build the ID attribute of a node
+ *
+ * INPUTS
+ * pNode - the node whose id attribute will be built
+ ******************************************************************************/
+{
+ xmlAttrPtr idAttr = xmlHasProp( pNode, reinterpret_cast<const unsigned char *>("id") );
+ if (idAttr == nullptr)
+ {
+ idAttr = xmlHasProp( pNode, reinterpret_cast<const unsigned char *>("Id") );
+ }
+
+ if (idAttr != nullptr)
+ {
+ xmlChar* idValue = xmlNodeListGetString( m_pDocument, idAttr->children, 1 ) ;
+ xmlAddID( nullptr, m_pDocument, idValue, idAttr );
+ }
+}
+
+void XMLDocumentWrapper_XmlSecImpl::rebuildIDLink(xmlNodePtr pNode) const
+/****** XMLDocumentWrapper_XmlSecImpl/rebuildIDLink ***************************
+ *
+ * NAME
+ * rebuildIDLink -- rebuild the ID link for the branch
+ *
+ * INPUTS
+ * pNode - the node, from which the branch will be rebuilt
+ ******************************************************************************/
+{
+ if (pNode != nullptr && pNode->type == XML_ELEMENT_NODE)
+ {
+ buildIDAttr( pNode );
+
+ xmlNodePtr child = pNode->children;
+ while (child != nullptr)
+ {
+ rebuildIDLink(child);
+ child = child->next;
+ }
+ }
+}
+
+/* XXMLDocumentWrapper */
+uno::Reference< css::xml::wrapper::XXMLElementWrapper > SAL_CALL XMLDocumentWrapper_XmlSecImpl::getCurrentElement( )
+{
+ return new XMLElementWrapper_XmlSecImpl(m_pCurrentElement);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::setCurrentElement( const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& element )
+{
+ m_pCurrentElement = checkElement( element );
+ saxHelper.setCurrentNode( m_pCurrentElement );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::removeCurrentElement( )
+{
+ OSL_ASSERT( m_pCurrentElement != nullptr );
+
+ xmlNodePtr pOldCurrentElement = m_pCurrentElement;
+
+ /*
+ * pop the top node in the parser context's
+ * nodeTab stack, then the parent of that node will
+ * automatically become the new stack top, and
+ * the current node as well.
+ */
+ saxHelper.endElement(OUString::fromUtf8(reinterpret_cast<char const *>(pOldCurrentElement->name)));
+ m_pCurrentElement = saxHelper.getCurrentNode();
+
+ /*
+ * remove the node
+ */
+ removeNode(pOldCurrentElement);
+}
+
+sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::isCurrent( const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node )
+{
+ xmlNodePtr pNode = checkElement(node);
+ return (pNode == m_pCurrentElement);
+}
+
+sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::isCurrentElementEmpty( )
+{
+ bool rc = false;
+
+ if (m_pCurrentElement->children == nullptr)
+ {
+ rc = true;
+ }
+
+ return rc;
+}
+
+OUString SAL_CALL XMLDocumentWrapper_XmlSecImpl::getNodeName( const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node )
+{
+ xmlNodePtr pNode = checkElement(node);
+ return OUString::fromUtf8(reinterpret_cast<char const *>(pNode->name));
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::clearUselessData(
+ const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node,
+ const uno::Sequence< uno::Reference< css::xml::wrapper::XXMLElementWrapper > >& reservedDescendants,
+ const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& stopAtNode )
+{
+ xmlNodePtr pTargetNode = checkElement(node);
+
+ m_pStopAtNode = checkElement(stopAtNode);
+ m_aReservedNodes = reservedDescendants;
+ m_nReservedNodeIndex = 0;
+
+ getNextReservedNode();
+
+ recursiveDelete(pTargetNode);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::collapse( const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node )
+{
+ xmlNodePtr pTargetNode = checkElement(node);
+ xmlNodePtr pParent;
+
+ while (pTargetNode != nullptr)
+ {
+ if (pTargetNode->children != nullptr || pTargetNode == m_pCurrentElement)
+ {
+ break;
+ }
+
+ pParent = pTargetNode->parent;
+ removeNode(pTargetNode);
+ pTargetNode = pParent;
+ }
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::getTree( const uno::Reference< css::xml::sax::XDocumentHandler >& handler )
+{
+ if (m_pRootElement == nullptr)
+ return;
+
+ xmlNodePtr pTempCurrentElement = m_pCurrentElement;
+ sal_Int32 nTempCurrentPosition = m_nCurrentPosition;
+
+ m_pCurrentElement = m_pRootElement;
+
+ m_nCurrentPosition = NODEPOSITION_STARTELEMENT;
+
+ while(true)
+ {
+ switch (m_nCurrentPosition)
+ {
+ case NODEPOSITION_STARTELEMENT:
+ sendStartElement(nullptr, handler, m_pCurrentElement);
+ break;
+ case NODEPOSITION_ENDELEMENT:
+ sendEndElement(nullptr, handler, m_pCurrentElement);
+ break;
+ case NODEPOSITION_NORMAL:
+ sendNode(nullptr, handler, m_pCurrentElement);
+ break;
+ }
+
+ if ( (m_pCurrentElement == m_pRootElement) && (m_nCurrentPosition == NODEPOSITION_ENDELEMENT ))
+ {
+ break;
+ }
+
+ getNextSAXEvent();
+ }
+
+ m_pCurrentElement = pTempCurrentElement;
+ m_nCurrentPosition = nTempCurrentPosition;
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::generateSAXEvents(
+ const uno::Reference< css::xml::sax::XDocumentHandler >& handler,
+ const uno::Reference< css::xml::sax::XDocumentHandler >& xEventKeeperHandler,
+ const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& startNode,
+ const uno::Reference< css::xml::wrapper::XXMLElementWrapper >& endNode )
+{
+ /*
+ * The first SAX event is the startElement of the startNode
+ * element.
+ */
+ bool bHasCurrentElementChild = (m_pCurrentElement->children != nullptr);
+
+ xmlNodePtr pTempCurrentElement = m_pCurrentElement;
+
+ m_pCurrentElement = checkElement(startNode);
+
+ if (m_pCurrentElement->type == XML_ELEMENT_NODE)
+ {
+ m_nCurrentPosition = NODEPOSITION_STARTELEMENT;
+ }
+ else
+ {
+ m_nCurrentPosition = NODEPOSITION_NORMAL;
+ }
+
+ xmlNodePtr pEndNode = checkElement(endNode);
+
+ uno::Reference < css::xml::crypto::sax::XSAXEventKeeper > xSAXEventKeeper( xEventKeeperHandler, uno::UNO_QUERY );
+
+ uno::Reference< css::xml::sax::XDocumentHandler > xHandler = handler;
+
+ while(true)
+ {
+ switch (m_nCurrentPosition)
+ {
+ case NODEPOSITION_STARTELEMENT:
+ sendStartElement(xHandler, xEventKeeperHandler, m_pCurrentElement);
+ break;
+ case NODEPOSITION_ENDELEMENT:
+ sendEndElement(xHandler, xEventKeeperHandler, m_pCurrentElement);
+ break;
+ case NODEPOSITION_NORMAL:
+ sendNode(xHandler, xEventKeeperHandler, m_pCurrentElement);
+ break;
+ default:
+ throw uno::RuntimeException();
+ }
+
+ if (xSAXEventKeeper->isBlocking())
+ {
+ xHandler = nullptr;
+ }
+
+ if (pEndNode == nullptr &&
+ ((bHasCurrentElementChild && m_pCurrentElement == xmlGetLastChild(pTempCurrentElement) && m_nCurrentPosition != NODEPOSITION_STARTELEMENT) ||
+ (!bHasCurrentElementChild && m_pCurrentElement == pTempCurrentElement && m_nCurrentPosition == NODEPOSITION_STARTELEMENT)))
+ {
+ break;
+ }
+
+ getNextSAXEvent();
+
+ /*
+ * If there is an end point specified, then check whether
+ * the current node equals to the end point. If so, stop
+ * generating.
+ */
+ if (pEndNode != nullptr && m_pCurrentElement == pEndNode)
+ {
+ break;
+ }
+ }
+
+ m_pCurrentElement = pTempCurrentElement;
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::rebuildIDLink(
+ const css::uno::Reference< css::xml::wrapper::XXMLElementWrapper >& node )
+{
+ xmlNodePtr pNode = checkElement( node );
+ rebuildIDLink(pNode);
+}
+
+
+/* css::xml::sax::XDocumentHandler */
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::startDocument( )
+{
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::endDocument( )
+{
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::startElement( const OUString& aName, const uno::Reference< css::xml::sax::XAttributeList >& xAttribs )
+{
+ sal_Int32 nLength = xAttribs->getLength();
+ uno::Sequence< css::xml::csax::XMLAttribute > aAttributes (nLength);
+ auto aAttributesRange = asNonConstRange(aAttributes);
+
+ for (int i = 0; i < nLength; ++i)
+ {
+ aAttributesRange[i].sName = xAttribs->getNameByIndex(static_cast<short>(i));
+ aAttributesRange[i].sValue =xAttribs->getValueByIndex(static_cast<short>(i));
+ }
+
+ compressedStartElement(aName, aAttributes);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::endElement( const OUString& aName )
+{
+ saxHelper.endElement(aName);
+ m_pCurrentElement = saxHelper.getCurrentNode();
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::characters( const OUString& aChars )
+{
+ saxHelper.characters(aChars);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::ignorableWhitespace( const OUString& aWhitespaces )
+{
+ saxHelper.ignorableWhitespace(aWhitespaces);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::processingInstruction( const OUString& aTarget, const OUString& aData )
+{
+ saxHelper.processingInstruction(aTarget, aData);
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::setDocumentLocator( const uno::Reference< css::xml::sax::XLocator >& )
+{
+}
+
+/* XCompressedDocumentHandler */
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedStartDocument( )
+{
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedEndDocument( )
+{
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedStartElement( const OUString& aName, const uno::Sequence< css::xml::csax::XMLAttribute >& aAttributes )
+{
+ saxHelper.startElement(aName, aAttributes);
+ m_pCurrentElement = saxHelper.getCurrentNode();
+
+ buildIDAttr( m_pCurrentElement );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedEndElement( const OUString& aName )
+{
+ endElement( aName );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedCharacters( const OUString& aChars )
+{
+ characters( aChars );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedIgnorableWhitespace( const OUString& aWhitespaces )
+{
+ ignorableWhitespace( aWhitespaces );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedProcessingInstruction( const OUString& aTarget, const OUString& aData )
+{
+ processingInstruction( aTarget, aData );
+}
+
+void SAL_CALL XMLDocumentWrapper_XmlSecImpl::compressedSetDocumentLocator( sal_Int32 /*columnNumber*/, sal_Int32 /*lineNumber*/, const OUString& /*publicId*/, const OUString& /*systemId*/ )
+{
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLDocumentWrapper_XmlSecImpl::getImplementationName( )
+{
+ return "com.sun.star.xml.wrapper.XMLDocumentWrapper";
+}
+
+sal_Bool SAL_CALL XMLDocumentWrapper_XmlSecImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL XMLDocumentWrapper_XmlSecImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.xml.wrapper.XMLDocumentWrapper" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_wrapper_XMLDocumentWrapper_get_implementation(
+ uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLDocumentWrapper_XmlSecImpl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.cxx b/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.cxx
new file mode 100644
index 0000000000..ccc4f03dd9
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include "xmlelementwrapper_xmlsecimpl.hxx"
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace com::sun::star;
+
+XMLElementWrapper_XmlSecImpl::XMLElementWrapper_XmlSecImpl(const xmlNodePtr pNode)
+ : m_pElement( pNode )
+{
+}
+
+/* XServiceInfo */
+OUString SAL_CALL XMLElementWrapper_XmlSecImpl::getImplementationName( )
+{
+ return "com.sun.star.xml.wrapper.XMLElementWrapper";
+}
+
+sal_Bool SAL_CALL XMLElementWrapper_XmlSecImpl::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService( this, rServiceName );
+}
+
+uno::Sequence< OUString > SAL_CALL XMLElementWrapper_XmlSecImpl::getSupportedServiceNames( )
+{
+ return { "com.sun.star.xml.wrapper.XMLElementWrapper" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_xml_wrapper_XMLElementWrapper_get_implementation(
+ uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
+{
+ return cppu::acquire(new XMLElementWrapper_XmlSecImpl(nullptr));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.hxx b/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.hxx
new file mode 100644
index 0000000000..93ce721f0b
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/xmlelementwrapper_xmlsecimpl.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/wrapper/XXMLElementWrapper.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <libxml/tree.h>
+#include <xsecxmlsecdllapi.h>
+
+class XMLElementWrapper_XmlSecImpl : public cppu::WeakImplHelper
+<
+ css::xml::wrapper::XXMLElementWrapper,
+ css::lang::XServiceInfo
+>
+/****** XMLElementWrapper_XmlSecImpl.hxx/CLASS XMLElementWrapper_XmlSecImpl ***
+ *
+ * NAME
+ * XMLElementWrapper_XmlSecImpl -- Class to wrap a libxml2 node
+ *
+ * FUNCTION
+ * Used as a wrapper class to transfer a libxml2 node structure
+ * between different UNO components.
+ ******************************************************************************/
+{
+private:
+ /* the libxml2 node wrapped by this object */
+ xmlNodePtr const m_pElement;
+
+public:
+ explicit XMLElementWrapper_XmlSecImpl(const xmlNodePtr pNode);
+
+ /* XXMLElementWrapper */
+
+ /* css::lang::XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+public:
+ /*
+ * NAME
+ * getNativeElement -- Retrieves the libxml2 node wrapped by this object
+ *
+ * SYNOPSIS
+ * pNode = getNativeElement();
+ *
+ * RESULT
+ * pNode - the libxml2 node wrapped by this object
+ */
+ xmlNodePtr getNativeElement( ) const { return m_pElement;}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/xmlsec_init.cxx b/xmlsecurity/source/xmlsec/xmlsec_init.cxx
new file mode 100644
index 0000000000..410408ed2e
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/xmlsec_init.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+#include <xmlsec/xmlsec_init.hxx>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <xmlsec/xmlstreamio.hxx>
+#ifdef XMLSEC_CRYPTO_MSCRYPTO
+#include <xmlsec/mscng/crypto.h>
+#endif
+#ifdef XMLSEC_CRYPTO_NSS
+#include <xmlsec/nss/crypto.h>
+#endif
+
+using namespace css::uno;
+
+XSECXMLSEC_DLLPUBLIC void initXmlSec()
+{
+ //Init xmlsec library
+ if( xmlSecInit() < 0 ) {
+ throw RuntimeException() ;
+ }
+
+ //Init xmlsec crypto engine library
+#ifdef XMLSEC_CRYPTO_MSCRYPTO
+ if( xmlSecMSCngInit() < 0 ) {
+ xmlSecShutdown();
+ throw RuntimeException();
+ }
+#endif
+#ifdef XMLSEC_CRYPTO_NSS
+ if( xmlSecNssInit() < 0 ) {
+ xmlSecShutdown();
+ throw RuntimeException();
+ }
+#endif
+
+ //Enable external stream handlers
+ if( xmlEnableStreamInputCallbacks() < 0 ) {
+#ifdef XMLSEC_CRYPTO_MSCRYPTO
+ xmlSecMSCngShutdown();
+#endif
+#ifdef XMLSEC_CRYPTO_NSS
+ xmlSecNssShutdown();
+#endif
+ xmlSecShutdown() ;
+ throw RuntimeException() ;
+ }
+}
+
+XSECXMLSEC_DLLPUBLIC void deInitXmlSec()
+{
+ xmlDisableStreamInputCallbacks();
+#ifdef XMLSEC_CRYPTO_MSCRYPTO
+ xmlSecMSCngShutdown();
+#endif
+#ifdef XMLSEC_CRYPTO_NSS
+ xmlSecNssShutdown();
+#endif
+ xmlSecShutdown();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/source/xmlsec/xmlstreamio.cxx b/xmlsecurity/source/xmlsec/xmlstreamio.cxx
new file mode 100644
index 0000000000..b3ee767120
--- /dev/null
+++ b/xmlsecurity/source/xmlsec/xmlstreamio.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <xmlsec-wrapper.h>
+
+/*
+ * Implementation of the I/O interfaces based on stream and URI binding
+ */
+#include <xmlsec/xmlstreamio.hxx>
+#include <xmlsec/errorcallback.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/uri.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/crypto/XUriBinding.hpp>
+
+static bool g_bInputCallbacksEnabled = false;
+static bool g_bInputCallbacksRegistered = false;
+
+static css::uno::Reference< css::xml::crypto::XUriBinding > m_xUriBinding ;
+
+extern "C" {
+
+static int xmlStreamMatch( const char* uri )
+{
+ css::uno::Reference< css::io::XInputStream > xInputStream ;
+
+ if (g_bInputCallbacksEnabled && g_bInputCallbacksRegistered)
+ {
+ if( uri == nullptr || !m_xUriBinding.is() )
+ return 0 ;
+ //XMLSec first unescapes the uri and calls this function. For example, we pass the Uri
+ //ObjectReplacements/Object%201 then XMLSec passes ObjectReplacements/Object 1
+ //first. If this failed it would try this
+ //again with the original escaped string. However, it does not get this far, because there
+ //is another callback registered by libxml which claims to be able to handle this uri.
+ OUString sUri =
+ ::rtl::Uri::encode( OUString::createFromAscii( uri ),
+ rtl_UriCharClassUric, rtl_UriEncodeKeepEscapes, RTL_TEXTENCODING_UTF8);
+ xInputStream = m_xUriBinding->getUriBinding( sUri ) ;
+ if (!xInputStream.is())
+ {
+ //Try the passed in uri directly.
+ //For old documents prior OOo 3.0. We did not use URIs then.
+ xInputStream = m_xUriBinding->getUriBinding(
+ OUString::createFromAscii(uri));
+ }
+ }
+ SAL_INFO("xmlsecurity.xmlsec",
+ "xmlStreamMath: uri is '" << uri << "', returning " << xInputStream.is());
+ if (xInputStream.is())
+ return 1;
+ else
+ return 0 ;
+}
+
+static void* xmlStreamOpen( const char* uri )
+{
+ css::uno::Reference< css::io::XInputStream > xInputStream ;
+
+ if (g_bInputCallbacksEnabled && g_bInputCallbacksRegistered)
+ {
+ if( uri == nullptr || !m_xUriBinding.is() )
+ return nullptr ;
+
+ //see xmlStreamMatch
+ OUString sUri =
+ ::rtl::Uri::encode( OUString::createFromAscii( uri ),
+ rtl_UriCharClassUric, rtl_UriEncodeKeepEscapes, RTL_TEXTENCODING_UTF8);
+ xInputStream = m_xUriBinding->getUriBinding( sUri ) ;
+ if (!xInputStream.is())
+ {
+ //For old documents.
+ //try the passed in uri directly.
+ xInputStream = m_xUriBinding->getUriBinding(
+ OUString::createFromAscii(uri));
+ }
+
+ if( xInputStream.is() ) {
+ css::io::XInputStream* pInputStream ;
+ pInputStream = xInputStream.get() ;
+ pInputStream->acquire() ;
+ SAL_INFO("xmlsecurity.xmlsec",
+ "xmlStreamOpen: uri is '" << uri << "', returning context " << pInputStream);
+ return static_cast<void*>(pInputStream) ;
+ }
+ }
+
+ return nullptr ;
+}
+
+static int xmlStreamRead( void* context, char* buffer, int len )
+{
+ int numbers ;
+ css::uno::Reference< css::io::XInputStream > xInputStream ;
+ css::uno::Sequence< sal_Int8 > outSeqs( len ) ;
+
+ numbers = 0 ;
+ if (g_bInputCallbacksEnabled && g_bInputCallbacksRegistered)
+ {
+ if( context != nullptr ) {
+ xInputStream = static_cast<css::io::XInputStream*>(context);
+ if( !xInputStream.is() )
+ return 0 ;
+
+ numbers = xInputStream->readBytes( outSeqs, len ) ;
+ const sal_Int8* readBytes = outSeqs.getArray() ;
+ for( int i = 0 ; i < numbers ; i ++ )
+ *( buffer + i ) = *( readBytes + i ) ;
+ }
+ }
+
+ SAL_INFO("xmlsecurity.xmlsec", "xmlStreamRead: context is " << context << ", buffer is now '"
+ << OString(buffer, numbers) << "'");
+ return numbers ;
+}
+
+static int xmlStreamClose( void * context )
+{
+ if (g_bInputCallbacksEnabled && g_bInputCallbacksRegistered)
+ {
+ if( context != nullptr ) {
+ css::io::XInputStream* pInputStream ;
+ pInputStream = static_cast<css::io::XInputStream*>(context);
+ pInputStream->release() ;
+ SAL_INFO("xmlsecurity.xmlsec", "xmlStreamRead: closed context " << context);
+ }
+ }
+
+ return 0 ;
+}
+
+}
+
+int xmlEnableStreamInputCallbacks()
+{
+ if (!g_bInputCallbacksEnabled)
+ {
+ //Register the callbacks into xmlSec
+ //In order to make the xmlsec io finding the callbacks firstly,
+ //I put the callbacks at the very beginning.
+
+ //Cleanup the older callbacks.
+ //Notes: all none default callbacks will lose.
+ xmlSecIOCleanupCallbacks() ;
+
+ // Make sure that errors are reported via SAL_WARN().
+ setErrorRecorder();
+ comphelper::ScopeGuard g([] { clearErrorRecorder(); });
+
+ // Newer xmlsec wants the callback order in the opposite direction.
+ if (xmlSecCheckVersionExt(1, 2, 26, xmlSecCheckVersionABICompatible))
+ {
+ //Register the default callbacks.
+ //Notes: the error will cause xmlsec working problems.
+ int cbs = xmlSecIORegisterDefaultCallbacks() ;
+ if( cbs < 0 ) {
+ return -1 ;
+ }
+
+ //Register my classbacks.
+ cbs = xmlSecIORegisterCallbacks(
+ xmlStreamMatch,
+ xmlStreamOpen,
+ xmlStreamRead,
+ xmlStreamClose ) ;
+ if( cbs < 0 ) {
+ return -1 ;
+ }
+ }
+ else
+ {
+ //Register my classbacks.
+ int cbs = xmlSecIORegisterCallbacks(
+ xmlStreamMatch,
+ xmlStreamOpen,
+ xmlStreamRead,
+ xmlStreamClose ) ;
+ if( cbs < 0 ) {
+ return -1 ;
+ }
+
+ //Register the default callbacks.
+ //Notes: the error will cause xmlsec working problems.
+ cbs = xmlSecIORegisterDefaultCallbacks() ;
+ if( cbs < 0 ) {
+ return -1 ;
+ }
+ }
+
+ g_bInputCallbacksEnabled = true;
+ }
+
+ return 0 ;
+}
+
+int xmlRegisterStreamInputCallbacks(
+ css::uno::Reference< css::xml::crypto::XUriBinding > const & aUriBinding
+) {
+ if (!g_bInputCallbacksEnabled)
+ {
+ if( xmlEnableStreamInputCallbacks() < 0 )
+ return -1 ;
+ }
+
+ if (!g_bInputCallbacksRegistered)
+ g_bInputCallbacksRegistered = true;
+
+ m_xUriBinding = aUriBinding ;
+
+ return 0 ;
+}
+
+int xmlUnregisterStreamInputCallbacks()
+{
+ if (g_bInputCallbacksRegistered)
+ {
+ //Clear the uri-stream binding
+ m_xUriBinding.clear() ;
+
+ //disable the registered flag
+ g_bInputCallbacksRegistered = false;
+ }
+
+ return 0 ;
+}
+
+void xmlDisableStreamInputCallbacks() {
+ xmlUnregisterStreamInputCallbacks() ;
+ g_bInputCallbacksEnabled = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */