From 00f86fd8431e3c89d2e626cbaf965b75bf2ea8d4 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Wed, 22 May 2019 16:07:16 +0200 Subject: Add support for generating X509 Certificate Signing Requests Change-Id: I6e69d38ff9285a3b7f84b7470fdd7a80505c4f2b Reviewed-by: Rainer Keller --- examples/opcua/opcua.pro | 4 +- examples/opcua/x509/doc/x509.qdoc | 36 + examples/opcua/x509/main.cpp | 123 ++ examples/opcua/x509/x509.pro | 12 + src/opcua/opcua.pro | 4 +- src/opcua/x509/openssl_symbols.cpp | 1335 ++++++++++++++++++++ src/opcua/x509/openssl_symbols_p.h | 566 +++++++++ src/opcua/x509/qopcuakeypair.cpp | 198 +++ src/opcua/x509/qopcuakeypair.h | 90 ++ src/opcua/x509/qopcuakeypair_openssl.cpp | 264 ++++ src/opcua/x509/qopcuakeypair_p.h | 84 ++ .../x509/qopcuax509certificatesigningrequest.cpp | 236 ++++ .../x509/qopcuax509certificatesigningrequest.h | 86 ++ ...qopcuax509certificatesigningrequest_openssl.cpp | 509 ++++++++ .../x509/qopcuax509certificatesigningrequest_p.h | 91 ++ src/opcua/x509/qopcuax509distinguishedname.cpp | 167 +++ src/opcua/x509/qopcuax509distinguishedname.h | 72 ++ src/opcua/x509/qopcuax509extension.cpp | 126 ++ src/opcua/x509/qopcuax509extension.h | 65 + src/opcua/x509/qopcuax509extension_p.h | 63 + .../x509/qopcuax509extensionbasicconstraints.cpp | 138 ++ .../x509/qopcuax509extensionbasicconstraints.h | 65 + .../x509/qopcuax509extensionextendedkeyusage.cpp | 140 ++ .../x509/qopcuax509extensionextendedkeyusage.h | 72 ++ src/opcua/x509/qopcuax509extensionkeyusage.cpp | 149 +++ src/opcua/x509/qopcuax509extensionkeyusage.h | 77 ++ .../qopcuax509extensionsubjectalternativename.cpp | 134 ++ .../qopcuax509extensionsubjectalternativename.h | 67 + src/opcua/x509/qopcuax509utils.cpp | 62 + src/opcua/x509/qopcuax509utils_p.h | 84 ++ src/opcua/x509/qsslsocket_openssl11_symbols_p.h | 178 +++ src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h | 196 +++ src/opcua/x509/x509.pri | 33 + src/plugins/opcua/open62541/qopen62541utils.h | 2 +- tests/auto/auto.pro | 3 +- tests/auto/x509/tst_x509.cpp | 274 ++++ tests/auto/x509/x509.pro | 8 + 37 files changed, 5809 insertions(+), 4 deletions(-) create mode 100644 examples/opcua/x509/doc/x509.qdoc create mode 100644 examples/opcua/x509/main.cpp create mode 100644 examples/opcua/x509/x509.pro create mode 100644 src/opcua/x509/openssl_symbols.cpp create mode 100644 src/opcua/x509/openssl_symbols_p.h create mode 100644 src/opcua/x509/qopcuakeypair.cpp create mode 100644 src/opcua/x509/qopcuakeypair.h create mode 100644 src/opcua/x509/qopcuakeypair_openssl.cpp create mode 100644 src/opcua/x509/qopcuakeypair_p.h create mode 100644 src/opcua/x509/qopcuax509certificatesigningrequest.cpp create mode 100644 src/opcua/x509/qopcuax509certificatesigningrequest.h create mode 100644 src/opcua/x509/qopcuax509certificatesigningrequest_openssl.cpp create mode 100644 src/opcua/x509/qopcuax509certificatesigningrequest_p.h create mode 100644 src/opcua/x509/qopcuax509distinguishedname.cpp create mode 100644 src/opcua/x509/qopcuax509distinguishedname.h create mode 100644 src/opcua/x509/qopcuax509extension.cpp create mode 100644 src/opcua/x509/qopcuax509extension.h create mode 100644 src/opcua/x509/qopcuax509extension_p.h create mode 100644 src/opcua/x509/qopcuax509extensionbasicconstraints.cpp create mode 100644 src/opcua/x509/qopcuax509extensionbasicconstraints.h create mode 100644 src/opcua/x509/qopcuax509extensionextendedkeyusage.cpp create mode 100644 src/opcua/x509/qopcuax509extensionextendedkeyusage.h create mode 100644 src/opcua/x509/qopcuax509extensionkeyusage.cpp create mode 100644 src/opcua/x509/qopcuax509extensionkeyusage.h create mode 100644 src/opcua/x509/qopcuax509extensionsubjectalternativename.cpp create mode 100644 src/opcua/x509/qopcuax509extensionsubjectalternativename.h create mode 100644 src/opcua/x509/qopcuax509utils.cpp create mode 100644 src/opcua/x509/qopcuax509utils_p.h create mode 100644 src/opcua/x509/qsslsocket_openssl11_symbols_p.h create mode 100644 src/opcua/x509/qsslsocket_opensslpre11_symbols_p.h create mode 100644 src/opcua/x509/x509.pri create mode 100644 tests/auto/x509/tst_x509.cpp create mode 100644 tests/auto/x509/x509.pro 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 +#include +#include +#include +#include +#include +#include + +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 +** 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 + +#ifdef Q_OS_WIN +# include +#elif QT_CONFIG(library) +# include +#endif +#include +#include +#if defined(Q_OS_UNIX) +#include +#endif +#include +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +#include +#endif +#ifdef Q_OS_DARWIN +#include "private/qcore_mac_p.h" +#endif + +#include + +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(-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 lhsparts = lhs.splitRef(QLatin1Char('.')); + const QVector 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 *paths = (QSet *)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(CFBundleCopyBundleURL(CFBundleGetMainBundle()))); + QUrl frameworksUrl = QUrl::fromCFURL(QCFType(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 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 ssl, crypto; +}; + +static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result) +{ + auto ssleay32 = qt_make_unique(ssleay32LibName); + if (!ssleay32->load(false)) { + return FALSE; + } + + auto libeay32 = qt_make_unique(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 ssl, crypto; +}; + +static LoadedOpenSsl loadOpenSsl() +{ + LoadedOpenSsl result = {qt_make_unique(), qt_make_unique()}; + +# 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. + libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER)); + libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER)); + if (libcrypto->load() && libssl->load()) { + // libssl.so. and libcrypto.so. 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_ /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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 +#include + +#ifdef Q_OS_WIN +#include +#if defined(X509_NAME) +#undef X509_NAME +#endif +#endif // Q_OS_WIN + +#include + +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 . +#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 +#include +#include +#include + +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(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 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 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 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(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 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 rsaDeleter(rsa, q_RSA_free); + + int result = q_RSA_generate_key_ex(rsa, static_cast(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 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 +#include "qopcuakeypair.h" +#include +#include + +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 +#include +#include + +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 +#include +#include + + +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(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(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(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(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 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 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 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 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 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 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 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 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 +#include +#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 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 + +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 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 +#include + +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 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 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 +#include + +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); + QSharedDataPointer 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 + +// +// 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(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(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(data.data()); + d->pathLength = length; +} + +/*! + Returns the validation path length of the certificate. +*/ +int QOpcUaX509ExtensionBasicConstraints::pathLength() const +{ + const QOpcUaX509ExtensionBasicConstraintsData *d = static_cast(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 + +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 + +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 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(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(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 + +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(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 + +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 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(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(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 + +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(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 > 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(data.data()); + d->entries.append(qMakePair(type, value)); +} + +/*! + Returns the vector of entries. +*/ +const QVector> &QOpcUaX509ExtensionSubjectAlternativeName::entries() const +{ + const QOpcUaX509ExtensionSubjectAlternativeNameData *d = static_cast(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 + +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> &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 +#include + +QT_BEGIN_NAMESPACE + +template +class Deleter +{ +public: + Deleter(T *data, std::function 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 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 +** 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 + +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 +#include #include 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define defineDataMethod(name) void name()\ +{\ + QTest::addColumn("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 -- cgit v1.2.3