diff options
author | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-02-19 12:07:12 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-02-21 19:57:22 +0000 |
commit | c484e7ee6e52652cb7d40112f104cb63d344445a (patch) | |
tree | 35fe60f89a33fb7f1fc9ef0ba2be59fb0593b007 | |
parent | 4924c53134fc89ac32c3a87f571baea296b7504e (diff) |
Prepare SSL implementation for different backends
Change-Id: I1591c896edba85ee274d19b9ecfff17be0d7c663
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r-- | src/knx/ssl/qknxcryptographicengine.cpp | 132 | ||||
-rw-r--r-- | src/knx/ssl/qknxssl_openssl.cpp | 176 | ||||
-rw-r--r-- | src/knx/ssl/qknxssl_p.h | 59 | ||||
-rw-r--r-- | src/knx/ssl/ssl.pri | 6 |
4 files changed, 246 insertions, 127 deletions
diff --git a/src/knx/ssl/qknxcryptographicengine.cpp b/src/knx/ssl/qknxcryptographicengine.cpp index 2032cd9..371aba3 100644 --- a/src/knx/ssl/qknxcryptographicengine.cpp +++ b/src/knx/ssl/qknxcryptographicengine.cpp @@ -35,89 +35,15 @@ #include "qknxnetipsessionstatus.h" #include "qknxnetiptimernotify.h" +#include "private/qknxssl_p.h" + #include <QtCore/qcryptographichash.h> #include <QtCore/qmutex.h> #include <QtNetwork/qpassworddigestor.h> -#include <QtNetwork/private/qtnetworkglobal_p.h> - -#if QT_CONFIG(opensslv11) -# include <QtKnx/private/qsslsocket_openssl_symbols_p.h> -# include <QtKnx/private/qsslsocket_openssl11_symbols_p.h> -#endif QT_BEGIN_NAMESPACE -class QKnxOpenSsl -{ -public: - static bool supportsSsl(); - static long sslLibraryVersionNumber(); - -protected: - static bool ensureLibraryLoaded(); - -private: - static bool s_libraryLoaded; - static bool s_libraryEnabled; -}; -bool QKnxOpenSsl::s_libraryLoaded = false; -bool QKnxOpenSsl::s_libraryEnabled = false; - -Q_GLOBAL_STATIC(QKnxOpenSsl, qt_QKnxOpenSsl) -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_knxOpenSslInitMutex, (QMutex::Recursive)) - -/*! - \internal -*/ -bool QKnxOpenSsl::supportsSsl() -{ -#if QT_CONFIG(opensslv11) - if (!q_resolveOpenSslSymbols()) - return false; - - const QMutexLocker locker(qt_knxOpenSslInitMutex); - if (!s_libraryLoaded) { - s_libraryLoaded = true; - - // Initialize OpenSSL. - if (q_OPENSSL_init_ssl(0, nullptr) != 1) - return false; - q_SSL_load_error_strings(); - q_OpenSSL_add_all_algorithms(); - - // Initialize OpenSSL's random seed. - if (!q_RAND_status()) { - qWarning("Random number generator not seeded, disabling SSL support"); - return false; - } - - if (q_EVP_PKEY_type(NID_X25519) == NID_undef) { - qWarning("The X25519 algorithm is not supported, disabling SSL support"); - return false; - } - s_libraryEnabled = true; - } - return s_libraryEnabled; -#else - Q_UNUSED(qt_knxOpenSslInitMutex) - return false; -#endif -} - -/*! - \internal -*/ -long QKnxOpenSsl::sslLibraryVersionNumber() -{ -#if QT_CONFIG(opensslv11) - if (supportsSsl()) - return q_OpenSSL_version_num(); -#endif - return 0; -} - - /*! \class QKnxCryptographicEngine @@ -238,7 +164,7 @@ long QKnxOpenSsl::sslLibraryVersionNumber() */ bool QKnxCryptographicEngine::supportsCryptography() { - return qt_QKnxOpenSsl->supportsSsl(); + return QKnxSsl::supportsCryptography(); } /* @@ -248,7 +174,7 @@ bool QKnxCryptographicEngine::supportsCryptography() */ long QKnxCryptographicEngine::sslLibraryVersionNumber() { - return qt_QKnxOpenSsl->sslLibraryVersionNumber(); + return QKnxSsl::sslLibraryVersionNumber(); } /*! @@ -340,50 +266,6 @@ namespace QKnxPrivate return QKnxPrivate::b0(sequence, serial, tag, 0xff00); } - static QKnxByteArray encrypt(const QKnxByteArray &key, const QKnxByteArray &data) - { -#if QT_CONFIG(opensslv11) - if (!qt_QKnxOpenSsl->supportsSsl()) - return {}; - - QSharedPointer<EVP_CIPHER_CTX> ctxPtr(q_EVP_CIPHER_CTX_new(), q_EVP_CIPHER_CTX_free); - if (ctxPtr.isNull()) - return {}; - q_EVP_CIPHER_CTX_reset(ctxPtr.data()); - - const auto ctx = ctxPtr.data(); - const auto c = q_EVP_aes_128_cbc(); - if (q_EVP_CipherInit_ex(ctx, c, nullptr, nullptr, nullptr, 0x01) <= 0) - return {}; - - if (q_EVP_CIPHER_CTX_set_padding(ctx, 0) <= 0) - return {}; - - Q_ASSERT(q_EVP_CIPHER_CTX_iv_length(ctx) == 16); - Q_ASSERT(q_EVP_CIPHER_CTX_key_length(ctx) == 16); - - static const quint8 iv[16] { 0x00 }; - if (q_EVP_CipherInit_ex(ctx, nullptr, nullptr, key.constData(), iv, 0x01) <= 0) - return {}; - - int outl, offset = 0; - QKnxByteArray out(data.size() + q_EVP_CIPHER_block_size(c), 0x00); - if (q_EVP_CipherUpdate(ctx, out.data(), &outl, data.constData(), data.size()) <= 0) - return {}; - offset += outl; - - if (q_EVP_CipherFinal_ex(ctx, out.data() + offset, &outl) <= 0) - return {}; - offset += outl; - - return out.mid(offset - 16, 16); -#else - Q_UNUSED(key) - Q_UNUSED(data) - return {}; -#endif - } - static QKnxByteArray processMAC(const QKnxByteArray &key, const QKnxByteArray &mac, quint48 sequenceNumber, const QKnxByteArray &serialNumber, quint16 messageTag) { @@ -393,7 +275,7 @@ namespace QKnxPrivate auto Ctr0 = QKnxPrivate::ctr0(sequenceNumber, (serialNumber.isEmpty() ? QKnxByteArray(6, 0x00) : serialNumber), messageTag); - return QKnxCryptographicEngine::XOR(QKnxPrivate::encrypt(key, Ctr0), mac); + return QKnxCryptographicEngine::XOR(QKnxSsl::encrypt(key, Ctr0), mac); } static QKnxByteArray processPayload(const QKnxByteArray &key, const QKnxByteArray &payload, @@ -408,7 +290,7 @@ namespace QKnxPrivate QKnxByteArray ctrArray; for (int i = 0; i < (payload.size() + 15) >> 4; ++i) { Ctr0.set(15, Ctr0.at(15) + 1); - ctrArray += QKnxPrivate::encrypt(key, Ctr0); + ctrArray += QKnxSsl::encrypt(key, Ctr0); } return QKnxCryptographicEngine::XOR(ctrArray, payload, false); @@ -464,7 +346,7 @@ QKnxByteArray QKnxCryptographicEngine::computeMessageAuthenticationCode(const QK return {}; B.resize(B.size() + (16 - (B.size() % 16))); // pad to multiple of 16 - return QKnxPrivate::encrypt(key, B); + return QKnxSsl::encrypt(key, B); } /*! diff --git a/src/knx/ssl/qknxssl_openssl.cpp b/src/knx/ssl/qknxssl_openssl.cpp new file mode 100644 index 0000000..2344cf5 --- /dev/null +++ b/src/knx/ssl/qknxssl_openssl.cpp @@ -0,0 +1,176 @@ +/****************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtKnx module. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ + +#include "qknxssl_p.h" + +#include <private/qtnetworkglobal_p.h> + +#if QT_CONFIG(opensslv11) +# include "private/qsslsocket_openssl_symbols_p.h" +# include "private/qsslsocket_openssl11_symbols_p.h" +#endif + +#include <QtCore/qmutex.h> + +QT_BEGIN_NAMESPACE + +class QKnxOpenSsl +{ +public: + static bool supportsSsl(); + static long sslLibraryVersionNumber(); + +protected: + static bool ensureLibraryLoaded(); + +private: + static bool s_libraryLoaded; + static bool s_libraryEnabled; +}; + +bool QKnxOpenSsl::s_libraryLoaded = false; +bool QKnxOpenSsl::s_libraryEnabled = false; + +Q_GLOBAL_STATIC(QKnxOpenSsl, qt_QKnxOpenSsl) +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_knxOpenSslInitMutex, (QMutex::Recursive)) + +/*! + \internal +*/ +bool QKnxOpenSsl::supportsSsl() +{ +#if QT_CONFIG(opensslv11) + if (!q_resolveOpenSslSymbols()) + return false; + + const QMutexLocker locker(qt_knxOpenSslInitMutex); + if (!s_libraryLoaded) { + s_libraryLoaded = true; + + // Initialize OpenSSL. + if (q_OPENSSL_init_ssl(0, nullptr) != 1) + return false; + q_SSL_load_error_strings(); + q_OpenSSL_add_all_algorithms(); + + // Initialize OpenSSL's random seed. + if (!q_RAND_status()) { + qWarning("Random number generator not seeded, disabling SSL support"); + return false; + } + + if (q_EVP_PKEY_type(NID_X25519) == NID_undef) { + qWarning("The X25519 algorithm is not supported, disabling SSL support"); + return false; + } + s_libraryEnabled = true; + } + return s_libraryEnabled; +#else + Q_UNUSED(qt_knxOpenSslInitMutex) + return false; +#endif +} + +/*! + \internal +*/ +long QKnxOpenSsl::sslLibraryVersionNumber() +{ +#if QT_CONFIG(opensslv11) + if (supportsSsl()) + return q_OpenSSL_version_num(); +#endif + return 0; +} + +/*! + \internal +*/ +bool QKnxSsl::supportsCryptography() +{ + return qt_QKnxOpenSsl->supportsSsl(); +} + +/*! + \internal +*/ +long QKnxSsl::sslLibraryVersionNumber() +{ + return qt_QKnxOpenSsl->sslLibraryVersionNumber(); +} + +/*! + \internal +*/ +QKnxByteArray QKnxSsl::encrypt(const QKnxByteArray &key, const QKnxByteArray &data) +{ +#if QT_CONFIG(opensslv11) + if (!qt_QKnxOpenSsl->supportsSsl()) + return {}; + + QSharedPointer<EVP_CIPHER_CTX> ctxPtr(q_EVP_CIPHER_CTX_new(), q_EVP_CIPHER_CTX_free); + if (ctxPtr.isNull()) + return {}; + q_EVP_CIPHER_CTX_reset(ctxPtr.data()); + + const auto ctx = ctxPtr.data(); + const auto c = q_EVP_aes_128_cbc(); + if (q_EVP_CipherInit_ex(ctx, c, nullptr, nullptr, nullptr, 0x01) <= 0) + return {}; + + if (q_EVP_CIPHER_CTX_set_padding(ctx, 0) <= 0) + return {}; + + Q_ASSERT(q_EVP_CIPHER_CTX_iv_length(ctx) == 16); + Q_ASSERT(q_EVP_CIPHER_CTX_key_length(ctx) == 16); + + static const quint8 iv[16] { 0x00 }; + if (q_EVP_CipherInit_ex(ctx, nullptr, nullptr, key.constData(), iv, 0x01) <= 0) + return {}; + + int outl, offset = 0; + QKnxByteArray out(data.size() + q_EVP_CIPHER_block_size(c), 0x00); + if (q_EVP_CipherUpdate(ctx, out.data(), &outl, data.constData(), data.size()) <= 0) + return {}; + offset += outl; + + if (q_EVP_CipherFinal_ex(ctx, out.data() + offset, &outl) <= 0) + return {}; + offset += outl; + + return out.mid(offset - 16, 16); +#else + Q_UNUSED(key) + Q_UNUSED(data) + return {}; +#endif +} + +QT_END_NAMESPACE diff --git a/src/knx/ssl/qknxssl_p.h b/src/knx/ssl/qknxssl_p.h new file mode 100644 index 0000000..860048c --- /dev/null +++ b/src/knx/ssl/qknxssl_p.h @@ -0,0 +1,59 @@ +/****************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtKnx module. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) 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.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-3.0.html. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ + +#ifndef QKNXSSL_P_H +#define QKNXSSL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt KNX API. It exists for the convenience +// of the Qt KNX implementation. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtKnx/qknxbytearray.h> + +QT_BEGIN_NAMESPACE + +class QKnxSsl +{ +public: + static bool supportsCryptography(); + static long sslLibraryVersionNumber(); + + static QKnxByteArray encrypt(const QKnxByteArray &key, const QKnxByteArray &data); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/knx/ssl/ssl.pri b/src/knx/ssl/ssl.pri index a4318a1..112d7fb 100644 --- a/src/knx/ssl/ssl.pri +++ b/src/knx/ssl/ssl.pri @@ -1,11 +1,13 @@ HEADERS += ssl/qknxcryptographicengine.h \ ssl/qknxsecurekey.h \ ssl/qknxsecureconfiguration.h \ - ssl/qknxsecureconfiguration_p.h + ssl/qknxsecureconfiguration_p.h \ + ssl/qknxssl_p.h SOURCES += ssl/qknxcryptographicengine.cpp \ ssl/qknxsecurekey.cpp \ - ssl/qknxsecureconfiguration.cpp + ssl/qknxsecureconfiguration.cpp \ + ssl/qknxssl_openssl.cpp qtConfig(opensslv11) { # OpenSSL 1.1 support is required. SOURCES += ssl/qsslsocket_openssl_symbols.cpp |