summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Keller <Rainer.Keller@qt.io>2019-05-22 16:07:16 +0200
committerRainer Keller <Rainer.Keller@qt.io>2019-11-12 09:56:50 +0100
commit00f86fd8431e3c89d2e626cbaf965b75bf2ea8d4 (patch)
treec5d45972c0f6c24dd47724c36e000a03b86620b0
parenta3506e293dd4a762764554b2792c2209d0e409c7 (diff)
Add support for generating X509 Certificate Signing Requests
Change-Id: I6e69d38ff9285a3b7f84b7470fdd7a80505c4f2b Reviewed-by: Rainer Keller <Rainer.Keller@qt.io>
-rw-r--r--examples/opcua/opcua.pro4
-rw-r--r--examples/opcua/x509/doc/x509.qdoc36
-rw-r--r--examples/opcua/x509/main.cpp123
-rw-r--r--examples/opcua/x509/x509.pro12
-rw-r--r--src/opcua/opcua.pro4
-rw-r--r--src/opcua/x509/openssl_symbols.cpp1335
-rw-r--r--src/opcua/x509/openssl_symbols_p.h566
-rw-r--r--src/opcua/x509/qopcuakeypair.cpp198
-rw-r--r--src/opcua/x509/qopcuakeypair.h90
-rw-r--r--src/opcua/x509/qopcuakeypair_openssl.cpp264
-rw-r--r--src/opcua/x509/qopcuakeypair_p.h84
-rw-r--r--src/opcua/x509/qopcuax509certificatesigningrequest.cpp236
-rw-r--r--src/opcua/x509/qopcuax509certificatesigningrequest.h86
-rw-r--r--src/opcua/x509/qopcuax509certificatesigningrequest_openssl.cpp509
-rw-r--r--src/opcua/x509/qopcuax509certificatesigningrequest_p.h91
-rw-r--r--src/opcua/x509/qopcuax509distinguishedname.cpp167
-rw-r--r--src/opcua/x509/qopcuax509distinguishedname.h72
-rw-r--r--src/opcua/x509/qopcuax509extension.cpp126
-rw-r--r--src/opcua/x509/qopcuax509extension.h65
-rw-r--r--src/opcua/x509/qopcuax509extension_p.h63
-rw-r--r--src/opcua/x509/qopcuax509extensionbasicconstraints.cpp138
-rw-r--r--src/opcua/x509/qopcuax509extensionbasicconstraints.h65
-rw-r--r--src/opcua/x509/qopcuax509extensionextendedkeyusage.cpp140
-rw-r--r--src/opcua/x509/qopcuax509extensionextendedkeyusage.h72
-rw-r--r--src/opcua/x509/qopcuax509extensionkeyusage.cpp149
-rw-r--r--src/opcua/x509/qopcuax509extensionkeyusage.h77
-rw-r--r--src/opcua/x509/qopcuax509extensionsubjectalternativename.cpp134
-rw-r--r--src/opcua/x509/qopcuax509extensionsubjectalternativename.h67
-rw-r--r--src/opcua/x509/qopcuax509utils.cpp62
-rw-r--r--src/opcua/x509/qopcuax509utils_p.h84
-rw-r--r--src/opcua/x509/qsslsocket_openssl11_symbols_p.h178
-rw-r--r--src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h196
-rw-r--r--src/opcua/x509/x509.pri33
-rw-r--r--src/plugins/opcua/open62541/qopen62541utils.h2
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/x509/tst_x509.cpp274
-rw-r--r--tests/auto/x509/x509.pro8
37 files changed, 5809 insertions, 4 deletions
diff --git a/examples/opcua/opcua.pro b/examples/opcua/opcua.pro
index eb396c5..dc5f5f4 100644
--- a/examples/opcua/opcua.pro
+++ b/examples/opcua/opcua.pro
@@ -2,7 +2,9 @@ TEMPLATE = subdirs
qtHaveModule(widgets): SUBDIRS += \
opcuaviewer \
-QT_FOR_CONFIG += opcua-private
+QT_FOR_CONFIG += opcua-private core-private
+
+qtConfig(ssl):!darwin:!winrt: SUBDIRS += x509
qtConfig(open62541) {
qtHaveModule(quick): SUBDIRS += waterpump
diff --git a/examples/opcua/x509/doc/x509.qdoc b/examples/opcua/x509/doc/x509.qdoc
new file mode 100644
index 0000000..506dc82
--- /dev/null
+++ b/examples/opcua/x509/doc/x509.qdoc
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the QtOpcUa module.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example x509
+ \ingroup qtopcua-examples
+ \title Qt OPC UA X509 Support Example
+ \brief Shows how to generate keys and certificate signing requests.
+
+ This example show how client applications can generate their own self-signed certificate
+ or generate a certificate signing request.
+*/
diff --git a/examples/opcua/x509/main.cpp b/examples/opcua/x509/main.cpp
new file mode 100644
index 0000000..b246fc3
--- /dev/null
+++ b/examples/opcua/x509/main.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QOpcUaProvider>
+#include <QOpcUaKeyPair>
+#include <QOpcUaX509CertificateSigningRequest>
+#include <QOpcUaX509ExtensionSubjectAlternativeName>
+#include <QOpcUaX509ExtensionBasicConstraints>
+#include <QOpcUaX509ExtensionKeyUsage>
+#include <QFile>
+
+int main(int argc, char **argv)
+{
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+
+ // Generate RSA Key
+ QOpcUaKeyPair key;
+ key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024);
+
+ // Save private key to file
+ QByteArray keyData = key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Aes128Cbc, "password");
+
+ QFile keyFile("privateKey.pem");
+ keyFile.open(QFile::WriteOnly);
+ keyFile.write(keyData);
+ keyFile.close();
+
+ // Create a certificate signing request
+ QOpcUaX509CertificateSigningRequest csr;
+
+ // Set the subject of the certificate
+ QOpcUaX509DistinguishedName dn;
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CommonName, "QtOpcUaViewer");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, "DE");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, "The Qt Company");
+ csr.setSubject(dn);
+
+ // The subject alternative name extension is needed for OPC UA
+ QOpcUaX509ExtensionSubjectAlternativeName *san = new QOpcUaX509ExtensionSubjectAlternativeName;
+ san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "foo.com");
+ san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::URI, "urn:foo.com:The%20Qt%20Company:QtOpcUaViewer");
+ san->setCritical(true);
+ csr.addExtension(san);
+
+ // Set the certificate basic constraints
+ QOpcUaX509ExtensionBasicConstraints *bc = new QOpcUaX509ExtensionBasicConstraints;
+ bc->setCa(false);
+ bc->setCritical(true);
+ csr.addExtension(bc);
+
+ // Set the key usage constraints
+ QOpcUaX509ExtensionKeyUsage *ku = new QOpcUaX509ExtensionKeyUsage;
+ ku->setCritical(true);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DigitalSignature);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::NonRepudiation);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DataEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CertificateSigning);
+ csr.addExtension(ku);
+
+ // Now there are two options:
+ // 1. When you need to get your certificate signing request signed by a certificate authority
+ // you have to use the request data.
+ // 2. When there is no certificate authority you have to self-sign the request.
+
+ // Option 1
+ QByteArray certificateSigingRequestData = csr.createRequest(key);
+
+ // Option 2
+ QByteArray selfSignedCertificateData = csr.createSelfSignedCertificate(key);
+
+ return 0;
+}
diff --git a/examples/opcua/x509/x509.pro b/examples/opcua/x509/x509.pro
new file mode 100644
index 0000000..f098656
--- /dev/null
+++ b/examples/opcua/x509/x509.pro
@@ -0,0 +1,12 @@
+QT += opcua
+CONFIG += c++11
+DEPENDPATH += INCLUDEPATH
+
+SOURCES += main.cpp \
+
+#install
+target.path = $$[QT_INSTALL_EXAMPLES]/opcua/x509
+INSTALLS += target
+
+HEADERS += \
+
diff --git a/src/opcua/opcua.pro b/src/opcua/opcua.pro
index 52daeb8..a67ff03 100644
--- a/src/opcua/opcua.pro
+++ b/src/opcua/opcua.pro
@@ -1,9 +1,11 @@
TARGET = QtOpcUa
-QT += core-private network
+QT += core-private network network-private
QT -= gui
+QT_FOR_CONFIG += core-private
include(core/core.pri)
include(client/client.pri)
+qtConfig(ssl):!darwin:!winrt: include(x509/x509.pri)
MODULE_PLUGIN_TYPES = opcua
QMAKE_DOCS = $$PWD/doc/qtopcua.qdocconf
diff --git a/src/opcua/x509/openssl_symbols.cpp b/src/opcua/x509/openssl_symbols.cpp
new file mode 100644
index 0000000..b3207a4
--- /dev/null
+++ b/src/opcua/x509/openssl_symbols.cpp
@@ -0,0 +1,1335 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#include "openssl_symbols_p.h"
+#include <QtCore/qurl.h>
+
+#ifdef Q_OS_WIN
+# include <private/qsystemlibrary_p.h>
+#elif QT_CONFIG(library)
+# include <QtCore/qlibrary.h>
+#endif
+#include <QtCore/qmutex.h>
+#include <QtCore/qdatetime.h>
+#if defined(Q_OS_UNIX)
+#include <QtCore/qdir.h>
+#endif
+#include <QtCore/private/qmemory_p.h>
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+#include <link.h>
+#endif
+#ifdef Q_OS_DARWIN
+#include "private/qcore_mac_p.h"
+#endif
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSsl, "qt.opcua.ssl");
+
+
+/*
+ Note to maintainer:
+ -------------------
+
+ We load OpenSSL symbols dynamically. Because symbols are known to
+ disappear, and signatures sometimes change, between releases, we need to
+ be careful about how this is done. To ensure we don't end up dereferencing
+ null function pointers, and continue running even if certain functions are
+ missing, we define helper functions for each of the symbols we load from
+ OpenSSL, all prefixed with "q_" (declared in
+ qsslsocket_openssl_symbols_p.h). So instead of calling SSL_connect
+ directly, we call q_SSL_connect, which is a function that checks if the
+ actual SSL_connect fptr is null, and returns a failure if it is, or calls
+ SSL_connect if it isn't.
+
+ This requires a somewhat tedious process of declaring each function we
+ want to call in OpenSSL thrice: once with the q_, in _p.h, once using the
+ DEFINEFUNC macros below, and once in the function that actually resolves
+ the symbols, below the DEFINEFUNC declarations below.
+
+ There's one DEFINEFUNC macro declared for every number of arguments
+ exposed by OpenSSL (feel free to extend when needed). The easiest thing to
+ do is to find an existing entry that matches the arg count of the function
+ you want to import, and do the same.
+
+ The first macro arg is the function return type. The second is the
+ verbatim name of the function/symbol. Then follows a list of N pairs of
+ argument types with a variable name, and just the variable name (char *a,
+ a, char *b, b, etc). Finally there's two arguments - a suitable return
+ statement for the error case (for an int function, return 0 or return -1
+ is usually right). Then either just "return" or DUMMYARG, the latter being
+ for void functions.
+
+ Note: Take into account that these macros and declarations are processed
+ at compile-time, and the result depends on the OpenSSL headers the
+ compiling host has installed, but the symbols are resolved at run-time,
+ possibly with a different version of OpenSSL.
+*/
+
+#ifndef QT_LINKED_OPENSSL
+
+namespace {
+void qsslSocketUnresolvedSymbolWarning(const char *functionName)
+{
+ qCWarning(lcSsl, "QSslSocket: cannot call unresolved function %s", functionName);
+}
+
+#if QT_CONFIG(library)
+void qsslSocketCannotResolveSymbolWarning(const char *functionName)
+{
+ qCWarning(lcSsl, "QSslSocket: cannot resolve %s", functionName);
+}
+#endif
+
+}
+
+#endif // QT_LINKED_OPENSSL
+
+#if QT_CONFIG(opensslv11)
+
+// Below are the functions first introduced in version 1.1:
+
+DEFINEFUNC(const unsigned char *, ASN1_STRING_get0_data, const ASN1_STRING *a, a, return nullptr, return)
+DEFINEFUNC2(int, OPENSSL_init_ssl, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
+DEFINEFUNC2(int, OPENSSL_init_crypto, uint64_t opts, opts, const OPENSSL_INIT_SETTINGS *settings, settings, return 0, return)
+DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return nullptr, return)
+DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(int, BN_is_word, BIGNUM *a, a, BN_ULONG w, w, return 0, return)
+DEFINEFUNC(int, EVP_CIPHER_CTX_reset, EVP_CIPHER_CTX *c, c, return 0, return)
+DEFINEFUNC(int, EVP_PKEY_base_id, EVP_PKEY *a, a, return NID_undef, return)
+DEFINEFUNC(int, RSA_bits, RSA *a, a, return 0, return)
+DEFINEFUNC(int, DSA_bits, DSA *a, a, return 0, return)
+DEFINEFUNC(int, OPENSSL_sk_num, OPENSSL_STACK *a, a, return -1, return)
+DEFINEFUNC2(void, OPENSSL_sk_pop_free, OPENSSL_STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
+DEFINEFUNC(OPENSSL_STACK *, OPENSSL_sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(void, OPENSSL_sk_push, OPENSSL_STACK *a, a, void *b, b, return, DUMMYARG)
+DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
+DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
+DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
+#ifdef TLS1_3_VERSION
+DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
+#endif
+DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return)
+DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return)
+DEFINEFUNC6(int, CRYPTO_get_ex_new_index, int class_index, class_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
+DEFINEFUNC2(unsigned long, SSL_set_options, SSL *ssl, ssl, unsigned long op, op, return 0, return)
+
+DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, X509_up_ref, X509 *a, a, return, DUMMYARG)
+DEFINEFUNC(ASN1_TIME *, X509_getm_notBefore, X509 *a, a, return nullptr, return)
+DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return nullptr, return)
+DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return)
+DEFINEFUNC(EVP_PKEY *, X509_get_pubkey, X509 *a, a, return nullptr, return)
+DEFINEFUNC2(void, X509_STORE_set_verify_cb, X509_STORE *a, a, X509_STORE_CTX_verify_cb verify_cb, verify_cb, return, DUMMYARG)
+DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get0_chain, X509_STORE_CTX *a, a, return nullptr, return)
+DEFINEFUNC3(void, CRYPTO_free, void *str, str, const char *file, file, int line, line, return, DUMMYARG)
+DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return)
+DEFINEFUNC(const char *, OpenSSL_version, int a, a, return nullptr, return)
+DEFINEFUNC(unsigned long, SSL_SESSION_get_ticket_lifetime_hint, const SSL_SESSION *session, session, return 0, return)
+DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
+DEFINEFUNC(int, DH_bits, DH *dh, dh, return 0, return)
+
+DEFINEFUNC2(void, BIO_set_data, BIO *a, a, void *ptr, ptr, return, DUMMYARG)
+DEFINEFUNC(void *, BIO_get_data, BIO *a, a, return nullptr, return)
+DEFINEFUNC2(void, BIO_set_init, BIO *a, a, int init, init, return, DUMMYARG)
+DEFINEFUNC(int, BIO_get_shutdown, BIO *a, a, return -1, return)
+DEFINEFUNC2(void, BIO_set_shutdown, BIO *a, a, int shut, shut, return, DUMMYARG)
+
+
+#else // QT_CONFIG(opensslv11)
+
+// Functions below are either deprecated or removed in OpenSSL >= 1.1:
+
+DEFINEFUNC(unsigned char *, ASN1_STRING_data, ASN1_STRING *a, a, return nullptr, return)
+
+#ifdef SSLEAY_MACROS
+DEFINEFUNC3(void *, ASN1_dup, i2d_of_void *a, a, d2i_of_void *b, b, char *c, c, return nullptr, return)
+#endif
+DEFINEFUNC2(BIO *, BIO_new_file, const char *filename, filename, const char *mode, mode, return nullptr, return)
+DEFINEFUNC(void, ERR_clear_error, DUMMYARG, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(BIO *, BIO_new, BIO_METHOD *a, a, return nullptr, return)
+DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG)
+DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG)
+DEFINEFUNC(void, CRYPTO_free, void *a, a, return, DUMMYARG)
+DEFINEFUNC(unsigned long, ERR_peek_last_error, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(void, ERR_free_strings, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(void, EVP_CIPHER_CTX_cleanup, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC(void, EVP_CIPHER_CTX_init, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
+
+#ifdef SSLEAY_MACROS
+DEFINEFUNC6(void *, PEM_ASN1_read_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return nullptr, return)
+DEFINEFUNC6(void *, PEM_ASN1_write_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return nullptr, return)
+#endif // SSLEAY_MACROS
+
+DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
+DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
+
+DEFINEFUNC(_STACK *, sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(void, sk_push, _STACK *a, a, void *b, b, return, DUMMYARG)
+DEFINEFUNC(void, sk_free, _STACK *a, a, return, DUMMYARG)
+DEFINEFUNC2(void *, sk_value, STACK *a, a, int b, b, return nullptr, return)
+
+DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return)
+DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG)
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+DEFINEFUNC5(int, SSL_get_ex_new_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L
+
+DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get_chain, X509_STORE_CTX *a, a, return nullptr, return)
+
+#ifdef SSLEAY_MACROS
+DEFINEFUNC2(int, i2d_DSAPrivateKey, const DSA *a, a, unsigned char **b, b, return -1, return)
+DEFINEFUNC2(int, i2d_RSAPrivateKey, const RSA *a, a, unsigned char **b, b, return -1, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(int, i2d_ECPrivateKey, const EC_KEY *a, a, unsigned char **b, b, return -1, return)
+#endif
+DEFINEFUNC3(RSA *, d2i_RSAPrivateKey, RSA **a, a, unsigned char **b, b, long c, c, return nullptr, return)
+DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, c, return nullptr, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC3(EC_KEY *, d2i_ECPrivateKey, EC_KEY **a, a, unsigned char **b, b, long c, c, return nullptr, return)
+#endif
+#endif
+
+DEFINEFUNC(char *, CONF_get1_default_config_file, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
+DEFINEFUNC(const char *, SSLeay_version, int a, a, return nullptr, return)
+DEFINEFUNC(void, ERR_load_crypto_strings, void, DUMMYARG, return, return)
+
+#endif // QT_CONFIG(opensslv11)
+
+DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
+DEFINEFUNC2(int, ASN1_INTEGER_cmp, const ASN1_INTEGER *a, a, const ASN1_INTEGER *b, b, return 1, return)
+DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return)
+DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return)
+DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
+DEFINEFUNC(void, BIO_free_all, BIO *a, a, return, return)
+DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return nullptr, return)
+DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
+
+DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
+DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
+DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
+DEFINEFUNC2(int, BN_set_word, const BIGNUM *a, a, BN_ULONG w, w, return 0, return)
+DEFINEFUNC(BIGNUM *, BN_new, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, BN_clear, BIGNUM *bignum, bignum, return, return)
+DEFINEFUNC(void, BN_free, BIGNUM *bignum, bignum, return, return)
+DEFINEFUNC(void, BN_clear_free, BIGNUM *bignum, bignum, return, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return nullptr, return)
+DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
+#endif
+DEFINEFUNC(DSA *, DSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
+DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return nullptr, return)
+DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return nullptr, return)
+DEFINEFUNC3(void, ERR_error_string_n, unsigned long e, e, char *b, b, size_t len, len, return, DUMMYARG)
+DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, void, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, EVP_CIPHER_CTX_free, EVP_CIPHER_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC4(int, EVP_CIPHER_CTX_ctrl, EVP_CIPHER_CTX *ctx, ctx, int type, type, int arg, arg, void *ptr, ptr, return 0, return)
+DEFINEFUNC2(int, EVP_CIPHER_CTX_set_key_length, EVP_CIPHER_CTX *ctx, ctx, int keylen, keylen, return 0, return)
+DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *type, type, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
+DEFINEFUNC6(int, EVP_CipherInit_ex, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *cipher, cipher, ENGINE *impl, impl, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return)
+DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return)
+DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return)
+DEFINEFUNC(const EVP_MD *, EVP_get_digestbyname, const char *name, name, return nullptr, return)
+DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_MD *, EVP_sha256, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_256_gcm, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_aes_128_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
+#endif
+DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
+DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
+DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
+DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return)
+#endif
+DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
+DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
+DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return nullptr, return)
+DEFINEFUNC(const char *, OBJ_nid2ln, int a, a, return nullptr, return)
+DEFINEFUNC(int, OBJ_sn2nid, const char *s, s, return 0, return)
+DEFINEFUNC(int, OBJ_ln2nid, const char *s, s, return 0, return)
+DEFINEFUNC3(int, i2t_ASN1_OBJECT, char *a, a, int b, b, ASN1_OBJECT *c, c, return -1, return)
+DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d, return -1, return)
+
+DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
+DEFINEFUNC4(X509_EXTENSION* , X509V3_EXT_conf_nid, LHASH_OF(CONF_VALUE) *conf, conf, X509V3_CTX *ctx, ctx, int ext_nid, ext_nid, char *value, value, return NULL, return)
+
+#ifndef SSLEAY_MACROS
+DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#endif
+DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_PKCS8PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+#endif
+#endif // !SSLEAY_MACROS
+DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#endif
+DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_PUBKEY, BIO *a, a, EVP_PKEY *b, b, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
+#endif
+DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
+DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
+DEFINEFUNC2(int, RAND_bytes, unsigned char *b, b, int n, n, return 0, return)
+DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC4(int, RSA_generate_key_ex, RSA *rsa, rsa, int bits, bits, BIGNUM *e, e, BN_GENCB *cb, cb, return 0, return)
+DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
+DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return nullptr, return)
+DEFINEFUNC2(int, X509_cmp, X509 *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC4(int, X509_digest, const X509 *x509, x509, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return -1, return)
+#ifndef SSLEAY_MACROS
+DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return nullptr, return)
+#endif
+DEFINEFUNC2(void, X509_print, BIO *a, a, X509 *b, b, return, DUMMYARG);
+DEFINEFUNC(ASN1_OBJECT *, X509_EXTENSION_get_object, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG)
+//Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
+DEFINEFUNC2(ASN1_TIME *, X509_gmtime_adj, ASN1_TIME *s, s, long adj, adj, return nullptr, return)
+DEFINEFUNC(void, ASN1_TIME_free, ASN1_TIME *t, t, return, DUMMYARG)
+DEFINEFUNC2(X509_EXTENSION *, X509_get_ext, X509 *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(int, X509_get_ext_count, X509 *a, a, return 0, return)
+DEFINEFUNC4(void *, X509_get_ext_d2i, X509 *a, a, int b, b, int *c, c, int *d, d, return nullptr, return)
+DEFINEFUNC(const X509V3_EXT_METHOD *, X509V3_EXT_get, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void *, X509V3_EXT_d2i, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(int, X509_EXTENSION_get_critical, X509_EXTENSION *a, a, return 0, return)
+DEFINEFUNC(ASN1_OCTET_STRING *, X509_EXTENSION_get_data, X509_EXTENSION *a, a, return nullptr, return)
+DEFINEFUNC(void, BASIC_CONSTRAINTS_free, BASIC_CONSTRAINTS *a, a, return, DUMMYARG)
+DEFINEFUNC(void, AUTHORITY_KEYID_free, AUTHORITY_KEYID *a, a, return, DUMMYARG)
+DEFINEFUNC(void, GENERAL_NAME_free, GENERAL_NAME *a, a, return, DUMMYARG)
+DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, const ASN1_STRING *b, b, return 0, return)
+DEFINEFUNC2(int, X509_check_issued, X509 *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return nullptr, return)
+DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return nullptr, return)
+DEFINEFUNC(ASN1_INTEGER *, X509_get_serialNumber, X509 *a, a, return nullptr, return)
+DEFINEFUNC(int, X509_verify_cert, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(int, X509_NAME_entry_count, X509_NAME *a, a, return 0, return)
+DEFINEFUNC2(X509_NAME_ENTRY *, X509_NAME_get_entry, X509_NAME *a, a, int b, b, return nullptr, return)
+DEFINEFUNC(ASN1_STRING *, X509_NAME_ENTRY_get_data, X509_NAME_ENTRY *a, a, return nullptr, return)
+DEFINEFUNC(ASN1_OBJECT *, X509_NAME_ENTRY_get_object, X509_NAME_ENTRY *a, a, return nullptr, return)
+DEFINEFUNC(EVP_PKEY *, X509_PUBKEY_get, X509_PUBKEY *a, a, return nullptr, return)
+DEFINEFUNC(void, X509_STORE_free, X509_STORE *a, a, return, DUMMYARG)
+DEFINEFUNC(X509_STORE *, X509_STORE_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(int, X509_STORE_add_cert, X509_STORE *a, a, X509 *b, b, return 0, return)
+DEFINEFUNC(void, X509_STORE_CTX_free, X509_STORE_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC4(int, X509_STORE_CTX_init, X509_STORE_CTX *a, a, X509_STORE *b, b, X509 *c, c, STACK_OF(X509) *d, d, return -1, return)
+DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, return -1, return)
+DEFINEFUNC(int, X509_STORE_CTX_get_error, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(int, X509_STORE_CTX_get_error_depth, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC(X509 *, X509_STORE_CTX_get_current_cert, X509_STORE_CTX *a, a, return nullptr, return)
+DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC2(void *, X509_STORE_CTX_get_ex_data, X509_STORE_CTX *ctx, ctx, int idx, idx, return nullptr, return)
+DEFINEFUNC(int, SSL_get_ex_data_X509_STORE_CTX_idx, DUMMYARG, DUMMYARG, return -1, return)
+DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
+DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
+DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
+DEFINEFUNC6(int, SSL_select_next_proto, unsigned char **out, out, unsigned char *outlen, outlen,
+ const unsigned char *in, in, unsigned int inlen, inlen,
+ const unsigned char *client, client, unsigned int client_len, client_len,
+ return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s,
+ int (*cb) (SSL *ssl, unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg), cb,
+ void *arg, arg, return, DUMMYARG)
+DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s,
+ const unsigned char **data, data, unsigned *len, len, return, DUMMYARG)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+DEFINEFUNC3(int, SSL_set_alpn_protos, SSL *s, s, const unsigned char *protos, protos,
+ unsigned protos_len, protos_len, return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_alpn_select_cb, SSL_CTX *s, s,
+ int (*cb) (SSL *ssl, const unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen, void *arg), cb,
+ void *arg, arg, return, DUMMYARG)
+DEFINEFUNC3(void, SSL_get0_alpn_selected, const SSL *s, s, const unsigned char **data, data,
+ unsigned *len, len, return, DUMMYARG)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+
+DEFINEFUNC2(void, BIO_set_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void, BIO_clear_flags, BIO *b, b, int flags, flags, return, DUMMYARG)
+DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, return)
+DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return)
+
+DEFINEFUNC3(void *, CRYPTO_malloc, size_t num, num, const char *file, file, int line, line, return nullptr, return)
+DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
+DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
+DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
+DEFINEFUNC2(int, i2d_DHparams, DH *a, a, unsigned char **p, p, return -1, return)
+DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
+DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC(EC_KEY *, EC_KEY_dup, const EC_KEY *ec, ec, return nullptr, return)
+DEFINEFUNC(EC_KEY *, EC_KEY_new_by_curve_name, int nid, nid, return nullptr, return)
+DEFINEFUNC(void, EC_KEY_free, EC_KEY *ecdh, ecdh, return, DUMMYARG)
+DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+#endif // OPENSSL_NO_EC
+
+DEFINEFUNC5(int, PKCS12_parse, PKCS12 *p12, p12, const char *pass, pass, EVP_PKEY **pkey, pkey, \
+ X509 **cert, cert, STACK_OF(X509) **ca, ca, return 1, return);
+DEFINEFUNC2(PKCS12 *, d2i_PKCS12_bio, BIO *bio, bio, PKCS12 **pkcs12, pkcs12, return nullptr, return);
+DEFINEFUNC(void, PKCS12_free, PKCS12 *pkcs12, pkcs12, return, DUMMYARG)
+
+DEFINEFUNC(X509_REQ*, X509_REQ_new, void, DUMMYARG, return NULL, return);
+DEFINEFUNC(void, X509_REQ_free, X509_REQ *req, req, return, return);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+DEFINEFUNC(X509_NAME*, X509_REQ_get_subject_name, X509_REQ *req, req, return NULL, return);
+DEFINEFUNC2(EVP_PKEY_CTX*, EVP_PKEY_CTX_new_id, int id, id, ENGINE *e, e, return NULL, return);
+DEFINEFUNC(void, EVP_PKEY_CTX_free, EVP_PKEY_CTX *ctx, ctx, return, return);
+DEFINEFUNC(int, EVP_PKEY_keygen_init, EVP_PKEY_CTX *ctx, ctx, return 0, return);
+DEFINEFUNC2(int, EVP_PKEY_keygen, EVP_PKEY_CTX *ctx, ctx, EVP_PKEY **pkey, pkey, return 0, return);
+DEFINEFUNC5(int, RSA_pkey_ctx_ctrl, EVP_PKEY_CTX *ctx, ctx, int optype, optype, int cmd, cmd, int p1, p1, void *p2, p2, return 0, return)
+
+#endif
+DEFINEFUNC7(int, X509_NAME_add_entry_by_txt, X509_NAME *name, name, const char *field, field, int type, type, const unsigned char *bytes, bytes, int len, len, int loc, loc, int set, set, return 0, return);
+DEFINEFUNC7(int, X509_NAME_add_entry_by_OBJ, X509_NAME *name, name, const ASN1_OBJECT *obj, obj, int type, type, const unsigned char *bytes, bytes, int len, len, int loc, loc, int set, set, return 0, return);
+DEFINEFUNC2(ASN1_OBJECT *, OBJ_txt2obj, const char *s, s, int no_name, no_name, return NULL, return);
+DEFINEFUNC2(int, X509_REQ_set_pubkey, X509_REQ *x, x, EVP_PKEY *pkey, pkey, return 0, return);
+DEFINEFUNC3(int, X509_REQ_sign, X509_REQ *x, x, EVP_PKEY *pkey, pkey, const EVP_MD *md, md, return 0, return);
+DEFINEFUNC2(int, PEM_write_bio_X509_REQ, BIO *bp, bp, X509_REQ *x, x, return 0, return);
+DEFINEFUNC2(int, PEM_write_bio_X509_REQ_NEW, BIO *bp, bp, X509_REQ *x, x, return 0, return);
+DEFINEFUNC2(int, X509_REQ_set_version, X509_REQ *x, x, long version, version, return 0, return);
+DEFINEFUNC2(int, X509_REQ_add_extensions, X509_REQ *req, req, STACK_OF(X509_EXTENSION) *exts, exts, return 0, return)
+DEFINEFUNC(void, X509_EXTENSION_free, X509_EXTENSION *ext, ext, return, return)
+DEFINEFUNC2(int, X509_EXTENSION_set_critical, X509_EXTENSION *ex, ex, int crit, crit, return 0, return)
+DEFINEFUNC3(X509*, X509_REQ_to_X509, X509_REQ *r, r, int days, days, EVP_PKEY *pkey, pkey, return NULL, return)
+DEFINEFUNC2(int, PEM_write_bio_X509, BIO *bp, bp, X509 *x, x, return 0, return)
+DEFINEFUNC(X509*, X509_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC2(int, ASN1_INTEGER_set, ASN1_INTEGER *a, a, long v, v, return 0, return)
+DEFINEFUNC2(int, X509_set_pubkey,X509 *x, x, EVP_PKEY *key, key, return 0, return)
+DEFINEFUNC2(int, X509_set_issuer_name, X509 *x, x, X509_NAME *name, name, return 0, return)
+DEFINEFUNC3(int, X509_sign, X509 *x, x, EVP_PKEY *key, key, const EVP_MD *md, md, return 0, return)
+DEFINEFUNC3(int, X509_add_ext, X509 *x, x, X509_EXTENSION *ex, ex, int loc, loc, return 0, return)
+DEFINEFUNC2(int, X509_set_version, X509 *x, x, long version, version, return 0, return)
+DEFINEFUNC2(int, X509_set_subject_name, X509 *x, x, X509_NAME *name, name, return 0, return)
+DEFINEFUNC(ASN1_OCTET_STRING *, ASN1_OCTET_STRING_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC4(int, X509_pubkey_digest, const X509 *data, data, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return 0, return)
+DEFINEFUNC3(int, ASN1_OCTET_STRING_set, ASN1_OCTET_STRING *str, str, const unsigned char *data, data, int len, len, return 0, return)
+DEFINEFUNC5(int, X509_add1_ext_i2d, X509 *x, x, int nid, nid, void *value, value, int crit, crit, unsigned long flags, flags, return 0, return)
+DEFINEFUNC(void, ASN1_OCTET_STRING_free, ASN1_OCTET_STRING *a, a, return, return)
+DEFINEFUNC(ASN1_INTEGER *, ASN1_INTEGER_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC(GENERAL_NAMES *, GENERAL_NAMES_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC(GENERAL_NAME *, GENERAL_NAME_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC(X509_NAME *, X509_NAME_dup, X509_NAME *xn, xn, return NULL, return)
+DEFINEFUNC2(int, X509_set_serialNumber, X509 *x, x, ASN1_INTEGER *serial, serial, return 0, return)
+DEFINEFUNC(AUTHORITY_KEYID *, AUTHORITY_KEYID_new, void, DUMMYARG, return NULL, return)
+DEFINEFUNC(ASN1_INTEGER *, ASN1_INTEGER_dup, const ASN1_INTEGER *x, x, return NULL, return)
+DEFINEFUNC4(int, X509_NAME_digest, const X509_NAME *data, data, const EVP_MD *type, type, unsigned char *md, md, unsigned int *len, len, return 0, return)
+DEFINEFUNC(void, ASN1_INTEGER_free, ASN1_INTEGER *a, a, return, return)
+DEFINEFUNC2(int, i2d_X509_REQ_bio, BIO *bp, bp, X509_REQ *req, req, return 0, return)
+DEFINEFUNC2(int, i2d_X509_bio, BIO *bp, bp, X509 *x509, x509, return 0, return)
+
+#define RESOLVEFUNC(func) \
+ if (!(_q_##func = _q_PTR_##func(libs.ssl->resolve(#func))) \
+ && !(_q_##func = _q_PTR_##func(libs.crypto->resolve(#func)))) \
+ qsslSocketCannotResolveSymbolWarning(#func);
+
+#if !defined QT_LINKED_OPENSSL
+
+#if !QT_CONFIG(library)
+bool q_resolveOpenSslSymbols()
+{
+ qCWarning(lcSsl, "QSslSocket: unable to resolve symbols. Qt is configured without the "
+ "'library' feature, which means runtime resolving of libraries won't work.");
+ qCWarning(lcSsl, "Either compile Qt statically or with support for runtime resolving "
+ "of libraries.");
+ return false;
+}
+#else
+
+# ifdef Q_OS_UNIX
+struct NumericallyLess
+{
+ typedef bool result_type;
+ result_type operator()(const QStringRef &lhs, const QStringRef &rhs) const
+ {
+ bool ok = false;
+ int b = 0;
+ int a = lhs.toInt(&ok);
+ if (ok)
+ b = rhs.toInt(&ok);
+ if (ok) {
+ // both toInt succeeded
+ return a < b;
+ } else {
+ // compare as strings;
+ return lhs < rhs;
+ }
+ }
+};
+
+struct LibGreaterThan
+{
+ typedef bool result_type;
+ result_type operator()(const QString &lhs, const QString &rhs) const
+ {
+ const QVector<QStringRef> lhsparts = lhs.splitRef(QLatin1Char('.'));
+ const QVector<QStringRef> rhsparts = rhs.splitRef(QLatin1Char('.'));
+ Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 1);
+
+ // note: checking rhs < lhs, the same as lhs > rhs
+ return std::lexicographical_compare(rhsparts.begin() + 1, rhsparts.end(),
+ lhsparts.begin() + 1, lhsparts.end(),
+ NumericallyLess());
+ }
+};
+
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+static int dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data)
+{
+ if (size < sizeof (info->dlpi_addr) + sizeof (info->dlpi_name))
+ return 1;
+ QSet<QString> *paths = (QSet<QString> *)data;
+ QString path = QString::fromLocal8Bit(info->dlpi_name);
+ if (!path.isEmpty()) {
+ QFileInfo fi(path);
+ path = fi.absolutePath();
+ if (!path.isEmpty())
+ paths->insert(path);
+ }
+ return 0;
+}
+#endif
+
+static QStringList libraryPathList()
+{
+ QStringList paths;
+# ifdef Q_OS_DARWIN
+ paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH"))
+ .split(QLatin1Char(':'), QString::SkipEmptyParts);
+
+ // search in .app/Contents/Frameworks
+ UInt32 packageType;
+ CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, nullptr);
+ if (packageType == FOUR_CHAR_CODE('APPL')) {
+ QUrl bundleUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyBundleURL(CFBundleGetMainBundle())));
+ QUrl frameworksUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle())));
+ paths << bundleUrl.resolved(frameworksUrl).path();
+ }
+# else
+ paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
+ .split(QLatin1Char(':'), QString::SkipEmptyParts);
+# endif
+ paths << QLatin1String("/lib") << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib");
+ paths << QLatin1String("/lib64") << QLatin1String("/usr/lib64") << QLatin1String("/usr/local/lib64");
+ paths << QLatin1String("/lib32") << QLatin1String("/usr/lib32") << QLatin1String("/usr/local/lib32");
+
+#if defined(Q_OS_ANDROID)
+ paths << QLatin1String("/system/lib");
+#elif defined(Q_OS_LINUX)
+ // discover paths of already loaded libraries
+ QSet<QString> loadedPaths;
+ dl_iterate_phdr(dlIterateCallback, &loadedPaths);
+ paths.append(loadedPaths.values());
+#endif
+
+ return paths;
+}
+
+Q_NEVER_INLINE
+static QStringList findAllLibs(QLatin1String filter)
+{
+ const QStringList paths = libraryPathList();
+ QStringList found;
+ const QStringList filters((QString(filter)));
+
+ for (const QString &path : paths) {
+ QDir dir(path);
+ QStringList entryList = dir.entryList(filters, QDir::Files);
+
+ std::sort(entryList.begin(), entryList.end(), LibGreaterThan());
+ for (const QString &entry : qAsConst(entryList))
+ found << path + QLatin1Char('/') + entry;
+ }
+
+ return found;
+}
+
+static QStringList findAllLibSsl()
+{
+ return findAllLibs(QLatin1String("libssl.*"));
+}
+
+static QStringList findAllLibCrypto()
+{
+ return findAllLibs(QLatin1String("libcrypto.*"));
+}
+# endif
+
+#ifdef Q_OS_WIN
+
+struct LoadedOpenSsl {
+ std::unique_ptr<QSystemLibrary> ssl, crypto;
+};
+
+static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result)
+{
+ auto ssleay32 = qt_make_unique<QSystemLibrary>(ssleay32LibName);
+ if (!ssleay32->load(false)) {
+ return FALSE;
+ }
+
+ auto libeay32 = qt_make_unique<QSystemLibrary>(libeay32LibName);
+ if (!libeay32->load(false)) {
+ return FALSE;
+ }
+
+ result.ssl = std::move(ssleay32);
+ result.crypto = std::move(libeay32);
+ return TRUE;
+}
+
+static LoadedOpenSsl loadOpenSsl()
+{
+ LoadedOpenSsl result;
+
+#if QT_CONFIG(opensslv11)
+ // With OpenSSL 1.1 the names have changed to libssl-1_1(-x64) and libcrypto-1_1(-x64), for builds using
+ // MSVC and GCC, (-x64 suffix for 64-bit builds).
+
+#ifdef Q_PROCESSOR_X86_64
+#define QT_SSL_SUFFIX "-x64"
+#else // !Q_PROCESSOFR_X86_64
+#define QT_SSL_SUFFIX
+#endif // !Q_PROCESSOR_x86_64
+
+ tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX),
+ QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result);
+
+#undef QT_SSL_SUFFIX
+
+#else // QT_CONFIG(opensslv11)
+
+ // When OpenSSL is built using MSVC then the libraries are named 'ssleay32.dll' and 'libeay32'dll'.
+ // When OpenSSL is built using GCC then different library names are used (depending on the OpenSSL version)
+ // The oldest version of a GCC-based OpenSSL which can be detected by the code below is 0.9.8g (released in 2007)
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("ssleay32"), QLatin1String("libeay32"), result)) {
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-10"), QLatin1String("libcrypto-10"), result)) {
+ if (!tryToLoadOpenSslWin32Library(QLatin1String("libssl-8"), QLatin1String("libcrypto-8"), result)) {
+ tryToLoadOpenSslWin32Library(QLatin1String("libssl-7"), QLatin1String("libcrypto-7"), result);
+ }
+ }
+ }
+#endif // !QT_CONFIG(opensslv11)
+
+ return result;
+}
+#else
+
+struct LoadedOpenSsl {
+ std::unique_ptr<QLibrary> ssl, crypto;
+};
+
+static LoadedOpenSsl loadOpenSsl()
+{
+ LoadedOpenSsl result = {qt_make_unique<QLibrary>(), qt_make_unique<QLibrary>()};
+
+# if defined(Q_OS_UNIX)
+ QLibrary * const libssl = result.ssl.get();
+ QLibrary * const libcrypto = result.crypto.get();
+
+ // Try to find the libssl library on the system.
+ //
+ // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that
+ // is, libssl.so on most Unix systems. However, the .so file isn't present in
+ // user installations because it's considered a development file.
+ //
+ // The right thing to do is to load the library at the major version we know how
+ // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h)
+ //
+ // However, OpenSSL is a well-known case of binary-compatibility breakage. To
+ // avoid such problems, many system integrators and Linux distributions change
+ // the soname of the binary, letting the full version number be the soname. So
+ // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that
+ // reason, we will search a few common paths (see findAllLibSsl() above) in hopes
+ // we find one that works.
+ //
+ // If that fails, for OpenSSL 1.0 we also try some fallbacks -- look up
+ // libssl.so with a hardcoded soname. The reason is QTBUG-68156: the binary
+ // builds of Qt happen (at the time of this writing) on RHEL machines,
+ // which change SHLIB_VERSION_NUMBER to a non-portable string. When running
+ // those binaries on the target systems, this code won't pick up
+ // libssl.so.MODIFIED_SHLIB_VERSION_NUMBER because it doesn't exist there.
+ // Given that the only 1.0 supported release (at the time of this writing)
+ // is 1.0.2, with soname "1.0.0", give that a try too. Note that we mandate
+ // OpenSSL >= 1.0.0 with a configure-time check, and OpenSSL has kept binary
+ // compatibility between 1.0.0 and 1.0.2.
+ //
+ // It is important, however, to try the canonical name and the unversioned name
+ // without going through the loop. By not specifying a path, we let the system
+ // dlopen(3) function determine it for us. This will include any DT_RUNPATH or
+ // DT_RPATH tags on our library header as well as other system-specific search
+ // paths. See the man page for dlopen(3) on your system for more information.
+
+#ifdef Q_OS_OPENBSD
+ libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
+#endif
+#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
+ // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
+ libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER));
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER));
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
+ return result;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+
+#if !QT_CONFIG(opensslv11)
+ // first-and-half attempts: for OpenSSL 1.0 try to load some hardcoded sonames:
+ // - "1.0.0" is the official upstream one
+ // - "1.0.2" is found on some distributions (e.g. Debian) that patch OpenSSL
+ static const QLatin1String fallbackSonames[] = {
+ QLatin1String("1.0.0"),
+ QLatin1String("1.0.2")
+ };
+
+ for (auto fallbackSoname : fallbackSonames) {
+ libssl->setFileNameAndVersion(QLatin1String("ssl"), fallbackSoname);
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto"), fallbackSoname);
+ if (libcrypto->load() && libssl->load()) {
+ return result;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+ }
+#endif
+#endif
+
+#ifndef Q_OS_DARWIN
+ // second attempt: find the development files libssl.so and libcrypto.so
+ //
+ // disabled on macOS/iOS:
+ // macOS's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third
+ // attempt, _after_ <bundle>/Contents/Frameworks has been searched.
+ // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place.
+# if defined(Q_OS_ANDROID)
+ // OpenSSL 1.1.x must be suffixed otherwise it will use the system libcrypto.so libssl.so which on API-21 are OpenSSL 1.0 not 1.1
+ auto openSSLSuffix = [](const QByteArray &defaultSuffix = {}) {
+ auto suffix = qgetenv("ANDROID_OPENSSL_SUFFIX");
+ if (suffix.isEmpty())
+ return defaultSuffix;
+ return suffix;
+ };
+# if QT_CONFIG(opensslv11)
+ static QString suffix = QString::fromLatin1(openSSLSuffix("_1_1"));
+# else
+ static QString suffix = QString::fromLatin1(openSSLSuffix());
+# endif
+ libssl->setFileNameAndVersion(QLatin1String("ssl") + suffix, -1);
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto") + suffix, -1);
+# else
+ libssl->setFileNameAndVersion(QLatin1String("ssl"), -1);
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1);
+# endif
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.0 and libcrypto.so.0 found
+ return result;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+#endif
+
+ // third attempt: loop on the most common library paths and find libssl
+ const QStringList sslList = findAllLibSsl();
+ const QStringList cryptoList = findAllLibCrypto();
+
+ for (const QString &crypto : cryptoList) {
+ libcrypto->setFileNameAndVersion(crypto, -1);
+ if (libcrypto->load()) {
+ QFileInfo fi(crypto);
+ QString version = fi.completeSuffix();
+
+ for (const QString &ssl : sslList) {
+ if (!ssl.endsWith(version))
+ continue;
+
+ libssl->setFileNameAndVersion(ssl, -1);
+
+ if (libssl->load()) {
+ // libssl.so.x and libcrypto.so.x found
+ return result;
+ } else {
+ libssl->unload();
+ }
+ }
+ }
+ libcrypto->unload();
+ }
+
+ // failed to load anything
+ result = {};
+ return result;
+
+# else
+ // not implemented for this platform yet
+ return result;
+# endif
+}
+#endif
+
+static QBasicMutex symbolResolveMutex;
+static QBasicAtomicInt symbolsResolved = Q_BASIC_ATOMIC_INITIALIZER(false);
+static bool triedToResolveSymbols = false;
+
+bool q_resolveOpenSslSymbols()
+{
+ if (symbolsResolved.loadAcquire())
+ return true;
+ QMutexLocker locker(&symbolResolveMutex);
+ if (symbolsResolved.loadRelaxed())
+ return true;
+ if (triedToResolveSymbols)
+ return false;
+ triedToResolveSymbols = true;
+
+ LoadedOpenSsl libs = loadOpenSsl();
+ if (!libs.ssl || !libs.crypto)
+ // failed to load them
+ return false;
+
+#if QT_CONFIG(opensslv11)
+ RESOLVEFUNC(X509_REQ_get_subject_name) // v1.1.0
+ RESOLVEFUNC(OPENSSL_init_ssl)
+ RESOLVEFUNC(OPENSSL_init_crypto)
+ RESOLVEFUNC(ASN1_STRING_get0_data)
+ RESOLVEFUNC(EVP_CIPHER_CTX_reset)
+ RESOLVEFUNC(EVP_PKEY_base_id)
+ RESOLVEFUNC(RSA_bits)
+ RESOLVEFUNC(OPENSSL_sk_new_null)
+ RESOLVEFUNC(OPENSSL_sk_push)
+ RESOLVEFUNC(OPENSSL_sk_free)
+ RESOLVEFUNC(OPENSSL_sk_num)
+ RESOLVEFUNC(OPENSSL_sk_pop_free)
+ RESOLVEFUNC(OPENSSL_sk_value)
+ RESOLVEFUNC(DH_get0_pqg)
+ RESOLVEFUNC(CRYPTO_get_ex_new_index)
+ RESOLVEFUNC(X509_up_ref)
+ RESOLVEFUNC(X509_STORE_CTX_get0_chain)
+ RESOLVEFUNC(X509_getm_notBefore)
+ RESOLVEFUNC(X509_getm_notAfter)
+ RESOLVEFUNC(X509_get_version)
+ RESOLVEFUNC(X509_get_pubkey)
+ RESOLVEFUNC(X509_STORE_set_verify_cb)
+ RESOLVEFUNC(CRYPTO_free)
+ RESOLVEFUNC(OpenSSL_version_num)
+ RESOLVEFUNC(OpenSSL_version)
+ if (!_q_OpenSSL_version) {
+ // Apparently, we were built with OpenSSL 1.1 enabled but are now using
+ // a wrong library.
+ qCWarning(lcSsl, "Incompatible version of OpenSSL");
+ return false;
+ }
+
+ RESOLVEFUNC(DH_bits)
+
+ RESOLVEFUNC(BIO_set_data)
+ RESOLVEFUNC(BIO_get_data)
+ RESOLVEFUNC(BIO_set_init)
+ RESOLVEFUNC(BIO_get_shutdown)
+ RESOLVEFUNC(BIO_set_shutdown)
+ RESOLVEFUNC(EVP_PKEY_CTX_new_id)
+ RESOLVEFUNC(EVP_PKEY_CTX_free)
+ RESOLVEFUNC(EVP_PKEY_keygen_init)
+ RESOLVEFUNC(EVP_PKEY_keygen);
+ RESOLVEFUNC(RSA_pkey_ctx_ctrl);
+ RESOLVEFUNC(BIO_free_all)
+ RESOLVEFUNC(X509_REQ_new)
+ RESOLVEFUNC(X509_REQ_set_version)
+ RESOLVEFUNC(OBJ_txt2obj)
+ RESOLVEFUNC(X509_NAME_add_entry_by_OBJ)
+ RESOLVEFUNC(X509_REQ_add_extensions)
+ RESOLVEFUNC(X509_EXTENSION_free)
+ RESOLVEFUNC(X509_REQ_set_pubkey)
+ RESOLVEFUNC(X509_REQ_sign)
+ RESOLVEFUNC(PEM_write_bio_X509_REQ)
+ RESOLVEFUNC(X509_REQ_free)
+
+#else // !opensslv11
+
+ RESOLVEFUNC(ASN1_STRING_data)
+
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(ASN1_dup)
+#endif // SSLEAY_MACROS
+ RESOLVEFUNC(BIO_new_file)
+ RESOLVEFUNC(ERR_clear_error)
+ RESOLVEFUNC(ERR_load_crypto_strings)
+ RESOLVEFUNC(CRYPTO_free)
+ RESOLVEFUNC(CRYPTO_num_locks)
+ RESOLVEFUNC(CRYPTO_set_id_callback)
+ RESOLVEFUNC(CRYPTO_set_locking_callback)
+ RESOLVEFUNC(ERR_peek_last_error)
+ RESOLVEFUNC(ERR_free_strings)
+ RESOLVEFUNC(EVP_CIPHER_CTX_cleanup)
+ RESOLVEFUNC(EVP_CIPHER_CTX_init)
+
+#ifdef SSLEAY_MACROS // ### verify
+ RESOLVEFUNC(PEM_ASN1_read_bio)
+#endif // SSLEAY_MACROS
+
+ RESOLVEFUNC(sk_new_null)
+ RESOLVEFUNC(sk_push)
+ RESOLVEFUNC(sk_free)
+ RESOLVEFUNC(sk_num)
+ RESOLVEFUNC(sk_pop_free)
+ RESOLVEFUNC(sk_value)
+ RESOLVEFUNC(X509_STORE_CTX_get_chain)
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(i2d_RSAPrivateKey)
+ RESOLVEFUNC(d2i_RSAPrivateKey)
+#endif
+
+ RESOLVEFUNC(CONF_get1_default_config_file)
+ RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf)
+ RESOLVEFUNC(OPENSSL_add_all_algorithms_conf)
+ RESOLVEFUNC(SSLeay)
+ RESOLVEFUNC(X509_REQ_new)
+ RESOLVEFUNC(X509_REQ_free)
+ RESOLVEFUNC(X509_NAME_add_entry_by_txt)
+ RESOLVEFUNC(X509_NAME_add_entry_by_OBJ)
+ RESOLVEFUNC(OBJ_txt2obj)
+ RESOLVEFUNC(X509_REQ_add_extensions)
+
+ RESOLVEFUNC(X509_REQ_set_pubkey)
+ RESOLVEFUNC(X509_REQ_sign)
+ RESOLVEFUNC(PEM_write_bio_X509_REQ)
+ RESOLVEFUNC(PEM_write_bio_X509_REQ_NEW)
+ RESOLVEFUNC(X509_REQ_set_version)
+ RESOLVEFUNC(BIO_free_all)
+ RESOLVEFUNC(X509_EXTENSION_free)
+
+ if (!_q_SSLeay || q_SSLeay() >= 0x10100000L) {
+ // OpenSSL 1.1 has deprecated and removed SSLeay. We consider a failure to
+ // resolve this symbol as a failure to resolve symbols.
+ // The right operand of '||' above is ... a bit of paranoia.
+ qCWarning(lcSsl, "Incompatible version of OpenSSL");
+ return false;
+ }
+
+
+ RESOLVEFUNC(SSLeay_version)
+
+#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ if (q_SSLeay() >= 0x10002000L)
+ RESOLVEFUNC(EC_curve_nist2nid)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+#endif // OPENSSL_NO_EC
+
+
+#endif // !opensslv11
+
+ RESOLVEFUNC(ASN1_INTEGER_get)
+ RESOLVEFUNC(ASN1_INTEGER_cmp)
+ RESOLVEFUNC(ASN1_STRING_length)
+ RESOLVEFUNC(ASN1_STRING_to_UTF8)
+ RESOLVEFUNC(BIO_ctrl)
+ RESOLVEFUNC(BIO_free)
+ RESOLVEFUNC(BIO_new)
+ RESOLVEFUNC(BIO_new_mem_buf)
+ RESOLVEFUNC(BIO_read)
+ RESOLVEFUNC(BIO_s_mem)
+ RESOLVEFUNC(BIO_write)
+ RESOLVEFUNC(BIO_set_flags)
+ RESOLVEFUNC(BIO_clear_flags)
+ RESOLVEFUNC(BIO_set_ex_data)
+ RESOLVEFUNC(BIO_get_ex_data)
+ RESOLVEFUNC(X509V3_EXT_conf_nid)
+ RESOLVEFUNC(X509_EXTENSION_set_critical)
+
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EC_KEY_get0_group)
+ RESOLVEFUNC(EC_GROUP_get_degree)
+#endif
+ RESOLVEFUNC(BN_num_bits)
+#if QT_CONFIG(opensslv11)
+ RESOLVEFUNC(BN_is_word)
+#endif
+ RESOLVEFUNC(BN_mod_word)
+ RESOLVEFUNC(BN_set_word)
+ RESOLVEFUNC(BN_new)
+ RESOLVEFUNC(BN_free)
+ RESOLVEFUNC(BN_clear)
+ RESOLVEFUNC(BN_clear_free)
+ RESOLVEFUNC(ERR_error_string)
+ RESOLVEFUNC(ERR_error_string_n)
+ RESOLVEFUNC(ERR_get_error)
+ RESOLVEFUNC(EVP_CIPHER_CTX_new)
+ RESOLVEFUNC(EVP_CIPHER_CTX_free)
+ RESOLVEFUNC(EVP_CIPHER_CTX_ctrl)
+ RESOLVEFUNC(EVP_CIPHER_CTX_set_key_length)
+ RESOLVEFUNC(EVP_CipherInit)
+ RESOLVEFUNC(EVP_CipherInit_ex)
+ RESOLVEFUNC(EVP_CipherUpdate)
+ RESOLVEFUNC(EVP_CipherFinal)
+ RESOLVEFUNC(EVP_get_digestbyname)
+ RESOLVEFUNC(EVP_sha1)
+ RESOLVEFUNC(EVP_sha256)
+ RESOLVEFUNC(EVP_aes_256_gcm)
+ RESOLVEFUNC(EVP_aes_128_cbc)
+ RESOLVEFUNC(EVP_PKEY_assign)
+ RESOLVEFUNC(EVP_PKEY_set1_RSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DH)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
+#endif
+ RESOLVEFUNC(EVP_PKEY_free)
+ RESOLVEFUNC(EVP_PKEY_get1_RSA)
+ RESOLVEFUNC(EVP_PKEY_get1_DH)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
+#endif
+ RESOLVEFUNC(EVP_PKEY_new)
+ RESOLVEFUNC(EVP_PKEY_type)
+ RESOLVEFUNC(OBJ_nid2sn)
+ RESOLVEFUNC(OBJ_nid2ln)
+ RESOLVEFUNC(OBJ_sn2nid)
+ RESOLVEFUNC(OBJ_ln2nid)
+ RESOLVEFUNC(i2t_ASN1_OBJECT)
+ RESOLVEFUNC(OBJ_obj2txt)
+ RESOLVEFUNC(OBJ_obj2nid)
+
+#ifndef SSLEAY_MACROS
+ RESOLVEFUNC(PEM_read_bio_PrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PKCS8PrivateKey)
+ RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
+#endif
+ RESOLVEFUNC(PEM_read_bio_DHparams)
+ RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PrivateKey)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
+#endif
+#endif // !SSLEAY_MACROS
+
+ RESOLVEFUNC(PEM_read_bio_PUBKEY)
+ RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
+#endif
+ RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_PUBKEY)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
+#endif
+ RESOLVEFUNC(RAND_seed)
+ RESOLVEFUNC(RAND_status)
+ RESOLVEFUNC(RAND_bytes)
+ RESOLVEFUNC(RSA_new)
+ RESOLVEFUNC(RSA_generate_key_ex);
+ RESOLVEFUNC(RSA_free)
+ RESOLVEFUNC(X509_NAME_entry_count)
+ RESOLVEFUNC(X509_NAME_get_entry)
+ RESOLVEFUNC(X509_NAME_ENTRY_get_data)
+ RESOLVEFUNC(X509_NAME_ENTRY_get_object)
+ RESOLVEFUNC(X509_PUBKEY_get)
+ RESOLVEFUNC(X509_STORE_free)
+ RESOLVEFUNC(X509_STORE_new)
+ RESOLVEFUNC(X509_STORE_add_cert)
+ RESOLVEFUNC(X509_STORE_CTX_free)
+ RESOLVEFUNC(X509_STORE_CTX_init)
+ RESOLVEFUNC(X509_STORE_CTX_new)
+ RESOLVEFUNC(X509_STORE_CTX_set_purpose)
+ RESOLVEFUNC(X509_STORE_CTX_get_error)
+ RESOLVEFUNC(X509_STORE_CTX_get_error_depth)
+ RESOLVEFUNC(X509_STORE_CTX_get_current_cert)
+ RESOLVEFUNC(X509_cmp)
+ RESOLVEFUNC(X509_STORE_CTX_get_ex_data)
+
+#ifndef SSLEAY_MACROS
+ RESOLVEFUNC(X509_dup)
+#endif
+ RESOLVEFUNC(X509_print)
+ RESOLVEFUNC(X509_digest)
+ RESOLVEFUNC(X509_EXTENSION_get_object)
+ RESOLVEFUNC(X509_free)
+ RESOLVEFUNC(X509_gmtime_adj)
+ RESOLVEFUNC(ASN1_TIME_free)
+ RESOLVEFUNC(X509_get_ext)
+ RESOLVEFUNC(X509_get_ext_count)
+ RESOLVEFUNC(X509_get_ext_d2i)
+ RESOLVEFUNC(X509V3_EXT_get)
+ RESOLVEFUNC(X509V3_EXT_d2i)
+ RESOLVEFUNC(X509_EXTENSION_get_critical)
+ RESOLVEFUNC(X509_EXTENSION_get_data)
+ RESOLVEFUNC(BASIC_CONSTRAINTS_free)
+ RESOLVEFUNC(AUTHORITY_KEYID_free)
+ RESOLVEFUNC(GENERAL_NAME_free)
+ RESOLVEFUNC(ASN1_STRING_print)
+ RESOLVEFUNC(X509_check_issued)
+ RESOLVEFUNC(X509_get_issuer_name)
+ RESOLVEFUNC(X509_get_subject_name)
+ RESOLVEFUNC(X509_get_serialNumber)
+ RESOLVEFUNC(X509_verify_cert)
+ RESOLVEFUNC(d2i_X509)
+ RESOLVEFUNC(i2d_X509)
+ RESOLVEFUNC(SSL_CTX_load_verify_locations)
+ RESOLVEFUNC(i2d_SSL_SESSION)
+ RESOLVEFUNC(d2i_SSL_SESSION)
+#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_NEXTPROTONEG)
+ RESOLVEFUNC(SSL_select_next_proto)
+ RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
+ RESOLVEFUNC(SSL_get0_next_proto_negotiated)
+#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ RESOLVEFUNC(SSL_set_alpn_protos)
+ RESOLVEFUNC(SSL_CTX_set_alpn_select_cb)
+ RESOLVEFUNC(SSL_get0_alpn_selected)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
+ RESOLVEFUNC(CRYPTO_malloc)
+ RESOLVEFUNC(DH_new)
+ RESOLVEFUNC(DH_free)
+ RESOLVEFUNC(d2i_DHparams)
+ RESOLVEFUNC(i2d_DHparams)
+ RESOLVEFUNC(DH_check)
+ RESOLVEFUNC(BN_bin2bn)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EC_KEY_dup)
+ RESOLVEFUNC(EC_KEY_new_by_curve_name)
+ RESOLVEFUNC(EC_KEY_free)
+ RESOLVEFUNC(EC_get_builtin_curves)
+#endif // OPENSSL_NO_EC
+ RESOLVEFUNC(PKCS12_parse)
+ RESOLVEFUNC(d2i_PKCS12_bio)
+ RESOLVEFUNC(PKCS12_free)
+ RESOLVEFUNC(X509_REQ_to_X509)
+ RESOLVEFUNC(PEM_write_bio_X509)
+ RESOLVEFUNC(X509_new)
+ RESOLVEFUNC(ASN1_INTEGER_set)
+ RESOLVEFUNC(X509_set_pubkey)
+ RESOLVEFUNC(X509_set_issuer_name)
+ RESOLVEFUNC(X509_sign)
+ RESOLVEFUNC(X509_add_ext)
+ RESOLVEFUNC(X509_set_version)
+ RESOLVEFUNC(X509_set_subject_name)
+ RESOLVEFUNC(ASN1_OCTET_STRING_new)
+ RESOLVEFUNC(X509_pubkey_digest)
+ RESOLVEFUNC(ASN1_OCTET_STRING_set)
+ RESOLVEFUNC(X509_add1_ext_i2d)
+ RESOLVEFUNC(ASN1_OCTET_STRING_free)
+ RESOLVEFUNC(ASN1_INTEGER_new)
+ RESOLVEFUNC(GENERAL_NAMES_new)
+ RESOLVEFUNC(GENERAL_NAME_new)
+ RESOLVEFUNC(X509_NAME_dup)
+ RESOLVEFUNC(X509_set_serialNumber)
+ RESOLVEFUNC(AUTHORITY_KEYID_new)
+ RESOLVEFUNC(ASN1_INTEGER_dup)
+ RESOLVEFUNC(X509_NAME_digest)
+ RESOLVEFUNC(ASN1_INTEGER_free)
+ RESOLVEFUNC(i2d_X509_REQ_bio)
+ RESOLVEFUNC(i2d_X509_bio)
+
+ symbolsResolved.storeRelease(true);
+ return true;
+}
+#endif // QT_CONFIG(library)
+
+#else // !defined QT_LINKED_OPENSSL
+
+bool q_resolveOpenSslSymbols()
+{
+#ifdef QT_NO_OPENSSL
+ return false;
+#endif
+ return true;
+}
+#endif // !defined QT_LINKED_OPENSSL
+
+//==============================================================================
+// contributed by Jay Case of Sarvega, Inc.; http://sarvega.com/
+// Based on X509_cmp_time() for intitial buffer hacking.
+//==============================================================================
+QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
+{
+ size_t lTimeLength = aTime->length;
+ char *pString = (char *) aTime->data;
+
+ if (aTime->type == V_ASN1_UTCTIME) {
+
+ char lBuffer[24];
+ char *pBuffer = lBuffer;
+
+ if ((lTimeLength < 11) || (lTimeLength > 17))
+ return QDateTime();
+
+ memcpy(pBuffer, pString, 10);
+ pBuffer += 10;
+ pString += 10;
+
+ if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
+ *pBuffer++ = '0';
+ *pBuffer++ = '0';
+ } else {
+ *pBuffer++ = *pString++;
+ *pBuffer++ = *pString++;
+ // Skip any fractional seconds...
+ if (*pString == '.') {
+ pString++;
+ while ((*pString >= '0') && (*pString <= '9'))
+ pString++;
+ }
+ }
+
+ *pBuffer++ = 'Z';
+ *pBuffer++ = '\0';
+
+ time_t lSecondsFromUCT;
+ if (*pString == 'Z') {
+ lSecondsFromUCT = 0;
+ } else {
+ if ((*pString != '+') && (*pString != '-'))
+ return QDateTime();
+
+ lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
+ lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
+ lSecondsFromUCT *= 60;
+ if (*pString == '-')
+ lSecondsFromUCT = -lSecondsFromUCT;
+ }
+
+ tm lTime;
+ lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
+ lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
+ lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
+ lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
+ lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
+ lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
+ if (lTime.tm_year < 50)
+ lTime.tm_year += 100; // RFC 2459
+
+ QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ result = result.addSecs(lSecondsFromUCT);
+ return result;
+
+ } else if (aTime->type == V_ASN1_GENERALIZEDTIME) {
+
+ if (lTimeLength < 15)
+ return QDateTime(); // hopefully never triggered
+
+ // generalized time is always YYYYMMDDHHMMSSZ (RFC 2459, section 4.1.2.5.2)
+ tm lTime;
+ lTime.tm_sec = ((pString[12] - '0') * 10) + (pString[13] - '0');
+ lTime.tm_min = ((pString[10] - '0') * 10) + (pString[11] - '0');
+ lTime.tm_hour = ((pString[8] - '0') * 10) + (pString[9] - '0');
+ lTime.tm_mday = ((pString[6] - '0') * 10) + (pString[7] - '0');
+ lTime.tm_mon = (((pString[4] - '0') * 10) + (pString[5] - '0'));
+ lTime.tm_year = ((pString[0] - '0') * 1000) + ((pString[1] - '0') * 100) +
+ ((pString[2] - '0') * 10) + (pString[3] - '0');
+
+ QDate resDate(lTime.tm_year, lTime.tm_mon, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ return result;
+
+ } else {
+ qCWarning(lcSsl, "unsupported date format detected");
+ return QDateTime();
+ }
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/openssl_symbols_p.h b/src/opcua/x509/openssl_symbols_p.h
new file mode 100644
index 0000000..0241c51
--- /dev/null
+++ b/src/opcua/x509/openssl_symbols_p.h
@@ -0,0 +1,566 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef OPENSSL_SYMBOLS_P_H
+#define OPENSSL_SYMBOLS_P_H
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/pkcs7.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/tls1.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtCore/QLoggingCategory>
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#if defined(X509_NAME)
+#undef X509_NAME
+#endif
+#endif // Q_OS_WIN
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSsl)
+
+#define DUMMYARG
+
+#if !defined QT_LINKED_OPENSSL
+// **************** Shared declarations ******************
+// ret func(arg)
+
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a); \
+ }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func);\
+ err; \
+ } \
+ funcret _q_##func(a, b); \
+ }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { \
+ if (Q_UNLIKELY(!_q_##func)) { \
+ qsslSocketUnresolvedSymbolWarning(#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g, h, i); \
+ }
+// **************** Shared declarations ******************
+
+#else // !defined QT_LINKED_OPENSSL
+
+// **************** Static declarations ******************
+
+// ret func(arg)
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ ret q_##func(arg) { funcret func(a); }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ ret q_##func(arg1, arg2) { funcret func(a, b); }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ ret q_##func(arg1, arg2, arg3) { funcret func(a, b, c); }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4) { funcret func(a, b, c, d); }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { funcret func(a, b, c, d, e); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { funcret func(a, b, c, d, e, f); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { funcret func(a, b, c, d, e, f, g); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { funcret func(a, b, c, d, e, f, g, h, i); }
+
+// **************** Static declarations ******************
+
+#endif // !defined QT_LINKED_OPENSSL
+
+#if QT_CONFIG(opensslv11)
+#include "qsslsocket_openssl11_symbols_p.h"
+#else
+#include "qsslsocket_opensslpre11_symbols_p.h"
+#endif // QT_CONFIG
+
+bool q_resolveOpenSslSymbols();
+long q_ASN1_INTEGER_get(ASN1_INTEGER *a);
+int q_ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
+int q_ASN1_STRING_length(ASN1_STRING *a);
+int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b);
+long q_BIO_ctrl(BIO *a, int b, long c, void *d);
+Q_AUTOTEST_EXPORT int q_BIO_free(BIO *a);
+void q_BIO_free_all(BIO *a);
+BIO *q_BIO_new_mem_buf(void *a, int b);
+int q_BIO_read(BIO *a, void *b, int c);
+Q_AUTOTEST_EXPORT int q_BIO_write(BIO *a, const void *b, int c);
+int q_BN_num_bits(const BIGNUM *a);
+
+#if QT_CONFIG(opensslv11)
+int q_BN_is_word(BIGNUM *a, BN_ULONG w);
+#else // opensslv11
+// BN_is_word is implemented purely as a
+// macro in OpenSSL < 1.1. It doesn't
+// call any functions.
+//
+// The implementation of BN_is_word is
+// 100% the same between 1.0.0, 1.0.1
+// and 1.0.2.
+//
+// Users are required to include <openssl/bn.h>.
+#define q_BN_is_word BN_is_word
+#endif // !opensslv11
+
+BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w);
+int q_BN_set_word(const BIGNUM *a, BN_ULONG w);
+BIGNUM *q_BN_new();
+void q_BN_clear(BIGNUM *a);
+void q_BN_free(BIGNUM *a);
+void q_BN_clear_free(BIGNUM *a);
+
+#ifndef OPENSSL_NO_EC
+const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
+int q_EC_GROUP_get_degree(const EC_GROUP* g);
+#endif
+DSA *q_DSA_new();
+void q_DSA_free(DSA *a);
+X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
+char *q_ERR_error_string(unsigned long a, char *b);
+void q_ERR_error_string_n(unsigned long e, char *buf, size_t len);
+unsigned long q_ERR_get_error();
+EVP_CIPHER_CTX *q_EVP_CIPHER_CTX_new();
+void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
+int q_EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+int q_EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
+int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv, int enc);
+int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc);
+int q_EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
+int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+const EVP_MD *q_EVP_get_digestbyname(const char *name);
+X509_REQ *q_X509_REQ_new();
+void q_X509_REQ_free(X509_REQ *req);
+int q_PEM_write_bio_X509_REQ(BIO *bp, X509_REQ *x);
+int q_PEM_write_bio_X509_REQ_NEW(BIO *bp, X509_REQ *x);
+int q_X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts);
+void q_X509_EXTENSION_free(X509_EXTENSION *ext);
+int q_X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit);
+ASN1_INTEGER *q_ASN1_INTEGER_dup(const ASN1_INTEGER *x);
+
+#if QT_CONFIG(opensslv11)
+X509_NAME *q_X509_REQ_get_subject_name(X509_REQ *req);
+#define q_ERR_load_crypto_strings() \
+ q_OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
+#else // opensslv11
+void q_ERR_load_crypto_strings();
+#define q_X509_REQ_get_subject_name X509_REQ_get_subject_name
+#define q_X509_get_notBefore X509_get_notBefore
+#define q_X509_get_notAfter X509_get_notAfter
+#endif // !opensslv11
+
+
+int q_X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, const unsigned char *bytes, int len, int loc, int set);
+int q_X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int type, const unsigned char *bytes, int len, int loc, int set);
+ASN1_OBJECT *q_OBJ_txt2obj(const char *s, int no_name);
+int q_X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
+int q_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
+int q_X509_REQ_set_version(X509_REQ *x, long version);
+X509_EXTENSION *q_X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, int ext_nid, char *value);
+
+#ifndef OPENSSL_NO_DES
+const EVP_CIPHER *q_EVP_des_cbc();
+const EVP_CIPHER *q_EVP_des_ede3_cbc();
+#endif
+const EVP_CIPHER *q_EVP_aes_256_gcm();
+const EVP_CIPHER *q_EVP_aes_128_cbc();
+Q_AUTOTEST_EXPORT const EVP_MD *q_EVP_sha1();
+const EVP_MD *q_EVP_sha256();
+int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c);
+Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
+int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
+int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
+#ifndef OPENSSL_NO_EC
+int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
+#endif
+Q_AUTOTEST_EXPORT void q_EVP_PKEY_free(EVP_PKEY *a);
+RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
+DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
+DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a);
+#ifndef OPENSSL_NO_EC
+EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
+#endif
+int q_EVP_PKEY_type(int a);
+Q_AUTOTEST_EXPORT EVP_PKEY *q_EVP_PKEY_new();
+int q_i2d_X509(X509 *a, unsigned char **b);
+const char *q_OBJ_nid2sn(int a);
+const char *q_OBJ_nid2ln(int a);
+int q_OBJ_sn2nid(const char *s);
+int q_OBJ_ln2nid(const char *s);
+int q_i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *obj);
+int q_OBJ_obj2txt(char *buf, int buf_len, ASN1_OBJECT *obj, int no_name);
+int q_OBJ_obj2nid(const ASN1_OBJECT *a);
+#define q_EVP_get_digestbynid(a) q_EVP_get_digestbyname(q_OBJ_nid2sn(a))
+#ifdef SSLEAY_MACROS
+// ### verify
+void *q_PEM_ASN1_read_bio(d2i_of_void *a, const char *b, BIO *c, void **d, pem_password_cb *e,
+ void *f);
+// ### ditto for write
+#else
+Q_AUTOTEST_EXPORT EVP_PKEY *q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
+DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
+#ifndef OPENSSL_NO_EC
+EC_KEY *q_PEM_read_bio_ECPrivateKey(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
+#endif
+DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
+int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_PKCS8PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+#ifndef OPENSSL_NO_EC
+int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+#endif
+#endif // SSLEAY_MACROS
+Q_AUTOTEST_EXPORT EVP_PKEY *q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
+DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
+#ifndef OPENSSL_NO_EC
+EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
+#endif
+int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
+int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
+int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b);
+#ifndef OPENSSL_NO_EC
+int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
+#endif
+void q_RAND_seed(const void *a, int b);
+int q_RAND_status();
+int q_RAND_bytes(unsigned char *b, int n);
+RSA *q_RSA_new();
+void q_RSA_free(RSA *a);
+int q_RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+typedef unsigned int (*q_psk_client_callback_t)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
+void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback);
+typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len);
+#endif // OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+int q_SSL_write(SSL *a, const void *b, int c);
+int q_X509_cmp(X509 *a, X509 *b);
+#ifdef SSLEAY_MACROS
+void *q_ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
+#define q_X509_dup(x509) (X509 *)q_ASN1_dup((i2d_of_void *)q_i2d_X509, \
+ (d2i_of_void *)q_d2i_X509,(char *)x509)
+#else
+X509 *q_X509_dup(X509 *a);
+#endif
+void q_X509_print(BIO *a, X509*b);
+int q_X509_digest(const X509 *x509, const EVP_MD *type, unsigned char *md, unsigned int *len);
+ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a);
+Q_AUTOTEST_EXPORT void q_X509_free(X509 *a);
+Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj);
+Q_AUTOTEST_EXPORT void q_ASN1_TIME_free(ASN1_TIME *t);
+X509_EXTENSION *q_X509_get_ext(X509 *a, int b);
+int q_X509_get_ext_count(X509 *a);
+void *q_X509_get_ext_d2i(X509 *a, int b, int *c, int *d);
+const X509V3_EXT_METHOD *q_X509V3_EXT_get(X509_EXTENSION *a);
+void *q_X509V3_EXT_d2i(X509_EXTENSION *a);
+int q_X509_EXTENSION_get_critical(X509_EXTENSION *a);
+ASN1_OCTET_STRING *q_X509_EXTENSION_get_data(X509_EXTENSION *a);
+void q_BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *a);
+void q_AUTHORITY_KEYID_free(AUTHORITY_KEYID *a);
+int q_ASN1_STRING_print(BIO *a, const ASN1_STRING *b);
+int q_X509_check_issued(X509 *a, X509 *b);
+X509_NAME *q_X509_get_issuer_name(X509 *a);
+X509_NAME *q_X509_get_subject_name(X509 *a);
+ASN1_INTEGER *q_X509_get_serialNumber(X509 *a);
+int q_X509_verify_cert(X509_STORE_CTX *ctx);
+int q_X509_NAME_entry_count(X509_NAME *a);
+X509_NAME_ENTRY *q_X509_NAME_get_entry(X509_NAME *a,int b);
+ASN1_STRING *q_X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *a);
+ASN1_OBJECT *q_X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *a);
+EVP_PKEY *q_X509_PUBKEY_get(X509_PUBKEY *a);
+void q_X509_STORE_free(X509_STORE *store);
+X509_STORE *q_X509_STORE_new();
+int q_X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
+void q_X509_STORE_CTX_free(X509_STORE_CTX *storeCtx);
+int q_X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+ X509 *x509, STACK_OF(X509) *chain);
+X509_STORE_CTX *q_X509_STORE_CTX_new();
+int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+int q_X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
+int q_X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
+X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
+X509 *q_X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey);
+int q_PEM_write_bio_X509(BIO *bp, X509 *x);
+X509 *q_X509_new();
+int q_ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+int q_X509_set_pubkey(X509 *x, EVP_PKEY *key);
+int q_X509_set_issuer_name(X509 *x, X509_NAME *name);
+int q_X509_sign(X509 *x, EVP_PKEY *key, const EVP_MD *md);
+int q_X509_add_ext(X509 *x, X509_EXTENSION *ex, int location);
+int q_X509_set_version(X509 *x, long version);
+int q_X509_set_subject_name(X509 *x, X509_NAME *name);
+ASN1_OCTET_STRING *q_ASN1_OCTET_STRING_new();
+int q_X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md, unsigned int *len);
+int q_ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len);
+int q_X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, unsigned long flags);
+void q_ASN1_OCTET_STRING_free(ASN1_OCTET_STRING *a);
+int q_X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, unsigned char *md, unsigned int *len);
+ASN1_INTEGER *q_ASN1_INTEGER_new();
+GENERAL_NAMES *q_GENERAL_NAMES_new();
+GENERAL_NAME *q_GENERAL_NAME_new();
+X509_NAME *q_X509_NAME_dup(X509_NAME *xn);
+int q_X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial);
+AUTHORITY_KEYID *q_AUTHORITY_KEYID_new();
+void q_ASN1_INTEGER_free(ASN1_INTEGER *a);
+int q_i2d_X509_REQ_bio(BIO *bp, X509_REQ *req);
+int q_i2d_X509_bio(BIO *bp, X509 *x509);
+
+// Diffie-Hellman support
+DH *q_DH_new();
+void q_DH_free(DH *dh);
+DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
+int q_i2d_DHparams(DH *a, unsigned char **p);
+int q_DH_check(DH *dh, int *codes);
+
+BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
+
+#ifndef OPENSSL_NO_EC
+// EC Diffie-Hellman support
+EC_KEY *q_EC_KEY_dup(const EC_KEY *src);
+EC_KEY *q_EC_KEY_new_by_curve_name(int nid);
+void q_EC_KEY_free(EC_KEY *ecdh);
+
+// EC curves management
+size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+int q_EC_curve_nist2nid(const char *name);
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+#endif // OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+
+// PKCS#12 support
+int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
+PKCS12 *q_d2i_PKCS12_bio(BIO *bio, PKCS12 **pkcs12);
+void q_PKCS12_free(PKCS12 *pkcs12);
+
+#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
+#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
+#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st))
+#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
+#if QT_CONFIG(opensslv11)
+#define q_sk_GENERAL_NAME_push(st, val) q_OPENSSL_sk_push((st), (val))
+#else
+#define q_sk_GENERAL_NAME_push(st, val) q_SKM_sk_push(GENERAL_NAME, (st), (val))
+#endif
+
+void q_GENERAL_NAME_free(GENERAL_NAME *a);
+
+#define q_sk_X509_num(st) q_SKM_sk_num(X509, (st))
+#define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i))
+#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num(SSL_CIPHER, (st))
+#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
+#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
+ q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
+ (char *)(rsa))
+#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
+ (char *)(dsa))
+#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
+int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
+
+void q_BIO_set_flags(BIO *b, int flags);
+void q_BIO_clear_flags(BIO *b, int flags);
+void *q_BIO_get_ex_data(BIO *b, int idx);
+int q_BIO_set_ex_data(BIO *b, int idx, void *data);
+
+#define q_BIO_set_retry_read(b) q_BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_retry_write(b) q_BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_clear_retry_flags(b) q_BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
+#define q_BIO_set_app_data(s,arg) q_BIO_set_ex_data(s,0,arg)
+#define q_BIO_get_app_data(s) q_BIO_get_ex_data(s,0)
+
+// Helper function
+class QDateTime;
+QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);
+
+void *q_CRYPTO_malloc(size_t num, const char *file, int line);
+#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/opcua/x509/qopcuakeypair.cpp b/src/opcua/x509/qopcuakeypair.cpp
new file mode 100644
index 0000000..90e60fe
--- /dev/null
+++ b/src/opcua/x509/qopcuakeypair.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuakeypair.h"
+#include "qopcuakeypair_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaKeyPair
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief QOpcUaKeyPair handles private and public key pairs
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ It can generate, load and store keys for asymmetric encryption.
+ Instances of this class have to be passed to functions which need a key.
+*/
+
+/*!
+ \enum QOpcUaKeyPair::RsaKeyStrength
+
+ This enum type specifies the strength of a RSA key.
+
+ \value Bits1024
+ A key strength of 1024 bits.
+ \value Bits2048
+ A key strength of 2048 bits.
+ \value Bits4096
+ A key strength of 4096 bits.
+*/
+
+/*!
+ \enum QOpcUaKeyPair::KeyType
+
+ This enum type specifies the type of a key.
+
+ \value Rsa
+ An RSA key
+ \value Empty
+ No key is available.
+ \value Unknown
+ The type of key is not handled.
+*/
+
+/*!
+ \enum QOpcUaKeyPair::Cipher
+
+ Ciphers for encryption of private keys.
+
+ \value Aes128Cbc
+ Encrypting AES128 with CBC
+ \value Unencrypted
+ The Key will not be encrypted.
+*/
+
+/*!
+ \fn QOpcUaKeyPair::passphaseNeeded()
+
+ This signal is emitted when a private key needs a passphrase for en- or decryption.
+
+ Place the passphrase in \a passphrase.
+ \a writeOperation is \c true when the passphrase is needed for exporting a key, and
+ is \c false when the passphrase is needed for importing a key.
+
+ \a maximumPassphraseSize specifies the maximum length in bytes for the passphrase.
+ All characters in \a passphrase exceeding this limit will be ignored.
+
+ In case you have use this signal crossing thread boundaries you have to connect it
+ with \c Qt::BlockingQueuedConnection.
+*/
+
+/*!
+ Creates a new empty key pair.
+*/
+QOpcUaKeyPair::QOpcUaKeyPair(QObject *parent)
+ : QObject(*(new QOpcUaKeyPairPrivate()), parent)
+{
+}
+/*!
+ Destroys the key pair.
+*/
+QOpcUaKeyPair::~QOpcUaKeyPair()
+{
+}
+
+/*!
+ Loads a key from PEM encoded data in \a data.
+ Returns \c true on success and \c false otherwise.
+
+ It detects from the PEM header if the data contains a private or
+ public key. Loading encrypted keys is possible by connecting a
+ function to the signal \c passphraseNeeded for provision of the
+ passphrase.
+*/
+bool QOpcUaKeyPair::loadFromPemData(const QByteArray &data)
+{
+ Q_D(QOpcUaKeyPair);
+ return d->loadFromPemData(data);
+}
+
+/*!
+ Loads a key from PEM encoded data in \a data.
+ Returns \c true on success and \c false otherwise.
+
+ It detects from the PEM header if the data contains a private or
+ public key. Loading encrypted keys is possible by connecting a
+ function to the signal \c passphraseNeeded for provision of the
+ passphrase.
+*/
+QByteArray QOpcUaKeyPair::publicKeyToByteArray() const
+{
+ Q_D(const QOpcUaKeyPair);
+ return d->publicKeyToByteArray();
+}
+
+/*!
+ Returns the type of the current key.
+*/
+QOpcUaKeyPair::KeyType QOpcUaKeyPair::type() const
+{
+ Q_D(const QOpcUaKeyPair);
+ return d->keyType();
+}
+
+/*!
+ Returns \c true if the current key contains a private key, otherwise \c false.
+*/
+bool QOpcUaKeyPair::hasPrivateKey() const
+{
+ Q_D(const QOpcUaKeyPair);
+ return d->hasPrivateKey();
+}
+
+/*!
+ Returns the PEM encoded private key.
+ In case there is no private key, an empty byte array is returned.
+
+ The encryption of the key has to be specified using the parameters
+ \a cipher and \a password. In order to store the key unencrypted
+ the cipher \c Cipher::Unencrypted has to be used.
+*/
+QByteArray QOpcUaKeyPair::privateKeyToByteArray(Cipher cipher, const QString &password) const
+{
+ Q_D(const QOpcUaKeyPair);
+ return d->privateKeyToByteArray(cipher, password);
+}
+
+
+/*!
+ Generates a new asymmetric RSA key pair.
+
+ The length of the key can be specified by the \c strength parameter.
+*/
+void QOpcUaKeyPair::generateRsaKey(QOpcUaKeyPair::RsaKeyStrength strength)
+{
+ Q_D(QOpcUaKeyPair);
+ d->generateRsaKey(strength);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuakeypair.h b/src/opcua/x509/qopcuakeypair.h
new file mode 100644
index 0000000..dbd1197
--- /dev/null
+++ b/src/opcua/x509/qopcuakeypair.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAKEYPAIR_H
+#define QOPCUAKEYPAIR_H
+
+#include <QObject>
+#include <QString>
+#include <QSharedPointer>
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaKeyPairPrivate;
+
+class Q_OPCUA_EXPORT QOpcUaKeyPair : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QOpcUaKeyPair)
+
+public:
+ enum class RsaKeyStrength {
+ Bits1024 = 1024,
+ Bits2048 = 2048,
+ Bits4096 = 4096
+ };
+
+ enum class KeyType {
+ Rsa,
+ Empty,
+ Unknown
+ };
+
+ enum class Cipher {
+ Aes128Cbc,
+ Unencrypted
+ };
+
+ QOpcUaKeyPair(QObject *parent = nullptr);
+
+ virtual ~QOpcUaKeyPair();
+ bool loadFromPemData(const QByteArray &data);
+ QByteArray publicKeyToByteArray() const;
+ QByteArray privateKeyToByteArray(Cipher cipher, const QString &password) const;
+ KeyType type() const;
+ bool hasPrivateKey() const;
+ void generateRsaKey(QOpcUaKeyPair::RsaKeyStrength strength);
+
+Q_SIGNALS:
+ void passphraseNeeded(QString &passphrase, int maximumLength, bool writeOperation);
+
+ friend class QOpcUaX509CertificateSigningRequestPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAKEYPAIR_H
diff --git a/src/opcua/x509/qopcuakeypair_openssl.cpp b/src/opcua/x509/qopcuakeypair_openssl.cpp
new file mode 100644
index 0000000..66a7b7e
--- /dev/null
+++ b/src/opcua/x509/qopcuakeypair_openssl.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuakeypair_p.h"
+#include "openssl_symbols_p.h"
+#include "qopcuax509utils_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QOpcUaKeyPairPrivate::QOpcUaKeyPairPrivate()
+ : QObjectPrivate()
+{
+ if (!q_resolveOpenSslSymbols())
+ qFatal("Failed to resolve symbols");
+
+ q_ERR_load_crypto_strings();
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ q_OPENSSL_add_all_algorithms_noconf();
+#endif
+}
+
+QOpcUaKeyPairPrivate::~QOpcUaKeyPairPrivate()
+{
+ if (m_keyData) {
+ q_EVP_PKEY_free(m_keyData);
+ m_keyData = nullptr;
+ }
+}
+
+static int passwordCallback(char *passphraseBuffer, int maximumPassphraseSize, int writeOperation, void *userData) {
+ QOpcUaKeyPair *source = reinterpret_cast<QOpcUaKeyPair*>(userData);
+ QString passphrase;
+ source->passphraseNeeded(passphrase, maximumPassphraseSize, writeOperation == 1);
+
+ if (passphrase.isEmpty())
+ return -1;
+
+ memcpy(passphraseBuffer, passphrase.toUtf8().constData(), qMin(maximumPassphraseSize, passphrase.size()));
+ return passphrase.size();
+}
+
+bool QOpcUaKeyPairPrivate::loadFromPemData(const QByteArray &data) {
+ Q_Q(QOpcUaKeyPair);
+
+ if (m_keyData) {
+ q_EVP_PKEY_free(m_keyData);
+ m_keyData = nullptr;
+ }
+ m_hasPrivateKey = false;
+
+ BIO *bio = q_BIO_new_mem_buf((void *)data.constData(), data.size());
+ if (!bio) {
+ qCWarning(lcSsl) << "Failed to allocate a buffer:" << getOpenSslError();
+ return false;
+ }
+ Deleter<BIO> bioDeleter(bio, q_BIO_free_all);
+
+ if (data.startsWith("-----BEGIN PRIVATE KEY-----") || data.startsWith("-----BEGIN ENCRYPTED PRIVATE KEY-----")) {
+ if (!q_PEM_read_bio_PrivateKey(bio, &m_keyData, &passwordCallback, q /* userData */)) {
+ qCWarning(lcSsl) << "Failed to load private key:" << getOpenSslError();
+ return false;
+ }
+ m_hasPrivateKey = true;
+ } else {
+ if (!q_PEM_read_bio_PUBKEY(bio, &m_keyData, NULL, NULL)) {
+ qCWarning(lcSsl) << "Failed to load public key:" << getOpenSslError();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QByteArray QOpcUaKeyPairPrivate::publicKeyToByteArray() const
+{
+ if (!m_keyData) {
+ qCWarning(lcSsl) << "No public key to write";
+ return QByteArray();
+ }
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio) {
+ qCWarning(lcSsl) << "Failed to allocate a buffer:" << getOpenSslError();
+ return QByteArray();
+ }
+ Deleter<BIO> bioDeleter(bio, q_BIO_free_all);
+
+ if (0 == q_PEM_write_bio_PUBKEY(bio, m_keyData)) {
+ qCWarning(lcSsl) << "Failed to write public key:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ char *buf;
+ int length = q_BIO_get_mem_data(bio, &buf);
+ QByteArray data(buf, length);
+ return data;
+}
+
+bool QOpcUaKeyPairPrivate::generateRsaKey(QOpcUaKeyPair::RsaKeyStrength strength)
+{
+ if (m_keyData) {
+ q_EVP_PKEY_free(m_keyData);
+ m_keyData = nullptr;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_PKEY_CTX *ctx = q_EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
+ if (!ctx) {
+ qCWarning(lcSsl) << "Failed to allocate context:" << getOpenSslError();
+ return false;
+ }
+ Deleter<EVP_PKEY_CTX> ctxDeleter(ctx, q_EVP_PKEY_CTX_free);
+
+ if (q_EVP_PKEY_keygen_init(ctx) <= 0) {
+ qCWarning(lcSsl) << "Failed to initialize context:" << getOpenSslError();
+ return false;
+ }
+
+ if (q_EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, static_cast<int>(strength)) <= 0) {
+ qCWarning(lcSsl) << "Failed to set context property:" << getOpenSslError();
+ return false;
+ }
+
+ if (q_EVP_PKEY_keygen(ctx, &m_keyData) <= 0) {
+ qCWarning(lcSsl) << "Failed to generate key:" << getOpenSslError();
+ return false;
+ }
+
+#else
+ RSA *rsa;
+ BIGNUM *publicExponent;
+
+ publicExponent = q_BN_new();
+ if (publicExponent == NULL) {
+ qCWarning(lcSsl) << "Failed to allocate public exponent:" << getOpenSslError();
+ return false;
+ }
+ Deleter<BIGNUM> publicExponentDeleter(publicExponent, q_BN_free);
+
+ if (q_BN_set_word(publicExponent, RSA_F4) == 0) {
+ qCWarning(lcSsl) << "Failed to set public exponent:" << getOpenSslError();
+ return false;
+ }
+
+ rsa = q_RSA_new();
+ if (rsa == NULL) {
+ qCWarning(lcSsl) << "Failed to allocate RSA:" << getOpenSslError();
+ return false;
+ }
+ Deleter<RSA> rsaDeleter(rsa, q_RSA_free);
+
+ int result = q_RSA_generate_key_ex(rsa, static_cast<int>(strength), publicExponent, nullptr /* progress callback */);
+ if (result == 0) {
+ qCWarning(lcSsl) << "Failed to generate key:" << getOpenSslError();
+ return false;
+ }
+
+ m_keyData = q_EVP_PKEY_new();
+ if (!m_keyData) {
+ qCWarning(lcSsl) << "Failed to allocate key data:" << getOpenSslError();
+ return false;
+ }
+
+ if (!q_EVP_PKEY_set1_RSA(m_keyData, rsa)) {
+ qCWarning(lcSsl) << "Failed to transfer key data:" << getOpenSslError();
+ return false;
+ }
+#endif
+ m_hasPrivateKey = true;
+ return true;
+}
+
+QOpcUaKeyPair::KeyType QOpcUaKeyPairPrivate::keyType() const
+{
+ if (!m_keyData)
+ return QOpcUaKeyPair::KeyType::Empty;
+ switch (q_EVP_PKEY_base_id(m_keyData)) {
+ case EVP_PKEY_RSA:
+ return QOpcUaKeyPair::KeyType::Rsa;
+ default:
+ return QOpcUaKeyPair::KeyType::Unknown;
+ }
+}
+
+QByteArray QOpcUaKeyPairPrivate::privateKeyToByteArray(QOpcUaKeyPair::Cipher cipher, const QString &password) const
+{
+ if (!m_keyData) {
+ qCWarning(lcSsl) << "No private key to write";
+ return QByteArray();
+ }
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio) {
+ qCWarning(lcSsl) << "Failed to allocate a buffer:" << getOpenSslError();
+ return QByteArray();
+ }
+ Deleter<BIO> bioDeleter(bio, q_BIO_free_all);
+
+ const EVP_CIPHER *enc = NULL;
+ if (cipher == QOpcUaKeyPair::Cipher::Unencrypted)
+ enc = NULL;
+ else if (cipher == QOpcUaKeyPair::Cipher::Aes128Cbc)
+ enc = q_EVP_aes_128_cbc();
+ else {
+ qCWarning(lcSsl) << "Unknown cipher given";
+ return QByteArray();
+ }
+
+ if (0 == q_PEM_write_bio_PKCS8PrivateKey(bio, m_keyData, enc,
+ enc ? (unsigned char*)password.toUtf8().constData() : NULL,
+ enc ? password.length() : 0,
+ NULL /* callback */, NULL /* userdata */)) {
+ qCWarning(lcSsl) << "Failed to write private key:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ char *buf;
+ int length = q_BIO_get_mem_data(bio, &buf);
+ QByteArray data(buf, length);
+ return data;
+}
+
+bool QOpcUaKeyPairPrivate::hasPrivateKey() const
+{
+ if (!m_keyData)
+ return false;
+
+ return m_hasPrivateKey;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuakeypair_p.h b/src/opcua/x509/qopcuakeypair_p.h
new file mode 100644
index 0000000..06b5565
--- /dev/null
+++ b/src/opcua/x509/qopcuakeypair_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOPCUAPUBLICKEYPRIVATE_H
+#define QOPCUAPUBLICKEYPRIVATE_H
+
+#include <private/qobject_p.h>
+#include "qopcuakeypair.h"
+#include <QtCore/QLoggingCategory>
+#include <openssl/rsa.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSsl)
+
+class QOpcUaKeyPairPrivate : public QObjectPrivate
+{
+public:
+ QOpcUaKeyPairPrivate();
+ ~QOpcUaKeyPairPrivate();
+
+ bool generateRsaKey(QOpcUaKeyPair::RsaKeyStrength strength);
+ bool loadFromPemData(const QByteArray &data);
+ QByteArray publicKeyToByteArray() const;
+ QByteArray privateKeyToByteArray(QOpcUaKeyPair::Cipher cipher, const QString &password) const;
+ QOpcUaKeyPair::KeyType keyType() const;
+ bool hasPrivateKey() const;
+
+protected:
+ EVP_PKEY *m_keyData = nullptr;
+ bool m_hasPrivateKey = false;
+
+private:
+ Q_DECLARE_PUBLIC(QOpcUaKeyPair)
+
+ friend class QOpcUaX509CertificateSigningRequestPrivate;
+};
+QT_END_NAMESPACE
+
+#endif // QOPCUAPUBLICKEYPRIVATE_H
diff --git a/src/opcua/x509/qopcuax509certificatesigningrequest.cpp b/src/opcua/x509/qopcuax509certificatesigningrequest.cpp
new file mode 100644
index 0000000..7bd808f
--- /dev/null
+++ b/src/opcua/x509/qopcuax509certificatesigningrequest.cpp
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509certificatesigningrequest.h"
+#include "openssl_symbols_p.h"
+
+#include "qopcuakeypair_p.h"
+#include "qopcuax509certificatesigningrequest_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509CertificateSigningRequest
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief QOpcUaX509CertificateSigningRequest create a certificate signing request
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ Before actually creating the singing request data, any extension needed for that
+ specific request has to be added. Current supported extensions are SubjectAlternativeName,
+ BasicConstrains, KeyUsage and ExtendedKeyUsage.
+
+ \code
+ // Generate key
+ QOpcUaKeyPair key;
+ key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024);
+
+ QOpcUaX509CertificateSigningRequest csr;
+
+ QOpcUaX509DistinguishedName dn;
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CommonName, "QtOpcUaViewer");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, "DE");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, "The Qt Company");
+ csr.setSubject(dn);
+
+ QOpcUaX509ExtensionSubjectAlternativeName *san = new QOpcUaX509ExtensionSubjectAlternativeName;
+ san->addData(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "foo.com");
+ san->addData(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "foo.com");
+ san->addData(QOpcUaX509ExtensionSubjectAlternativeName::Type::URI, "urn:foo.com:The%20Qt%20Company:QtOpcUaViewer");
+ san->setCritical(true);
+ csr.addExtension(san);
+
+ QOpcUaX509ExtensionBasicConstraints *bc = new QOpcUaX509ExtensionBasicConstraints;
+ bc->setCa(false);
+ bc->setCritical(true);
+ csr.addExtension(bc);
+
+ QOpcUaX509ExtensionKeyUsage *ku = new QOpcUaX509ExtensionKeyUsage;
+ ku->setCritical(true);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DigitalSignature);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::NonRepudiation);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DataEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CertificateSigning);
+ csr.addExtension(ku);
+
+ QOpcUaX509ExtensionExtendedKeyUsage *eku = new QOpcUaX509ExtensionExtendedKeyUsage;
+ eku->setCritical(true);
+ eku->setKeyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::EmailProtection);
+ csr.addExtension(eku);
+
+ QByteArray csrData = csr.createRequest(key);
+ \endcode
+
+ \sa QOpcUaX509ExtensionSubjectAlternativeName, QOpcUaX509ExtensionBasicConstraints, QOpcUaX509ExtensionKeyUsage, QOpcUaX509ExtensionKeyUsage
+*/
+
+/*!
+ \enum QOpcUaX509CertificateSigningRequest::MessageDigest
+
+ This enum type specifies the message digest to be used.
+
+ \value SHA256
+ Using the SHA256 message digest
+*/
+
+/*!
+ \enum QOpcUaX509CertificateSigningRequest::Encoding
+
+ This enum type specifies the encoding of the generated certificate siging request.
+
+ \value PEM
+ Using PEM encoding
+ \value DER
+ Using DER encoding
+*/
+
+/*!
+ Creates an empty certificate signing request.
+*/
+QOpcUaX509CertificateSigningRequest::QOpcUaX509CertificateSigningRequest()
+ : d_ptr(new QOpcUaX509CertificateSigningRequestPrivate)
+{
+ setEncoding(Encoding::PEM);
+}
+
+/*!
+ Destroys the request and frees all extensions.
+*/
+QOpcUaX509CertificateSigningRequest::~QOpcUaX509CertificateSigningRequest()
+{
+}
+
+/*!
+ Sets the used message digest to \a digest.
+ The default message digest is SHA256.
+*/
+void QOpcUaX509CertificateSigningRequest::setMessageDigest(QOpcUaX509CertificateSigningRequest::MessageDigest digest)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ d->setMessageDigest(digest);
+}
+
+/*!
+ Returns the used message digest.
+*/
+QOpcUaX509CertificateSigningRequest::MessageDigest QOpcUaX509CertificateSigningRequest::messageDigest() const
+{
+ Q_D(const QOpcUaX509CertificateSigningRequest);
+ return d->messageDigest();
+}
+
+/*!
+ Returns the used request encoding.
+*/
+QOpcUaX509CertificateSigningRequest::Encoding QOpcUaX509CertificateSigningRequest::encoding() const
+{
+ Q_D(const QOpcUaX509CertificateSigningRequest);
+ return d->encoding();
+}
+
+/*!
+ Sets the used request encoding to \a encoding.
+ The default request encoding is PEM.
+*/
+void QOpcUaX509CertificateSigningRequest::setEncoding(QOpcUaX509CertificateSigningRequest::Encoding encoding)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ d->setEncoding(encoding);
+}
+
+/*!
+ Adds a certificate extension to the request.
+
+ The ownership of the extension object will be transferred to this class.
+
+ \sa QOpcUaX509ExtensionSubjectAlternativeName, QOpcUaX509ExtensionBasicConstraints, QOpcUaX509ExtensionKeyUsage, QOpcUaX509ExtensionKeyUsage
+*/
+void QOpcUaX509CertificateSigningRequest::addExtension(QOpcUaX509Extension *extension)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ d->addExtension(extension);
+}
+
+/*!
+ Sets the subject for this request.
+ Without a subject it is not possible to generate the request.
+*/
+void QOpcUaX509CertificateSigningRequest::setSubject(const QOpcUaX509DistinguishedName &subject)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ d->setSubject(subject);
+}
+
+/*!
+ Returns the subject of this request.
+*/
+const QOpcUaX509DistinguishedName &QOpcUaX509CertificateSigningRequest::subject() const
+{
+ Q_D(const QOpcUaX509CertificateSigningRequest);
+ return d->subject();
+}
+
+/*!
+ Creates a certificate signing request to be the to a CA for signing.
+ The private key in \a privateKey is used to sign the request.
+ The request data is returned as a byte array in the encoding set by setEncoding().
+*/
+QByteArray QOpcUaX509CertificateSigningRequest::createRequest(const QOpcUaKeyPair &privateKey)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ return d->createRequest(privateKey);
+}
+
+/*!
+ Creates a self-signed certificate from this request for immediate use.
+ The private key in \a privateKey is used to sign the request.
+ A validity in days can be specified in \a validityInDays.
+ The request data is returned as a byte array in the encoding set by setEncoding().
+*/
+QByteArray QOpcUaX509CertificateSigningRequest::createSelfSignedCertificate(const QOpcUaKeyPair &privateKey, int validityInDays)
+{
+ Q_D(QOpcUaX509CertificateSigningRequest);
+ return d->createSelfSignedCertificate(privateKey, validityInDays);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509certificatesigningrequest.h b/src/opcua/x509/qopcuax509certificatesigningrequest.h
new file mode 100644
index 0000000..eb750c0
--- /dev/null
+++ b/src/opcua/x509/qopcuax509certificatesigningrequest.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509CERTIFICATESIGNINGREQUEST_H
+#define QOPCUAX509CERTIFICATESIGNINGREQUEST_H
+
+#include "QtOpcUa/qopcuakeypair.h"
+#include "QtOpcUa/qopcuax509extension.h"
+#include "QtOpcUa/qopcuax509distinguishedname.h"
+#include <QVector>
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtOpcUa/qopcuax509certificatesigningrequest.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509CertificateSigningRequestPrivate;
+
+class Q_OPCUA_EXPORT QOpcUaX509CertificateSigningRequest
+{
+ Q_DECLARE_PRIVATE(QOpcUaX509CertificateSigningRequest)
+
+public:
+ enum class MessageDigest {
+ SHA256
+ };
+ enum class Encoding {
+ PEM,
+ DER
+ };
+
+ QOpcUaX509CertificateSigningRequest();
+ ~QOpcUaX509CertificateSigningRequest();
+
+ void setMessageDigest(MessageDigest digest);
+ MessageDigest messageDigest() const;
+
+ void setEncoding(Encoding encoding);
+ Encoding encoding() const;
+
+ void setSubject(const QOpcUaX509DistinguishedName &subject);
+ const QOpcUaX509DistinguishedName &subject() const;
+
+ void addExtension(QOpcUaX509Extension *extension);
+ QByteArray createRequest(const QOpcUaKeyPair &privateKey);
+ QByteArray createSelfSignedCertificate(const QOpcUaKeyPair &privateKey, int validityInDays = 365);
+
+private:
+ QOpcUaX509CertificateSigningRequestPrivate *d_ptr = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509CERTIFICATESIGNINGREQUEST_H
diff --git a/src/opcua/x509/qopcuax509certificatesigningrequest_openssl.cpp b/src/opcua/x509/qopcuax509certificatesigningrequest_openssl.cpp
new file mode 100644
index 0000000..4ec4421
--- /dev/null
+++ b/src/opcua/x509/qopcuax509certificatesigningrequest_openssl.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509certificatesigningrequest.h"
+#include "openssl_symbols_p.h"
+#include "qopcuakeypair_p.h"
+#include "qopcuax509utils_p.h"
+#include "qopcuax509distinguishedname.h"
+#include "qopcuax509extensionsubjectalternativename.h"
+#include "qopcuax509certificatesigningrequest_p.h"
+#include <QOpcUaX509ExtensionBasicConstraints>
+#include <QOpcUaX509ExtensionKeyUsage>
+#include <QOpcUaX509ExtensionExtendedKeyUsage>
+
+
+QT_BEGIN_NAMESPACE
+
+QOpcUaX509CertificateSigningRequestPrivate::QOpcUaX509CertificateSigningRequestPrivate()
+{
+
+}
+
+QOpcUaX509CertificateSigningRequestPrivate::~QOpcUaX509CertificateSigningRequestPrivate()
+{
+ qDeleteAll(m_extensions);
+}
+
+void QOpcUaX509CertificateSigningRequestPrivate::setMessageDigest(QOpcUaX509CertificateSigningRequest::MessageDigest digest)
+{
+ m_messageDigest = digest;
+}
+
+QOpcUaX509CertificateSigningRequest::MessageDigest QOpcUaX509CertificateSigningRequestPrivate::messageDigest() const
+{
+ return m_messageDigest;
+}
+
+void QOpcUaX509CertificateSigningRequestPrivate::addExtension(QOpcUaX509Extension *extension)
+{
+ m_extensions.append(extension);
+}
+
+void QOpcUaX509CertificateSigningRequestPrivate::setSubject(const QOpcUaX509DistinguishedName &subject)
+{
+ m_subject = subject;
+}
+
+QOpcUaX509CertificateSigningRequest::Encoding QOpcUaX509CertificateSigningRequestPrivate::encoding() const
+{
+ return m_encoding;
+}
+
+void QOpcUaX509CertificateSigningRequestPrivate::setEncoding(QOpcUaX509CertificateSigningRequest::Encoding encoding)
+{
+ m_encoding = encoding;
+}
+
+const QOpcUaX509DistinguishedName &QOpcUaX509CertificateSigningRequestPrivate::subject() const
+{
+ return m_subject;
+}
+
+static X509_EXTENSION *createExtension(QOpcUaX509Extension *extension)
+{
+ X509_EXTENSION *ex = nullptr;
+
+ if (const auto *san = dynamic_cast<const QOpcUaX509ExtensionSubjectAlternativeName *>(extension)) {
+ QStringList data;
+
+ for (const auto &pair : qAsConst(san->entries())) {
+ QString prefix;
+ if (pair.first == QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS)
+ prefix = QLatin1String("DNS:");
+ else if (pair.first == QOpcUaX509ExtensionSubjectAlternativeName::Type::Email)
+ prefix = QLatin1String("EMAIL:");
+ else if (pair.first == QOpcUaX509ExtensionSubjectAlternativeName::Type::IP)
+ prefix = QLatin1String("IP:");
+ else if (pair.first == QOpcUaX509ExtensionSubjectAlternativeName::Type::URI)
+ prefix = QLatin1String("URI:");
+ else {
+ qCWarning(lcSsl()) << "Invalid SubjectAlternativeName type";
+ return nullptr;
+ }
+
+ if (pair.second.isEmpty() || pair.second.contains(',')) {
+ qCWarning(lcSsl()) << "Invalid SubjectAlternativeName value";
+ return nullptr;
+ }
+
+ data.append(prefix + pair.second);
+ }
+
+ ex = q_X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, data.join(QLatin1Char(',')).toUtf8().data());
+ if (!ex) {
+ qCWarning(lcSsl()) << "Failed to create X509 extension" << data;
+ return nullptr;
+ }
+ q_X509_EXTENSION_set_critical(ex, san->critical() ? 1 : 0);
+ } else if (const auto *bc = dynamic_cast<const QOpcUaX509ExtensionBasicConstraints *>(extension)) {
+ QString data = QLatin1String("CA:") + QLatin1String(bc->ca() ? "true" : "false");
+ if (bc->ca() && bc->pathLength() >= 0)
+ data.append(QLatin1String(",pathlen:") + QString::number(bc->pathLength()));
+
+ ex = q_X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, data.toUtf8().data());
+ if (!ex) {
+ qCWarning(lcSsl()) << "Failed to create X509 extension" << data;
+ return nullptr;
+ }
+ q_X509_EXTENSION_set_critical(ex, bc->critical() ? 1 : 0);
+ } else if (const auto *ku = dynamic_cast<const QOpcUaX509ExtensionKeyUsage *>(extension)) {
+ QStringList data;
+
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DigitalSignature))
+ data.append(QLatin1String("Digital Signature"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::NonRepudiation))
+ data.append(QLatin1String("Non Repudiation"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyEncipherment))
+ data.append(QLatin1String("Key Encipherment"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DataEncipherment))
+ data.append(QLatin1String("Data Encipherment"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyAgreement))
+ data.append(QLatin1String("Key Agreement"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CertificateSigning))
+ data.append(QLatin1String("Certificate Sign"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CrlSigning))
+ data.append(QLatin1String("CRL Sign"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::EnciptherOnly))
+ data.append(QLatin1String("Encipther Only"));
+ if (ku->keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DecipherOnly))
+ data.append(QLatin1String("Decipher Only"));
+
+ ex = q_X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, data.join(QLatin1Char(',')).toUtf8().data());
+ if (!ex) {
+ qCWarning(lcSsl()) << "Failed to create X509 extension" << data;
+ return nullptr;
+ }
+ q_X509_EXTENSION_set_critical(ex, ku->critical() ? 1 : 0);
+ } else if (const auto *eku = dynamic_cast<const QOpcUaX509ExtensionExtendedKeyUsage *>(extension)) {
+ QStringList data;
+
+ if (eku->keyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::TlsWebServerAuthentication))
+ data.append(QLatin1String("SSL Server"));
+ if (eku->keyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::TlsWebClientAuthentication))
+ data.append(QLatin1String("SSL Client"));
+ if (eku->keyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::SignExecutableCode))
+ data.append(QLatin1String("Object Signing"));
+ if (eku->keyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::EmailProtection))
+ data.append(QLatin1String("S/MIME"));
+
+ // NID_ext_key_usage
+ ex = q_X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, data.join(QLatin1Char(',')).toUtf8().data());
+ if (!ex) {
+ qCWarning(lcSsl()) << "Failed to create X509 extension" << data;
+ return nullptr;
+ }
+ q_X509_EXTENSION_set_critical(ex, eku->critical() ? 1 : 0);
+ } else {
+ qCWarning(lcSsl) << "Unknown X509 extension";
+ return nullptr;
+ }
+ return ex;
+}
+
+static bool setSubjectName(X509_NAME *subject, const QOpcUaX509DistinguishedName &dn) {
+ QVector<QOpcUaX509DistinguishedName::Type> entries = {
+ QOpcUaX509DistinguishedName::Type::CommonName,
+ QOpcUaX509DistinguishedName::Type::CountryName,
+ QOpcUaX509DistinguishedName::Type::LocalityName,
+ QOpcUaX509DistinguishedName::Type::StateOrProvinceName,
+ QOpcUaX509DistinguishedName::Type::OrganizationName,
+ };
+
+ for (const auto &type : entries) {
+ const auto value = dn.entry(type);
+ if (value.isEmpty())
+ continue;
+
+ ASN1_OBJECT *obj = q_OBJ_txt2obj(QOpcUaX509DistinguishedName::typeToOid(type).toLatin1().constData(), 1 /* no names allowed */);
+ if (!obj) {
+ qCWarning(lcSsl()) << "Invalid distinguishedName type";
+ return false;
+ }
+
+ if (!q_X509_NAME_add_entry_by_OBJ(subject, obj, MBSTRING_UTF8, (const unsigned char*)(value.toUtf8().constData()), -1, -1, 0)) {
+ qCWarning(lcSsl) << "Failed to set CSR enrty:" << getOpenSslError();
+ return false;
+ }
+ }
+ return true;
+}
+
+// Creates the request and returns a PEM encoded byte array
+QByteArray QOpcUaX509CertificateSigningRequestPrivate::createRequest(const QOpcUaKeyPair &privateKey)
+{
+ if (!privateKey.hasPrivateKey()) {
+ qCWarning(lcSsl) << "Key has no private key";
+ return QByteArray();
+ }
+
+ auto keyData = privateKey.d_func()->m_keyData;
+
+ X509_REQ *req = q_X509_REQ_new();
+ if (!req) {
+ qCWarning(lcSsl) << "Failed to create CSR:" << getOpenSslError();
+ return QByteArray();
+ }
+ Deleter<X509_REQ> reqDeleter(req, q_X509_REQ_free);
+
+ if (!q_X509_REQ_set_version(req, 0 /* version */)) {
+ qCWarning(lcSsl) << "Failed to set CSR version:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ X509_NAME *subj = q_X509_REQ_get_subject_name(req);
+ if (!subj) {
+ qCWarning(lcSsl) << "Invalid subject pointer";
+ return QByteArray();
+ }
+
+ if (!setSubjectName(subj, m_subject)) {
+ qCWarning(lcSsl) << "Failed to set subject";
+ return QByteArray();
+ }
+
+ if (m_extensions.size() > 0) {
+ auto exts = q_sk_X509_EXTENSION_new_null();
+
+ for (auto extension : m_extensions) {
+ auto ex = createExtension(extension);
+ if (ex)
+ q_sk_X509_EXTENSION_push(exts, ex); // returns void
+ }
+ if (q_X509_REQ_add_extensions(req, (STACK_OF(X509_EXTENSION) *)exts) == 0) {
+ qCWarning(lcSsl) << "Failed to add X509 extensions";
+ return QByteArray();
+ }
+ q_sk_X509_EXTENSION_pop_free(exts, (void(*)(void*))q_X509_EXTENSION_free); // frees the whole stack, returns void
+ } // end of for loop
+
+ if (!q_X509_REQ_set_pubkey(req, keyData)) {
+ qCWarning(lcSsl) << "Failed to set public key:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ const EVP_MD *digest = nullptr;
+ if (m_messageDigest == QOpcUaX509CertificateSigningRequest::MessageDigest::SHA256)
+ digest = q_EVP_sha256();
+
+ if (!digest) {
+ qCWarning(lcSsl) << "Invalid message digest";
+ return QByteArray();
+ }
+
+ if (q_X509_REQ_sign(req, keyData, digest) <= 0) {
+ qCWarning(lcSsl) << "Failed to sign CSR:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio) {
+ qCWarning(lcSsl) << "Failed to allocate a buffer:" << getOpenSslError();
+ return QByteArray();
+ }
+ Deleter<BIO> bioDeleter(bio, q_BIO_free_all);
+
+ int result = 0;
+
+ if (m_encoding == QOpcUaX509CertificateSigningRequest::Encoding::PEM) {
+ // Some CAs require to use q_PEM_write_bio_X509_REW_NEW
+ result = q_PEM_write_bio_X509_REQ(bio, req);
+ } else if (m_encoding == QOpcUaX509CertificateSigningRequest::Encoding::DER) {
+ result = q_i2d_X509_REQ_bio(bio, req);
+ }
+ if (result != 1) {
+ qCWarning(lcSsl) << "Failed to export certificate request";
+ return QByteArray();
+ }
+
+ char *buf;
+ int length = q_BIO_get_mem_data(bio, &buf);
+ QByteArray data(buf, length);
+ return data;
+}
+
+QByteArray QOpcUaX509CertificateSigningRequestPrivate::createSelfSignedCertificate(const QOpcUaKeyPair &privateKey, int validityInDays)
+{
+ if (!privateKey.hasPrivateKey()) {
+ qCWarning(lcSsl) << "Key has no private key";
+ return QByteArray();
+ }
+
+ auto keyData = privateKey.d_func()->m_keyData;
+
+ X509 *x509 = q_X509_new();
+ if (!x509)
+ return QByteArray();
+
+ Deleter<X509> x509Deleter(x509, q_X509_free);
+
+ if (!q_X509_set_version(x509, 2 /* version */)) {
+ qCWarning(lcSsl) << "Failed to set version";
+ return QByteArray();
+ }
+ q_X509_gmtime_adj(q_X509_getm_notBefore(x509), 0); // current time
+ q_X509_gmtime_adj(q_X509_getm_notAfter(x509), (long)60 * 60 * 24 * validityInDays);
+
+ if (!q_X509_set_pubkey(x509, keyData)) {
+ qCWarning(lcSsl) << "Failed to set public key:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ X509_NAME *subj = q_X509_get_subject_name(x509);
+ if (!subj) {
+ qCWarning(lcSsl) << "Invalid subject pointer";
+ return QByteArray();
+ }
+
+ if (!setSubjectName(subj, m_subject)) {
+ qCWarning(lcSsl) << "Failed to set subject";
+ return QByteArray();
+ }
+
+ X509_NAME *issuer = q_X509_get_issuer_name(x509);
+ if (!issuer) {
+ qCWarning(lcSsl) << "Invalid issuer pointer";
+ return QByteArray();
+ }
+
+ if (!setSubjectName(issuer, m_subject)) {
+ qCWarning(lcSsl) << "Failed to set issuer";
+ return QByteArray();
+ }
+
+ for (auto extension : m_extensions) {
+ auto ex = createExtension(extension);
+ if (ex) {
+ if (!q_X509_add_ext(x509, ex, -1)) {
+ qCWarning(lcSsl) << "Failed to add extension";
+ return QByteArray();
+ }
+ q_X509_EXTENSION_free(ex);
+ } else {
+ qCWarning(lcSsl) << "Invalid extension";
+ return QByteArray();
+ }
+ }
+
+ // Hash of public key
+ unsigned char publicKeyHash[SHA_DIGEST_LENGTH];
+ unsigned int len;
+ if (!q_X509_pubkey_digest(x509, q_EVP_sha1(), publicKeyHash, &len)) {
+ qCWarning(lcSsl) << "Failed to hash public key";
+ return QByteArray();
+ }
+
+ // Set subject key identifier
+ ASN1_OCTET_STRING *subjectKeyIdentifier = q_ASN1_OCTET_STRING_new();
+ if (!subjectKeyIdentifier) {
+ qCWarning(lcSsl) << "Failed to allocate ASN1 string";
+ return QByteArray();
+ }
+ Deleter<ASN1_OCTET_STRING> subjectKeyIdentifierDeleter(subjectKeyIdentifier, q_ASN1_OCTET_STRING_free);
+
+ if (!q_ASN1_OCTET_STRING_set(subjectKeyIdentifier, publicKeyHash, SHA_DIGEST_LENGTH)) {
+ qCWarning(lcSsl) << "Failed set ASN1 string";
+ return QByteArray();
+ }
+
+ if (!q_X509_add1_ext_i2d(x509, NID_subject_key_identifier, subjectKeyIdentifier, 0, X509V3_ADD_DEFAULT)) {
+ qCWarning(lcSsl) << "Failed to add subject key identifier extension";
+ return QByteArray();
+ }
+
+ // Set serial number
+ unsigned char subjHash[SHA_DIGEST_LENGTH];
+ unsigned char finalHash[SHA_DIGEST_LENGTH];
+
+ if (!q_X509_NAME_digest(subj, q_EVP_sha1(), subjHash, &len)) {
+ qCWarning(lcSsl) << "failed";
+ return QByteArray();
+ }
+ for (unsigned int i = 0; i < len; i++)
+ finalHash[i] = subjHash[i] ^ publicKeyHash[i];
+
+ ASN1_INTEGER *serial_num = q_ASN1_INTEGER_new();
+ if (!serial_num) {
+ qCWarning(lcSsl) << "Failed to allocate ASN1 integer";
+ return QByteArray();
+ }
+ Deleter<ASN1_OCTET_STRING> serial_numDeleter(serial_num, q_ASN1_INTEGER_free);
+
+ if (!q_ASN1_OCTET_STRING_set(serial_num, finalHash, len)) {
+ qCWarning(lcSsl) << "Failed to set ASN1 integer";
+ return QByteArray();
+ }
+ if (!q_X509_set_serialNumber(x509, serial_num)) {
+ qCWarning(lcSsl) << "Failed to set serial number";
+ return QByteArray();
+ }
+
+ // Set authority key identifier
+ AUTHORITY_KEYID *akid = q_AUTHORITY_KEYID_new();
+ if (!akid) {
+ qCWarning(lcSsl) << "Failed to allocate authority key id";
+ return QByteArray();
+ }
+ Deleter<AUTHORITY_KEYID> akidDeleter(akid, q_AUTHORITY_KEYID_free);
+
+ akid->issuer = q_GENERAL_NAMES_new();
+ if (!akid->issuer) {
+ qCWarning(lcSsl) << "Failed to set authority key id";
+ return QByteArray();
+ }
+
+ GENERAL_NAME *generalName = q_GENERAL_NAME_new();
+ if (!generalName) {
+ qCWarning(lcSsl) << "Failed to set authority key id";
+ return QByteArray();
+ }
+ generalName->type = GEN_DIRNAME;
+ generalName->d.directoryName = q_X509_NAME_dup(q_X509_get_subject_name(x509));
+
+#if QT_CONFIG(opensslv11)
+ q_sk_GENERAL_NAME_push((OPENSSL_STACK*)akid->issuer, generalName);
+#else
+ q_sk_GENERAL_NAME_push(akid->issuer, generalName);
+#endif
+ akid->keyid = (ASN1_OCTET_STRING*)q_X509_get_ext_d2i(x509, NID_subject_key_identifier, NULL, NULL);
+ akid->serial = q_ASN1_INTEGER_dup(q_X509_get_serialNumber(x509));
+
+ if (!q_X509_add1_ext_i2d(x509, NID_authority_key_identifier, akid, 0, X509V3_ADD_DEFAULT)) {
+ qCWarning(lcSsl) << "Failed to add authority key id extension";
+ return QByteArray();
+ }
+
+ const EVP_MD *digest = nullptr;
+ if (m_messageDigest == QOpcUaX509CertificateSigningRequest::MessageDigest::SHA256)
+ digest = q_EVP_sha256();
+
+ if (!digest) {
+ qCWarning(lcSsl) << "Invalid message digest";
+ return QByteArray();
+ }
+
+ if (q_X509_sign(x509, keyData, digest) <= 0) {
+ qCWarning(lcSsl) << "Failed to sign certificate:" << getOpenSslError();
+ return QByteArray();
+ }
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio) {
+ qCWarning(lcSsl) << "Failed to allocate a buffer:" << getOpenSslError();
+ return QByteArray();
+ }
+ Deleter<BIO> bioDeleter(bio, q_BIO_free_all);
+
+ int result = 0;
+
+ if (m_encoding == QOpcUaX509CertificateSigningRequest::Encoding::PEM) {
+ result = q_PEM_write_bio_X509(bio, x509);
+ } else if (m_encoding == QOpcUaX509CertificateSigningRequest::Encoding::DER) {
+ result = q_i2d_X509_bio(bio, x509);
+ }
+ if (result != 1) {
+ qCWarning(lcSsl) << "Failed to export certificate";
+ return QByteArray();
+ }
+
+ char *buf;
+ int length = q_BIO_get_mem_data(bio, &buf);
+ QByteArray data(buf, length);
+ return data;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/opcua/x509/qopcuax509certificatesigningrequest_p.h b/src/opcua/x509/qopcuax509certificatesigningrequest_p.h
new file mode 100644
index 0000000..6406d46
--- /dev/null
+++ b/src/opcua/x509/qopcuax509certificatesigningrequest_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOPCUAX509CERTIFICATESIGNINGREQUESTPRIVATE_H
+#define QOPCUAX509CERTIFICATESIGNINGREQUESTPRIVATE_H
+
+#include "QtOpcUa/qopcuax509extension.h"
+#include "QtOpcUa/qopcuax509distinguishedname.h"
+#include "QtOpcUa/qopcuakeypair.h"
+#include <QVector>
+#include <QtOpcUa/qopcuaglobal.h>
+#include "qopcuax509certificatesigningrequest.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509CertificateSigningRequestPrivate
+{
+public:
+ QOpcUaX509CertificateSigningRequestPrivate();
+ ~QOpcUaX509CertificateSigningRequestPrivate();
+
+ void setMessageDigest(QOpcUaX509CertificateSigningRequest::MessageDigest);
+ QOpcUaX509CertificateSigningRequest::MessageDigest messageDigest() const;
+
+ QOpcUaX509CertificateSigningRequest::Encoding encoding() const;
+ void setEncoding(QOpcUaX509CertificateSigningRequest::Encoding encoding);
+
+ const QOpcUaX509DistinguishedName& subject() const;
+ void setSubject(const QOpcUaX509DistinguishedName &subject);
+
+ void addExtension(QOpcUaX509Extension *extension);
+ QByteArray createRequest(const QOpcUaKeyPair &privateKey);
+ QByteArray createSelfSignedCertificate(const QOpcUaKeyPair &privateKey, int validityInDays);
+
+private:
+ QVector<QOpcUaX509Extension *> m_extensions;
+ QOpcUaX509CertificateSigningRequest::MessageDigest m_messageDigest = QOpcUaX509CertificateSigningRequest::MessageDigest::SHA256;
+ QOpcUaX509DistinguishedName m_subject;
+ QOpcUaX509CertificateSigningRequest::Encoding m_encoding = QOpcUaX509CertificateSigningRequest::Encoding::PEM;
+
+ Q_DECLARE_PUBLIC(QOpcUaX509CertificateSigningRequest)
+ QOpcUaX509CertificateSigningRequest *q_ptr = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509CERTIFICATESIGNINGREQUESTPRIVATE_H
diff --git a/src/opcua/x509/qopcuax509distinguishedname.cpp b/src/opcua/x509/qopcuax509distinguishedname.cpp
new file mode 100644
index 0000000..a4c39b0
--- /dev/null
+++ b/src/opcua/x509/qopcuax509distinguishedname.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509distinguishedname.h"
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509DistinguishedName
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Information about a distinguished name item
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ \code
+ QOpcUaX509DistinguishedName dn;
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CommonName, "QtOpcUaViewer");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, "DE");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, "The Qt Company");
+ \endcode
+
+ \sa QOpcUaX509CertificateSigningRequest
+*/
+
+/*!
+ \enum QOpcUaX509DistinguishedName::Type
+
+ Enum with entry types for X509DistinguishedName.
+
+ \value CommonName
+ Common name
+ \value CountryName
+ Country name
+ \value LocalityName
+ Locality name
+ \value StateOrProvinceName
+ State or provice name
+ \value OrganizationName
+ Organization name
+*/
+
+class QOpcUaX509DistinguishedNameData : public QSharedData
+{
+public:
+ QMap<QOpcUaX509DistinguishedName::Type, QString> entries;
+};
+
+/*!
+ Constructs an empty X509DistinguishedName.
+*/
+QOpcUaX509DistinguishedName::QOpcUaX509DistinguishedName()
+ : data(new QOpcUaX509DistinguishedNameData)
+{
+}
+
+/*!
+ Destructs a X509DistinguishedName.
+*/
+QOpcUaX509DistinguishedName::~QOpcUaX509DistinguishedName()
+{
+}
+
+/*!
+ Constructs a X509DistinguishedName from \a rhs.
+*/
+QOpcUaX509DistinguishedName::QOpcUaX509DistinguishedName(const QOpcUaX509DistinguishedName &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Sets the values from \a rhs in this X509DistinguishedName.
+*/
+QOpcUaX509DistinguishedName &QOpcUaX509DistinguishedName::operator=(const QOpcUaX509DistinguishedName &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Returns \c true if this X509DistinguishedName has the same value as \a rhs.
+*/
+bool QOpcUaX509DistinguishedName::operator==(const QOpcUaX509DistinguishedName &rhs) const
+{
+ return data->entries == rhs.data->entries;
+}
+
+/*!
+ Sets the entry of \a type to \a value.
+ Already existing types will be overwritten.
+*/
+void QOpcUaX509DistinguishedName::setEntry(QOpcUaX509DistinguishedName::Type type, const QString &value)
+{
+ data->entries.insert(type, value);
+}
+
+/*!
+ Returns the object id string for \a type.
+*/
+QString QOpcUaX509DistinguishedName::typeToOid(QOpcUaX509DistinguishedName::Type type)
+{
+ switch (type) {
+ case Type::CommonName:
+ return QLatin1String("2.5.4.3");
+ case Type::CountryName:
+ return QLatin1String("2.5.4.6");
+ case Type::LocalityName:
+ return QLatin1String("2.5.4.7");
+ case Type::StateOrProvinceName:
+ return QLatin1String("2.5.4.8");
+ case Type::OrganizationName:
+ return QLatin1String("2.5.4.10");
+ default:
+ return QString();
+ }
+}
+
+/*!
+ Returns value for a \a type.
+*/
+QString QOpcUaX509DistinguishedName::entry(QOpcUaX509DistinguishedName::Type type) const
+{
+ return data->entries.value(type);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509distinguishedname.h b/src/opcua/x509/qopcuax509distinguishedname.h
new file mode 100644
index 0000000..f7df9f2
--- /dev/null
+++ b/src/opcua/x509/qopcuax509distinguishedname.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUADISTINGUISHEDNAME_H
+#define QOPCUADISTINGUISHEDNAME_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509DistinguishedNameData;
+class Q_OPCUA_EXPORT QOpcUaX509DistinguishedName
+{
+public:
+ enum class Type {
+ CommonName, // 2.5.4.3
+ CountryName, // 2.5.4.6
+ LocalityName, // 2.5.4.7
+ StateOrProvinceName, // 2.5.4.8
+ OrganizationName, // 2.5.4.10
+ };
+
+ QOpcUaX509DistinguishedName();
+ QOpcUaX509DistinguishedName(const QOpcUaX509DistinguishedName &);
+ QOpcUaX509DistinguishedName &operator=(const QOpcUaX509DistinguishedName &);
+ bool operator==(const QOpcUaX509DistinguishedName &rhs) const;
+ ~QOpcUaX509DistinguishedName();
+ void setEntry(Type type, const QString &value);
+ QString entry(Type type) const;
+ static QString typeToOid(Type type);
+
+private:
+ QSharedDataPointer<QOpcUaX509DistinguishedNameData> data;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUADISTINGUISHEDNAME_H
diff --git a/src/opcua/x509/qopcuax509extension.cpp b/src/opcua/x509/qopcuax509extension.cpp
new file mode 100644
index 0000000..566a8de
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extension.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509extension.h"
+#include "qopcuax509extension_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509Extension
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Base class for all X509 extensions
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+
+ \sa QOpcUaX509ExtensionSubjectAlternativeName, QOpcUaX509ExtensionBasicConstraints, QOpcUaX509ExtensionKeyUsage, QOpcUaX509ExtensionKeyUsage
+*/
+
+/*!
+ Constructs a default X509Extension.
+*/
+QOpcUaX509Extension::QOpcUaX509Extension()
+ : data(new QOpcUaX509ExtensionData)
+{
+}
+
+/*!
+ Constructs a X509Extension from \a rhs.
+*/
+QOpcUaX509Extension::QOpcUaX509Extension(const QOpcUaX509Extension &rhs)
+ : data(rhs.data)
+{
+}
+
+/*!
+ Constructs a X509Extension from \a rhs.
+*/
+QOpcUaX509Extension::QOpcUaX509Extension(QSharedDataPointer<QOpcUaX509ExtensionData> rhs)
+ : data(rhs)
+{
+}
+
+/*!
+ Returns \c true if this X509Extension has the same value as \a rhs.
+*/
+bool QOpcUaX509Extension::operator==(const QOpcUaX509Extension &rhs) const
+{
+ return data->critical == rhs.data->critical;
+}
+
+/*!
+ Sets the values from \a rhs in this X509Extension.
+*/
+QOpcUaX509Extension &QOpcUaX509Extension::operator=(const QOpcUaX509Extension &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Destructs a X509Extension.
+*/
+QOpcUaX509Extension::~QOpcUaX509Extension()
+{
+}
+
+/*!
+ Sets the critical flag to \a critical.
+*/
+void QOpcUaX509Extension::setCritical(bool critical)
+{
+ data->critical = critical;
+}
+
+/*!
+ Return the state of the critical flag.
+*/
+bool QOpcUaX509Extension::critical() const
+{
+ return data->critical;
+}
+
+QOpcUaX509Extension::QOpcUaX509Extension(QOpcUaX509ExtensionData *other)
+{
+ data = other;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509extension.h b/src/opcua/x509/qopcuax509extension.h
new file mode 100644
index 0000000..6e502df
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extension.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSION_H
+#define QOPCUAX509EXTENSION_H
+
+#include <QtOpcUa/qopcuaglobal.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509ExtensionData;
+class Q_OPCUA_EXPORT QOpcUaX509Extension
+{
+public:
+ QOpcUaX509Extension();
+ QOpcUaX509Extension(const QOpcUaX509Extension &);
+ QOpcUaX509Extension &operator=(const QOpcUaX509Extension &);
+ bool operator==(const QOpcUaX509Extension &rhs) const;
+ virtual ~QOpcUaX509Extension();
+ void setCritical(bool critical);
+ bool critical() const;
+
+protected:
+ QOpcUaX509Extension(QOpcUaX509ExtensionData*);
+ QOpcUaX509Extension(QSharedDataPointer<QOpcUaX509ExtensionData>);
+ QSharedDataPointer<QOpcUaX509ExtensionData> data;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509EXTENSION_H
diff --git a/src/opcua/x509/qopcuax509extension_p.h b/src/opcua/x509/qopcuax509extension_p.h
new file mode 100644
index 0000000..e945ffd
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extension_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSION_P_H
+#define QOPCUAX509EXTENSION_P_H
+
+#include <QtCore/qshareddata.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509ExtensionData : public QSharedData
+{
+public:
+ bool critical = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509EXTENSION_P_H
diff --git a/src/opcua/x509/qopcuax509extensionbasicconstraints.cpp b/src/opcua/x509/qopcuax509extensionbasicconstraints.cpp
new file mode 100644
index 0000000..366288c
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionbasicconstraints.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509extensionbasicconstraints.h"
+#include "qopcuax509extension_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509ExtensionBasicConstraints
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Class for X509 basic constraints
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+
+class QOpcUaX509ExtensionBasicConstraintsData : public QOpcUaX509ExtensionData
+{
+public:
+ bool ca = false;
+ int pathLength = -1;
+};
+
+/*!
+ Constructs a default X509ExtensionBasicConstraints.
+*/
+QOpcUaX509ExtensionBasicConstraints::QOpcUaX509ExtensionBasicConstraints()
+ : QOpcUaX509Extension(new QOpcUaX509ExtensionBasicConstraintsData)
+{
+}
+
+/*!
+ Constructs a X509ExtensionBasicConstraints from \a rhs.
+*/
+QOpcUaX509ExtensionBasicConstraints::QOpcUaX509ExtensionBasicConstraints(const QOpcUaX509ExtensionBasicConstraints &rhs)
+ : QOpcUaX509Extension(rhs.data)
+{
+}
+
+/*!
+ Returns \c true if this X509ExtensionBasicConstraints has the same value as \a rhs.
+*/
+bool QOpcUaX509ExtensionBasicConstraints::operator==(const QOpcUaX509ExtensionBasicConstraints &rhs) const
+{
+ return data->critical == rhs.data->critical;
+}
+
+/*!
+ Destructs a X509ExtensionBasicConstraints.
+*/
+QOpcUaX509ExtensionBasicConstraints::~QOpcUaX509ExtensionBasicConstraints()
+{
+}
+
+/*!
+ Sets the values from \a rhs in this X509ExtensionBasicConstraints.
+*/
+QOpcUaX509ExtensionBasicConstraints &QOpcUaX509ExtensionBasicConstraints::operator=(const QOpcUaX509ExtensionBasicConstraints &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Sets the flag, if the certificate's subject is a CA to \a value.
+*/
+void QOpcUaX509ExtensionBasicConstraints::setCa(bool value)
+{
+ QOpcUaX509ExtensionBasicConstraintsData *d = static_cast<QOpcUaX509ExtensionBasicConstraintsData*>(data.data());
+ d->ca = value;
+}
+
+/*!
+ Returns the flag, if the certificate's subject is a CA.
+*/
+bool QOpcUaX509ExtensionBasicConstraints::ca() const
+{
+ const QOpcUaX509ExtensionBasicConstraintsData *d = static_cast<const QOpcUaX509ExtensionBasicConstraintsData*>(data.data());
+ return d->ca;
+}
+
+/*!
+ Sets the validation path length of the certificate to \a length.
+*/
+void QOpcUaX509ExtensionBasicConstraints::setPathLength(int length)
+{
+ QOpcUaX509ExtensionBasicConstraintsData *d = static_cast<QOpcUaX509ExtensionBasicConstraintsData*>(data.data());
+ d->pathLength = length;
+}
+
+/*!
+ Returns the validation path length of the certificate.
+*/
+int QOpcUaX509ExtensionBasicConstraints::pathLength() const
+{
+ const QOpcUaX509ExtensionBasicConstraintsData *d = static_cast<const QOpcUaX509ExtensionBasicConstraintsData*>(data.data());
+ return d->pathLength;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509extensionbasicconstraints.h b/src/opcua/x509/qopcuax509extensionbasicconstraints.h
new file mode 100644
index 0000000..eccbcd8
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionbasicconstraints.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSIONBASICCONSTRAINTS_H
+#define QOPCUAX509EXTENSIONBASICCONSTRAINTS_H
+
+#include "QtOpcUa/qopcuax509extension.h"
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpcUaX509ExtensionBasicConstraintsData;
+
+class Q_OPCUA_EXPORT QOpcUaX509ExtensionBasicConstraints : public QOpcUaX509Extension
+{
+public:
+ QOpcUaX509ExtensionBasicConstraints();
+ QOpcUaX509ExtensionBasicConstraints(const QOpcUaX509ExtensionBasicConstraints &);
+ QOpcUaX509ExtensionBasicConstraints &operator=(const QOpcUaX509ExtensionBasicConstraints &);
+ bool operator==(const QOpcUaX509ExtensionBasicConstraints &rhs) const;
+ ~QOpcUaX509ExtensionBasicConstraints();
+
+ void setCa(bool value);
+ bool ca() const;
+
+ void setPathLength(int length);
+ int pathLength() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509EXTENSIONBASICCONSTRAINTS_H
diff --git a/src/opcua/x509/qopcuax509extensionextendedkeyusage.cpp b/src/opcua/x509/qopcuax509extensionextendedkeyusage.cpp
new file mode 100644
index 0000000..cbe85d4
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionextendedkeyusage.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509extensionextendedkeyusage.h"
+#include "qopcuax509extension_p.h"
+#include <QSet>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509ExtensionExtendedKeyUsage
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Class for X509 extended key usage
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+
+/*!
+ \enum QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage
+
+ Enum with entry types for X509ExtensionExtendedKeyUsage.
+
+ \value TlsWebServerAuthentication
+ Permits TLS webserver Authentication
+ \value TlsWebClientAuthentication
+ Permits TLS client authentication
+ \value SignExecutableCode
+ Permits signature of executable code
+ \value EmailProtection
+ Permits signing emails
+*/
+
+class QOpcUaX509ExtensionExtendedKeyUsageData : public QOpcUaX509ExtensionData
+{
+public:
+ QSet<QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage> keyUsage;
+};
+
+/*!
+ Constructs a X509ExtensionExtendedKeyUsage.
+*/
+QOpcUaX509ExtensionExtendedKeyUsage::QOpcUaX509ExtensionExtendedKeyUsage()
+ : QOpcUaX509Extension(new QOpcUaX509ExtensionExtendedKeyUsageData)
+{
+
+}
+
+/*!
+ Constructs a X509ExtensionExtendedKeyUsage from \a rhs.
+*/
+QOpcUaX509ExtensionExtendedKeyUsage::QOpcUaX509ExtensionExtendedKeyUsage(const QOpcUaX509ExtensionExtendedKeyUsage &rhs)
+ : QOpcUaX509Extension(rhs.data)
+{
+}
+
+/*!
+ Returns \c true if this X509ExtensionExtendedKeyUsage has the same value as \a rhs.
+*/
+bool QOpcUaX509ExtensionExtendedKeyUsage::operator==(const QOpcUaX509ExtensionExtendedKeyUsage &rhs) const
+{
+ return data->critical == rhs.data->critical;
+}
+
+/*!
+ Destructs a X509ExtensionExtendedKeyUsage.
+*/
+QOpcUaX509ExtensionExtendedKeyUsage::~QOpcUaX509ExtensionExtendedKeyUsage()
+{
+}
+
+/*!
+ Sets the values from \a rhs in this X509ExtensionExtendedKeyUsage.
+*/
+QOpcUaX509ExtensionExtendedKeyUsage &QOpcUaX509ExtensionExtendedKeyUsage::operator=(const QOpcUaX509ExtensionExtendedKeyUsage &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Sets the key usage flag in \a keyUsage to \a enable.
+*/
+void QOpcUaX509ExtensionExtendedKeyUsage::setKeyUsage(KeyUsage keyUsage, bool enable)
+{
+ QOpcUaX509ExtensionExtendedKeyUsageData *d = static_cast<QOpcUaX509ExtensionExtendedKeyUsageData*>(data.data());
+
+ if (enable)
+ d->keyUsage.insert(keyUsage);
+ else
+ d->keyUsage.remove(keyUsage);
+}
+
+/*!
+ Returns the key usage flag for \a keyUsage.
+*/
+bool QOpcUaX509ExtensionExtendedKeyUsage::keyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage keyUsage) const
+{
+ const QOpcUaX509ExtensionExtendedKeyUsageData *d = static_cast<const QOpcUaX509ExtensionExtendedKeyUsageData*>(data.data());
+ return d->keyUsage.contains(keyUsage);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509extensionextendedkeyusage.h b/src/opcua/x509/qopcuax509extensionextendedkeyusage.h
new file mode 100644
index 0000000..7fc7ce2
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionextendedkeyusage.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSIONEXTENDEDKEYUSAGE_H
+#define QOPCUAX509EXTENSIONEXTENDEDKEYUSAGE_H
+
+#include "QtOpcUa/qopcuax509extension.h"
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_OPCUA_EXPORT QOpcUaX509ExtensionExtendedKeyUsage : public QOpcUaX509Extension
+{
+public:
+ enum class KeyUsage : uint {
+ TlsWebServerAuthentication,
+ TlsWebClientAuthentication,
+ SignExecutableCode,
+ EmailProtection,
+ };
+
+ QOpcUaX509ExtensionExtendedKeyUsage();
+ QOpcUaX509ExtensionExtendedKeyUsage(const QOpcUaX509ExtensionExtendedKeyUsage &);
+ QOpcUaX509ExtensionExtendedKeyUsage &operator=(const QOpcUaX509ExtensionExtendedKeyUsage &);
+ bool operator==(const QOpcUaX509ExtensionExtendedKeyUsage &rhs) const;
+ ~QOpcUaX509ExtensionExtendedKeyUsage();
+
+ void setKeyUsage(KeyUsage keyUsage, bool enable = true);
+ bool keyUsage(KeyUsage) const;
+};
+
+inline uint qHash(const QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage &key)
+{
+ return ::qHash(static_cast<uint>(key));
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509EXTENSIONEXTENDEDKEYUSAGE_H
diff --git a/src/opcua/x509/qopcuax509extensionkeyusage.cpp b/src/opcua/x509/qopcuax509extensionkeyusage.cpp
new file mode 100644
index 0000000..f270899
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionkeyusage.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509extensionkeyusage.h"
+#include "qopcuax509extension_p.h"
+#include <QSet>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509ExtensionKeyUsage
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Class for X509 extended key usage
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+
+/*!
+ \enum QOpcUaX509ExtensionKeyUsage::KeyUsage
+
+ Enum with entry types for X509ExtensionKeyUsage.
+
+ \value DigitalSignature
+ Permits digital signatures
+ \value NonRepudiation
+ Permits non repudiation
+ \value KeyEncipherment
+ Permits key encipherment
+ \value DataEncipherment
+ Permits data encipherment
+ \value KeyAgreement
+ Permits key agreement
+ \value CertificateSigning
+ Permits certificate signing
+ \value CrlSigning
+ Permits CRL signing
+ \value EnciptherOnly
+ Restricts to encipherment only
+ \value DecipherOnly
+ Restricts to decipher only
+*/
+
+class QOpcUaX509ExtensionKeyUsageData : public QOpcUaX509ExtensionData
+{
+public:
+ QSet<QOpcUaX509ExtensionKeyUsage::KeyUsage> keyUsage;
+};
+
+/*!
+ Constructs a X509ExtensionKeyUsage.
+*/
+QOpcUaX509ExtensionKeyUsage::QOpcUaX509ExtensionKeyUsage()
+ : QOpcUaX509Extension(new QOpcUaX509ExtensionKeyUsageData)
+{
+}
+
+/*!
+ Constructs a X509ExtensionKeyUsage from \a rhs.
+*/
+QOpcUaX509ExtensionKeyUsage::QOpcUaX509ExtensionKeyUsage(const QOpcUaX509ExtensionKeyUsage &rhs)
+ : QOpcUaX509Extension(rhs.data)
+{
+}
+
+/*!
+ Returns \c true if this X509ExtensionKeyUsage has the same value as \a rhs.
+*/
+bool QOpcUaX509ExtensionKeyUsage::operator==(const QOpcUaX509ExtensionKeyUsage &rhs) const
+{
+ return data->critical == rhs.data->critical;
+}
+
+/*!
+ Destructs a X509ExtensionKeyUsage.
+*/
+QOpcUaX509ExtensionKeyUsage::~QOpcUaX509ExtensionKeyUsage()
+{
+}
+
+/*!
+ Sets the values from \a rhs in this X509ExtensionKeyUsage.
+*/
+QOpcUaX509ExtensionKeyUsage &QOpcUaX509ExtensionKeyUsage::operator=(const QOpcUaX509ExtensionKeyUsage &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Sets the key usage flag in \a keyUsage to \a enable.
+*/
+void QOpcUaX509ExtensionKeyUsage::setKeyUsage(KeyUsage keyUsage, bool enable)
+{
+ QOpcUaX509ExtensionKeyUsageData *d = static_cast<QOpcUaX509ExtensionKeyUsageData*>(data.data());
+
+ if (enable)
+ d->keyUsage.insert(keyUsage);
+ else
+ d->keyUsage.remove(keyUsage);
+}
+
+/*!
+ Returns the key usage flag for \a keyUsage.
+*/
+bool QOpcUaX509ExtensionKeyUsage::keyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage keyUsage) const
+{
+ const QOpcUaX509ExtensionKeyUsageData *d = static_cast<const QOpcUaX509ExtensionKeyUsageData*>(data.data());
+ return d->keyUsage.contains(keyUsage);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509extensionkeyusage.h b/src/opcua/x509/qopcuax509extensionkeyusage.h
new file mode 100644
index 0000000..7e0586c
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionkeyusage.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSIONKEYUSAGE_H
+#define QOPCUAX509EXTENSIONKEYUSAGE_H
+
+#include "QtOpcUa/qopcuax509extension.h"
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_OPCUA_EXPORT QOpcUaX509ExtensionKeyUsage : public QOpcUaX509Extension
+{
+public:
+ enum class KeyUsage : uint {
+ DigitalSignature,
+ NonRepudiation,
+ KeyEncipherment,
+ DataEncipherment,
+ KeyAgreement,
+ CertificateSigning,
+ CrlSigning,
+ EnciptherOnly,
+ DecipherOnly
+ };
+
+ QOpcUaX509ExtensionKeyUsage();
+ QOpcUaX509ExtensionKeyUsage(const QOpcUaX509ExtensionKeyUsage &);
+ QOpcUaX509ExtensionKeyUsage &operator=(const QOpcUaX509ExtensionKeyUsage &);
+ bool operator==(const QOpcUaX509ExtensionKeyUsage &rhs) const;
+ ~QOpcUaX509ExtensionKeyUsage();
+
+ void setKeyUsage(KeyUsage keyUsage, bool enable = true);
+ bool keyUsage(KeyUsage) const;
+};
+
+inline uint qHash(const QOpcUaX509ExtensionKeyUsage::KeyUsage &key)
+{
+ return ::qHash(static_cast<uint>(key));
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509EXTENSIONKEYUSAGE_H
diff --git a/src/opcua/x509/qopcuax509extensionsubjectalternativename.cpp b/src/opcua/x509/qopcuax509extensionsubjectalternativename.cpp
new file mode 100644
index 0000000..86bad2e
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionsubjectalternativename.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopcuax509extensionsubjectalternativename.h"
+#include "qopcuax509extension_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOpcUaX509ExtensionSubjectAlternativeName
+ \inmodule QtOpcUa
+ \since 5.14
+
+ \brief Class for an X509 subject alternative name
+
+ This class is currently available as a Technology Preview, and therefore the API
+ and functionality provided by the class may be subject to change at any time without
+ prior notice.
+*/
+
+/*!
+ \enum QOpcUaX509ExtensionSubjectAlternativeName::Type
+
+ Enum with entry types for subject alternative name.
+
+ \value Email
+ Entry type for an email address
+ \value URI
+ Entry type for an URI
+ \value DNS
+ Entry type for DNS
+ \value IP
+ Entry type for an IP address
+*/
+
+class QOpcUaX509ExtensionSubjectAlternativeNameData : public QOpcUaX509ExtensionData
+{
+public:
+ QVector <QPair<QOpcUaX509ExtensionSubjectAlternativeName::Type, QString>> entries;
+};
+
+/*!
+ Constructs a X509ExtensionSubjectAlternativeName.
+*/
+QOpcUaX509ExtensionSubjectAlternativeName::QOpcUaX509ExtensionSubjectAlternativeName()
+ : QOpcUaX509Extension(new QOpcUaX509ExtensionSubjectAlternativeNameData)
+{
+}
+
+/*!
+ Constructs a X509ExtensionSubjectAlternativeName from \a rhs.
+*/
+QOpcUaX509ExtensionSubjectAlternativeName::QOpcUaX509ExtensionSubjectAlternativeName(const QOpcUaX509ExtensionSubjectAlternativeName &rhs)
+ : QOpcUaX509Extension(rhs.data)
+{
+}
+
+/*!
+ Returns \c true if this X509ExtensionSubjectAlternativeName has the same value as \a rhs.
+*/
+bool QOpcUaX509ExtensionSubjectAlternativeName::operator==(const QOpcUaX509ExtensionSubjectAlternativeName &rhs) const
+{
+ return data->critical == rhs.data->critical;
+}
+
+/*!
+ Destructs a X509ExtensionSubjectAlternativeName.
+*/
+QOpcUaX509ExtensionSubjectAlternativeName::~QOpcUaX509ExtensionSubjectAlternativeName()
+{
+}
+
+/*!
+ Sets the values from \a rhs in this X509ExtensionSubjectAlternativeName.
+*/
+QOpcUaX509ExtensionSubjectAlternativeName &QOpcUaX509ExtensionSubjectAlternativeName::operator=(const QOpcUaX509ExtensionSubjectAlternativeName &rhs)
+{
+ if (this != &rhs)
+ data.operator=(rhs.data);
+ return *this;
+}
+
+/*!
+ Adds an entry of type \a type with content \a value.
+*/
+void QOpcUaX509ExtensionSubjectAlternativeName::addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type type, const QString &value)
+{
+ QOpcUaX509ExtensionSubjectAlternativeNameData *d = static_cast<QOpcUaX509ExtensionSubjectAlternativeNameData*>(data.data());
+ d->entries.append(qMakePair(type, value));
+}
+
+/*!
+ Returns the vector of entries.
+*/
+const QVector<QPair<QOpcUaX509ExtensionSubjectAlternativeName::Type, QString>> &QOpcUaX509ExtensionSubjectAlternativeName::entries() const
+{
+ const QOpcUaX509ExtensionSubjectAlternativeNameData *d = static_cast<const QOpcUaX509ExtensionSubjectAlternativeNameData*>(data.data());
+ return d->entries;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opcua/x509/qopcuax509extensionsubjectalternativename.h b/src/opcua/x509/qopcuax509extensionsubjectalternativename.h
new file mode 100644
index 0000000..4f13117
--- /dev/null
+++ b/src/opcua/x509/qopcuax509extensionsubjectalternativename.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPCUAX509EXTENSIONSUBJECTALTERNATIVENAME_H
+#define QOPCUAX509EXTENSIONSUBJECTALTERNATIVENAME_H
+
+#include "QtOpcUa/qopcuax509extension.h"
+#include <QtOpcUa/qopcuaglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+// OID 2.5.29.17
+class Q_OPCUA_EXPORT QOpcUaX509ExtensionSubjectAlternativeName : public QOpcUaX509Extension
+{
+public:
+ enum class Type {
+ Email,
+ URI,
+ DNS,
+ IP
+ };
+
+ QOpcUaX509ExtensionSubjectAlternativeName();
+ QOpcUaX509ExtensionSubjectAlternativeName(const QOpcUaX509ExtensionSubjectAlternativeName &);
+ QOpcUaX509ExtensionSubjectAlternativeName &operator=(const QOpcUaX509ExtensionSubjectAlternativeName &);
+ bool operator==(const QOpcUaX509ExtensionSubjectAlternativeName &rhs) const;
+ ~QOpcUaX509ExtensionSubjectAlternativeName();
+
+ void addEntry(Type type, const QString &value);
+ const QVector<QPair<Type, QString>> &entries() const;
+};
+
+QT_END_NAMESPACE
+#endif // QOPCUAX509EXTENSIONSUBJECTALTERNATIVENAME_H
diff --git a/src/opcua/x509/qopcuax509utils.cpp b/src/opcua/x509/qopcuax509utils.cpp
new file mode 100644
index 0000000..74eb5d4
--- /dev/null
+++ b/src/opcua/x509/qopcuax509utils.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qopcuax509utils_p.h"
+#include "openssl_symbols_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QString getOpenSslError()
+{
+ char errorBuf[1024];
+ errorBuf[0] = 0;
+ q_ERR_error_string_n(q_ERR_get_error(), errorBuf, sizeof(errorBuf));
+ return QString::fromLatin1(errorBuf);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/opcua/x509/qopcuax509utils_p.h b/src/opcua/x509/qopcuax509utils_p.h
new file mode 100644
index 0000000..4f9f00e
--- /dev/null
+++ b/src/opcua/x509/qopcuax509utils_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOPCUAX509UTILS_H
+#define QOPCUAX509UTILS_H
+
+#include <functional>
+#include <QString>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+class Deleter
+{
+public:
+ Deleter(T *data, std::function<void(T *value)> f)
+ : m_data(data)
+ , m_function(f)
+ {
+ }
+ ~Deleter()
+ {
+ if (m_data)
+ m_function(m_data);
+ }
+ void release()
+ {
+ m_data = nullptr;
+ m_function = nullptr;
+ }
+private:
+ T *m_data {nullptr};
+ std::function<void(T *attribute)> m_function;
+};
+
+QString getOpenSslError();
+
+QT_END_NAMESPACE
+
+#endif // QOPCUAX509UTILS_H
diff --git a/src/opcua/x509/qsslsocket_openssl11_symbols_p.h b/src/opcua/x509/qsslsocket_openssl11_symbols_p.h
new file mode 100644
index 0000000..cac3999
--- /dev/null
+++ b/src/opcua/x509/qsslsocket_openssl11_symbols_p.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef QSSLSOCKET_OPENSSL11_SYMBOLS_P_H
+#define QSSLSOCKET_OPENSSL11_SYMBOLS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// Note: this file does not have QT_BEGIN_NAMESPACE/QT_END_NAMESPACE, it's done
+// in qsslsocket_openssl_symbols_p.h.
+
+#ifndef OPENSSL_SYMBOLS_P_H
+#error "You are not supposed to use this header file, include openssl_symbols_p.h instead"
+#endif
+
+#include <openssl/x509.h>
+
+const unsigned char * q_ASN1_STRING_get0_data(const ASN1_STRING *x);
+
+Q_AUTOTEST_EXPORT BIO *q_BIO_new(const BIO_METHOD *a);
+Q_AUTOTEST_EXPORT const BIO_METHOD *q_BIO_s_mem();
+
+int q_DSA_bits(DSA *a);
+int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c);
+int q_EVP_PKEY_base_id(EVP_PKEY *a);
+int q_RSA_bits(RSA *a);
+Q_AUTOTEST_EXPORT int q_OPENSSL_sk_num(OPENSSL_STACK *a);
+Q_AUTOTEST_EXPORT void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *));
+Q_AUTOTEST_EXPORT OPENSSL_STACK *q_OPENSSL_sk_new_null();
+Q_AUTOTEST_EXPORT void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data);
+Q_AUTOTEST_EXPORT void q_OPENSSL_sk_free(OPENSSL_STACK *a);
+Q_AUTOTEST_EXPORT void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
+int q_SSL_session_reused(SSL *a);
+unsigned long q_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op);
+int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
+size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
+int q_CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+const SSL_METHOD *q_TLS_method();
+const SSL_METHOD *q_TLS_client_method();
+const SSL_METHOD *q_TLS_server_method();
+ASN1_TIME *q_X509_getm_notBefore(X509 *a);
+ASN1_TIME *q_X509_getm_notAfter(X509 *a);
+
+Q_AUTOTEST_EXPORT void q_X509_up_ref(X509 *a);
+long q_X509_get_version(X509 *a);
+EVP_PKEY *q_X509_get_pubkey(X509 *a);
+void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb);
+STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
+void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+int q_DH_bits(DH *dh);
+
+# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
+ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
+
+#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_OPENSSL_sk_num)(st)
+#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_OPENSSL_sk_value)(st, i)
+
+#define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS \
+ | OPENSSL_INIT_LOAD_CONFIG, NULL)
+#define q_OPENSSL_add_all_algorithms_noconf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
+
+// We resolve q_sk_ functions, but use q_OPENSSL_sk_ macros in code to reduce
+// the amount of #ifdefs and for confusing developers.
+OPENSSL_STACK *q_sk_new_null();
+#define q_OPENSSL_sk_new_null() q_sk_new_null()
+#define q_sk_X509_EXTENSION_new_null() \
+ ((OPENSSL_STACK *)q_sk_new_null())
+
+void q_sk_push(OPENSSL_STACK *st, void *data);
+
+#define q_sk_X509_EXTENSION_push(st, val) \
+ q_OPENSSL_sk_push((st), (val))
+#define q_sk_X509_EXTENSION_pop_free(st, free_func) \
+ q_OPENSSL_sk_pop_free((st), (free_func))
+
+
+int q_OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+void q_CRYPTO_free(void *str, const char *file, int line);
+
+long q_OpenSSL_version_num();
+const char *q_OpenSSL_version(int type);
+
+unsigned long q_SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
+unsigned long q_SSL_set_options(SSL *s, unsigned long op);
+
+#ifdef TLS1_3_VERSION
+int q_SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
+#endif
+
+void q_BIO_set_data(BIO *a, void *ptr);
+void *q_BIO_get_data(BIO *a);
+void q_BIO_set_init(BIO *a, int init);
+int q_BIO_get_shutdown(BIO *a);
+void q_BIO_set_shutdown(BIO *a, int shut);
+
+EVP_PKEY_CTX* q_EVP_PKEY_CTX_new_id(int id, ENGINE *e);
+void q_EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
+int q_EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
+
+int q_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2);
+#define q_EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \
+ q_RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \
+ EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL)
+
+int q_EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **pkey);
+
+#define q_SSL_CTX_set_min_proto_version(ctx, version) \
+ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr)
+
+#define q_SSL_CTX_set_max_proto_version(ctx, version) \
+ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr)
+
+#endif
diff --git a/src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h b/src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h
new file mode 100644
index 0000000..ee41ad9
--- /dev/null
+++ b/src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, the copyright holders listed above give
+** permission to link the code of its release of Qt with the OpenSSL project's
+** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
+** same license as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+
+#ifndef QSSLSOCKET_OPENSSLPRE11_SYMBOLS_P_H
+#define QSSLSOCKET_OPENSSLPRE11_SYMBOLS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// Note: this file does not have QT_BEGIN_NAMESPACE/QT_END_NAMESPACE, it's done
+// in qsslsocket_openssl_symbols_p.h.
+
+#ifndef OPENSSL_SYMBOLS_P_H
+#error "You are not supposed to use this header file, include openssl_symbols_p.h instead"
+#endif
+
+unsigned char * q_ASN1_STRING_data(ASN1_STRING *a);
+BIO *q_BIO_new_file(const char *filename, const char *mode);
+void q_ERR_clear_error();
+Q_AUTOTEST_EXPORT BIO *q_BIO_new(BIO_METHOD *a);
+Q_AUTOTEST_EXPORT BIO_METHOD *q_BIO_s_mem();
+int q_CRYPTO_num_locks();
+void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int));
+void q_CRYPTO_set_id_callback(unsigned long (*a)());
+void q_CRYPTO_free(void *a);
+unsigned long q_ERR_peek_last_error();
+void q_ERR_free_strings();
+void q_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
+void q_EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
+
+typedef _STACK STACK;
+
+// The typedef we use to make our pre 1.1 code look more like 1.1 (less ifdefs).
+typedef STACK OPENSSL_STACK;
+
+// We resolve q_sk_ functions, but use q_OPENSSL_sk_ macros in code to reduce
+// the amount of #ifdefs and for confusing developers.
+int q_sk_num(STACK *a);
+#define q_OPENSSL_sk_num(a) q_sk_num(a)
+void q_sk_pop_free(STACK *a, void (*b)(void *));
+#define q_OPENSSL_sk_pop_free(a, b) (a, b)
+STACK *q_sk_new_null();
+#define q_OPENSSL_sk_new_null() q_sk_new_null()
+
+#define q_sk_X509_EXTENSION_new_null() \
+ ((STACK_OF(X509_EXTENSION) *)q_sk_new_null())
+
+#define q_SKM_sk_push(type, st, val) \
+ q_OPENSSL_sk_push(CHECKED_STACK_OF(type, st), CHECKED_PTR_OF(type, val))
+
+#define q_sk_X509_EXTENSION_push(st, val) \
+ q_SKM_sk_push(X509_EXTENSION, (st), (val))
+#define q_sk_X509_EXTENSION_pop_free(st, free_func) \
+ q_OPENSSL_sk_pop_free(CHECKED_STACK_OF(X509_EXTENSION, st), (free_func))
+
+void q_sk_free(STACK *a);
+
+// Just a name alias (not a function call expression) since in code we take an
+// address of this:
+#define q_OPENSSL_sk_free q_sk_free
+
+void *q_sk_value(STACK *a, int b);
+void q_sk_push(STACK *st, void *data);
+
+#define q_OPENSSL_sk_value(a, b) q_sk_value(a, b)
+#define q_OPENSSL_sk_push(st, data) q_sk_push(st, data)
+
+SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
+
+int q_SSL_library_init();
+void q_SSL_load_error_strings();
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+int q_SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+#endif
+
+const SSL_METHOD *q_SSLv23_client_method();
+const SSL_METHOD *q_TLSv1_client_method();
+const SSL_METHOD *q_TLSv1_1_client_method();
+const SSL_METHOD *q_TLSv1_2_client_method();
+const SSL_METHOD *q_SSLv23_server_method();
+const SSL_METHOD *q_TLSv1_server_method();
+const SSL_METHOD *q_TLSv1_1_server_method();
+const SSL_METHOD *q_TLSv1_2_server_method();
+
+STACK_OF(X509) *q_X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
+
+#ifdef SSLEAY_MACROS
+int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
+int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
+RSA *q_d2i_RSAPrivateKey(RSA **a, unsigned char **pp, long length);
+DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
+#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
+ (RSA *)q_PEM_ASN1_read_bio( \
+ (void *(*)(void**, const unsigned char**, long int))q_d2i_RSAPrivateKey, PEM_STRING_RSA, bp, (void **)x, cb, u)
+#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
+ (DSA *)q_PEM_ASN1_read_bio( \
+ (void *(*)(void**, const unsigned char**, long int))q_d2i_DSAPrivateKey, PEM_STRING_DSA, bp, (void **)x, cb, u)
+#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
+#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
+#define q_PEM_read_bio_DHparams(bp, dh, cb, u) \
+ (DH *)q_PEM_ASN1_read_bio( \
+ (void *(*)(void**, const unsigned char**, long int))q_d2i_DHparams, PEM_STRING_DHPARAMS, bp, (void **)x, cb, u)
+#endif // SSLEAY_MACROS
+
+#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define q_SSL_set_options(ssl,op) q_SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),nullptr)
+#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st)
+#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i)
+#define q_X509_getm_notAfter(x) X509_get_notAfter(x)
+#define q_X509_getm_notBefore(x) X509_get_notBefore(x)
+
+// "Forward compatibility" with OpenSSL 1.1 (to save on #if-ery elsewhere):
+#define q_X509_get_version(x509) q_ASN1_INTEGER_get((x509)->cert_info->version)
+#define q_ASN1_STRING_get0_data(x) q_ASN1_STRING_data(x)
+#define q_EVP_PKEY_base_id(pkey) ((pkey)->type)
+#define q_X509_get_pubkey(x509) q_X509_PUBKEY_get((x509)->cert_info->key)
+#define q_SSL_SESSION_get_ticket_lifetime_hint(s) ((s)->tlsext_tick_lifetime_hint)
+#define q_RSA_bits(rsa) q_BN_num_bits((rsa)->n)
+#define q_DSA_bits(dsa) q_BN_num_bits((dsa)->p)
+#define q_DH_bits(dsa) q_BN_num_bits((dh)->p)
+#define q_X509_STORE_set_verify_cb(s,c) X509_STORE_set_verify_cb_func((s),(c))
+
+char *q_CONF_get1_default_config_file();
+void q_OPENSSL_add_all_algorithms_noconf();
+void q_OPENSSL_add_all_algorithms_conf();
+
+long q_SSLeay();
+const char *q_SSLeay_version(int type);
+
+#endif // QSSLSOCKET_OPENSSL_PRE11_SYMBOLS_P_H
diff --git a/src/opcua/x509/x509.pri b/src/opcua/x509/x509.pri
new file mode 100644
index 0000000..efcb13c
--- /dev/null
+++ b/src/opcua/x509/x509.pri
@@ -0,0 +1,33 @@
+PUBLIC_HEADERS += \
+ $$PWD/qopcuakeypair.h \
+ $$PWD/qopcuax509certificatesigningrequest.h \
+ $$PWD/qopcuax509distinguishedname.h \
+ $$PWD/qopcuax509extensionextendedkeyusage.h \
+ $$PWD/qopcuax509extension.h \
+ $$PWD/qopcuax509extensionkeyusage.h \
+ $$PWD/qopcuax509extensionsubjectalternativename.h \
+ $$PWD/qopcuax509extensionbasicconstraints.h \
+
+PRIVATE_HEADERS += \
+ $$PWD/qopcuakeypair_p.h \
+ $$PWD/openssl_symbols_p.h \
+ $$PWD/qsslsocket_openssl11_symbols_p.h \
+ $$PWD/qsslsocket_opensslpre11_symbols_p.h \
+ $$PWD/qopcuax509certificatesigningrequest_p.h \
+ $$PWD/qopcuax509utils_p.h \
+ $$PWD/qopcuax509extension_p.h \
+
+SOURCES += \
+ $$PWD/qopcuax509certificatesigningrequest.cpp \
+ $$PWD/qopcuax509distinguishedname.cpp \
+ $$PWD/qopcuax509extensionextendedkeyusage.cpp \
+ $$PWD/qopcuax509extension.cpp \
+ $$PWD/qopcuax509extensionkeyusage.cpp \
+ $$PWD/qopcuax509extensionsubjectalternativename.cpp \
+ $$PWD/qopcuax509extensionbasicconstraints.cpp \
+ $$PWD/openssl_symbols.cpp \
+ $$PWD/qopcuakeypair.cpp \
+ $$PWD/qopcuakeypair_openssl.cpp \
+ $$PWD/qopcuax509certificatesigningrequest_openssl.cpp \
+ $$PWD/qopcuax509utils.cpp \
+
diff --git a/src/plugins/opcua/open62541/qopen62541utils.h b/src/plugins/opcua/open62541/qopen62541utils.h
index fd13219..6990912 100644
--- a/src/plugins/opcua/open62541/qopen62541utils.h
+++ b/src/plugins/opcua/open62541/qopen62541utils.h
@@ -39,7 +39,7 @@
#include "qopen62541.h"
-#include <QtCore/qstring.h>
+#include <QString>
#include <functional>
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 9d8b7db..82a44df 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,10 +1,11 @@
TEMPLATE = subdirs
SUBDIRS += qopcuaclient connection clientSetupInCpp security
-QT_FOR_CONFIG += opcua-private
+QT_FOR_CONFIG += opcua-private core-private
# only build declarative tests if at least one backend was built
qtHaveModule(qmltest):qtConfig(open62541)|qtConfig(uacpp) {
SUBDIRS += declarative
}
+qtConfig(ssl):!darwin:!winrt: SUBDIRS += x509
diff --git a/tests/auto/x509/tst_x509.cpp b/tests/auto/x509/tst_x509.cpp
new file mode 100644
index 0000000..d00c3d9
--- /dev/null
+++ b/tests/auto/x509/tst_x509.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt OPC UA module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtOpcUa/QOpcUaProvider>
+#include <QtOpcUa/QOpcUaKeyPair>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QScopedPointer>
+#include <QOpcUaX509CertificateSigningRequest>
+#include <QOpcUaX509ExtensionSubjectAlternativeName>
+#include <QOpcUaX509ExtensionBasicConstraints>
+#include <QOpcUaX509ExtensionKeyUsage>
+#include <QOpcUaX509ExtensionExtendedKeyUsage>
+
+#include <QtTest/QSignalSpy>
+#include <QtTest/QtTest>
+
+#define defineDataMethod(name) void name()\
+{\
+ QTest::addColumn<QString>("backend");\
+ for (auto backend : m_backends) {\
+ const QString rowName = QString("%1").arg(backend); \
+ QTest::newRow(rowName.toLatin1().constData()) << backend ; \
+ }\
+}
+
+class Tst_QOpcUaSecurity: public QObject
+{
+ Q_OBJECT
+
+public:
+ Tst_QOpcUaSecurity();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ defineDataMethod(keyPairs_data)
+ void keyPairs();
+
+ defineDataMethod(certificateSigningRequest_data)
+ void certificateSigningRequest();
+
+private:
+ QStringList m_backends;
+ QOpcUaProvider m_opcUa;
+};
+
+QByteArray textifyCertificateRequest(const QByteArray &data)
+{
+ QProcess p;
+ p.start("openssl", QStringList {"req", "-text", "-noout"});
+ p.waitForStarted();
+ p.write(data);
+ p.closeWriteChannel();
+ p.waitForFinished();
+ return p.readAllStandardOutput();
+}
+
+QByteArray textifyCertificate(const QByteArray &data)
+{
+ QProcess p;
+ p.start("openssl", QStringList {"x509", "-text", "-noout"});
+ p.waitForStarted();
+ p.write(data);
+ p.closeWriteChannel();
+ p.waitForFinished();
+ return p.readAllStandardOutput();
+}
+
+QByteArray asn1dump(const QByteArray &data)
+{
+ QProcess p;
+ p.start("openssl", QStringList {"asn1parse", "-inform","PEM"});
+ p.waitForStarted();
+ p.write(data);
+ p.closeWriteChannel();
+ p.waitForFinished();
+ return p.readAllStandardOutput();
+}
+
+Tst_QOpcUaSecurity::Tst_QOpcUaSecurity()
+{
+ m_backends = QOpcUaProvider::availableBackends();
+}
+
+void Tst_QOpcUaSecurity::initTestCase()
+{
+}
+
+void Tst_QOpcUaSecurity::keyPairs()
+{
+ QFETCH(QString, backend);
+
+ QOpcUaKeyPair key;
+ QOpcUaKeyPair loadedKey;
+ QByteArray byteArray;
+
+ QVERIFY(key.hasPrivateKey() == false);
+
+ // Generate key
+ key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024);
+ QVERIFY(key.hasPrivateKey() == true);
+
+ // Export public key
+ byteArray = key.publicKeyToByteArray();
+ QVERIFY(byteArray.startsWith("-----BEGIN PUBLIC KEY-----\n"));
+ QVERIFY(byteArray.endsWith("-----END PUBLIC KEY-----\n"));
+
+ // Load public key
+ QVERIFY(loadedKey.loadFromPemData(byteArray));
+ QVERIFY(loadedKey.hasPrivateKey() == false);
+
+ // Check unencrypted PEM export
+ byteArray = key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString());
+ QVERIFY(byteArray.startsWith("-----BEGIN PRIVATE KEY-----\n"));
+ QVERIFY(byteArray.endsWith("-----END PRIVATE KEY-----\n"));
+
+ // Load private key from PEM data
+ QSignalSpy passwordSpy(&loadedKey, SIGNAL(passphraseNeeded(QString&,int,bool)));
+
+ QVERIFY(loadedKey.loadFromPemData(byteArray));
+ QVERIFY(loadedKey.hasPrivateKey() == true);
+ QCOMPARE(passwordSpy.count(), 0);
+ QCOMPARE(loadedKey.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()), byteArray);
+
+ // Check encrypted PEM export
+ byteArray = key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Aes128Cbc, QString("password"));
+ QVERIFY(byteArray.startsWith("-----BEGIN ENCRYPTED PRIVATE KEY-----\n"));
+ QVERIFY(byteArray.endsWith("-----END ENCRYPTED PRIVATE KEY-----\n"));
+ QCOMPARE(passwordSpy.count(), 0);
+
+ // Setup password callback
+ QString passphraseToReturn;
+ connect(&loadedKey, &QOpcUaKeyPair::passphraseNeeded, this, [&passphraseToReturn](QString &passphrase, int maximumLength, bool writeOperation){
+ Q_UNUSED(maximumLength);
+ qDebug() << "Requested a passphrase for" << (writeOperation ? "write":"read") << "operation";
+ passphrase = passphraseToReturn;
+ });
+
+ // Load key with wrong password
+ qDebug() << "Trying to decrypt with wrong password; will cause an error";
+ passphraseToReturn = "WrongPassword";
+ QVERIFY(!loadedKey.loadFromPemData(byteArray));
+ QCOMPARE(passwordSpy.count(), 1);
+ QVERIFY(loadedKey.hasPrivateKey() == false);
+
+ // Load key with right password
+ qDebug() << "Trying to decrypt with right password; will cause no error";
+ passphraseToReturn = "password";
+ QVERIFY(loadedKey.loadFromPemData(byteArray));
+ QCOMPARE(passwordSpy.count(), 2);
+ QCOMPARE(loadedKey.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()),
+ key.privateKeyToByteArray(QOpcUaKeyPair::Cipher::Unencrypted, QString()));
+ QVERIFY(loadedKey.hasPrivateKey() == true);
+}
+
+void Tst_QOpcUaSecurity::certificateSigningRequest()
+{
+ QFETCH(QString, backend);
+
+ QOpcUaKeyPair key;
+
+ // Generate key
+ key.generateRsaKey(QOpcUaKeyPair::RsaKeyStrength::Bits1024);
+ QVERIFY(key.hasPrivateKey() == true);
+
+ QOpcUaX509CertificateSigningRequest csr;
+
+ QOpcUaX509DistinguishedName dn;
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CommonName, "QtOpcUaViewer");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::CountryName, "DE");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::LocalityName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::StateOrProvinceName, "Berlin");
+ dn.setEntry(QOpcUaX509DistinguishedName::Type::OrganizationName, "The Qt Company");
+ csr.setSubject(dn);
+
+ QOpcUaX509ExtensionSubjectAlternativeName *san = new QOpcUaX509ExtensionSubjectAlternativeName;
+ san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "foo.com");
+ san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::DNS, "bla.com");
+ san->addEntry(QOpcUaX509ExtensionSubjectAlternativeName::Type::URI, "urn:foo.com:The%20Qt%20Company:QtOpcUaViewer");
+ san->setCritical(true);
+ csr.addExtension(san);
+
+ QOpcUaX509ExtensionBasicConstraints *bc = new QOpcUaX509ExtensionBasicConstraints;
+ bc->setCa(false);
+ bc->setCritical(true);
+ csr.addExtension(bc);
+
+ QOpcUaX509ExtensionKeyUsage *ku = new QOpcUaX509ExtensionKeyUsage;
+ ku->setCritical(true);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DigitalSignature);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::NonRepudiation);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::KeyEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::DataEncipherment);
+ ku->setKeyUsage(QOpcUaX509ExtensionKeyUsage::KeyUsage::CertificateSigning);
+ csr.addExtension(ku);
+
+ QOpcUaX509ExtensionExtendedKeyUsage *eku = new QOpcUaX509ExtensionExtendedKeyUsage;
+ eku->setCritical(true);
+ eku->setKeyUsage(QOpcUaX509ExtensionExtendedKeyUsage::KeyUsage::EmailProtection);
+ csr.addExtension(eku);
+
+ QByteArray csrData = csr.createRequest(key);
+ qDebug() << csrData;
+ QVERIFY(csrData.startsWith("-----BEGIN CERTIFICATE REQUEST-----\n"));
+ QVERIFY(csrData.endsWith("\n-----END CERTIFICATE REQUEST-----\n"));
+ qDebug().noquote() << textifyCertificateRequest(csrData);
+ qDebug().noquote() << asn1dump(csrData);
+
+ QByteArray certData = csr.createSelfSignedCertificate(key);
+ qDebug() << certData;
+ QVERIFY(certData.startsWith("-----BEGIN CERTIFICATE-----\n"));
+ QVERIFY(certData.endsWith("\n-----END CERTIFICATE-----\n"));
+ qDebug().noquote() << textifyCertificate(certData);
+ qDebug().noquote() << asn1dump(certData);
+}
+
+void Tst_QOpcUaSecurity::cleanupTestCase()
+{
+}
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QTEST_SET_MAIN_SOURCE_PATH
+
+ // run tests for all available backends
+ QStringList availableBackends = QOpcUaProvider::availableBackends();
+ if (availableBackends.empty()) {
+ qDebug("No OPCUA backends found, skipping tests.");
+ return EXIT_SUCCESS;
+ }
+
+ Tst_QOpcUaSecurity tc;
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_x509.moc"
+
diff --git a/tests/auto/x509/x509.pro b/tests/auto/x509/x509.pro
new file mode 100644
index 0000000..b1f1fc1
--- /dev/null
+++ b/tests/auto/x509/x509.pro
@@ -0,0 +1,8 @@
+TARGET = tst_x509
+
+QT += testlib opcua network
+QT -= gui
+CONFIG += testcase
+
+SOURCES += \
+ tst_x509.cpp