summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Keller <Rainer.Keller@qt.io>2019-02-04 16:14:25 +0100
committerRainer Keller <Rainer.Keller@qt.io>2019-03-06 15:35:04 +0000
commit19073534dff44d76e8d0c51358bdc0e4520d6907 (patch)
treea6db4b8186ad48134a8e7179d55b26b14d12e9bc
parentdee609343270c17b9ff132860eda822eb01028ed (diff)
tests: Add security extensions to testserver
Change-Id: I3f463f290d86f38dbf7fd7ae2a67d643b31113d1 Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
-rw-r--r--LICENSE-CC0110
-rw-r--r--src/opcua/doc/src/security.qdoc2
-rw-r--r--tests/auto/declarative/DiscoveryTest.qml5
-rw-r--r--tests/auto/qopcuaclient/data.qrc5
-rw-r--r--tests/auto/qopcuaclient/qopcuaclient.pro6
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp9
-rw-r--r--tests/open62541-testserver/certs.qrc6
-rw-r--r--tests/open62541-testserver/open62541-testserver.pro17
-rw-r--r--tests/open62541-testserver/pki/own/certs/open62541-testserver.derbin0 -> 1031 bytes
-rw-r--r--tests/open62541-testserver/pki/own/private/open62541-testserver.derbin0 -> 1190 bytes
-rw-r--r--tests/open62541-testserver/pki/trusted/certs/.gitkeep0
-rw-r--r--tests/open62541-testserver/qt_attribution.json23
-rw-r--r--tests/open62541-testserver/security_addon.cpp121
-rw-r--r--tests/open62541-testserver/security_addon.h23
-rw-r--r--tests/open62541-testserver/testserver.cpp163
-rw-r--r--tests/open62541-testserver/testserver.h4
16 files changed, 489 insertions, 5 deletions
diff --git a/LICENSE-CC0 b/LICENSE-CC0
new file mode 100644
index 0000000..ad7fdad
--- /dev/null
+++ b/LICENSE-CC0
@@ -0,0 +1,110 @@
+Creative Commons CCZero 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/src/opcua/doc/src/security.qdoc b/src/opcua/doc/src/security.qdoc
index 8575cce..4fc8e5d 100644
--- a/src/opcua/doc/src/security.qdoc
+++ b/src/opcua/doc/src/security.qdoc
@@ -65,7 +65,7 @@
\code
[ req ]
default_bits = 2048
- default_md = sha512
+ default_md = sha256
distinguished_name = subject
req_extensions = req_ext
x509_extensions = req_ext
diff --git a/tests/auto/declarative/DiscoveryTest.qml b/tests/auto/declarative/DiscoveryTest.qml
index c5e09bc..9a64365 100644
--- a/tests/auto/declarative/DiscoveryTest.qml
+++ b/tests/auto/declarative/DiscoveryTest.qml
@@ -256,7 +256,10 @@ Item {
compare(endpointsCountSpy2.count, 1);
compare(endpointsStatusSpy2.count, 2);
compare(endpointsChangedSpy2.count, 2);
- compare(myEndpoints2.count, 1);
+ if (SERVER_SUPPORTS_SECURITY)
+ compare(myEndpoints2.count, 5);
+ else
+ compare(myEndpoints2.count, 1);
verify(myEndpoints2.at(0).endpointUrl.startsWith("opc.tcp://"));
compare(myEndpoints2.at(0).securityPolicyUri, "http://opcfoundation.org/UA/SecurityPolicy#None");
diff --git a/tests/auto/qopcuaclient/data.qrc b/tests/auto/qopcuaclient/data.qrc
new file mode 100644
index 0000000..eba56cb
--- /dev/null
+++ b/tests/auto/qopcuaclient/data.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>../../open62541-testserver/pki/own/certs/open62541-testserver.der</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qopcuaclient/qopcuaclient.pro b/tests/auto/qopcuaclient/qopcuaclient.pro
index 930b54d..62c50c7 100644
--- a/tests/auto/qopcuaclient/qopcuaclient.pro
+++ b/tests/auto/qopcuaclient/qopcuaclient.pro
@@ -12,3 +12,9 @@ HEADERS += \
INCLUDEPATH += \
$$PWD/../../common
+
+RESOURCES += data.qrc
+
+# This tries to check if the server supports security
+QT += opcua_private
+qtConfig(mbedtls): DEFINES += SERVER_SUPPORTS_SECURITY
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index 15edffc..1b39781 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -734,7 +734,16 @@ void Tst_QOpcUaClient::requestEndpoints()
QCOMPARE(desc[0].transportProfileUri(), QStringLiteral("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"));
QCOMPARE(desc[0].securityLevel(), 0);
QCOMPARE(desc[0].securityMode(), QOpcUaEndpointDescription::MessageSecurityMode::None);
+#ifdef SERVER_SUPPORTS_SECURITY
+ QFile file(":/open62541-testserver/pki/own/certs/open62541-testserver.der");
+ QVERIFY(file.open(QFile::ReadOnly));
+ const auto serverCertificate = file.readAll();
+ QVERIFY(serverCertificate.size() > 0);
+ file.close();
+ QCOMPARE(desc[0].serverCertificate(), serverCertificate);
+#else
QCOMPARE(desc[0].serverCertificate(), QByteArray());
+#endif
QCOMPARE(desc[0].userIdentityTokens().size(), 2);
QCOMPARE(desc[0].userIdentityTokens()[0].policyId(), QStringLiteral("open62541-anonymous-policy"));
diff --git a/tests/open62541-testserver/certs.qrc b/tests/open62541-testserver/certs.qrc
new file mode 100644
index 0000000..c0eb8a2
--- /dev/null
+++ b/tests/open62541-testserver/certs.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>pki/own/private/open62541-testserver.der</file>
+ <file>pki/own/certs/open62541-testserver.der</file>
+ </qresource>
+</RCC>
diff --git a/tests/open62541-testserver/open62541-testserver.pro b/tests/open62541-testserver/open62541-testserver.pro
index 68a0069..5e9bb14 100644
--- a/tests/open62541-testserver/open62541-testserver.pro
+++ b/tests/open62541-testserver/open62541-testserver.pro
@@ -11,6 +11,10 @@ CONFIG += c++11 console
QT += opcua-private
qtConfig(open62541):!qtConfig(system-open62541) {
+ qtConfig(mbedtls):{
+ QMAKE_USE_PRIVATE += mbedtls
+ DEFINES += UA_ENABLE_ENCRYPTION
+ }
include($$PWD/../../src/3rdparty/open62541.pri)
} else {
QMAKE_USE_PRIVATE += open62541
@@ -18,6 +22,13 @@ qtConfig(open62541):!qtConfig(system-open62541) {
win32: DESTDIR = ./
+# This file can only be compiled in case of TLS support
+qtConfig(mbedtls) {
+ # Use custom compiler from src/3rdparty/open62541.pri to hide warning caused by
+ # including open62541.h
+ OPEN62541_SOURCES += security_addon.cpp
+}
+
SOURCES += \
main.cpp \
testserver.cpp \
@@ -26,4 +37,8 @@ SOURCES += \
HEADERS += \
- testserver.h
+ testserver.h \
+ security_addon.h \
+
+RESOURCES += certs.qrc
+
diff --git a/tests/open62541-testserver/pki/own/certs/open62541-testserver.der b/tests/open62541-testserver/pki/own/certs/open62541-testserver.der
new file mode 100644
index 0000000..c8bad3d
--- /dev/null
+++ b/tests/open62541-testserver/pki/own/certs/open62541-testserver.der
Binary files differ
diff --git a/tests/open62541-testserver/pki/own/private/open62541-testserver.der b/tests/open62541-testserver/pki/own/private/open62541-testserver.der
new file mode 100644
index 0000000..f396b44
--- /dev/null
+++ b/tests/open62541-testserver/pki/own/private/open62541-testserver.der
Binary files differ
diff --git a/tests/open62541-testserver/pki/trusted/certs/.gitkeep b/tests/open62541-testserver/pki/trusted/certs/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/open62541-testserver/pki/trusted/certs/.gitkeep
diff --git a/tests/open62541-testserver/qt_attribution.json b/tests/open62541-testserver/qt_attribution.json
new file mode 100644
index 0000000..7536c1c
--- /dev/null
+++ b/tests/open62541-testserver/qt_attribution.json
@@ -0,0 +1,23 @@
+{
+ "Id": "open62541",
+ "Name": "Open62541",
+ "QDocModule": "qtopcua",
+ "QtUsage": "Used in the Qt OPC UA module to build the test server.",
+ "Description": "Open62541 is an open source implementation of the OPC UA protocol.",
+ "Homepage": "https://open62541.org/",
+ "Version": "0.3",
+ "License": "Creative Commons CCZero 1.0 Universal License",
+ "LicenseId": "CC0-1.0",
+ "LicenseFile": "../../LICENSE-CC0",
+ "Copyright": "Bauer, Maximilian Ebrahimi
+ Reza <reza.ebrahimi.dev (at) gmail.com>
+ Graube, Markus <markus.graube (at) tu-dresden.de>
+ Gruener, Sten <s.gruener (at) plt.rwth-aachen.de>
+ Iatrou, Chris Paul <chris_paul.iatrou (at) tu-dresden.de>
+ Jeromin, Holger Palm, Florian <f.palm (at) plt.rwth-aachen.de>
+ Pfrommer, Julius <julius.pfrommer (at) iosb.fraunhofer.edu>
+ Profanter, Stefan <profanter (at) fortiss.org>
+ Stalder, Thomas <t.stalder (at) bluetimeconcept.ch>
+ Urbas, Leon <leon.urbas (at) tu-dresden.de>
+ "
+}
diff --git a/tests/open62541-testserver/security_addon.cpp b/tests/open62541-testserver/security_addon.cpp
new file mode 100644
index 0000000..99a8809
--- /dev/null
+++ b/tests/open62541-testserver/security_addon.cpp
@@ -0,0 +1,121 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB
+ * Copyright 2017 (c) Julian Grothoff
+ * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
+ * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
+ * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ */
+
+//
+// This code was mostly taken from the open62541 project from file plugins/ua_config_default.c
+//
+
+#include "security_addon.h"
+
+UA_StatusCode createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint, const UA_ByteString localCertificate)
+{
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_SecurityPolicy_None(&endpoint->securityPolicy, NULL, localCertificate, conf->logger);
+ endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ UA_StatusCode retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize = conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf,
+ UA_Endpoint *endpoint,
+ UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate,
+ const UA_ByteString localPrivateKey) {
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_StatusCode retval =
+ UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, &conf->certificateVerification,
+ localCertificate, localPrivateKey, conf->logger);
+ if (retval != UA_STATUSCODE_GOOD) {
+ endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);
+ return retval;
+ }
+
+ endpoint->endpointDescription.securityMode = securityMode;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize =
+ conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+createSecurityPolicyBasic256Sha256Endpoint(UA_ServerConfig *const conf,
+ UA_Endpoint *endpoint,
+ UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate,
+ const UA_ByteString localPrivateKey) {
+ UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+ UA_StatusCode retval =
+ UA_SecurityPolicy_Basic256Sha256(&endpoint->securityPolicy, &conf->certificateVerification, localCertificate,
+ localPrivateKey, conf->logger);
+ if (retval != UA_STATUSCODE_GOOD) {
+ endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);
+ return retval;
+ }
+
+ endpoint->endpointDescription.securityMode = securityMode;
+ endpoint->endpointDescription.securityPolicyUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
+ endpoint->endpointDescription.transportProfileUri =
+ UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+ /* Enable all login mechanisms from the access control plugin */
+ retval = UA_Array_copy(conf->accessControl.userTokenPolicies,
+ conf->accessControl.userTokenPoliciesSize,
+ (void **)&endpoint->endpointDescription.userIdentityTokens,
+ &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+ if (retval != UA_STATUSCODE_GOOD)
+ return retval;
+ endpoint->endpointDescription.userIdentityTokensSize =
+ conf->accessControl.userTokenPoliciesSize;
+
+ UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+ UA_ApplicationDescription_copy(&conf->applicationDescription,
+ &endpoint->endpointDescription.server);
+
+ return UA_STATUSCODE_GOOD;
+}
diff --git a/tests/open62541-testserver/security_addon.h b/tests/open62541-testserver/security_addon.h
new file mode 100644
index 0000000..455092f
--- /dev/null
+++ b/tests/open62541-testserver/security_addon.h
@@ -0,0 +1,23 @@
+
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ * Copyright 2017 (c) Julius Pfrommer, Fraunhofer IOSB
+ * Copyright 2017 (c) Julian Grothoff
+ * Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
+ * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ * Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
+ * Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ */
+
+//
+// This code was taken from the open62541 project from file plugins/ua_config_default.c
+//
+
+#include "open62541.h"
+
+UA_StatusCode createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint, const UA_ByteString localCertificate);
+UA_StatusCode createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf, UA_Endpoint *endpoint, UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate, const UA_ByteString localPrivateKey);
+UA_StatusCode createSecurityPolicyBasic256Sha256Endpoint(UA_ServerConfig *const conf, UA_Endpoint *endpoint, UA_MessageSecurityMode securityMode,
+ const UA_ByteString localCertificate, const UA_ByteString localPrivateKey);
diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp
index b0edba9..2e79d72 100644
--- a/tests/open62541-testserver/testserver.cpp
+++ b/tests/open62541-testserver/testserver.cpp
@@ -42,15 +42,24 @@
#include <QtCore/QDebug>
#include <QtCore/QLoggingCategory>
#include <QtCore/QUuid>
+#include <QDir>
+#include <QFile>
+
+#if defined UA_ENABLE_ENCRYPTION
+#include "security_addon.h"
+#endif
#include <cstring>
QT_BEGIN_NAMESPACE
+const UA_UInt16 portNumber = 43344;
+
// Node ID conversion is included from the open62541 plugin but warnings from there should be logged
// using qt.opcua.testserver instead of qt.opcua.plugins.open62541 for usage in the test server
Q_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_OPEN62541, "qt.opcua.testserver")
+
TestServer::TestServer(QObject *parent) : QObject(parent)
{
m_timer.setInterval(30);
@@ -65,15 +74,165 @@ TestServer::~TestServer()
UA_ServerConfig_delete(m_config);
}
-bool TestServer::init()
+bool TestServer::createInsecureServerConfig()
+{
+ m_config = UA_ServerConfig_new_minimal(portNumber, nullptr);
+ return m_config != nullptr;
+}
+
+#if defined UA_ENABLE_ENCRYPTION
+static UA_ByteString loadFile(const QString &filePath) {
+ UA_ByteString fileContents = UA_STRING_NULL;
+ fileContents.length = 0;
+
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly))
+ return fileContents;
+
+ fileContents.length = file.size();
+ fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
+ if (!fileContents.data)
+ return fileContents;
+
+ if (file.read(reinterpret_cast<char*>(fileContents.data), fileContents.length) != fileContents.length) {
+ UA_ByteString_deleteMembers(&fileContents);
+ fileContents.length = 0;
+ return fileContents;
+ }
+ return fileContents;
+}
+
+bool TestServer::createSecureServerConfig()
{
- m_config = UA_ServerConfig_new_minimal(43344, nullptr);
+ const QString certificateFilePath = QLatin1String(":/pki/own/certs/open62541-testserver.der");
+ const QString privateKeyFilePath = QLatin1String(":/pki/own/private/open62541-testserver.der");
+
+ UA_ByteString certificate = loadFile(certificateFilePath);
+ UaDeleter<UA_ByteString> certificateDeleter(&certificate, UA_ByteString_deleteMembers);
+ UA_ByteString privateKey = loadFile(privateKeyFilePath);
+ UaDeleter<UA_ByteString> privateKeyDeleter(&privateKey, UA_ByteString_deleteMembers);
+
+ if (certificate.length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Failed to load certificate %s", certificateFilePath.toLocal8Bit().constData());
+ return false;
+ }
+ if (privateKey.length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "Failed to load private key %s", privateKeyFilePath.toLocal8Bit().constData());
+ return false;
+ }
+
+ // Load the trustlist
+ QDir trustDir(":/pki/trusted/certs");
+ if (!trustDir.exists()) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Trust directory does not exist");
+ return false;
+ }
+
+ const auto trustedCerts = trustDir.entryList(QDir::Files);
+ const size_t trustListSize = trustedCerts.size();
+ int i = 0;
+
+ UA_STACKARRAY(UA_ByteString, trustList, trustListSize);
+ UaArrayDeleter<UA_TYPES_BYTESTRING> trustListDeleter(&trustList, trustListSize);
+
+ for (const auto &entry : trustedCerts) {
+ trustList[i] = loadFile(trustDir.filePath(entry));
+ if (trustList[i].length == 0) {
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Failed to load trusted certificate");
+ return false;
+ } else {
+ UA_LOG_DEBUG(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Trusted certificate %s loaded", entry.toLocal8Bit().constData());
+ }
+ ++i;
+ }
+
+ // Loading of a revocation list currently unsupported
+ UA_ByteString *revocationList = nullptr;
+ size_t revocationListSize = 0;
+
+ m_config = UA_ServerConfig_new_minimal(portNumber, nullptr);
if (!m_config)
return false;
+ UA_StatusCode retval = UA_CertificateVerification_Trustlist(&m_config->certificateVerification,
+ trustList, trustListSize,
+ revocationList, revocationListSize);
+
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = UA_Nodestore_default_new(&m_config->nodestore);
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ if (trustListSize == 0)
+ UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+ "No CA trust-list provided. Any remote certificate will be accepted.");
+
+ /* Allocate the endpoints */
+ m_config->endpointsSize = 0;
+ m_config->endpoints = (UA_Endpoint *)UA_malloc(sizeof(UA_Endpoint) * 5);
+ if (!m_config->endpoints)
+ return false;
+
+ /* Populate the endpoints */
+ retval = createSecurityPolicyNoneEndpoint(m_config, &m_config->endpoints[m_config->endpointsSize], certificate);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic128Rsa15Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGN, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic128Rsa15Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic256Sha256Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGN, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ retval = createSecurityPolicyBasic256Sha256Endpoint(m_config, &m_config->endpoints[m_config->endpointsSize],
+ UA_MESSAGESECURITYMODE_SIGNANDENCRYPT, certificate, privateKey);
+ ++m_config->endpointsSize;
+ if (retval != UA_STATUSCODE_GOOD)
+ return false;
+
+ // Do not delete items on success.
+ // They will be used by the server.
+ certificateDeleter.release();
+ privateKeyDeleter.release();
+ trustListDeleter.release();
+
+ return true;
+}
+#endif
+
+bool TestServer::init()
+{
+ bool success;
+
+#if defined UA_ENABLE_ENCRYPTION
+ success = createSecureServerConfig();
+#else
+ success = createInsecureServerConfig();
+#endif
+
// This is needed for COIN because the hostname returned by gethostname() is not resolvable.
m_config->customHostname = UA_String_fromChars("localhost");
+ if (!success || !m_config)
+ return false;
+
m_server = UA_Server_new(m_config);
if (!m_server)
diff --git a/tests/open62541-testserver/testserver.h b/tests/open62541-testserver/testserver.h
index 0a0f383..c70fef6 100644
--- a/tests/open62541-testserver/testserver.h
+++ b/tests/open62541-testserver/testserver.h
@@ -55,6 +55,10 @@ public:
explicit TestServer(QObject *parent = nullptr);
~TestServer();
bool init();
+ bool createInsecureServerConfig();
+#if defined UA_ENABLE_ENCRYPTION
+ bool createSecureServerConfig();
+#endif
int registerNamespace(const QString &ns);
UA_NodeId addFolder(const QString &nodeString, const QString &displayName, const QString &description = QString());