summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2021-03-25 12:41:08 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2021-04-22 22:51:54 +0200
commitd385158d5213ef568b7629e2aa4a818016bbffac (patch)
tree2c111b462fe39dffacb3c7f5cdd8db269f87ed6c /src/network/ssl
parent6b1a7341fed4b9456ea6bfa2de7412d45ef56c65 (diff)
Move plugin code from QtNetwork to qtbase/plugins
All TLS (and non-TLS) backends that QSsl classes rely on are now in plugins/tls (as openssl, securetransport, schannel and certonly plugins). For now, I have to disable some tests that were using OpenSSL calls - this to be refactored/re-thought. These include: qsslsocket auto-test (test-case where we work with private keys), qsslkey auto-test (similar to qsslsocket - test-case working with keys using OpenSSL calls). qasn1element moved to plugins too, so its auto-test have to be re-thought. Since now we can have more than one working TLS-backend on a given platform, the presence of OpenSSL also means I force this backend as active before running tests, to make sure features implemented only in OpenSSL-backend are tested. OCSP auto test is disabled for now, since it heavily relies on OpenSSL symbols (to be refactored). [ChangeLog][QtNetwork][QSslSocket] QSslSocket by default prefers 'openssl' backend if it is available. [ChangeLog][QtNetwork][QSslSocket] TLS-backends are not mutually exclusive anymore, depending on a platform, more than one TLS backend can be built. E.g., configuring Qt with -openssl does not prevent SecureTransport or Schannel plugin from being built. Fixes: QTBUG-91928 Change-Id: I4c05e32f10179066bee3a518bdfdd6c4b15320c3 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qasn1element.cpp400
-rw-r--r--src/network/ssl/qasn1element_p.h188
-rw-r--r--src/network/ssl/qdtls_base.cpp112
-rw-r--r--src/network/ssl/qdtls_base_p.h115
-rw-r--r--src/network/ssl/qdtls_openssl.cpp1451
-rw-r--r--src/network/ssl/qdtls_openssl_p.h251
-rw-r--r--src/network/ssl/qopenssl.cpp71
-rw-r--r--src/network/ssl/qopenssl_p.h117
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp824
-rw-r--r--src/network/ssl/qsslcontext_openssl_p.h132
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_openssl.cpp230
-rw-r--r--src/network/ssl/qsslkey_p.cpp4
-rw-r--r--src/network/ssl/qsslkey_p.h4
-rw-r--r--src/network/ssl/qsslsocket.cpp2
-rw-r--r--src/network/ssl/qsslsocket_mac_shared.cpp148
-rw-r--r--src/network/ssl/qsslsocket_openssl_android.cpp93
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp1234
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h761
-rw-r--r--src/network/ssl/qsslsocket_p.h5
-rw-r--r--src/network/ssl/qsslsocket_qt.cpp309
-rw-r--r--src/network/ssl/qtls_openssl.cpp1837
-rw-r--r--src/network/ssl/qtls_openssl_p.h169
-rw-r--r--src/network/ssl/qtls_schannel.cpp2322
-rw-r--r--src/network/ssl/qtls_schannel_p.h159
-rw-r--r--src/network/ssl/qtls_st.cpp1331
-rw-r--r--src/network/ssl/qtls_st_p.h141
-rw-r--r--src/network/ssl/qtlsbackend.cpp47
-rw-r--r--src/network/ssl/qtlsbackend_cert.cpp96
-rw-r--r--src/network/ssl/qtlsbackend_cert_p.h83
-rw-r--r--src/network/ssl/qtlsbackend_openssl.cpp630
-rw-r--r--src/network/ssl/qtlsbackend_openssl_p.h134
-rw-r--r--src/network/ssl/qtlsbackend_p.h6
-rw-r--r--src/network/ssl/qtlsbackend_schannel_p.h100
-rw-r--r--src/network/ssl/qtlsbackend_st.cpp341
-rw-r--r--src/network/ssl/qtlsbackend_st_p.h94
-rw-r--r--src/network/ssl/qtlskey_base.cpp133
-rw-r--r--src/network/ssl/qtlskey_base_p.h112
-rw-r--r--src/network/ssl/qtlskey_generic.cpp884
-rw-r--r--src/network/ssl/qtlskey_generic_p.h117
-rw-r--r--src/network/ssl/qtlskey_openssl.cpp509
-rw-r--r--src/network/ssl/qtlskey_openssl_p.h126
-rw-r--r--src/network/ssl/qtlskey_schannel.cpp187
-rw-r--r--src/network/ssl/qtlskey_schannel_p.h82
-rw-r--r--src/network/ssl/qtlskey_st.cpp110
-rw-r--r--src/network/ssl/qtlskey_st_p.h83
-rw-r--r--src/network/ssl/qwincrypt_p.h81
-rw-r--r--src/network/ssl/qwindowscarootfetcher.cpp292
-rw-r--r--src/network/ssl/qwindowscarootfetcher_p.h95
-rw-r--r--src/network/ssl/qx509_base.cpp178
-rw-r--r--src/network/ssl/qx509_base_p.h125
-rw-r--r--src/network/ssl/qx509_generic.cpp467
-rw-r--r--src/network/ssl/qx509_generic_p.h101
-rw-r--r--src/network/ssl/qx509_openssl.cpp929
-rw-r--r--src/network/ssl/qx509_openssl_p.h133
-rw-r--r--src/network/ssl/qx509_schannel.cpp87
-rw-r--r--src/network/ssl/qx509_schannel_p.h87
-rw-r--r--src/network/ssl/qx509_st.cpp61
-rw-r--r--src/network/ssl/qx509_st_p.h74
58 files changed, 42 insertions, 18952 deletions
diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp
deleted file mode 100644
index 3df76c3774..0000000000
--- a/src/network/ssl/qasn1element.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qlist.h>
-#include <QDebug>
-
-#include <limits>
-
-QT_BEGIN_NAMESPACE
-
-typedef QMap<QByteArray, QByteArray> OidNameMap;
-static OidNameMap createOidMap()
-{
- OidNameMap oids;
- // used by unit tests
- oids.insert(oids.cend(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP"));
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
- oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
- return oids;
-}
-Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
-
-QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
- : mType(type)
- , mValue(value)
-{
-}
-
-bool QAsn1Element::read(QDataStream &stream)
-{
- // type
- quint8 tmpType;
- stream >> tmpType;
- if (!tmpType)
- return false;
-
- // length
- quint64 length = 0;
- quint8 first;
- stream >> first;
- if (first & 0x80) {
- // long form
- const quint8 bytes = (first & 0x7f);
- if (bytes > 7)
- return false;
-
- quint8 b;
- for (int i = 0; i < bytes; i++) {
- stream >> b;
- length = (length << 8) | b;
- }
- } else {
- // short form
- length = (first & 0x7f);
- }
-
- if (length > quint64(std::numeric_limits<int>::max()))
- return false;
-
- // read value in blocks to avoid being fooled by incorrect length
- const int BUFFERSIZE = 4 * 1024;
- QByteArray tmpValue;
- int remainingLength = length;
- while (remainingLength) {
- char readBuffer[BUFFERSIZE];
- const int bytesToRead = qMin(remainingLength, BUFFERSIZE);
- const int count = stream.readRawData(readBuffer, bytesToRead);
- if (count != int(bytesToRead))
- return false;
- tmpValue.append(readBuffer, bytesToRead);
- remainingLength -= bytesToRead;
- }
-
- mType = tmpType;
- mValue.swap(tmpValue);
- return true;
-}
-
-bool QAsn1Element::read(const QByteArray &data)
-{
- QDataStream stream(data);
- return read(stream);
-}
-
-void QAsn1Element::write(QDataStream &stream) const
-{
- // type
- stream << mType;
-
- // length
- qint64 length = mValue.size();
- if (length >= 128) {
- // long form
- quint8 encodedLength = 0x80;
- QByteArray ba;
- while (length) {
- ba.prepend(quint8((length & 0xff)));
- length >>= 8;
- encodedLength += 1;
- }
- stream << encodedLength;
- stream.writeRawData(ba.data(), ba.size());
- } else {
- // short form
- stream << quint8(length);
- }
-
- // value
- stream.writeRawData(mValue.data(), mValue.size());
-}
-
-QAsn1Element QAsn1Element::fromBool(bool val)
-{
- return QAsn1Element(QAsn1Element::BooleanType,
- QByteArray(1, val ? 0xff : 0x00));
-}
-
-QAsn1Element QAsn1Element::fromInteger(unsigned int val)
-{
- QAsn1Element elem(QAsn1Element::IntegerType);
- while (val > 127) {
- elem.mValue.prepend(val & 0xff);
- val >>= 8;
- }
- elem.mValue.prepend(val & 0x7f);
- return elem;
-}
-
-QAsn1Element QAsn1Element::fromVector(const QList<QAsn1Element> &items)
-{
- QAsn1Element seq;
- seq.mType = SequenceType;
- QDataStream stream(&seq.mValue, QDataStream::WriteOnly);
- for (auto it = items.cbegin(), end = items.cend(); it != end; ++it)
- it->write(stream);
- return seq;
-}
-
-QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
-{
- QAsn1Element elem;
- elem.mType = ObjectIdentifierType;
- const QList<QByteArray> bits = id.split('.');
- Q_ASSERT(bits.size() > 2);
- elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
- for (int i = 2; i < bits.size(); ++i) {
- char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
- char *pBuffer = buffer + sizeof(buffer);
- *--pBuffer = '\0';
- unsigned int node = bits[i].toUInt();
- *--pBuffer = quint8((node & 0x7f));
- node >>= 7;
- while (node) {
- *--pBuffer = quint8(((node & 0x7f) | 0x80));
- node >>= 7;
- }
- elem.mValue += pBuffer;
- }
- return elem;
-}
-
-bool QAsn1Element::toBool(bool *ok) const
-{
- if (*this == fromBool(true)) {
- if (ok)
- *ok = true;
- return true;
- } else if (*this == fromBool(false)) {
- if (ok)
- *ok = true;
- return false;
- } else {
- if (ok)
- *ok = false;
- return false;
- }
-}
-
-QDateTime QAsn1Element::toDateTime() const
-{
- QDateTime result;
-
- if (mValue.size() != 13 && mValue.size() != 15)
- return result;
-
- // QDateTime::fromString is lenient and accepts +- signs in front
- // of the year; but ASN.1 doesn't allow them.
- const auto isAsciiDigit = [](char c)
- {
- return c >= '0' && c <= '9';
- };
-
- if (!isAsciiDigit(mValue[0]))
- return result;
-
- // Timezone must be present, and UTC
- if (mValue.back() != 'Z')
- return result;
-
- // In addition, check that we only have digits representing the
- // date/time. This should not really be necessary (there's no such
- // thing as negative months/days/etc.); it's a workaround for
- // QTBUG-84349.
- if (!std::all_of(mValue.begin(), mValue.end() - 1, isAsciiDigit))
- return result;
-
- if (mType == UtcTimeType && mValue.size() == 13) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyMMddHHmmsst"));
- if (!result.isValid())
- return result;
-
- Q_ASSERT(result.timeSpec() == Qt::UTC);
-
- QDate date = result.date();
-
- // RFC 2459:
- // Where YY is greater than or equal to 50, the year shall be
- // interpreted as 19YY; and
- //
- // Where YY is less than 50, the year shall be interpreted as 20YY.
- //
- // QDateTime interprets the 'yy' format as 19yy, so we may need to adjust
- // the year (bring it in the [1950, 2049] range).
- if (date.year() < 1950)
- result.setDate(date.addYears(100));
-
- Q_ASSERT(result.date().year() >= 1950);
- Q_ASSERT(result.date().year() <= 2049);
- } else if (mType == GeneralizedTimeType && mValue.size() == 15) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyyyMMddHHmmsst"));
- }
-
- return result;
-}
-
-QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
-{
- QMultiMap<QByteArray, QString> info;
- QAsn1Element elem;
- QDataStream issuerStream(mValue);
- while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
- QAsn1Element issuerElem;
- QDataStream setStream(elem.mValue);
- if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
- const auto elems = issuerElem.toList();
- if (elems.size() == 2) {
- const QByteArray key = elems.front().toObjectName();
- if (!key.isEmpty())
- info.insert(key, elems.back().toString());
- }
- }
- }
- return info;
-}
-
-qint64 QAsn1Element::toInteger(bool *ok) const
-{
- if (mType != QAsn1Element::IntegerType || mValue.isEmpty()) {
- if (ok)
- *ok = false;
- return 0;
- }
-
- // NOTE: - negative numbers are not handled
- // - greater sizes would overflow
- if (mValue.at(0) & 0x80 || mValue.size() > 8) {
- if (ok)
- *ok = false;
- return 0;
- }
-
- qint64 value = mValue.at(0) & 0x7f;
- for (int i = 1; i < mValue.size(); ++i)
- value = (value << 8) | quint8(mValue.at(i));
-
- if (ok)
- *ok = true;
- return value;
-}
-
-QList<QAsn1Element> QAsn1Element::toList() const
-{
- QList<QAsn1Element> items;
- if (mType == SequenceType) {
- QAsn1Element elem;
- QDataStream stream(mValue);
- while (elem.read(stream))
- items << elem;
- }
- return items;
-}
-
-QByteArray QAsn1Element::toObjectId() const
-{
- QByteArray key;
- if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
- quint8 b = mValue.at(0);
- key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
- unsigned int val = 0;
- for (int i = 1; i < mValue.size(); ++i) {
- b = mValue.at(i);
- val = (val << 7) | (b & 0x7f);
- if (!(b & 0x80)) {
- key += '.' + QByteArray::number(val);
- val = 0;
- }
- }
- }
- return key;
-}
-
-QByteArray QAsn1Element::toObjectName() const
-{
- QByteArray key = toObjectId();
- return oidNameMap->value(key, key);
-}
-
-QString QAsn1Element::toString() const
-{
- // Detect embedded NULs and reject
- if (qstrlen(mValue) < uint(mValue.size()))
- return QString();
-
- if (mType == PrintableStringType || mType == TeletexStringType
- || mType == Rfc822NameType || mType == DnsNameType
- || mType == UniformResourceIdentifierType)
- return QString::fromLatin1(mValue, mValue.size());
- if (mType == Utf8StringType)
- return QString::fromUtf8(mValue, mValue.size());
-
- return QString();
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
deleted file mode 100644
index 48fe45c9a5..0000000000
--- a/src/network/ssl/qasn1element_p.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#ifndef QASN1ELEMENT_P_H
-#define QASN1ELEMENT_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmap.h>
-
-QT_BEGIN_NAMESPACE
-
-// General
-#define RSADSI_OID "1.2.840.113549."
-
-#define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1")
-#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
-#define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1")
-#define DH_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.3.1")
-
-// These are mostly from the RFC for PKCS#5
-// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
-#define PKCS5_OID RSADSI_OID "1.5."
-// PKCS#12: https://tools.ietf.org/html/rfc7292#appendix-D)
-#define PKCS12_OID RSADSI_OID "1.12."
-
-// -PBES1
-#define PKCS5_MD2_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "1") // Not (yet) implemented
-#define PKCS5_MD2_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "4") // Not (yet) implemented
-#define PKCS5_MD5_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "3")
-#define PKCS5_MD5_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "6")
-#define PKCS5_SHA1_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "10")
-#define PKCS5_SHA1_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "11")
-#define PKCS12_SHA1_RC4_128_OID QByteArrayLiteral(PKCS12_OID "1.1") // Not (yet) implemented
-#define PKCS12_SHA1_RC4_40_OID QByteArrayLiteral(PKCS12_OID "1.2") // Not (yet) implemented
-#define PKCS12_SHA1_3KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.3")
-#define PKCS12_SHA1_2KEY_3DES_CBC_OID QByteArrayLiteral(PKCS12_OID "1.4")
-#define PKCS12_SHA1_RC2_128_CBC_OID QByteArrayLiteral(PKCS12_OID "1.5")
-#define PKCS12_SHA1_RC2_40_CBC_OID QByteArrayLiteral(PKCS12_OID "1.6")
-
-// -PBKDF2
-#define PKCS5_PBKDF2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "12")
-
-// -PBES2
-#define PKCS5_PBES2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "13")
-
-// Digest
-#define DIGEST_ALGORITHM_OID RSADSI_OID "2."
-// -HMAC-SHA-1
-#define HMAC_WITH_SHA1 QByteArrayLiteral(DIGEST_ALGORITHM_OID "7")
-// -HMAC-SHA-2
-#define HMAC_WITH_SHA224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "8")
-#define HMAC_WITH_SHA256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "9")
-#define HMAC_WITH_SHA384 QByteArrayLiteral(DIGEST_ALGORITHM_OID "10")
-#define HMAC_WITH_SHA512 QByteArrayLiteral(DIGEST_ALGORITHM_OID "11")
-#define HMAC_WITH_SHA512_224 QByteArrayLiteral(DIGEST_ALGORITHM_OID "12")
-#define HMAC_WITH_SHA512_256 QByteArrayLiteral(DIGEST_ALGORITHM_OID "13")
-
-// Encryption algorithms
-#define ENCRYPTION_ALGORITHM_OID RSADSI_OID "3."
-#define DES_CBC_ENCRYPTION_OID QByteArrayLiteral("1.3.14.3.2.7")
-#define DES_EDE3_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "7")
-#define RC2_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "2")
-#define RC5_CBC_ENCRYPTION_OID QByteArrayLiteral(ENCRYPTION_ALGORITHM_OID "9") // Not (yet) implemented
-#define AES_OID "2.16.840.1.101.3.4.1."
-#define AES128_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "2")
-#define AES192_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "22") // Not (yet) implemented
-#define AES256_CBC_ENCRYPTION_OID QByteArrayLiteral(AES_OID "42") // Not (yet) implemented
-
-class Q_AUTOTEST_EXPORT QAsn1Element
-{
-public:
- enum ElementType {
- // universal
- BooleanType = 0x01,
- IntegerType = 0x02,
- BitStringType = 0x03,
- OctetStringType = 0x04,
- NullType = 0x05,
- ObjectIdentifierType = 0x06,
- Utf8StringType = 0x0c,
- PrintableStringType = 0x13,
- TeletexStringType = 0x14,
- UtcTimeType = 0x17,
- GeneralizedTimeType = 0x18,
- SequenceType = 0x30,
- SetType = 0x31,
-
- // GeneralNameTypes
- Rfc822NameType = 0x81,
- DnsNameType = 0x82,
- UniformResourceIdentifierType = 0x86,
- IpAddressType = 0x87,
-
- // context specific
- Context0Type = 0xA0,
- Context1Type = 0xA1,
- Context3Type = 0xA3
- };
-
- explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
- bool read(QDataStream &data);
- bool read(const QByteArray &data);
- void write(QDataStream &data) const;
-
- static QAsn1Element fromBool(bool val);
- static QAsn1Element fromInteger(unsigned int val);
- static QAsn1Element fromVector(const QList<QAsn1Element> &items);
- static QAsn1Element fromObjectId(const QByteArray &id);
-
- bool toBool(bool *ok = nullptr) const;
- QDateTime toDateTime() const;
- QMultiMap<QByteArray, QString> toInfo() const;
- qint64 toInteger(bool *ok = nullptr) const;
- QList<QAsn1Element> toList() const;
- QByteArray toObjectId() const;
- QByteArray toObjectName() const;
- QString toString() const;
-
- quint8 type() const { return mType; }
- QByteArray value() const { return mValue; }
-
- friend inline bool operator==(const QAsn1Element &, const QAsn1Element &);
- friend inline bool operator!=(const QAsn1Element &, const QAsn1Element &);
-
-private:
- quint8 mType;
- QByteArray mValue;
-};
-Q_DECLARE_TYPEINFO(QAsn1Element, Q_RELOCATABLE_TYPE);
-
-inline bool operator==(const QAsn1Element &e1, const QAsn1Element &e2)
-{ return e1.mType == e2.mType && e1.mValue == e2.mValue; }
-
-inline bool operator!=(const QAsn1Element &e1, const QAsn1Element &e2)
-{ return e1.mType != e2.mType || e1.mValue != e2.mValue; }
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qdtls_base.cpp b/src/network/ssl/qdtls_base.cpp
deleted file mode 100644
index 6a5979eb9e..0000000000
--- a/src/network/ssl/qdtls_base.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qdtls_base_p.h"
-
-QT_BEGIN_NAMESPACE
-
-void QDtlsBasePrivate::setDtlsError(QDtlsError code, const QString &description)
-{
- errorCode = code;
- errorDescription = description;
-}
-
-QDtlsError QDtlsBasePrivate::error() const
-{
- return errorCode;
-}
-
-QString QDtlsBasePrivate::errorString() const
-{
- return errorDescription;
-}
-
-void QDtlsBasePrivate::clearDtlsError()
-{
- errorCode = QDtlsError::NoError;
- errorDescription.clear();
-}
-
-QSslConfiguration QDtlsBasePrivate::configuration() const
-{
- return dtlsConfiguration;
-}
-
-void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
-{
- dtlsConfiguration = configuration;
- clearDtlsError();
-}
-
-bool QDtlsBasePrivate::setCookieGeneratorParameters(const GenParams &params)
-{
- if (!params.secret.size()) {
- setDtlsError(QDtlsError::InvalidInputParameters,
- QDtls::tr("Invalid (empty) secret"));
- return false;
- }
-
- clearDtlsError();
-
- hashAlgorithm = params.hash;
- secret = params.secret;
-
- return true;
-}
-
-QDtlsClientVerifier::GeneratorParameters
-QDtlsBasePrivate::cookieGeneratorParameters() const
-{
- return {hashAlgorithm, secret};
-}
-
-bool QDtlsBasePrivate::isDtlsProtocol(QSsl::SslProtocol protocol)
-{
- switch (protocol) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
- return true;
- default:
- return false;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qdtls_base_p.h b/src/network/ssl/qdtls_base_p.h
deleted file mode 100644
index df35f514a2..0000000000
--- a/src/network/ssl/qdtls_base_p.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QDTLS_BASE_P_H
-#define QDTLS_BASE_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-QT_REQUIRE_CONFIG(dtls);
-
-#include "qsslconfiguration.h"
-#include "qtlsbackend_p.h"
-#include "qsslcipher.h"
-#include "qsslsocket.h"
-#include "qssl.h"
-
-#include <QtNetwork/qhostaddress.h>
-
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qstring.h>
-
-QT_BEGIN_NAMESPACE
-
-// This class exists to re-implement the shared error/cookie handling
-// for both QDtls and QDtlsClientVerifier classes. Use it if/when
-// you need it. Backend neutral.
-class QDtlsBasePrivate : virtual public QTlsPrivate::DtlsBase
-{
-public:
- QDtlsBasePrivate(QSslSocket::SslMode m, const QByteArray &s) : mode(m), secret(s) {}
- void setDtlsError(QDtlsError code, const QString &description) override;
- QDtlsError error() const override;
- QString errorString() const override;
- void clearDtlsError() override;
-
- void setConfiguration(const QSslConfiguration &configuration) override;
- QSslConfiguration configuration() const override;
-
- bool setCookieGeneratorParameters(const GenParams &) override;
- GenParams cookieGeneratorParameters() const override;
-
- static bool isDtlsProtocol(QSsl::SslProtocol protocol);
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
- quint16 mtuHint = 0;
-
- QDtlsError errorCode = QDtlsError::NoError;
- QString errorDescription;
- QSslConfiguration dtlsConfiguration;
- QSslSocket::SslMode mode = QSslSocket::SslClientMode;
- QSslCipher sessionCipher;
- QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
- QString peerVfyName;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif // QDTLS_BASE_P_H
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
deleted file mode 100644
index fe6c8013c7..0000000000
--- a/src/network/ssl/qdtls_openssl.cpp
+++ /dev/null
@@ -1,1451 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif // NOMINMAX
-#include "private/qnativesocketengine_p.h"
-
-#include "qsslpresharedkeyauthenticator_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslcertificate_p.h"
-#include "qdtls_openssl_p.h"
-#include "qx509_openssl_p.h"
-#include "qudpsocket.h"
-#include "qssl_p.h"
-
-#include "qmessageauthenticationcode.h"
-#include "qcryptographichash.h"
-
-#include "qdebug.h"
-
-#include <cstring>
-#include <cstddef>
-
-QT_BEGIN_NAMESPACE
-
-#define QT_DTLS_VERBOSE 0
-
-#if QT_DTLS_VERBOSE
-
-#define qDtlsWarning(arg) qWarning(arg)
-#define qDtlsDebug(arg) qDebug(arg)
-
-#else
-
-#define qDtlsWarning(arg)
-#define qDtlsDebug(arg)
-
-#endif // QT_DTLS_VERBOSE
-
-namespace dtlsutil
-{
-
-QByteArray cookie_for_peer(SSL *ssl)
-{
- Q_ASSERT(ssl);
-
- // SSL_get_rbio does not increment the reference count
- BIO *readBIO = q_SSL_get_rbio(ssl);
- if (!readBIO) {
- qCWarning(lcSsl, "No BIO (dgram) found in SSL object");
- return {};
- }
-
- auto listener = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(readBIO));
- if (!listener) {
- qCWarning(lcSsl, "BIO_get_app_data returned invalid (nullptr) value");
- return {};
- }
-
- const QHostAddress peerAddress(listener->remoteAddress);
- const quint16 peerPort(listener->remotePort);
- QByteArray peerData;
- if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) {
- const Q_IPV6ADDR sin6_addr(peerAddress.toIPv6Address());
- peerData.resize(int(sizeof sin6_addr + sizeof peerPort));
- char *dst = peerData.data();
- std::memcpy(dst, &peerPort, sizeof peerPort);
- dst += sizeof peerPort;
- std::memcpy(dst, &sin6_addr, sizeof sin6_addr);
- } else if (peerAddress.protocol() == QAbstractSocket::IPv4Protocol) {
- const quint32 sin_addr(peerAddress.toIPv4Address());
- peerData.resize(int(sizeof sin_addr + sizeof peerPort));
- char *dst = peerData.data();
- std::memcpy(dst, &peerPort, sizeof peerPort);
- dst += sizeof peerPort;
- std::memcpy(dst, &sin_addr, sizeof sin_addr);
- } else {
- Q_UNREACHABLE();
- }
-
- return peerData;
-}
-
-struct FallbackCookieSecret
-{
- FallbackCookieSecret()
- {
- key.resize(32);
- const int status = q_RAND_bytes(reinterpret_cast<unsigned char *>(key.data()),
- key.size());
- if (status <= 0)
- key.clear();
- }
-
- QByteArray key;
-
- Q_DISABLE_COPY_MOVE(FallbackCookieSecret)
-};
-
-QByteArray fallbackSecret()
-{
- static const FallbackCookieSecret generator;
- return generator.key;
-}
-
-int next_timeoutMs(SSL *tlsConnection)
-{
- Q_ASSERT(tlsConnection);
- timeval timeLeft = {};
- q_DTLSv1_get_timeout(tlsConnection, &timeLeft);
- return timeLeft.tv_sec * 1000;
-}
-
-
-void delete_connection(SSL *ssl)
-{
- // The 'deleter' for QSharedPointer<SSL>.
- if (ssl)
- q_SSL_free(ssl);
-}
-
-void delete_BIO_ADDR(BIO_ADDR *bio)
-{
- // A deleter for QSharedPointer<BIO_ADDR>
- if (bio)
- q_BIO_ADDR_free(bio);
-}
-
-void delete_bio_method(BIO_METHOD *method)
-{
- // The 'deleter' for QSharedPointer<BIO_METHOD>.
- if (method)
- q_BIO_meth_free(method);
-}
-
-// The path MTU discovery is non-trivial: it's a mix of getsockopt/setsockopt
-// (IP_MTU/IP6_MTU/IP_MTU_DISCOVER) and fallback MTU values. It's not
-// supported on all platforms, worse so - imposes specific requirements on
-// underlying UDP socket etc. So for now, we either try a user-proposed MTU
-// hint or rely on our own fallback value. As a fallback mtu OpenSSL uses 576
-// for IPv4 and 1280 for IPv6 (RFC 791, RFC 2460). To KIS we use 576. This
-// rather small MTU value does not affect the size that can be read/written
-// by QDtls, only a handshake (which is allowed to fragment).
-enum class MtuGuess : long
-{
- defaultMtu = 576
-};
-
-} // namespace dtlsutil
-
-namespace dtlscallbacks
-{
-
-extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
- unsigned *cookieLength)
-{
- if (!ssl || !dst || !cookieLength) {
- qCWarning(lcSsl,
- "Failed to generate cookie - invalid (nullptr) parameter(s)");
- return 0;
- }
-
- void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
- if (!generic) {
- qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, cannot generate cookie");
- return 0;
- }
-
- *cookieLength = 0;
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
- if (!dtls->secret.size())
- return 0;
-
- const QByteArray peerData(dtlsutil::cookie_for_peer(ssl));
- if (!peerData.size())
- return 0;
-
- QMessageAuthenticationCode hmac(dtls->hashAlgorithm, dtls->secret);
- hmac.addData(peerData);
- const QByteArray cookie = hmac.result();
- Q_ASSERT(cookie.size() >= 0);
- // DTLS1_COOKIE_LENGTH is erroneously 256 bytes long, must be 255 - RFC 6347, 4.2.1.
- *cookieLength = qMin(DTLS1_COOKIE_LENGTH - 1, cookie.size());
- std::memcpy(dst, cookie.constData(), *cookieLength);
-
- return 1;
-}
-
-extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
- unsigned cookieLength)
-{
- if (!ssl || !cookie || !cookieLength) {
- qCWarning(lcSsl, "Could not verify cookie, invalid (nullptr or zero) parameters");
- return 0;
- }
-
- unsigned char newCookie[DTLS1_COOKIE_LENGTH] = {};
- unsigned newCookieLength = 0;
- if (q_generate_cookie_callback(ssl, newCookie, &newCookieLength) != 1)
- return 0;
-
- return newCookieLength == cookieLength
- && !std::memcmp(cookie, newCookie, cookieLength);
-}
-
-extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
-{
- if (!ok) {
- // Store the error and at which depth the error was detected.
- SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
- if (!ssl) {
- qCWarning(lcSsl, "X509_STORE_CTX_get_ex_data returned nullptr, handshake failure");
- return 0;
- }
-
- void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
- if (!generic) {
- qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, handshake failure");
- return 0;
- }
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic);
- dtls->x509Errors.append(QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
- }
-
- // Always return 1 (OK) to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity,
- unsigned max_identity_len, unsigned char *psk,
- unsigned max_psk_len)
-{
- auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
- QTlsBackendOpenSSL::s_indexForSSLExtraData));
- if (!dtls)
- return 0;
-
- Q_ASSERT(dtls->dtlsPrivate);
- return dtls->dtlsPrivate->pskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
-}
-
-extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
- unsigned max_psk_len)
-{
- auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
- QTlsBackendOpenSSL::s_indexForSSLExtraData));
- if (!dtls)
- return 0;
-
- Q_ASSERT(dtls->dtlsPrivate);
- return dtls->dtlsPrivate->pskServerCallback(identity, psk, max_psk_len);
-}
-
-} // namespace dtlscallbacks
-
-namespace dtlsbio
-{
-
-extern "C" int q_dgram_read(BIO *bio, char *dst, int bytesToRead)
-{
- if (!bio || !dst || bytesToRead <= 0) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- q_BIO_clear_retry_flags(bio);
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- // It's us who set data, if OpenSSL does too, the logic here is wrong
- // then and we have to use BIO_set_app_data then!
- Q_ASSERT(dtls);
- int bytesRead = 0;
- if (dtls->dgram.size()) {
- bytesRead = qMin(dtls->dgram.size(), bytesToRead);
- std::memcpy(dst, dtls->dgram.constData(), bytesRead);
-
- if (!dtls->peeking)
- dtls->dgram = dtls->dgram.mid(bytesRead);
- } else {
- bytesRead = -1;
- }
-
- if (bytesRead <= 0)
- q_BIO_set_retry_read(bio);
-
- return bytesRead;
-}
-
-extern "C" int q_dgram_write(BIO *bio, const char *src, int bytesToWrite)
-{
- if (!bio || !src || bytesToWrite <= 0) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- q_BIO_clear_retry_flags(bio);
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- Q_ASSERT(dtls);
- if (dtls->writeSuppressed) {
- // See the comment in QDtls::startHandshake.
- return bytesToWrite;
- }
-
- QUdpSocket *udpSocket = dtls->udpSocket;
- Q_ASSERT(udpSocket);
-
- const QByteArray dgram(QByteArray::fromRawData(src, bytesToWrite));
- qint64 bytesWritten = -1;
- if (udpSocket->state() == QAbstractSocket::ConnectedState) {
- bytesWritten = udpSocket->write(dgram);
- } else {
- bytesWritten = udpSocket->writeDatagram(dgram, dtls->remoteAddress,
- dtls->remotePort);
- }
-
- if (bytesWritten <= 0)
- q_BIO_set_retry_write(bio);
-
- Q_ASSERT(bytesWritten <= std::numeric_limits<int>::max());
- return int(bytesWritten);
-}
-
-extern "C" int q_dgram_puts(BIO *bio, const char *src)
-{
- if (!bio || !src) {
- qCWarning(lcSsl, "invalid input parameter(s)");
- return 0;
- }
-
- return q_dgram_write(bio, src, int(std::strlen(src)));
-}
-
-extern "C" long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
-{
- // This is our custom BIO_ctrl. bio.h defines a lot of BIO_CTRL_*
- // and BIO_* constants and BIO_somename macros that expands to BIO_ctrl
- // call with one of those constants as argument. What exactly BIO_ctrl
- // does - depends on the 'cmd' and the type of BIO (so BIO_ctrl does
- // not even have a single well-defined value meaning success or failure).
- // We handle only the most generic commands - the ones documented for
- // BIO_ctrl - and also DGRAM specific ones. And even for them - in most
- // cases we do nothing but report a success or some non-error value.
- // Documents also state: "Source/sink BIOs return an 0 if they do not
- // recognize the BIO_ctrl() operation." - these are covered by 'default'
- // label in the switch-statement below. Debug messages in the switch mean:
- // 1) we got a command that is unexpected for dgram BIO, or:
- // 2) we do not call any function that would lead to OpenSSL using this
- // command.
-
- if (!bio) {
- qDebug(lcSsl, "invalid 'bio' parameter (nullptr)");
- return -1;
- }
-
- auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio));
- Q_ASSERT(dtls);
-
- switch (cmd) {
- // Let's start from the most generic ones, in the order in which they are
- // documented (as BIO_ctrl):
- case BIO_CTRL_RESET:
- // BIO_reset macro.
- // From documentation:
- // "BIO_reset() normally returns 1 for success and 0 or -1 for failure.
- // File BIOs are an exception, they return 0 for success and -1 for
- // failure."
- // We have nothing to reset and we are not file BIO.
- return 1;
- case BIO_C_FILE_SEEK:
- case BIO_C_FILE_TELL:
- qDtlsWarning("Unexpected cmd (BIO_C_FILE_SEEK/BIO_C_FILE_TELL)");
- // These are for BIO_seek, BIO_tell. We are not a file BIO.
- // Non-negative return value means success.
- return 0;
- case BIO_CTRL_FLUSH:
- // BIO_flush, nothing to do, we do not buffer any data.
- // 0 or -1 means error, 1 - success.
- return 1;
- case BIO_CTRL_EOF:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_EOF)");
- // BIO_eof, 1 means EOF read. Makes no sense for us.
- return 0;
- case BIO_CTRL_SET_CLOSE:
- // BIO_set_close with BIO_CLOSE/BIO_NOCLOSE flags. Documented as
- // always returning 1.
- // From the documentation:
- // "Typically BIO_CLOSE is used in a source/sink BIO to indicate that
- // the underlying I/O stream should be closed when the BIO is freed."
- //
- // QUdpSocket we work with is not BIO's business, ignoring.
- return 1;
- case BIO_CTRL_GET_CLOSE:
- // BIO_get_close. No, never, see the comment above.
- return 0;
- case BIO_CTRL_PENDING:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_PENDING)");
- // BIO_pending. Not used by DTLS/OpenSSL (we are not buffering).
- return 0;
- case BIO_CTRL_WPENDING:
- // No, we have nothing buffered.
- return 0;
- // The constants below are not documented as a part BIO_ctrl documentation,
- // but they are also not type-specific.
- case BIO_CTRL_DUP:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DUP)");
- // BIO_dup_state, not used by DTLS (and socket-related BIOs in general).
- // For some very specific BIO type this 'cmd' would copy some state
- // from 'bio' to (BIO*)'ptr'. 1 means success.
- return 0;
- case BIO_CTRL_SET_CALLBACK:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_SET_CALLBACK)");
- // BIO_set_info_callback. We never call this, OpenSSL does not do this
- // on its own (normally it's used if client code wants to have some
- // debug information, for example, dumping handshake state via
- // BIO_printf from SSL info_callback).
- return 0;
- case BIO_CTRL_GET_CALLBACK:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_GET_CALLBACK)");
- // BIO_get_info_callback. We never call this.
- if (ptr)
- *static_cast<bio_info_cb **>(ptr) = nullptr;
- return 0;
- case BIO_CTRL_SET:
- case BIO_CTRL_GET:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_SET/BIO_CTRL_GET)");
- // Somewhat 'documented' as setting/getting IO type. Not used anywhere
- // except BIO_buffer_get_num_lines (which contradics 'get IO type').
- // Ignoring.
- return 0;
- // DGRAM-specific operation, we have to return some reasonable value
- // (so far, I've encountered only peek mode switching, connect).
- case BIO_CTRL_DGRAM_CONNECT:
- // BIO_ctrl_dgram_connect. Not needed. Our 'dtls' already knows
- // the peer's address/port. Report success though.
- return 1;
- case BIO_CTRL_DGRAM_SET_CONNECTED:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_CONNECTED)");
- // BIO_ctrl_dgram_set_connected. We never call it, OpenSSL does
- // not call it on its own (so normally it's done by client code).
- // Similar to BIO_CTRL_DGRAM_CONNECT, but it also informs the BIO
- // that its UDP socket is connected. We never need it though.
- return -1;
- case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_RECV_TIMEOUT)");
- // Essentially setsockopt with SO_RCVTIMEO, not needed, our sockets
- // are non-blocking.
- return -1;
- case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_RECV_TIMEOUT)");
- // getsockopt with SO_RCVTIMEO, not needed, our sockets are
- // non-blocking. ptr is timeval *.
- return -1;
- case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_SEND_TIMEOUT)");
- // setsockopt, SO_SNDTIMEO, cannot happen.
- return -1;
- case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_SEND_TIMEOUT)");
- // getsockopt, SO_SNDTIMEO, cannot happen.
- return -1;
- case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
- // BIO_dgram_recv_timedout. No, we are non-blocking.
- return 0;
- case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
- // BIO_dgram_send_timedout. No, we are non-blocking.
- return 0;
- case BIO_CTRL_DGRAM_MTU_DISCOVER:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_DISCOVER)");
- // setsockopt, IP_MTU_DISCOVER/IP6_MTU_DISCOVER, to be done
- // in QUdpSocket instead. OpenSSL never calls it, only client
- // code.
- return 1;
- case BIO_CTRL_DGRAM_QUERY_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_QUERY_MTU)");
- // To be done in QUdpSocket instead.
- return 1;
- case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
- qDtlsWarning("Unexpected command *BIO_CTRL_DGRAM_GET_FALLBACK_MTU)");
- // Without SSL_OP_NO_QUERY_MTU set on SSL, OpenSSL can request for
- // fallback MTU after several re-transmissions.
- // Should never happen in our case.
- return long(dtlsutil::MtuGuess::defaultMtu);
- case BIO_CTRL_DGRAM_GET_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_MTU)");
- return -1;
- case BIO_CTRL_DGRAM_SET_MTU:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_MTU)");
- // Should not happen (we don't call BIO_ctrl with this parameter)
- // and set MTU on SSL instead.
- return -1; // num is mtu and it's a return value meaning success.
- case BIO_CTRL_DGRAM_MTU_EXCEEDED:
- qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_EXCEEDED)");
- return 0;
- case BIO_CTRL_DGRAM_GET_PEER:
- qDtlsDebug("BIO_CTRL_DGRAM_GET_PEER");
- // BIO_dgram_get_peer. We do not return a real address (DTLS is not
- // using this address), but let's pretend a success.
- switch (dtls->remoteAddress.protocol()) {
- case QAbstractSocket::IPv6Protocol:
- return sizeof(sockaddr_in6);
- case QAbstractSocket::IPv4Protocol:
- return sizeof(sockaddr_in);
- default:
- return -1;
- }
- case BIO_CTRL_DGRAM_SET_PEER:
- // Similar to BIO_CTRL_DGRAM_CONNECTED.
- return 1;
- case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
- // DTLSTODO: I'm not sure yet, how it's used by OpenSSL.
- return 1;
- case BIO_CTRL_DGRAM_SET_DONT_FRAG:
- qDtlsDebug("BIO_CTRL_DGRAM_SET_DONT_FRAG");
- // To be done in QUdpSocket, it's about IP_DONTFRAG etc.
- return 1;
- case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
- // AFAIK it's 28 for IPv4 and 48 for IPv6, but let's pretend it's 0
- // so that OpenSSL does not start suddenly fragmenting the first
- // client hello (which will result in DTLSv1_listen rejecting it).
- return 0;
- case BIO_CTRL_DGRAM_SET_PEEK_MODE:
- dtls->peeking = num;
- return 1;
- default:;
-#if QT_DTLS_VERBOSE
- qWarning() << "Unexpected cmd (" << cmd << ")";
-#endif
- }
-
- return 0;
-}
-
-extern "C" int q_dgram_create(BIO *bio)
-{
-
- q_BIO_set_init(bio, 1);
- // With a custom BIO you'd normally allocate some implementation-specific
- // data and append it to this new BIO using BIO_set_data. We don't need
- // it and thus q_dgram_destroy below is a noop.
- return 1;
-}
-
-extern "C" int q_dgram_destroy(BIO *bio)
-{
- Q_UNUSED(bio);
- return 1;
-}
-
-const char * const qdtlsMethodName = "qdtlsbio";
-
-} // namespace dtlsbio
-
-namespace dtlsopenssl
-{
-
-bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
- const QHostAddress &remote, quint16 port,
- const QByteArray &receivedMessage)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(socket);
-
- if (!tlsContext.data() && !initTls(dtlsBase))
- return false;
-
- udpSocket = socket;
-
- setLinkMtu(dtlsBase);
-
- dgram = receivedMessage;
- remoteAddress = remote;
- remotePort = port;
-
- // SSL_get_rbio does not increment a reference count.
- BIO *bio = q_SSL_get_rbio(tlsConnection.data());
- Q_ASSERT(bio);
- q_BIO_set_app_data(bio, this);
-
- return true;
-}
-
-void DtlsState::reset()
-{
- tlsConnection.reset();
- tlsContext.reset();
-}
-
-bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase)
-{
- if (tlsContext.data())
- return true;
-
- if (!QSslSocket::supportsSsl())
- return false;
-
- if (!initCtxAndConnection(dtlsBase))
- return false;
-
- if (!initBIO(dtlsBase)) {
- tlsConnection.reset();
- tlsContext.reset();
- return false;
- }
-
- return true;
-}
-
-static QString msgFunctionFailed(const char *function)
-{
- //: %1: Some function
- return QDtls::tr("%1 failed").arg(QLatin1String(function));
-}
-
-bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(QSslSocket::supportsSsl());
-
- if (dtlsBase->mode == QSslSocket::UnencryptedMode) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("Invalid SslMode, SslServerMode or SslClientMode expected"));
- return false;
- }
-
- if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("Invalid protocol version, DTLS protocol expected"));
- return false;
- }
-
- const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration);
- TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration,
- rootsOnDemand));
-
- if (newContext->error() != QSslError::NoError) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
- return false;
- }
-
- TlsConnection newConnection(newContext->createSsl(), dtlsutil::delete_connection);
- if (!newConnection.data()) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("SSL_new"));
- return false;
- }
-
- const int set = q_SSL_set_ex_data(newConnection.data(),
- QTlsBackendOpenSSL::s_indexForSSLExtraData,
- this);
-
- if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("SSL_set_ex_data"));
- return false;
- }
-
- if (dtlsBase->mode == QSslSocket::SslServerMode) {
- if (dtlsBase->dtlsConfiguration.dtlsCookieVerificationEnabled())
- q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
- q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
- } else {
- q_SSL_set_psk_client_callback(newConnection.data(), dtlscallbacks::q_PSK_client_callback);
- }
-
- tlsContext.swap(newContext);
- tlsConnection.swap(newConnection);
-
- return true;
-}
-
-bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(tlsContext.data() && tlsConnection.data());
-
- BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName),
- dtlsutil::delete_bio_method);
- if (!customMethod.data()) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("BIO_meth_new"));
- return false;
- }
-
- BIO_METHOD *biom = customMethod.data();
- q_BIO_meth_set_create(biom, dtlsbio::q_dgram_create);
- q_BIO_meth_set_destroy(biom, dtlsbio::q_dgram_destroy);
- q_BIO_meth_set_read(biom, dtlsbio::q_dgram_read);
- q_BIO_meth_set_write(biom, dtlsbio::q_dgram_write);
- q_BIO_meth_set_puts(biom, dtlsbio::q_dgram_puts);
- q_BIO_meth_set_ctrl(biom, dtlsbio::q_dgram_ctrl);
-
- BIO *bio = q_BIO_new(biom);
- if (!bio) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("BIO_new"));
- return false;
- }
-
- q_SSL_set_bio(tlsConnection.data(), bio, bio);
-
- bioMethod.swap(customMethod);
-
- return true;
-}
-
-void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase)
-{
- Q_ASSERT(dtlsBase);
- Q_ASSERT(udpSocket);
- Q_ASSERT(tlsConnection.data());
-
- long mtu = dtlsBase->mtuHint;
- if (!mtu) {
- // If the underlying QUdpSocket was connected, getsockopt with
- // IP_MTU/IP6_MTU can give us some hint:
- bool optionFound = false;
- if (udpSocket->state() == QAbstractSocket::ConnectedState) {
- const QVariant val(udpSocket->socketOption(QAbstractSocket::PathMtuSocketOption));
- if (val.isValid() && val.canConvert<int>())
- mtu = val.toInt(&optionFound);
- }
-
- if (!optionFound || mtu <= 0) {
- // OK, our own initial guess.
- mtu = long(dtlsutil::MtuGuess::defaultMtu);
- }
- }
-
- // For now, we disable this option.
- q_SSL_set_options(tlsConnection.data(), SSL_OP_NO_QUERY_MTU);
-
- q_DTLS_set_link_mtu(tlsConnection.data(), mtu);
-}
-
-} // namespace dtlsopenssl
-
-QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL()
- : QDtlsBasePrivate(QSslSocket::SslServerMode, dtlsutil::fallbackSecret())
-{
-}
-
-bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port)
-{
- Q_ASSERT(socket);
- Q_ASSERT(dgram.size());
- Q_ASSERT(!address.isNull());
- Q_ASSERT(port);
-
- clearDtlsError();
- verifiedClientHello.clear();
-
- if (!dtls.init(this, socket, address, port, dgram))
- return false;
-
- dtls.secret = secret;
- dtls.hashAlgorithm = hashAlgorithm;
-
- Q_ASSERT(dtls.tlsConnection.data());
- QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
- if (!peer.data()) {
- setDtlsError(QDtlsError::TlsInitializationError,
- QDtlsClientVerifier::tr("BIO_ADDR_new failed, ignoring client hello"));
- return false;
- }
-
- const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
- if (ret < 0) {
- // Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
- setDtlsError(QDtlsError::TlsFatalError, QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- return false;
- }
-
- if (ret > 0) {
- verifiedClientHello = dgram;
- return true;
- }
-
- return false;
-}
-
-QByteArray QDtlsClientVerifierOpenSSL::verifiedHello() const
-{
- return verifiedClientHello;
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs)
-{
- Q_ASSERT(timerId == -1);
- timerId = startTimer(hintMs > 0 ? hintMs : timeoutMs, Qt::PreciseTimer);
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::doubleTimeout()
-{
- if (timeoutMs * 2 < 60000)
- timeoutMs *= 2;
- else
- timeoutMs = 60000;
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::stop()
-{
- if (timerId != -1) {
- killTimer(timerId);
- timerId = -1;
- }
-}
-
-void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event)
-{
- Q_UNUSED(event);
- Q_ASSERT(timerId != -1);
-
- killTimer(timerId);
- timerId = -1;
-
- Q_ASSERT(dtlsConnection);
- dtlsConnection->reportTimeout();
-}
-
-QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode side)
- : QDtlsBasePrivate(side, dtlsutil::fallbackSecret()), q(qObject)
-{
- Q_ASSERT(qObject);
-
- dtls.dtlsPrivate = this;
-}
-
-QSslSocket::SslMode QDtlsPrivateOpenSSL::cryptographMode() const
-{
- return mode;
-}
-
-void QDtlsPrivateOpenSSL::setPeer(const QHostAddress &addr, quint16 port, const QString &name)
-{
- remoteAddress = addr;
- remotePort = port;
- peerVfyName = name;
-}
-
-QHostAddress QDtlsPrivateOpenSSL::peerAddress() const
-{
- return remoteAddress;
-}
-
-quint16 QDtlsPrivateOpenSSL::peerPort() const
-{
- return remotePort;
-}
-
-void QDtlsPrivateOpenSSL::setPeerVerificationName(const QString &name)
-{
- peerVfyName = name;
-}
-
-QString QDtlsPrivateOpenSSL::peerVerificationName() const
-{
- return peerVfyName;
-}
-
-void QDtlsPrivateOpenSSL::setDtlsMtuHint(quint16 mtu)
-{
- mtuHint = mtu;
-}
-
-quint16 QDtlsPrivateOpenSSL::dtlsMtuHint() const
-{
- return mtuHint;
-}
-
-QDtls::HandshakeState QDtlsPrivateOpenSSL::state() const
-{
- return handshakeState;
-}
-
-bool QDtlsPrivateOpenSSL::isConnectionEncrypted() const
-{
- return connectionEncrypted;
-}
-
-bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::HandshakeNotStarted);
-
- clearDtlsError();
- connectionEncrypted = false;
-
- if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
- return false;
-
- if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) {
- dtls.secret = secret;
- dtls.hashAlgorithm = hashAlgorithm;
- // Let's prepare the state machine so that message sequence 1 does not
- // surprise DTLS/OpenSSL (such a message would be disregarded as
- // 'stale or future' in SSL_accept otherwise):
- int result = 0;
- QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR);
- if (!peer.data()) {
- setDtlsError(QDtlsError::TlsInitializationError,
- QDtls::tr("BIO_ADD_new failed, cannot start handshake"));
- return false;
- }
-
- // If it's an invalid/unexpected ClientHello, we don't want to send
- // VerifyClientRequest - it's a job of QDtlsClientVerifier - so we
- // suppress any attempts to write into socket:
- dtls.writeSuppressed = true;
- result = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
- dtls.writeSuppressed = false;
-
- if (result <= 0) {
- setDtlsError(QDtlsError::TlsFatalError,
- QDtls::tr("Cannot start the handshake, verified client hello expected"));
- dtls.reset();
- return false;
- }
- }
-
- handshakeState = QDtls::HandshakeInProgress;
- opensslErrors.clear();
- tlsErrors.clear();
-
- return continueHandshake(socket, dgram);
-}
-
-bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray &dgram)
-{
- Q_ASSERT(socket);
-
- Q_ASSERT(handshakeState == QDtls::HandshakeInProgress);
-
- clearDtlsError();
-
- if (timeoutHandler.data())
- timeoutHandler->stop();
-
- if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
- return false;
-
- dtls.x509Errors.clear();
-
- int result = 0;
- if (mode == QSslSocket::SslServerMode)
- result = q_SSL_accept(dtls.tlsConnection.data());
- else
- result = q_SSL_connect(dtls.tlsConnection.data());
-
- // DTLSTODO: Investigate/test if it makes sense - QSslSocket can emit
- // peerVerifyError at this point (and thus potentially client code
- // will close the underlying TCP connection immediately), but we are using
- // QUdpSocket, no connection to close, our verification callback returns 1
- // (verified OK) and this probably means OpenSSL has already sent a reply
- // to the server's hello/certificate.
-
- opensslErrors << dtls.x509Errors;
-
- if (result <= 0) {
- const auto code = q_SSL_get_error(dtls.tlsConnection.data(), result);
- switch (code) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // DTLSTODO: to be tested - in principle, if it was the first call to
- // continueHandshake and server for some reason discards the client
- // hello message (even the verified one) - our 'this' will probably
- // forever stay in this strange InProgress state? (the client
- // will dully re-transmit the same hello and we discard it again?)
- // SSL_get_state can provide more information about state
- // machine and we can switch to NotStarted (since we have not
- // replied with our hello ...)
- if (!timeoutHandler.data()) {
- timeoutHandler.reset(new TimeoutHandler);
- timeoutHandler->dtlsConnection = this;
- } else {
- // Back to 1s.
- timeoutHandler->resetTimeout();
- }
-
- timeoutHandler->start();
-
- return true; // The handshake is not yet complete.
- default:
- storePeerCertificates();
- setDtlsError(QDtlsError::TlsFatalError,
- QTlsBackendOpenSSL::msgErrorsDuringHandshake());
- dtls.reset();
- handshakeState = QDtls::HandshakeNotStarted;
- return false;
- }
- }
-
- storePeerCertificates();
- fetchNegotiatedParameters();
-
- const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer
- || (dtlsConfiguration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
-
- if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
- connectionEncrypted = true;
- handshakeState = QDtls::HandshakeComplete;
- return true;
- }
-
- setDtlsError(QDtlsError::PeerVerificationError, QDtls::tr("Peer verification failed"));
- handshakeState = QDtls::PeerVerificationFailed;
- return false;
-}
-
-
-bool QDtlsPrivateOpenSSL::handleTimeout(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
-
- Q_ASSERT(timeoutHandler.data());
- Q_ASSERT(dtls.tlsConnection.data());
-
- clearDtlsError();
-
- dtls.udpSocket = socket;
-
- if (q_DTLSv1_handle_timeout(dtls.tlsConnection.data()) > 0) {
- timeoutHandler->doubleTimeout();
- timeoutHandler->start();
- } else {
- timeoutHandler->start(dtlsutil::next_timeoutMs(dtls.tlsConnection.data()));
- }
-
- return true;
-}
-
-bool QDtlsPrivateOpenSSL::resumeHandshake(QUdpSocket *socket)
-{
- Q_UNUSED(socket);
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed);
-
- clearDtlsError();
-
- if (tlsErrorsWereIgnored()) {
- handshakeState = QDtls::HandshakeComplete;
- connectionEncrypted = true;
- tlsErrors.clear();
- tlsErrorsToIgnore.clear();
- return true;
- }
-
- return false;
-}
-
-void QDtlsPrivateOpenSSL::abortHandshake(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
- Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed
- || handshakeState == QDtls::HandshakeInProgress);
-
- clearDtlsError();
-
- if (handshakeState == QDtls::PeerVerificationFailed) {
- // Yes, while peer verification failed, we were actually encrypted.
- // Let's play it nice - inform our peer about connection shut down.
- sendShutdownAlert(socket);
- } else {
- resetDtls();
- }
-}
-
-void QDtlsPrivateOpenSSL::sendShutdownAlert(QUdpSocket *socket)
-{
- Q_ASSERT(socket);
-
- clearDtlsError();
-
- if (connectionEncrypted && !connectionWasShutdown) {
- dtls.udpSocket = socket;
- Q_ASSERT(dtls.tlsConnection.data());
- q_SSL_shutdown(dtls.tlsConnection.data());
- }
-
- resetDtls();
-}
-
-QList<QSslError> QDtlsPrivateOpenSSL::peerVerificationErrors() const
-{
- return tlsErrors;
-}
-
-void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
-{
- tlsErrorsToIgnore = errorsToIgnore;
-}
-
-QSslCipher QDtlsPrivateOpenSSL::dtlsSessionCipher() const
-{
- return sessionCipher;
-}
-
-QSsl::SslProtocol QDtlsPrivateOpenSSL::dtlsSessionProtocol() const
-{
- return sessionProtocol;
-}
-
-qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
- const QByteArray &dgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(dtls.tlsConnection.data());
- Q_ASSERT(connectionEncrypted);
-
- clearDtlsError();
-
- dtls.udpSocket = socket;
- const int written = q_SSL_write(dtls.tlsConnection.data(),
- dgram.constData(), dgram.size());
- if (written > 0)
- return written;
-
- const unsigned long errorCode = q_ERR_get_error();
- if (!dgram.size() && errorCode == SSL_ERROR_NONE) {
- // With OpenSSL <= 1.1 this can happen. For example, DTLS client
- // tries to reconnect (while re-using the same address/port) -
- // DTLS server drops a message with unexpected epoch but says - no
- // error. We leave to client code to resolve such problems until
- // OpenSSL provides something better.
- return 0;
- }
-
- switch (errorCode) {
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- // We do not set any error/description ... a user can probably re-try
- // sending a datagram.
- break;
- case SSL_ERROR_ZERO_RETURN:
- connectionWasShutdown = true;
- setDtlsError(QDtlsError::TlsFatalError, QDtls::tr("The DTLS connection has been closed"));
- handshakeState = QDtls::HandshakeNotStarted;
- dtls.reset();
- break;
- case SSL_ERROR_SYSCALL:
- case SSL_ERROR_SSL:
- default:
- // DTLSTODO: we don't know yet what to do. Tests needed - probably,
- // some errors can be just ignored (it's UDP, not TCP after all).
- // Unlike QSslSocket we do not abort though.
- QString description(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
- setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
- } else {
- setDtlsError(QDtlsError::TlsFatalError,
- QDtls::tr("Error while writing: %1").arg(description));
- }
- }
-
- return -1;
-}
-
-QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram)
-{
- Q_ASSERT(socket);
- Q_ASSERT(tlsdgram.size());
-
- Q_ASSERT(dtls.tlsConnection.data());
- Q_ASSERT(connectionEncrypted);
-
- dtls.dgram = tlsdgram;
- dtls.udpSocket = socket;
-
- clearDtlsError();
-
- QByteArray dgram;
- dgram.resize(tlsdgram.size());
- const int read = q_SSL_read(dtls.tlsConnection.data(), dgram.data(),
- dgram.size());
-
- if (read > 0) {
- dgram.resize(read);
- return dgram;
- }
-
- dgram.clear();
- unsigned long errorCode = q_ERR_get_error();
- if (errorCode == SSL_ERROR_NONE) {
- const int shutdown = q_SSL_get_shutdown(dtls.tlsConnection.data());
- if (shutdown & SSL_RECEIVED_SHUTDOWN)
- errorCode = SSL_ERROR_ZERO_RETURN;
- else
- return dgram;
- }
-
- switch (errorCode) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- return dgram;
- case SSL_ERROR_ZERO_RETURN:
- // "The connection was shut down cleanly" ... hmm, whatever,
- // needs testing (DTLSTODO).
- connectionWasShutdown = true;
- setDtlsError(QDtlsError::RemoteClosedConnectionError,
- QDtls::tr("The DTLS connection has been shutdown"));
- dtls.reset();
- connectionEncrypted = false;
- handshakeState = QDtls::HandshakeNotStarted;
- return dgram;
- case SSL_ERROR_SYSCALL: // some IO error
- case SSL_ERROR_SSL: // error in the SSL library
- // DTLSTODO: Apparently, some errors can be ignored, for example,
- // ECONNRESET etc. This all needs a lot of testing!!!
- default:
- setDtlsError(QDtlsError::TlsNonFatalError,
- QDtls::tr("Error while reading: %1")
- .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return dgram;
- }
-}
-
-unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity,
- unsigned max_identity_len,
- unsigned char *psk,
- unsigned max_psk_len)
-{
- // The code below is taken (with some modifications) from qsslsocket_openssl
- // - alas, we cannot simply re-use it, it's in QSslSocketPrivate.
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for client code)
- if (hint) {
- identityHint.clear();
- identityHint.append(hint);
- }
-
- QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr,
- hint ? int(std::strlen(hint)) : 0, max_identity_len, max_psk_len);
- pskAuthenticator.swap(authenticator);
- }
-
- // Let the client provide the remaining bits...
- emit q->pskRequired(&pskAuthenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (pskAuthenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int identityLength = qMin(pskAuthenticator.identity().length(),
- pskAuthenticator.maximumIdentityLength());
- std::memcpy(identity, pskAuthenticator.identity().constData(), identityLength);
- identity[identityLength] = 0;
-
- const int pskLength = qMin(pskAuthenticator.preSharedKey().length(),
- pskAuthenticator.maximumPreSharedKeyLength());
- std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
-
- return pskLength;
-}
-
-unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len)
-{
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for the user)
- QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint(),
- max_psk_len);
- pskAuthenticator.swap(authenticator);
- }
-
- // Let the client provide the remaining bits...
- emit q->pskRequired(&pskAuthenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (pskAuthenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int pskLength = qMin(pskAuthenticator.preSharedKey().length(),
- pskAuthenticator.maximumPreSharedKeyLength());
-
- std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength);
-
- return pskLength;
-}
-
-bool QDtlsPrivateOpenSSL::verifyPeer()
-{
- QList<QSslError> errors;
-
- // Check the whole chain for blacklisting (including root, as we check for
- // subjectInfo and issuer)
- const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain();
- for (const QSslCertificate &cert : peerCertificateChain) {
- if (QSslCertificatePrivate::isBlacklisted(cert))
- errors << QSslError(QSslError::CertificateBlacklisted, cert);
- }
-
- const auto peerCertificate = dtlsConfiguration.peerCertificate();
- if (peerCertificate.isNull()) {
- errors << QSslError(QSslError::NoPeerCertificate);
- } else if (mode == QSslSocket::SslClientMode) {
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
-
- // QSslSocket has a rather twisted logic: if verificationPeerName
- // is empty, we call QAbstractSocket::peerName(), which returns
- // either peerName (can be set by setPeerName) or host name
- // (can be set as a result of connectToHost).
- QString name = peerVfyName;
- if (name.isEmpty()) {
- Q_ASSERT(dtls.udpSocket);
- name = dtls.udpSocket->peerName();
- }
-
- if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name))
- errors << QSslError(QSslError::HostNameMismatch, peerCertificate);
- }
-
- // Translate errors from the error list into QSslErrors
- using CertClass = QTlsPrivate::X509CertificateOpenSSL;
- errors.reserve(errors.size() + opensslErrors.size());
- for (const auto &error : qAsConst(opensslErrors)) {
- const auto value = peerCertificateChain.value(error.depth);
- errors << CertClass::openSSLErrorToQSslError(error.code, value);
- }
-
- tlsErrors = errors;
- return tlsErrors.isEmpty();
-}
-
-void QDtlsPrivateOpenSSL::storePeerCertificates()
-{
- Q_ASSERT(dtls.tlsConnection.data());
- // Store the peer certificate and chain. For clients, the peer certificate
- // chain includes the peer certificate; for servers, it doesn't. Both the
- // peer certificate and the chain may be empty if the peer didn't present
- // any certificate.
- X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
- const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
- QTlsBackend::storePeerCertificate(dtlsConfiguration, peerCertificate);
- q_X509_free(x509);
-
- auto peerCertificateChain = dtlsConfiguration.peerCertificateChain();
- if (peerCertificateChain.isEmpty()) {
- auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
- peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
- if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
- peerCertificateChain.prepend(peerCertificate);
- QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain);
- }
-}
-
-bool QDtlsPrivateOpenSSL::tlsErrorsWereIgnored() const
-{
- // check whether the errors we got are all in the list of expected errors
- // (applies only if the method QDtlsConnection::ignoreTlsErrors(const
- // QList<QSslError> &errors) was called)
- for (const QSslError &error : tlsErrors) {
- if (!tlsErrorsToIgnore.contains(error))
- return false;
- }
-
- return !tlsErrorsToIgnore.empty();
-}
-
-void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
-{
- Q_ASSERT(dtls.tlsConnection.data());
-
- if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data()))
- sessionCipher = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
- else
- sessionCipher = {};
-
- // Note: cipher's protocol version will be reported as either TLS 1.0 or
- // TLS 1.2, that's how it's set by OpenSSL (and that's what they are?).
-
- switch (q_SSL_version(dtls.tlsConnection.data())) {
- case DTLS1_VERSION:
- sessionProtocol = QSsl::DtlsV1_0;
- break;
- case DTLS1_2_VERSION:
- sessionProtocol = QSsl::DtlsV1_2;
- break;
- default:
- qCWarning(lcSsl, "unknown protocol version");
- sessionProtocol = QSsl::UnknownProtocol;
- }
-}
-
-void QDtlsPrivateOpenSSL::reportTimeout()
-{
- emit q->handshakeTimeout();
-}
-
-void QDtlsPrivateOpenSSL::resetDtls()
-{
- dtls.reset();
- connectionEncrypted = false;
- tlsErrors.clear();
- tlsErrorsToIgnore.clear();
- QTlsBackend::clearPeerCertificates(dtlsConfiguration);
- connectionWasShutdown = false;
- handshakeState = QDtls::HandshakeNotStarted;
- sessionCipher = {};
- sessionProtocol = QSsl::UnknownProtocol;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qdtls_openssl_p.h b/src/network/ssl/qdtls_openssl_p.h
deleted file mode 100644
index 281e1133cd..0000000000
--- a/src/network/ssl/qdtls_openssl_p.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QDTLS_OPENSSL_P_H
-#define QDTLS_OPENSSL_P_H
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <QtCore/qglobal.h>
-
-#include <openssl/ossl_typ.h>
-
-#include "qtlsbackend_openssl_p.h"
-#include "qtls_openssl_p.h"
-#include "qdtls_base_p.h"
-#include "qdtls_p.h"
-
-#include <private/qsslcontext_openssl_p.h>
-#include <private/qopenssl_p.h>
-
-#include <QtNetwork/qsslpresharedkeyauthenticator.h>
-#include <QtNetwork/qhostaddress.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qsharedpointer.h>
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_REQUIRE_CONFIG(openssl);
-QT_REQUIRE_CONFIG(dtls);
-
-QT_BEGIN_NAMESPACE
-
-class QDtlsPrivateOpenSSL;
-class QDtlsBasePrivate;
-class QUdpSocket;
-
-namespace dtlsopenssl
-{
-
-class DtlsState
-{
-public:
- // Note, bioMethod _must_ outlive BIOs it was used to create. Thus
- // the order of declarations here matters.
- using BioMethod = QSharedPointer<BIO_METHOD>;
- BioMethod bioMethod;
-
- using TlsContext = QSharedPointer<QSslContext>;
- TlsContext tlsContext;
-
- using TlsConnection = QSharedPointer<SSL>;
- TlsConnection tlsConnection;
-
- QByteArray dgram;
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
-
- QList<QSslErrorEntry> x509Errors;
-
- long peeking = false;
- QUdpSocket *udpSocket = nullptr;
- bool writeSuppressed = false;
-
- bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
- const QHostAddress &remote, quint16 port,
- const QByteArray &receivedMessage);
-
- void reset();
-
- QDtlsPrivateOpenSSL *dtlsPrivate = nullptr;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-
-private:
-
- bool initTls(QDtlsBasePrivate *dtlsBase);
- bool initCtxAndConnection(QDtlsBasePrivate *dtlsBase);
- bool initBIO(QDtlsBasePrivate *dtlsBase);
- void setLinkMtu(QDtlsBasePrivate *dtlsBase);
-};
-
-} // namespace dtlsopenssl
-
-// The trick with 'right' ancestor in the tree overriding (only once) some shared
-// virtual functions is intentional. Too bad MSVC warns me about ... exactly the
-// feature of C++ that I want to use.
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4250)
-
-class QDtlsClientVerifierOpenSSL : public QTlsPrivate::DtlsCookieVerifier, public QDtlsBasePrivate
-{
-public:
- QDtlsClientVerifierOpenSSL();
-
- bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) override;
- QByteArray verifiedHello() const override;
-
-private:
- dtlsopenssl::DtlsState dtls;
- QByteArray verifiedClientHello;
-};
-
-class QDtlsPrivateOpenSSL : public QTlsPrivate::DtlsCryptograph, public QDtlsBasePrivate
-{
-public:
-
- QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode mode);
-
-private:
-
- QSslSocket::SslMode cryptographMode() const override;
- void setPeer(const QHostAddress &addr, quint16 port, const QString &name) override;
- QHostAddress peerAddress() const override;
- quint16 peerPort() const override;
- void setPeerVerificationName(const QString &name) override;
- QString peerVerificationName() const override;
-
- virtual void setDtlsMtuHint(quint16 mtu) override;
- virtual quint16 dtlsMtuHint() const override;
-
- virtual QDtls::HandshakeState state() const override;
- virtual bool isConnectionEncrypted() const override;
-
- bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
- bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
- bool resumeHandshake(QUdpSocket *socket) override;
- void abortHandshake(QUdpSocket *socket) override;
- bool handleTimeout(QUdpSocket *socket) override;
- void sendShutdownAlert(QUdpSocket *socket) override;
-
- QList<QSslError> peerVerificationErrors() const override;
- void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) override;
-
- QSslCipher dtlsSessionCipher() const override;
- QSsl::SslProtocol dtlsSessionProtocol() const override;
-
- qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
- QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
-
-public:
- unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len);
- unsigned pskServerCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len);
-
-private:
-
- bool verifyPeer();
- void storePeerCertificates();
- bool tlsErrorsWereIgnored() const;
- void fetchNegotiatedParameters();
- void reportTimeout();
- void resetDtls();
-
- QList<QSslErrorEntry> opensslErrors;
- dtlsopenssl::DtlsState dtls;
-
- // We have to externally handle timeouts since we have non-blocking
- // sockets and OpenSSL(DTLS) with non-blocking UDP sockets does not
- // know if a timeout has occurred.
- struct TimeoutHandler : QObject
- {
- TimeoutHandler() = default;
-
- void start(int hintMs = 0);
- void doubleTimeout();
- void resetTimeout() {timeoutMs = 1000;}
- void stop();
- void timerEvent(QTimerEvent *event) override;
-
- int timerId = -1;
- int timeoutMs = 1000;
-
- QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
- };
-
- QDtls *q = nullptr;
- QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
-
- QList<QSslError> tlsErrors;
- QList<QSslError> tlsErrorsToIgnore;
- bool connectionEncrypted = false;
- // We will initialize it 'lazily', just in case somebody wants to move
- // QDtls to another thread.
- QScopedPointer<TimeoutHandler> timeoutHandler;
- bool connectionWasShutdown = false;
- QSslPreSharedKeyAuthenticator pskAuthenticator;
- QByteArray identityHint;
-};
-
-QT_WARNING_POP // C4250
-
-QT_END_NAMESPACE
-
-#endif // QDTLS_OPENSSL_P_H
diff --git a/src/network/ssl/qopenssl.cpp b/src/network/ssl/qopenssl.cpp
deleted file mode 100644
index 1453b4d881..0000000000
--- a/src/network/ssl/qopenssl.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2014 Governikus GmbH & Co. KG
-** 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 "qtlsbackend_openssl_p.h"
-#include "qopenssl_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QTlsBackendOpenSSL, backendOpenSsl)
-
-void QSslSocketPrivate::registerAdHocFactory()
-{
- // TLSTODO: this is a temporary solution, waiting for
- // backends to move to ... plugins.
- if (!backendOpenSsl())
- qCWarning(lcSsl, "Failed to create backend factory");
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qopenssl_p.h b/src/network/ssl/qopenssl_p.h
deleted file mode 100644
index fa3efb2c28..0000000000
--- a/src/network/ssl/qopenssl_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** 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_OPENSSL_P_H
-#define QSSLSOCKET_OPENSSL_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include "qsslsocket_p.h"
-#include "qsslcipher.h"
-
-#ifdef Q_OS_WIN
-#include <qt_windows.h>
-#if defined(OCSP_RESPONSE)
-#undef OCSP_RESPONSE
-#endif
-#if defined(X509_NAME)
-#undef X509_NAME
-#endif
-#endif // Q_OS_WIN
-
-// This file is included in several *.cpp files and provides different
-// openssl declarations where they are needed.
-#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/pkcs12.h>
-#include <openssl/pkcs7.h>
-#include <openssl/rand.h>
-#include <openssl/ssl.h>
-#include <openssl/stack.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/x509_vfy.h>
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/crypto.h>
-#include <openssl/tls1.h>
-#include <openssl/dh.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QSslErrorEntry {
- int code = 0;
- int depth = 0;
-};
-
-Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
deleted file mode 100644
index de7ef15d10..0000000000
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ /dev/null
@@ -1,824 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2014 Governikus GmbH & Co. KG.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtNetwork/qsslsocket.h>
-#include <QtNetwork/qssldiffiehellmanparameters.h>
-
-#include "private/qopenssl_p.h"
-#include "private/qssl_p.h"
-#include "private/qsslsocket_p.h"
-#include "private/qsslcontext_openssl_p.h"
-#include "private/qsslsocket_openssl_symbols_p.h"
-#include "private/qssldiffiehellmanparameters_p.h"
-#include "private/qtlsbackend_openssl_p.h"
-
-#include <vector>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(bool, forceSecurityLevel)
-
-Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
-{
- *forceSecurityLevel() = true;
-}
-
-namespace QTlsPrivate
-{
-// These callback functions are defined in qtls_openssl.cpp.
-extern "C" int q_X509Callback(int ok, X509_STORE_CTX *ctx);
-extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
-
-#if QT_CONFIG(ocsp)
-extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *);
-#endif // ocsp
-
-} // namespace QTlsPrivate
-
-#if QT_CONFIG(dtls)
-// defined in qdtls_openssl.cpp:
-namespace dtlscallbacks
-{
-extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx);
-extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
- unsigned *cookieLength);
-extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
- unsigned cookieLength);
-}
-#endif // dtls
-
-#ifdef TLS1_3_VERSION
-extern "C" int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
-#endif // TLS1_3_VERSION
-
-static inline QString msgErrorSettingBackendConfig(const QString &why)
-{
- return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why);
-}
-
-static inline QString msgErrorSettingEllipticCurves(const QString &why)
-{
- return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
-}
-
-long QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
-{
- long options;
- switch (protocol) {
- case QSsl::SecureProtocols:
- case QSsl::TlsV1_0OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
- break;
- case QSsl::TlsV1_1OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
- break;
- case QSsl::TlsV1_2OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
- break;
- case QSsl::TlsV1_3OrLater:
- options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
- break;
- default:
- options = SSL_OP_ALL;
- }
-
- // This option is disabled by default, so we need to be able to clear it
- if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
- options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
- else
- options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
-
-#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
- // This option is disabled by default, so we need to be able to clear it
- if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
- options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
- else
- options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-#endif
-
-#ifdef SSL_OP_NO_TICKET
- if (sslOptions & QSsl::SslOptionDisableSessionTickets)
- options |= SSL_OP_NO_TICKET;
-#endif
-#ifdef SSL_OP_NO_COMPRESSION
- if (sslOptions & QSsl::SslOptionDisableCompression)
- options |= SSL_OP_NO_COMPRESSION;
-#endif
-
- if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
- options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
-
- return options;
-}
-
-QSslContext::QSslContext()
- : ctx(nullptr),
- pkey(nullptr),
- session(nullptr),
- m_sessionTicketLifeTimeHint(-1)
-{
-}
-
-QSslContext::~QSslContext()
-{
- if (ctx)
- // This will decrement the reference count by 1 and free the context eventually when possible
- q_SSL_CTX_free(ctx);
-
- if (pkey)
- q_EVP_PKEY_free(pkey);
-
- if (session)
- q_SSL_SESSION_free(session);
-}
-
-QSslContext* QSslContext::fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
-{
- QSslContext *sslContext = new QSslContext();
- initSslContext(sslContext, mode, configuration, allowRootCertOnDemandLoading);
- return sslContext;
-}
-
-QSharedPointer<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
-{
- QSharedPointer<QSslContext> sslContext = QSharedPointer<QSslContext>::create();
- initSslContext(sslContext.data(), mode, configuration, allowRootCertOnDemandLoading);
- return sslContext;
-}
-
-QSharedPointer<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
- bool allowRootCertOnDemandLoading)
-{
- return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-
-static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg)
-{
- QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
-
- // comment out to debug:
-// QList<QByteArray> supportedVersions;
-// for (unsigned int i = 0; i < inlen; ) {
-// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
-// supportedVersions << version;
-// i += in[i] + 1;
-// }
-
- int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
- switch (proto) {
- case OPENSSL_NPN_UNSUPPORTED:
- ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
- break;
- case OPENSSL_NPN_NEGOTIATED:
- ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
- break;
- case OPENSSL_NPN_NO_OVERLAP:
- ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
- break;
- default:
- qCWarning(lcSsl, "OpenSSL sent unknown NPN status");
- }
-
- return SSL_TLSEXT_ERR_OK;
-}
-
-QSslContext::NPNContext QSslContext::npnContext() const
-{
- return m_npnContext;
-}
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-
-
-// Needs to be deleted by caller
-SSL* QSslContext::createSsl()
-{
- SSL* ssl = q_SSL_new(ctx);
- q_SSL_clear(ssl);
-
- if (!session && !sessionASN1().isEmpty()
- && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
- session = q_d2i_SSL_SESSION(nullptr, &data, m_sessionASN1.size());
- // 'session' has refcount 1 already, set by the function above
- }
-
- if (session) {
- // Try to resume the last session we cached
- if (!q_SSL_set_session(ssl, session)) {
- qCWarning(lcSsl, "could not set SSL session");
- q_SSL_SESSION_free(session);
- session = nullptr;
- }
- }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- QList<QByteArray> protocols = sslConfiguration.d.constData()->nextAllowedProtocols;
- if (!protocols.isEmpty()) {
- m_supportedNPNVersions.clear();
- for (int a = 0; a < protocols.count(); ++a) {
- if (protocols.at(a).size() > 255) {
- qCWarning(lcSsl) << "TLS NPN extension" << protocols.at(a)
- << "is too long and will be ignored.";
- continue;
- } else if (protocols.at(a).isEmpty()) {
- continue;
- }
- m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
- }
- if (m_supportedNPNVersions.size()) {
- m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
- m_npnContext.len = m_supportedNPNVersions.count();
- m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
- // Callback's type has a parameter 'const unsigned char ** out'
- // since it was introduced in 1.0.2. Internally, OpenSSL's own code
- // (tests/examples) cast it to unsigned char * (since it's 'out').
- // We just re-use our NPN callback and cast here:
- typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *,
- const unsigned char *, unsigned int, void *);
- // With ALPN callback is for a server side only, for a client m_npnContext.status
- // will stay in NextProtocolNegotiationNone.
- q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext);
- // Client:
- q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len);
- // And in case our peer does not support ALPN, but supports NPN:
- q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
- }
- }
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
- return ssl;
-}
-
-// We cache exactly one session here
-bool QSslContext::cacheSession(SSL* ssl)
-{
- // don't cache the same session again
- if (session && session == q_SSL_get_session(ssl))
- return true;
-
- // decrease refcount of currently stored session
- // (this might happen if there are several concurrent handshakes in flight)
- if (session)
- q_SSL_SESSION_free(session);
-
- // cache the session the caller gave us and increase reference count
- session = q_SSL_get1_session(ssl);
-
- if (session && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- int sessionSize = q_i2d_SSL_SESSION(session, nullptr);
- if (sessionSize > 0) {
- m_sessionASN1.resize(sessionSize);
- unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
- if (!q_i2d_SSL_SESSION(session, &data))
- qCWarning(lcSsl, "could not store persistent version of SSL session");
- m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
- }
- }
-
- return (session != nullptr);
-}
-
-QByteArray QSslContext::sessionASN1() const
-{
- return m_sessionASN1;
-}
-
-void QSslContext::setSessionASN1(const QByteArray &session)
-{
- m_sessionASN1 = session;
-}
-
-int QSslContext::sessionTicketLifeTimeHint() const
-{
- return m_sessionTicketLifeTimeHint;
-}
-
-QSslError::SslError QSslContext::error() const
-{
- return errorCode;
-}
-
-QString QSslContext::errorString() const
-{
- return errorStr;
-}
-
-void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode,
- const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading)
-{
- sslContext->sslConfiguration = configuration;
- sslContext->errorCode = QSslError::NoError;
-
- bool client = (mode == QSslSocket::SslClientMode);
-
- bool reinitialized = false;
- bool unsupportedProtocol = false;
- bool isDtls = false;
-init_context:
- switch (sslContext->sslConfiguration.protocol()) {
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_2OrLater:
-#if QT_CONFIG(dtls)
- isDtls = true;
- sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
-#else // dtls
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- qCWarning(lcSsl, "DTLS protocol requested, but feature 'dtls' is disabled");
-#endif // dtls
- break;
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
-#if !defined(TLS1_3_VERSION)
- qCWarning(lcSsl, "TLS 1.3 is not supported");
- sslContext->ctx = nullptr;
- unsupportedProtocol = true;
- break;
-#endif // TLS1_3_VERSION
- default:
- // The ssl options will actually control the supported methods
- sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
- }
-
- if (!sslContext->ctx) {
- // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
- // by re-initializing the library.
- if (!reinitialized) {
- reinitialized = true;
- if (q_OPENSSL_init_ssl(0, nullptr) == 1)
- goto init_context;
- }
-
- sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
- unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QTlsBackendOpenSSL::getErrorsFromOpenSsl()
- );
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // A nasty hacked OpenSSL using a level that will make our auto-tests fail:
- if (q_SSL_CTX_get_security_level(sslContext->ctx) > 1 && *forceSecurityLevel())
- q_SSL_CTX_set_security_level(sslContext->ctx, 1);
-
- const long anyVersion =
-#if QT_CONFIG(dtls)
- isDtls ? DTLS_ANY_VERSION : TLS_ANY_VERSION;
-#else
- TLS_ANY_VERSION;
-#endif // dtls
- long minVersion = anyVersion;
- long maxVersion = anyVersion;
-
- switch (sslContext->sslConfiguration.protocol()) {
- case QSsl::TlsV1_0:
- minVersion = TLS1_VERSION;
- maxVersion = TLS1_VERSION;
- break;
- case QSsl::TlsV1_1:
- minVersion = TLS1_1_VERSION;
- maxVersion = TLS1_1_VERSION;
- break;
- case QSsl::TlsV1_2:
- minVersion = TLS1_2_VERSION;
- maxVersion = TLS1_2_VERSION;
- break;
- case QSsl::TlsV1_3:
-#ifdef TLS1_3_VERSION
- minVersion = TLS1_3_VERSION;
- maxVersion = TLS1_3_VERSION;
-#else
- // This protocol is not supported by OpenSSL 1.1 and we handle
- // it as an error (see the code above).
- Q_UNREACHABLE();
-#endif // TLS1_3_VERSION
- break;
- // Ranges:
- case QSsl::AnyProtocol:
- case QSsl::SecureProtocols:
- case QSsl::TlsV1_0OrLater:
- minVersion = TLS1_VERSION;
- maxVersion = 0;
- break;
- case QSsl::TlsV1_1OrLater:
- minVersion = TLS1_1_VERSION;
- maxVersion = 0;
- break;
- case QSsl::TlsV1_2OrLater:
- minVersion = TLS1_2_VERSION;
- maxVersion = 0;
- break;
- case QSsl::DtlsV1_0:
- minVersion = DTLS1_VERSION;
- maxVersion = DTLS1_VERSION;
- break;
- case QSsl::DtlsV1_0OrLater:
- minVersion = DTLS1_VERSION;
- maxVersion = DTLS_MAX_VERSION;
- break;
- case QSsl::DtlsV1_2:
- minVersion = DTLS1_2_VERSION;
- maxVersion = DTLS1_2_VERSION;
- break;
- case QSsl::DtlsV1_2OrLater:
- minVersion = DTLS1_2_VERSION;
- maxVersion = DTLS_MAX_VERSION;
- break;
- case QSsl::TlsV1_3OrLater:
-#ifdef TLS1_3_VERSION
- minVersion = TLS1_3_VERSION;
- maxVersion = 0;
- break;
-#else
- // This protocol is not supported by OpenSSL 1.1 and we handle
- // it as an error (see the code above).
- Q_UNREACHABLE();
- break;
-#endif // TLS1_3_VERSION
- case QSsl::UnknownProtocol:
- break;
- }
-
- if (minVersion != anyVersion
- && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) {
- sslContext->errorStr = QSslSocket::tr("Error while setting the minimal protocol version");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (maxVersion != anyVersion
- && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) {
- sslContext->errorStr = QSslSocket::tr("Error while setting the maximum protocol version");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Enable bug workarounds.
- const long options = setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
- q_SSL_CTX_set_options(sslContext->ctx, options);
-
- // Tell OpenSSL to release memory early
- // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
- q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
-
- auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13)
- {
- QByteArray cipherString;
-
- for (const QSslCipher &cipher : ciphers) {
- const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater;
- if (selectTls13 != isTls13Cipher)
- continue;
-
- if (cipherString.size())
- cipherString.append(':');
- cipherString.append(cipher.name().toLatin1());
- }
- return cipherString;
- };
-
- // Initialize ciphers
- QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
- if (ciphers.isEmpty())
- ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
-
- const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
-
- if (preTls13Ciphers.size()) {
- if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
- }
-
- const QByteArray tls13Ciphers = filterCiphers(ciphers, true);
-#ifdef TLS1_3_VERSION
- if (tls13Ciphers.size()) {
- if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
- }
-#endif // TLS1_3_VERSION
- if (!preTls13Ciphers.size() && !tls13Ciphers.size()) {
- sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QStringLiteral(""));
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- const QDateTime now = QDateTime::currentDateTimeUtc();
-
- // Add all our CAs to this store.
- const auto caCertificates = sslContext->sslConfiguration.caCertificates();
- for (const QSslCertificate &caCertificate : caCertificates) {
- // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
- //
- // If several CA certificates matching the name, key identifier, and
- // serial number condition are available, only the first one will be
- // examined. This may lead to unexpected results if the same CA
- // certificate is available with different expiration dates. If a
- // ``certificate expired'' verification error occurs, no other
- // certificate will be searched. Make sure to not have expired
- // certificates mixed with valid ones.
- //
- // See also: QSslSocketBackendPrivate::verify()
- if (caCertificate.expiryDate() >= now) {
- q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
- }
- }
-
- if (QSslSocketPrivate::rootCertOnDemandLoadingSupported() && allowRootCertOnDemandLoading) {
- // tell OpenSSL the directories where to look up the root certs on demand
- const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
- int success = 1;
-#if OPENSSL_VERSION_MAJOR < 3
- for (const QByteArray &unixDir : unixDirs) {
- if ((success = q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData())) != 1)
- break;
- }
-#else
- for (const QByteArray &unixDir : unixDirs) {
- if ((success = q_SSL_CTX_load_verify_dir(sslContext->ctx, unixDir.constData())) != 1)
- break;
- }
-#endif // OPENSSL_VERSION_MAJOR
- if (success != 1) {
- const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
- qCWarning(lcSsl) << "An error encountered while to set root certificates location:"
- << qtErrors;
- }
- }
-
- if (!sslContext->sslConfiguration.localCertificate().isNull()) {
- // Require a private key as well.
- if (sslContext->sslConfiguration.privateKey().isNull()) {
- sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Load certificate
- if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
- sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (configuration.d->privateKey.algorithm() == QSsl::Opaque) {
- sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
- } else {
- // Load private key
- sslContext->pkey = q_EVP_PKEY_new();
- // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
- // this lead to a memory leak. Now we use the *_set1_* functions which do not
- // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
- if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
- q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
- else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
- q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
-#ifndef OPENSSL_NO_EC
- else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
- q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
-#endif
- }
- auto pkey = sslContext->pkey;
- if (configuration.d->privateKey.algorithm() == QSsl::Opaque)
- sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
-
- if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
- sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // Check if the certificate matches the private key.
- if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
- sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- // If we have any intermediate certificates then we need to add them to our chain
- bool first = true;
- for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) {
- if (first) {
- first = false;
- continue;
- }
- q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
- q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
- }
- }
-
- // Initialize peer verification, different callbacks, TLS/DTLS verification first
- // (note, all these set_some_callback do not have return value):
- if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
- q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
- } else {
- auto verificationCallback =
- #if QT_CONFIG(dtls)
- isDtls ? dtlscallbacks::q_X509DtlsCallback :
- #endif // dtls
- QTlsPrivate::q_X509Callback;
-
- if (!isDtls && configuration.handshakeMustInterruptOnError())
- verificationCallback = QTlsPrivate::q_X509CallbackDirect;
-
- auto verificationMode = SSL_VERIFY_PEER;
- if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
- verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-
- q_SSL_CTX_set_verify(sslContext->ctx, verificationMode, verificationCallback);
- }
-
-#ifdef TLS1_3_VERSION
- // NewSessionTicket callback:
- if (mode == QSslSocket::SslClientMode && !isDtls) {
- q_SSL_CTX_sess_set_new_cb(sslContext->ctx, q_ssl_sess_set_new_cb);
- q_SSL_CTX_set_session_cache_mode(sslContext->ctx, SSL_SESS_CACHE_CLIENT);
- }
-
-#endif // TLS1_3_VERSION
-
-#if QT_CONFIG(dtls)
- // DTLS cookies:
- if (mode == QSslSocket::SslServerMode && isDtls && configuration.dtlsCookieVerificationEnabled()) {
- q_SSL_CTX_set_cookie_generate_cb(sslContext->ctx, dtlscallbacks::q_generate_cookie_callback);
- q_SSL_CTX_set_cookie_verify_cb(sslContext->ctx, dtlscallbacks::q_verify_cookie_callback);
- }
-#endif // dtls
-
- // Set verification depth.
- if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
- q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
-
- // set persisted session if the user set it
- if (!configuration.sessionTicket().isEmpty())
- sslContext->setSessionASN1(configuration.sessionTicket());
-
- // Set temp DH params
- QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
-
- if (!dhparams.isValid()) {
- sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-
- if (!dhparams.isEmpty()) {
- const QByteArray &params = dhparams.d->derData;
- const char *ptr = params.constData();
- DH *dh = q_d2i_DHparams(nullptr, reinterpret_cast<const unsigned char **>(&ptr),
- params.length());
- if (dh == nullptr)
- qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
- q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
- q_DH_free(dh);
- }
-
-#ifndef OPENSSL_NO_PSK
- if (!client)
- q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
-#endif // !OPENSSL_NO_PSK
-
- const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
- if (!qcurves.isEmpty()) {
-#ifdef OPENSSL_NO_EC
- sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
-#else
- // Set the curves to be used.
- std::vector<int> curves;
- curves.reserve(qcurves.size());
- for (const auto &sslCurve : qcurves)
- curves.push_back(sslCurve.id);
- if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
- sslContext->errorStr = msgErrorSettingEllipticCurves(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-#endif
- }
-
- applyBackendConfig(sslContext);
-}
-
-void QSslContext::applyBackendConfig(QSslContext *sslContext)
-{
- const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
- if (conf.isEmpty())
- return;
-
-#if QT_CONFIG(ocsp)
- auto ocspResponsePos = conf.find("Qt-OCSP-response");
- if (ocspResponsePos != conf.end()) {
- // This is our private, undocumented configuration option, existing only for
- // the purpose of testing OCSP status responses. We don't even check this
- // callback was set. If no - the test must fail.
- q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
- if (conf.size() == 1)
- return;
- }
-#endif // ocsp
-
- QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
- if (cctx) {
- q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx);
- q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE);
-
- for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
- if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
- continue;
-
- if (!i.value().canConvert(QMetaType(QMetaType::QByteArray))) {
- sslContext->errorCode = QSslError::UnspecifiedError;
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Expecting QByteArray for %1").arg(
- QString::fromUtf8(i.key())));
- return;
- }
-
- const QByteArray &value = i.value().toByteArray();
- const int result = q_SSL_CONF_cmd(cctx.data(), i.key().constData(), value.constData());
- if (result == 2)
- continue;
-
- sslContext->errorCode = QSslError::UnspecifiedError;
- switch (result) {
- case 0:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("An error occurred attempting to set %1 to %2").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- case 1:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Wrong value for %1 (%2)").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- default:
- sslContext->errorStr = msgErrorSettingBackendConfig(
- QSslSocket::tr("Unrecognized command %1 = %2").arg(
- QString::fromUtf8(i.key()), QString::fromUtf8(value)));
- return;
- }
- }
-
- if (q_SSL_CONF_CTX_finish(cctx.data()) == 0) {
- sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_finish() failed"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- }
- } else {
- sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_CTX_new() failed"));
- sslContext->errorCode = QSslError::UnspecifiedError;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcontext_openssl_p.h b/src/network/ssl/qsslcontext_openssl_p.h
deleted file mode 100644
index 4b343e7842..0000000000
--- a/src/network/ssl/qsslcontext_openssl_p.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
-
-
-#ifndef QSSLCONTEXT_OPENSSL_P_H
-#define QSSLCONTEXT_OPENSSL_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qvariant.h>
-#include <QtNetwork/qsslcertificate.h>
-#include <QtNetwork/qsslconfiguration.h>
-#include <openssl/ssl.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_SSL
-
-class QSslContext
-{
-public:
-
- ~QSslContext();
-
- static QSslContext* fromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static QSharedPointer<QSslContext> sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
- bool allowRootCertOnDemandLoading);
- static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
-
- QSslError::SslError error() const;
- QString errorString() const;
-
- SSL* createSsl();
- bool cacheSession(SSL*); // should be called when handshake completed
-
- QByteArray sessionASN1() const;
- void setSessionASN1(const QByteArray &sessionASN1);
- int sessionTicketLifeTimeHint() const;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- // must be public because we want to use it from an OpenSSL callback
- struct NPNContext {
- NPNContext() : data(nullptr),
- len(0),
- status(QSslConfiguration::NextProtocolNegotiationNone)
- { }
- unsigned char *data;
- unsigned short len;
- QSslConfiguration::NextProtocolNegotiationStatus status;
- };
- NPNContext npnContext() const;
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-protected:
- QSslContext();
- friend class QSharedPointer<QSslContext>;
-
-private:
- static void initSslContext(QSslContext* sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration,
- bool allowRootCertOnDemandLoading);
- static void applyBackendConfig(QSslContext *sslContext);
-
-private:
- SSL_CTX* ctx;
- EVP_PKEY *pkey;
- SSL_SESSION *session;
- QByteArray m_sessionASN1;
- int m_sessionTicketLifeTimeHint;
- QSslError::SslError errorCode;
- QString errorStr;
- QSslConfiguration sslConfiguration;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- QByteArray m_supportedNPNVersions;
- NPNContext m_npnContext;
-#endif // !OPENSSL_NO_NEXTPROTONEG
-};
-
-#endif // QT_NO_SSL
-
-QT_END_NAMESPACE
-
-#endif // QSSLCONTEXT_OPENSSL_P_H
diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
deleted file mode 100644
index 8e0458de4e..0000000000
--- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qtlsbackend_openssl_p.h"
-#include "qsslsocket_p.h"
-
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qdebug.h>
-
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-
-#ifdef OPENSSL_NO_DEPRECATED_3_0
-
-int q_DH_check(DH *dh, int *status)
-{
- // DH_check was first deprecated in OpenSSL 3.0.0, as low-level
- // API; the EVP_PKEY family of functions was advised as an alternative.
- // As of now EVP_PKEY_params_check ends up calling ... DH_check,
- // which is good enough.
-
- Q_ASSERT(dh);
- Q_ASSERT(status);
-
- EVP_PKEY *key = q_EVP_PKEY_new();
- if (!key) {
- qCWarning(lcSsl, "EVP_PKEY_new failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
- const auto keyDeleter = qScopeGuard([key](){
- q_EVP_PKEY_free(key);
- });
- if (!q_EVP_PKEY_set1_DH(key, dh)) {
- qCWarning(lcTlsBackend, "EVP_PKEY_set1_DH failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
-
- EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
- if (!keyCtx) {
- qCWarning(lcTlsBackend, "EVP_PKEY_CTX_new failed");
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return 0;
- }
- const auto ctxDeleter = qScopeGuard([keyCtx]{
- q_EVP_PKEY_CTX_free(keyCtx);
- });
-
- const int result = q_EVP_PKEY_param_check(keyCtx);
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- // Note: unlike DH_check, we cannot obtain the 'status',
- // if the 'result' is 0 (actually the result is 1 only
- // if this 'status' was 0). We could probably check the
- // errors from the error queue, but it's not needed anyway
- // - see the 'isSafeDH' below, how it returns immediately
- // on 0.
- Q_UNUSED(status);
-
- return result;
-}
-#endif // OPENSSL_NO_DEPRECATED_3_0
-
-bool isSafeDH(DH *dh)
-{
- int status = 0;
- int bad = 0;
-
- // TLSTODO: check it's needed or if supportsSsl()
- // is enough.
- QSslSocketPrivate::ensureInitialized();
-
- // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters:
- //
- // The additional call to BN_mod_word(dh->p, 24)
- // (and unmasking of DH_NOT_SUITABLE_GENERATOR)
- // is performed to ensure your program accepts
- // IETF group parameters. OpenSSL checks the prime
- // is congruent to 11 when g = 2; while the IETF's
- // primes are congruent to 23 when g = 2.
- // Without the test, the IETF parameters would
- // fail validation. For details, see Diffie-Hellman
- // Parameter Check (when g = 2, must p mod 24 == 11?).
- // Mark p < 1024 bits as unsafe.
- if (q_DH_bits(dh) < 1024)
- return false;
-
- if (q_DH_check(dh, &status) != 1)
- return false;
-
- const BIGNUM *p = nullptr;
- const BIGNUM *q = nullptr;
- const BIGNUM *g = nullptr;
- q_DH_get0_pqg(dh, &p, &q, &g);
-
- if (q_BN_is_word(const_cast<BIGNUM *>(g), DH_GENERATOR_2)) {
- const unsigned long residue = q_BN_mod_word(p, 24);
- if (residue == 11 || residue == 23)
- status &= ~DH_NOT_SUITABLE_GENERATOR;
- }
-
- bad |= DH_CHECK_P_NOT_PRIME;
- bad |= DH_CHECK_P_NOT_SAFE_PRIME;
- bad |= DH_NOT_SUITABLE_GENERATOR;
-
- return !(status & bad);
-}
-
-} // unnamed namespace
-
-int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const
-{
- Q_ASSERT(derData);
-
- if (der.isEmpty())
- return DHParams::InvalidInputDataError;
-
- const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data());
- const int len = der.size();
-
- // TLSTODO: check it's needed (loading ciphers and certs in
- // addition to the library!)
- QSslSocketPrivate::ensureInitialized();
-
- DH *dh = q_d2i_DHparams(nullptr, &data, len);
- if (dh) {
- const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);});
-
- if (isSafeDH(dh))
- *derData = der;
- else
- return DHParams::UnsafeParametersError;
- } else {
- return DHParams::InvalidInputDataError;
- }
-
- return DHParams::NoError;
-}
-
-int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *data) const
-{
- Q_ASSERT(data);
-
- if (pem.isEmpty())
- return DHParams::InvalidInputDataError;
-
- // TLSTODO: check it was not a cargo-cult programming in case of
- // DH ...
- QSslSocketPrivate::ensureInitialized();
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio)
- return DHParams::InvalidInputDataError;
-
- const auto bioRaii = qScopeGuard([bio]
- {
- q_BIO_free(bio);
- });
-
- DH *dh = nullptr;
- q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr);
-
- if (dh) {
- const auto dhGuard = qScopeGuard([dh]
- {
- q_DH_free(dh);
- });
-
- if (isSafeDH(dh)) {
- char *buf = nullptr;
- const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
- if (len > 0)
- *data = QByteArray(buf, len);
- else
- return DHParams::InvalidInputDataError;
- } else {
- return DHParams::UnsafeParametersError;
- }
- } else {
- return DHParams::InvalidInputDataError;
- }
-
- return DHParams::NoError;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index 010f45fca9..8a5af25e75 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -57,12 +57,8 @@
#include "qssl_p.h"
#include "qsslkey.h"
#include "qsslkey_p.h"
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
#include "qsslsocket.h"
#include "qsslsocket_p.h"
-#include "qasn1element_p.h"
#include "qtlsbackend_p.h"
#include <QtCore/qatomic.h>
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index f5895561b4..6fea1ad66a 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -73,8 +73,8 @@ public:
using Cipher = QTlsPrivate::Cipher;
- Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
- Q_AUTOTEST_EXPORT static QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
+ Q_NETWORK_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
+ Q_NETWORK_EXPORT static QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
std::unique_ptr<QTlsPrivate::TlsKey> backend;
QAtomicInt ref;
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 546c26272d..003bbf0787 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1573,7 +1573,7 @@ QList<QString> QSslSocket::availableBackends()
from the list of available backends.
\note When selecting a default backend implicitly, QSslSocket prefers
- native backends, such as SecureTransport on Darwin, or Schannel on Windows.
+ the OpenSSL backend if available.
\sa setActiveBackend(), availableBackends()
*/
diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
deleted file mode 100644
index 837ac4a4f6..0000000000
--- a/src/network/ssl/qsslsocket_mac_shared.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2015 ownCloud Inc
-** 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$
-**
-****************************************************************************/
-
-#include "qsslcertificate.h"
-
-#include <QtCore/qglobal.h>
-
-#ifdef Q_OS_MACOS
-
-#include "qtlsbackend_p.h"
-
-#include <private/qcore_mac_p.h>
-
-#include <QtCore/qdebug.h>
-
-#include <CoreFoundation/CFArray.h>
-#include <Security/Security.h>
-
-#endif // Q_OS_MACOS
-
-QT_BEGIN_NAMESPACE
-
-#ifdef Q_OS_MACOS
-namespace {
-
-bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) {
- QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy);
- // only accept certificates with policies for SSL server validation for now
- if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) {
- CFBooleanRef policyClient;
- if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) &&
- CFEqual(policyClient, kCFBooleanTrue)) {
- return false; // no client certs
- }
- if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) {
- // as per the docs, no trust settings result implies full trust
- return true;
- }
- CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult));
- SecTrustSettingsResult settingsResult;
- CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult);
- switch (settingsResult) {
- case kSecTrustSettingsResultTrustRoot:
- case kSecTrustSettingsResultTrustAsRoot:
- return true;
- default:
- return false;
- }
- }
- return false;
-}
-
-bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
-{
- QCFType<CFArrayRef> cfTrustSettings;
- OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, SecTrustSettingsDomain(domain), &cfTrustSettings);
- if (status == noErr) {
- CFIndex size = CFArrayGetCount(cfTrustSettings);
- // if empty, trust for everything (as per the Security Framework documentation)
- if (size == 0) {
- return true;
- } else {
- for (CFIndex i = 0; i < size; ++i) {
- CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i));
- if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) {
- if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props))
- return true;
- }
- }
- }
- } else {
- qCWarning(lcTlsBackend, "Error receiving trust for a CA certificate");
- }
- return false;
-}
-
-} // unnamed namespace
-#endif // Q_OS_MACOS
-
-namespace QTlsPrivate {
-QList<QSslCertificate> systemCaCertificates()
-{
- QList<QSslCertificate> systemCerts;
- // SecTrustSettingsCopyCertificates is not defined on iOS.
-#ifdef Q_OS_MACOS
- // iterate through all enum members, order:
- // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem
- for (int dom = kSecTrustSettingsDomainUser; dom <= int(kSecTrustSettingsDomainSystem); dom++) {
- QCFType<CFArrayRef> cfCerts;
- OSStatus status = SecTrustSettingsCopyCertificates(SecTrustSettingsDomain(dom), &cfCerts);
- if (status == noErr) {
- const CFIndex size = CFArrayGetCount(cfCerts);
- for (CFIndex i = 0; i < size; ++i) {
- SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
- QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
- if (isCaCertificateTrusted(cfCert, dom)) {
- if (derData == nullptr) {
- qCWarning(lcSsl, "Error retrieving a CA certificate from the system store");
- } else {
- systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
- }
- }
- }
- }
-#endif
- return systemCerts;
-}
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_android.cpp b/src/network/ssl/qsslsocket_openssl_android.cpp
deleted file mode 100644
index 22884cb819..0000000000
--- a/src/network/ssl/qsslsocket_openssl_android.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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 "qsslsocket_p.h"
-#include <QtCore/QJniEnvironment>
-#include <QtCore/QJniObject>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-QList<QByteArray> fetchSslCertificateData()
-{
- QList<QByteArray> certificateData;
-
- QJniObject certificates = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
- "getSSLCertificates",
- "()[[B");
- if (!certificates.isValid())
- return certificateData;
-
- QJniEnvironment env;
- jobjectArray jcertificates = static_cast<jobjectArray>(certificates.object());
- const jint nCertificates = env->GetArrayLength(jcertificates);
- certificateData.reserve(static_cast<int>(nCertificates));
-
- for (int i = 0; i < nCertificates; ++i) {
- jbyteArray jCert = static_cast<jbyteArray>(env->GetObjectArrayElement(jcertificates, i));
- const uint sz = env->GetArrayLength(jCert);
- jbyte *buffer = env->GetByteArrayElements(jCert, 0);
- certificateData.append(QByteArray(reinterpret_cast<char*>(buffer), sz));
-
- env->ReleaseByteArrayElements(jCert, buffer, JNI_ABORT); // don't copy back the elements
- env->DeleteLocalRef(jCert);
- }
-
- return certificateData;
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
deleted file mode 100644
index 82429800f8..0000000000
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ /dev/null
@@ -1,1234 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** In addition, as a special exception, the copyright holders listed above give
-** permission to link the code of its release of Qt with the OpenSSL project's
-** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
-** same license as the original version), and distribute the linked executables.
-**
-** You must comply with the GNU General Public License version 2 in all
-** respects for all of the code used other than the "OpenSSL" code. If you
-** modify this file, you may extend this exception to your version of the file,
-** but you are not obligated to do so. If you do not wish to do so, delete
-** this exception statement from your version of this file.
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-
-#ifdef Q_OS_WIN
-# include <private/qsystemlibrary_p.h>
-#elif QT_CONFIG(library)
-# include <QtCore/qlibrary.h>
-#endif
-#include <QtCore/qmutex.h>
-#include <QtCore/qdatetime.h>
-#if defined(Q_OS_UNIX)
-#include <QtCore/qdir.h>
-#endif
-#include <QtCore/private/qduplicatetracker_p.h>
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
-#include <link.h>
-#endif
-#ifdef Q_OS_DARWIN
-#include "private/qcore_mac_p.h"
-#endif
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-/*
- 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
-
-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_up_ref, EVP_PKEY *a, a, return 0, return)
-DEFINEFUNC2(EVP_PKEY_CTX *, EVP_PKEY_CTX_new, EVP_PKEY *pkey, pkey, ENGINE *e, e, return nullptr, return)
-DEFINEFUNC(int, EVP_PKEY_param_check, EVP_PKEY_CTX *ctx, ctx, return 0, return)
-DEFINEFUNC(void, EVP_PKEY_CTX_free, EVP_PKEY_CTX *ctx, ctx, return, 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)
-using info_callback = void (*) (const SSL *ssl, int type, int val);
-DEFINEFUNC2(void, SSL_set_info_callback, SSL *ssl, ssl, info_callback cb, cb, return, return)
-DEFINEFUNC(const char *, SSL_alert_type_string, int value, value, return nullptr, return)
-DEFINEFUNC(const char *, SSL_alert_desc_string_long, int value, value, return nullptr, return)
-DEFINEFUNC(int, SSL_CTX_get_security_level, const SSL_CTX *ctx, ctx, return -1, return)
-DEFINEFUNC2(void, SSL_CTX_set_security_level, SSL_CTX *ctx, ctx, int level, level, return, return)
-#ifdef TLS1_3_VERSION
-DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
-DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_sess_set_new_cb, SSL_CTX *ctx, ctx, NewSessionCallback cb, cb, return, return)
-DEFINEFUNC(int, SSL_SESSION_is_resumable, const SSL_SESSION *s, s, 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)
-DEFINEFUNC3(int, X509_STORE_set_ex_data, X509_STORE *a, a, int idx, idx, void *data, data, return 0, return)
-DEFINEFUNC2(void *, X509_STORE_get_ex_data, X509_STORE *r, r, int idx, idx, return nullptr, return)
-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)
-
-#if QT_CONFIG(dtls)
-DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
-DEFINEFUNC(BIO_ADDR *, BIO_ADDR_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(void, BIO_ADDR_free, BIO_ADDR *ap, ap, return, DUMMYARG)
-DEFINEFUNC2(BIO_METHOD *, BIO_meth_new, int type, type, const char *name, name, return nullptr, return)
-DEFINEFUNC(void, BIO_meth_free, BIO_METHOD *biom, biom, return, DUMMYARG)
-DEFINEFUNC2(int, BIO_meth_set_write, BIO_METHOD *biom, biom, DgramWriteCallback write, write, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_read, BIO_METHOD *biom, biom, DgramReadCallback read, read, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_puts, BIO_METHOD *biom, biom, DgramPutsCallback puts, puts, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_ctrl, BIO_METHOD *biom, biom, DgramCtrlCallback ctrl, ctrl, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_create, BIO_METHOD *biom, biom, DgramCreateCallback crt, crt, return 0, return)
-DEFINEFUNC2(int, BIO_meth_set_destroy, BIO_METHOD *biom, biom, DgramDestroyCallback dtr, dtr, return 0, return)
-#endif // dtls
-
-#if QT_CONFIG(ocsp)
-DEFINEFUNC(const OCSP_CERTID *, OCSP_SINGLERESP_get0_id, const OCSP_SINGLERESP *x, x, return nullptr, return)
-DEFINEFUNC3(OCSP_RESPONSE *, d2i_OCSP_RESPONSE, OCSP_RESPONSE **a, a, const unsigned char **in, in, long len, len, return nullptr, return)
-DEFINEFUNC(void, OCSP_RESPONSE_free, OCSP_RESPONSE *rs, rs, return, DUMMYARG)
-DEFINEFUNC(OCSP_BASICRESP *, OCSP_response_get1_basic, OCSP_RESPONSE *resp, resp, return nullptr, return)
-DEFINEFUNC(void, OCSP_BASICRESP_free, OCSP_BASICRESP *bs, bs, return, DUMMYARG)
-DEFINEFUNC(int, OCSP_response_status, OCSP_RESPONSE *resp, resp, return OCSP_RESPONSE_STATUS_INTERNALERROR, return)
-DEFINEFUNC4(int, OCSP_basic_verify, OCSP_BASICRESP *bs, bs, STACK_OF(X509) *certs, certs, X509_STORE *st, st, unsigned long flags, flags, return -1, return)
-DEFINEFUNC(int, OCSP_resp_count, OCSP_BASICRESP *bs, bs, return 0, return)
-DEFINEFUNC2(OCSP_SINGLERESP *, OCSP_resp_get0, OCSP_BASICRESP *bs, bs, int idx, idx, return nullptr, return)
-DEFINEFUNC5(int, OCSP_single_get0_status, OCSP_SINGLERESP *single, single, int *reason, reason, ASN1_GENERALIZEDTIME **revtime, revtime,
- ASN1_GENERALIZEDTIME **thisupd, thisupd, ASN1_GENERALIZEDTIME **nextupd, nextupd, return -1, return)
-DEFINEFUNC4(int, OCSP_check_validity, ASN1_GENERALIZEDTIME *thisupd, thisupd, ASN1_GENERALIZEDTIME *nextupd, nextupd, long nsec, nsec, long maxsec, maxsec, return 0, return)
-DEFINEFUNC3(OCSP_CERTID *, OCSP_cert_to_id, const EVP_MD *dgst, dgst, X509 *subject, subject, X509 *issuer, issuer, return nullptr, return)
-DEFINEFUNC(void, OCSP_CERTID_free, OCSP_CERTID *cid, cid, return, DUMMYARG)
-DEFINEFUNC5(int, OCSP_id_get0_info, ASN1_OCTET_STRING **piNameHash, piNameHash, ASN1_OBJECT **pmd, pmd,
- ASN1_OCTET_STRING **piKeyHash, piKeyHash, ASN1_INTEGER **pserial, pserial, OCSP_CERTID *cid, cid,
- return 0, return)
-DEFINEFUNC2(OCSP_RESPONSE *, OCSP_response_create, int status, status, OCSP_BASICRESP *bs, bs, return nullptr, return)
-DEFINEFUNC(const STACK_OF(X509) *, OCSP_resp_get0_certs, const OCSP_BASICRESP *bs, bs, return nullptr, return)
-DEFINEFUNC2(int, OCSP_id_cmp, OCSP_CERTID *a, a, OCSP_CERTID *b, b, return -1, return)
-DEFINEFUNC7(OCSP_SINGLERESP *, OCSP_basic_add1_status, OCSP_BASICRESP *r, r, OCSP_CERTID *c, c, int s, s,
- int re, re, ASN1_TIME *rt, rt, ASN1_TIME *t, t, ASN1_TIME *n, n, return nullptr, return)
-DEFINEFUNC(OCSP_BASICRESP *, OCSP_BASICRESP_new, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC2(int, i2d_OCSP_RESPONSE, OCSP_RESPONSE *r, r, unsigned char **ppout, ppout, return 0, return)
-DEFINEFUNC6(int, OCSP_basic_sign, OCSP_BASICRESP *br, br, X509 *signer, signer, EVP_PKEY *key, key,
- const EVP_MD *dg, dg, STACK_OF(X509) *cs, cs, unsigned long flags, flags, return 0, return)
-#endif // ocsp
-
-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)
-
-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)
-DEFINEFUNC2(int, ASN1_TIME_to_tm, const ASN1_TIME *s, s, struct tm *tm, tm, 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)
-DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return nullptr, return)
-DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
-
-DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
-DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
-DEFINEFUNC2(BN_ULONG, BN_mod_word, const BIGNUM *a, a, BN_ULONG w, w, return static_cast<BN_ULONG>(-1), return)
-#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)
-#ifndef OPENSSL_NO_DES
-DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-#ifndef OPENSSL_NO_RC2
-DEFINEFUNC(const EVP_CIPHER *, EVP_rc2_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-#ifndef OPENSSL_NO_AES
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_128_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_192_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const EVP_CIPHER *, EVP_aes_256_cbc, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif
-DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, void *r, r, 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
-DEFINEFUNC2(int, EVP_PKEY_cmp, const EVP_PKEY *a, a, const EVP_PKEY *b, b, return -1, return)
-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(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)
-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)
-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)
-DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
-#endif // OPENSSL_NO_EC
-
-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)
-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)
-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)
-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)
-DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
-DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
-DEFINEFUNC3(char *, SSL_CIPHER_description, const SSL_CIPHER *a, a, char *b, b, int c, c, return nullptr, return)
-DEFINEFUNC2(int, SSL_CIPHER_get_bits, const SSL_CIPHER *a, a, int *b, b, return 0, return)
-DEFINEFUNC(BIO *, SSL_get_rbio, const SSL *s, s, return nullptr, return)
-DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
-DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
-DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
-DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return nullptr, return)
-DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
-DEFINEFUNC3(long, SSL_CTX_callback_ctrl, SSL_CTX *ctx, ctx, int dst, dst, GenericCallbackType cb, cb, return 0, return)
-DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
-DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
-DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
-DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
-DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
-DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
-DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
-DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return nullptr, return)
-DEFINEFUNC(SSL_CONF_CTX *, SSL_CONF_CTX_new, DUMMYARG, DUMMYARG, return nullptr, return);
-DEFINEFUNC(void, SSL_CONF_CTX_free, SSL_CONF_CTX *a, a, return ,return);
-DEFINEFUNC2(void, SSL_CONF_CTX_set_ssl_ctx, SSL_CONF_CTX *a, a, SSL_CTX *b, b, return, return);
-DEFINEFUNC2(unsigned int, SSL_CONF_CTX_set_flags, SSL_CONF_CTX *a, a, unsigned int b, b, return 0, return);
-DEFINEFUNC(int, SSL_CONF_CTX_finish, SSL_CONF_CTX *a, a, return 0, return);
-DEFINEFUNC3(int, SSL_CONF_cmd, SSL_CONF_CTX *a, a, const char *b, b, const char *c, c, return 0, return);
-DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return nullptr, return)
-DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr, return)
-DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
-DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
-DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return nullptr, return)
-DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return nullptr, return)
-DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
-DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return nullptr, return)
-DEFINEFUNC(SSL_CTX *, SSL_get_SSL_CTX, SSL *a, a, return nullptr, return)
-DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return)
-DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
-DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
-DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
-DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
-DEFINEFUNC(int, SSL_in_init, const SSL *a, a, return 0, return)
-DEFINEFUNC(int, SSL_get_shutdown, const SSL *ssl, ssl, return 0, return)
-DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, return -1, return)
-DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
-DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return nullptr, return)
-DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return nullptr, return)
-DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
-DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return nullptr, return)
-
-#ifndef OPENSSL_NO_PSK
-DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
-DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
-#endif // !OPENSSL_NO_PSK
-
-DEFINEFUNC3(int, SSL_write, SSL *a, a, const void *b, b, int c, c, return -1, 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)
-DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return nullptr, return)
-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 *, X509_STORE_CTX_get0_store, X509_STORE_CTX *ctx, ctx, 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)
-
-#if OPENSSL_VERSION_MAJOR < 3
-DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
-#else
-DEFINEFUNC2(int, SSL_CTX_load_verify_dir, SSL_CTX *ctx, ctx, const char *CApath, CApath, return 0, return)
-#endif // OPENSSL_VERSION_MAJOR
-
-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)
-
-#ifndef 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)
-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_NO_NEXTPROTONEG
-
-// DTLS:
-#if QT_CONFIG(dtls)
-DEFINEFUNC2(void, SSL_CTX_set_cookie_generate_cb, SSL_CTX *ctx, ctx, CookieGenerateCallback cb, cb, return, DUMMYARG)
-DEFINEFUNC2(void, SSL_CTX_set_cookie_verify_cb, SSL_CTX *ctx, ctx, CookieVerifyCallback cb, cb, return, DUMMYARG)
-DEFINEFUNC(const SSL_METHOD *, DTLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return)
-DEFINEFUNC(const SSL_METHOD *, DTLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return)
-#endif // dtls
-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)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
-DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
-#endif // OPENSSL_NO_DEPRECATED_3_0
-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)
-DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
-#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)
-
-#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()(QStringView lhs, QStringView 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()(QStringView lhs, QStringView rhs) const
- {
- const auto lhsparts = lhs.split(QLatin1Char('.'));
- const auto rhsparts = rhs.split(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;
- QDuplicateTracker<QString> *paths = (QDuplicateTracker<QString> *)data;
- QString path = QString::fromLocal8Bit(info->dlpi_name);
- if (!path.isEmpty()) {
- QFileInfo fi(path);
- path = fi.absolutePath();
- if (!path.isEmpty())
- (void)paths->hasSeen(std::move(path));
- }
- return 0;
-}
-#endif
-
-static QStringList libraryPathList()
-{
- QStringList paths;
-# ifdef Q_OS_DARWIN
- paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH"))
- .split(QLatin1Char(':'), Qt::SkipEmptyParts);
-
- // search in .app/Contents/Frameworks
- UInt32 packageType;
- CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, nullptr);
- if (packageType == FOUR_CHAR_CODE('APPL')) {
- QUrl bundleUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyBundleURL(CFBundleGetMainBundle())));
- QUrl frameworksUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle())));
- paths << bundleUrl.resolved(frameworksUrl).path();
- }
-# else
- paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
- .split(QLatin1Char(':'), Qt::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
- QDuplicateTracker<QString> loadedPaths;
- dl_iterate_phdr(dlIterateCallback, &loadedPaths);
- std::move(loadedPaths).appendTo(paths);
-#endif
-
- return paths;
-}
-
-Q_NEVER_INLINE
-static QStringList findAllLibs(QLatin1String filter)
-{
- const QStringList paths = libraryPathList();
- QStringList found;
- const QStringList filters((QString(filter)));
-
- for (const QString &path : paths) {
- QDir dir(path);
- QStringList entryList = dir.entryList(filters, QDir::Files);
-
- std::sort(entryList.begin(), entryList.end(), LibGreaterThan());
- for (const QString &entry : qAsConst(entryList))
- found << path + QLatin1Char('/') + entry;
- }
-
- return found;
-}
-
-static QStringList findAllLibSsl()
-{
- return findAllLibs(QLatin1String("libssl.*"));
-}
-
-static QStringList findAllLibCrypto()
-{
- return findAllLibs(QLatin1String("libcrypto.*"));
-}
-# endif
-
-#ifdef Q_OS_WIN
-
-struct LoadedOpenSsl {
- std::unique_ptr<QSystemLibrary> ssl, crypto;
-};
-
-static bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result)
-{
- auto ssleay32 = std::make_unique<QSystemLibrary>(ssleay32LibName);
- if (!ssleay32->load(false)) {
- return FALSE;
- }
-
- auto libeay32 = std::make_unique<QSystemLibrary>(libeay32LibName);
- if (!libeay32->load(false)) {
- return FALSE;
- }
-
- result.ssl = std::move(ssleay32);
- result.crypto = std::move(libeay32);
- return TRUE;
-}
-
-static LoadedOpenSsl loadOpenSsl()
-{
- LoadedOpenSsl result;
-
- // With OpenSSL 1.1 the names have changed to libssl-1_1 and libcrypto-1_1 for builds using
- // MSVC and GCC, with architecture suffixes for non-x86 builds.
-
-#if defined(Q_PROCESSOR_X86_64)
-#define QT_SSL_SUFFIX "-x64"
-#elif defined(Q_PROCESSOR_ARM_64)
-#define QT_SSL_SUFFIX "-arm64"
-#elif defined(Q_PROCESSOR_ARM_32)
-#define QT_SSL_SUFFIX "-arm"
-#else
-#define QT_SSL_SUFFIX
-#endif
-
- tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX),
- QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result);
-
-#undef QT_SSL_SUFFIX
- return result;
-}
-#else
-
-struct LoadedOpenSsl {
- std::unique_ptr<QLibrary> ssl, crypto;
-};
-
-static LoadedOpenSsl loadOpenSsl()
-{
- LoadedOpenSsl result = { std::make_unique<QLibrary>(), std::make_unique<QLibrary>() };
-
-# if defined(Q_OS_UNIX)
- QLibrary * const libssl = result.ssl.get();
- QLibrary * const libcrypto = result.crypto.get();
-
- // Try to find the libssl library on the system.
- //
- // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that
- // is, libssl.so on most Unix systems. However, the .so file isn't present in
- // user installations because it's considered a development file.
- //
- // The right thing to do is to load the library at the major version we know how
- // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h)
- //
- // However, OpenSSL is a well-known case of binary-compatibility breakage. To
- // avoid such problems, many system integrators and Linux distributions change
- // the soname of the binary, letting the full version number be the soname. So
- // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that
- // reason, we will search a few common paths (see findAllLibSsl() above) in hopes
- // we find one that works.
- //
- // If that fails, for OpenSSL 1.0 we also try some fallbacks -- look up
- // libssl.so with a hardcoded soname. The reason is QTBUG-68156: the binary
- // builds of Qt happen (at the time of this writing) on RHEL machines,
- // which change SHLIB_VERSION_NUMBER to a non-portable string. When running
- // those binaries on the target systems, this code won't pick up
- // libssl.so.MODIFIED_SHLIB_VERSION_NUMBER because it doesn't exist there.
- // Given that the only 1.0 supported release (at the time of this writing)
- // is 1.0.2, with soname "1.0.0", give that a try too. Note that we mandate
- // OpenSSL >= 1.0.0 with a configure-time check, and OpenSSL has kept binary
- // compatibility between 1.0.0 and 1.0.2.
- //
- // It is important, however, to try the canonical name and the unversioned name
- // without going through the loop. By not specifying a path, we let the system
- // dlopen(3) function determine it for us. This will include any DT_RUNPATH or
- // DT_RPATH tags on our library header as well as other system-specific search
- // paths. See the man page for dlopen(3) on your system for more information.
-
-#ifdef Q_OS_OPENBSD
- libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
-#endif
-#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
- // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
- libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER));
- libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER));
- if (libcrypto->load() && libssl->load()) {
- // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
- return result;
- } else {
- libssl->unload();
- libcrypto->unload();
- }
-#endif
-
-#ifndef Q_OS_DARWIN
- // second attempt: find the development files libssl.so and libcrypto.so
- //
- // disabled on macOS/iOS:
- // macOS's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third
- // attempt, _after_ <bundle>/Contents/Frameworks has been searched.
- // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place.
-# if defined(Q_OS_ANDROID)
- // OpenSSL 1.1.x must be suffixed otherwise it will use the system libcrypto.so libssl.so which on API-21 are OpenSSL 1.0 not 1.1
- auto openSSLSuffix = [](const QByteArray &defaultSuffix = {}) {
- auto suffix = qgetenv("ANDROID_OPENSSL_SUFFIX");
- if (suffix.isEmpty())
- return defaultSuffix;
- return suffix;
- };
-
- static QString suffix = QString::fromLatin1(openSSLSuffix("_1_1"));
-
- 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;
-
- RESOLVEFUNC(OPENSSL_init_ssl)
- RESOLVEFUNC(OPENSSL_init_crypto)
- RESOLVEFUNC(ASN1_STRING_get0_data)
- RESOLVEFUNC(EVP_CIPHER_CTX_reset)
- RESOLVEFUNC(EVP_PKEY_up_ref)
- RESOLVEFUNC(EVP_PKEY_CTX_new)
- RESOLVEFUNC(EVP_PKEY_param_check)
- RESOLVEFUNC(EVP_PKEY_CTX_free)
- 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(SSL_CTX_set_options)
- RESOLVEFUNC(SSL_set_info_callback)
- RESOLVEFUNC(SSL_alert_type_string)
- RESOLVEFUNC(SSL_alert_desc_string_long)
- RESOLVEFUNC(SSL_CTX_get_security_level)
- RESOLVEFUNC(SSL_CTX_set_security_level)
-#ifdef TLS1_3_VERSION
- RESOLVEFUNC(SSL_CTX_set_ciphersuites)
- RESOLVEFUNC(SSL_set_psk_use_session_callback)
- RESOLVEFUNC(SSL_CTX_sess_set_new_cb)
- RESOLVEFUNC(SSL_SESSION_is_resumable)
-#endif // TLS 1.3 or OpenSSL > 1.1.1
-
- RESOLVEFUNC(SSL_get_client_random)
- RESOLVEFUNC(SSL_SESSION_get_master_key)
- RESOLVEFUNC(SSL_session_reused)
- RESOLVEFUNC(SSL_get_session)
- RESOLVEFUNC(SSL_set_options)
- RESOLVEFUNC(CRYPTO_get_ex_new_index)
- RESOLVEFUNC(TLS_method)
- RESOLVEFUNC(TLS_client_method)
- RESOLVEFUNC(TLS_server_method)
- 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(X509_STORE_set_ex_data)
- RESOLVEFUNC(X509_STORE_get_ex_data)
- 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(SSL_SESSION_get_ticket_lifetime_hint)
- RESOLVEFUNC(DH_bits)
- RESOLVEFUNC(DSA_bits)
-
-#if QT_CONFIG(dtls)
- RESOLVEFUNC(DTLSv1_listen)
- RESOLVEFUNC(BIO_ADDR_new)
- RESOLVEFUNC(BIO_ADDR_free)
- RESOLVEFUNC(BIO_meth_new)
- RESOLVEFUNC(BIO_meth_free)
- RESOLVEFUNC(BIO_meth_set_write)
- RESOLVEFUNC(BIO_meth_set_read)
- RESOLVEFUNC(BIO_meth_set_puts)
- RESOLVEFUNC(BIO_meth_set_ctrl)
- RESOLVEFUNC(BIO_meth_set_create)
- RESOLVEFUNC(BIO_meth_set_destroy)
-#endif // dtls
-
-#if QT_CONFIG(ocsp)
- RESOLVEFUNC(OCSP_SINGLERESP_get0_id)
- RESOLVEFUNC(d2i_OCSP_RESPONSE)
- RESOLVEFUNC(OCSP_RESPONSE_free)
- RESOLVEFUNC(OCSP_response_status)
- RESOLVEFUNC(OCSP_response_get1_basic)
- RESOLVEFUNC(OCSP_BASICRESP_free)
- RESOLVEFUNC(OCSP_basic_verify)
- RESOLVEFUNC(OCSP_resp_count)
- RESOLVEFUNC(OCSP_resp_get0)
- RESOLVEFUNC(OCSP_single_get0_status)
- RESOLVEFUNC(OCSP_check_validity)
- RESOLVEFUNC(OCSP_cert_to_id)
- RESOLVEFUNC(OCSP_id_get0_info)
- RESOLVEFUNC(OCSP_resp_get0_certs)
- RESOLVEFUNC(OCSP_basic_sign)
- RESOLVEFUNC(OCSP_response_create)
- RESOLVEFUNC(i2d_OCSP_RESPONSE)
- RESOLVEFUNC(OCSP_basic_add1_status)
- RESOLVEFUNC(OCSP_BASICRESP_new)
- RESOLVEFUNC(OCSP_CERTID_free)
- RESOLVEFUNC(OCSP_cert_to_id)
- RESOLVEFUNC(OCSP_id_cmp)
-#endif // ocsp
-
- RESOLVEFUNC(BIO_set_data)
- RESOLVEFUNC(BIO_get_data)
- RESOLVEFUNC(BIO_set_init)
- RESOLVEFUNC(BIO_get_shutdown)
- RESOLVEFUNC(BIO_set_shutdown)
- RESOLVEFUNC(ASN1_INTEGER_get)
- RESOLVEFUNC(ASN1_INTEGER_cmp)
- RESOLVEFUNC(ASN1_STRING_length)
- RESOLVEFUNC(ASN1_STRING_to_UTF8)
- RESOLVEFUNC(ASN1_TIME_to_tm)
- 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)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EC_KEY_get0_group)
- RESOLVEFUNC(EC_GROUP_get_degree)
-#endif
- RESOLVEFUNC(BN_num_bits)
- RESOLVEFUNC(BN_is_word)
- RESOLVEFUNC(BN_mod_word)
- RESOLVEFUNC(DSA_new)
- RESOLVEFUNC(DSA_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)
-#ifndef OPENSSL_NO_DES
- RESOLVEFUNC(EVP_des_cbc)
- RESOLVEFUNC(EVP_des_ede3_cbc)
-#endif
-#ifndef OPENSSL_NO_RC2
- RESOLVEFUNC(EVP_rc2_cbc)
-#endif
-#ifndef OPENSSL_NO_AES
- RESOLVEFUNC(EVP_aes_128_cbc)
- RESOLVEFUNC(EVP_aes_192_cbc)
- RESOLVEFUNC(EVP_aes_256_cbc)
-#endif
- RESOLVEFUNC(EVP_sha1)
- RESOLVEFUNC(EVP_PKEY_assign)
- RESOLVEFUNC(EVP_PKEY_set1_RSA)
- RESOLVEFUNC(EVP_PKEY_set1_DSA)
- RESOLVEFUNC(EVP_PKEY_set1_DH)
-
-#ifndef OPENSSL_NO_EC
- RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
- RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
- RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
- RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
-#endif // OPENSSL_NO_EC
-
- RESOLVEFUNC(EVP_PKEY_cmp)
- RESOLVEFUNC(EVP_PKEY_free)
- RESOLVEFUNC(EVP_PKEY_get1_DSA)
- RESOLVEFUNC(EVP_PKEY_get1_RSA)
- RESOLVEFUNC(EVP_PKEY_get1_DH)
- 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)
- RESOLVEFUNC(PEM_read_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
- RESOLVEFUNC(PEM_read_bio_DHparams)
- RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
- RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
- RESOLVEFUNC(PEM_write_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
- RESOLVEFUNC(PEM_write_bio_PUBKEY)
- RESOLVEFUNC(RAND_seed)
- RESOLVEFUNC(RAND_status)
- RESOLVEFUNC(RAND_bytes)
- RESOLVEFUNC(RSA_new)
- RESOLVEFUNC(RSA_free)
- RESOLVEFUNC(SSL_CIPHER_description)
- RESOLVEFUNC(SSL_CIPHER_get_bits)
- RESOLVEFUNC(SSL_get_rbio)
- RESOLVEFUNC(SSL_CTX_check_private_key)
- RESOLVEFUNC(SSL_CTX_ctrl)
- RESOLVEFUNC(SSL_CTX_free)
- RESOLVEFUNC(SSL_CTX_new)
- RESOLVEFUNC(SSL_CTX_set_cipher_list)
- RESOLVEFUNC(SSL_CTX_callback_ctrl)
- RESOLVEFUNC(SSL_CTX_set_default_verify_paths)
- RESOLVEFUNC(SSL_CTX_set_verify)
- RESOLVEFUNC(SSL_CTX_set_verify_depth)
- RESOLVEFUNC(SSL_CTX_use_certificate)
- RESOLVEFUNC(SSL_CTX_use_certificate_file)
- RESOLVEFUNC(SSL_CTX_use_PrivateKey)
- RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey)
- RESOLVEFUNC(SSL_CTX_use_PrivateKey_file)
- RESOLVEFUNC(SSL_CTX_get_cert_store);
- RESOLVEFUNC(SSL_CONF_CTX_new);
- RESOLVEFUNC(SSL_CONF_CTX_free);
- RESOLVEFUNC(SSL_CONF_CTX_set_ssl_ctx);
- RESOLVEFUNC(SSL_CONF_CTX_set_flags);
- RESOLVEFUNC(SSL_CONF_CTX_finish);
- RESOLVEFUNC(SSL_CONF_cmd);
- RESOLVEFUNC(SSL_accept)
- RESOLVEFUNC(SSL_clear)
- RESOLVEFUNC(SSL_connect)
- RESOLVEFUNC(SSL_free)
- RESOLVEFUNC(SSL_get_ciphers)
- RESOLVEFUNC(SSL_get_current_cipher)
- RESOLVEFUNC(SSL_version)
- RESOLVEFUNC(SSL_get_error)
- RESOLVEFUNC(SSL_get_peer_cert_chain)
- RESOLVEFUNC(SSL_get_peer_certificate)
- RESOLVEFUNC(SSL_get_verify_result)
- RESOLVEFUNC(SSL_new)
- RESOLVEFUNC(SSL_get_SSL_CTX)
- RESOLVEFUNC(SSL_ctrl)
- RESOLVEFUNC(SSL_read)
- RESOLVEFUNC(SSL_set_accept_state)
- RESOLVEFUNC(SSL_set_bio)
- RESOLVEFUNC(SSL_set_connect_state)
- RESOLVEFUNC(SSL_shutdown)
- RESOLVEFUNC(SSL_in_init)
- RESOLVEFUNC(SSL_get_shutdown)
- RESOLVEFUNC(SSL_set_session)
- RESOLVEFUNC(SSL_SESSION_free)
- RESOLVEFUNC(SSL_get1_session)
- RESOLVEFUNC(SSL_get_session)
- RESOLVEFUNC(SSL_set_ex_data)
- RESOLVEFUNC(SSL_get_ex_data)
- RESOLVEFUNC(SSL_get_ex_data_X509_STORE_CTX_idx)
-
-#ifndef OPENSSL_NO_PSK
- RESOLVEFUNC(SSL_set_psk_client_callback)
- RESOLVEFUNC(SSL_set_psk_server_callback)
- RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
-#endif // !OPENSSL_NO_PSK
-
- RESOLVEFUNC(SSL_write)
- 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_STORE_CTX_get0_store)
- RESOLVEFUNC(X509_cmp)
- RESOLVEFUNC(X509_STORE_CTX_get_ex_data)
- RESOLVEFUNC(X509_dup)
- 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)
-#if OPENSSL_VERSION_MAJOR < 3
- RESOLVEFUNC(SSL_CTX_load_verify_locations)
-#else
- RESOLVEFUNC(SSL_CTX_load_verify_dir)
-#endif // OPENSSL_VERSION_MAJOR
- RESOLVEFUNC(i2d_SSL_SESSION)
- RESOLVEFUNC(d2i_SSL_SESSION)
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- RESOLVEFUNC(SSL_select_next_proto)
- RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
- RESOLVEFUNC(SSL_get0_next_proto_negotiated)
- RESOLVEFUNC(SSL_set_alpn_protos)
- RESOLVEFUNC(SSL_CTX_set_alpn_select_cb)
- RESOLVEFUNC(SSL_get0_alpn_selected)
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-#if QT_CONFIG(dtls)
- RESOLVEFUNC(SSL_CTX_set_cookie_generate_cb)
- RESOLVEFUNC(SSL_CTX_set_cookie_verify_cb)
- RESOLVEFUNC(DTLS_server_method)
- RESOLVEFUNC(DTLS_client_method)
-#endif // dtls
-
- RESOLVEFUNC(CRYPTO_malloc)
- RESOLVEFUNC(DH_new)
- RESOLVEFUNC(DH_free)
- RESOLVEFUNC(d2i_DHparams)
- RESOLVEFUNC(i2d_DHparams)
-#ifndef OPENSSL_NO_DEPRECATED_3_0
- RESOLVEFUNC(DH_check)
-#endif // OPENSSL_NO_DEPRECATED_3_0
- 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)
-
- 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
-
-QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
-{
- QDateTime result;
- tm lTime;
-
- if (q_ASN1_TIME_to_tm(aTime, &lTime)) {
- QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
- QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
- result = QDateTime(resDate, resTime, Qt::UTC);
- }
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
deleted file mode 100644
index f733c64fe3..0000000000
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ /dev/null
@@ -1,761 +0,0 @@
-/****************************************************************************
-**
-** 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_OPENSSL_SYMBOLS_P_H
-#define QSSLSOCKET_OPENSSL_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qopenssl_p.h"
-#include <QtCore/qglobal.h>
-
-#if QT_CONFIG(ocsp)
-#include "qocsp_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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 = nullptr; \
- 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
-
-// TODO: the following lines previously were a part of 1.1 - specific header.
-// To reduce the amount of the change, I'm directly copying and pasting the
-// content of the header here. Later, can be better sorted/split into groups,
-// depending on the functionality.
-
-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);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_up_ref(EVP_PKEY *a);
-EVP_PKEY_CTX *q_EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
-void q_EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
-int q_EVP_PKEY_param_check(EVP_PKEY_CTX *ctx);
-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);
-int q_X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data);
-void *q_X509_STORE_get_ex_data(X509_STORE *r, int idx);
-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(st) q_OPENSSL_sk_num((OPENSSL_STACK *)st)
-#define q_SKM_sk_value(type, st,i) (type *)q_OPENSSL_sk_value((OPENSSL_STACK *)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)
-
-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);
-
-// The functions below do not really have to be ifdefed like this, but for now
-// they only used in TLS 1.3 handshake (and probably future versions).
-// Plus, 'is resumalbe' is OpenSSL 1.1.1-only (and again we need it for
-// TLS 1.3-specific session management).
-
-extern "C"
-{
-using NewSessionCallback = int (*)(SSL *, SSL_SESSION *);
-}
-
-void q_SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, NewSessionCallback cb);
-int q_SSL_SESSION_is_resumable(const SSL_SESSION *s);
-
-#define q_SSL_CTX_set_session_cache_mode(ctx,m) \
- q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
-
-#endif
-
-#if QT_CONFIG(dtls)
-// Functions and types required for DTLS support:
-extern "C"
-{
-
-typedef int (*CookieVerifyCallback)(SSL *, const unsigned char *, unsigned);
-typedef int (*DgramWriteCallback) (BIO *, const char *, int);
-typedef int (*DgramReadCallback) (BIO *, char *, int);
-typedef int (*DgramPutsCallback) (BIO *, const char *);
-typedef long (*DgramCtrlCallback) (BIO *, int, long, void *);
-typedef int (*DgramCreateCallback) (BIO *);
-typedef int (*DgramDestroyCallback) (BIO *);
-
-}
-
-int q_DTLSv1_listen(SSL *s, BIO_ADDR *client);
-BIO_ADDR *q_BIO_ADDR_new();
-void q_BIO_ADDR_free(BIO_ADDR *ap);
-
-// API we need for a custom dgram BIO:
-
-BIO_METHOD *q_BIO_meth_new(int type, const char *name);
-void q_BIO_meth_free(BIO_METHOD *biom);
-int q_BIO_meth_set_write(BIO_METHOD *biom, DgramWriteCallback);
-int q_BIO_meth_set_read(BIO_METHOD *biom, DgramReadCallback);
-int q_BIO_meth_set_puts(BIO_METHOD *biom, DgramPutsCallback);
-int q_BIO_meth_set_ctrl(BIO_METHOD *biom, DgramCtrlCallback);
-int q_BIO_meth_set_create(BIO_METHOD *biom, DgramCreateCallback);
-int q_BIO_meth_set_destroy(BIO_METHOD *biom, DgramDestroyCallback);
-
-#endif // dtls
-
-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);
-
-#if QT_CONFIG(ocsp)
-const OCSP_CERTID *q_OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x);
-#endif // ocsp
-
-#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)
-
-extern "C" {
-typedef int (*q_SSL_psk_use_session_cb_func_t)(SSL *, const EVP_MD *, const unsigned char **, size_t *,
- SSL_SESSION **);
-}
-void q_SSL_set_psk_use_session_callback(SSL *s, q_SSL_psk_use_session_cb_func_t);
-// Here the content of the 1.1 header ends.
-
-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);
-int q_ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm);
-long q_BIO_ctrl(BIO *a, int b, long c, void *d);
-Q_AUTOTEST_EXPORT int q_BIO_free(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);
-int q_BN_is_word(BIGNUM *a, BN_ULONG w);
-BN_ULONG q_BN_mod_word(const BIGNUM *a, BN_ULONG w);
-
-#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 // OPENSSL_NO_EC
-
-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);
-
-#ifndef OPENSSL_NO_DES
-const EVP_CIPHER *q_EVP_des_cbc();
-const EVP_CIPHER *q_EVP_des_ede3_cbc();
-#endif // OPENSSL_NO_DES
-
-#ifndef OPENSSL_NO_RC2
-const EVP_CIPHER *q_EVP_rc2_cbc();
-#endif // OPENSSL_NO_RC2
-
-#ifndef OPENSSL_NO_AES
-const EVP_CIPHER *q_EVP_aes_128_cbc();
-const EVP_CIPHER *q_EVP_aes_192_cbc();
-const EVP_CIPHER *q_EVP_aes_256_cbc();
-#endif // OPENSSL_NO_AES
-
-Q_AUTOTEST_EXPORT const EVP_MD *q_EVP_sha1();
-int q_EVP_PKEY_assign(EVP_PKEY *a, int b, void *r);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
-
-#ifndef OPENSSL_NO_EC
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
-#endif
-
-Q_AUTOTEST_EXPORT int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
-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))
-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);
-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);
-EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
-int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
-#endif // OPENSSL_NO_EC
-
-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);
-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);
-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);
-
-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_SSL_accept(SSL *a);
-int q_SSL_clear(SSL *a);
-char *q_SSL_CIPHER_description(const SSL_CIPHER *a, char *b, int c);
-int q_SSL_CIPHER_get_bits(const SSL_CIPHER *a, int *b);
-BIO *q_SSL_get_rbio(const SSL *s);
-int q_SSL_connect(SSL *a);
-int q_SSL_CTX_check_private_key(const SSL_CTX *a);
-long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d);
-void q_SSL_CTX_free(SSL_CTX *a);
-SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
-int q_SSL_CTX_set_cipher_list(SSL_CTX *a, const char *b);
-int q_SSL_CTX_set_default_verify_paths(SSL_CTX *a);
-void q_SSL_CTX_set_verify(SSL_CTX *a, int b, int (*c)(int, X509_STORE_CTX *));
-void q_SSL_CTX_set_verify_depth(SSL_CTX *a, int b);
-extern "C" {
-typedef void (*GenericCallbackType)();
-}
-long q_SSL_CTX_callback_ctrl(SSL_CTX *, int, GenericCallbackType);
-int q_SSL_CTX_use_certificate(SSL_CTX *a, X509 *b);
-int q_SSL_CTX_use_certificate_file(SSL_CTX *a, const char *b, int c);
-int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b);
-int q_SSL_CTX_use_RSAPrivateKey(SSL_CTX *a, RSA *b);
-int q_SSL_CTX_use_PrivateKey_file(SSL_CTX *a, const char *b, int c);
-X509_STORE *q_SSL_CTX_get_cert_store(const SSL_CTX *a);
-SSL_CONF_CTX *q_SSL_CONF_CTX_new();
-void q_SSL_CONF_CTX_free(SSL_CONF_CTX *a);
-void q_SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *a, SSL_CTX *b);
-unsigned int q_SSL_CONF_CTX_set_flags(SSL_CONF_CTX *a, unsigned int b);
-int q_SSL_CONF_CTX_finish(SSL_CONF_CTX *a);
-int q_SSL_CONF_cmd(SSL_CONF_CTX *a, const char *b, const char *c);
-void q_SSL_free(SSL *a);
-STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a);
-const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
-int q_SSL_version(const SSL *a);
-int q_SSL_get_error(SSL *a, int b);
-STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
-X509 *q_SSL_get_peer_certificate(SSL *a);
-long q_SSL_get_verify_result(const SSL *a);
-SSL *q_SSL_new(SSL_CTX *a);
-SSL_CTX *q_SSL_get_SSL_CTX(SSL *a);
-long q_SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
-int q_SSL_read(SSL *a, void *b, int c);
-void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
-void q_SSL_set_accept_state(SSL *a);
-void q_SSL_set_connect_state(SSL *a);
-int q_SSL_shutdown(SSL *a);
-int q_SSL_in_init(const SSL *s);
-int q_SSL_get_shutdown(const SSL *ssl);
-int q_SSL_set_session(SSL *to, SSL_SESSION *session);
-void q_SSL_SESSION_free(SSL_SESSION *ses);
-SSL_SESSION *q_SSL_get1_session(SSL *ssl);
-SSL_SESSION *q_SSL_get_session(const SSL *ssl);
-int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg);
-void *q_SSL_get_ex_data(const SSL *ssl, int idx);
-#ifndef 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);
-void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback);
-int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
-#endif // !OPENSSL_NO_PSK
-int q_SSL_write(SSL *a, const void *b, int c);
-int q_X509_cmp(X509 *a, X509 *b);
-X509 *q_X509_dup(X509 *a);
-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_STORE *q_X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
-
-// 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);
-
-#ifndef OPENSSL_NO_DEPRECATED_3_0
-int q_DH_check(DH *dh, int *codes);
-#endif // OPENSSL_NO_DEPRECATED_3_0
-
-BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
-#define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh)
-
-#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);
-#define q_SSL_CTX_set_tmp_ecdh(ctx, ecdh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_ECDH, 0, (char *)ecdh)
-
-// EC curves management
-size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
-int q_EC_curve_nist2nid(const char *name);
-#endif // OPENSSL_NO_EC
-
-#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
-
-// 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((st))
-#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
-
-void q_GENERAL_NAME_free(GENERAL_NAME *a);
-
-#define q_sk_X509_num(st) q_SKM_sk_num((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((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()
-
-#if OPENSSL_VERSION_MAJOR < 3
-int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
-#else
-int q_SSL_CTX_load_verify_dir(SSL_CTX *ctx, const char *CApath);
-#endif // OPENSSL_VERSION_MAJOR
-
-int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
-SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-int q_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- const unsigned char *client, unsigned int client_len);
-void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
- int (*cb) (SSL *ssl, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen, void *arg),
- void *arg);
-void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
- unsigned *len);
-int q_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
- unsigned protos_len);
-void q_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
- int (*cb) (SSL *ssl,
- const unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg), void *arg);
-void q_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
- unsigned *len);
-#endif // !OPENSSL_NO_NEXTPROTONEG
-
-
-#if QT_CONFIG(dtls)
-
-extern "C"
-{
-typedef int (*CookieGenerateCallback)(SSL *, unsigned char *, unsigned *);
-}
-
-void q_SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, CookieGenerateCallback cb);
-void q_SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, CookieVerifyCallback cb);
-const SSL_METHOD *q_DTLS_server_method();
-const SSL_METHOD *q_DTLS_client_method();
-
-#endif // dtls
-
-void *q_X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx);
-int q_SSL_get_ex_data_X509_STORE_CTX_idx();
-
-#if QT_CONFIG(dtls)
-#define q_DTLS_set_link_mtu(ssl, mtu) q_SSL_ctrl((ssl), DTLS_CTRL_SET_LINK_MTU, (mtu), nullptr)
-#define q_DTLSv1_get_timeout(ssl, arg) q_SSL_ctrl(ssl, DTLS_CTRL_GET_TIMEOUT, 0, arg)
-#define q_DTLSv1_handle_timeout(ssl) q_SSL_ctrl(ssl, DTLS_CTRL_HANDLE_TIMEOUT, 0, nullptr)
-#endif // dtls
-
-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);
-
-#define q_SSL_set_tlsext_status_type(ssl, type) \
- q_SSL_ctrl((ssl), SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, (type), nullptr)
-
-#if QT_CONFIG(ocsp)
-
-OCSP_RESPONSE *q_d2i_OCSP_RESPONSE(OCSP_RESPONSE **a, const unsigned char **in, long len);
-Q_AUTOTEST_EXPORT int q_i2d_OCSP_RESPONSE(OCSP_RESPONSE *r, unsigned char **ppout);
-Q_AUTOTEST_EXPORT OCSP_RESPONSE *q_OCSP_response_create(int status, OCSP_BASICRESP *bs);
-Q_AUTOTEST_EXPORT void q_OCSP_RESPONSE_free(OCSP_RESPONSE *rs);
-int q_OCSP_response_status(OCSP_RESPONSE *resp);
-OCSP_BASICRESP *q_OCSP_response_get1_basic(OCSP_RESPONSE *resp);
-Q_AUTOTEST_EXPORT OCSP_SINGLERESP *q_OCSP_basic_add1_status(OCSP_BASICRESP *rsp, OCSP_CERTID *cid,
- int status, int reason, ASN1_TIME *revtime,
- ASN1_TIME *thisupd, ASN1_TIME *nextupd);
-Q_AUTOTEST_EXPORT int q_OCSP_basic_sign(OCSP_BASICRESP *brsp, X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
- STACK_OF(X509) *certs, unsigned long flags);
-Q_AUTOTEST_EXPORT OCSP_BASICRESP *q_OCSP_BASICRESP_new();
-Q_AUTOTEST_EXPORT void q_OCSP_BASICRESP_free(OCSP_BASICRESP *bs);
-int q_OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags);
-int q_OCSP_resp_count(OCSP_BASICRESP *bs);
-OCSP_SINGLERESP *q_OCSP_resp_get0(OCSP_BASICRESP *bs, int idx);
-int q_OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, ASN1_GENERALIZEDTIME **revtime,
- ASN1_GENERALIZEDTIME **thisupd, ASN1_GENERALIZEDTIME **nextupd);
-int q_OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec);
-int q_OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, ASN1_OCTET_STRING **pikeyHash,
- ASN1_INTEGER **pserial, OCSP_CERTID *cid);
-
-const STACK_OF(X509) *q_OCSP_resp_get0_certs(const OCSP_BASICRESP *bs);
-Q_AUTOTEST_EXPORT OCSP_CERTID *q_OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
-Q_AUTOTEST_EXPORT void q_OCSP_CERTID_free(OCSP_CERTID *cid);
-int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
-
-#define q_SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
- q_SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, arg)
-
-#define q_SSL_CTX_set_tlsext_status_cb(ssl, cb) \
- q_SSL_CTX_callback_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, GenericCallbackType(cb))
-
-# define q_SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
- q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, arglen, arg)
-
-#endif // ocsp
-
-
-void *q_CRYPTO_malloc(size_t num, const char *file, int line);
-#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0)
-
-void q_SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val));
-const char *q_SSL_alert_type_string(int value);
-const char *q_SSL_alert_desc_string_long(int value);
-
-int q_SSL_CTX_get_security_level(const SSL_CTX *ctx);
-void q_SSL_CTX_set_security_level(SSL_CTX *ctx, int level);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index c90dfc8883..2816e62381 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -103,7 +103,7 @@ public:
static bool s_loadRootCertsOnDemand;
static bool supportsSsl();
- static void ensureInitialized();
+ Q_NETWORK_EXPORT static void ensureInitialized();
static QList<QSslCipher> defaultCiphers();
static QList<QSslCipher> defaultDtlsCiphers();
@@ -117,7 +117,7 @@ public:
static void resetDefaultEllipticCurves();
static QList<QSslCertificate> defaultCaCertificates();
- static QList<QSslCertificate> systemCaCertificates();
+ Q_NETWORK_EXPORT static QList<QSslCertificate> systemCaCertificates();
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
static void addDefaultCaCertificate(const QSslCertificate &cert);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
@@ -168,7 +168,6 @@ public:
Q_NETWORK_PRIVATE_EXPORT static void setRootCertOnDemandLoadingSupported(bool supported);
static QTlsBackend *tlsBackendInUse();
- static void registerAdHocFactory();
// Needed by TlsCryptograph:
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
diff --git a/src/network/ssl/qsslsocket_qt.cpp b/src/network/ssl/qsslsocket_qt.cpp
deleted file mode 100644
index 13bbb76367..0000000000
--- a/src/network/ssl/qsslsocket_qt.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <QtCore/qbytearray.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qmessageauthenticationcode.h>
-#include <QtCore/qrandom.h>
-
-#include "qsslsocket_p.h"
-#include "qasn1element_p.h"
-#include "qsslkey_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*
- PKCS12 helpers.
-*/
-
-static QAsn1Element wrap(quint8 type, const QAsn1Element &child)
-{
- QByteArray value;
- QDataStream stream(&value, QIODevice::WriteOnly);
- child.write(stream);
- return QAsn1Element(type, value);
-}
-
-static QAsn1Element _q_PKCS7_data(const QByteArray &data)
-{
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1");
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element(QAsn1Element::OctetStringType, data));
- return QAsn1Element::fromVector(items);
-}
-
-/*!
- PKCS #12 key derivation.
-
- Some test vectors:
- http://www.drh-consultancy.demon.co.uk/test.txt
- \internal
-*/
-static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r)
-{
- const int u = 20;
- const int v = 64;
-
- // password formatting
- QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0');
- char *p = passUnicode.data();
- for (int i = 0; i < passPhrase.size(); ++i) {
- quint16 ch = passPhrase[i].unicode();
- *(p++) = (ch & 0xff00) >> 8;
- *(p++) = (ch & 0xff);
- }
-
- // prepare I
- QByteArray D(64, id);
- QByteArray S, P;
- const int sSize = v * ((salt.size() + v - 1) / v);
- S.resize(sSize);
- for (int i = 0; i < sSize; ++i)
- S[i] = salt[i % salt.size()];
- const int pSize = v * ((passUnicode.size() + v - 1) / v);
- P.resize(pSize);
- for (int i = 0; i < pSize; ++i)
- P[i] = passUnicode[i % passUnicode.size()];
- QByteArray I = S + P;
-
- // apply hashing
- const int c = (n + u - 1) / u;
- QByteArray A;
- QByteArray B;
- B.resize(v);
- QCryptographicHash hash(QCryptographicHash::Sha1);
- for (int i = 0; i < c; ++i) {
- // hash r iterations
- QByteArray Ai = D + I;
- for (int j = 0; j < r; ++j) {
- hash.reset();
- hash.addData(Ai);
- Ai = hash.result();
- }
-
- for (int j = 0; j < v; ++j)
- B[j] = Ai[j % u];
-
- // modify I as Ij = (Ij + B + 1) modulo 2^v
- for (int p = 0; p < I.size(); p += v) {
- quint8 carry = 1;
- for (int j = v - 1; j >= 0; --j) {
- quint16 v = quint8(I[p + j]) + quint8(B[j]) + carry;
- I[p + j] = v & 0xff;
- carry = (v & 0xff00) >> 8;
- }
- }
- A += Ai;
- }
- return A.left(n);
-}
-
-static QByteArray _q_PKCS12_salt()
-{
- QByteArray salt;
- salt.resize(8);
- for (int i = 0; i < salt.size(); ++i)
- salt[i] = (QRandomGenerator::global()->generate() & 0xff);
- return salt;
-}
-
-static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert)
-{
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3");
-
- // certificate
- QList<QAsn1Element> certItems;
- certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1");
- certItems << wrap(QAsn1Element::Context0Type,
- QAsn1Element(QAsn1Element::OctetStringType, cert.toDer()));
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element::fromVector(certItems));
-
- // local key id
- const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1);
- QList<QAsn1Element> idItems;
- idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
- idItems << wrap(QAsn1Element::SetType,
- QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
- items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems));
-
- // dump
- QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QAsn1Element _q_PKCS12_key(const QSslKey &key)
-{
- Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa);
-
- QList<QAsn1Element> keyItems;
- keyItems << QAsn1Element::fromInteger(0);
- QList<QAsn1Element> algoItems;
- if (key.algorithm() == QSsl::Rsa)
- algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID);
- else if (key.algorithm() == QSsl::Dsa)
- algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID);
- algoItems << QAsn1Element(QAsn1Element::NullType);
- keyItems << QAsn1Element::fromVector(algoItems);
- keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer());
- return QAsn1Element::fromVector(keyItems);
-}
-
-static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId)
-{
- const int iterations = 2048;
- QByteArray salt = _q_PKCS12_salt();
- QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations);
- QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations);
-
- // prepare and encrypt data
- QByteArray plain;
- QDataStream plainStream(&plain, QIODevice::WriteOnly);
- _q_PKCS12_key(key).write(plainStream);
- QByteArray crypted = QSslKeyPrivate::encrypt(QTlsPrivate::Cipher::DesEde3Cbc,
- plain, cKey, cIv);
-
- QList<QAsn1Element> items;
- items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2");
-
- // key
- QList<QAsn1Element> keyItems;
- QList<QAsn1Element> algoItems;
- algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3");
- QList<QAsn1Element> paramItems;
- paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt);
- paramItems << QAsn1Element::fromInteger(iterations);
- algoItems << QAsn1Element::fromVector(paramItems);
- keyItems << QAsn1Element::fromVector(algoItems);
- keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted);
- items << wrap(QAsn1Element::Context0Type,
- QAsn1Element::fromVector(keyItems));
-
- // local key id
- QList<QAsn1Element> idItems;
- idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21");
- idItems << wrap(QAsn1Element::SetType,
- QAsn1Element(QAsn1Element::OctetStringType, localKeyId));
- items << wrap(QAsn1Element::SetType,
- QAsn1Element::fromVector(idItems));
-
- // dump
- QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items));
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
-{
- QList<QAsn1Element> items;
-
- // certs
- for (int i = 0; i < certs.size(); ++i)
- items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i]));
-
- // key
- if (!key.isNull()) {
- const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1);
- items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId));
- }
-
- // dump
- QAsn1Element root = QAsn1Element::fromVector(items);
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase)
-{
- const int iterations = 2048;
-
- // salt generation
- QByteArray macSalt = _q_PKCS12_salt();
- QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations);
-
- // HMAC calculation
- QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key);
- hmac.addData(data);
-
- QList<QAsn1Element> algoItems;
- algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26");
- algoItems << QAsn1Element(QAsn1Element::NullType);
-
- QList<QAsn1Element> digestItems;
- digestItems << QAsn1Element::fromVector(algoItems);
- digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result());
-
- QList<QAsn1Element> macItems;
- macItems << QAsn1Element::fromVector(digestItems);
- macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt);
- macItems << QAsn1Element::fromInteger(iterations);
- return QAsn1Element::fromVector(macItems);
-}
-
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase)
-{
- QList<QAsn1Element> items;
-
- // version
- items << QAsn1Element::fromInteger(3);
-
- // auth safe
- const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase);
- items << _q_PKCS7_data(data);
-
- // HMAC
- items << _q_PKCS12_mac(data, passPhrase);
-
- // dump
- QAsn1Element root = QAsn1Element::fromVector(items);
- QByteArray ba;
- QDataStream stream(&ba, QIODevice::WriteOnly);
- root.write(stream);
- return ba;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtls_openssl.cpp b/src/network/ssl/qtls_openssl.cpp
deleted file mode 100644
index 90561943f5..0000000000
--- a/src/network/ssl/qtls_openssl.cpp
+++ /dev/null
@@ -1,1837 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qsslpresharedkeyauthenticator_p.h"
-#include "qsslpresharedkeyauthenticator.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslcertificate_p.h"
-#include "qx509_openssl_p.h"
-#include "qocspresponse_p.h"
-#include "qtls_openssl_p.h"
-#include "qsslsocket_p.h"
-
-#ifdef Q_OS_WIN
-#include "qwindowscarootfetcher_p.h"
-#endif
-
-#include <QtCore/qscopedvaluerollback.h>
-#include <QtCore/qscopeguard.h>
-
-#include <algorithm>
-#include <cstring>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-
-QSsl::AlertLevel tlsAlertLevel(int value)
-{
- using QSsl::AlertLevel;
-
- if (const char *typeString = q_SSL_alert_type_string(value)) {
- // Documented to return 'W' for warning, 'F' for fatal,
- // 'U' for unknown.
- switch (typeString[0]) {
- case 'W':
- return AlertLevel::Warning;
- case 'F':
- return AlertLevel::Fatal;
- default:;
- }
- }
-
- return AlertLevel::Unknown;
-}
-
-QString tlsAlertDescription(int value)
-{
- QString description = QLatin1String(q_SSL_alert_desc_string_long(value));
- if (!description.size())
- description = QLatin1String("no description provided");
- return description;
-}
-
-QSsl::AlertType tlsAlertType(int value)
-{
- // In case for some reason openssl gives us a value,
- // which is not in our enum actually, we leave it to
- // an application to handle (supposedly they have
- // if or switch-statements).
- return QSsl::AlertType(value & 0xff);
-}
-
-#ifdef Q_OS_WIN
-
-QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool checkAIA)
-{
- QSslCertificate certToFetch;
-
- for (const auto &tlsError : tlsErrors) {
- switch (tlsError.error()) {
- case QSslError::UnableToGetLocalIssuerCertificate: // site presented intermediate cert, but root is unknown
- case QSslError::SelfSignedCertificateInChain: // site presented a complete chain, but root is unknown
- certToFetch = tlsError.certificate();
- break;
- case QSslError::SelfSignedCertificate:
- case QSslError::CertificateBlacklisted:
- //With these errors, we know it will be untrusted so save time by not asking windows
- return QSslCertificate{};
- default:
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << tlsError.errorString();
-#endif
- //TODO - this part is strange.
- break;
- }
- }
-
- if (checkAIA) {
- const auto extensions = certToFetch.extensions();
- for (const auto &ext : extensions) {
- if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.1")) // See RFC 4325
- return certToFetch;
- }
- //The only reason we check this extensions is because an application set trusted
- //CA certificates explicitly, thus technically disabling CA fetch. So, if it's
- //the case and an intermediate certificate is missing, and no extensions is
- //present on the leaf certificate - we fail the handshake immediately.
- return QSslCertificate{};
- }
-
- return certToFetch;
-}
-
-#endif // Q_OS_WIN
-
-} // unnamed namespace
-
-namespace QTlsPrivate {
-
-extern "C" {
-
-int q_X509Callback(int ok, X509_STORE_CTX *ctx)
-{
- if (!ok) {
- // Store the error and at which depth the error was detected.
-
- using ErrorListPtr = QList<QSslErrorEntry> *;
- ErrorListPtr errors = nullptr;
-
- // Error list is attached to either 'SSL' or 'X509_STORE'.
- if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
- errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
-
- if (!errors) {
- // Not found on store? Try SSL and its external data then. According to the OpenSSL's
- // documentation:
- //
- // "Whenever a X509_STORE_CTX object is created for the verification of the
- // peer's certificate during a handshake, a pointer to the SSL object is
- // stored into the X509_STORE_CTX object to identify the connection affected.
- // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
- // used with the correct index."
- const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::errorOffsetInExData;
- if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
- errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
- }
-
- if (!errors) {
- qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, handshake failure");
- return 0;
- }
-
- errors->append(X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
- }
- // Always return OK to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx)
-{
- // Passed to SSL_CTX_set_verify()
- // https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html
- // Returns 0 to abort verification, 1 to continue.
-
- // This is a new, experimental verification callback, reporting
- // errors immediately and returning 0 or 1 depending on an application
- // either ignoring or not ignoring verification errors as they come.
- if (!ctx) {
- qCWarning(lcSsl, "Invalid store context (nullptr)");
- return 0;
- }
-
- if (!ok) {
- // "Whenever a X509_STORE_CTX object is created for the verification of the
- // peer's certificate during a handshake, a pointer to the SSL object is
- // stored into the X509_STORE_CTX object to identify the connection affected.
- // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
- // used with the correct index."
- SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()));
- if (!ssl) {
- qCWarning(lcTlsBackend, "No external data (SSL) found in X509 store object");
- return 0;
- }
-
- const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::socketOffsetInExData;
- auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, offset));
- if (!crypto) {
- qCWarning(lcTlsBackend, "No external data (TlsCryptographOpenSSL) found in SSL object");
- return 0;
- }
-
- return crypto->emitErrorFromCallback(ctx);
- }
- return 1;
-}
-
-#ifndef OPENSSL_NO_PSK
-static unsigned q_ssl_psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len)
-{
- auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- return tls->pskClientTlsCallback(hint, identity, max_identity_len, psk, max_psk_len);
-}
-
-static unsigned int q_ssl_psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
- unsigned int max_psk_len)
-{
- auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- Q_ASSERT(tls);
- return tls->pskServerTlsCallback(identity, psk, max_psk_len);
-}
-
-#ifdef TLS1_3_VERSION
-static unsigned q_ssl_psk_restore_client(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len)
-{
- Q_UNUSED(hint);
- Q_UNUSED(identity);
- Q_UNUSED(max_identity_len);
- Q_UNUSED(psk);
- Q_UNUSED(max_psk_len);
-
-#ifdef QT_DEBUG
- auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- Q_ASSERT(tls);
- Q_ASSERT(tls->d);
- Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode);
-#endif
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
-
- return 0;
-}
-
-static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id,
- size_t *idlen, SSL_SESSION **sess)
-{
- Q_UNUSED(ssl);
- Q_UNUSED(md);
- Q_UNUSED(id);
- Q_UNUSED(idlen);
- Q_UNUSED(sess);
-
-#ifdef QT_DEBUG
- auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- Q_ASSERT(tls);
- Q_ASSERT(tls->d);
- Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode);
-#endif
-
- // Temporarily rebind the psk because it will be called next. The function will restore it.
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_restore_client);
-
- return 1; // need to return 1 or else "the connection setup fails."
-}
-
-int q_ssl_sess_set_new_cb(SSL *ssl, SSL_SESSION *session)
-{
- if (!ssl) {
- qCWarning(lcTlsBackend, "Invalid SSL (nullptr)");
- return 0;
- }
- if (!session) {
- qCWarning(lcTlsBackend, "Invalid SSL_SESSION (nullptr)");
- return 0;
- }
-
- auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- Q_ASSERT(tls);
- return tls->handleNewSessionTicket(ssl);
-}
-#endif // TLS1_3_VERSION
-
-#endif // !OPENSSL_NO_PSK
-
-#if QT_CONFIG(ocsp)
-
-int qt_OCSP_status_server_callback(SSL *ssl, void *ocspRequest)
-{
- Q_UNUSED(ocspRequest);
- if (!ssl)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData));
- if (!crypto)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- Q_ASSERT(crypto->d);
- Q_ASSERT(crypto->d->tlsMode() == QSslSocket::SslServerMode);
- const QByteArray &response = crypto->ocspResponseDer;
- Q_ASSERT(response.size());
-
- unsigned char *derCopy = static_cast<unsigned char *>(q_OPENSSL_malloc(size_t(response.size())));
- if (!derCopy)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- std::copy(response.data(), response.data() + response.size(), derCopy);
- // We don't check the return value: internally OpenSSL simply assignes the
- // pointer (it assumes it now owns this memory btw!) and the length.
- q_SSL_set_tlsext_status_ocsp_resp(ssl, derCopy, response.size());
-
- return SSL_TLSEXT_ERR_OK;
-}
-
-#endif // ocsp
-
-void qt_AlertInfoCallback(const SSL *connection, int from, int value)
-{
- // Passed to SSL_set_info_callback()
- // https://www.openssl.org/docs/man1.1.1/man3/SSL_set_info_callback.html
-
- if (!connection) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "Invalid 'connection' parameter (nullptr)");
-#endif // QSSLSOCKET_DEBUG
- return;
- }
-
- const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::socketOffsetInExData;
- auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(connection, offset));
- if (!crypto) {
- // SSL_set_ex_data can fail:
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend, "No external data (socket backend) found for parameter 'connection'");
-#endif // QSSLSOCKET_DEBUG
- return;
- }
-
- if (!(from & SSL_CB_ALERT)) {
- // We only want to know about alerts (at least for now).
- return;
- }
-
- if (from & SSL_CB_WRITE)
- crypto->alertMessageSent(value);
- else
- crypto->alertMessageReceived(value);
-}
-
-} // extern "C"
-
-#if QT_CONFIG(ocsp)
-namespace {
-
-QSslError::SslError qt_OCSP_response_status_to_SslError(long code)
-{
- switch (code) {
- case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
- return QSslError::OcspMalformedRequest;
- case OCSP_RESPONSE_STATUS_INTERNALERROR:
- return QSslError::OcspInternalError;
- case OCSP_RESPONSE_STATUS_TRYLATER:
- return QSslError::OcspTryLater;
- case OCSP_RESPONSE_STATUS_SIGREQUIRED:
- return QSslError::OcspSigRequred;
- case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
- return QSslError::OcspUnauthorized;
- case OCSP_RESPONSE_STATUS_SUCCESSFUL:
- default:
- return {};
- }
- Q_UNREACHABLE();
-}
-
-QOcspRevocationReason qt_OCSP_revocation_reason(int reason)
-{
- switch (reason) {
- case OCSP_REVOKED_STATUS_NOSTATUS:
- return QOcspRevocationReason::None;
- case OCSP_REVOKED_STATUS_UNSPECIFIED:
- return QOcspRevocationReason::Unspecified;
- case OCSP_REVOKED_STATUS_KEYCOMPROMISE:
- return QOcspRevocationReason::KeyCompromise;
- case OCSP_REVOKED_STATUS_CACOMPROMISE:
- return QOcspRevocationReason::CACompromise;
- case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED:
- return QOcspRevocationReason::AffiliationChanged;
- case OCSP_REVOKED_STATUS_SUPERSEDED:
- return QOcspRevocationReason::Superseded;
- case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION:
- return QOcspRevocationReason::CessationOfOperation;
- case OCSP_REVOKED_STATUS_CERTIFICATEHOLD:
- return QOcspRevocationReason::CertificateHold;
- case OCSP_REVOKED_STATUS_REMOVEFROMCRL:
- return QOcspRevocationReason::RemoveFromCRL;
- default:
- return QOcspRevocationReason::None;
- }
-
- Q_UNREACHABLE();
-}
-
-bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer)
-{
- // OCSP_basic_verify does verify that the responder is legit, the response is
- // correctly signed, CertID is correct. But it does not know which certificate
- // we were presented with by our peer, so it does not check if it's a response
- // for our peer's certificate.
- Q_ASSERT(singleResponse && peerCert && issuer);
-
- const OCSP_CERTID *certId = q_OCSP_SINGLERESP_get0_id(singleResponse); // Does not increment refcount.
- if (!certId) {
- qCWarning(lcSsl, "A SingleResponse without CertID");
- return false;
- }
-
- ASN1_OBJECT *md = nullptr;
- ASN1_INTEGER *reportedSerialNumber = nullptr;
- const int result = q_OCSP_id_get0_info(nullptr, &md, nullptr, &reportedSerialNumber, const_cast<OCSP_CERTID *>(certId));
- if (result != 1 || !md || !reportedSerialNumber) {
- qCWarning(lcSsl, "Failed to extract a hash and serial number from CertID structure");
- return false;
- }
-
- if (!q_X509_get_serialNumber(peerCert)) {
- // Is this possible at all? But we have to check this,
- // ASN1_INTEGER_cmp (called from OCSP_id_cmp) dereferences
- // without any checks at all.
- qCWarning(lcSsl, "No serial number in peer's ceritificate");
- return false;
- }
-
- const int nid = q_OBJ_obj2nid(md);
- if (nid == NID_undef) {
- qCWarning(lcSsl, "Unknown hash algorithm in CertID");
- return false;
- }
-
- const EVP_MD *digest = q_EVP_get_digestbynid(nid); // Does not increment refcount.
- if (!digest) {
- qCWarning(lcSsl) << "No digest for nid" << nid;
- return false;
- }
-
- OCSP_CERTID *recreatedId = q_OCSP_cert_to_id(digest, peerCert, issuer);
- if (!recreatedId) {
- qCWarning(lcSsl, "Failed to re-create CertID");
- return false;
- }
- const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free);
-
- if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) {
- qDebug(lcSsl, "Certificate ID mismatch");
- return false;
- }
- // Bingo!
- return true;
-}
-
-} // unnamed namespace
-#endif // ocsp
-
-TlsCryptographOpenSSL::~TlsCryptographOpenSSL()
-{
- destroySslContext();
-}
-
-void TlsCryptographOpenSSL::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
-{
- Q_ASSERT(qObj);
- Q_ASSERT(dObj);
- q = qObj;
- d = dObj;
-
- ocspResponses.clear();
- ocspResponseDer.clear();
-
- systemOrSslErrorDetected = false;
- handshakeInterrupted = false;
-
- fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
-}
-
-void TlsCryptographOpenSSL::checkSettingSslContext(QSharedPointer<QSslContext> tlsContext)
-{
- if (sslContextPointer.isNull())
- sslContextPointer = tlsContext;
-}
-
-QSharedPointer<QSslContext> TlsCryptographOpenSSL::sslContext() const
-{
- return sslContextPointer;
-}
-
-QList<QSslError> TlsCryptographOpenSSL::tlsErrors() const
-{
- return sslErrors;
-}
-
-void TlsCryptographOpenSSL::startClientEncryption()
-{
- if (!initSslContext()) {
- Q_ASSERT(d);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-void TlsCryptographOpenSSL::startServerEncryption()
-{
- if (!initSslContext()) {
- Q_ASSERT(d);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-bool TlsCryptographOpenSSL::startHandshake()
-{
- // Check if the connection has been established. Get all errors from the
- // verification stage.
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return false;
-
- const auto mode = d->tlsMode();
-
- pendingFatalAlert = false;
- errorsReportedFromCallback = false;
- QList<QSslErrorEntry> lastErrors;
- q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, &lastErrors);
-
- // SSL_set_ex_data can fail, but see the callback's code - we handle this there.
- q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + socketOffsetInExData, this);
- q_SSL_set_info_callback(ssl, qt_AlertInfoCallback);
-
- int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
- q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, nullptr);
- // Note, unlike errors as external data on SSL object, we do not unset
- // a callback/ex-data if alert notifications are enabled: an alert can
- // arrive after the handshake, for example, this happens when the server
- // does not find a ClientCert or does not like it.
-
- if (!lastErrors.isEmpty() || errorsReportedFromCallback)
- storePeerCertificates();
-
- // storePeerCertificate() if called above - would update the
- // configuration with peer's certificates.
- auto configuration = q->sslConfiguration();
- if (!errorsReportedFromCallback) {
- const auto &peerCertificateChain = configuration.peerCertificateChain();
- for (const auto &currentError : qAsConst(lastErrors)) {
- emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
- peerCertificateChain.value(currentError.depth)));
- if (q->state() != QAbstractSocket::ConnectedState)
- break;
- }
- }
-
- errorList << lastErrors;
-
- // Connection aborted during handshake phase.
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
-
- // Check if we're encrypted or not.
- if (result <= 0) {
- switch (q_SSL_get_error(ssl, result)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // The handshake is not yet complete.
- break;
- default:
- QString errorString = QTlsBackendOpenSSL::msgErrorsDuringHandshake();
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::startHandshake: error!" << errorString;
-#endif
- {
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, errorString);
- if (pendingFatalAlert) {
- trySendFatalAlert();
- pendingFatalAlert = false;
- }
- }
- q->abort();
- }
- return false;
- }
-
- // store peer certificate chain
- storePeerCertificates();
-
- // Start translating errors.
- QList<QSslError> errors;
-
- // Note, the storePeerCerificates() probably updated the configuration at this point.
- configuration = q->sslConfiguration();
- // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
- const auto &peerCertificateChain = configuration.peerCertificateChain();
- for (const QSslCertificate &cert : peerCertificateChain) {
- if (QSslCertificatePrivate::isBlacklisted(cert)) {
- QSslError error(QSslError::CertificateBlacklisted, cert);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
-
-#if QT_CONFIG(ocsp)
- // For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
- // if it's enabled in QSslSocket::SslServerMode. This can change.
- if (!configuration.peerCertificate().isNull() && configuration.ocspStaplingEnabled() && doVerifyPeer) {
- if (!checkOcspStatus()) {
- if (ocspErrors.isEmpty()) {
- {
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, ocspErrorDescription);
- }
- q->abort();
- return false;
- }
-
- for (const QSslError &error : ocspErrors) {
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- }
-#endif // ocsp
-
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- if (!configuration.peerCertificate().isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- const auto verificationPeerName = d->verificationName();
- if (mode == QSslSocket::SslClientMode) {
- QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
-
- if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
- // No matches in common names or alternate names.
- QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- if (doVerifyPeer) {
- QSslError error(QSslError::NoPeerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // Translate errors from the error list into QSslErrors.
- errors.reserve(errors.size() + errorList.size());
- for (const auto &error : qAsConst(errorList))
- errors << X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, peerCertificateChain.value(error.depth));
-
- if (!errors.isEmpty()) {
- sslErrors = errors;
-#ifdef Q_OS_WIN
- const bool fetchEnabled = QSslSocketPrivate::rootCertOnDemandLoadingSupported()
- && d->isRootsOnDemandAllowed();
- // !fetchEnabled is a special case scenario, when we potentially have a missing
- // intermediate certificate and a recoverable chain, but on demand cert loading
- // was disabled by setCaCertificates call. For this scenario we check if "Authority
- // Information Access" is present - wincrypt can deal with such certificates.
- QSslCertificate certToFetch;
- if (doVerifyPeer && !d->verifyErrorsHaveBeenIgnored())
- certToFetch = findCertificateToFetch(sslErrors, !fetchEnabled);
-
- //Skip this if not using system CAs, or if the SSL errors are configured in advance to be ignorable
- if (!certToFetch.isNull()) {
- fetchAuthorityInformation = !fetchEnabled;
- //Windows desktop versions starting from vista ship with minimal set of roots and download on demand
- //from the windows update server CA roots that are trusted by MS. It also can fetch a missing intermediate
- //in case "Authority Information Access" extension is present.
- //
- //However, this is only transparent if using WinINET - we have to trigger it
- //ourselves.
- fetchCaRootForCert(certToFetch);
- return false;
- }
-#endif // Q_OS_WIN
- if (!checkSslErrors())
- return false;
- // A slot, attached to sslErrors signal can call
- // abort/close/disconnetFromHost/etc; no need to
- // continue handshake then.
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- } else {
- sslErrors.clear();
- }
-
- continueHandshake();
- return true;
-}
-
-void TlsCryptographOpenSSL::enableHandshakeContinuation()
-{
- handshakeInterrupted = false;
-}
-
-void TlsCryptographOpenSSL::cancelCAFetch()
-{
- fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
-}
-
-void TlsCryptographOpenSSL::continueHandshake()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- const auto mode = d->tlsMode();
-
- // if we have a max read buffer size, reset the plain socket's to match
- if (const auto maxSize = d->maxReadBufferSize())
- plainSocket->setReadBufferSize(maxSize);
-
- if (q_SSL_session_reused(ssl))
- QTlsBackend::setPeerSessionShared(d, true);
-
-#ifdef QT_DECRYPT_SSL_TRAFFIC
- if (q_SSL_get_session(ssl)) {
- size_t master_key_len = q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), nullptr, 0);
- size_t client_random_len = q_SSL_get_client_random(ssl, nullptr, 0);
- QByteArray masterKey(int(master_key_len), Qt::Uninitialized); // Will not overflow
- QByteArray clientRandom(int(client_random_len), Qt::Uninitialized); // Will not overflow
-
- q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl),
- reinterpret_cast<unsigned char*>(masterKey.data()),
- masterKey.size());
- q_SSL_get_client_random(ssl, reinterpret_cast<unsigned char *>(clientRandom.data()),
- clientRandom.size());
-
- QByteArray debugLineClientRandom("CLIENT_RANDOM ");
- debugLineClientRandom.append(clientRandom.toHex().toUpper());
- debugLineClientRandom.append(" ");
- debugLineClientRandom.append(masterKey.toHex().toUpper());
- debugLineClientRandom.append("\n");
-
- QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
- QFile file(sslKeyFile);
- if (!file.open(QIODevice::Append))
- qCWarning(lcSsl) << "could not open file" << sslKeyFile << "for appending";
- if (!file.write(debugLineClientRandom))
- qCWarning(lcSsl) << "could not write to file" << sslKeyFile;
- file.close();
- } else {
- qCWarning(lcTlsBackend, "could not decrypt SSL traffic");
- }
-#endif // QT_DECRYPT_SSL_TRAFFIC
-
- const auto &configuration = q->sslConfiguration();
- // Cache this SSL session inside the QSslContext
- if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionSharing))) {
- if (!sslContextPointer->cacheSession(ssl)) {
- sslContextPointer.clear(); // we could not cache the session
- } else {
- // Cache the session for permanent usage as well
- if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionPersistence))) {
- if (!sslContextPointer->sessionASN1().isEmpty())
- QTlsBackend::setSessionAsn1(d, sslContextPointer->sessionASN1());
- QTlsBackend::setSessionLifetimeHint(d, sslContextPointer->sessionTicketLifeTimeHint());
- }
- }
- }
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-
- QTlsBackend::setAlpnStatus(d, sslContextPointer->npnContext().status);
- if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
- // we could not agree -> be conservative and use HTTP/1.1
- // T.P.: I have to admit, this is a really strange notion of 'conservative',
- // given the protocol-neutral nature of ALPN/NPN.
- QTlsBackend::setNegotiatedProtocol(d, QByteArrayLiteral("http/1.1"));
- } else {
- const unsigned char *proto = nullptr;
- unsigned int proto_len = 0;
-
- q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
- if (proto_len && mode == QSslSocket::SslClientMode) {
- // Client does not have a callback that sets it ...
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
- }
-
- if (!proto_len) { // Test if NPN was more lucky ...
- q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
- }
-
- if (proto_len)
- QTlsBackend::setNegotiatedProtocol(d, QByteArray(reinterpret_cast<const char *>(proto), proto_len));
- else
- QTlsBackend::setNegotiatedProtocol(d,{});
- }
-#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
-
- if (mode == QSslSocket::SslClientMode) {
- EVP_PKEY *key;
- if (q_SSL_get_server_tmp_key(ssl, &key))
- QTlsBackend::setEphemeralKey(d, QSslKey(key, QSsl::PublicKey));
- }
-
- d->setEncrypted(true);
- emit q->encrypted();
- if (d->isAutoStartingHandshake() && d->isPendingClose()) {
- d->setPendingClose(false);
- q->disconnectFromHost();
- }
-}
-
-void TlsCryptographOpenSSL::transmit()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return;
-
- // If we don't have any SSL context, don't bother transmitting.
- if (!ssl)
- return;
-
- auto &writeBuffer = d->tlsWriteBuffer();
- auto &buffer = d->tlsBuffer();
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
- bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
-
- bool transmitting;
- do {
- transmitting = false;
-
- // If the connection is secure, we can transfer data from the write
- // buffer (in plain text) to the write BIO through SSL_write.
- if (q->isEncrypted() && !writeBuffer.isEmpty()) {
- qint64 totalBytesWritten = 0;
- int nextDataBlockSize;
- while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
- int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize);
- if (writtenBytes <= 0) {
- int error = q_SSL_get_error(ssl, writtenBytes);
- //write can result in a want_write_error - not an error - continue transmitting
- if (error == SSL_ERROR_WANT_WRITE) {
- transmitting = true;
- break;
- } else if (error == SSL_ERROR_WANT_READ) {
- //write can result in a want_read error, possibly due to renegotiation - not an error - stop transmitting
- transmitting = false;
- break;
- } else {
- // ### Better error handling.
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to write data: %1").arg(
- QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return;
- }
- }
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encrypted" << writtenBytes << "bytes";
-#endif
- writeBuffer.free(writtenBytes);
- totalBytesWritten += writtenBytes;
-
- if (writtenBytes < nextDataBlockSize) {
- // break out of the writing loop and try again after we had read
- transmitting = true;
- break;
- }
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- // Check if we've got any data to be written to the socket.
- QVarLengthArray<char, 4096> data;
- int pendingBytes;
- while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
- && plainSocket->openMode() != QIODevice::NotOpen) {
- // Read encrypted data from the write BIO into a buffer.
- data.resize(pendingBytes);
- int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes);
-
- // Write encrypted data from the buffer to the socket.
- qint64 actualWritten = plainSocket->write(data.constData(), encryptedBytesRead);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: wrote" << encryptedBytesRead
- << "encrypted bytes to the socket" << actualWritten << "actual.";
-#endif
- if (actualWritten < 0) {
- //plain socket write fails if it was in the pending close state.
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- transmitting = true;
- }
-
- // Check if we've got any data to be read from the socket.
- if (!q->isEncrypted() || !d->maxReadBufferSize() || buffer.size() < d->maxReadBufferSize())
- while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
- // Read encrypted data from the socket into a buffer.
- data.resize(pendingBytes);
- // just peek() here because q_BIO_write could write less data than expected
- int encryptedBytesRead = plainSocket->peek(data.data(), pendingBytes);
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket";
-#endif
- // Write encrypted data from the buffer into the read BIO.
- int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead);
-
- // Throw away the results.
- if (writtenToBio > 0) {
- plainSocket->skip(writtenToBio);
- } else {
- // ### Better error handling.
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to decrypt data: %1")
- .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return;
- }
-
- transmitting = true;
- }
-
- // If the connection isn't secured yet, this is the time to retry the
- // connect / accept.
- if (!q->isEncrypted()) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: testing encryption";
-#endif
- if (startHandshake()) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption established";
-#endif
- d->setEncrypted(true);
- transmitting = true;
- } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: connection lost";
-#endif
- break;
- } else if (d->isPaused()) {
- // just wait until the user continues
- return;
- } else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption not done yet";
-#endif
- }
- }
-
- // If the request is small and the remote host closes the transmission
- // after sending, there's a chance that startHandshake() will already
- // have triggered a shutdown.
- if (!ssl)
- continue;
-
- // We always read everything from the SSL decryption buffers, even if
- // we have a readBufferMaxSize. There's no point in leaving data there
- // just so that readBuffer.size() == readBufferMaxSize.
- int readBytes = 0;
- const int bytesToRead = 4096;
- do {
- if (q->readChannelCount() == 0) {
- // The read buffer is deallocated, don't try resize or write to it.
- break;
- }
- // Don't use SSL_pending(). It's very unreliable.
- readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead);
- if (readBytes > 0) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: decrypted" << readBytes << "bytes";
-#endif
- buffer.chop(bytesToRead - readBytes);
-
- if (bool *readyReadEmittedPointer = d->readyReadPointer())
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- transmitting = true;
- continue;
- }
- buffer.chop(bytesToRead);
-
- // Error.
- switch (q_SSL_get_error(ssl, readBytes)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- // Out of data.
- break;
- case SSL_ERROR_ZERO_RETURN:
- // The remote host closed the connection.
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: remote disconnect";
-#endif
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- {
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- }
- return;
- case SSL_ERROR_SYSCALL: // some IO error
- case SSL_ERROR_SSL: // error in the SSL library
- // we do not know exactly what the error is, nor whether we can recover from it,
- // so just return to prevent an endless loop in the outer "while" statement
- systemOrSslErrorDetected = true;
- {
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1")
- .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- }
- return;
- default:
- // SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a
- // BIO_s_connect() or BIO_s_accept(), which we do not call.
- // SSL_ERROR_WANT_X509_LOOKUP: can only happen with a
- // SSL_CTX_set_client_cert_cb(), which we do not call.
- // So this default case should never be triggered.
- {
- const ScopedBool bg(inSetAndEmitError, true);
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1")
- .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- }
- break;
- }
- } while (ssl && readBytes > 0);
- } while (ssl && transmitting);
-}
-
-void TlsCryptographOpenSSL::disconnectFromHost()
-{
- if (ssl) {
- if (!shutdown && !q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
- if (q_SSL_shutdown(ssl) != 1) {
- // Some error may be queued, clear it.
- QTlsBackendOpenSSL::clearErrorQueue();
- }
- shutdown = true;
- transmit();
- }
- }
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
- plainSocket->disconnectFromHost();
-}
-
-void TlsCryptographOpenSSL::disconnected()
-{
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- if (plainSocket->bytesAvailable() <= 0) {
- destroySslContext();
- } else {
- // Move all bytes into the plain buffer.
- const qint64 tmpReadBufferMaxSize = d->maxReadBufferSize();
- // Reset temporarily, so the plain socket buffer is completely drained:
- d->setMaxReadBufferSize(0);
- transmit();
- d->setMaxReadBufferSize(tmpReadBufferMaxSize);
- }
- //if there is still buffered data in the plain socket, don't destroy the ssl context yet.
- //it will be destroyed when the socket is deleted.
-}
-
-QSslCipher TlsCryptographOpenSSL::sessionCipher() const
-{
- if (!ssl)
- return {};
-
- const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
- return sessionCipher ? QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(sessionCipher) : QSslCipher{};
-}
-
-QSsl::SslProtocol TlsCryptographOpenSSL::sessionProtocol() const
-{
- if (!ssl)
- return QSsl::UnknownProtocol;
-
- const int ver = q_SSL_version(ssl);
- switch (ver) {
- case 0x301:
- return QSsl::TlsV1_0;
- case 0x302:
- return QSsl::TlsV1_1;
- case 0x303:
- return QSsl::TlsV1_2;
- case 0x304:
- return QSsl::TlsV1_3;
- }
-
- return QSsl::UnknownProtocol;
-}
-
-QList<QOcspResponse> TlsCryptographOpenSSL::ocsps() const
-{
- return ocspResponses;
-}
-
-bool TlsCryptographOpenSSL::checkSslErrors()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- if (sslErrors.isEmpty())
- return true;
-
- emit q->sslErrors(sslErrors);
-
- const auto vfyMode = q->peerVerifyMode();
- const auto mode = d->tlsMode();
-
- bool doVerifyPeer = vfyMode == QSslSocket::VerifyPeer || (vfyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- QSslSocketPrivate::pauseSocketNotifiers(q);
- d->setPaused(true);
- } else {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
- plainSocket->disconnectFromHost();
- }
- return false;
- }
- return true;
-}
-
-int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
-{
- // If we return 1, this means we own the session, but we don't.
- // 0 would tell OpenSSL to deref (but they still have it in the
- // internal cache).
- Q_ASSERT(connection);
-
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
- // We silently ignore, do nothing, remove from cache.
- return 0;
- }
-
- SSL_SESSION *currentSession = q_SSL_get_session(connection);
- if (!currentSession) {
- qCWarning(lcTlsBackend,
- "New session ticket callback, the session is invalid (nullptr)");
- return 0;
- }
-
- if (q_SSL_version(connection) < 0x304) {
- // We only rely on this mechanics with TLS >= 1.3
- return 0;
- }
-
-#ifdef TLS1_3_VERSION
- if (!q_SSL_SESSION_is_resumable(currentSession)) {
- qCDebug(lcTlsBackend, "New session ticket, but the session is non-resumable");
- return 0;
- }
-#endif // TLS1_3_VERSION
-
- const int sessionSize = q_i2d_SSL_SESSION(currentSession, nullptr);
- if (sessionSize <= 0) {
- qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
- return 0;
- }
-
- // We have somewhat perverse naming, it's not a ticket, it's a session.
- QByteArray sessionTicket(sessionSize, 0);
- auto data = reinterpret_cast<unsigned char *>(sessionTicket.data());
- if (!q_i2d_SSL_SESSION(currentSession, &data)) {
- qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
- return 0;
- }
-
- QTlsBackend::setSessionAsn1(d, sessionTicket);
- QTlsBackend::setSessionLifetimeHint(d, q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
-
- emit q->newSessionTicketReceived();
- return 0;
-}
-
-void TlsCryptographOpenSSL::alertMessageSent(int value)
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- const auto level = tlsAlertLevel(value);
- if (level == QSsl::AlertLevel::Fatal && !q->isEncrypted()) {
- // Note, this logic is handshake-time only:
- pendingFatalAlert = true;
- }
-
- emit q->alertSent(level, tlsAlertType(value), tlsAlertDescription(value));
-
-}
-
-void TlsCryptographOpenSSL::alertMessageReceived(int value)
-{
- Q_ASSERT(q);
-
- emit q->alertReceived(tlsAlertLevel(value), tlsAlertType(value), tlsAlertDescription(value));
-}
-
-int TlsCryptographOpenSSL::emitErrorFromCallback(X509_STORE_CTX *ctx)
-{
- // Returns 0 to abort verification, 1 to continue despite error (as
- // OpenSSL expects from the verification callback).
- Q_ASSERT(q);
- Q_ASSERT(ctx);
-
- using ScopedBool = QScopedValueRollback<bool>;
- // While we are not setting, we are emitting and in general -
- // we want to prevent accidental recursive startHandshake()
- // calls:
- const ScopedBool bg(inSetAndEmitError, true);
-
- X509 *x509 = q_X509_STORE_CTX_get_current_cert(ctx);
- if (!x509) {
- qCWarning(lcTlsBackend, "Could not obtain the certificate (that failed to verify)");
- return 0;
- }
-
- const QSslCertificate certificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
- const auto errorAndDepth = QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx);
- const QSslError tlsError = QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(errorAndDepth.code, certificate);
-
- errorsReportedFromCallback = true;
- handshakeInterrupted = true;
- emit q->handshakeInterruptedOnError(tlsError);
-
- // Conveniently so, we also can access 'lastErrors' external data set
- // in startHandshake, we store it for the case an application later
- // wants to check errors (ignored or not):
- const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::errorOffsetInExData;
- if (auto errorList = static_cast<QList<QSslErrorEntry> *>(q_SSL_get_ex_data(ssl, offset)))
- errorList->append(errorAndDepth);
-
- // An application is expected to ignore this error (by calling ignoreSslErrors)
- // in its directly connected slot:
- return !handshakeInterrupted;
-}
-
-void TlsCryptographOpenSSL::trySendFatalAlert()
-{
- Q_ASSERT(pendingFatalAlert);
- Q_ASSERT(d);
-
- auto *plainSocket = d->plainTcpSocket();
-
- pendingFatalAlert = false;
- QVarLengthArray<char, 4096> data;
- int pendingBytes = 0;
- while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0
- && plainSocket->openMode() != QIODevice::NotOpen) {
- // Read encrypted data from the write BIO into a buffer.
- data.resize(pendingBytes);
- const int bioReadBytes = q_BIO_read(writeBio, data.data(), pendingBytes);
-
- // Write encrypted data from the buffer to the socket.
- qint64 actualWritten = plainSocket->write(data.constData(), bioReadBytes);
- if (actualWritten < 0)
- return;
- plainSocket->flush();
- }
-}
-
-bool TlsCryptographOpenSSL::initSslContext()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- // If no external context was set (e.g. by QHttpNetworkConnection) we will
- // create a new one.
- const auto mode = d->tlsMode();
- const auto configuration = q->sslConfiguration();
- if (!sslContextPointer)
- sslContextPointer = QSslContext::sharedFromConfiguration(mode, configuration, d->isRootsOnDemandAllowed());
-
- if (sslContextPointer->error() != QSslError::NoError) {
- d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
- sslContextPointer.clear(); // deletes the QSslContext
- return false;
- }
-
- // Create and initialize SSL session
- if (!(ssl = sslContextPointer->createSsl())) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- return false;
- }
-
- if (configuration.protocol() != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
- const auto verificationPeerName = d->verificationName();
- // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
- QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
- if (tlsHostName.isEmpty())
- tlsHostName = d->tlsHostName();
- QByteArray ace = QUrl::toAce(tlsHostName);
- // only send the SNI header if the URL is valid and not an IP
- if (!ace.isEmpty()
- && !QHostAddress().setAddress(tlsHostName)
- && !(configuration.testSslOption(QSsl::SslOptionDisableServerNameIndication))) {
- // We don't send the trailing dot from the host header if present see
- // https://tools.ietf.org/html/rfc6066#section-3
- if (ace.endsWith('.'))
- ace.chop(1);
- if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data()))
- qCWarning(lcTlsBackend, "could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled");
- }
- }
-
- // Clear the session.
- errorList.clear();
-
- // Initialize memory BIOs for encryption and decryption.
- readBio = q_BIO_new(q_BIO_s_mem());
- writeBio = q_BIO_new(q_BIO_s_mem());
- if (!readBio || !writeBio) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session: %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
- if (readBio)
- q_BIO_free(readBio);
- if (writeBio)
- q_BIO_free(writeBio);
- return false;
- }
-
- // Assign the bios.
- q_SSL_set_bio(ssl, readBio, writeBio);
-
- if (mode == QSslSocket::SslClientMode)
- q_SSL_set_connect_state(ssl);
- else
- q_SSL_set_accept_state(ssl);
-
- q_SSL_set_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData, this);
-
-#ifndef OPENSSL_NO_PSK
- // Set the client callback for PSK
- if (mode == QSslSocket::SslClientMode)
- q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
- else if (mode == QSslSocket::SslServerMode)
- q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback);
-
-#if OPENSSL_VERSION_NUMBER >= 0x10101006L
- // Set the client callback for TLSv1.3 PSK
- if (mode == QSslSocket::SslClientMode
- && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) {
- q_SSL_set_psk_use_session_callback(ssl, &q_ssl_psk_use_session_callback);
- }
-#endif // openssl version >= 0x10101006L
-
-#endif // OPENSSL_NO_PSK
-
-#if QT_CONFIG(ocsp)
- if (configuration.ocspStaplingEnabled()) {
- if (mode == QSslSocket::SslServerMode) {
- d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
- return false;
- }
- if (q_SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp) != 1) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Failed to enable OCSP stapling"));
- return false;
- }
- }
-
- ocspResponseDer.clear();
- const auto backendConfig = configuration.backendConfiguration();
- auto responsePos = backendConfig.find("Qt-OCSP-response");
- if (responsePos != backendConfig.end()) {
- // This is our private, undocumented 'API' we use for the auto-testing of
- // OCSP-stapling. It must be a der-encoded OCSP response, presumably set
- // by tst_QOcsp.
- const QVariant data(responsePos.value());
- if (data.canConvert<QByteArray>())
- ocspResponseDer = data.toByteArray();
- }
-
- if (ocspResponseDer.size()) {
- if (mode != QSslSocket::SslServerMode) {
- d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Client-side sockets do not send OCSP responses"));
- return false;
- }
- }
-#endif // ocsp
-
- return true;
-}
-
-void TlsCryptographOpenSSL::destroySslContext()
-{
- if (ssl) {
- if (!q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
- // We do not send a shutdown alert here. Just mark the session as
- // resumable for qhttpnetworkconnection's "optimization", otherwise
- // OpenSSL won't start a session resumption.
- if (q_SSL_shutdown(ssl) != 1) {
- // Some error may be queued, clear it.
- const auto errors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
- Q_UNUSED(errors);
- }
- }
- q_SSL_free(ssl);
- ssl = nullptr;
- }
- sslContextPointer.clear();
-}
-
-void TlsCryptographOpenSSL::storePeerCertificates()
-{
- Q_ASSERT(d);
-
- // Store the peer certificate and chain. For clients, the peer certificate
- // chain includes the peer certificate; for servers, it doesn't. Both the
- // peer certificate and the chain may be empty if the peer didn't present
- // any certificate.
- X509 *x509 = q_SSL_get_peer_certificate(ssl);
-
- const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
- QTlsBackend::storePeerCertificate(d, peerCertificate);
- q_X509_free(x509);
- auto peerCertificateChain = q->peerCertificateChain();
- if (peerCertificateChain.isEmpty()) {
- peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
- if (!peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
- peerCertificateChain.prepend(peerCertificate);
- QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
- }
-}
-
-#if QT_CONFIG(ocsp)
-
-bool TlsCryptographOpenSSL::checkOcspStatus()
-{
- Q_ASSERT(ssl);
- Q_ASSERT(d);
-
- const auto &configuration = q->sslConfiguration();
- Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
- Q_ASSERT(configuration.peerVerifyMode() != QSslSocket::VerifyNone);
-
- const auto clearErrorQueue = qScopeGuard([] {
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- });
-
- ocspResponses.clear();
- ocspErrorDescription.clear();
- ocspErrors.clear();
-
- const unsigned char *responseData = nullptr;
- const long responseLength = q_SSL_get_tlsext_status_ocsp_resp(ssl, &responseData);
- if (responseLength <= 0 || !responseData) {
- ocspErrors.push_back(QSslError(QSslError::OcspNoResponseFound));
- return false;
- }
-
- OCSP_RESPONSE *response = q_d2i_OCSP_RESPONSE(nullptr, &responseData, responseLength);
- if (!response) {
- // Treat this as a fatal SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to decode OCSP response");
- return false;
- }
- const QSharedPointer<OCSP_RESPONSE> responseGuard(response, q_OCSP_RESPONSE_free);
-
- const int ocspStatus = q_OCSP_response_status(response);
- if (ocspStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
- // It's not a definitive response, it's an error message (not signed by the responder).
- ocspErrors.push_back(QSslError(qt_OCSP_response_status_to_SslError(ocspStatus)));
- return false;
- }
-
- OCSP_BASICRESP *basicResponse = q_OCSP_response_get1_basic(response);
- if (!basicResponse) {
- // SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to extract basic OCSP response");
- return false;
- }
- const QSharedPointer<OCSP_BASICRESP> basicResponseGuard(basicResponse, q_OCSP_BASICRESP_free);
-
- SSL_CTX *ctx = q_SSL_get_SSL_CTX(ssl); // Does not increment refcount.
- Q_ASSERT(ctx);
- X509_STORE *store = q_SSL_CTX_get_cert_store(ctx); // Does not increment refcount.
- if (!store) {
- // SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("No certificate verification store, cannot verify OCSP response");
- return false;
- }
-
- STACK_OF(X509) *peerChain = q_SSL_get_peer_cert_chain(ssl); // Does not increment refcount.
- X509 *peerX509 = q_SSL_get_peer_certificate(ssl);
- Q_ASSERT(peerChain || peerX509);
- const QSharedPointer<X509> peerX509Guard(peerX509, q_X509_free);
- // OCSP_basic_verify with 0 as verificationFlags:
- //
- // 0) Tries to find the OCSP responder's certificate in either peerChain
- // or basicResponse->certs. If not found, verification fails.
- // 1) It checks the signature using the responder's public key.
- // 2) Then it tries to validate the responder's cert (building a chain
- // etc.)
- // 3) It checks CertID in response.
- // 4) Ensures the responder is authorized to sign the status respond.
- //
- // Note, OpenSSL prior to 1.0.2b would only use bs->certs to
- // verify the responder's chain (see their commit 4ba9a4265bd).
- // Working this around - is too much fuss for ancient versions we
- // are dropping quite soon anyway.
- const unsigned long verificationFlags = 0;
- const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags);
- if (success <= 0)
- ocspErrors.push_back(QSslError(QSslError::OcspResponseCannotBeTrusted));
-
- if (q_OCSP_resp_count(basicResponse) != 1) {
- ocspErrors.push_back(QSslError(QSslError::OcspMalformedResponse));
- return false;
- }
-
- OCSP_SINGLERESP *singleResponse = q_OCSP_resp_get0(basicResponse, 0);
- if (!singleResponse) {
- ocspErrors.clear();
- // A fatal problem -> SslHandshakeError.
- ocspErrorDescription = QSslSocket::tr("Failed to decode a SingleResponse from OCSP status response");
- return false;
- }
-
- // Let's make sure the response is for the correct certificate - we
- // can re-create this CertID using our peer's certificate and its
- // issuer's public key.
- ocspResponses.push_back(QOcspResponse());
- QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
- dResponse->subjectCert = configuration.peerCertificate();
- bool matchFound = false;
- if (dResponse->subjectCert.isSelfSigned()) {
- dResponse->signerCert = configuration.peerCertificate();
- matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
- } else {
- const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
- if (!certs) // Oh, what a cataclysm! Last try:
- certs = q_OCSP_resp_get0_certs(basicResponse);
- if (certs) {
- // It could be the first certificate in 'certs' is our peer's
- // certificate. Since it was not captured by the 'self-signed' branch
- // above, the CertID will not match and we'll just iterate on to the
- // next certificate. So we start from 0, not 1.
- for (int i = 0, e = q_sk_X509_num(certs); i < e; ++i) {
- X509 *issuer = q_sk_X509_value(certs, i);
- matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer);
- if (matchFound) {
- if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) {
- dResponse->signerCert = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(issuer);
- break;
- }
- matchFound = false;
- }
- }
- }
- }
-
- if (!matchFound) {
- dResponse->signerCert.clear();
- ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate()});
- }
-
- // Check if the response is valid time-wise:
- ASN1_GENERALIZEDTIME *revTime = nullptr;
- ASN1_GENERALIZEDTIME *thisUpdate = nullptr;
- ASN1_GENERALIZEDTIME *nextUpdate = nullptr;
- int reason;
- const int certStatus = q_OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate);
- if (!thisUpdate) {
- // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer
- // to be != nullptr.
- ocspErrors.clear();
- ocspResponses.clear();
- ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse");
- return false;
- }
-
- // OCSP_check_validity(this, next, nsec, maxsec) does this check:
- // this <= now <= next. They allow some freedom to account
- // for delays/time inaccuracy.
- // this > now + nsec ? -> NOT_YET_VALID
- // if maxsec >= 0:
- // now - maxsec > this ? -> TOO_OLD
- // now - nsec > next ? -> EXPIRED
- // next < this ? -> NEXT_BEFORE_THIS
- // OK.
- if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1))
- ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate()});
-
- // And finally, the status:
- switch (certStatus) {
- case V_OCSP_CERTSTATUS_GOOD:
- // This certificate was not found among the revoked ones.
- dResponse->certificateStatus = QOcspCertificateStatus::Good;
- break;
- case V_OCSP_CERTSTATUS_REVOKED:
- dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
- dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
- ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate()});
- break;
- case V_OCSP_CERTSTATUS_UNKNOWN:
- dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
- ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate()});
- }
-
- return !ocspErrors.size();
-}
-
-#endif // QT_CONFIG(ocsp)
-
-
-unsigned TlsCryptographOpenSSL::pskClientTlsCallback(const char *hint, char *identity,
- unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len)
-{
- Q_ASSERT(q);
-
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for the user)
- const int hintLength = hint ? int(std::strlen(hint)) : 0;
- QTlsBackend::setupClientPskAuth(&authenticator, hint, hintLength, max_identity_len, max_psk_len);
- // Let the client provide the remaining bits...
- emit q->preSharedKeyAuthenticationRequired(&authenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (authenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int identityLength = qMin(authenticator.identity().length(), authenticator.maximumIdentityLength());
- std::memcpy(identity, authenticator.identity().constData(), identityLength);
- identity[identityLength] = 0;
-
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
- std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len)
-{
- Q_ASSERT(q);
-
- QSslPreSharedKeyAuthenticator authenticator;
-
- // Fill in some read-only fields (for the user)
- QTlsBackend::setupServerPskAuth(&authenticator, identity, q->sslConfiguration().preSharedKeyIdentityHint(),
- max_psk_len);
- emit q->preSharedKeyAuthenticationRequired(&authenticator);
-
- // No PSK set? Return now to make the handshake fail
- if (authenticator.preSharedKey().isEmpty())
- return 0;
-
- // Copy data back into OpenSSL
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
- std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-#ifdef Q_OS_WIN
-
-void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert)
-{
- Q_ASSERT(d);
- Q_ASSERT(q);
-
- //The root certificate is downloaded from windows update, which blocks for 15 seconds in the worst case
- //so the request is done in a worker thread.
- QList<QSslCertificate> customRoots;
- if (fetchAuthorityInformation)
- customRoots = q->sslConfiguration().caCertificates();
-
- //Remember we are fetching and what we are fetching:
- caToFetch = cert;
-
- QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, d->tlsMode(), customRoots,
- q->peerVerifyName());
- connect(fetcher, &QWindowsCaRootFetcher::finished, this, &TlsCryptographOpenSSL::caRootLoaded,
- Qt::QueuedConnection);
- QMetaObject::invokeMethod(fetcher, "start", Qt::QueuedConnection);
- QSslSocketPrivate::pauseSocketNotifiers(q);
- d->setPaused(true);
-}
-
-void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot)
-{
- if (caToFetch != cert) {
- //Ooops, something from the previous connection attempt, ignore!
- return;
- }
-
- Q_ASSERT(d);
- Q_ASSERT(q);
-
- //Done, fetched already:
- caToFetch = QSslCertificate{};
-
- if (fetchAuthorityInformation) {
- if (!q->sslConfiguration().caCertificates().contains(trustedRoot))
- trustedRoot = QSslCertificate{};
- fetchAuthorityInformation = false;
- }
-
- if (!trustedRoot.isNull() && !trustedRoot.isBlacklisted()) {
- if (QSslSocketPrivate::rootCertOnDemandLoadingSupported()) {
- //Add the new root cert to default cert list for use by future sockets
- auto defaultConfig = QSslConfiguration::defaultConfiguration();
- defaultConfig.addCaCertificate(trustedRoot);
- QSslConfiguration::setDefaultConfiguration(defaultConfig);
- }
- //Add the new root cert to this socket for future connections
- QTlsBackend::addTustedRoot(d, trustedRoot);
- //Remove the broken chain ssl errors (as chain is verified by windows)
- for (int i=sslErrors.count() - 1; i >= 0; --i) {
- if (sslErrors.at(i).certificate() == cert) {
- switch (sslErrors.at(i).error()) {
- case QSslError::UnableToGetLocalIssuerCertificate:
- case QSslError::CertificateUntrusted:
- case QSslError::UnableToVerifyFirstCertificate:
- case QSslError::SelfSignedCertificateInChain:
- // error can be ignored if OS says the chain is trusted
- sslErrors.removeAt(i);
- break;
- default:
- // error cannot be ignored
- break;
- }
- }
- }
- }
-
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
- // Continue with remaining errors
- if (plainSocket)
- plainSocket->resume();
- d->setPaused(false);
- if (checkSslErrors() && ssl) {
- bool willClose = (d->isAutoStartingHandshake() && d->isPendingClose());
- continueHandshake();
- if (!willClose)
- transmit();
- }
-}
-
-#endif // Q_OS_WIN
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtls_openssl_p.h b/src/network/ssl/qtls_openssl_p.h
deleted file mode 100644
index 1def93831d..0000000000
--- a/src/network/ssl/qtls_openssl_p.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLS_OPENSSL_P_H
-#define QTLS_OPENSSL_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qtlsbackend_openssl_p.h"
-#include "qsslcontext_openssl_p.h"
-#include "qsslcertificate.h"
-#include "qocspresponse.h"
-#include "qopenssl_p.h"
-
-#include <QtCore/qsharedpointer.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class TlsCryptographOpenSSL : public TlsCryptograph
-{
-public:
- enum ExDataOffset {
- errorOffsetInExData = 1,
- socketOffsetInExData = 2
- };
-
- ~TlsCryptographOpenSSL();
-
- void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
- void checkSettingSslContext(QSharedPointer<QSslContext> tlsContext) override;
- QSharedPointer<QSslContext> sslContext() const override;
-
- QList<QSslError> tlsErrors() const override;
-
- void startClientEncryption() override;
- void startServerEncryption() override;
- bool startHandshake();
- void enableHandshakeContinuation() override;
- void cancelCAFetch() override;
- void continueHandshake() override;
- void transmit() override;
- void disconnectFromHost() override;
- void disconnected() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- QList<QOcspResponse> ocsps() const override;
-
- bool checkSslErrors();
- int handleNewSessionTicket(SSL *connection);
-
- void alertMessageSent(int encoded);
- void alertMessageReceived(int encoded);
-
- int emitErrorFromCallback(X509_STORE_CTX *ctx);
- void trySendFatalAlert();
-
-#if QT_CONFIG(ocsp)
- bool checkOcspStatus();
-#endif
-
- QSslSocket *q = nullptr;
- QSslSocketPrivate *d = nullptr;
-
- void storePeerCertificates();
-
- unsigned pskClientTlsCallback(const char *hint, char *identity, unsigned max_identity_len,
- unsigned char *psk, unsigned max_psk_len);
- unsigned pskServerTlsCallback(const char *identity, unsigned char *psk,
- unsigned max_psk_len);
-
-#ifdef Q_OS_WIN
- void fetchCaRootForCert(const QSslCertificate &cert);
- void caRootLoaded(QSslCertificate certificate, QSslCertificate trustedRoot);
-#endif
-
- QByteArray ocspResponseDer;
-private:
- // TLSTODO: names were preserved, to make comparison
- // easier (see qsslsocket_openssl.cpp, while it exists).
- bool initSslContext();
- void destroySslContext();
-
- QSharedPointer<QSslContext> sslContextPointer;
- SSL *ssl = nullptr; // TLSTODO: RAII.
-
- QList<QSslErrorEntry> errorList;
- QList<QSslError> sslErrors;
-
- BIO *readBio = nullptr;
- BIO *writeBio = nullptr;
-
- QList<QOcspResponse> ocspResponses;
-
- // This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
- QString ocspErrorDescription;
- // These will go to sslErrors()
- QList<QSslError> ocspErrors;
-
- bool systemOrSslErrorDetected = false;
- bool handshakeInterrupted = false;
-
- bool fetchAuthorityInformation = false;
- QSslCertificate caToFetch;
-
- bool inSetAndEmitError = false;
- bool pendingFatalAlert = false;
- bool errorsReportedFromCallback = false;
-
- bool shutdown = false;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLS_OPENSSL_P_H
-
diff --git a/src/network/ssl/qtls_schannel.cpp b/src/network/ssl/qtls_schannel.cpp
deleted file mode 100644
index cb4b9ce79d..0000000000
--- a/src/network/ssl/qtls_schannel.cpp
+++ /dev/null
@@ -1,2322 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-// #define QSSLSOCKET_DEBUG
-
-#include "qssl_p.h"
-#include "qsslsocket.h"
-#include "qtls_schannel_p.h"
-#include "qsslcertificate.h"
-#include "qsslcertificateextension.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_p.h"
-#include "qtlsbackend_schannel_p.h"
-#include "qtlskey_schannel_p.h"
-#include "qx509_schannel_p.h"
-
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qoperatingsystemversion.h>
-#include <QtCore/qregularexpression.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qmutex.h>
-
-#define SECURITY_WIN32
-#include <security.h>
-#include <schnlsp.h>
-
-#if NTDDI_VERSION >= NTDDI_WINBLUE && !defined(Q_CC_MINGW)
-// ALPN = Application Layer Protocol Negotiation
-#define SUPPORTS_ALPN 1
-#endif
-
-// Redstone 5/1809 has all the API available, but TLS 1.3 is not enabled until a later version of
-// Win 10, checked at runtime in supportsTls13()
-#if defined(NTDDI_WIN10_RS5) && NTDDI_VERSION >= NTDDI_WIN10_RS5
-#define SUPPORTS_TLS13 1
-#endif
-
-// Not defined in MinGW
-#ifndef SECBUFFER_ALERT
-#define SECBUFFER_ALERT 17
-#endif
-#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
-#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
-#endif
-
-// Another missing MinGW define
-#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
-#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
-#endif
-
-// Also not defined in MinGW.......
-#ifndef SP_PROT_TLS1_SERVER
-#define SP_PROT_TLS1_SERVER 0x00000040
-#endif
-#ifndef SP_PROT_TLS1_CLIENT
-#define SP_PROT_TLS1_CLIENT 0x00000080
-#endif
-#ifndef SP_PROT_TLS1_0_SERVER
-#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
-#endif
-#ifndef SP_PROT_TLS1_0_CLIENT
-#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
-#endif
-#ifndef SP_PROT_TLS1_0
-#define SP_PROT_TLS1_0 (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_1_SERVER
-#define SP_PROT_TLS1_1_SERVER 0x00000100
-#endif
-#ifndef SP_PROT_TLS1_1_CLIENT
-#define SP_PROT_TLS1_1_CLIENT 0x00000200
-#endif
-#ifndef SP_PROT_TLS1_1
-#define SP_PROT_TLS1_1 (SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_2_SERVER
-#define SP_PROT_TLS1_2_SERVER 0x00000400
-#endif
-#ifndef SP_PROT_TLS1_2_CLIENT
-#define SP_PROT_TLS1_2_CLIENT 0x00000800
-#endif
-#ifndef SP_PROT_TLS1_2
-#define SP_PROT_TLS1_2 (SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER)
-#endif
-#ifndef SP_PROT_TLS1_3_SERVER
-#define SP_PROT_TLS1_3_SERVER 0x00001000
-#endif
-#ifndef SP_PROT_TLS1_3_CLIENT
-#define SP_PROT_TLS1_3_CLIENT 0x00002000
-#endif
-#ifndef SP_PROT_TLS1_3
-#define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
-#endif
-
-/*
- @future!:
-
- - Transmitting intermediate certificates
- - Look for a way to avoid putting intermediate certificates in the certificate store
- - No documentation on how to send the chain
- - A stackoverflow question on this from 3 years ago implies schannel only sends intermediate
- certificates if it's "in the system or user certificate store".
- - https://stackoverflow.com/q/30156584/2493610
- - This can be done by users, but we shouldn't add any and all local intermediate
- certs to the stores automatically.
- - PSK support
- - Was added in Windows 10 (it seems), documentation at time of writing is sparse/non-existent.
- - Specifically about how to supply credentials when they're requested.
- - Or how to recognize that they're requested in the first place.
- - Skip certificate verification.
- - Check if "PSK-only" is still required to do PSK _at all_ (all-around bad solution).
- - Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
- "missing PSK" when calling InitializeSecurityContext in "performHandshake".
-
- Medium priority:
- - Setting cipher-suites (or ALG_ID)
- - People have survived without it in WinRT
-
- Low priority:
- - Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
-
-*/
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.schannel");
-
-// Defined in qsslsocket_qt.cpp.
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
- const QString &passPhrase);
-
-namespace QTlsPrivate {
-
-QList<QSslCipher> defaultCiphers()
-{
- // Previously the code was in QSslSocketBackendPrivate.
- QList<QSslCipher> ciphers;
- // @temp (I hope), stolen from qsslsocket_winrt.cpp
- const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
- QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
- const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
- QSsl::TlsV1_2, QSsl::TlsV1_3 };
- const int size = ARRAYSIZE(protocols);
- static_assert(size == ARRAYSIZE(protocolStrings));
- ciphers.reserve(size);
- for (int i = 0; i < size; ++i) {
- const QSslCipher cipher = QTlsBackend::createCipher(QStringLiteral("Schannel"),
- protocols[i], protocolStrings[i]);
-
- ciphers.append(cipher);
- }
-
- return ciphers;
-
-}
-
-} // namespace QTlsPrivate
-
-namespace {
-bool supportsTls13();
-}
-
-bool QSchannelBackend::s_loadedCiphersAndCerts = false;
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
-
-long QSchannelBackend::tlsLibraryVersionNumber() const
-{
- const auto os = QOperatingSystemVersion::current();
- return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
-}
-
-QString QSchannelBackend::tlsLibraryVersionString() const
-{
- const auto os = QOperatingSystemVersion::current();
- return QString::fromLatin1("Secure Channel, %1 %2.%3.%4")
- .arg(os.name(),
- QString::number(os.majorVersion()),
- QString::number(os.minorVersion()),
- QString::number(os.microVersion()));
-}
-
-long QSchannelBackend::tlsLibraryBuildVersionNumber() const
-{
- return tlsLibraryVersionNumber();
-}
-
-QString QSchannelBackend::tlsLibraryBuildVersionString() const
-{
- const auto os = QOperatingSystemVersion::current();
- return QString::fromLatin1("%1.%2.%3")
- .arg(QString::number(os.majorVersion()),
- QString::number(os.minorVersion()),
- QString::number(os.microVersion()));
-}
-
-void QSchannelBackend::ensureInitialized() const
-{
- ensureInitializedImplementation();
-}
-
-void QSchannelBackend::ensureInitializedImplementation()
-{
- const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
- if (s_loadedCiphersAndCerts)
- return;
- s_loadedCiphersAndCerts = true;
-
- setDefaultCaCertificates(systemCaCertificatesImplementation());
- // setDefaultCaCertificates sets it to false, re-enable it:
- QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
-
- resetDefaultCiphers();
-}
-
-void QSchannelBackend::resetDefaultCiphers()
-{
- setDefaultSupportedCiphers(QTlsPrivate::defaultCiphers());
- setDefaultCiphers(QTlsPrivate::defaultCiphers());
-}
-
-QString QSchannelBackend::backendName() const
-{
- return builtinBackendNames[nameIndexSchannel];
-}
-
-QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols() const
-{
- QList<QSsl::SslProtocol> protocols;
-
- protocols << QSsl::AnyProtocol;
- protocols << QSsl::SecureProtocols;
- protocols << QSsl::TlsV1_0;
- protocols << QSsl::TlsV1_0OrLater;
- protocols << QSsl::TlsV1_1;
- protocols << QSsl::TlsV1_1OrLater;
- protocols << QSsl::TlsV1_2;
- protocols << QSsl::TlsV1_2OrLater;
-
- if (supportsTls13()) {
- protocols << QSsl::TlsV1_3;
- protocols << QSsl::TlsV1_3OrLater;
- }
-
- return protocols;
-}
-
-QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures() const
-{
- QList<QSsl::SupportedFeature> features;
-
- features << QSsl::SupportedFeature::ClientSideAlpn;
- features << QSsl::SupportedFeature::ServerSideAlpn;
-
- return features;
-}
-
-QList<QSsl::ImplementedClass> QSchannelBackend::implementedClasses() const
-{
- QList<QSsl::ImplementedClass> classes;
-
- classes << QSsl::ImplementedClass::Socket;
- classes << QSsl::ImplementedClass::Certificate;
- classes << QSsl::ImplementedClass::Key;
-
- return classes;
-}
-
-QTlsPrivate::TlsKey *QSchannelBackend::createKey() const
-{
- return new QTlsPrivate::TlsKeySchannel;
-}
-
-QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate() const
-{
- return new QTlsPrivate::X509CertificateSchannel;
-}
-
-QList<QSslCertificate> QSchannelBackend::systemCaCertificates() const
-{
- return systemCaCertificatesImplementation();
-}
-
-QTlsPrivate::TlsCryptograph *QSchannelBackend::createTlsCryptograph() const
-{
- return new QTlsPrivate::TlsCryptographSchannel;
-}
-
-QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
-{
- // Similar to non-Darwin version found in qtlsbackend_openssl.cpp,
- // QTlsPrivate::systemCaCertificates function.
- QList<QSslCertificate> systemCerts;
- auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
- if (hSystemStore) {
- PCCERT_CONTEXT pc = nullptr;
- while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
- CERT_FIND_ANY, nullptr, pc))) {
- systemCerts.append(QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
- }
- }
- return systemCerts;
-}
-
-QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
-}
-
-QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
-}
-
-Q_GLOBAL_STATIC(QSchannelBackend, backendSchannel)
-
-namespace {
-
-SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
-{
- return SecBuffer{ length, bufferType, ptr };
-}
-
-SecBuffer createSecBuffer(QByteArray &buffer, unsigned long bufferType)
-{
- return createSecBuffer(buffer.data(), static_cast<unsigned long>(buffer.length()), bufferType);
-}
-
-QString schannelErrorToString(qint32 status)
-{
- switch (status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- return QSslSocket::tr("Insufficient memory");
- case SEC_E_INTERNAL_ERROR:
- return QSslSocket::tr("Internal error");
- case SEC_E_INVALID_HANDLE:
- return QSslSocket::tr("An internal handle was invalid");
- case SEC_E_INVALID_TOKEN:
- return QSslSocket::tr("An internal token was invalid");
- case SEC_E_LOGON_DENIED:
- // According to the link below we get this error when Schannel receives TLS1_ALERT_ACCESS_DENIED
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/schannel-error-codes-for-tls-and-ssl-alerts
- return QSslSocket::tr("Access denied");
- case SEC_E_NO_AUTHENTICATING_AUTHORITY:
- return QSslSocket::tr("No authority could be contacted for authorization");
- case SEC_E_NO_CREDENTIALS:
- return QSslSocket::tr("No credentials");
- case SEC_E_TARGET_UNKNOWN:
- return QSslSocket::tr("The target is unknown or unreachable");
- case SEC_E_UNSUPPORTED_FUNCTION:
- return QSslSocket::tr("An unsupported function was requested");
- case SEC_E_WRONG_PRINCIPAL:
- // SNI error
- return QSslSocket::tr("The hostname provided does not match the one received from the peer");
- case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
- return QSslSocket::tr("No common protocol exists between the client and the server");
- case SEC_E_ILLEGAL_MESSAGE:
- return QSslSocket::tr("Unexpected or badly-formatted message received");
- case SEC_E_ENCRYPT_FAILURE:
- return QSslSocket::tr("The data could not be encrypted");
- case SEC_E_ALGORITHM_MISMATCH:
- return QSslSocket::tr("No cipher suites in common");
- case SEC_E_UNKNOWN_CREDENTIALS:
- // This can mean "invalid argument" in some cases...
- return QSslSocket::tr("The credentials were not recognized / Invalid argument");
- case SEC_E_MESSAGE_ALTERED:
- // According to the Internet it also triggers for messages that are out of order.
- // https://microsoft.public.platformsdk.security.narkive.com/4JAvlMvD/help-please-schannel-security-contexts-and-decryptmessage
- return QSslSocket::tr("The message was tampered with, damaged or out of sequence.");
- case SEC_E_OUT_OF_SEQUENCE:
- return QSslSocket::tr("A message was received out of sequence.");
- case SEC_E_CONTEXT_EXPIRED:
- return QSslSocket::tr("The TLS/SSL connection has been closed");
- default:
- return QSslSocket::tr("Unknown error occurred: %1").arg(status);
- }
-}
-
-bool supportsTls13()
-{
-#ifdef SUPPORTS_TLS13
- static bool supported = []() {
- const auto current = QOperatingSystemVersion::current();
- // 20221 just happens to be the preview version I run on my laptop where I tested TLS 1.3.
- const auto minimum =
- QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
- return current >= minimum;
- }();
- return supported;
-#else
- return false;
-#endif
-}
-
-DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
-{
- DWORD protocols = SP_PROT_NONE;
- switch (protocol) {
- case QSsl::UnknownProtocol:
- return DWORD(-1);
- case QSsl::DtlsV1_0:
- case QSsl::DtlsV1_2:
- case QSsl::DtlsV1_0OrLater:
- case QSsl::DtlsV1_2OrLater:
- return DWORD(-1); // Not supported at the moment (@future)
- case QSsl::AnyProtocol:
- protocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
- if (supportsTls13())
- protocols |= SP_PROT_TLS1_3;
- break;
- case QSsl::TlsV1_0:
- protocols = SP_PROT_TLS1_0;
- break;
- case QSsl::TlsV1_1:
- protocols = SP_PROT_TLS1_1;
- break;
- case QSsl::TlsV1_2:
- protocols = SP_PROT_TLS1_2;
- break;
- case QSsl::TlsV1_3:
- if (supportsTls13())
- protocols = SP_PROT_TLS1_3;
- else
- protocols = DWORD(-1);
- break;
- case QSsl::SecureProtocols: // TLS v1.0 and later is currently considered secure
- case QSsl::TlsV1_0OrLater:
- // For the "OrLater" protocols we fall through from one to the next, adding all of them
- // in ascending order
- protocols = SP_PROT_TLS1_0;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_1OrLater:
- protocols |= SP_PROT_TLS1_1;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_2OrLater:
- protocols |= SP_PROT_TLS1_2;
- Q_FALLTHROUGH();
- case QSsl::TlsV1_3OrLater:
- if (supportsTls13())
- protocols |= SP_PROT_TLS1_3;
- else if (protocol == QSsl::TlsV1_3OrLater)
- protocols = DWORD(-1); // if TlsV1_3OrLater was specifically chosen we should fail
- break;
- }
- return protocols;
-}
-
-#ifdef SUPPORTS_TLS13
-// In the new API that descended down upon us we are not asked which protocols we want
-// but rather which protocols we don't want. So now we have this function to disable
-// anything that is not enabled.
-DWORD toSchannelProtocolNegated(QSsl::SslProtocol protocol)
-{
- DWORD protocols = SP_PROT_ALL; // all protocols
- protocols &= ~toSchannelProtocol(protocol); // minus the one(s) we want
- return protocols;
-}
-#endif
-
-/*!
- \internal
- Used when converting the established session's \a protocol back to
- Qt's own SslProtocol type.
-
- Only one protocol should be passed in at a time.
-*/
-QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
-{
-#define MAP_PROTOCOL(sp_protocol, q_protocol) \
- if (protocol & sp_protocol) { \
- Q_ASSERT(!(protocol & ~sp_protocol)); \
- return q_protocol; \
- }
-
- MAP_PROTOCOL(SP_PROT_TLS1_0, QSsl::TlsV1_0)
- MAP_PROTOCOL(SP_PROT_TLS1_1, QSsl::TlsV1_1)
- MAP_PROTOCOL(SP_PROT_TLS1_2, QSsl::TlsV1_2)
- MAP_PROTOCOL(SP_PROT_TLS1_3, QSsl::TlsV1_3)
-#undef MAP_PROTOCOL
- Q_UNREACHABLE();
- return QSsl::UnknownProtocol;
-}
-
-/*!
- \internal
- Used by verifyCertContext to check if a client cert is used by a server or vice versa.
-*/
-bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient)
-{
- const auto netscapeIt = std::find_if(
- extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- const auto netscapeCertType = QStringLiteral("2.16.840.1.113730.1.1");
- return extension.oid() == netscapeCertType;
- });
- if (netscapeIt != extensions.cend()) {
- const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
- int netscapeCertType = 0;
- QDataStream dataStream(netscapeCertTypeByte);
- dataStream >> netscapeCertType;
- if (dataStream.status() != QDataStream::Status::Ok)
- return true;
- const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
- : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
- if ((netscapeCertType & expectedPeerCertType) == 0)
- return true;
- }
- return false;
-}
-
-/*!
- \internal
- Used by verifyCertContext to check the basicConstraints certificate
- extension to see if the certificate is a certificate authority.
- Returns false if the certificate does not have the basicConstraints
- extension or if it is not a certificate authority.
-*/
-bool isCertificateAuthority(const QList<QSslCertificateExtension> &extensions)
-{
- auto it = std::find_if(extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- return extension.name() == QLatin1String("basicConstraints");
- });
- if (it != extensions.cend()) {
- QVariantMap basicConstraints = it->value().toMap();
- return basicConstraints.value(QLatin1String("ca"), false).toBool();
- }
- return false;
-}
-
-/*!
- \internal
- Returns true if the attributes we requested from the context/handshake have
- been given.
-*/
-bool matchesContextRequirements(DWORD attributes, DWORD requirements,
- QSslSocket::PeerVerifyMode verifyMode,
- bool isClient)
-{
-#ifdef QSSLSOCKET_DEBUG
-#define DEBUG_WARN(message) qCWarning(lcSsl, message)
-#else
-#define DEBUG_WARN(message)
-#endif
-
-#define CHECK_ATTRIBUTE(attributeName) \
- do { \
- const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
- const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
- if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) { \
- DEBUG_WARN("Missing attribute \"" #attributeName "\""); \
- return false; \
- } \
- } while (false)
-
- CHECK_ATTRIBUTE(CONFIDENTIALITY);
- CHECK_ATTRIBUTE(REPLAY_DETECT);
- CHECK_ATTRIBUTE(SEQUENCE_DETECT);
- CHECK_ATTRIBUTE(STREAM);
- if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
- CHECK_ATTRIBUTE(MUTUAL_AUTH);
-
- // This one is manual because there is no server / ASC_ version
- if (isClient) {
- const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
- const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
- if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
- DEBUG_WARN("Missing attribute \"MANUAL_CRED_VALIDATION\"");
- return false;
- }
- }
-
- return true;
-#undef CHECK_ATTRIBUTE
-#undef DEBUG_WARN
-}
-
-template<typename Required, typename Actual>
-Required const_reinterpret_cast(Actual *p)
-{
- return Required(p);
-}
-
-#ifdef SUPPORTS_ALPN
-bool supportsAlpn()
-{
- return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1;
-}
-
-QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
-{
- QByteArray alpnString;
- if (!nextAllowedProtocols.isEmpty() && supportsAlpn()) {
- const QByteArray names = [&nextAllowedProtocols]() {
- QByteArray protocolString;
- for (QByteArray proto : nextAllowedProtocols) {
- if (proto.size() > 255) {
- qCWarning(lcSsl) << "TLS ALPN extension" << proto
- << "is too long and will be ignored.";
- continue;
- } else if (proto.isEmpty()) {
- continue;
- }
- protocolString += char(proto.length()) + proto;
- }
- return protocolString;
- }();
- if (names.isEmpty())
- return alpnString;
-
- const quint16 namesSize = names.size();
- const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
- const quint32 totalSize = sizeof(alpnId) + sizeof(namesSize) + namesSize;
- alpnString = QByteArray::fromRawData(reinterpret_cast<const char *>(&totalSize), sizeof(totalSize))
- + QByteArray::fromRawData(reinterpret_cast<const char *>(&alpnId), sizeof(alpnId))
- + QByteArray::fromRawData(reinterpret_cast<const char *>(&namesSize), sizeof(namesSize))
- + names;
- }
- return alpnString;
-}
-#endif // SUPPORTS_ALPN
-
-qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
-{
- Q_ASSERT(plainSocket);
- static const qint64 shrinkCutoff = 1024 * 12;
- static const qint64 defaultRead = 1024 * 16;
- qint64 bytesRead = 0;
-
- const auto toRead = std::min(defaultRead, plainSocket->bytesAvailable());
- if (toRead > 0) {
- const auto bufferSize = buffer.size();
- buffer.reserve(bufferSize + toRead); // avoid growth strategy kicking in
- buffer.resize(bufferSize + toRead);
- bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
- buffer.resize(bufferSize + bytesRead);
- // In case of excessive memory usage we shrink:
- if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
- buffer.shrink_to_fit();
- }
-
- return bytesRead;
-}
-
-void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
-{
- Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
- if (int(secBuffer.cbBuffer) >= buffer.size())
- return;
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We got SECBUFFER_EXTRA, will retain %lu bytes", secBuffer.cbBuffer);
-#endif
- std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
- buffer.resize(secBuffer.cbBuffer);
-}
-
-qint64 checkIncompleteData(const SecBuffer &secBuffer)
-{
- if (secBuffer.BufferType == SECBUFFER_MISSING) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Need %lu more bytes.", secBuffer.cbBuffer);
-#endif
- return secBuffer.cbBuffer;
-}
- return 0;
-}
-
-} // anonymous namespace
-
-
-namespace QTlsPrivate {
-
-TlsCryptographSchannel::TlsCryptographSchannel()
-{
- SecInvalidateHandle(&credentialHandle);
- SecInvalidateHandle(&contextHandle);
- QSchannelBackend::ensureInitializedImplementation();
-}
-
-TlsCryptographSchannel::~TlsCryptographSchannel()
-{
- closeCertificateStores();
- deallocateContext();
- freeCredentialsHandle();
- CertFreeCertificateContext(localCertContext);
-}
-
-void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
-{
- Q_ASSERT(qObj);
- Q_ASSERT(dObj);
-
- q = qObj;
- d = dObj;
-
- reset();
-}
-
-bool TlsCryptographSchannel::sendToken(void *token, unsigned long tokenLength, bool emitError)
-{
- if (tokenLength == 0)
- return true;
-
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
- if (written != qint64(tokenLength)) {
- // Failed to write/buffer everything or an error occurred
- if (emitError)
- d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return false;
- }
- return true;
-}
-
-QString TlsCryptographSchannel::targetName() const
-{
- // Used for SNI extension
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- const auto verificationPeerName = d->verificationName();
- return verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
-}
-
-ULONG TlsCryptographSchannel::getContextRequirements()
-{
- Q_ASSERT(d);
- Q_ASSERT(q);
-
- const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
- ULONG req = 0;
-
- req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
- req |= ISC_REQ_CONFIDENTIALITY; // Encrypt messages
- req |= ISC_REQ_REPLAY_DETECT; // Detect replayed messages
- req |= ISC_REQ_SEQUENCE_DETECT; // Detect out of sequence messages
- req |= ISC_REQ_STREAM; // Support a stream-oriented connection
-
- if (isClient) {
- req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
- } else {
- switch (q->peerVerifyMode()) {
- case QSslSocket::PeerVerifyMode::VerifyNone:
- // There doesn't seem to be a way to ask for an optional client cert :-(
- case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
- case QSslSocket::PeerVerifyMode::QueryPeer:
- break;
- case QSslSocket::PeerVerifyMode::VerifyPeer:
- req |= ISC_REQ_MUTUAL_AUTH;
- break;
- }
- }
-
- return req;
-}
-
-bool TlsCryptographSchannel::acquireCredentialsHandle()
-{
- Q_ASSERT(d);
- Q_ASSERT(q);
- const auto &configuration = q->sslConfiguration();
-
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
-
- const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
- const DWORD protocols = toSchannelProtocol(configuration.protocol());
- if (protocols == DWORD(-1)) {
- d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Invalid protocol chosen"));
- return false;
- }
-
- const CERT_CHAIN_CONTEXT *chainContext = nullptr;
- auto freeCertChain = qScopeGuard([&chainContext]() {
- if (chainContext)
- CertFreeCertificateChain(chainContext);
- });
-
- DWORD certsCount = 0;
- // Set up our certificate stores before trying to use one...
- initializeCertificateStores();
-
- // Check if user has specified a certificate chain but it could not be loaded.
- // This happens if there was something wrong with the certificate chain or there was no private
- // key.
- if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
- return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
-
- if (localCertificateStore != nullptr) {
- CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
- ZeroMemory(&findParam, sizeof(findParam));
- findParam.cbSize = sizeof(findParam);
- findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
-
- // There should only be one chain in our store, so.. we grab that one.
- chainContext = CertFindChainInStore(localCertificateStore.get(),
- X509_ASN_ENCODING,
- 0,
- CERT_CHAIN_FIND_BY_ISSUER,
- &findParam,
- nullptr);
- if (!chainContext) {
- const QString message = isClient
- ? QSslSocket::tr("The certificate provided cannot be used for a client.")
- : QSslSocket::tr("The certificate provided cannot be used for a server.");
- d->setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
- return false;
- }
- Q_ASSERT(chainContext->cChain == 1);
- Q_ASSERT(chainContext->rgpChain[0]);
- Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
- Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
- Q_ASSERT(!localCertContext);
- localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
- ->rgpElement[0]
- ->pCertContext);
- certsCount = 1;
- Q_ASSERT(localCertContext);
- }
- void *credentials = nullptr;
-#ifdef SUPPORTS_TLS13
- TLS_PARAMETERS tlsParameters = {
- 0,
- nullptr,
- toSchannelProtocolNegated(configuration.protocol()), // what protocols to disable
- 0,
- nullptr,
- 0
- };
- if (supportsTls13()) {
- SCH_CREDENTIALS *cred = new SCH_CREDENTIALS{
- SCH_CREDENTIALS_VERSION,
- 0,
- certsCount,
- &localCertContext,
- nullptr,
- 0,
- nullptr,
- 0,
- SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
- | SCH_CRED_NO_DEFAULT_CREDS,
- 1,
- &tlsParameters
- };
- credentials = cred;
- } else
-#endif // SUPPORTS_TLS13
- {
- SCHANNEL_CRED *cred = new SCHANNEL_CRED{
- SCHANNEL_CRED_VERSION, // dwVersion
- certsCount, // cCreds
- &localCertContext, // paCred (certificate(s) containing a private key for authentication)
- nullptr, // hRootStore
-
- 0, // cMappers (reserved)
- nullptr, // aphMappers (reserved)
-
- 0, // cSupportedAlgs
- nullptr, // palgSupportedAlgs (nullptr = system default)
-
- protocols, // grbitEnabledProtocols
- 0, // dwMinimumCipherStrength (0 = system default)
- 0, // dwMaximumCipherStrength (0 = system default)
- 0, // dwSessionLifespan (0 = schannel default, 10 hours)
- SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
- | SCH_CRED_NO_DEFAULT_CREDS, // dwFlags
- 0 // dwCredFormat (must be 0)
- };
- credentials = cred;
- }
- Q_ASSERT(credentials != nullptr);
-
- TimeStamp expiration{};
- auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
- const_cast<wchar_t *>(UNISP_NAME), // pszPackage
- isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
- nullptr, // pvLogonID (unused)
- credentials, // pAuthData
- nullptr, // pGetKeyFn (unused)
- nullptr, // pvGetKeyArgument (unused)
- &credentialHandle, // phCredential
- &expiration // ptsExpir
- );
-
-#ifdef SUPPORTS_TLS13
- if (supportsTls13()) {
- delete static_cast<SCH_CREDENTIALS *>(credentials);
- } else
-#endif // SUPPORTS_TLS13
- {
- delete static_cast<SCHANNEL_CRED *>(credentials);
- }
-
- if (status != SEC_E_OK) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
- return false;
- }
- return true;
-}
-
-void TlsCryptographSchannel::deallocateContext()
-{
- if (SecIsValidHandle(&contextHandle)) {
- DeleteSecurityContext(&contextHandle);
- SecInvalidateHandle(&contextHandle);
- }
-}
-
-void TlsCryptographSchannel::freeCredentialsHandle()
-{
- if (SecIsValidHandle(&credentialHandle)) {
- FreeCredentialsHandle(&credentialHandle);
- SecInvalidateHandle(&credentialHandle);
- }
-}
-
-void TlsCryptographSchannel::closeCertificateStores()
-{
- localCertificateStore.reset();
- peerCertificateStore.reset();
- caCertificateStore.reset();
-}
-
-bool TlsCryptographSchannel::createContext()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- const auto &configuration = q->sslConfiguration();
-
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
- ULONG contextReq = getContextRequirements();
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- TimeStamp expiry;
-
- SecBufferDesc alpnBufferDesc;
- bool useAlpn = false;
-#ifdef SUPPORTS_ALPN
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
- QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
- useAlpn = !alpnString.isEmpty();
- SecBuffer alpnBuffers[1];
- alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
- alpnBufferDesc = {
- SECBUFFER_VERSION,
- ARRAYSIZE(alpnBuffers),
- alpnBuffers
- };
-#endif
-
- auto status = InitializeSecurityContext(&credentialHandle, // phCredential
- nullptr, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- useAlpn ? &alpnBufferDesc : nullptr, // pInput
- 0, // Reserved2
- &contextHandle, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
-
- // This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
- // should be the only non-error return-code here.
- if (status != SEC_I_CONTINUE_NEEDED) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
- return false;
- }
-
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::PerformHandshake;
- return true;
-}
-
-bool TlsCryptographSchannel::acceptContext()
-{
- Q_ASSERT(d);
- Q_ASSERT(q);
- const auto &configuration = q->sslConfiguration();
- auto *plainSocket = d->plainTcpSocket();
-
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
- ULONG contextReq = getContextRequirements();
-
- if (missingData > plainSocket->bytesAvailable())
- return true;
-
- missingData = 0;
- readToBuffer(intermediateBuffer, plainSocket);
- if (intermediateBuffer.isEmpty())
- return true; // definitely need more data..
-
- SecBuffer inBuffers[2];
- inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
-
-#ifdef SUPPORTS_ALPN
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
- // The string must be alive when we call AcceptSecurityContext
- QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
- if (!alpnString.isEmpty()) {
- inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
- } else
-#endif
- {
- inBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- }
-
- SecBufferDesc inputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(inBuffers),
- inBuffers
- };
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- TimeStamp expiry;
- auto status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- nullptr, // phContext
- &inputBufferDesc, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- &contextHandle, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsTimeStamp
- );
-
- if (status == SEC_E_INCOMPLETE_MESSAGE) {
- // Need more data
- missingData = checkIncompleteData(outBuffers[0]);
- return true;
- }
-
- if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // inBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need to
- // be stored.
- retainExtraData(intermediateBuffer, inBuffers[1]);
- } else { /* No 'extra' data, message not incomplete */
- intermediateBuffer.resize(0);
- }
-
- if (status != SEC_I_CONTINUE_NEEDED) {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
- return false;
- }
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::PerformHandshake;
- return true;
-}
-
-bool TlsCryptographSchannel::performHandshake()
-{
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
- d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- return false;
- }
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(SecIsValidHandle(&contextHandle));
- Q_ASSERT(schannelState == SchannelState::PerformHandshake);
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Bytes available from socket: %lld", plainSocket->bytesAvailable());
- qCDebug(lcSsl, "intermediateBuffer size: %d", intermediateBuffer.size());
-#endif
-
- if (missingData > plainSocket->bytesAvailable())
- return true;
-
- missingData = 0;
- readToBuffer(intermediateBuffer, plainSocket);
- if (intermediateBuffer.isEmpty())
- return true; // no data, will fail
-
- SecBuffer outBuffers[3] = {};
- const auto freeOutBuffers = [&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- };
- const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
- // For this call to InitializeSecurityContext we may need to call it twice.
- // In some cases us not having a certificate isn't actually an error, but just a request.
- // With Schannel, to ignore this warning, we need to call InitializeSecurityContext again
- // when we get SEC_I_INCOMPLETE_CREDENTIALS! As far as I can tell it's not documented anywhere.
- // https://stackoverflow.com/a/47479968/2493610
- SECURITY_STATUS status;
- short attempts = 2;
- do {
- SecBuffer inputBuffers[2];
- inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
- inputBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- SecBufferDesc inputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(inputBuffers),
- inputBuffers
- };
-
- freeOutBuffers(); // free buffers from any previous attempt
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- status = InitializeSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- &inputBufferDesc, // pInput
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
-
- if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // inputBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need
- // to be stored.
- retainExtraData(intermediateBuffer, inputBuffers[1]);
- } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
- // Clear the buffer if we weren't asked for more data
- intermediateBuffer.resize(0);
- }
-
- --attempts;
- } while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
-
- switch (status) {
- case SEC_E_OK:
- // Need to transmit a final token in the handshake if 'cbBuffer' is non-zero.
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- schannelState = SchannelState::VerifyHandshake;
- return true;
- case SEC_I_CONTINUE_NEEDED:
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- // Must call InitializeSecurityContext again later (done through continueHandshake)
- return true;
- case SEC_I_INCOMPLETE_CREDENTIALS:
- // Schannel takes care of picking certificate to send (other than the one we can specify),
- // so if we get here then that means we don't have a certificate the server accepts.
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Server did not accept any certificate we could present."));
- return false;
- case SEC_I_CONTEXT_EXPIRED:
- // "The message sender has finished using the connection and has initiated a shutdown."
- if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
- return false;
- }
- if (!shutdown) { // we did not initiate this
- d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- }
- return true;
- case SEC_E_INCOMPLETE_MESSAGE:
- // Simply incomplete, wait for more data
- missingData = checkIncompleteData(outBuffers[0]);
- return true;
- case SEC_E_ALGORITHM_MISMATCH:
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Algorithm mismatch"));
- shutdown = true; // skip sending the "Shutdown" alert
- return false;
- }
-
- // Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
- // MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
- // (If you came here investigating an error: md5 is insecure, update your certificate)
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
- return false;
-}
-
-bool TlsCryptographSchannel::verifyHandshake()
-{
- Q_ASSERT(d);
- Q_ASSERT(q);
- const auto &configuration = q->sslConfiguration();
-
- sslErrors.clear();
-
- const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
-#define CHECK_STATUS(status) \
- if (status != SEC_E_OK) { \
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, \
- QSslSocket::tr("Failed to query the TLS context: %1") \
- .arg(schannelErrorToString(status))); \
- return false; \
- }
-
- // Everything is set up, now make sure there's nothing wrong and query some attributes...
- if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
- configuration.peerVerifyMode(), isClient)) {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Did not get the required attributes for the connection."));
- return false;
- }
-
- // Get stream sizes (to know the max size of a message and the size of the header and trailer)
- auto status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_STREAM_SIZES,
- &streamSizes);
- CHECK_STATUS(status);
-
- // Get session cipher info
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_CONNECTION_INFO,
- &connectionInfo);
- CHECK_STATUS(status);
-
-#ifdef SUPPORTS_ALPN
- const auto allowedProtos = configuration.allowedNextProtocols();
- if (!allowedProtos.isEmpty() && supportsAlpn()) {
- SecPkgContext_ApplicationProtocol alpn;
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_APPLICATION_PROTOCOL,
- &alpn);
- CHECK_STATUS(status);
- if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
- QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
- alpn.ProtocolIdSize);
- if (!allowedProtos.contains(negotiatedProto)) {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Unwanted protocol was negotiated"));
- return false;
- }
- QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
- } else {
- QTlsBackend::setNegotiatedProtocol(d, {});
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
- }
- }
-#endif // supports ALPN
-
-#undef CHECK_STATUS
-
- // Verify certificate
- CERT_CONTEXT *certificateContext = nullptr;
- auto freeCertificate = qScopeGuard([&certificateContext]() {
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
- });
- status = QueryContextAttributes(&contextHandle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &certificateContext);
-
- // QueryPeer can (currently) not work in Schannel since Schannel itself doesn't have a way to
- // ask for a certificate and then still be OK if it's not received.
- // To work around this we don't request a certificate at all for QueryPeer.
- // For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
- // This means that servers using Schannel will only request client certificate for "VerifyPeer".
- if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
- || (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
- && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
- if (status != SEC_E_OK) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
- << schannelErrorToString(status);
-#endif
- const QSslError error{ QSslError::NoPeerCertificate };
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // verifyCertContext returns false if the user disconnected while it was checking errors.
- if (certificateContext && !verifyCertContext(certificateContext))
- return false;
-
- if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
-#endif
- // If we're paused then checkSslErrors returned false, but it's not an error
- return d->isPaused() && q->state() == QAbstractSocket::ConnectedState;
- }
-
- schannelState = SchannelState::Done;
- return true;
-}
-
-bool TlsCryptographSchannel::renegotiate()
-{
- Q_ASSERT(d);
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- SECURITY_STATUS status;
- if (d->tlsMode() == QSslSocket::SslClientMode) {
- status = InitializeSecurityContext(&credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- nullptr, // pInput (nullptr for renegotiate)
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
- } else {
- status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- nullptr, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- nullptr, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr,
- &expiry // ptsTimeStamp
- );
- }
- if (status == SEC_I_CONTINUE_NEEDED) {
- schannelState = SchannelState::PerformHandshake;
- return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
- } else if (status == SEC_E_OK) {
- schannelState = SchannelState::PerformHandshake;
- return true;
- }
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
- return false;
-}
-
-/*!
- \internal
- reset the state in preparation for reuse of socket
-*/
-void TlsCryptographSchannel::reset()
-{
- Q_ASSERT(d);
-
- closeCertificateStores(); // certificate stores could've changed
- deallocateContext();
- freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
-
- connectionInfo = {};
- streamSizes = {};
-
- CertFreeCertificateContext(localCertContext);
- localCertContext = nullptr;
-
- contextAttributes = 0;
- intermediateBuffer.clear();
- schannelState = SchannelState::InitializeHandshake;
-
-
- d->setEncrypted(false);
- shutdown = false;
- renegotiating = false;
-
- missingData = 0;
-}
-
-void TlsCryptographSchannel::startClientEncryption()
-{
- Q_ASSERT(q);
-
- if (q->isEncrypted())
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void TlsCryptographSchannel::startServerEncryption()
-{
- Q_ASSERT(q);
-
- if (q->isEncrypted())
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void TlsCryptographSchannel::transmit()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- if (d->tlsMode() == QSslSocket::UnencryptedMode)
- return; // This function should not have been called
-
- // Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
- if (plainSocket->state() == QAbstractSocket::SocketState::UnconnectedState)
- return;
-
- if (schannelState != SchannelState::Done) {
- continueHandshake();
- return;
- }
-
- auto &writeBuffer = d->tlsWriteBuffer();
- auto &buffer = d->tlsBuffer();
- if (q->isEncrypted()) { // encrypt data in writeBuffer and write it to plainSocket
- qint64 totalBytesWritten = 0;
- qint64 writeBufferSize;
- while ((writeBufferSize = writeBuffer.size()) > 0) {
- const int headerSize = int(streamSizes.cbHeader);
- const int trailerSize = int(streamSizes.cbTrailer);
- // Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
- const int size = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
- QByteArray fullMessage(headerSize + trailerSize + size, Qt::Uninitialized);
- {
- // Use peek() here instead of read() so we don't lose data if encryption fails.
- qint64 copied = writeBuffer.peek(fullMessage.data() + headerSize, size);
- Q_ASSERT(copied == size);
- }
-
- SecBuffer inputBuffers[4]{
- createSecBuffer(fullMessage.data(), headerSize, SECBUFFER_STREAM_HEADER),
- createSecBuffer(fullMessage.data() + headerSize, size, SECBUFFER_DATA),
- createSecBuffer(fullMessage.data() + headerSize + size, trailerSize, SECBUFFER_STREAM_TRAILER),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
- };
- SecBufferDesc message{
- SECBUFFER_VERSION,
- ARRAYSIZE(inputBuffers),
- inputBuffers
- };
- auto status = EncryptMessage(&contextHandle, 0, &message, 0);
- if (status != SEC_E_OK) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Schannel failed to encrypt data: %1")
- .arg(schannelErrorToString(status)));
- return;
- }
- // Data was encrypted successfully, so we free() what we peek()ed earlier
- writeBuffer.free(size);
-
- // The trailer's size is not final, so resize fullMessage to not send trailing junk
- fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
- const qint64 bytesWritten = plainSocket->write(fullMessage);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Wrote %lld of total %d bytes", bytesWritten, fullMessage.length());
-#endif
- if (bytesWritten >= 0) {
- totalBytesWritten += bytesWritten;
- } else {
- d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- if (q->isEncrypted()) { // Decrypt data from remote
- int totalRead = 0;
- bool hadIncompleteData = false;
- const auto readBufferMaxSize = d->maxReadBufferSize();
- while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
- if (missingData > plainSocket->bytesAvailable()
- && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We're still missing %lld bytes, will check later.", missingData);
-#endif
- break;
- }
-
- missingData = 0;
- const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Read %lld encrypted bytes from the socket", bytesRead);
-#endif
- if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, (hadIncompleteData ? "No new data received, leaving loop!"
- : "Nothing to decrypt, leaving loop!"));
-#endif
- break;
- }
- hadIncompleteData = false;
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Total amount of bytes to decrypt: %d", intermediateBuffer.length());
-#endif
-
- SecBuffer dataBuffer[4]{
- createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
- createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
- };
- SecBufferDesc message{
- SECBUFFER_VERSION,
- ARRAYSIZE(dataBuffer),
- dataBuffer
- };
- auto status = DecryptMessage(&contextHandle, &message, 0, nullptr);
- if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
- // There can still be 0 output even if it succeeds, this is fine
- if (dataBuffer[1].cbBuffer > 0) {
- // It is always decrypted in-place.
- // But [0] is the STREAM_HEADER, [1] is the DATA and [2] is the STREAM_TRAILER.
- // The pointers in all of those still point into 'intermediateBuffer'.
- buffer.append(static_cast<char *>(dataBuffer[1].pvBuffer),
- dataBuffer[1].cbBuffer);
- totalRead += dataBuffer[1].cbBuffer;
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "Decrypted %lu bytes. New read buffer size: %d",
- dataBuffer[1].cbBuffer, buffer.size());
-#endif
- }
- if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
- // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
- // dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
- // the rest need to be stored.
- retainExtraData(intermediateBuffer, dataBuffer[3]);
- } else {
- intermediateBuffer.resize(0);
- }
- }
-
- if (status == SEC_E_INCOMPLETE_MESSAGE) {
- missingData = checkIncompleteData(dataBuffer[0]);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "We didn't have enough data to decrypt anything, will try again!");
-#endif
- // We try again, but if we don't get any more data then we leave
- hadIncompleteData = true;
- } else if (status == SEC_E_INVALID_HANDLE) {
- // I don't think this should happen, if it does we're done...
- qCWarning(lcSsl, "The internal SSPI handle is invalid!");
- Q_UNREACHABLE();
- } else if (status == SEC_E_INVALID_TOKEN) {
- qCWarning(lcSsl, "Got SEC_E_INVALID_TOKEN!");
- Q_UNREACHABLE(); // Happened once due to a bug, but shouldn't generally happen(?)
- } else if (status == SEC_E_MESSAGE_ALTERED) {
- // The message has been altered, disconnect now.
- shutdown = true; // skips sending the shutdown alert
- disconnectFromHost();
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_E_OUT_OF_SEQUENCE) {
- // @todo: I don't know if this one is actually "fatal"..
- // This path might never be hit as it seems this is for connection-oriented connections,
- // while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
- shutdown = true; // skips sending the shutdown alert
- disconnectFromHost();
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_I_CONTEXT_EXPIRED) {
- // 'remote' has initiated a shutdown
- disconnectFromHost();
- d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_I_RENEGOTIATE) {
- // 'remote' wants to renegotiate
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "The peer wants to renegotiate.");
-#endif
- schannelState = SchannelState::Renegotiate;
- renegotiating = true;
-
- // We need to call 'continueHandshake' or else there's no guarantee it ever gets called
- continueHandshake();
- break;
- }
- }
-
- if (totalRead) {
- if (bool *readyReadEmittedPointer = d->readyReadPointer())
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
- }
-}
-
-void TlsCryptographSchannel::sendShutdown()
-{
- Q_ASSERT(d);
-
- const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
- DWORD shutdownToken = SCHANNEL_SHUTDOWN;
- SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
- SecBufferDesc token{
- SECBUFFER_VERSION,
- 1,
- &buffer
- };
- auto status = ApplyControlToken(&contextHandle, &token);
-
- if (status != SEC_E_OK) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Failed to apply shutdown control token:" << schannelErrorToString(status);
-#endif
- return;
- }
-
- SecBuffer outBuffers[3];
- outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
- outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
- outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
- auto freeBuffers = qScopeGuard([&outBuffers]() {
- for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
- if (outBuffers[i].pvBuffer)
- FreeContextBuffer(outBuffers[i].pvBuffer);
- }
- });
- SecBufferDesc outputBufferDesc{
- SECBUFFER_VERSION,
- ARRAYSIZE(outBuffers),
- outBuffers
- };
-
- ULONG contextReq = getContextRequirements();
- TimeStamp expiry;
- if (isClient) {
- status = InitializeSecurityContext(&credentialHandle, // phCredential
- &contextHandle, // phContext
- const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
- contextReq, // fContextReq
- 0, // Reserved1
- 0, // TargetDataRep (unused)
- nullptr, // pInput
- 0, // Reserved2
- nullptr, // phNewContext (we already have one)
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr
- &expiry // ptsExpiry
- );
- } else {
- status = AcceptSecurityContext(
- &credentialHandle, // phCredential
- &contextHandle, // phContext
- nullptr, // pInput
- contextReq, // fContextReq
- 0, // TargetDataRep (unused)
- nullptr, // phNewContext
- &outputBufferDesc, // pOutput
- &contextAttributes, // pfContextAttr,
- &expiry // ptsTimeStamp
- );
- }
- if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
- if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, false)) {
- // We failed to send the shutdown message, but it's not that important since we're
- // shutting down anyway.
- return;
- }
- } else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "Failed to initialize shutdown:" << schannelErrorToString(status);
-#endif
- }
-}
-
-void TlsCryptographSchannel::disconnectFromHost()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- if (SecIsValidHandle(&contextHandle)) {
- if (!shutdown) {
- shutdown = true;
- if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
- if (q->isEncrypted()) {
- // Read as much as possible because this is likely our last chance
- qint64 tempMax = d->maxReadBufferSize();
- d->setMaxReadBufferSize(0);
- transmit();
- d->setMaxReadBufferSize(tempMax);
- sendShutdown();
- }
- }
- }
- }
- if (plainSocket->state() != QAbstractSocket::UnconnectedState)
- plainSocket->disconnectFromHost();
-}
-
-void TlsCryptographSchannel::disconnected()
-{
- Q_ASSERT(d);
-
- shutdown = true;
- d->setEncrypted(false);
- deallocateContext();
- freeCredentialsHandle();
-}
-
-QSslCipher TlsCryptographSchannel::sessionCipher() const
-{
- Q_ASSERT(q);
-
- if (!q->isEncrypted())
- return QSslCipher();
- return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
-}
-
-QSsl::SslProtocol TlsCryptographSchannel::sessionProtocol() const
-{
- if (!q->isEncrypted())
- return QSsl::SslProtocol::UnknownProtocol;
- return toQtSslProtocol(connectionInfo.dwProtocol);
-}
-
-void TlsCryptographSchannel::continueHandshake()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
- switch (schannelState) {
- case SchannelState::InitializeHandshake:
- if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
- disconnectFromHost();
- return;
- }
- if (!SecIsValidHandle(&credentialHandle)) // Needed to support tst_QSslSocket::setEmptyKey
- return;
- if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::PerformHandshake)
- break;
- Q_FALLTHROUGH();
- case SchannelState::PerformHandshake:
- if (!performHandshake()) {
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::VerifyHandshake)
- break;
- Q_FALLTHROUGH();
- case SchannelState::VerifyHandshake:
- // if we're in shutdown or renegotiating then we might not need to verify
- // (since we already did)
- if (!verifyHandshake()) {
- shutdown = true; // Skip sending shutdown alert
- q->abort(); // We don't want to send buffered data
- disconnectFromHost();
- return;
- }
- if (schannelState != SchannelState::Done)
- break;
- Q_FALLTHROUGH();
- case SchannelState::Done:
- // connectionEncrypted is already true if we come here from a renegotiation
- if (!q->isEncrypted()) {
- d->setEncrypted(true); // all is done
- emit q->encrypted();
- }
- renegotiating = false;
- if (d->isPendingClose()) {
- d->setPendingClose(false);
- disconnectFromHost();
- } else {
- transmit();
- }
- break;
- case SchannelState::Renegotiate:
- if (!renegotiate()) {
- disconnectFromHost();
- return;
- } else if (intermediateBuffer.size() || plainSocket->bytesAvailable()) {
- continueHandshake();
- }
- break;
- }
-}
-
-QList<QSslError> TlsCryptographSchannel::tlsErrors() const
-{
- return sslErrors;
-}
-
-/*
- Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
-*/
-bool TlsCryptographSchannel::checkSslErrors()
-{
- if (sslErrors.isEmpty())
- return true;
-
- Q_ASSERT(q);
- Q_ASSERT(d);
- const auto &configuration = q->sslConfiguration();
- auto *plainSocket = d->plainTcpSocket();
-
- emit q->sslErrors(sslErrors);
-
- const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
- && d->tlsMode() == QSslSocket::SslClientMode);
- const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- QSslSocketPrivate::pauseSocketNotifiers(q);
- d->setPaused(true);
- } else {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-void TlsCryptographSchannel::initializeCertificateStores()
-{
- //// helper function which turns a chain into a certificate store
- Q_ASSERT(d);
- Q_ASSERT(q);
- const auto &configuration = q->sslConfiguration();
-
- auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
- const wchar_t *passphrase = L"";
- // Need to embed the private key in the certificate
- QByteArray pkcs12 = _q_makePkcs12(certChain,
- privateKey,
- QString::fromWCharArray(passphrase, 0));
- CRYPT_DATA_BLOB pfxBlob;
- pfxBlob.cbData = DWORD(pkcs12.length());
- pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
- return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
- };
-
- if (!configuration.localCertificateChain().isEmpty()) {
- if (configuration.privateKey().isNull()) {
- d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Cannot provide a certificate with no key"));
- return;
- }
- if (localCertificateStore == nullptr) {
- localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
- configuration.privateKey());
- if (localCertificateStore == nullptr)
- qCWarning(lcSsl, "Failed to load certificate chain!");
- }
- }
-
- if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
- caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
- {}); // No private key for the CA certs
- }
-}
-
-bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
-{
- Q_ASSERT(certContext);
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
-
- // Create a collection of stores so we can pass in multiple stores as additional locations to
- // search for the certificate chain
- auto tempCertCollection = QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
- X509_ASN_ENCODING,
- 0,
- CERT_STORE_CREATE_NEW_FLAG,
- nullptr));
- if (!tempCertCollection) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to create certificate store collection!");
-#endif
- return false;
- }
-
- if (rootCertOnDemandLoadingAllowed()) {
- // @future(maybe): following the OpenSSL backend these certificates should be added into
- // the Ca list, not just included during verification.
- // That being said, it's not trivial to add the root certificates (if and only if they
- // came from the system root store). And I don't see this mentioned in our documentation.
- auto rootStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
- if (!rootStore) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to open the system root CA certificate store!");
-#endif
- return false;
- } else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add the system root CA certificate store to the certificate store collection!");
-#endif
- return false;
- }
- }
- if (caCertificateStore) {
- if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add the user's CA certificate store to the certificate store collection!");
-#endif
- return false;
- }
- }
-
- if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "Failed to add certificate's origin store to the certificate store collection!");
-#endif
- return false;
- }
-
- CERT_CHAIN_PARA parameters;
- ZeroMemory(&parameters, sizeof(parameters));
- parameters.cbSize = sizeof(CERT_CHAIN_PARA);
- parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
- parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
- LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
- : szOID_PKIX_KP_CLIENT_AUTH);
- parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
-
- QTlsBackend::clearPeerCertificates(d);
- const CERT_CHAIN_CONTEXT *chainContext = nullptr;
- auto freeCertChain = qScopeGuard([&chainContext]() {
- if (chainContext)
- CertFreeCertificateChain(chainContext);
- });
- BOOL status = CertGetCertificateChain(nullptr, // hChainEngine, default
- certContext, // pCertContext
- nullptr, // pTime, 'now'
- tempCertCollection.get(), // hAdditionalStore, additional cert store
- &parameters, // pChainPara
- CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // dwFlags
- nullptr, // reserved
- &chainContext // ppChainContext
- );
- if (status == FALSE || !chainContext || chainContext->cChain == 0) {
- QSslError error(QSslError::UnableToVerifyFirstCertificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- return q->state() == QAbstractSocket::ConnectedState;
- }
-
- // Helper-function to get a QSslCertificate given a CERT_CHAIN_ELEMENT
- static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
- if (!element)
- return QSslCertificate();
-
- const CERT_CONTEXT *certContext = element->pCertContext;
- return QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(certContext);
- };
-
- // Pick a chain to use as the certificate chain, if multiple are available:
- // According to https://docs.microsoft.com/en-gb/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
- // this seems to be the best way to get a trusted chain.
- CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
-
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
- auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
- getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
- // @Note: This is actually one of two errors:
- // "either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded."
- // But here we are checking the chain's status, so we assume the "issuing" error cannot occur here.
- auto error = QSslError(QSslError::PathLengthExceeded);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
- | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
- | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
- | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
- if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
- auto error = QSslError(QSslError::SslError::UnspecifiedError);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- DWORD verifyDepth = chain->cElement;
- if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
- verifyDepth = DWORD(q->peerVerifyDepth());
-
- const auto &caCertificates = q->sslConfiguration().caCertificates();
- QList<QSslCertificate> peerCertificateChain;
- for (DWORD i = 0; i < verifyDepth; i++) {
- CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
- QSslCertificate certificate = getCertificateFromChainElement(element);
- const QList<QSslCertificateExtension> extensions = certificate.extensions();
-
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "issuer:" << certificate.issuerDisplayName()
- << "\nsubject:" << certificate.subjectDisplayName()
- << "\nQSslCertificate info:" << certificate
- << "\nextended error info:" << element->pwszExtendedErrorInfo
- << "\nerror status:" << element->TrustStatus.dwErrorStatus;
-#endif
-
- peerCertificateChain.append(certificate);
- QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
-
- if (certificate.isBlacklisted()) {
- const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- LONG result = CertVerifyTimeValidity(nullptr /*== now */, element->pCertContext->pCertInfo);
- if (result != 0) {
- auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
- : QSslError::CertificateExpired,
- certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- //// Errors
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
- // handled right above
- Q_ASSERT(!sslErrors.isEmpty());
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
- auto error = QSslError(QSslError::CertificateRevoked, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
- auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- // While netscape shouldn't be relevant now it defined an extension which is
- // still in use. Schannel does not check this automatically, so we do it here.
- // It is used to differentiate between client and server certificates.
- if (netscapeWrongCertType(extensions, isClient))
- element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
- auto error = QSslError(QSslError::InvalidPurpose, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
- // Override this error if we have the certificate inside our trusted CAs list.
- const bool isTrustedRoot = caCertificates.contains(certificate);
- if (!isTrustedRoot) {
- auto error = QSslError(QSslError::CertificateUntrusted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
- | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
- if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
- // @future(maybe): Do something with this
- }
-
- // Dumping ground of errors that don't fit our specific errors
- static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
- | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
- | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
- | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
- | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
- | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
- if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
- auto error = QSslError(QSslError::UnspecifiedError, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
- auto it = std::find_if(extensions.cbegin(), extensions.cend(),
- [](const QSslCertificateExtension &extension) {
- return extension.name() == QLatin1String("basicConstraints");
- });
- if (it != extensions.cend()) {
- // @Note: This is actually one of two errors:
- // "either the certificate cannot be used to issue other certificates,
- // or the chain path length has been exceeded."
- QVariantMap basicConstraints = it->value().toMap();
- QSslError error;
- if (i > 0 && !basicConstraints.value(QLatin1String("ca"), false).toBool())
- error = QSslError(QSslError::InvalidPurpose, certificate);
- else
- error = QSslError(QSslError::PathLengthExceeded, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
- auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
- // If it's self-signed *and* a CA then we can assume it's a root CA certificate
- // and we can ignore the "self-signed" note:
- // We check the basicConstraints certificate extension when possible, but this didn't
- // exist for version 1, so we can only guess in that case
- const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
- || certificate.version() == "1";
-
- // Root certificate tends to be signed by themselves, so ignore self-signed status.
- if (!isRootCertificateAuthority) {
- auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- }
-
- if (!peerCertificateChain.isEmpty())
- QTlsBackend::storePeerCertificate(d, peerCertificateChain.first());
-
- const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
- // @Note: Somewhat copied from qsslsocket_mac.cpp
- const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
- || (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
- && d->tlsMode() == QSslSocket::SslClientMode);
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- if (!configuration.peerCertificate().isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- if (d->tlsMode() == QSslSocket::SslClientMode) {
- const auto verificationPeerName = d->verificationName();
- const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
- if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
- // No matches in common names or alternate names.
- const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else if (doVerifyPeer) {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- const QSslError error(QSslError::NoPeerCertificate);
- sslErrors += error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
-
- return true;
-}
-
-bool TlsCryptographSchannel::rootCertOnDemandLoadingAllowed()
-{
- Q_ASSERT(d);
- return d->isRootsOnDemandAllowed() && QSslSocketPrivate::rootCertOnDemandLoadingSupported();
-}
-
-} // namespace QTlsPrivate
-
-void QSslSocketPrivate::registerAdHocFactory()
-{
- // TLSTODO: this is a temporary solution, waiting for
- // backends to move to ... plugins.
- if (!backendSchannel())
- qCWarning(lcTlsBackend, "Failed to create backend factory");
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtls_schannel_p.h b/src/network/ssl/qtls_schannel_p.h
deleted file mode 100644
index e4ac15206c..0000000000
--- a/src/network/ssl/qtls_schannel_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLS_SCHANNEL_P_H
-#define QTLS_SCHANNEL_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-QT_REQUIRE_CONFIG(schannel);
-
-#include <QtCore/qt_windows.h>
-
-#include "qtlsbackend_schannel_p.h"
-#include "qsslsocket_p.h"
-
-#include "qwincrypt_p.h"
-
-#define SECURITY_WIN32
-#define SCHANNEL_USE_BLACKLISTS 1
-#include <Winternl.h> // needed for UNICODE defines
-#include <security.h>
-#include <schnlsp.h>
-#undef SCHANNEL_USE_BLACKLISTS
-#undef SECURITY_WIN32
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class TlsCryptographSchannel final : public TlsCryptograph
-{
- Q_DISABLE_COPY_MOVE(TlsCryptographSchannel)
-public:
- TlsCryptographSchannel();
- ~TlsCryptographSchannel();
-
- void init(QSslSocket *q, QSslSocketPrivate *d) override;
-
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
- void disconnectFromHost() override;
- void disconnected() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void continueHandshake() override;
- QList<QSslError> tlsErrors() const override;
-
-private:
- enum class SchannelState {
- InitializeHandshake, // create and transmit context (client)/accept context (server)
- PerformHandshake, // get token back, process it
- VerifyHandshake, // Verify that things are OK
- Done, // Connection encrypted!
- Renegotiate // Renegotiating!
- } schannelState = SchannelState::InitializeHandshake;
-
- void reset();
- bool acquireCredentialsHandle();
- ULONG getContextRequirements();
- bool createContext(); // for clients
- bool acceptContext(); // for server
- bool performHandshake();
- bool verifyHandshake();
- bool renegotiate();
-
- bool sendToken(void *token, unsigned long tokenLength, bool emitError = true);
- QString targetName() const;
-
- bool checkSslErrors();
- void deallocateContext();
- void freeCredentialsHandle();
- void closeCertificateStores();
- void sendShutdown();
-
- void initializeCertificateStores();
- bool verifyCertContext(CERT_CONTEXT *certContext);
-
- bool rootCertOnDemandLoadingAllowed();
-
- bool hasUndecryptedData() const override { return intermediateBuffer.size() > 0; }
-
- QSslSocket *q = nullptr;
- QSslSocketPrivate *d = nullptr;
-
- SecPkgContext_ConnectionInfo connectionInfo = {};
- SecPkgContext_StreamSizes streamSizes = {};
-
- CredHandle credentialHandle; // Initialized in ctor
- CtxtHandle contextHandle; // Initialized in ctor
-
- QByteArray intermediateBuffer; // data which is left-over or incomplete
-
- QHCertStorePointer localCertificateStore = nullptr;
- QHCertStorePointer peerCertificateStore = nullptr;
- QHCertStorePointer caCertificateStore = nullptr;
-
- const CERT_CONTEXT *localCertContext = nullptr;
-
- ULONG contextAttributes = 0;
- qint64 missingData = 0;
-
- bool renegotiating = false;
- bool shutdown = false;
- QList<QSslError> sslErrors;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLS_SCHANNEL_P_H
diff --git a/src/network/ssl/qtls_st.cpp b/src/network/ssl/qtls_st.cpp
deleted file mode 100644
index e4f5c71c02..0000000000
--- a/src/network/ssl/qtls_st.cpp
+++ /dev/null
@@ -1,1331 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsslsocket.h"
-
-#include "qssl_p.h"
-#include "qtls_st_p.h"
-#include "qasn1element_p.h"
-#include "qsslcertificate_p.h"
-#include "qtlsbackend_st_p.h"
-#include "qsslcipher_p.h"
-#include "qtlskey_st_p.h"
-#include "qsslkey_p.h"
-
-#include <QtCore/qmessageauthenticationcode.h>
-#include <QtCore/qoperatingsystemversion.h>
-#include <QtCore/qscopedvaluerollback.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qsystemdetection.h>
-#include <QtCore/qdatastream.h>
-#include <QtCore/qsysinfo.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/quuid.h>
-#include <QtCore/qdir.h>
-
-#include <algorithm>
-#include <cstddef>
-#include <limits>
-#include <vector>
-
-#include <QtCore/private/qcore_mac_p.h>
-
-#ifdef Q_OS_MACOS
-#include <CoreServices/CoreServices.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QSecureTransportBackend, backendSecureTransport)
-
-// Defined in qsslsocket_qt.cpp.
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
- const QString &passPhrase);
-
-namespace QTlsPrivate {
-
-// Defined in qtlsbackend_st.cpp
-QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
-
-namespace {
-
-#ifdef Q_OS_MACOS
-/*
-
-Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
-the default keychain and where we see annoying pop-ups asking about accessing a
-private key.
-
-*/
-
-struct EphemeralSecKeychain
-{
- EphemeralSecKeychain();
- ~EphemeralSecKeychain();
-
- SecKeychainRef keychain = nullptr;
- Q_DISABLE_COPY_MOVE(EphemeralSecKeychain)
-};
-
-EphemeralSecKeychain::EphemeralSecKeychain()
-{
- const auto uuid = QUuid::createUuid();
- if (uuid.isNull()) {
- qCWarning(lcTlsBackend) << "Failed to create a unique keychain name";
- return;
- }
-
- const QByteArray uuidAsByteArray = uuid.toByteArray();
- Q_ASSERT(uuidAsByteArray.size() > 2);
- Q_ASSERT(uuidAsByteArray.startsWith('{'));
- Q_ASSERT(uuidAsByteArray.endsWith('}'));
- const auto uuidAsString = QLatin1String(uuidAsByteArray.data(), uuidAsByteArray.size()).mid(1, uuidAsByteArray.size() - 2);
-
- const QString keychainName
- = QDir::tempPath() + QDir::separator() + uuidAsString + QLatin1String(".keychain");
- // SecKeychainCreate, pathName parameter:
- //
- // "A constant character string representing the POSIX path indicating where
- // to store the keychain."
- //
- // Internally they seem to use std::string, but this does not really help.
- // Fortunately, CFString has a convenient API.
- QCFType<CFStringRef> cfName = keychainName.toCFString();
- std::vector<char> posixPath;
- // "Extracts the contents of a string as a NULL-terminated 8-bit string
- // appropriate for passing to POSIX APIs."
- posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
- const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
- CFIndex(posixPath.size()));
- if (!ok) {
- qCWarning(lcTlsBackend) << "Failed to create a unique keychain name from"
- << "QDir::tempPath()";
- return;
- }
-
- std::vector<uint8_t> passUtf8(256);
- if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
- qCWarning(lcTlsBackend) << "SecRandomCopyBytes: failed to create a key";
- return;
- }
-
- const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
- &passUtf8[0], FALSE, nullptr,
- &keychain);
- if (status != errSecSuccess || !keychain) {
- qCWarning(lcTlsBackend) << "SecKeychainCreate: failed to create a custom keychain";
- if (keychain) {
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- keychain = nullptr;
- }
- }
-
- if (keychain) {
- SecKeychainSettings settings = {};
- settings.version = SEC_KEYCHAIN_SETTINGS_VERS1;
- // Strange, huh? But that's what their docs say to do! With lockOnSleep
- // == false, set interval to INT_MAX to never lock ...
- settings.lockInterval = INT_MAX;
- if (SecKeychainSetSettings(keychain, &settings) != errSecSuccess)
- qCWarning(lcTlsBackend) << "SecKeychainSettings: failed to disable lock on sleep";
- }
-
-#ifdef QSSLSOCKET_DEBUG
- if (keychain) {
- qCDebug(lcTlsBackend) << "Custom keychain with name" << keychainName << "was created"
- << "successfully";
- }
-#endif
-}
-
-EphemeralSecKeychain::~EphemeralSecKeychain()
-{
- if (keychain) {
- // clear file off disk
- SecKeychainDelete(keychain);
- CFRelease(keychain);
- }
-}
-
-#endif // Q_OS_MACOS
-
-void qt_releaseSecureTransportContext(SSLContextRef context)
-{
- if (context)
- CFRelease(context);
-}
-
-} // unnamed namespace
-
-// To be also used by qtlsbackend_st.cpp (thus not in unnamed namespace).
-SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
-{
- const bool isServer = mode == QSslSocket::SslServerMode;
- const SSLProtocolSide side = isServer ? kSSLServerSide : kSSLClientSide;
- // We never use kSSLDatagramType, so it's kSSLStreamType unconditionally.
- SSLContextRef context = SSLCreateContext(nullptr, side, kSSLStreamType);
- if (!context)
- qCWarning(lcSsl) << "SSLCreateContext failed";
- return context;
-}
-
-QSecureTransportContext::QSecureTransportContext(SSLContextRef c)
- : context(c)
-{
-}
-
-QSecureTransportContext::~QSecureTransportContext()
-{
- qt_releaseSecureTransportContext(context);
-}
-
-QSecureTransportContext::operator SSLContextRef()const
-{
- return context;
-}
-
-void QSecureTransportContext::reset(SSLContextRef newContext)
-{
- qt_releaseSecureTransportContext(context);
- context = newContext;
-}
-
-#if !defined(QT_PLATFORM_UIKIT) // dhparam is only used on macOS. (see the SSLSetDiffieHellmanParams call below)
-static const uint8_t dhparam[] =
- "\x30\x82\x01\x08\x02\x82\x01\x01\x00\x97\xea\xd0\x46\xf7\xae\xa7\x76\x80"
- "\x9c\x74\x56\x98\xd8\x56\x97\x2b\x20\x6c\x77\xe2\x82\xbb\xc8\x84\xbe\xe7"
- "\x63\xaf\xcc\x30\xd0\x67\x97\x7d\x1b\xab\x59\x30\xa9\x13\x67\x21\xd7\xd4"
- "\x0e\x46\xcf\xe5\x80\xdf\xc9\xb9\xba\x54\x9b\x46\x2f\x3b\x45\xfc\x2f\xaf"
- "\xad\xc0\x17\x56\xdd\x52\x42\x57\x45\x70\x14\xe5\xbe\x67\xaa\xde\x69\x75"
- "\x30\x0d\xf9\xa2\xc4\x63\x4d\x7a\x39\xef\x14\x62\x18\x33\x44\xa1\xf9\xc1"
- "\x52\xd1\xb6\x72\x21\x98\xf8\xab\x16\x1b\x7b\x37\x65\xe3\xc5\x11\x00\xf6"
- "\x36\x1f\xd8\x5f\xd8\x9f\x43\xa8\xce\x9d\xbf\x5e\xd6\x2d\xfa\x0a\xc2\x01"
- "\x54\xc2\xd9\x81\x54\x55\xb5\x26\xf8\x88\x37\xf5\xfe\xe0\xef\x4a\x34\x81"
- "\xdc\x5a\xb3\x71\x46\x27\xe3\xcd\x24\xf6\x1b\xf1\xe2\x0f\xc2\xa1\x39\x53"
- "\x5b\xc5\x38\x46\x8e\x67\x4c\xd9\xdd\xe4\x37\x06\x03\x16\xf1\x1d\x7a\xba"
- "\x2d\xc1\xe4\x03\x1a\x58\xe5\x29\x5a\x29\x06\x69\x61\x7a\xd8\xa9\x05\x9f"
- "\xc1\xa2\x45\x9c\x17\xad\x52\x69\x33\xdc\x18\x8d\x15\xa6\x5e\xcd\x94\xf4"
- "\x45\xbb\x9f\xc2\x7b\x85\x00\x61\xb0\x1a\xdc\x3c\x86\xaa\x9f\x5c\x04\xb3"
- "\x90\x0b\x35\x64\xff\xd9\xe3\xac\xf2\xf2\xeb\x3a\x63\x02\x01\x02";
-#endif
-
-OSStatus TlsCryptographSecureTransport::ReadCallback(TlsCryptographSecureTransport *socket,
- char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- Q_ASSERT(socket->d);
- QTcpSocket *plainSocket = socket->d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- if (socket->isHandshakeComplete()) {
- // Check if it's a renegotiation attempt, when the handshake is complete, the
- // session state is 'kSSLConnected':
- SSLSessionState currentState = kSSLConnected;
- const OSStatus result = SSLGetSessionState(socket->context, &currentState);
- if (result != noErr) {
- *dataLength = 0;
- return result;
- }
-
- if (currentState == kSSLHandshake) {
- // Renegotiation detected, don't allow read more yet - 'transmit'
- // will notice this and will call 'startHandshake':
- *dataLength = 0;
- socket->renegotiating = true;
- return errSSLWouldBlock;
- }
- }
-
- const qint64 bytes = plainSocket->read(data, *dataLength);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "read" << bytes;
-#endif
- if (bytes < 0) {
- *dataLength = 0;
- return errSecIO;
- }
-
- const OSStatus err = (size_t(bytes) < *dataLength) ? errSSLWouldBlock : errSecSuccess;
- *dataLength = bytes;
-
- return err;
-}
-
-OSStatus TlsCryptographSecureTransport::WriteCallback(TlsCryptographSecureTransport *socket,
- const char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- Q_ASSERT(socket->d);
- QTcpSocket *plainSocket = socket->d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- const qint64 bytes = plainSocket->write(data, *dataLength);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "write" << bytes;
-#endif
- if (bytes < 0) {
- *dataLength = 0;
- return errSecIO;
- }
-
- const OSStatus err = (size_t(bytes) < *dataLength) ? errSSLWouldBlock : errSecSuccess;
- *dataLength = bytes;
-
- return err;
-}
-
-TlsCryptographSecureTransport::TlsCryptographSecureTransport()
- : context(nullptr)
-{
-}
-
-TlsCryptographSecureTransport::~TlsCryptographSecureTransport()
-{
- destroySslContext();
-}
-
-void TlsCryptographSecureTransport::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
-{
- Q_ASSERT(qObj);
- Q_ASSERT(dObj);
- q = qObj;
- d = dObj;
-
- renegotiating = false;
- shutdown = false;
-}
-
-void TlsCryptographSecureTransport::continueHandshake()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- d->setEncrypted(true);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "connection encrypted";
-#endif
-
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
- // Unlike OpenSSL, Secure Transport does not allow to negotiate protocols via
- // a callback during handshake. We can only set our list of preferred protocols
- // (and send it during handshake) and then receive what our peer has sent to us.
- // And here we can finally try to find a match (if any).
- const auto &configuration = q->sslConfiguration();
- if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
- const auto &requestedProtocols = configuration.allowedNextProtocols();
- if (const int requestedCount = requestedProtocols.size()) {
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
- QTlsBackend::setNegotiatedProtocol(d, {});
-
- QCFType<CFArrayRef> cfArray;
- const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
- if (result == errSecSuccess && cfArray && CFArrayGetCount(cfArray)) {
- const int size = CFArrayGetCount(cfArray);
- QList<QString> peerProtocols(size);
- for (int i = 0; i < size; ++i)
- peerProtocols[i] = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(cfArray, i));
-
- for (int i = 0; i < requestedCount; ++i) {
- const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
- for (int j = 0; j < size; ++j) {
- if (requestedName == peerProtocols[j]) {
- QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
- QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
- break;
- }
- }
- if (configuration.nextProtocolNegotiationStatus() == QSslConfiguration::NextProtocolNegotiationNegotiated)
- break;
- }
- }
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (!renegotiating)
- emit q->encrypted();
-
- if (d->isAutoStartingHandshake() && d->isPendingClose()) {
- d->setPendingClose(false);
- q->disconnectFromHost();
- }
-}
-
-void TlsCryptographSecureTransport::disconnected()
-{
- Q_ASSERT(d && d->plainTcpSocket());
- if (d->plainTcpSocket()->bytesAvailable() <= 0)
- destroySslContext();
- // If there is still buffered data in the plain socket, don't destroy the ssl context yet.
- // It will be destroyed when the socket is deleted.
-}
-
-void TlsCryptographSecureTransport::disconnectFromHost()
-{
- Q_ASSERT(d && d->plainTcpSocket());
- if (context) {
- if (!shutdown) {
- SSLClose(context);
- shutdown = true;
- }
- }
- d->plainTcpSocket()->disconnectFromHost();
-}
-
-QSslCipher TlsCryptographSecureTransport::sessionCipher() const
-{
- SSLCipherSuite cipher = 0;
- if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
- return QSslCipher_from_SSLCipherSuite(cipher);
-
- return QSslCipher();
-}
-
-QSsl::SslProtocol TlsCryptographSecureTransport::sessionProtocol() const
-{
- if (!context)
- return QSsl::UnknownProtocol;
-
- SSLProtocol protocol = kSSLProtocolUnknown;
- const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
- if (err != errSecSuccess) {
- qCWarning(lcTlsBackend) << "SSLGetNegotiatedProtocolVersion failed:" << err;
- return QSsl::UnknownProtocol;
- }
-
- switch (protocol) {
- case kTLSProtocol1:
- return QSsl::TlsV1_0;
- case kTLSProtocol11:
- return QSsl::TlsV1_1;
- case kTLSProtocol12:
- return QSsl::TlsV1_2;
- case kTLSProtocol13:
- return QSsl::TlsV1_3;
- default:
- return QSsl::UnknownProtocol;
- }
-}
-
-void TlsCryptographSecureTransport::startClientEncryption()
-{
- if (!initSslContext()) {
- Q_ASSERT(d);
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void TlsCryptographSecureTransport::startServerEncryption()
-{
- if (!initSslContext()) {
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void TlsCryptographSecureTransport::transmit()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- // If we don't have any SSL context, don't bother transmitting.
- // Edit: if SSL session closed, don't bother either.
- if (!context || shutdown)
- return;
-
- if (!isHandshakeComplete())
- startHandshake();
-
- auto &writeBuffer = d->tlsWriteBuffer();
- if (isHandshakeComplete() && !writeBuffer.isEmpty()) {
- qint64 totalBytesWritten = 0;
- while (writeBuffer.nextDataBlockSize() > 0 && context) {
- const size_t nextDataBlockSize = writeBuffer.nextDataBlockSize();
- size_t writtenBytes = 0;
- const OSStatus err = SSLWrite(context, writeBuffer.readPointer(), nextDataBlockSize, &writtenBytes);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "SSLWrite returned" << err;
-#endif
- if (err != errSecSuccess && err != errSSLWouldBlock) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLWrite failed: %1").arg(err));
- break;
- }
-
- if (writtenBytes) {
- writeBuffer.free(writtenBytes);
- totalBytesWritten += writtenBytes;
- }
-
- if (writtenBytes < nextDataBlockSize)
- break;
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- auto &emittedBytesWritten = d->tlsEmittedBytesWritten();
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- auto &buffer = d->tlsBuffer();
- const auto readBufferMaxSize = d->maxReadBufferSize();
- if (isHandshakeComplete()) {
- QVarLengthArray<char, 4096> data;
- while (context && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
- size_t readBytes = 0;
- data.resize(4096);
- const OSStatus err = SSLRead(context, data.data(), data.size(), &readBytes);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << d->plainTcpSocket() << "SSLRead returned" << err;
-#endif
- if (err == errSSLClosedGraceful) {
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- break;
- } else if (err != errSecSuccess && err != errSSLWouldBlock) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLRead failed: %1").arg(err));
- break;
- }
-
- if (err == errSSLWouldBlock && renegotiating) {
- startHandshake();
- break;
- }
-
- if (readBytes) {
- buffer.append(data.constData(), readBytes);
- if (bool *readyReadEmittedPointer = d->readyReadPointer())
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
-
- if (err == errSSLWouldBlock)
- break;
- }
- }
-}
-
-SSLCipherSuite TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
-{
- if (ciph.name() == QLatin1String("AES128-SHA"))
- return TLS_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("DHE-RSA-AES128-SHA"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("AES256-SHA"))
- return TLS_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("DHE-RSA-AES256-SHA"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-NULL-SHA"))
- return TLS_ECDH_ECDSA_WITH_NULL_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-NULL-SHA"))
- return TLS_ECDH_RSA_WITH_NULL_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDH_RSA_WITH_RC4_128_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.name() == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.name() == QLatin1String("DES-CBC3-SHA"))
- return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("AES128-SHA256"))
- return TLS_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("AES256-SHA256"))
- return TLS_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.name() == QLatin1String("DHE-RSA-DES-CBC3-SHA"))
- return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.name() == QLatin1String("DHE-RSA-AES128-SHA256"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("DHE-RSA-AES256-SHA256"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.name() == QLatin1String("AES256-GCM-SHA384"))
- return TLS_RSA_WITH_AES_256_GCM_SHA384;
- if (ciph.name() == QLatin1String("ECDHE-ECDSA-AES128-SHA256"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("ECDHE-ECDSA-AES256-SHA384"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES128-SHA256"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("ECDH-ECDSA-AES256-SHA384"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.name() == QLatin1String("ECDHE-RSA-AES128-SHA256"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
- if (ciph.name() == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.name() == QLatin1String("ECDHE-RSA-AES256-GCM-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
- return 0;
-}
-
-bool TlsCryptographSecureTransport::initSslContext()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- const auto mode = d->tlsMode();
-
- context.reset(qt_createSecureTransportContext(mode));
- if (!context) {
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
- return false;
- }
-
- const OSStatus err = SSLSetIOFuncs(context,
- reinterpret_cast<SSLReadFunc>(&TlsCryptographSecureTransport::ReadCallback),
- reinterpret_cast<SSLWriteFunc>(&TlsCryptographSecureTransport::WriteCallback));
- if (err != errSecSuccess) {
- destroySslContext();
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
- return false;
- }
-
- SSLSetConnection(context, this);
-
- const auto &configuration = q->sslConfiguration();
- if (mode == QSslSocket::SslServerMode
- && !configuration.localCertificateChain().isEmpty()) {
- QString errorDescription;
- QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
- if (!setSessionCertificate(errorDescription, errorCode)) {
- destroySslContext();
- d->setErrorAndEmit(errorCode, errorDescription);
- return false;
- }
- }
-
- if (!setSessionProtocol()) {
- destroySslContext();
- d->setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
- return false;
- }
-
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
- if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
- const auto protocolNames = configuration.allowedNextProtocols();
- QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
- if (cfNames) {
- for (const QByteArray &name : protocolNames) {
- if (name.size() > 255) {
- qCWarning(lcTlsBackend) << "TLS ALPN extension" << name
- << "is too long and will be ignored.";
- continue;
- } else if (name.isEmpty()) {
- continue;
- }
- QCFString cfName(QString::fromLatin1(name).toCFString());
- CFArrayAppendValue(cfNames, cfName);
- }
-
- if (CFArrayGetCount(cfNames)) {
- // Up to the application layer to check that negotiation
- // failed, and handle this non-TLS error, we do not handle
- // the result of this call as an error:
- if (SSLSetALPNProtocols(context, cfNames) != errSecSuccess)
- qCWarning(lcTlsBackend) << "SSLSetALPNProtocols failed - too long protocol names?";
- }
- } else {
- qCWarning(lcTlsBackend) << "failed to allocate ALPN names array";
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (mode == QSslSocket::SslClientMode) {
- // enable Server Name Indication (SNI)
- const auto verificationPeerName = d->verificationName();
- QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
- if (tlsHostName.isEmpty())
- tlsHostName = d->tlsHostName();
-
- const QByteArray ace(QUrl::toAce(tlsHostName));
- SSLSetPeerDomainName(context, ace.data(), ace.size());
- // tell SecureTransport we handle peer verification ourselves
- OSStatus err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnServerAuth, true);
- if (err == errSecSuccess)
- err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnCertRequested, true);
-
- if (err != errSecSuccess) {
- destroySslContext();
- d->setErrorAndEmit(QSslSocket::SslInternalError,
- QStringLiteral("SSLSetSessionOption failed: %1").arg(err));
- return false;
- }
- //
- } else {
- if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
- // kAlwaysAuthenticate - always fails even if we set break on client auth.
- OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
- if (err == errSecSuccess) {
- // We'd like to verify peer ourselves, otherwise handshake will
- // most probably fail before we can do anything.
- err = SSLSetSessionOption(context, kSSLSessionOptionBreakOnClientAuth, true);
- }
-
- if (err != errSecSuccess) {
- destroySslContext();
- d->setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("failed to set SSL context option in server mode: %1").arg(err));
- return false;
- }
- }
-#if !defined(QT_PLATFORM_UIKIT)
- // No SSLSetDiffieHellmanParams on iOS; calling it is optional according to docs.
- SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
-#endif
- }
- if (configuration.ciphers().size() > 0) {
- QVector<SSLCipherSuite> cfCiphers;
- for (const QSslCipher &cipher : configuration.ciphers()) {
- if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
- cfCiphers << sslCipher;
- }
- if (cfCiphers.size() == 0) {
- qCWarning(lcTlsBackend) << "failed to add any of the requested ciphers from the configuration";
- return false;
- }
- OSStatus err = SSLSetEnabledCiphers(context, cfCiphers.data(), cfCiphers.size());
- if (err != errSecSuccess) {
- qCWarning(lcTlsBackend) << "failed to set the ciphers from the configuration";
- return false;
- }
- }
- return true;
-}
-
-void TlsCryptographSecureTransport::destroySslContext()
-{
- context.reset(nullptr);
-}
-
-bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- Q_ASSERT(d);
- const auto &configuration = q->sslConfiguration();
-
-#ifdef QSSLSOCKET_DEBUG
- auto *plainSocket = d->plainTcpSocket();
-#endif
-
- QSslCertificate localCertificate;
-
- if (!configuration.localCertificateChain().isEmpty())
- localCertificate = configuration.localCertificateChain().at(0);
-
- if (!localCertificate.isNull()) {
- // Require a private key as well.
- if (configuration.privateKey().isNull()) {
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("Cannot provide a certificate with no key");
- return false;
- }
-
- // import certificates and key
- const QString passPhrase(QString::fromLatin1("foobar"));
- QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
- configuration.privateKey(), passPhrase).toCFData();
- QCFType<CFStringRef> password = passPhrase.toCFString();
- const void *keys[2] = { kSecImportExportPassphrase };
- const void *values[2] = { password };
- CFIndex nKeys = 1;
-#ifdef Q_OS_MACOS
- bool envOk = false;
- const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
- if (envOk && env) {
- static const EphemeralSecKeychain temporaryKeychain;
- if (temporaryKeychain.keychain) {
- nKeys = 2;
- keys[1] = kSecImportExportKeychain;
- values[1] = temporaryKeychain.keychain;
- }
- }
-#endif
- QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
- nullptr, nullptr);
- QCFType<CFArrayRef> items;
- OSStatus err = SecPKCS12Import(pkcs12, options, &items);
- if (err != errSecSuccess) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket
- << QStringLiteral("SecPKCS12Import failed: %1").arg(err);
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import failed: %1").arg(err);
- return false;
- }
-
- if (!CFArrayGetCount(items)) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket << "SecPKCS12Import returned no items";
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import returned no items");
- return false;
- }
-
- CFDictionaryRef import = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
- SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(import, kSecImportItemIdentity);
- if (!identity) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend) << plainSocket << "SecPKCS12Import returned no identity";
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("SecPKCS12Import returned no identity");
- return false;
- }
-
- QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
- if (!certs) {
- errorCode = QAbstractSocket::SslInternalError;
- errorDescription = QStringLiteral("Failed to allocate certificates array");
- return false;
- }
-
- CFArrayAppendValue(certs, identity);
-
- CFArrayRef chain = (CFArrayRef)CFDictionaryGetValue(import, kSecImportItemCertChain);
- if (chain) {
- for (CFIndex i = 1, e = CFArrayGetCount(chain); i < e; ++i)
- CFArrayAppendValue(certs, CFArrayGetValueAtIndex(chain, i));
- }
-
- err = SSLSetCertificate(context, certs);
- if (err != errSecSuccess) {
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcTlsBackend)
- << plainSocket << QStringLiteral("Cannot set certificate and key: %1").arg(err);
-#endif
- errorCode = QAbstractSocket::SslInvalidUserDataError;
- errorDescription = QStringLiteral("Cannot set certificate and key: %1").arg(err);
- return false;
- }
- }
-
- return true;
-}
-
-bool TlsCryptographSecureTransport::setSessionProtocol()
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- Q_ASSERT(q);
- Q_ASSERT(d);
- // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
- // Calling SSLSetProtocolVersionMax/Min with any of these two constants results
- // in errInvalidParam and a failure to set the protocol version. This means
- // no TLS 1.3 on macOS and iOS.
- const auto &configuration = q->sslConfiguration();
- auto *plainSocket = d->plainTcpSocket();
- switch (configuration.protocol()) {
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
- qCWarning(lcTlsBackend) << plainSocket << "SecureTransport does not support TLS 1.3";
- return false;
- default:;
- }
-
- OSStatus err = errSecSuccess;
-
- if (configuration.protocol() == QSsl::TlsV1_0) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.0";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
- } else if (configuration.protocol() == QSsl::TlsV1_1) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
- } else if (configuration.protocol() == QSsl::TlsV1_2) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == errSecSuccess)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol() == QSsl::AnyProtocol) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : any";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol() == QSsl::SecureProtocols) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- } else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- } else {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "no protocol version found in the configuration";
- #endif
- return false;
- }
-
- return err == errSecSuccess;
-}
-
-bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
- const auto &configuration = q->sslConfiguration();
- const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
- return d->tlsMode() == QSslSocket::SslServerMode
- && (verifyMode == QSslSocket::QueryPeer
- || verifyMode == QSslSocket::AutoVerifyPeer
- || verifyMode == QSslSocket::VerifyNone);
-}
-
-bool TlsCryptographSecureTransport::verifySessionProtocol() const
-{
- Q_ASSERT(q);
-
- const auto &configuration = q->sslConfiguration();
- bool protocolOk = false;
- if (configuration.protocol() == QSsl::AnyProtocol)
- protocolOk = true;
- else if (configuration.protocol() == QSsl::SecureProtocols)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
- else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
- else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
- else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
- else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
- protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
- else
- protocolOk = (sessionProtocol() == configuration.protocol());
-
- return protocolOk;
-}
-
-bool TlsCryptographSecureTransport::verifyPeerTrust()
-{
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- const auto mode = d->tlsMode();
- const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
- const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
-
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
-
- QCFType<SecTrustRef> trust;
- OSStatus err = SSLCopyPeerTrust(context, &trust);
- // !trust - SSLCopyPeerTrust can return errSecSuccess but null trust.
- if (err != errSecSuccess || !trust) {
- if (!canIgnoreVerify) {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("Failed to obtain peer trust: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- } else {
- return true;
- }
- }
-
- QList<QSslError> errors;
-
- // Store certificates.
- // Apple's docs say SetTrustEvaluate must be called before
- // SecTrustGetCertificateAtIndex, but this results
- // in 'kSecTrustResultRecoverableTrustFailure', so
- // here we just ignore 'res' (later we'll use SetAnchor etc.
- // and evaluate again).
- SecTrustResultType res = kSecTrustResultInvalid;
- err = SecTrustEvaluate(trust, &res);
- if (err != errSecSuccess) {
- // We can not ignore this, it's not even about trust verification
- // probably ...
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- QTlsBackend::clearPeerCertificates(d);
-
- QList<QSslCertificate> peerCertificateChain;
- const CFIndex certCount = SecTrustGetCertificateCount(trust);
- for (CFIndex i = 0; i < certCount; ++i) {
- SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
- QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
- peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
- QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
-
- if (peerCertificateChain.size())
- QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
-
- // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
- for (const QSslCertificate &cert : qAsConst(peerCertificateChain)) {
- if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
- const QSslError error(QSslError::CertificateBlacklisted, cert);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- const bool doVerifyPeer = verifyMode == QSslSocket::VerifyPeer
- || (verifyMode == QSslSocket::AutoVerifyPeer
- && d->tlsMode() == QSslSocket::SslClientMode);
- // Check the peer certificate itself. First try the subject's common name
- // (CN) as a wildcard, then try all alternate subject name DNS entries the
- // same way.
- const auto &peerCertificate = q->peerCertificate();
- if (!peerCertificate.isNull()) {
- // but only if we're a client connecting to a server
- // if we're the server, don't check CN
- const QString verificationPeerName = d->verificationName();
- if (mode == QSslSocket::SslClientMode) {
- const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
- if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
- // No matches in common names or alternate names.
- const QSslError error(QSslError::HostNameMismatch, peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
- } else {
- // No peer certificate presented. Report as error if the socket
- // expected one.
- if (doVerifyPeer && !canIgnoreVerify) {
- const QSslError error(QSslError::NoPeerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- if (q->state() != QAbstractSocket::ConnectedState)
- return false;
- }
- }
-
- // verify certificate chain
- QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
- const auto &caCertificates = q->sslConfiguration().caCertificates();
- for (const QSslCertificate &cert : caCertificates) {
- QCFType<CFDataRef> certData = cert.toDer().toCFData();
- if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
- CFArrayAppendValue(certArray, secRef);
- else
- qCWarning(lcTlsBackend, "Failed to create SecCertificate from QSslCertificate");
- }
-
- SecTrustSetAnchorCertificates(trust, certArray);
-
- // By default SecTrustEvaluate uses both CA certificates provided in
- // QSslConfiguration and the ones from the system database. This behavior can
- // be unexpected if a user's code tries to limit the trusted CAs to those
- // explicitly set in QSslConfiguration.
- // Since on macOS we initialize the default QSslConfiguration copying the
- // system CA certificates (using SecTrustSettingsCopyCertificates) we can
- // call SecTrustSetAnchorCertificatesOnly(trust, true) to force SecTrustEvaluate
- // to use anchors only from our QSslConfiguration.
- // Unfortunately, SecTrustSettingsCopyCertificates is not available on iOS
- // and the default QSslConfiguration always has an empty list of system CA
- // certificates. This leaves no way to provide client code with access to the
- // actual system CA certificate list (which most use-cases need) other than
- // by letting SecTrustEvaluate fall through to the system list; so, in this case
- // (even though the client code may have provided its own certs), we retain
- // the default behavior. Note, with macOS SDK below 10.12 using 'trust my
- // anchors only' may result in some valid chains rejected, apparently the
- // ones containing intermediated certificates; so we use this functionality
- // on more recent versions only.
-
- bool anchorsFromConfigurationOnly = false;
-
-#ifdef Q_OS_MACOS
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra)
- anchorsFromConfigurationOnly = true;
-#endif // Q_OS_MACOS
-
- SecTrustSetAnchorCertificatesOnly(trust, anchorsFromConfigurationOnly);
-
- SecTrustResultType trustResult = kSecTrustResultInvalid;
- SecTrustEvaluate(trust, &trustResult);
- switch (trustResult) {
- case kSecTrustResultUnspecified:
- case kSecTrustResultProceed:
- break;
- default:
- if (!canIgnoreVerify) {
- const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
- errors << error;
- emit q->peerVerifyError(error);
- }
- }
-
- // report errors
- if (!errors.isEmpty() && !canIgnoreVerify) {
- sslErrors = errors;
- // checkSslErrors unconditionally emits sslErrors:
- // a user's slot can abort/close/disconnect on this
- // signal, so we also test the socket's state:
- if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState)
- return false;
- } else {
- sslErrors.clear();
- }
-
- return true;
-}
-
-/*
- Copied verbatim from qsslsocket_openssl.cpp
-*/
-bool TlsCryptographSecureTransport::checkSslErrors()
-{
- if (sslErrors.isEmpty())
- return true;
-
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- emit q->sslErrors(sslErrors);
- const auto mode = d->tlsMode();
- const auto &configuration = q->sslConfiguration();
- const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- QSslSocketPrivate::pauseSocketNotifiers(q);
- d->setPaused(true);
- } else {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- Q_ASSERT(d->plainTcpSocket());
- d->plainTcpSocket()->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-bool TlsCryptographSecureTransport::startHandshake()
-{
- Q_ASSERT(context);
- Q_ASSERT(q);
- Q_ASSERT(d);
-
- auto *plainSocket = d->plainTcpSocket();
- Q_ASSERT(plainSocket);
- const auto mode = d->tlsMode();
-
- OSStatus err = SSLHandshake(context);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << plainSocket << "SSLHandhake returned" << err;
-#endif
-
- if (err == errSSLWouldBlock) {
- // startHandshake has to be called again ... later.
- return false;
- } else if (err == errSSLServerAuthCompleted) {
- // errSSLServerAuthCompleted is a define for errSSLPeerAuthCompleted,
- // it works for both server/client modes.
- // In future we'll evaluate peer's trust at this point,
- // for now we just continue.
- // if (!verifyPeerTrust())
- // ...
- return startHandshake();
- } else if (err == errSSLClientCertRequested) {
- Q_ASSERT(mode == QSslSocket::SslClientMode);
- QString errorDescription;
- QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
- // setSessionCertificate does not fail if we have no certificate.
- // Failure means a real error (invalid certificate, no private key, etc).
- if (!setSessionCertificate(errorDescription, errorCode)) {
- d->setErrorAndEmit(errorCode, errorDescription);
- renegotiating = false;
- return false;
- } else {
- // We try to resume a handshake, even if have no
- // local certificates ... (up to server to deal with our failure).
- return startHandshake();
- }
- } else if (err != errSecSuccess) {
- if (err == errSSLBadCert && canIgnoreTrustVerificationFailure()) {
- // We're on the server side and client did not provide any
- // certificate. This is the new 'nice' error returned by
- // Security Framework after it was recently updated.
- return startHandshake();
- }
-
- renegotiating = false;
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SSLHandshake failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- // Connection aborted during handshake phase.
- if (q->state() != QAbstractSocket::ConnectedState) {
- qCDebug(lcTlsBackend) << "connection aborted";
- renegotiating = false;
- return false;
- }
-
- // check protocol version ourselves, as Secure Transport does not enforce
- // the requested min / max versions.
- if (!verifySessionProtocol()) {
- d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
- plainSocket->disconnectFromHost();
- renegotiating = false;
- return false;
- }
-
- if (verifyPeerTrust()) {
- continueHandshake();
- renegotiating = false;
- return true;
- } else {
- renegotiating = false;
- return false;
- }
-}
-
-bool TlsCryptographSecureTransport::isHandshakeComplete() const
-{
- Q_ASSERT(q);
- return q->isEncrypted() && !renegotiating;
-}
-
-QList<QSslError> TlsCryptographSecureTransport::tlsErrors() const
-{
- return sslErrors;
-}
-
-} // namespace QTlsPrivate
-
-void QSslSocketPrivate::registerAdHocFactory()
-{
- // TLSTODO: this is a temporary solution, waiting for
- // backends to move to ... plugins.
- if (!backendSecureTransport())
- qCWarning(lcTlsBackend, "Failed to create backend factory");
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtls_st_p.h b/src/network/ssl/qtls_st_p.h
deleted file mode 100644
index 42c0ad622f..0000000000
--- a/src/network/ssl/qtls_st_p.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QTLS_ST_P_H
-#define QTLS_ST_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the QtNetwork library. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include "qtlsbackend_st_p.h"
-
-#include <QtCore/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-
-#include "qabstractsocket.h"
-#include "qsslsocket_p.h"
-
-#include <Security/Security.h>
-#include <Security/SecureTransport.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class QSecureTransportContext
-{
-public:
- explicit QSecureTransportContext(SSLContextRef context);
- ~QSecureTransportContext();
-
- operator SSLContextRef () const;
- void reset(SSLContextRef newContext);
-private:
- SSLContextRef context;
-
- Q_DISABLE_COPY_MOVE(QSecureTransportContext)
-};
-
-class TlsCryptographSecureTransport : public TlsCryptograph
-{
-public:
- TlsCryptographSecureTransport();
- ~TlsCryptographSecureTransport() override;
-
- void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
- void continueHandshake() override;
- void disconnected() override;
- void disconnectFromHost() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
- QList<QSslError> tlsErrors() const override;
-
- SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph);
-
-private:
- // SSL context management/properties:
- bool initSslContext();
- void destroySslContext();
- bool setSessionCertificate(QString &errorDescription,
- QAbstractSocket::SocketError &errorCode);
- bool setSessionProtocol();
- // Aux. functions to do a verification during handshake phase:
- bool canIgnoreTrustVerificationFailure() const;
- bool verifySessionProtocol() const;
- bool verifyPeerTrust();
-
- bool checkSslErrors();
- bool startHandshake();
-
- bool isHandshakeComplete() const;
-
- // IO callbacks:
- static OSStatus ReadCallback(TlsCryptographSecureTransport *socket, char *data, size_t *dataLength);
- static OSStatus WriteCallback(TlsCryptographSecureTransport *plainSocket, const char *data, size_t *dataLength);
-
- QSecureTransportContext context;
- bool renegotiating = false;
- QSslSocket *q = nullptr;
- QSslSocketPrivate *d = nullptr;
- bool shutdown = false;
- QList<QSslError> sslErrors;
-
- Q_DISABLE_COPY_MOVE(TlsCryptographSecureTransport)
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLS_ST_P_H
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
index 079cbccbc0..4c412d436f 100644
--- a/src/network/ssl/qtlsbackend.cpp
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -46,8 +46,6 @@
#include "qsslcipher_p.h"
#include "qsslkey_p.h"
#include "qsslkey.h"
-#else
-#include "qtlsbackend_cert_p.h"
#endif
#include "qssl_p.h"
@@ -63,7 +61,7 @@
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QTlsBackend_iid, QStringLiteral("/tlsbackends")))
+ (QTlsBackend_iid, QStringLiteral("/tls")))
namespace {
@@ -104,14 +102,6 @@ public:
while (loader->instance(index))
++index;
- // TLSTODO: obviously, these two below should
- // disappear as soon as plugins are in place.
-#if QT_CONFIG(ssl)
- QSslSocketPrivate::registerAdHocFactory();
-#else
- static QTlsBackendCertOnly certGenerator;
-#endif // QT_CONFIG(ssl)
-
return loaded = true;
}
@@ -244,6 +234,13 @@ bool TlsCryptograph::isMatchingHostname(const QString &cn, const QString &hostna
return QSslSocketPrivate::isMatchingHostname(cn, hostname);
}
+void TlsCryptograph::setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const
+{
+ Q_ASSERT(d);
+ d->setErrorAndEmit(errorCode, errorDescription);
+}
+
#endif // QT_CONFIG(ssl)
#if QT_CONFIG(dtls)
@@ -255,7 +252,8 @@ DtlsBase::~DtlsBase() = default;
const QString QTlsBackend::builtinBackendNames[] = {
QStringLiteral("schannel"),
QStringLiteral("securetransport"),
- QStringLiteral("openssl")
+ QStringLiteral("openssl"),
+ QStringLiteral("cert-only")
};
QTlsBackend::QTlsBackend()
@@ -436,18 +434,25 @@ QList<QString> QTlsBackend::availableBackendNames()
QString QTlsBackend::defaultBackendName()
{
- // We prefer native as default:
+ // We prefer OpenSSL as default:
const auto names = availableBackendNames();
- auto name = builtinBackendNames[nameIndexSchannel];
+ auto name = builtinBackendNames[nameIndexOpenSSL];
if (names.contains(name))
return name;
- name = builtinBackendNames[nameIndexSecureTransport];
+ name = builtinBackendNames[nameIndexSchannel];
if (names.contains(name))
return name;
- name = builtinBackendNames[nameIndexOpenSSL];
+ name = builtinBackendNames[nameIndexSecureTransport];
if (names.contains(name))
return name;
+ const auto pos = std::find_if(names.begin(), names.end(), [](const auto &name) {
+ return name != builtinBackendNames[nameIndexCertOnly];
+ });
+
+ if (pos != names.end())
+ return *pos;
+
if (names.size())
return names[0];
@@ -787,6 +792,16 @@ void QTlsBackend::setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key)
d->configuration.ephemeralServerKey = key;
}
+void QTlsBackend::forceAutotestSecurityLevel()
+{
+}
+
+Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
+{
+ if (auto *backend = QSslSocketPrivate::tlsBackendInUse())
+ backend->forceAutotestSecurityLevel();
+}
+
#endif // QT_CONFIG(ssl)
QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlsbackend_cert.cpp b/src/network/ssl/qtlsbackend_cert.cpp
deleted file mode 100644
index f541381ecb..0000000000
--- a/src/network/ssl/qtlsbackend_cert.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlsbackend_cert_p.h"
-
-#ifdef QT_NO_SSL
-
-#include "qx509_generic_p.h"
-
-#include <qssl.h>
-
-#include <qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.cert-only");
-
-QString QTlsBackendCertOnly::backendName() const
-{
- return QStringLiteral("cert-only");
-}
-
-
-QList<QSsl::SslProtocol> QTlsBackendCertOnly::supportedProtocols() const
-{
- return {};
-}
-
-QList<QSsl::SupportedFeature> QTlsBackendCertOnly::supportedFeatures() const
-{
- return {};
-}
-
-QList<QSsl::ImplementedClass> QTlsBackendCertOnly::implementedClasses() const
-{
- QList<QSsl::ImplementedClass> classes;
- classes << QSsl::ImplementedClass::Certificate;
-
- return classes;
-}
-
-QTlsPrivate::X509Certificate *QTlsBackendCertOnly::createCertificate() const
-{
- return new QTlsPrivate::X509CertificateGeneric;
-}
-
-QTlsPrivate::X509PemReaderPtr QTlsBackendCertOnly::X509PemReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
-}
-
-QTlsPrivate::X509DerReaderPtr QTlsBackendCertOnly::X509DerReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_SSL
-
diff --git a/src/network/ssl/qtlsbackend_cert_p.h b/src/network/ssl/qtlsbackend_cert_p.h
deleted file mode 100644
index 4a010dbf79..0000000000
--- a/src/network/ssl/qtlsbackend_cert_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSBACKEND_CERT_P_H
-#define QTLSBACKEND_CERT_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qtlsbackend_p.h"
-
-#include <QtCore/qglobal.h>
-
-#ifdef QT_NO_SSL
-
-QT_BEGIN_NAMESPACE
-
-class QTlsBackendCertOnly final : public QTlsBackend
-{
-public:
-private:
- QString backendName() const override;
-
- QList<QSsl::SslProtocol> supportedProtocols() const override;
- QList<QSsl::SupportedFeature> supportedFeatures() const override;
- QList<QSsl::ImplementedClass> implementedClasses() const override;
-
- QTlsPrivate::X509Certificate *createCertificate() const override;
- QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
- QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_SSL
-
-#endif // QTLSBACKEND_CERT_P_H
diff --git a/src/network/ssl/qtlsbackend_openssl.cpp b/src/network/ssl/qtlsbackend_openssl.cpp
deleted file mode 100644
index ef4aab6283..0000000000
--- a/src/network/ssl/qtlsbackend_openssl.cpp
+++ /dev/null
@@ -1,630 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlsbackend_openssl_p.h"
-#include "qtlskey_openssl_p.h"
-#include "qx509_openssl_p.h"
-#include "qtls_openssl_p.h"
-#include "qsslcipher_p.h"
-//#include "qsslsocket_p.h"
-#include "qsslcipher.h"
-
-#if QT_CONFIG(dtls)
-#include "qdtls_openssl_p.h"
-#endif // QT_CONFIG(dtls)
-
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qopenssl_p.h"
-
-#include <qssl.h>
-
-#include <qdir.h>
-#include <qdiriterator.h>
-#include <qlist.h>
-#include <qmutex.h>
-#include <qscopeguard.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
-
-static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
- QList<QSslCipher> &defaultCiphers)
-{
- Q_ASSERT(connection);
-
- STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
- for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
- if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
- const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
- if (!ciph.isNull()) {
- // Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
- if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
- !ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
- ciphers << ciph;
-
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
- }
- }
-}
-
-bool QTlsBackendOpenSSL::s_libraryLoaded = false;
-bool QTlsBackendOpenSSL::s_loadedCiphersAndCerts = false;
-int QTlsBackendOpenSSL::s_indexForSSLExtraData = -1;
-
-QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
-{
- QString errorString;
- char buf[256] = {}; // OpenSSL docs claim both 120 and 256; use the larger.
- unsigned long errNum;
- while ((errNum = q_ERR_get_error())) {
- if (!errorString.isEmpty())
- errorString.append(QLatin1String(", "));
- q_ERR_error_string_n(errNum, buf, sizeof buf);
- errorString.append(QString::fromLatin1(buf)); // error is ascii according to man ERR_error_string
- }
- return errorString;
-}
-
-void QTlsBackendOpenSSL::logAndClearErrorQueue()
-{
- const auto errors = getErrorsFromOpenSsl();
- if (errors.size())
- qCWarning(lcTlsBackend) << "Discarding errors:" << errors;
-}
-
-void QTlsBackendOpenSSL::clearErrorQueue()
-{
- const auto errs = getErrorsFromOpenSsl();
- Q_UNUSED(errs);
-}
-
-bool QTlsBackendOpenSSL::ensureLibraryLoaded()
-{
- if (!q_resolveOpenSslSymbols())
- return false;
-
- const QMutexLocker locker(qt_opensslInitMutex());
-
- if (!s_libraryLoaded) {
- // Initialize OpenSSL.
- if (q_OPENSSL_init_ssl(0, nullptr) != 1)
- return false;
-
- if (q_OpenSSL_version_num() < 0x10101000L) {
- qCWarning(lcTlsBackend, "QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead", q_OpenSSL_version(OPENSSL_VERSION));
- return false;
- }
-
- q_SSL_load_error_strings();
- q_OpenSSL_add_all_algorithms();
-
- s_indexForSSLExtraData = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr,
- nullptr, nullptr);
-
- // Initialize OpenSSL's random seed.
- if (!q_RAND_status()) {
- qWarning("Random number generator not seeded, disabling SSL support");
- return false;
- }
-
- s_libraryLoaded = true;
- }
-
- return true;
-}
-
-QString QTlsBackendOpenSSL::backendName() const
-{
- return builtinBackendNames[nameIndexOpenSSL];
-}
-
-bool QTlsBackendOpenSSL::isValid() const
-{
- return ensureLibraryLoaded();
-}
-
-long QTlsBackendOpenSSL::tlsLibraryVersionNumber() const
-{
- return q_OpenSSL_version_num();
-}
-
-QString QTlsBackendOpenSSL::tlsLibraryVersionString() const
-{
- const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
- if (!versionString)
- return QString();
-
- return QString::fromLatin1(versionString);
-}
-
-long QTlsBackendOpenSSL::tlsLibraryBuildVersionNumber() const
-{
- return OPENSSL_VERSION_NUMBER;
-}
-
-QString QTlsBackendOpenSSL::tlsLibraryBuildVersionString() const
-{
- // Using QStringLiteral to store the version string as unicode and
- // avoid false positives from Google searching the playstore for old
- // SSL versions. See QTBUG-46265
- return QStringLiteral(OPENSSL_VERSION_TEXT);
-}
-
-void QTlsBackendOpenSSL::ensureInitialized() const
-{
- // Old qsslsocket_openssl calls supportsSsl() (which means
- // library found and symbols resolved, this already assured
- // by the fact we end up in this function (isValid() returned
- // true for the backend, see its code). The qsslsocket_openssl
- // proceedes with loading certificate, ciphers and elliptic
- // curves.
- ensureCiphersAndCertsLoaded();
-}
-
-void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
-{
- const QMutexLocker locker(qt_opensslInitMutex());
-
- if (s_loadedCiphersAndCerts)
- return;
- s_loadedCiphersAndCerts = true;
-
- resetDefaultCiphers();
- resetDefaultEllipticCurves();
-
-#if QT_CONFIG(library)
- //load symbols needed to receive certificates from system store
-#if defined(Q_OS_QNX)
- QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
-#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
- // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
- QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
- QStringList symLinkFilter;
- symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
- for (int a = 0; a < dirs.count(); ++a) {
- QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
- if (iterator.hasNext()) {
- QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
- break;
- }
- }
-#endif
-#endif // QT_CONFIG(library)
- // if on-demand loading was not enabled, load the certs now
- if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
- setDefaultCaCertificates(systemCaCertificates());
-#ifdef Q_OS_WIN
- //Enabled for fetching additional root certs from windows update on windows.
- //This flag is set false by setDefaultCaCertificates() indicating the app uses
- //its own cert bundle rather than the system one.
- //Same logic that disables the unix on demand cert loading.
- //Unlike unix, we do preload the certificates from the cert store.
- QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
-#endif
-}
-
-void QTlsBackendOpenSSL::resetDefaultCiphers()
-{
- SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method());
- // Note, we assert, not just silently return/bail out early:
- // this should never happen and problems with OpenSSL's initialization
- // must be caught before this (see supportsSsl()).
- Q_ASSERT(myCtx);
- SSL *mySsl = q_SSL_new(myCtx);
- Q_ASSERT(mySsl);
-
- QList<QSslCipher> ciphers;
- QList<QSslCipher> defaultCiphers;
-
- q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
-
- q_SSL_CTX_free(myCtx);
- q_SSL_free(mySsl);
-
- setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(defaultCiphers);
-
-#if QT_CONFIG(dtls)
- ciphers.clear();
- defaultCiphers.clear();
- myCtx = q_SSL_CTX_new(q_DTLS_client_method());
- if (myCtx) {
- mySsl = q_SSL_new(myCtx);
- if (mySsl) {
- q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
- setDefaultDtlsCiphers(defaultCiphers);
- q_SSL_free(mySsl);
- }
- q_SSL_CTX_free(myCtx);
- }
-#endif // dtls
-}
-
-QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
-{
- QList<QSsl::SslProtocol> protocols;
-
- protocols << QSsl::AnyProtocol;
- protocols << QSsl::SecureProtocols;
- protocols << QSsl::TlsV1_0;
- protocols << QSsl::TlsV1_0OrLater;
- protocols << QSsl::TlsV1_1;
- protocols << QSsl::TlsV1_1OrLater;
- protocols << QSsl::TlsV1_2;
- protocols << QSsl::TlsV1_2OrLater;
-
-#ifdef TLS1_3_VERSION
- protocols << QSsl::TlsV1_3;
- protocols << QSsl::TlsV1_3OrLater;
-#endif // TLS1_3_VERSION
-
-#if QT_CONFIG(dtls)
- protocols << QSsl::DtlsV1_0;
- protocols << QSsl::DtlsV1_0OrLater;
- protocols << QSsl::DtlsV1_2;
- protocols << QSsl::DtlsV1_2OrLater;
-#endif // dtls
-
- return protocols;
-}
-
-QList<QSsl::SupportedFeature> QTlsBackendOpenSSL::supportedFeatures() const
-{
- QList<QSsl::SupportedFeature> features;
-
- features << QSsl::SupportedFeature::CertificateVerification;
- features << QSsl::SupportedFeature::ClientSideAlpn;
- features << QSsl::SupportedFeature::ServerSideAlpn;
- features << QSsl::SupportedFeature::Ocsp;
- features << QSsl::SupportedFeature::Psk;
- features << QSsl::SupportedFeature::SessionTicket;
- features << QSsl::SupportedFeature::Alerts;
-
- return features;
-}
-
-QList<QSsl::ImplementedClass> QTlsBackendOpenSSL::implementedClasses() const
-{
- QList<QSsl::ImplementedClass> classes;
-
- classes << QSsl::ImplementedClass::Key;
- classes << QSsl::ImplementedClass::Certificate;
- classes << QSsl::ImplementedClass::Socket;
- classes << QSsl::ImplementedClass::Dtls;
- classes << QSsl::ImplementedClass::EllipticCurve;
- classes << QSsl::ImplementedClass::DiffieHellman;
-
- return classes;
-}
-
-QTlsPrivate::TlsKey *QTlsBackendOpenSSL::createKey() const
-{
- return new QTlsPrivate::TlsKeyOpenSSL;
-}
-
-QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
-{
- return new QTlsPrivate::X509CertificateOpenSSL;
-}
-
-namespace QTlsPrivate {
-
-// TLSTODO: remove.
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-QList<QByteArray> fetchSslCertificateData();
-#endif
-
-QList<QSslCertificate> systemCaCertificates();
-
-#ifndef Q_OS_DARWIN
-QList<QSslCertificate> systemCaCertificates()
-{
-#ifdef QSSLSOCKET_DEBUG
- QElapsedTimer timer;
- timer.start();
-#endif
- QList<QSslCertificate> systemCerts;
-#if defined(Q_OS_WIN)
- HCERTSTORE hSystemStore;
- hSystemStore = CertOpenSystemStoreW(0, L"ROOT");
- if (hSystemStore) {
- PCCERT_CONTEXT pc = nullptr;
- while (1) {
- pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
- if (!pc)
- break;
- QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
- static_cast<int>(pc->cbCertEncoded));
- QSslCertificate cert(der, QSsl::Der);
- systemCerts.append(cert);
- }
- CertCloseStore(hSystemStore, 0);
- }
-#elif defined(Q_OS_UNIX)
- QSet<QString> certFiles;
- QDir currentDir;
- QStringList nameFilters;
- QList<QByteArray> directories;
- QSsl::EncodingFormat platformEncodingFormat;
-# ifndef Q_OS_ANDROID
- directories = QSslSocketPrivate::unixRootCertDirectories();
- nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
- platformEncodingFormat = QSsl::Pem;
-# else
- // Q_OS_ANDROID
- QByteArray ministroPath = qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
- directories << ministroPath;
- nameFilters << QLatin1String("*.der");
- platformEncodingFormat = QSsl::Der;
-# ifndef Q_OS_ANDROID_EMBEDDED
- if (ministroPath.isEmpty()) {
- QList<QByteArray> certificateData = fetchSslCertificateData();
- for (int i = 0; i < certificateData.size(); ++i) {
- systemCerts.append(QSslCertificate::fromData(certificateData.at(i), QSsl::Der));
- }
- } else
-# endif //Q_OS_ANDROID_EMBEDDED
-# endif //Q_OS_ANDROID
- {
- currentDir.setNameFilters(nameFilters);
- for (int a = 0; a < directories.count(); a++) {
- currentDir.setPath(QLatin1String(directories.at(a)));
- QDirIterator it(currentDir);
- while (it.hasNext()) {
- it.next();
- // use canonical path here to not load the same certificate twice if symlinked
- certFiles.insert(it.fileInfo().canonicalFilePath());
- }
- }
- for (const QString& file : qAsConst(certFiles))
- systemCerts.append(QSslCertificate::fromPath(file, platformEncodingFormat));
-# ifndef Q_OS_ANDROID
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
- systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
-# endif
- }
-#endif
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcTlsBackend) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
- qCDebug(lcTlsBackend) << "imported " << systemCerts.count() << " certificates";
-#endif
-
- return systemCerts;
-}
-#endif // !Q_OS_DARWIN
-} // namespace QTlsPrivate
-
-QList<QSslCertificate> QTlsBackendOpenSSL::systemCaCertificates() const
-{
- return QTlsPrivate::systemCaCertificates();
-}
-
-QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
-{
-#if QT_CONFIG(dtls)
- return new QDtlsClientVerifierOpenSSL;
-#else
- qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot verify DTLS cookies");
- return nullptr;
-#endif // QT_CONFIG(dtls)
-}
-
-QTlsPrivate::TlsCryptograph *QTlsBackendOpenSSL::createTlsCryptograph() const
-{
- return new QTlsPrivate::TlsCryptographOpenSSL;
-}
-
-QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
-{
-#if QT_CONFIG(dtls)
- return new QDtlsPrivateOpenSSL(q, QSslSocket::SslMode(mode));
-#else
- Q_UNUSED(q);
- Q_UNUSED(mode);
- qCWarning(lcTlsBackend, "Feature 'dtls' is disabled, cannot encrypt UDP datagrams");
- return nullptr;
-#endif // QT_CONFIG(dtls)
-}
-
-QTlsPrivate::X509ChainVerifyPtr QTlsBackendOpenSSL::X509Verifier() const
-{
- return QTlsPrivate::X509CertificateOpenSSL::verify;
-}
-
-QTlsPrivate::X509PemReaderPtr QTlsBackendOpenSSL::X509PemReader() const
-{
- return QTlsPrivate::X509CertificateOpenSSL::certificatesFromPem;
-}
-
-QTlsPrivate::X509DerReaderPtr QTlsBackendOpenSSL::X509DerReader() const
-{
- return QTlsPrivate::X509CertificateOpenSSL::certificatesFromDer;
-}
-
-QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackendOpenSSL::X509Pkcs12Reader() const
-{
- return QTlsPrivate::X509CertificateOpenSSL::importPkcs12;
-}
-
-QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
-{
- QList<int> ids;
-
-#ifndef OPENSSL_NO_EC
- const size_t curveCount = q_EC_get_builtin_curves(nullptr, 0);
- QVarLengthArray<EC_builtin_curve> builtinCurves(static_cast<int>(curveCount));
-
- if (q_EC_get_builtin_curves(builtinCurves.data(), curveCount) == curveCount) {
- ids.reserve(curveCount);
- for (const auto &ec : builtinCurves)
- ids.push_back(ec.nid);
- }
-#endif // OPENSSL_NO_EC
-
- return ids;
-}
-
- int QTlsBackendOpenSSL::curveIdFromShortName(const QString &name) const
- {
- int nid = 0;
- if (name.isEmpty())
- return nid;
-
- ensureInitialized(); // TLSTODO: check if it's needed!
-#ifndef OPENSSL_NO_EC
- const QByteArray curveNameLatin1 = name.toLatin1();
- nid = q_OBJ_sn2nid(curveNameLatin1.data());
-
- if (nid == 0)
- nid = q_EC_curve_nist2nid(curveNameLatin1.data());
-#endif // !OPENSSL_NO_EC
-
- return nid;
- }
-
- int QTlsBackendOpenSSL::curveIdFromLongName(const QString &name) const
- {
- int nid = 0;
- if (name.isEmpty())
- return nid;
-
- ensureInitialized();
-
-#ifndef OPENSSL_NO_EC
- const QByteArray curveNameLatin1 = name.toLatin1();
- nid = q_OBJ_ln2nid(curveNameLatin1.data());
-#endif
-
- return nid;
- }
-
- QString QTlsBackendOpenSSL::shortNameForId(int id) const
- {
- QString result;
-
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2sn(id));
-#endif
-
- return result;
- }
-
-QString QTlsBackendOpenSSL::longNameForId(int id) const
-{
- QString result;
-
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2ln(id));
-#endif
-
- return result;
-}
-
-// NIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
-// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
-static const int tlsNamedCurveNIDs[] = {
- // RFC 4492
- NID_sect163k1,
- NID_sect163r1,
- NID_sect163r2,
- NID_sect193r1,
- NID_sect193r2,
- NID_sect233k1,
- NID_sect233r1,
- NID_sect239k1,
- NID_sect283k1,
- NID_sect283r1,
- NID_sect409k1,
- NID_sect409r1,
- NID_sect571k1,
- NID_sect571r1,
-
- NID_secp160k1,
- NID_secp160r1,
- NID_secp160r2,
- NID_secp192k1,
- NID_X9_62_prime192v1, // secp192r1
- NID_secp224k1,
- NID_secp224r1,
- NID_secp256k1,
- NID_X9_62_prime256v1, // secp256r1
- NID_secp384r1,
- NID_secp521r1,
-
- // RFC 7027
- NID_brainpoolP256r1,
- NID_brainpoolP384r1,
- NID_brainpoolP512r1
-};
-
-const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
-
-bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
-{
- const int *const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
- return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
-}
-
-QString QTlsBackendOpenSSL::msgErrorsDuringHandshake()
-{
- return QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
-}
-
-QSslCipher QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher)
-{
- Q_ASSERT(cipher);
- char buf [256] = {};
- const QString desc = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
- int supportedBits = 0;
- const int bits = q_SSL_CIPHER_get_bits(cipher, &supportedBits);
- return createCiphersuite(desc, bits, supportedBits);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlsbackend_openssl_p.h b/src/network/ssl/qtlsbackend_openssl_p.h
deleted file mode 100644
index 1a02bf5bed..0000000000
--- a/src/network/ssl/qtlsbackend_openssl_p.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSBACKEND_OPENSSL_P_H
-#define QTLSBACKEND_OPENSSL_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qssldiffiehellmanparameters.h"
-#include "qsslcertificate.h"
-#include "qtlsbackend_p.h"
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-
-#include <openssl/ssl.h>
-
-QT_BEGIN_NAMESPACE
-
-class QTlsBackendOpenSSL final : public QTlsBackend
-{
-public:
-
- static QString getErrorsFromOpenSsl();
- static void logAndClearErrorQueue();
- static void clearErrorQueue();
-
- static bool ensureLibraryLoaded();
- // Index used in SSL_get_ex_data to get the matching TlsCryptographerOpenSSL:
- static bool s_libraryLoaded;
- static bool s_loadedCiphersAndCerts;
- static int s_indexForSSLExtraData;
-
- static QString msgErrorsDuringHandshake();
- static QSslCipher qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher);
-private:
-
- QString backendName() const override;
- bool isValid() const override;
- long tlsLibraryVersionNumber() const override;
- QString tlsLibraryVersionString() const override;
- long tlsLibraryBuildVersionNumber() const override;
- QString tlsLibraryBuildVersionString() const override;
-
- void ensureInitialized() const override;
- void ensureCiphersAndCertsLoaded() const;
- static void resetDefaultCiphers();
-
- QList<QSsl::SslProtocol> supportedProtocols() const override;
- QList<QSsl::SupportedFeature> supportedFeatures() const override;
- QList<QSsl::ImplementedClass> implementedClasses() const override;
-
- // QSslKey:
- QTlsPrivate::TlsKey *createKey() const override;
-
- // QSslCertificate:
- QTlsPrivate::X509Certificate *createCertificate() const override;
- QList<QSslCertificate> systemCaCertificates() const override;
-
- QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
- QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
- QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
-
- QTlsPrivate::X509ChainVerifyPtr X509Verifier() const override;
- QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
- QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
- QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
-
- // Elliptic curves:
- QList<int> ellipticCurvesIds() const override;
- int curveIdFromShortName(const QString &name) const override;
- int curveIdFromLongName(const QString &name) const override;
- QString shortNameForId(int cid) const override;
- QString longNameForId(int cid) const override;
- bool isTlsNamedCurve(int cid) const override;
-
- // DH parameters:
- using DHParams = QSslDiffieHellmanParameters;
- int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const override;
- int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const override;
-};
-
-QT_END_NAMESPACE
-
-#endif // QTLSBACKEND_OPENSSL_P_H
-
-
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
index 4d2bc25300..1a6110b17b 100644
--- a/src/network/ssl/qtlsbackend_p.h
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -226,6 +226,9 @@ public:
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
static bool isMatchingHostname(const QString &cn, const QString &hostname);
+
+ void setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const;
};
#else
class TlsCryptograph;
@@ -371,6 +374,7 @@ public:
static constexpr const int nameIndexSchannel = 0;
static constexpr const int nameIndexSecureTransport = 1;
static constexpr const int nameIndexOpenSSL = 2;
+ static constexpr const int nameIndexCertOnly = 3;
static const QString builtinBackendNames[];
@@ -428,6 +432,8 @@ public:
static void addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert);
// The next one - is a "very important" feature! Kidding ...
static void setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key);
+
+ virtual void forceAutotestSecurityLevel();
#endif // QT_CONFIG(ssl)
Q_DISABLE_COPY_MOVE(QTlsBackend)
diff --git a/src/network/ssl/qtlsbackend_schannel_p.h b/src/network/ssl/qtlsbackend_schannel_p.h
deleted file mode 100644
index ca1cb9e621..0000000000
--- a/src/network/ssl/qtlsbackend_schannel_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSBACKEND_ST_P_H
-#define QTLSBACKEND_ST_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qtlsbackend_p.h"
-
-#include <QtCore/qglobal.h>
-
-
-QT_BEGIN_NAMESPACE
-
-class QSchannelBackend : public QTlsBackend
-{
-public:
- static void ensureInitializedImplementation();
-
-private:
- long tlsLibraryVersionNumber() const override;
- QString tlsLibraryVersionString() const override;
- long tlsLibraryBuildVersionNumber() const override;
- QString tlsLibraryBuildVersionString() const override;
- void ensureInitialized() const override;
-
- static void resetDefaultCiphers();
-
- QString backendName() const override;
- QList<QSsl::SslProtocol> supportedProtocols() const override;
- QList<QSsl::SupportedFeature> supportedFeatures() const override;
- QList<QSsl::ImplementedClass> implementedClasses() const override;
-
- QTlsPrivate::TlsKey *createKey() const override;
- QTlsPrivate::X509Certificate *createCertificate() const override;
-
- QTlsPrivate::TlsCryptograph * createTlsCryptograph() const override;
-
- QList<QSslCertificate> systemCaCertificates() const override;
- static QList<QSslCertificate> systemCaCertificatesImplementation();
-
- QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
- QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
-
- static bool s_loadedCiphersAndCerts;
-};
-
-QT_END_NAMESPACE
-
-#endif // QTLSBACKEND_ST_P_H
-
-
diff --git a/src/network/ssl/qtlsbackend_st.cpp b/src/network/ssl/qtlsbackend_st.cpp
deleted file mode 100644
index 7fc7692350..0000000000
--- a/src/network/ssl/qtlsbackend_st.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlsbackend_st_p.h"
-#include "qtlskey_st_p.h"
-#include "qx509_st_p.h"
-#include "qtls_st_p.h"
-
-#include <QtCore/qsysinfo.h>
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
-
-Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.securetransport");
-
-namespace QTlsPrivate {
-
-QList<QSslCertificate> systemCaCertificates(); // defined in qsslsocket_mac_shared.cpp
-
-SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode);
-
-QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
-{
- QString name;
- switch (cipher) {
- // Sorted as in CipherSuite.h (and groupped by their RFC)
- // TLS addenda using AES, per RFC 3268
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("AES128-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("DHE-RSA-AES128-SHA");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("AES256-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("DHE-RSA-AES256-SHA");
- break;
-
- // ECDSA addenda, RFC 4492
- case TLS_ECDH_ECDSA_WITH_NULL_SHA:
- name = QLatin1String("ECDH-ECDSA-NULL-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- name = QLatin1String("ECDH-ECDSA-RC4-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("ECDH-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("ECDH-ECDSA-AES128-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("ECDH-ECDSA-AES256-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
- break;
- case TLS_ECDH_RSA_WITH_NULL_SHA:
- name = QLatin1String("ECDH-RSA-NULL-SHA");
- break;
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- name = QLatin1String("ECDH-RSA-RC4-SHA");
- break;
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("ECDH-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("ECDH-RSA-AES128-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("ECDH-RSA-AES256-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- name = QLatin1String("ECDHE-RSA-NULL-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- name = QLatin1String("ECDHE-RSA-RC4-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- name = QLatin1String("ECDHE-RSA-AES128-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- name = QLatin1String("ECDHE-RSA-AES256-SHA");
- break;
-
- // TLS 1.2 addenda, RFC 5246
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("DES-CBC3-SHA");
- break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("AES128-SHA256");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- name = QLatin1String("AES256-SHA256");
- break;
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("DHE-RSA-AES128-SHA256");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- name = QLatin1String("DHE-RSA-AES256-SHA256");
- break;
-
- // Addendum from RFC 4279, TLS PSK
- // all missing atm.
-
- // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
- // all missing atm.
-
- // Addenda from rfc 5288 AES Galois Counter Mode (CGM) Cipher Suites for TLS
- case TLS_RSA_WITH_AES_256_GCM_SHA384:
- name = QLatin1String("AES256-GCM-SHA384");
- break;
-
- // RFC 5487 - PSK with SHA-256/384 and AES GCM
- // all missing atm.
-
- // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("ECDHE-RSA-AES128-SHA256");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- name = QLatin1String("ECDHE-RSA-AES256-SHA384");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- name = QLatin1String("ECDH-RSA-AES128-SHA256");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- name = QLatin1String("ECDH-RSA-AES256-SHA384");
- break;
-
- // Addenda from rfc 5289 Elliptic Curve Cipher Suites
- // with SHA-256/384 and AES Galois Counter Mode (GCM)
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384");
- break;
-
- default:
- return {};
- }
-
- return QTlsBackend::createCiphersuite(name, QSsl::TlsV1_2, QLatin1String("TLSv1.2"));
-}
-
-} // namespace QTlsPrivate
-
-bool QSecureTransportBackend::s_loadedCiphersAndCerts = false;
-
-QString QSecureTransportBackend::tlsLibraryVersionString() const
-{
- return QLatin1String("Secure Transport, ") + QSysInfo::prettyProductName();
-}
-
-QString QSecureTransportBackend::tlsLibraryBuildVersionString() const
-{
- return tlsLibraryVersionString();
-}
-
-void QSecureTransportBackend::ensureInitialized() const
-{
- const QMutexLocker locker(qt_securetransport_mutex());
- if (s_loadedCiphersAndCerts)
- return;
-
- // We have to set it before setDefaultSupportedCiphers,
- // since this function can trigger static (global)'s initialization
- // and as a result - recursive ensureInitialized call
- // from QSslCertificatePrivate's ctor.
- s_loadedCiphersAndCerts = true;
-
- const QTlsPrivate::QSecureTransportContext context(QTlsPrivate::qt_createSecureTransportContext(QSslSocket::SslClientMode));
- if (context) {
- QList<QSslCipher> ciphers;
- QList<QSslCipher> defaultCiphers;
-
- size_t numCiphers = 0;
- // Fails only if any of parameters is null.
- SSLGetNumberSupportedCiphers(context, &numCiphers);
- QList<SSLCipherSuite> cfCiphers(numCiphers);
- // Fails only if any of parameter is null or number of ciphers is wrong.
- SSLGetSupportedCiphers(context, cfCiphers.data(), &numCiphers);
-
- for (size_t i = 0; i < size_t(cfCiphers.size()); ++i) {
- const QSslCipher ciph(QTlsPrivate::QSslCipher_from_SSLCipherSuite(cfCiphers.at(i)));
- if (!ciph.isNull()) {
- ciphers << ciph;
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
-
- setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(defaultCiphers);
-
- if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
- setDefaultCaCertificates(systemCaCertificates());
- } else {
- s_loadedCiphersAndCerts = false;
- }
-}
-
-QString QSecureTransportBackend::backendName() const
-{
- return builtinBackendNames[nameIndexSecureTransport];
-}
-
-QTlsPrivate::TlsKey *QSecureTransportBackend::createKey() const
-{
- return new QTlsPrivate::TlsKeySecureTransport;
-}
-
-QTlsPrivate::X509Certificate *QSecureTransportBackend::createCertificate() const
-{
- return new QTlsPrivate::X509CertificateSecureTransport;
-}
-
-QList<QSslCertificate> QSecureTransportBackend::systemCaCertificates() const
-{
- return QTlsPrivate::systemCaCertificates();
-}
-
-QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
-{
- QList<QSsl::SslProtocol> protocols;
-
- protocols << QSsl::AnyProtocol;
- protocols << QSsl::SecureProtocols;
- protocols << QSsl::TlsV1_0;
- protocols << QSsl::TlsV1_0OrLater;
- protocols << QSsl::TlsV1_1;
- protocols << QSsl::TlsV1_1OrLater;
- protocols << QSsl::TlsV1_2;
- protocols << QSsl::TlsV1_2OrLater;
-
- return protocols;
-}
-
-QList<QSsl::SupportedFeature> QSecureTransportBackend::supportedFeatures() const
-{
- QList<QSsl::SupportedFeature> features;
- features << QSsl::SupportedFeature::ClientSideAlpn;
-
- return features;
-}
-
-QList<QSsl::ImplementedClass> QSecureTransportBackend::implementedClasses() const
-{
- QList<QSsl::ImplementedClass> classes;
- classes << QSsl::ImplementedClass::Socket;
- classes << QSsl::ImplementedClass::Certificate;
- classes << QSsl::ImplementedClass::Key;
-
- return classes;
-}
-
-QTlsPrivate::X509PemReaderPtr QSecureTransportBackend::X509PemReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
-}
-
-QTlsPrivate::X509DerReaderPtr QSecureTransportBackend::X509DerReader() const
-{
- return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
-}
-
-QTlsPrivate::TlsCryptograph *QSecureTransportBackend::createTlsCryptograph() const
-{
- return new QTlsPrivate::TlsCryptographSecureTransport;
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/network/ssl/qtlsbackend_st_p.h b/src/network/ssl/qtlsbackend_st_p.h
deleted file mode 100644
index b0f3050674..0000000000
--- a/src/network/ssl/qtlsbackend_st_p.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSBACKEND_ST_P_H
-#define QTLSBACKEND_ST_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qtlsbackend_p.h"
-
-#include <QtCore/qglobal.h>
-
-
-QT_BEGIN_NAMESPACE
-
-class QSecureTransportBackend : public QTlsBackend
-{
-private:
-
- QString tlsLibraryVersionString() const override;
- virtual QString tlsLibraryBuildVersionString() const override;
- virtual void ensureInitialized() const override;
-
- QString backendName() const override;
-
- QList<QSsl::SslProtocol> supportedProtocols() const override;
- QList<QSsl::SupportedFeature> supportedFeatures() const override;
- QList<QSsl::ImplementedClass> implementedClasses() const override;
-
- QTlsPrivate::TlsKey *createKey() const override;
- QTlsPrivate::X509Certificate *createCertificate() const override;
-
- QList<QSslCertificate> systemCaCertificates() const override;
-
- QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
- QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
-
- QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
-
- static bool s_loadedCiphersAndCerts;
-};
-
-QT_END_NAMESPACE
-
-#endif // QTLSBACKEND_ST_P_H
-
-
diff --git a/src/network/ssl/qtlskey_base.cpp b/src/network/ssl/qtlskey_base.cpp
deleted file mode 100644
index 13ce063f30..0000000000
--- a/src/network/ssl/qtlskey_base.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlskey_base_p.h"
-#include "qasn1element_p.h"
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-QByteArray TlsKeyBase::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
-{
- QByteArray pem(der.toBase64());
-
- const int lineWidth = 64; // RFC 1421
- const int newLines = pem.size() / lineWidth;
- const bool rem = pem.size() % lineWidth;
-
- for (int i = 0; i < newLines; ++i)
- pem.insert((i + 1) * lineWidth + i, '\n');
- if (rem)
- pem.append('\n');
-
- QByteArray extra;
- if (!headers.isEmpty()) {
- QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
- do {
- --it;
- extra += it.key() + ": " + it.value() + '\n';
- } while (it != headers.constBegin());
- extra += '\n';
- }
-
- if (isEncryptedPkcs8(der)) {
- pem.prepend(pkcs8Header(true) + '\n' + extra);
- pem.append(pkcs8Footer(true) + '\n');
- } else if (isPkcs8()) {
- pem.prepend(pkcs8Header(false) + '\n' + extra);
- pem.append(pkcs8Footer(false) + '\n');
- } else {
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
- }
-
- return pem;
-}
-
-QByteArray TlsKeyBase::pkcs8Header(bool encrypted)
-{
- return encrypted
- ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
-}
-
-QByteArray TlsKeyBase::pkcs8Footer(bool encrypted)
-{
- return encrypted
- ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----END PRIVATE KEY-----");
-}
-
-bool TlsKeyBase::isEncryptedPkcs8(const QByteArray &der)
-{
- static const QList<QByteArray> pbes1OIds {
- // PKCS5
- { PKCS5_MD2_DES_CBC_OID }, { PKCS5_MD2_RC2_CBC_OID }, { PKCS5_MD5_DES_CBC_OID },
- { PKCS5_MD5_RC2_CBC_OID }, { PKCS5_SHA1_DES_CBC_OID }, { PKCS5_SHA1_RC2_CBC_OID },
- };
- QAsn1Element elem;
- if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- const auto items = elem.toList();
- if (items.size() != 2
- || items[0].type() != QAsn1Element::SequenceType
- || items[1].type() != QAsn1Element::OctetStringType) {
- return false;
- }
-
- const auto encryptionSchemeContainer = items[0].toList();
- if (encryptionSchemeContainer.size() != 2
- || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
- return false;
- }
-
- const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
- return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
- || pbes1OIds.contains(encryptionScheme)
- || encryptionScheme.startsWith(PKCS12_OID);
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-
diff --git a/src/network/ssl/qtlskey_base_p.h b/src/network/ssl/qtlskey_base_p.h
deleted file mode 100644
index 6befed876c..0000000000
--- a/src/network/ssl/qtlskey_base_p.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSKEY_BASE_P_H
-#define QTLSKEY_BASE_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlsbackend_p.h>
-
-#include <qssl.h>
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-// TLSTODO: Note, 'base' is supposed to move to plugins together with
-// 'generic' and 'backendXXX'.
-class TlsKeyBase : public TlsKey
-{
-public:
- TlsKeyBase(KeyType type = QSsl::PublicKey, KeyAlgorithm algorithm = QSsl::Opaque)
- : keyType(type),
- keyAlgorithm(algorithm)
- {
- }
-
- bool isNull() const override
- {
- return keyIsNull;
- }
- KeyType type() const override
- {
- return keyType;
- }
- KeyAlgorithm algorithm() const override
- {
- return keyAlgorithm;
- }
- bool isPkcs8 () const override
- {
- return false;
- }
-
- QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const override;
-
-protected:
- static QByteArray pkcs8Header(bool encrypted);
- static QByteArray pkcs8Footer(bool encrypted);
- static bool isEncryptedPkcs8(const QByteArray &der);
-public:
- // TLSTODO: this public is quick fix needed by old _openssl classes
- // will become non-public as soon as those classes fixed.
- bool keyIsNull = true;
- KeyType keyType = QSsl::PublicKey;
- KeyAlgorithm keyAlgorithm = QSsl::Opaque;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLSKEY_BASE_P_H
diff --git a/src/network/ssl/qtlskey_generic.cpp b/src/network/ssl/qtlskey_generic.cpp
deleted file mode 100644
index b0ab0bfa96..0000000000
--- a/src/network/ssl/qtlskey_generic.cpp
+++ /dev/null
@@ -1,884 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlskey_generic_p.h"
-#include "qasn1element_p.h"
-#include "qsslkey_p.h"
-
-#include <QtNetwork/qpassworddigestor.h>
-
-#include <QtCore/QMessageAuthenticationCode>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qrandom.h>
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmap.h>
-
-#include <cstring>
-
-QT_BEGIN_NAMESPACE
-
-// The code here is essentially what we had in qsslkey_qt.cpp before, with
-// minimal changes/restructure.
-
-namespace QTlsPrivate {
-
-// OIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
-// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
-namespace {
-
-const quint8 bits_table[256] = {
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-using OidLengthMap = QMap<QByteArray, int>;
-
-OidLengthMap createOidMap()
-{
- OidLengthMap oids;
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.1"), 192); // secp192r1 a.k.a prime192v1
- oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.7"), 256); // secp256r1 a.k.a prime256v1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.1"), 193); // sect193r2
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.10"), 256); // secp256k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.16"), 283); // sect283k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.17"), 283); // sect283r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.26"), 233); // sect233k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.27"), 233); // sect233r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.3"), 239); // sect239k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.30"), 160); // secp160r2
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.31"), 192); // secp192k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.32"), 224); // secp224k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.33"), 224); // secp224r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.34"), 384); // secp384r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.35"), 521); // secp521r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.36"), 409); // sect409k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.37"), 409); // sect409r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.38"), 571); // sect571k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.39"), 571); // sect571r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.8"), 160); // secp160r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.9"), 160); // secp160k1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.11"), 384); // brainpoolP384r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.13"), 512); // brainpoolP512r1
- oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.7"), 256); // brainpoolP256r1
- return oids;
-}
-
-} // Unnamed namespace.
-
-Q_GLOBAL_STATIC_WITH_ARGS(OidLengthMap, oidLengthMap, (createOidMap()))
-
-namespace {
-
-// Maps OIDs to the encryption cipher they specify
-const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
- {DES_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesCbc},
- {DES_EDE3_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesEde3Cbc},
- // {PKCS5_MD2_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc}, // No MD2
- {PKCS5_MD5_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
- {PKCS5_SHA1_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
- // {PKCS5_MD2_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc}, // No MD2
- {PKCS5_MD5_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
- {PKCS5_SHA1_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
- {RC2_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc2Cbc}
- // {RC5_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc5Cbc}, // No RC5
- // {AES128_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes128}, // no AES
- // {AES192_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes192},
- // {AES256_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes256}
-};
-
-struct EncryptionData
-{
- EncryptionData() = default;
-
- EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
- : initialized(true), cipher(cipher), key(key), iv(iv)
- {
- }
- bool initialized = false;
- QSslKeyPrivate::Cipher cipher;
- QByteArray key;
- QByteArray iv;
-};
-
-EncryptionData readPbes2(const QList<QAsn1Element> &element, const QByteArray &passPhrase)
-{
- // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.2
- /*** Scheme: ***
- * Sequence (scheme-specific info..)
- * Sequence (key derivation info)
- * Object Identifier (Key derivation algorithm (e.g. PBKDF2))
- * Sequence (salt)
- * CHOICE (this entry can be either of the types it contains)
- * Octet string (actual salt)
- * Object identifier (Anything using this is deferred to a later version of PKCS #5)
- * Integer (iteration count)
- * Sequence (encryption algorithm info)
- * Object identifier (identifier for the algorithm)
- * Algorithm dependent, is covered in the switch further down
- */
-
- static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
- // PBES2/PBKDF2
- {HMAC_WITH_SHA1, QCryptographicHash::Sha1},
- {HMAC_WITH_SHA224, QCryptographicHash::Sha224},
- {HMAC_WITH_SHA256, QCryptographicHash::Sha256},
- {HMAC_WITH_SHA512, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA512_224, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA512_256, QCryptographicHash::Sha512},
- {HMAC_WITH_SHA384, QCryptographicHash::Sha384}
- };
-
- // Values from their respective sections here: https://tools.ietf.org/html/rfc8018#appendix-B.2
- static const QMap<QSslKeyPrivate::Cipher, int> cipherKeyLengthMap {
- {QSslKeyPrivate::Cipher::DesCbc, 8},
- {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
- // @note: variable key-length (https://tools.ietf.org/html/rfc8018#appendix-B.2.3)
- {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
- // @todo: AES(, rc5?)
- };
-
- const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
- if (keyDerivationContainer.size() != 2
- || keyDerivationContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || keyDerivationContainer[1].type() != QAsn1Element::SequenceType) {
- return {};
- }
-
- const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
- const auto keyDerivationParams = keyDerivationContainer[1].toList();
-
- const auto encryptionAlgorithmContainer = element[1].toList();
- if (encryptionAlgorithmContainer.size() != 2
- || encryptionAlgorithmContainer[0].type() != QAsn1Element::ObjectIdentifierType) {
- return {};
- }
-
- auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
- if (iterator == oidCipherMap.cend()) {
- qWarning()
- << "QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
- << "\nFile a bug report to Qt (include the line above).";
- return {};
- }
-
- QSslKeyPrivate::Cipher cipher = *iterator;
- QByteArray key;
- QByteArray iv;
- switch (cipher) {
- case QSslKeyPrivate::Cipher::DesCbc:
- case QSslKeyPrivate::Cipher::DesEde3Cbc:
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.1 (DES-CBC-PAD)
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.2 (DES-EDE3-CBC-PAD)
- // @todo https://tools.ietf.org/html/rfc8018#appendix-B.2.5 (AES-CBC-PAD)
- /*** Scheme: ***
- * Octet string (IV)
- */
- if (encryptionAlgorithmContainer[1].type() != QAsn1Element::OctetStringType)
- return {};
-
- // @note: All AES identifiers should be able to use this branch!!
- iv = encryptionAlgorithmContainer[1].value();
-
- if (iv.size() != 8) // @note: AES needs 16 bytes
- return {};
- break;
- case QSslKeyPrivate::Cipher::Rc2Cbc: {
- // https://tools.ietf.org/html/rfc8018#appendix-B.2.3
- /*** Scheme: ***
- * Sequence (rc2 parameters)
- * Integer (rc2 parameter version)
- * Octet string (IV)
- */
- if (encryptionAlgorithmContainer[1].type() != QAsn1Element::SequenceType)
- return {};
- const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
- if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
- || rc2ParametersContainer.back().type() != QAsn1Element::OctetStringType) {
- return {};
- }
- iv = rc2ParametersContainer.back().value();
- if (iv.size() != 8)
- return {};
- break;
- } // @todo(?): case (RC5 , AES)
- case QSslKeyPrivate::Cipher::Aes128Cbc:
- case QSslKeyPrivate::Cipher::Aes192Cbc:
- case QSslKeyPrivate::Cipher::Aes256Cbc:
- Q_UNREACHABLE();
- }
-
- if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
- // Definition: https://tools.ietf.org/html/rfc8018#appendix-A.2
- QByteArray salt;
- if (keyDerivationParams[0].type() == QAsn1Element::OctetStringType) {
- salt = keyDerivationParams[0].value();
- } else if (keyDerivationParams[0].type() == QAsn1Element::ObjectIdentifierType) {
- Q_UNIMPLEMENTED();
- /* See paragraph from https://tools.ietf.org/html/rfc8018#appendix-A.2
- which ends with: "such facilities are deferred to a future version of PKCS #5"
- */
- return {};
- } else {
- return {};
- }
-
- // Iterations needed to derive the key
- int iterationCount = keyDerivationParams[1].toInteger();
- // Optional integer
- int keyLength = -1;
- int vectorPos = 2;
- if (keyDerivationParams.size() > vectorPos
- && keyDerivationParams[vectorPos].type() == QAsn1Element::IntegerType) {
- keyLength = keyDerivationParams[vectorPos].toInteger(nullptr);
- ++vectorPos;
- } else {
- keyLength = cipherKeyLengthMap[cipher];
- }
-
- // Optional algorithm identifier (default: HMAC-SHA-1)
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
- if (keyDerivationParams.size() > vectorPos
- && keyDerivationParams[vectorPos].type() == QAsn1Element::SequenceType) {
- const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
- hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
- Q_ASSERT(hashAlgorithmContainer[1].type() == QAsn1Element::NullType);
- ++vectorPos;
- }
- Q_ASSERT(keyDerivationParams.size() == vectorPos);
-
- key = QPasswordDigestor::deriveKeyPbkdf2(hashAlgorithm, passPhrase, salt, iterationCount, keyLength);
- } else {
- qWarning()
- << "QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
- << "\nFile a bugreport to Qt (include the line above).";
- return {};
- }
- return {cipher, key, iv};
-}
-
-// Maps OIDs to the hash function it specifies
-const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
-#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- // PKCS5
- //{PKCS5_MD2_DES_CBC_OID, QCryptographicHash::Md2}, No MD2
- //{PKCS5_MD2_RC2_CBC_OID, QCryptographicHash::Md2},
- {PKCS5_MD5_DES_CBC_OID, QCryptographicHash::Md5},
- {PKCS5_MD5_RC2_CBC_OID, QCryptographicHash::Md5},
-#endif
- {PKCS5_SHA1_DES_CBC_OID, QCryptographicHash::Sha1},
- {PKCS5_SHA1_RC2_CBC_OID, QCryptographicHash::Sha1},
- // PKCS12 (unimplemented)
- // {PKCS12_SHA1_RC4_128_OID, QCryptographicHash::Sha1}, // No RC4
- // {PKCS12_SHA1_RC4_40_OID, QCryptographicHash::Sha1},
- // @todo: lacking support. @note: there might be code to do this inside qsslsocket_mac...
- // further note that more work may be required for the 3DES variations listed to be available.
- // {PKCS12_SHA1_3KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_2KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_RC2_128_CBC_OID, QCryptographicHash::Sha1},
- // {PKCS12_SHA1_RC2_40_CBC_OID, QCryptographicHash::Sha1}
-};
-
-EncryptionData readPbes1(const QList<QAsn1Element> &element, const QByteArray &encryptionScheme,
- const QByteArray &passPhrase)
-{
- // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.1
- // Steps refer to this section: https://tools.ietf.org/html/rfc8018#section-6.1.2
- /*** Scheme: ***
- * Sequence (PBE Parameter)
- * Octet string (salt)
- * Integer (iteration counter)
- */
- // Step 1
- if (element.size() != 2
- || element[0].type() != QAsn1Element::ElementType::OctetStringType
- || element[1].type() != QAsn1Element::ElementType::IntegerType) {
- return {};
- }
- QByteArray salt = element[0].value();
- if (salt.size() != 8)
- return {};
-
- int iterationCount = element[1].toInteger();
- if (iterationCount < 0)
- return {};
-
- // Step 2
- auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
- if (iterator == pbes1OidHashFunctionMap.cend()) {
- // Qt was compiled with ONLY_SHA1 (or it's MD2)
- return {};
- }
- QCryptographicHash::Algorithm hashAlgorithm = *iterator;
- QByteArray key = QPasswordDigestor::deriveKeyPbkdf1(hashAlgorithm, passPhrase, salt, iterationCount, 16);
- if (key.size() != 16)
- return {};
-
- // Step 3
- QByteArray iv = key.right(8); // last 8 bytes are used as IV
- key.truncate(8); // first 8 bytes are used for the key
-
- QSslKeyPrivate::Cipher cipher = oidCipherMap[encryptionScheme];
- // Steps 4-6 are done after returning
- return {cipher, key, iv};
-}
-
-int curveBits(const QByteArray &oid)
-{
- const int length = oidLengthMap->value(oid);
- return length ? length : -1;
-}
-
-int numberOfBits(const QByteArray &modulus)
-{
- int bits = modulus.size() * 8;
- for (int i = 0; i < modulus.size(); ++i) {
- quint8 b = modulus[i];
- bits -= 8;
- if (b != 0) {
- bits += bits_table[b];
- break;
- }
- }
- return bits;
-}
-
-QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
- const QByteArray &iv)
-{
- // This is somewhat simplified and shortened version of what OpenSSL does.
- // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
- // in their code for what they pass as arguments to EVP_BytesToKey when
- // deriving encryption keys (when reading/writing pems files with encrypted
- // keys).
-
- Q_ASSERT(iv.size() >= 8);
-
- QCryptographicHash hash(QCryptographicHash::Md5);
-
- QByteArray data(passPhrase);
- data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
-
- hash.addData(data);
-
- if (cipher == Cipher::Aes128Cbc)
- return hash.result();
-
- QByteArray key(hash.result());
- hash.reset();
- hash.addData(key);
- hash.addData(data);
-
- if (cipher == Cipher::Aes192Cbc)
- return key.append(hash.result().constData(), 8);
-
- return key.append(hash.result());
-}
-
-QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
- const QByteArray &iv)
-{
- QByteArray key;
- QCryptographicHash hash(QCryptographicHash::Md5);
- hash.addData(passPhrase);
- hash.addData(iv);
- switch (cipher) {
- case Cipher::DesCbc:
- key = hash.result().left(8);
- break;
- case Cipher::DesEde3Cbc:
- key = hash.result();
- hash.reset();
- hash.addData(key);
- hash.addData(passPhrase);
- hash.addData(iv);
- key += hash.result().left(8);
- break;
- case Cipher::Rc2Cbc:
- key = hash.result();
- break;
- case Cipher::Aes128Cbc:
- case Cipher::Aes192Cbc:
- case Cipher::Aes256Cbc:
- return deriveAesKey(cipher, passPhrase, iv);
- }
- return key;
-}
-
-int extractPkcs8KeyLength(const QList<QAsn1Element> &items, TlsKey *that)
-{
- Q_ASSERT(items.size() == 3);
- Q_ASSERT(that);
-
- int keyLength = -1;
-
- auto getName = [](QSsl::KeyAlgorithm algorithm) {
- switch (algorithm){
- case QSsl::Rsa: return "RSA";
- case QSsl::Dsa: return "DSA";
- case QSsl::Dh: return "DH";
- case QSsl::Ec: return "EC";
- case QSsl::Opaque: return "Opaque";
- }
- Q_UNREACHABLE();
- };
-
- const auto pkcs8Info = items[1].toList();
- if (pkcs8Info.size() != 2 || pkcs8Info[0].type() != QAsn1Element::ObjectIdentifierType)
- return -1;
- const QByteArray value = pkcs8Info[0].toObjectId();
- if (value == RSA_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm() != QSsl::Rsa)) {
- // We could change the 'algorithm' of QSslKey here and continue loading, but
- // this is not supported in the openssl back-end, so we'll fail here and give
- // the user some feedback.
- qWarning() << "QSslKey: Found RSA key when asked to use" << getName(that->algorithm())
- << "\nLoading will fail.";
- return -1;
- }
- // Luckily it contains the 'normal' RSA-key format inside, so we can just recurse
- // and read the key's info.
- that->decodeDer(that->type(), that->algorithm(), items[2].value(), {}, true);
- // The real info has been filled out in the call above, so return as if it was invalid
- // to avoid overwriting the data.
- return -1;
- } else if (value == EC_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm() != QSsl::Ec)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found EC key when asked to use" << getName(that->algorithm())
- << "\nLoading will fail.";
- return -1;
- }
- // I don't know where this is documented, but the elliptic-curve identifier has been
- // moved into the "pkcs#8 wrapper", which is what we're interested in.
- if (pkcs8Info[1].type() != QAsn1Element::ObjectIdentifierType)
- return -1;
- keyLength = curveBits(pkcs8Info[1].toObjectId());
- } else if (value == DSA_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm() != QSsl::Dsa)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found DSA when asked to use" << getName(that->algorithm())
- << "\nLoading will fail.";
- return -1;
- }
- // DSA's structure is documented here:
- // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
- if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
- return -1;
- const auto dsaInfo = pkcs8Info[1].toList();
- if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType)
- return -1;
- keyLength = numberOfBits(dsaInfo[0].value());
- } else if (value == DH_ENCRYPTION_OID) {
- if (Q_UNLIKELY(that->algorithm() != QSsl::Dh)) {
- // As above for RSA.
- qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm())
- << "\nLoading will fail.";
- return -1;
- }
- // DH's structure is documented here:
- // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
- if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
- return -1;
- const auto dhInfo = pkcs8Info[1].toList();
- if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType)
- return -1;
- keyLength = numberOfBits(dhInfo[0].value());
- } else {
- // in case of unexpected formats:
- qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value
- << "\nFile a bugreport to Qt (include the line above).";
- return -1;
- }
-
- return keyLength;
-}
-
-} // Unnamed namespace
-
-void TlsKeyGeneric::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
- const QByteArray &passPhrase, bool deepClear)
-{
- keyType = type;
- keyAlgorithm = algorithm;
-
- clear(deepClear);
-
- if (der.isEmpty())
- return;
- // decryptPkcs8 decrypts if necessary or returns 'der' unaltered
- QByteArray decryptedDer = decryptPkcs8(der, passPhrase);
-
- QAsn1Element elem;
- if (!elem.read(decryptedDer) || elem.type() != QAsn1Element::SequenceType)
- return;
-
- if (type == QSsl::PublicKey) {
- // key info
- QDataStream keyStream(elem.value());
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
- return;
- const auto infoItems = elem.toList();
- if (infoItems.size() < 2 || infoItems[0].type() != QAsn1Element::ObjectIdentifierType)
- return;
- if (algorithm == QSsl::Rsa) {
- if (infoItems[0].toObjectId() != RSA_ENCRYPTION_OID)
- return;
- // key data
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::BitStringType || elem.value().isEmpty())
- return;
- if (!elem.read(elem.value().mid(1)) || elem.type() != QAsn1Element::SequenceType)
- return;
- if (!elem.read(elem.value()) || elem.type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(elem.value());
- } else if (algorithm == QSsl::Dsa) {
- if (infoItems[0].toObjectId() != DSA_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::SequenceType)
- return;
- // key params
- const auto params = infoItems[1].toList();
- if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(params[0].value());
- } else if (algorithm == QSsl::Dh) {
- if (infoItems[0].toObjectId() != DH_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::SequenceType)
- return;
- // key params
- const auto params = infoItems[1].toList();
- if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(params[0].value());
- } else if (algorithm == QSsl::Ec) {
- if (infoItems[0].toObjectId() != EC_ENCRYPTION_OID)
- return;
- if (infoItems[1].type() != QAsn1Element::ObjectIdentifierType)
- return;
- keyLength = curveBits(infoItems[1].toObjectId());
- }
-
- } else {
- const auto items = elem.toList();
- if (items.isEmpty())
- return;
-
- // version
- if (items[0].type() != QAsn1Element::IntegerType)
- return;
- const QByteArray versionHex = items[0].value().toHex();
-
- if (items.size() == 3 && items[1].type() == QAsn1Element::SequenceType
- && items[2].type() == QAsn1Element::OctetStringType) {
- if (versionHex != "00" && versionHex != "01")
- return;
- int pkcs8KeyLength = extractPkcs8KeyLength(items, this);
- if (pkcs8KeyLength == -1)
- return;
- pkcs8 = true;
- keyLength = pkcs8KeyLength;
- } else if (algorithm == QSsl::Rsa) {
- if (versionHex != "00")
- return;
- if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Dsa) {
- if (versionHex != "00")
- return;
- if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Dh) {
- if (versionHex != "00")
- return;
- if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType)
- return;
- keyLength = numberOfBits(items[1].value());
- } else if (algorithm == QSsl::Ec) {
- if (versionHex != "01")
- return;
- if (items.size() != 4
- || items[1].type() != QAsn1Element::OctetStringType
- || items[2].type() != QAsn1Element::Context0Type
- || items[3].type() != QAsn1Element::Context1Type)
- return;
- QAsn1Element oidElem;
- if (!oidElem.read(items[2].value())
- || oidElem.type() != QAsn1Element::ObjectIdentifierType)
- return;
- keyLength = curveBits(oidElem.toObjectId());
- }
- }
-
- derData = decryptedDer;
- keyIsNull = false;
-}
-
-void TlsKeyGeneric::decodePem(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &pem,
- const QByteArray &passPhrase, bool deepClear)
-{
- keyType = type;
- keyAlgorithm = algorithm;
-
- QMap<QByteArray, QByteArray> headers;
- QByteArray data = derFromPem(pem, &headers);
-
- if (headers.value("Proc-Type") == "4,ENCRYPTED") {
- const QList<QByteArray> dekInfo = headers.value("DEK-Info").split(',');
- if (dekInfo.size() != 2) {
- clear(deepClear);
- return;
- }
-
- QSslKeyPrivate::Cipher cipher;
- if (dekInfo.first() == "DES-CBC") {
- cipher = Cipher::DesCbc;
- } else if (dekInfo.first() == "DES-EDE3-CBC") {
- cipher = Cipher::DesEde3Cbc;
- } else if (dekInfo.first() == "RC2-CBC") {
- cipher = Cipher::Rc2Cbc;
- } else if (dekInfo.first() == "AES-128-CBC") {
- cipher = Cipher::Aes128Cbc;
- } else if (dekInfo.first() == "AES-192-CBC") {
- cipher = Cipher::Aes192Cbc;
- } else if (dekInfo.first() == "AES-256-CBC") {
- cipher = Cipher::Aes256Cbc;
- } else {
- clear(deepClear);
- return;
- }
-
- const QByteArray iv = QByteArray::fromHex(dekInfo.last());
- const QByteArray key = deriveKey(cipher, passPhrase, iv);
- data = decrypt(cipher, data, key, iv);
- }
-
- decodeDer(keyType, keyAlgorithm, data, passPhrase, deepClear);
-}
-
-QByteArray TlsKeyGeneric::toPem(const QByteArray &passPhrase) const
-{
- QByteArray data;
- QMap<QByteArray, QByteArray> headers;
-
- if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
- // ### use a cryptographically secure random number generator
- quint64 random = QRandomGenerator::system()->generate64();
- QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random));
-
- auto cipher = Cipher::DesEde3Cbc;
- const QByteArray key = deriveKey(cipher, passPhrase, iv);
- data = encrypt(cipher, derData, key, iv);
-
- headers.insert("Proc-Type", "4,ENCRYPTED");
- headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex());
- } else {
- data = derData;
- }
-
- return pemFromDer(data, headers);
-}
-
-QByteArray TlsKeyGeneric::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
-{
- if (derData.size())
- return derData;
-
- QByteArray header = pemHeader();
- QByteArray footer = pemFooter();
-
- QByteArray der(pem);
-
- int headerIndex = der.indexOf(header);
- int footerIndex = der.indexOf(footer, headerIndex + header.length());
- if (type() != QSsl::PublicKey) {
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(true);
- footer = pkcs8Footer(true);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(false);
- footer = pkcs8Footer(false);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- }
- if (headerIndex == -1 || footerIndex == -1)
- return QByteArray();
-
- der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
-
- if (der.contains("Proc-Type:")) {
- // taken from QHttpNetworkReplyPrivate::parseHeader
- int i = 0;
- while (i < der.count()) {
- int j = der.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = der.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = der.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && der[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += der.mid(j, length).trimmed();
- j = ++i;
- } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- headers->insert(field, value);
- }
- der = der.mid(i);
- }
-
- return QByteArray::fromBase64(der); // ignores newlines
-}
-
-void TlsKeyGeneric::fromHandle(Qt::HANDLE handle, KeyType expectedType)
-{
- opaque = handle;
- keyType = expectedType;
-}
-
-void TlsKeyGeneric::clear(bool deep)
-{
- keyIsNull = true;
- if (deep)
- std::memset(derData.data(), 0, derData.size());
- derData.clear();
- keyLength = -1;
-}
-
-QByteArray TlsKeyGeneric::decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase)
-{
- // RFC 5958: https://tools.ietf.org/html/rfc5958
- /*** Scheme: ***
- * Sequence
- * Sequence
- * Object Identifier (encryption scheme (currently PBES2, PBES1, @todo PKCS12))
- * Sequence (scheme parameters)
- * Octet String (the encrypted data)
- */
- QAsn1Element elem;
- if (!elem.read(encrypted) || elem.type() != QAsn1Element::SequenceType)
- return encrypted;
-
- const auto items = elem.toList();
- if (items.size() != 2
- || items[0].type() != QAsn1Element::SequenceType
- || items[1].type() != QAsn1Element::OctetStringType) {
- return encrypted;
- }
-
- const auto encryptionSchemeContainer = items[0].toList();
-
- if (encryptionSchemeContainer.size() != 2
- || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
- return encrypted;
- }
-
- const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
- const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
-
- if (schemeParameterContainer.size() != 2
- && schemeParameterContainer[0].type() != QAsn1Element::SequenceType
- && schemeParameterContainer[1].type() != QAsn1Element::SequenceType) {
- return encrypted;
- }
-
- EncryptionData data;
- if (encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID) {
- data = readPbes2(schemeParameterContainer, passPhrase);
- } else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
- data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
- } else if (encryptionScheme.startsWith(PKCS12_OID)) {
- Q_UNIMPLEMENTED(); // this isn't some 'unknown', I know these aren't implemented
- return encrypted;
- } else {
- qWarning()
- << "QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
- << "\nFile a bugreport to Qt (include the line above).";
- return encrypted;
- }
-
- if (!data.initialized) {
- // something went wrong, return
- return encrypted;
- }
-
- QByteArray decryptedKey = decrypt(data.cipher, items[1].value(), data.key, data.iv);
- // The data is still wrapped in a octet string, so let's unwrap it
- QAsn1Element decryptedKeyElement(QAsn1Element::ElementType::OctetStringType, decryptedKey);
- return decryptedKeyElement.value();
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlskey_generic_p.h b/src/network/ssl/qtlskey_generic_p.h
deleted file mode 100644
index 4c409f5f51..0000000000
--- a/src/network/ssl/qtlskey_generic_p.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSKEY_GENERIC_P_H
-#define QTLSKEY_GENERIC_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlskey_base_p.h>
-#include <private/qtlsbackend_p.h>
-
-#include <QtCore/qnamespace.h>
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-// This class is what previously was known as qsslkey_qt:
-// it implements most of functionality needed by QSslKey
-// not relying on any TLS implementation. It's used by
-// our SecureTransport and Schannel backends.
-class TlsKeyGeneric : public TlsKeyBase
-{
-public:
- using TlsKeyBase::TlsKeyBase;
-
- void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
- const QByteArray &passPhrase, bool deepClear) override;
- void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
- const QByteArray &passPhrase, bool deepClear) override;
-
- QByteArray toPem(const QByteArray &passPhrase) const override;
-
- QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray,
- QByteArray> *headers) const override;
-
- void fromHandle(Qt::HANDLE opaque, KeyType expectedType) override;
-
- void clear(bool deep) override;
-
- Qt::HANDLE handle() const override
- {
- return Qt::HANDLE(opaque);
- }
-
- int length() const override
- {
- return keyLength;
- }
-
- bool isPkcs8() const override
- {
- return pkcs8;
- }
-
-private:
- QByteArray decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase);
-
- bool pkcs8 = false;
- Qt::HANDLE opaque = nullptr;
- QByteArray derData;
- int keyLength = -1;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLSKEY_GENERIC_P_H
diff --git a/src/network/ssl/qtlskey_openssl.cpp b/src/network/ssl/qtlskey_openssl.cpp
deleted file mode 100644
index 6d75dfd5b4..0000000000
--- a/src/network/ssl/qtlskey_openssl.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qtlskey_openssl_p.h"
-#include "qsslsocket.h"
-#include "qsslkey_p.h"
-
-#include <qscopeguard.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-void TlsKeyOpenSSL::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
- const QByteArray &passPhrase, bool deepClear)
-{
- if (der.isEmpty())
- return;
-
- keyType = type;
- keyAlgorithm = algorithm;
-
- QMap<QByteArray, QByteArray> headers;
- const auto pem = pemFromDer(der, headers);
-
- decodePem(type, algorithm, pem, passPhrase, deepClear);
-}
-
-void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
- const QByteArray &passPhrase, bool deepClear)
-{
- if (pem.isEmpty())
- return;
-
- keyType = type;
- keyAlgorithm = algorithm;
-
- clear(deepClear);
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio)
- return;
-
- const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
-
- void *phrase = const_cast<char *>(passPhrase.data());
-
- if (algorithm == QSsl::Rsa) {
- RSA *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, nullptr, phrase)
- : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, nullptr, phrase);
- if (rsa && rsa == result)
- keyIsNull = false;
- } else if (algorithm == QSsl::Dsa) {
- DSA *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, nullptr, phrase)
- : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase);
- if (dsa && dsa == result)
- keyIsNull = false;
- } else if (algorithm == QSsl::Dh) {
- EVP_PKEY *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase)
- : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
- if (result)
- dh = q_EVP_PKEY_get1_DH(result);
- if (dh)
- keyIsNull = false;
- q_EVP_PKEY_free(result);
-#ifndef OPENSSL_NO_EC
- } else if (algorithm == QSsl::Ec) {
- EC_KEY *result = (type == QSsl::PublicKey)
- ? q_PEM_read_bio_EC_PUBKEY(bio, &ec, nullptr, phrase)
- : q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase);
- if (ec && ec == result)
- keyIsNull = false;
-#endif
- }
-}
-
-QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
-{
- QByteArray header = pemHeader();
- QByteArray footer = pemFooter();
-
- QByteArray der(pem);
-
- int headerIndex = der.indexOf(header);
- int footerIndex = der.indexOf(footer, headerIndex + header.length());
- if (type() != QSsl::PublicKey) {
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(true);
- footer = pkcs8Footer(true);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(false);
- footer = pkcs8Footer(false);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- }
- if (headerIndex == -1 || footerIndex == -1)
- return QByteArray();
-
- der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
-
- if (der.contains("Proc-Type:")) {
- // taken from QHttpNetworkReplyPrivate::parseHeader
- int i = 0;
- while (i < der.count()) {
- int j = der.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = der.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = der.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && der[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += der.mid(j, length).trimmed();
- j = ++i;
- } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- headers->insert(field, value);
- }
- der = der.mid(i);
- }
-
- return QByteArray::fromBase64(der); // ignores newlines
-}
-
-void TlsKeyOpenSSL::clear(bool deep)
-{
- keyIsNull = true;
-
- if (algorithm() == QSsl::Rsa && rsa) {
- if (deep)
- q_RSA_free(rsa);
- rsa = nullptr;
- }
- if (algorithm() == QSsl::Dsa && dsa) {
- if (deep)
- q_DSA_free(dsa);
- dsa = nullptr;
- }
- if (algorithm() == QSsl::Dh && dh) {
- if (deep)
- q_DH_free(dh);
- dh = nullptr;
- }
-#ifndef OPENSSL_NO_EC
- if (algorithm() == QSsl::Ec && ec) {
- if (deep)
- q_EC_KEY_free(ec);
- ec = nullptr;
- }
-#endif
- if (algorithm() == QSsl::Opaque && opaque) {
- if (deep)
- q_EVP_PKEY_free(opaque);
- opaque = nullptr;
- }
-}
-
-Qt::HANDLE TlsKeyOpenSSL::handle() const
-{
- switch (keyAlgorithm) {
- case QSsl::Opaque:
- return Qt::HANDLE(opaque);
- case QSsl::Rsa:
- return Qt::HANDLE(rsa);
- case QSsl::Dsa:
- return Qt::HANDLE(dsa);
- case QSsl::Dh:
- return Qt::HANDLE(dh);
-#ifndef OPENSSL_NO_EC
- case QSsl::Ec:
- return Qt::HANDLE(ec);
-#endif
- default:
- return Qt::HANDLE(nullptr);
- }
-}
-
-int TlsKeyOpenSSL::length() const
-{
- if (isNull() || algorithm() == QSsl::Opaque)
- return -1;
-
- switch (algorithm()) {
- case QSsl::Rsa:
- return q_RSA_bits(rsa);
- case QSsl::Dsa:
- return q_DSA_bits(dsa);
- case QSsl::Dh:
- return q_DH_bits(dh);
-#ifndef OPENSSL_NO_EC
- case QSsl::Ec:
- return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
-#endif
- default:
- return -1;
- }
-}
-
-QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
-{
- if (!QSslSocket::supportsSsl() || isNull() || algorithm() == QSsl::Opaque)
- return {};
-
- const EVP_CIPHER *cipher = nullptr;
- if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
-#ifndef OPENSSL_NO_DES
- cipher = q_EVP_des_ede3_cbc();
-#else
- return {};
-#endif
- }
-
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return {};
-
- const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
-
- bool fail = false;
-
- if (algorithm() == QSsl::Rsa) {
- if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_RSA_PUBKEY(bio, rsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_RSAPrivateKey(
- bio, rsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
- } else if (algorithm() == QSsl::Dsa) {
- if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_DSA_PUBKEY(bio, dsa))
- fail = true;
- } else {
- if (!q_PEM_write_bio_DSAPrivateKey(
- bio, dsa, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
- } else if (algorithm() == QSsl::Dh) {
- EVP_PKEY *result = q_EVP_PKEY_new();
- if (!result || !q_EVP_PKEY_set1_DH(result, dh)) {
- fail = true;
- } else if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_PUBKEY(bio, result))
- fail = true;
- } else if (!q_PEM_write_bio_PrivateKey(
- bio, result, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- q_EVP_PKEY_free(result);
-#ifndef OPENSSL_NO_EC
- } else if (algorithm() == QSsl::Ec) {
- if (type() == QSsl::PublicKey) {
- if (!q_PEM_write_bio_EC_PUBKEY(bio, ec))
- fail = true;
- } else {
- if (!q_PEM_write_bio_ECPrivateKey(
- bio, ec, cipher, (uchar *)passPhrase.data(),
- passPhrase.size(), nullptr, nullptr)) {
- fail = true;
- }
- }
-#endif
- } else {
- fail = true;
- }
-
- QByteArray pem;
- if (!fail) {
- char *data = nullptr;
- const long size = q_BIO_get_mem_data(bio, &data);
- if (size > 0 && data)
- pem = QByteArray(data, size);
- }
-
- return pem;
-}
-
-void TlsKeyOpenSSL::fromHandle(Qt::HANDLE handle, QSsl::KeyType expectedType)
-{
- EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
- if (!evpKey || !fromEVP_PKEY(evpKey)) {
- opaque = evpKey;
- keyAlgorithm = QSsl::Opaque;
- } else {
- q_EVP_PKEY_free(evpKey);
- }
-
- keyType = expectedType;
- keyIsNull = !opaque;
-}
-
-bool TlsKeyOpenSSL::fromEVP_PKEY(EVP_PKEY *pkey)
-{
- if (!pkey)
- return false;
-
- switch (q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey))) {
- case EVP_PKEY_RSA:
- keyIsNull = false;
- keyAlgorithm = QSsl::Rsa;
- keyType = QSsl::PrivateKey;
- rsa = q_EVP_PKEY_get1_RSA(pkey);
-
- return true;
- case EVP_PKEY_DSA:
- keyIsNull = false;
- keyAlgorithm = QSsl::Dsa;
- keyType = QSsl::PrivateKey;
- dsa = q_EVP_PKEY_get1_DSA(pkey);
-
- return true;
- case EVP_PKEY_DH:
- keyIsNull = false;
- keyAlgorithm = QSsl::Dh;
- keyType = QSsl::PrivateKey;
- dh = q_EVP_PKEY_get1_DH(pkey);
- return true;
-#ifndef OPENSSL_NO_EC
- case EVP_PKEY_EC:
- keyIsNull = false;
- keyAlgorithm = QSsl::Ec;
- keyType = QSsl::PrivateKey;
- ec = q_EVP_PKEY_get1_EC_KEY(pkey);
-
- return true;
-#endif
- default:;
- // Unknown key type. This could be handled as opaque, but then
- // we'd eventually leak memory since we wouldn't be able to free
- // the underlying EVP_PKEY structure. For now, we won't support
- // this.
- }
-
- return false;
-}
-
-QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv, bool enc)
-{
- const EVP_CIPHER *type = nullptr;
- int i = 0, len = 0;
-
- switch (cipher) {
- case Cipher::DesCbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_cbc();
-#endif
- break;
- case Cipher::DesEde3Cbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_ede3_cbc();
-#endif
- break;
- case Cipher::Rc2Cbc:
-#ifndef OPENSSL_NO_RC2
- type = q_EVP_rc2_cbc();
-#endif
- break;
- case Cipher::Aes128Cbc:
- type = q_EVP_aes_128_cbc();
- break;
- case Cipher::Aes192Cbc:
- type = q_EVP_aes_192_cbc();
- break;
- case Cipher::Aes256Cbc:
- type = q_EVP_aes_256_cbc();
- break;
- }
-
- if (type == nullptr)
- return {};
-
- QByteArray output;
- output.resize(data.size() + EVP_MAX_BLOCK_LENGTH);
-
- EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
- q_EVP_CIPHER_CTX_reset(ctx);
- q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc);
- q_EVP_CIPHER_CTX_set_key_length(ctx, key.size());
- if (cipher == Cipher::Rc2Cbc)
- q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), nullptr);
-
- q_EVP_CipherInit_ex(ctx, nullptr, nullptr,
- reinterpret_cast<const unsigned char *>(key.constData()),
- reinterpret_cast<const unsigned char *>(iv.constData()),
- enc);
- q_EVP_CipherUpdate(ctx,
- reinterpret_cast<unsigned char *>(output.data()), &len,
- reinterpret_cast<const unsigned char *>(data.constData()), data.size());
- q_EVP_CipherFinal(ctx,
- reinterpret_cast<unsigned char *>(output.data()) + len, &i);
- len += i;
-
- q_EVP_CIPHER_CTX_reset(ctx);
- q_EVP_CIPHER_CTX_free(ctx);
-
- return output.left(len);
-}
-
-QByteArray TlsKeyOpenSSL::decrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const
-{
- return doCrypt(cipher, data, key, iv, false);
-}
-
-QByteArray TlsKeyOpenSSL::encrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const
-{
- return doCrypt(cipher, data, key, iv, true);
-}
-
-TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
-{
- TlsKeyOpenSSL *tlsKey = new TlsKeyOpenSSL;
- std::unique_ptr<TlsKeyOpenSSL> keyRaii(tlsKey);
-
- tlsKey->keyType = QSsl::PublicKey;
-
- EVP_PKEY *pkey = q_X509_get_pubkey(x);
- Q_ASSERT(pkey);
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
-
- if (keyType == EVP_PKEY_RSA) {
- tlsKey->rsa = q_EVP_PKEY_get1_RSA(pkey);
- tlsKey->keyAlgorithm = QSsl::Rsa;
- tlsKey->keyIsNull = false;
- } else if (keyType == EVP_PKEY_DSA) {
- tlsKey->dsa = q_EVP_PKEY_get1_DSA(pkey);
- tlsKey->keyAlgorithm = QSsl::Dsa;
- tlsKey->keyIsNull = false;
-#ifndef OPENSSL_NO_EC
- } else if (keyType == EVP_PKEY_EC) {
- tlsKey->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- tlsKey->keyAlgorithm = QSsl::Ec;
- tlsKey->keyIsNull = false;
-#endif
- } else if (keyType == EVP_PKEY_DH) {
- // DH unsupported (key is null)
- } else {
- // error? (key is null)
- }
-
- q_EVP_PKEY_free(pkey);
- return keyRaii.release();
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlskey_openssl_p.h b/src/network/ssl/qtlskey_openssl_p.h
deleted file mode 100644
index 5ef51dfd56..0000000000
--- a/src/network/ssl/qtlskey_openssl_p.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSKEY_OPENSSL_H
-#define QTLSKEY_OPENSSL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include "qtlskey_base_p.h"
-#include "qtlsbackend_p.h"
-#include "qsslkey_p.h"
-
-#include <QtNetwork/qssl.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
-
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-#include <openssl/dh.h>
-
-QT_BEGIN_NAMESPACE
-
-QT_REQUIRE_CONFIG(ssl);
-
-namespace QTlsPrivate {
-
-class TlsKeyOpenSSL final : public TlsKeyBase
-{
-public:
- TlsKeyOpenSSL()
- : opaque(nullptr)
- {
- clear(false);
- }
- ~TlsKeyOpenSSL()
- {
- clear(true);
- }
-
- void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
- const QByteArray &passPhrase, bool deepClear) override;
- void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
- const QByteArray &passPhrase, bool deepClear) override;
-
- QByteArray toPem(const QByteArray &passPhrase) const override;
- QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const override;
-
- void fromHandle(Qt::HANDLE opaque, KeyType expectedType) override;
-
- void clear(bool deep) override;
- Qt::HANDLE handle() const override;
- int length() const override;
-
- QByteArray decrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override;
- QByteArray encrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override;
-
- static TlsKeyOpenSSL *publicKeyFromX509(X509 *x);
-
- union {
- EVP_PKEY *opaque;
- RSA *rsa;
- DSA *dsa;
- DH *dh;
-#ifndef OPENSSL_NO_EC
- EC_KEY *ec;
-#endif
- };
-
- bool fromEVP_PKEY(EVP_PKEY *pkey);
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLSKEY_OPENSSL_H
diff --git a/src/network/ssl/qtlskey_schannel.cpp b/src/network/ssl/qtlskey_schannel.cpp
deleted file mode 100644
index e788eac03a..0000000000
--- a/src/network/ssl/qtlskey_schannel.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qssl_p.h"
-#include "qtlskey_schannel_p.h"
-#include "qtlsbackend_p.h"
-#include "qsslkey_p.h"
-#include "qsslkey.h"
-
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qbytearray.h>
-
-#include <QtCore/qt_windows.h>
-#include <wincrypt.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
-{
- switch (cipher) {
- case QTlsPrivate::Cipher::DesCbc:
- return BCRYPT_DES_ALGORITHM;
- case QTlsPrivate::Cipher::DesEde3Cbc:
- return BCRYPT_3DES_ALGORITHM;
- case QTlsPrivate::Cipher::Rc2Cbc:
- return BCRYPT_RC2_ALGORITHM;
- case QTlsPrivate::Cipher::Aes128Cbc:
- case QTlsPrivate::Cipher::Aes192Cbc:
- case QTlsPrivate::Cipher::Aes256Cbc:
- return BCRYPT_AES_ALGORITHM;
- }
- Q_UNREACHABLE();
-}
-
-BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
-{
- BCRYPT_ALG_HANDLE handle;
- NTSTATUS status = BCryptOpenAlgorithmProvider(
- &handle, // phAlgorithm
- getName(cipher), // pszAlgId
- nullptr, // pszImplementation
- 0 // dwFlags
- );
- if (status < 0) {
- qCWarning(lcTlsBackend, "Failed to open algorithm handle (%ld)!", status);
- return nullptr;
- }
-
- return handle;
-}
-
-BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
- const QByteArray &key)
-{
- BCRYPT_KEY_HANDLE keyHandle;
- NTSTATUS status = BCryptGenerateSymmetricKey(
- handle, // hAlgorithm
- &keyHandle, // phKey
- nullptr, // pbKeyObject (can ignore)
- 0, // cbKeyObject (also ignoring)
- reinterpret_cast<unsigned char *>(const_cast<char *>(key.data())), // pbSecret
- ULONG(key.length()), // cbSecret
- 0 // dwFlags
- );
- if (status < 0) {
- qCWarning(lcTlsBackend, "Failed to generate symmetric key (%ld)!", status);
- return nullptr;
- }
-
- status = BCryptSetProperty(
- keyHandle, // hObject
- BCRYPT_CHAINING_MODE, // pszProperty
- reinterpret_cast<UCHAR *>(const_cast<wchar_t *>(BCRYPT_CHAIN_MODE_CBC)), // pbInput
- ARRAYSIZE(BCRYPT_CHAIN_MODE_CBC), // cbInput
- 0 // dwFlags
- );
- if (status < 0) {
- BCryptDestroyKey(keyHandle);
- qCWarning(lcTlsBackend, "Failed to change the symmetric key's chaining mode (%ld)!", status);
- return nullptr;
- }
- return keyHandle;
-}
-
-QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv, bool encrypt)
-{
- BCRYPT_ALG_HANDLE handle = getHandle(cipher);
- if (!handle)
- return {};
- auto handleDealloc = qScopeGuard([&handle]() {
- BCryptCloseAlgorithmProvider(handle, 0);
- });
-
- BCRYPT_KEY_HANDLE keyHandle = generateSymmetricKey(handle, key);
- if (!keyHandle)
- return {};
- auto keyHandleDealloc = qScopeGuard([&keyHandle]() {
- BCryptDestroyKey(keyHandle);
- });
-
- QByteArray ivCopy = iv; // This gets modified, so we take a copy
-
- ULONG sizeNeeded = 0;
- QVarLengthArray<unsigned char> output;
- auto cryptFunction = encrypt ? BCryptEncrypt : BCryptDecrypt;
- for (int i = 0; i < 2; i++) {
- output.resize(int(sizeNeeded));
- auto input = reinterpret_cast<unsigned char *>(const_cast<char *>(data.data()));
- // Need to call it twice because the first iteration lets us know the size needed.
- NTSTATUS status = cryptFunction(
- keyHandle, // hKey
- input, // pbInput
- ULONG(data.length()), // cbInput
- nullptr, // pPaddingInfo
- reinterpret_cast<unsigned char *>(ivCopy.data()), // pbIV
- ULONG(ivCopy.length()), // cbIV
- sizeNeeded ? output.data() : nullptr, // pbOutput
- ULONG(output.length()), // cbOutput
- &sizeNeeded, // pcbResult
- BCRYPT_BLOCK_PADDING // dwFlags
- );
- if (status < 0) {
- qCWarning(lcTlsBackend, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
- return {};
- }
- }
-
- return QByteArray(reinterpret_cast<const char *>(output.constData()), int(sizeNeeded));
-}
-} // anonymous namespace
-
-namespace QTlsPrivate {
-
-QByteArray TlsKeySchannel::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv) const
-{
- return doCrypt(cipher, data, key, iv, false);
-}
-
-QByteArray TlsKeySchannel::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv) const
-{
- return doCrypt(cipher, data, key, iv, true);
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
diff --git a/src/network/ssl/qtlskey_schannel_p.h b/src/network/ssl/qtlskey_schannel_p.h
deleted file mode 100644
index 72747e7fa6..0000000000
--- a/src/network/ssl/qtlskey_schannel_p.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSKEY_SCHANNEL_P_H
-#define QTLSKEY_SCHANNEL_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlskey_generic_p.h>
-
-#include <QtCore/qglobal.h>
-
-QT_REQUIRE_CONFIG(ssl);
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class TlsKeySchannel final : public TlsKeyGeneric
-{
-public:
- using TlsKeyGeneric::TlsKeyGeneric;
-
- QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv) const override;
- QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv) const override;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLSKEY_SCHANNEL_P_H
-
diff --git a/src/network/ssl/qtlskey_st.cpp b/src/network/ssl/qtlskey_st.cpp
deleted file mode 100644
index c551729c24..0000000000
--- a/src/network/ssl/qtlskey_st.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qtlskey_st_p.h"
-#include "qsslkey_p.h"
-
-#include <qbytearray.h>
-
-#include <CommonCrypto/CommonCrypto.h>
-
-#include <cstddef>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-namespace {
-
-// Before this code was located in qsslkey_mac.cpp.
-QByteArray wrapCCCrypt(CCOperation ccOp, QSslKeyPrivate::Cipher cipher,
- const QByteArray &data, const QByteArray &key,
- const QByteArray &iv)
-{
- int blockSize = {};
- CCAlgorithm ccAlgorithm = {};
- switch (cipher) {
- case Cipher::DesCbc:
- blockSize = kCCBlockSizeDES;
- ccAlgorithm = kCCAlgorithmDES;
- break;
- case Cipher::DesEde3Cbc:
- blockSize = kCCBlockSize3DES;
- ccAlgorithm = kCCAlgorithm3DES;
- break;
- case Cipher::Rc2Cbc:
- blockSize = kCCBlockSizeRC2;
- ccAlgorithm = kCCAlgorithmRC2;
- break;
- case Cipher::Aes128Cbc:
- case Cipher::Aes192Cbc:
- case Cipher::Aes256Cbc:
- blockSize = kCCBlockSizeAES128;
- ccAlgorithm = kCCAlgorithmAES;
- break;
- }
- std::size_t plainLength = 0;
- QByteArray plain(data.size() + blockSize, 0);
- CCCryptorStatus status = CCCrypt(ccOp, ccAlgorithm, kCCOptionPKCS7Padding,
- key.constData(), std::size_t(key.size()),
- iv.constData(), data.constData(), std::size_t(data.size()),
- plain.data(), std::size_t(plain.size()), &plainLength);
- if (status == kCCSuccess)
- return plain.left(int(plainLength));
-
- return {};
-}
-
-} // Unnamed namespace.
-
-QByteArray TlsKeySecureTransport::decrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const
-{
- return wrapCCCrypt(kCCDecrypt, cipher, data, key, iv);
-}
-
-QByteArray TlsKeySecureTransport::encrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const
-{
- return wrapCCCrypt(kCCEncrypt, cipher, data, key, iv);
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qtlskey_st_p.h b/src/network/ssl/qtlskey_st_p.h
deleted file mode 100644
index 7088daf39a..0000000000
--- a/src/network/ssl/qtlskey_st_p.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QTLSKEY_ST_P_H
-#define QTLSKEY_ST_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlskey_generic_p.h>
-
-#include <QtCore/qglobal.h>
-
-QT_REQUIRE_CONFIG(ssl);
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class TlsKeySecureTransport final : public TlsKeyGeneric
-{
-public:
- using TlsKeyGeneric::TlsKeyGeneric;
-
- QByteArray decrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override;
- QByteArray encrypt(Cipher cipher, const QByteArray &data,
- const QByteArray &key, const QByteArray &iv) const override;
-
- Q_DISABLE_COPY_MOVE(TlsKeySecureTransport)
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QTLSKEY_ST_P_H
diff --git a/src/network/ssl/qwincrypt_p.h b/src/network/ssl/qwincrypt_p.h
deleted file mode 100644
index 2a7bd1fae2..0000000000
--- a/src/network/ssl/qwincrypt_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QWINCRYPT_P_H
-#define QWINCRYPT_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.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include <QtCore/qt_windows.h>
-
-#include <QtCore/qglobal.h>
-
-#include <wincrypt.h>
-#ifndef HCRYPTPROV_LEGACY
-#define HCRYPTPROV_LEGACY HCRYPTPROV
-#endif // !HCRYPTPROV_LEGACY
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-struct QHCertStoreDeleter {
- void operator()(HCERTSTORE store)
- {
- CertCloseStore(store, 0);
- }
-};
-
-// A simple RAII type used by Schannel code and Window CA fetcher class:
-using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
-
-QT_END_NAMESPACE
-
-#endif // QWINCRYPT_P_H
diff --git a/src/network/ssl/qwindowscarootfetcher.cpp b/src/network/ssl/qwindowscarootfetcher.cpp
deleted file mode 100644
index b675ac8d4e..0000000000
--- a/src/network/ssl/qwindowscarootfetcher.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qwindowscarootfetcher_p.h"
-
-#include <QtCore/QThread>
-#include <QtGlobal>
-
-#include <QtCore/qscopeguard.h>
-
-#ifdef QSSLSOCKET_DEBUG
-#include "qssl_p.h" // for debug categories
-#include <QtCore/QElapsedTimer>
-#endif
-
-#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
-
-#if QT_CONFIG(openssl)
-#include "qopenssl_p.h"
-#include "qx509_openssl_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsCaRootFetcherThread : public QThread
-{
-public:
- QWindowsCaRootFetcherThread()
- {
- qRegisterMetaType<QSslCertificate>();
- setObjectName(QStringLiteral("QWindowsCaRootFetcher"));
- start();
- }
- ~QWindowsCaRootFetcherThread()
- {
- quit();
- wait(15500); // worst case, a running request can block for 15 seconds
- }
-};
-
-Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
-
-#if QT_CONFIG(openssl)
-namespace {
-// TLSTODO: we have to ask the currently active TLS backend about verification
-// support and get a function pointer. QT_CONFIG(openssl) check is becoming useless
-// as soon as we have several plugins.
-const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &caCertificates,
- PCCERT_CHAIN_CONTEXT chainContext,
- const QString &peerVerifyName)
-{
- // We ended up here because OpenSSL verification failed to
- // build a chain, with intermediate certificate missing
- // but "Authority Information Access" extension present.
- // Also, apparently the normal CA fetching path was disabled
- // by setting custom CA certificates. We convert wincrypt's
- // structures in QSslCertificate and give OpenSSL the second
- // chance to verify the now (apparently) complete chain.
- // In addition, wincrypt gives us a benifit of some checks
- // we don't have in OpenSSL back-end.
- Q_ASSERT(chainContext);
-
- if (!chainContext->cChain)
- return {};
-
- QList<QSslCertificate> verifiedChain;
-
- CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
- if (!chain)
- return {};
-
- if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
- return {}; // No need to mess with OpenSSL (the chain is still incomplete).
-
- for (DWORD i = 0; i < chain->cElement; ++i) {
- CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
- QSslCertificate cert(QByteArray(reinterpret_cast<const char*>(element->pCertContext->pbCertEncoded),
- int(element->pCertContext->cbCertEncoded)), QSsl::Der);
-
- if (cert.isBlacklisted())
- return {};
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) // Good to know!
- return {};
-
- if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
- return {};
-
- verifiedChain.append(cert);
- }
-
- // We rely on OpenSSL's ability to find other problems.
- const auto tlsErrors = QTlsPrivate::X509CertificateOpenSSL::verify(caCertificates, verifiedChain, peerVerifyName);
- if (tlsErrors.size())
- verifiedChain.clear();
-
- return verifiedChain;
-}
-
-} // unnamed namespace
-#endif // QT_CONFIG(openssl)
-
-QWindowsCaRootFetcher::QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
- const QList<QSslCertificate> &caCertificates, const QString &hostName)
- : cert(certificate), mode(sslMode), explicitlyTrustedCAs(caCertificates), peerVerifyName(hostName)
-{
- moveToThread(windowsCaRootFetcherThread());
-}
-
-QWindowsCaRootFetcher::~QWindowsCaRootFetcher()
-{
-}
-
-void QWindowsCaRootFetcher::start()
-{
- QByteArray der = cert.toDer();
- PCCERT_CONTEXT wincert = CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)der.constData(), der.length());
- if (!wincert) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl, "QWindowsCaRootFetcher failed to convert certificate to windows form");
-#endif
- emit finished(cert, QSslCertificate());
- deleteLater();
- return;
- }
-
- CERT_CHAIN_PARA parameters;
- memset(&parameters, 0, sizeof(parameters));
- parameters.cbSize = sizeof(parameters);
- // set key usage constraint
- parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
- parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
- LPSTR oid = (LPSTR)(mode == QSslSocket::SslClientMode ? szOID_PKIX_KP_SERVER_AUTH : szOID_PKIX_KP_CLIENT_AUTH);
- parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
-
-#ifdef QSSLSOCKET_DEBUG
- QElapsedTimer stopwatch;
- stopwatch.start();
-#endif
- PCCERT_CHAIN_CONTEXT chain;
- auto additionalStore = createAdditionalStore();
- BOOL result = CertGetCertificateChain(
- nullptr, //default engine
- wincert,
- nullptr, //current date/time
- additionalStore.get(), //default store (nullptr) or CAs an application trusts
- &parameters,
- 0, //default dwFlags
- nullptr, //reserved
- &chain);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher" << stopwatch.elapsed() << "ms to get chain";
-#endif
-
- QSslCertificate trustedRoot;
- if (result) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QWindowsCaRootFetcher - examining windows chains";
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED";
- else
- qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
- if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
- qCDebug(lcSsl) << " - SELF SIGNED";
- qCDebug(lcSsl) << "QWindowsCaRootFetcher - dumping simple chains";
- for (unsigned int i = 0; i < chain->cChain; i++) {
- if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
- qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
- else
- qCDebug(lcSsl) << " - UNTRUSTED SIMPLE CHAIN" << i << "reason:" << chain->rgpChain[i]->TrustStatus.dwErrorStatus;
- for (unsigned int j = 0; j < chain->rgpChain[i]->cElement; j++) {
- QSslCertificate foundCert(QByteArray((const char *)chain->rgpChain[i]->rgpElement[j]->pCertContext->pbCertEncoded
- , chain->rgpChain[i]->rgpElement[j]->pCertContext->cbCertEncoded), QSsl::Der);
- qCDebug(lcSsl) << " - " << foundCert;
- }
- }
- qCDebug(lcSsl) << " - and" << chain->cLowerQualityChainContext << "low quality chains"; //expect 0, we haven't asked for them
-#endif
-
- //based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa377182%28v=vs.85%29.aspx
- //about the final chain rgpChain[cChain-1] which must begin with a trusted root to be valid
- if (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && chain->cChain > 0) {
- const PCERT_SIMPLE_CHAIN finalChain = chain->rgpChain[chain->cChain - 1];
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa377544%28v=vs.85%29.aspx
- // rgpElement[0] is the end certificate chain element. rgpElement[cElement-1] is the self-signed "root" certificate element.
- if (finalChain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR
- && finalChain->cElement > 0) {
- trustedRoot = QSslCertificate(QByteArray((const char *)finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->pbCertEncoded
- , finalChain->rgpElement[finalChain->cElement - 1]->pCertContext->cbCertEncoded), QSsl::Der);
- }
- } else if (explicitlyTrustedCAs.size()) {
- // Setting custom CA in configuration, and those CAs are not trusted by MS.
-#if QT_CONFIG(openssl)
- const auto verifiedChain = buildVerifiedChain(explicitlyTrustedCAs, chain, peerVerifyName);
- if (verifiedChain.size())
- trustedRoot = verifiedChain.last();
-#else
- //It's only OpenSSL code-path that can trigger such a fetch.
- Q_UNREACHABLE();
-#endif
- }
- CertFreeCertificateChain(chain);
- }
- CertFreeCertificateContext(wincert);
-
- emit finished(cert, trustedRoot);
- deleteLater();
-}
-
-QHCertStorePointer QWindowsCaRootFetcher::createAdditionalStore() const
-{
- QHCertStorePointer customStore;
- if (explicitlyTrustedCAs.isEmpty())
- return customStore;
-
- if (HCERTSTORE rawPtr = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nullptr)) {
- customStore.reset(rawPtr);
-
- unsigned rootsAdded = 0;
- for (const QSslCertificate &caCert : explicitlyTrustedCAs) {
- const auto der = caCert.toDer();
- PCCERT_CONTEXT winCert = CertCreateCertificateContext(X509_ASN_ENCODING,
- reinterpret_cast<const BYTE *>(der.data()),
- DWORD(der.length()));
- if (!winCert) {
-#if defined(QSSLSOCKET_DEBUG)
- qCWarning(lcSsl) << "CA fetcher, failed to convert QSslCertificate"
- << "to the native representation";
-#endif // QSSLSOCKET_DEBUG
- continue;
- }
- const auto deleter = qScopeGuard([winCert](){
- CertFreeCertificateContext(winCert);
- });
- if (CertAddCertificateContextToStore(customStore.get(), winCert, CERT_STORE_ADD_ALWAYS, nullptr))
- ++rootsAdded;
-#if defined(QSSLSOCKET_DEBUG)
- else //Why assert? With flags we're using and winCert check - should not happen!
- Q_ASSERT("CertAddCertificateContextToStore() failed");
-#endif // QSSLSOCKET_DEBUG
- }
- if (!rootsAdded) //Useless store, no cert was added.
- customStore.reset();
-#if defined(QSSLSOCKET_DEBUG)
- } else {
-
- qCWarning(lcSsl) << "CA fetcher, failed to create a custom"
- << "store for explicitly trusted CA certificate";
-#endif // QSSLSOCKET_DEBUG
- }
-
- return customStore;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qwindowscarootfetcher_p.h b/src/network/ssl/qwindowscarootfetcher_p.h
deleted file mode 100644
index ee0d07c1e0..0000000000
--- a/src/network/ssl/qwindowscarootfetcher_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QWINDOWSCAROOTFETCHER_P_H
-#define QWINDOWSCAROOTFETCHER_P_H
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QObject>
-
-#include "qsslcertificate.h"
-#include "qsslsocket.h"
-
-#include "qwincrypt_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.
-//
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsCaRootFetcher : public QObject
-{
- Q_OBJECT
-public:
- QWindowsCaRootFetcher(const QSslCertificate &certificate, QSslSocket::SslMode sslMode,
- const QList<QSslCertificate> &caCertificates = {},
- const QString &hostName = {});
- ~QWindowsCaRootFetcher();
-public slots:
- void start();
-signals:
- void finished(QSslCertificate brokenChain, QSslCertificate caroot);
-private:
- QHCertStorePointer createAdditionalStore() const;
-
- QSslCertificate cert;
- QSslSocket::SslMode mode;
- // In case the application set CA certificates in the configuration,
- // in the past we did not load missing certs. But this disables
- // recoverable case when a certificate has Authority Information Access
- // extension. So we try to fetch in this scenario also, but in case
- // explicitly trusted root was not in a system store, we'll do
- // additional checks, thus we need 'peerVerifyName':
- QList<QSslCertificate> explicitlyTrustedCAs;
- QString peerVerifyName;
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSCAROOTFETCHER_P_H
diff --git a/src/network/ssl/qx509_base.cpp b/src/network/ssl/qx509_base.cpp
deleted file mode 100644
index d7b7b81606..0000000000
--- a/src/network/ssl/qx509_base.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qx509_base_p.h"
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-QByteArray X509CertificateBase::subjectInfoToString(QSslCertificate::SubjectInfo info)
-{
- QByteArray str;
- switch (info) {
- case QSslCertificate::Organization: str = QByteArray("O"); break;
- case QSslCertificate::CommonName: str = QByteArray("CN"); break;
- case QSslCertificate::LocalityName: str = QByteArray("L"); break;
- case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
- case QSslCertificate::CountryName: str = QByteArray("C"); break;
- case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
- case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
- case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
- case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
- }
-
- return str;
-}
-
-bool X509CertificateBase::matchLineFeed(const QByteArray &pem, int *offset)
-{
- Q_ASSERT(offset);
-
- char ch = 0;
- // ignore extra whitespace at the end of the line
- while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
- ++*offset;
-
- if (ch == '\n') {
- *offset += 1;
- return true;
- }
-
- if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
- *offset += 2;
- return true;
- }
-
- return false;
-}
-
-bool X509CertificateBase::isNull() const
-{
- return null;
-}
-
-QByteArray X509CertificateBase::version() const
-{
- return versionString;
-}
-
-QByteArray X509CertificateBase::serialNumber() const
-{
- return serialNumberString;
-}
-
-QStringList X509CertificateBase::issuerInfo(QSslCertificate::SubjectInfo info) const
-{
- return issuerInfo(subjectInfoToString(info));
-}
-
-QStringList X509CertificateBase::issuerInfo(const QByteArray &attribute) const
-{
- return issuerInfoEntries.values(attribute);
-}
-
-QStringList X509CertificateBase::subjectInfo(QSslCertificate::SubjectInfo info) const
-{
- return subjectInfo(subjectInfoToString(info));
-}
-
-QStringList X509CertificateBase::subjectInfo(const QByteArray &attribute) const
-{
- return subjectInfoEntries.values(attribute);
-}
-
-QList<QByteArray> X509CertificateBase::subjectInfoAttributes() const
-{
- return subjectInfoEntries.uniqueKeys();
-}
-
-QList<QByteArray> X509CertificateBase::issuerInfoAttributes() const
-{
- return issuerInfoEntries.uniqueKeys();
-}
-
-QDateTime X509CertificateBase::effectiveDate() const
-{
- return notValidBefore;
-}
-
-QDateTime X509CertificateBase::expiryDate() const
-{
- return notValidAfter;
-}
-
-qsizetype X509CertificateBase::numberOfExtensions() const
-{
- return extensions.size();
-}
-
-QString X509CertificateBase::oidForExtension(qsizetype index) const
-{
- Q_ASSERT(validIndex(index));
- return extensions[index].oid;
-}
-
-QString X509CertificateBase::nameForExtension(qsizetype index) const
-{
- Q_ASSERT(validIndex(index));
- return extensions[index].name;
-}
-
-QVariant X509CertificateBase::valueForExtension(qsizetype index) const
-{
- Q_ASSERT(validIndex(index));
- return extensions[index].value;
-}
-
-bool X509CertificateBase::isExtensionCritical(qsizetype index) const
-{
- Q_ASSERT(validIndex(index));
- return extensions[index].critical;
-}
-
-bool X509CertificateBase::isExtensionSupported(qsizetype index) const
-{
- Q_ASSERT(validIndex(index));
- return extensions[index].supported;
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qx509_base_p.h b/src/network/ssl/qx509_base_p.h
deleted file mode 100644
index 6905848e46..0000000000
--- a/src/network/ssl/qx509_base_p.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QX509CERTIFICATE_BASE_P_H
-#define QX509CERTIFICATE_BASE_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlsbackend_p.h>
-
-#include <qssl.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class X509CertificateBase : public X509Certificate
-{
-public:
- bool isNull() const override;
- QByteArray version() const override;
- QByteArray serialNumber() const override;
- QStringList issuerInfo(QSslCertificate::SubjectInfo info) const override;
- QStringList issuerInfo(const QByteArray &attribute) const override;
- QStringList subjectInfo(QSslCertificate::SubjectInfo info) const override;
- QStringList subjectInfo(const QByteArray &attribute) const override;
- QList<QByteArray> subjectInfoAttributes() const override;
- QList<QByteArray> issuerInfoAttributes() const override;
- QDateTime effectiveDate() const override;
- QDateTime expiryDate() const override;
-
- qsizetype numberOfExtensions() const override;
- QString oidForExtension(qsizetype index) const override;
- QString nameForExtension(qsizetype index) const override;
- QVariant valueForExtension(qsizetype index) const override;
- bool isExtensionCritical(qsizetype index) const override;
- bool isExtensionSupported(qsizetype index) const override;
-
- static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
- static bool matchLineFeed(const QByteArray &pem, int *offset);
-
-protected:
- bool validIndex(qsizetype index) const
- {
- return index >= 0 && index < extensions.size();
- }
-
- bool null = true;
- QByteArray versionString;
- QByteArray serialNumberString;
-
- QMultiMap<QByteArray, QString> issuerInfoEntries;
- QMultiMap<QByteArray, QString> subjectInfoEntries;
- QDateTime notValidAfter;
- QDateTime notValidBefore;
-
- struct X509CertificateExtension
- {
- QString oid;
- QString name;
- QVariant value;
- bool critical = false;
- bool supported = false;
- };
-
- QList<X509CertificateExtension> extensions;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QX509CERTIFICATE_BASE_P_H
diff --git a/src/network/ssl/qx509_generic.cpp b/src/network/ssl/qx509_generic.cpp
deleted file mode 100644
index 40178f5e7c..0000000000
--- a/src/network/ssl/qx509_generic.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qsslcertificate_p.h"
-#include "qx509_generic_p.h"
-#include "qasn1element_p.h"
-
-#include "qssl_p.h"
-
-#include <qhostaddress.h>
-#include <qendian.h>
-#include <qhash.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-namespace {
-
-QByteArray colonSeparatedHex(const QByteArray &value)
-{
- const int size = value.size();
- int i = 0;
- while (i < size && !value.at(i)) // skip leading zeros
- ++i;
-
- return value.mid(i).toHex(':');
-}
-
-} // Unnamed namespace.
-
-bool X509CertificateGeneric::isEqual(const X509Certificate &rhs) const
-{
- const auto &other = static_cast<const X509CertificateGeneric &>(rhs);
- return derData == other.derData;
-}
-
-bool X509CertificateGeneric::isSelfSigned() const
-{
- if (null)
- return false;
-
- qCWarning(lcTlsBackend, "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
- "is actually signed. It just checks whether issuer and subject are identical");
- return subjectMatchesIssuer;
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> X509CertificateGeneric::subjectAlternativeNames() const
-{
- return saNames;
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-QByteArray X509CertificateGeneric::toPem() const
-{
- QByteArray array = toDer();
- // Convert to Base64 - wrap at 64 characters.
- array = array.toBase64();
- QByteArray tmp;
- for (int i = 0; i <= array.size() - 64; i += 64) {
- tmp += QByteArray::fromRawData(array.data() + i, 64);
- tmp += '\n';
- }
- if (int remainder = array.size() % 64) {
- tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
- tmp += '\n';
- }
-
- return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
-}
-
-QByteArray X509CertificateGeneric::toDer() const
-{
- return derData;
-}
-
-QString X509CertificateGeneric::toText() const
-{
- Q_UNIMPLEMENTED();
- return {};
-}
-
-Qt::HANDLE X509CertificateGeneric::handle() const
-{
- Q_UNIMPLEMENTED();
- return nullptr;
-}
-
-size_t X509CertificateGeneric::hash(size_t seed) const noexcept
-{
- return qHash(toDer(), seed);
-}
-
-QList<QSslCertificate> X509CertificateGeneric::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
- int offset = 0;
- while (count == -1 || certificates.size() < count) {
- int startPos = pem.indexOf(BEGINCERTSTRING, offset);
- if (startPos == -1)
- break;
- startPos += sizeof(BEGINCERTSTRING) - 1;
- if (!matchLineFeed(pem, &startPos))
- break;
-
- int endPos = pem.indexOf(ENDCERTSTRING, startPos);
- if (endPos == -1)
- break;
-
- offset = endPos + sizeof(ENDCERTSTRING) - 1;
- if (offset < pem.size() && !matchLineFeed(pem, &offset))
- break;
-
- QByteArray decoded = QByteArray::fromBase64(
- QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
- certificates << certificatesFromDer(decoded, 1);;
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> X509CertificateGeneric::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
-
- QByteArray data = der;
- while (count == -1 || certificates.size() < count) {
- QSslCertificate cert;
- auto *certBackend = QTlsBackend::backend<X509CertificateGeneric>(cert);
- if (!certBackend->parse(data))
- break;
-
- certificates << cert;
- data.remove(0, certBackend->derData.size());
- }
-
- return certificates;
-}
-
-bool X509CertificateGeneric::parse(const QByteArray &data)
-{
- QAsn1Element root;
-
- QDataStream dataStream(data);
- if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
- return false;
-
- QDataStream rootStream(root.value());
- QAsn1Element cert;
- if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
- return false;
-
- // version or serial number
- QAsn1Element elem;
- QDataStream certStream(cert.value());
- if (!elem.read(certStream))
- return false;
-
- if (elem.type() == QAsn1Element::Context0Type) {
- QDataStream versionStream(elem.value());
- if (!elem.read(versionStream)
- || elem.type() != QAsn1Element::IntegerType
- || elem.value().isEmpty())
- return false;
-
- versionString = QByteArray::number(elem.value().at(0) + 1);
- if (!elem.read(certStream))
- return false;
- } else {
- versionString = QByteArray::number(1);
- }
-
- // serial number
- if (elem.type() != QAsn1Element::IntegerType)
- return false;
- serialNumberString = colonSeparatedHex(elem.value());
-
- // algorithm ID
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- // issuer info
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
- issuerInfoEntries = elem.toInfo();
-
- // validity period
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QDataStream validityStream(elem.value());
- if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
- return false;
-
- notValidBefore = elem.toDateTime();
- if (!notValidBefore.isValid())
- return false;
-
- if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
- return false;
-
- notValidAfter = elem.toDateTime();
- if (!notValidAfter.isValid())
- return false;
-
-
- // subject name
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
- subjectInfoEntries = elem.toInfo();
- subjectMatchesIssuer = issuerDer == subjectDer;
-
- // public key
- qint64 keyStart = certStream.device()->pos();
- if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- publicKeyDerData.resize(certStream.device()->pos() - keyStart);
- QDataStream keyStream(elem.value());
- if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
-
- // key algorithm
- if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
- return false;
-
- const QByteArray oid = elem.toObjectId();
- if (oid == RSA_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Rsa;
- else if (oid == DSA_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Dsa;
- else if (oid == EC_ENCRYPTION_OID)
- publicKeyAlgorithm = QSsl::Ec;
- else
- publicKeyAlgorithm = QSsl::Opaque;
-
- certStream.device()->seek(keyStart);
- certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
-
- // extensions
- while (elem.read(certStream)) {
- if (elem.type() == QAsn1Element::Context3Type) {
- if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
- QDataStream extStream(elem.value());
- while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
- X509CertificateExtension extension;
- if (!parseExtension(elem.value(), extension))
- return false;
-
- if (extension.oid == QLatin1String("2.5.29.17")) {
- // subjectAltName
-
- // Note, parseExtension() returns true for this extensions,
- // but considers it to be unsupported and assignes a useless
- // value. OpenSSL also treats this extension as unsupported,
- // but properly creates a map with 'name' and 'value' taken
- // from the extension. We only support 'email', 'IP' and 'DNS',
- // but this is what our subjectAlternativeNames map can contain
- // anyway.
- QVariantMap extValue;
- QAsn1Element sanElem;
- if (sanElem.read(extension.value.toByteArray()) && sanElem.type() == QAsn1Element::SequenceType) {
- QDataStream nameStream(sanElem.value());
- QAsn1Element nameElem;
- while (nameElem.read(nameStream)) {
- switch (nameElem.type()) {
- case QAsn1Element::Rfc822NameType:
- saNames.insert(QSsl::EmailEntry, nameElem.toString());
- extValue[QStringLiteral("email")] = nameElem.toString();
- break;
- case QAsn1Element::DnsNameType:
- saNames.insert(QSsl::DnsEntry, nameElem.toString());
- extValue[QStringLiteral("DNS")] = nameElem.toString();
- break;
- case QAsn1Element::IpAddressType: {
- QHostAddress ipAddress;
- QByteArray ipAddrValue = nameElem.value();
- switch (ipAddrValue.length()) {
- case 4: // IPv4
- ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(ipAddrValue.data())));
- break;
- case 16: // IPv6
- ipAddress = QHostAddress(reinterpret_cast<quint8 *>(ipAddrValue.data()));
- break;
- default: // Unknown IP address format
- break;
- }
- if (!ipAddress.isNull()) {
- saNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
- extValue[QStringLiteral("IP")] = ipAddress.toString();
- }
- break;
- }
- default:
- break;
- }
- }
- extension.value = extValue;
- extension.supported = true;
- }
- }
-
- extensions << extension;
- }
- }
- }
- }
-
- derData = data.left(dataStream.device()->pos());
- null = false;
- return true;
-}
-
-bool X509CertificateGeneric::parseExtension(const QByteArray &data, X509CertificateExtension &extension)
-{
- bool ok = false;
- bool critical = false;
- QAsn1Element oidElem, valElem;
-
- QDataStream seqStream(data);
-
- // oid
- if (!oidElem.read(seqStream) || oidElem.type() != QAsn1Element::ObjectIdentifierType)
- return false;
-
- const QByteArray oid = oidElem.toObjectId();
- // critical and value
- if (!valElem.read(seqStream))
- return false;
-
- if (valElem.type() == QAsn1Element::BooleanType) {
- critical = valElem.toBool(&ok);
-
- if (!ok || !valElem.read(seqStream))
- return false;
- }
-
- if (valElem.type() != QAsn1Element::OctetStringType)
- return false;
-
- // interpret value
- QAsn1Element val;
- bool supported = true;
- QVariant value;
- if (oid == "1.3.6.1.5.5.7.1.1") {
- // authorityInfoAccess
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
- QVariantMap result;
- const auto elems = val.toList();
- for (const QAsn1Element &el : elems) {
- const auto items = el.toList();
- if (items.size() != 2)
- return false;
- const QString key = QString::fromLatin1(items.at(0).toObjectName());
- switch (items.at(1).type()) {
- case QAsn1Element::Rfc822NameType:
- case QAsn1Element::DnsNameType:
- case QAsn1Element::UniformResourceIdentifierType:
- result[key] = items.at(1).toString();
- break;
- }
- }
- value = result;
- } else if (oid == "2.5.29.14") {
- // subjectKeyIdentifier
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::OctetStringType)
- return false;
- value = colonSeparatedHex(val.value()).toUpper();
- } else if (oid == "2.5.29.19") {
- // basicConstraints
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
-
- QVariantMap result;
- const auto items = val.toList();
- if (items.size() > 0) {
- result[QStringLiteral("ca")] = items.at(0).toBool(&ok);
- if (!ok)
- return false;
- } else {
- result[QStringLiteral("ca")] = false;
- }
- if (items.size() > 1) {
- result[QStringLiteral("pathLenConstraint")] = items.at(1).toInteger(&ok);
- if (!ok)
- return false;
- }
- value = result;
- } else if (oid == "2.5.29.35") {
- // authorityKeyIdentifier
- if (!val.read(valElem.value()) || val.type() != QAsn1Element::SequenceType)
- return false;
- QVariantMap result;
- const auto elems = val.toList();
- for (const QAsn1Element &el : elems) {
- if (el.type() == 0x80) {
- const QString key = QStringLiteral("keyid");
- result[key] = el.value().toHex();
- } else if (el.type() == 0x82) {
- const QString serial = QStringLiteral("serial");
- result[serial] = colonSeparatedHex(el.value());
- }
- }
- value = result;
- } else {
- supported = false;
- value = valElem.value();
- }
-
- extension.critical = critical;
- extension.supported = supported;
- extension.oid = QString::fromLatin1(oid);
- extension.name = QString::fromLatin1(oidElem.toObjectName());
- extension.value = value;
-
- return true;
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qx509_generic_p.h b/src/network/ssl/qx509_generic_p.h
deleted file mode 100644
index b0dd3ec4b5..0000000000
--- a/src/network/ssl/qx509_generic_p.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-#ifndef QX509_GENERIC_P_H
-#define QX509_GENERIC_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qtlsbackend_p.h>
-#include <private/qx509_base_p.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-// TLSTODO: This class is what previously was known as qsslcertificate_qt.
-// A part of SecureTransport and Schannel plugin.
-class X509CertificateGeneric : public X509CertificateBase
-{
-public:
- bool isEqual(const X509Certificate &rhs) const override;
- bool isSelfSigned() const override;
-
- QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
- QByteArray toPem() const override;
- QByteArray toDer() const override;
- QString toText() const override;
- Qt::HANDLE handle() const override;
-
- size_t hash(size_t seed) const noexcept override;
-
- static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
- static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
-
-protected:
-
- bool subjectMatchesIssuer = false;
- QSsl::KeyAlgorithm publicKeyAlgorithm = QSsl::Rsa;
- QByteArray publicKeyDerData;
-
- QMultiMap<QSsl::AlternativeNameEntryType, QString> saNames;
- QByteArray derData;
-
- bool parse(const QByteArray &data);
- bool parseExtension(const QByteArray &data, X509CertificateExtension &extension);
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QX509_GENERIC_P_H
diff --git a/src/network/ssl/qx509_openssl.cpp b/src/network/ssl/qx509_openssl.cpp
deleted file mode 100644
index 6c4a83be0b..0000000000
--- a/src/network/ssl/qx509_openssl.cpp
+++ /dev/null
@@ -1,929 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlsbackend_openssl_p.h"
-#include "qsslcertificate_p.h"
-#include "qtlskey_openssl_p.h"
-#include "qx509_openssl_p.h"
-
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qtlsbackend_openssl_p.h"
-#include "qtls_openssl_p.h"
-#include "qsslsocket.h"
-
-#include <QtNetwork/qhostaddress.h>
-
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qendian.h>
-#include <QtCore/qhash.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-namespace {
-
-// TLSTODO: These helper functions below were static member-functions of
-// QSslCertificatePrivate, if-defed with !QT_NO_OPENSSL, no need
-// for them to be exposed this way anymore. Remove this comment when
-// plugins are ready.
-QByteArray asn1ObjectId(ASN1_OBJECT *object)
-{
- if (!object)
- return {};
-
- char buf[80] = {}; // The openssl docs a buffer length of 80 should be more than enough
- q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
-
- return QByteArray(buf);
-}
-
-QByteArray asn1ObjectName(ASN1_OBJECT *object)
-{
- if (!object)
- return {};
-
- const int nid = q_OBJ_obj2nid(object);
- if (nid != NID_undef)
- return QByteArray(q_OBJ_nid2sn(nid));
-
- return asn1ObjectId(object);
-}
-
-QMultiMap<QByteArray, QString> mapFromX509Name(X509_NAME *name)
-{
- if (!name)
- return {};
-
- QMultiMap<QByteArray, QString> info;
- for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
- X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
-
- QByteArray name = asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
- unsigned char *data = nullptr;
- int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
- info.insert(name, QString::fromUtf8((char*)data, size));
- q_CRYPTO_free(data, nullptr, 0);
- }
-
- return info;
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-QByteArray x509ToQByteArray(X509 *x509, QSsl::EncodingFormat format)
-{
- Q_ASSERT(x509);
-
- // Use i2d_X509 to convert the X509 to an array.
- const int length = q_i2d_X509(x509, nullptr);
- if (length <= 0) {
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- return {};
- }
-
- QByteArray array;
- array.resize(length);
-
- char *data = array.data();
- char **dataP = &data;
- unsigned char **dataPu = (unsigned char **)dataP;
- if (q_i2d_X509(x509, dataPu) < 0)
- return QByteArray();
-
- if (format == QSsl::Der)
- return array;
-
- // Convert to Base64 - wrap at 64 characters.
- array = array.toBase64();
- QByteArray tmp;
- for (int i = 0; i <= array.size() - 64; i += 64) {
- tmp += QByteArray::fromRawData(array.data() + i, 64);
- tmp += '\n';
- }
- if (int remainder = array.size() % 64) {
- tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
- tmp += '\n';
- }
-
- return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
-}
-
-QString x509ToText(X509 *x509)
-{
- Q_ASSERT(x509);
-
- QByteArray result;
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QString();
- const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
-
- q_X509_print(bio, x509);
-
- QVarLengthArray<char, 16384> data;
- int count = q_BIO_read(bio, data.data(), 16384);
- if ( count > 0 )
- result = QByteArray( data.data(), count );
-
- return QString::fromLatin1(result);
-}
-
-QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
-{
- // Get the extension specific method object if available
- // we cast away the const-ness here because some versions of openssl
- // don't use const for the parameters in the functions pointers stored
- // in the object.
- Q_ASSERT(ext);
-
- X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
- if (!meth) {
- ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
- Q_ASSERT(value);
- QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
- q_ASN1_STRING_length(value));
- return result;
- }
-
- void *ext_internal = q_X509V3_EXT_d2i(ext);
-
- // If this extension can be converted
- if (meth->i2v && ext_internal) {
- STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
-
- QVariantMap map;
- QVariantList list;
- bool isMap = false;
-
- for (int j = 0; j < q_SKM_sk_num(val); j++) {
- CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
- if (nval->name && nval->value) {
- isMap = true;
- map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
- } else if (nval->name) {
- list << QString::fromUtf8(nval->name);
- } else if (nval->value) {
- list << QString::fromUtf8(nval->value);
- }
- }
-
- if (isMap)
- return map;
- else
- return list;
- } else if (meth->i2s && ext_internal) {
- QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
- return result;
- } else if (meth->i2r && ext_internal) {
- QByteArray result;
-
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return result;
-
- meth->i2r(meth, ext_internal, bio, 0);
-
- char *bio_buffer;
- long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
- result = QByteArray(bio_buffer, bio_size);
-
- q_BIO_free(bio);
- return result;
- }
-
- return QVariant();
-}
-
-/*
- * Convert extensions to a variant. The naming of the keys of the map are
- * taken from RFC 5280, however we decided the capitalisation in the RFC
- * was too silly for the real world.
- */
-QVariant x509ExtensionToValue(X509_EXTENSION *ext)
-{
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- int nid = q_OBJ_obj2nid(obj);
- switch (nid) {
- case NID_basic_constraints:
- {
- BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
- if (!basic)
- return {};
- QVariantMap result;
- result[QLatin1String("ca")] = basic->ca ? true : false;
- if (basic->pathlen)
- result[QLatin1String("pathLenConstraint")] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
-
- q_BASIC_CONSTRAINTS_free(basic);
- return result;
- }
- break;
- case NID_info_access:
- {
- AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
- if (!info)
- return {};
- QVariantMap result;
- for (int i=0; i < q_SKM_sk_num(info); i++) {
- ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
-
- GENERAL_NAME *name = ad->location;
- if (name->type == GEN_URI) {
- int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
- if (len < 0 || len >= 8192) {
- // broken name
- continue;
- }
-
- const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
- const QString uri = QString::fromUtf8(uriStr, len);
-
- result[QString::fromUtf8(asn1ObjectName(ad->method))] = uri;
- } else {
- qCWarning(lcTlsBackend) << "Strange location type" << name->type;
- }
- }
-
- q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
- return result;
- }
- break;
- case NID_subject_key_identifier:
- {
- void *ext_internal = q_X509V3_EXT_d2i(ext);
- if (!ext_internal)
- return {};
- // we cast away the const-ness here because some versions of openssl
- // don't use const for the parameters in the functions pointers stored
- // in the object.
- X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
-
- return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
- }
- break;
- case NID_authority_key_identifier:
- {
- AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
- if (!auth_key)
- return {};
- QVariantMap result;
-
- // keyid
- if (auth_key->keyid) {
- QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
- auth_key->keyid->length);
- result[QLatin1String("keyid")] = keyid.toHex();
- }
-
- // issuer
- // TODO: GENERAL_NAMES
-
- // serial
- if (auth_key->serial)
- result[QLatin1String("serial")] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
-
- q_AUTHORITY_KEYID_free(auth_key);
- return result;
- }
- break;
- }
-
- return {};
-}
-
-} // Unnamed namespace
-
-extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx)
-{
- if (!ok) {
- // Store the error and at which depth the error was detected.
- using ErrorListPtr = QList<QSslErrorEntry> *;
- ErrorListPtr errors = nullptr;
-
- // Error list is attached to either 'SSL' or 'X509_STORE'.
- if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
- errors = ErrorListPtr(q_X509_STORE_get_ex_data(store, 0));
-
- if (!errors) {
- // Not found on store? Try SSL and its external data then. According to the OpenSSL's
- // documentation:
- //
- // "Whenever a X509_STORE_CTX object is created for the verification of the
- // peer's certificate during a handshake, a pointer to the SSL object is
- // stored into the X509_STORE_CTX object to identify the connection affected.
- // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
- // used with the correct index."
-
- // TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
- // This is a temporary solution for now to ease the transition.
- const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::errorOffsetInExData;
- if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
- errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
- }
-
- if (!errors) {
- qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, verification failed");
- return 0;
- }
-
- errors->append(X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
- }
- // Always return OK to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-X509CertificateOpenSSL::X509CertificateOpenSSL() = default;
-
-X509CertificateOpenSSL::~X509CertificateOpenSSL()
-{
- if (x509)
- q_X509_free(x509);
-}
-
-bool X509CertificateOpenSSL::isEqual(const X509Certificate &rhs) const
-{
- //TLSTODO: to make it safe I'll check the backend type later.
- const auto &other = static_cast<const X509CertificateOpenSSL &>(rhs);
- if (x509 && other.x509) {
- const int ret = q_X509_cmp(x509, other.x509);
- if (ret >= -1 && ret <= 1)
- return ret == 0;
- QTlsBackendOpenSSL::logAndClearErrorQueue();
- }
-
- return false;
-}
-
-bool X509CertificateOpenSSL::isSelfSigned() const
-{
- if (!x509)
- return false;
-
- return q_X509_check_issued(x509, x509) == X509_V_OK;
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString>
-X509CertificateOpenSSL::subjectAlternativeNames() const
-{
- QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
-
- if (!x509)
- return result;
-
- auto *altNames = static_cast<STACK_OF(GENERAL_NAME) *>(q_X509_get_ext_d2i(x509, NID_subject_alt_name,
- nullptr, nullptr));
- if (!altNames)
- return result;
-
- auto altName = [](ASN1_IA5STRING *ia5, int len) {
- const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(ia5));
- return QString::fromLatin1(altNameStr, len);
- };
-
- for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
- const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
- if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
- continue;
-
- const int len = q_ASN1_STRING_length(genName->d.ia5);
- if (len < 0 || len >= 8192) {
- // broken name
- continue;
- }
-
- switch (genName->type) {
- case GEN_DNS:
- result.insert(QSsl::DnsEntry, altName(genName->d.ia5, len));
- break;
- case GEN_EMAIL:
- result.insert(QSsl::EmailEntry, altName(genName->d.ia5, len));
- break;
- case GEN_IPADD: {
- QHostAddress ipAddress;
- switch (len) {
- case 4: // IPv4
- ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
- break;
- case 16: // IPv6
- ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
- break;
- default: // Unknown IP address format
- break;
- }
- if (!ipAddress.isNull())
- result.insert(QSsl::IpAddressEntry, ipAddress.toString());
- break;
- }
- default:
- break;
- }
- }
-
- q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
-
- return result;
-}
-
-TlsKey *X509CertificateOpenSSL::publicKey() const
-{
- if (!x509)
- return {};
-
- return TlsKeyOpenSSL::publicKeyFromX509(x509);
-}
-
-QByteArray X509CertificateOpenSSL::toPem() const
-{
- if (!x509)
- return {};
-
- return x509ToQByteArray(x509, QSsl::Pem);
-}
-
-QByteArray X509CertificateOpenSSL::toDer() const
-{
- if (!x509)
- return {};
-
- return x509ToQByteArray(x509, QSsl::Der);
-
-}
-QString X509CertificateOpenSSL::toText() const
-{
- if (!x509)
- return {};
-
- return x509ToText(x509);
-}
-
-Qt::HANDLE X509CertificateOpenSSL::handle() const
-{
- return Qt::HANDLE(x509);
-}
-
-size_t X509CertificateOpenSSL::hash(size_t seed) const noexcept
-{
- if (x509) {
- const EVP_MD *sha1 = q_EVP_sha1();
- unsigned int len = 0;
- unsigned char md[EVP_MAX_MD_SIZE];
- q_X509_digest(x509, sha1, md, &len);
- return qHashBits(md, len, seed);
- }
-
- return seed;
-}
-
-QSslCertificate X509CertificateOpenSSL::certificateFromX509(X509 *x509)
-{
- QSslCertificate certificate;
-
- auto *backend = QTlsBackend::backend<X509CertificateOpenSSL>(certificate);
- if (!backend || !x509)
- return certificate;
-
- ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
- if (nbef)
- backend->notValidBefore = q_getTimeFromASN1(nbef);
-
- ASN1_TIME *naft = q_X509_getm_notAfter(x509);
- if (naft)
- backend->notValidAfter = q_getTimeFromASN1(naft);
-
- backend->null = false;
- backend->x509 = q_X509_dup(x509);
-
- backend->issuerInfoEntries = mapFromX509Name(q_X509_get_issuer_name(x509));
- backend->subjectInfoEntries = mapFromX509Name(q_X509_get_subject_name(x509));
- backend->versionString = QByteArray::number(qlonglong(q_X509_get_version(x509)) + 1);
-
- if (ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(x509)) {
- QByteArray hexString;
- hexString.reserve(serialNumber->length * 3);
- for (int a = 0; a < serialNumber->length; ++a) {
- hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
- hexString += ':';
- }
- hexString.chop(1);
- backend->serialNumberString = hexString;
- }
-
- backend->parseExtensions();
-
- return certificate;
-}
-
-QList<QSslCertificate> X509CertificateOpenSSL::stackOfX509ToQSslCertificates(STACK_OF(X509) *x509)
-{
- if (!x509)
- return {};
-
- QList<QSslCertificate> certificates;
- for (int i = 0; i < q_sk_X509_num(x509); ++i) {
- if (X509 *entry = q_sk_X509_value(x509, i))
- certificates << certificateFromX509(entry);
- }
-
- return certificates;
-}
-
-QSslErrorEntry X509CertificateOpenSSL::errorEntryFromStoreContext(X509_STORE_CTX *ctx)
-{
- Q_ASSERT(ctx);
-
- return {q_X509_STORE_CTX_get_error(ctx), q_X509_STORE_CTX_get_error_depth(ctx)};
-}
-
-QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &chain,
- const QString &hostName)
-{
- // This was previously QSslSocketPrivate::verify().
- auto roots = QSslConfiguration::defaultConfiguration().caCertificates();
-#ifndef Q_OS_WIN
- // On Windows, system CA certificates are already set as default ones.
- // No need to add them again (and again) and also, if the default configuration
- // has its own set of CAs, this probably should not be amended by the ones
- // from the 'ROOT' store, since it's not what an application chose to trust.
- if (QSslSocketPrivate::rootCertOnDemandLoadingSupported())
- roots.append(QSslSocketPrivate::systemCaCertificates());
-#endif // Q_OS_WIN
- return verify(roots, chain, hostName);
-}
-
-QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &caCertificates,
- const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- // This was previously QSslSocketPrivate::verify().
- if (certificateChain.count() <= 0)
- return {QSslError(QSslError::UnspecifiedError)};
-
- QList<QSslError> errors;
- X509_STORE *certStore = q_X509_STORE_new();
- if (!certStore) {
- qCWarning(lcTlsBackend) << "Unable to create certificate store";
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
- const std::unique_ptr<X509_STORE, decltype(&q_X509_STORE_free)> storeGuard(certStore, q_X509_STORE_free);
-
- const QDateTime now = QDateTime::currentDateTimeUtc();
- for (const QSslCertificate &caCertificate : caCertificates) {
- // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
- //
- // If several CA certificates matching the name, key identifier, and
- // serial number condition are available, only the first one will be
- // examined. This may lead to unexpected results if the same CA
- // certificate is available with different expiration dates. If a
- // ``certificate expired'' verification error occurs, no other
- // certificate will be searched. Make sure to not have expired
- // certificates mixed with valid ones.
- //
- // See also: QSslContext::fromConfiguration()
- if (caCertificate.expiryDate() >= now) {
- q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle()));
- }
- }
-
- QList<QSslErrorEntry> lastErrors;
- if (!q_X509_STORE_set_ex_data(certStore, 0, &lastErrors)) {
- qCWarning(lcTlsBackend) << "Unable to attach external data (error list) to a store";
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- // Register a custom callback to get all verification errors.
- q_X509_STORE_set_verify_cb(certStore, qt_X509Callback);
-
- // Build the chain of intermediate certificates
- STACK_OF(X509) *intermediates = nullptr;
- if (certificateChain.length() > 1) {
- intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
-
- if (!intermediates) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- bool first = true;
- for (const QSslCertificate &cert : certificateChain) {
- if (first) {
- first = false;
- continue;
- }
-
- q_OPENSSL_sk_push((OPENSSL_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle()));
- }
- }
-
- X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
- if (!storeContext) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
- std::unique_ptr<X509_STORE_CTX, decltype(&q_X509_STORE_CTX_free)> ctxGuard(storeContext, q_X509_STORE_CTX_free);
-
- if (!q_X509_STORE_CTX_init(storeContext, certStore, reinterpret_cast<X509 *>(certificateChain[0].handle()), intermediates)) {
- errors << QSslError(QSslError::UnspecifiedError);
- return errors;
- }
-
- // Now we can actually perform the verification of the chain we have built.
- // We ignore the result of this function since we process errors via the
- // callback.
- (void) q_X509_verify_cert(storeContext);
- ctxGuard.reset();
- q_OPENSSL_sk_free((OPENSSL_STACK *)intermediates);
-
- // Now process the errors
-
- if (certificateChain[0].isBlacklisted())
- errors << QSslError(QSslError::CertificateBlacklisted, certificateChain[0]);
-
- // Check the certificate name against the hostname if one was specified
- if (!hostName.isEmpty() && !QSslSocketPrivate::isMatchingHostname(certificateChain[0], hostName)) {
- // No matches in common names or alternate names.
- QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
- errors << error;
- }
-
- // Translate errors from the error list into QSslErrors.
- errors.reserve(errors.size() + lastErrors.size());
- for (const auto &error : qAsConst(lastErrors))
- errors << openSSLErrorToQSslError(error.code, certificateChain.value(error.depth));
-
- return errors;
-}
-
-QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
-
- int offset = 0;
- while (count == -1 || certificates.size() < count) {
- int startPos = pem.indexOf(BEGINCERTSTRING, offset);
- if (startPos == -1)
- break;
- startPos += sizeof(BEGINCERTSTRING) - 1;
- if (!matchLineFeed(pem, &startPos))
- break;
-
- int endPos = pem.indexOf(ENDCERTSTRING, startPos);
- if (endPos == -1)
- break;
-
- offset = endPos + sizeof(ENDCERTSTRING) - 1;
- if (offset < pem.size() && !matchLineFeed(pem, &offset))
- break;
-
- QByteArray decoded = QByteArray::fromBase64(
- QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
- const unsigned char *data = (const unsigned char *)decoded.data();
-
- if (X509 *x509 = q_d2i_X509(nullptr, &data, decoded.size())) {
- certificates << certificateFromX509(x509);
- q_X509_free(x509);
- }
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
-
- const unsigned char *data = (const unsigned char *)der.data();
- int size = der.size();
-
- while (size > 0 && (count == -1 || certificates.size() < count)) {
- if (X509 *x509 = q_d2i_X509(nullptr, &data, size)) {
- certificates << certificateFromX509(x509);
- q_X509_free(x509);
- } else {
- break;
- }
- size -= ((const char *)data - der.data());
- }
-
- return certificates;
-}
-
-bool X509CertificateOpenSSL::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- // These are required
- Q_ASSERT(device);
- Q_ASSERT(key);
- Q_ASSERT(cert);
-
- // Read the file into a BIO
- QByteArray pkcs12data = device->readAll();
- if (pkcs12data.size() == 0)
- return false;
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pkcs12data.constData()), pkcs12data.size());
- if (!bio) {
- qCWarning(lcTlsBackend, "BIO_new_mem_buf returned null");
- return false;
- }
- const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
-
- // Create the PKCS#12 object
- PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
- if (!p12) {
- qCWarning(lcTlsBackend, "Unable to read PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- return false;
- }
- const auto p12Raii = qScopeGuard([p12]{q_PKCS12_free(p12);});
-
- // Extract the data
- EVP_PKEY *pkey = nullptr;
- X509 *x509 = nullptr;
- STACK_OF(X509) *ca = nullptr;
-
- if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
- qCWarning(lcTlsBackend, "Unable to parse PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- return false;
- }
-
- const auto x509Raii = qScopeGuard([x509]{q_X509_free(x509);});
- const auto keyRaii = qScopeGuard([pkey]{q_EVP_PKEY_free(pkey);});
- const auto caRaii = qScopeGuard([ca] {
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
- });
-
- // Convert to Qt types
- auto *tlsKey = QTlsBackend::backend<TlsKeyOpenSSL>(*key);
- if (!tlsKey || !tlsKey->fromEVP_PKEY(pkey)) {
- qCWarning(lcTlsBackend, "Unable to convert private key");
- return false;
- }
-
- *cert = certificateFromX509(x509);
-
- if (caCertificates)
- *caCertificates = stackOfX509ToQSslCertificates(ca);
-
- return true;
-}
-
-QSslError X509CertificateOpenSSL::openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert)
-{
- QSslError error;
- switch (errorCode) {
- case X509_V_OK:
- // X509_V_OK is also reported if the peer had no certificate.
- break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
- case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
- error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
- case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
- error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
- case X509_V_ERR_CERT_SIGNATURE_FAILURE:
- error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- error = QSslError(QSslError::CertificateNotYetValid, cert); break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- error = QSslError(QSslError::CertificateExpired, cert); break;
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- error = QSslError(QSslError::InvalidNotAfterField, cert); break;
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- error = QSslError(QSslError::SelfSignedCertificate, cert); break;
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
- case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
- error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
- case X509_V_ERR_CERT_REVOKED:
- error = QSslError(QSslError::CertificateRevoked, cert); break;
- case X509_V_ERR_INVALID_CA:
- error = QSslError(QSslError::InvalidCaCertificate, cert); break;
- case X509_V_ERR_PATH_LENGTH_EXCEEDED:
- error = QSslError(QSslError::PathLengthExceeded, cert); break;
- case X509_V_ERR_INVALID_PURPOSE:
- error = QSslError(QSslError::InvalidPurpose, cert); break;
- case X509_V_ERR_CERT_UNTRUSTED:
- error = QSslError(QSslError::CertificateUntrusted, cert); break;
- case X509_V_ERR_CERT_REJECTED:
- error = QSslError(QSslError::CertificateRejected, cert); break;
- default:
- error = QSslError(QSslError::UnspecifiedError, cert); break;
- }
- return error;
-}
-
-void X509CertificateOpenSSL::parseExtensions()
-{
- extensions.clear();
-
- if (!x509)
- return;
-
- int count = q_X509_get_ext_count(x509);
- if (count <= 0)
- return;
-
- extensions.reserve(count);
-
- for (int i = 0; i < count; i++) {
- X509_EXTENSION *ext = q_X509_get_ext(x509, i);
- if (!ext) {
- qCWarning(lcTlsBackend) << "Invalid (nullptr) extension at index" << i;
- continue;
- }
-
- extensions << convertExtension(ext);
- }
-
- // Converting an extension may result in an error(s), clean them up:
- QTlsBackendOpenSSL::clearErrorQueue();
-}
-
-X509CertificateBase::X509CertificateExtension X509CertificateOpenSSL::convertExtension(X509_EXTENSION *ext)
-{
- Q_ASSERT(ext);
-
- X509CertificateExtension result;
-
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- if (!obj)
- return result;
-
- result.oid = QString::fromUtf8(asn1ObjectId(obj));
- result.name = QString::fromUtf8(asn1ObjectName(obj));
-
- result.critical = bool(q_X509_EXTENSION_get_critical(ext));
-
- // Lets see if we have custom support for this one
- QVariant extensionValue = x509ExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.value = extensionValue;
- result.supported = true;
- return result;
- }
-
- extensionValue = x509UnknownExtensionToValue(ext);
- if (extensionValue.isValid())
- result.value = extensionValue;
-
- result.supported = false;
-
- return result;
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qx509_openssl_p.h b/src/network/ssl/qx509_openssl_p.h
deleted file mode 100644
index 5bc5ad63f5..0000000000
--- a/src/network/ssl/qx509_openssl_p.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QX509_OPENSSL_P_H
-#define QX509_OPENSSL_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qopenssl_p.h>
-
-#include <private/qtlsbackend_p.h>
-#include <private/qx509_base_p.h>
-
-#include <QtCore/qvariant.h>
-#include <QtCore/qglobal.h>
-#include <QtCore/qstring.h>
-
-#include <openssl/x509.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-// TLSTODO: This class is essentially what qsslcertificate_openssl.cpp
-// contains - OpenSSL-based version of QSslCertificatePrivate. Remove
-// this comment when plugins are ready.
-class X509CertificateOpenSSL final : public X509CertificateBase
-{
-public:
- X509CertificateOpenSSL();
- ~X509CertificateOpenSSL();
-
- // TLSTODO: in future may become movable/copyable (ref-counted based
- // OpenSSL's X509 implementation).
-
- bool isEqual(const X509Certificate &rhs) const override;
- bool isSelfSigned() const override;
- QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const override;
- TlsKey *publicKey() const override;
-
- QByteArray toPem() const override;
- QByteArray toDer() const override;
- QString toText() const override;
- Qt::HANDLE handle() const override;
-
- size_t hash(size_t seed) const noexcept override;
-
- // TLSTODO: these are needed by qsslsocket_openssl and later, by
- // TLS code inside OpenSSL plugin. Remove this comment when
- // plugins are ready.
- static QSslCertificate certificateFromX509(X509 *x);
- static QList<QSslCertificate> stackOfX509ToQSslCertificates(STACK_OF(X509) *x509);
- static QSslErrorEntry errorEntryFromStoreContext(X509_STORE_CTX *ctx);
-
- // TLSTODO: remove this comment when plugins are in place. This is what QSslSocketPrivate::verify()
- // in qsslsocket_openssl.cpp is (was) doing (in the past).
- static QList<QSslError> verify(const QList<QSslCertificate> &chain, const QString &hostName);
- static QList<QSslError> verify(const QList<QSslCertificate> &caCertificates,
- const QList<QSslCertificate> &certificateChain,
- const QString &hostName);
-
- static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count);
- static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count);
- static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
-
- static QSslError openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert);
-private:
- void parseExtensions();
- static X509CertificateExtension convertExtension(X509_EXTENSION *ext);
-
- X509 *x509 = nullptr;
-
- Q_DISABLE_COPY_MOVE(X509CertificateOpenSSL)
-};
-
-extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx);
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QX509_OPENSSL_P_H
diff --git a/src/network/ssl/qx509_schannel.cpp b/src/network/ssl/qx509_schannel.cpp
deleted file mode 100644
index a7371e0d97..0000000000
--- a/src/network/ssl/qx509_schannel.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlskey_schannel_p.h"
-#include "qsslcertificate_p.h"
-#include "qx509_schannel_p.h"
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-X509CertificateSchannel::X509CertificateSchannel() = default;
-
-X509CertificateSchannel::~X509CertificateSchannel()
-{
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
-}
-
-TlsKey *X509CertificateSchannel::publicKey() const
-{
- auto key = std::make_unique<TlsKeySchannel>(QSsl::PublicKey);
- if (publicKeyAlgorithm != QSsl::Opaque)
- key->decodeDer(QSsl::PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
-
- return key.release();
-}
-
-Qt::HANDLE X509CertificateSchannel::handle() const
-{
- return Qt::HANDLE(certificateContext);
-}
-
-QSslCertificate X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
-{
- QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
- certificateContext->cbCertEncoded);
- QSslCertificate certificate(derData, QSsl::Der);
-
- auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
- Q_ASSERT(certBackend);
- certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
- return certificate;
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
diff --git a/src/network/ssl/qx509_schannel_p.h b/src/network/ssl/qx509_schannel_p.h
deleted file mode 100644
index 3b5d567c7b..0000000000
--- a/src/network/ssl/qx509_schannel_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QX509_SCHANNEL_P_H
-#define QX509_SCHANNEL_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qx509_generic_p.h>
-
-#include <QtCore/qglobal.h>
-
-#include <QtCore/qt_windows.h>
-#include <wincrypt.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class X509CertificateSchannel final : public X509CertificateGeneric
-{
-public:
- X509CertificateSchannel();
- ~X509CertificateSchannel();
-
- TlsKey *publicKey() const override;
- Qt::HANDLE handle() const override;
-
- static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
-private:
- const CERT_CONTEXT *certificateContext = nullptr;
-
- Q_DISABLE_COPY_MOVE(X509CertificateSchannel);
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QX509_SCHANNEL_P_H
diff --git a/src/network/ssl/qx509_st.cpp b/src/network/ssl/qx509_st.cpp
deleted file mode 100644
index 737b15cef8..0000000000
--- a/src/network/ssl/qx509_st.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#include "qtlskey_st_p.h"
-#include "qx509_st_p.h"
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-TlsKey *X509CertificateSecureTransport::publicKey() const
-{
- auto key = std::make_unique<TlsKeySecureTransport>(QSsl::PublicKey);
- if (publicKeyAlgorithm != QSsl::Opaque)
- key->decodeDer(QSsl::PublicKey, publicKeyAlgorithm, publicKeyDerData, {}, false);
-
- return key.release();
-}
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
diff --git a/src/network/ssl/qx509_st_p.h b/src/network/ssl/qx509_st_p.h
deleted file mode 100644
index 8c3969442c..0000000000
--- a/src/network/ssl/qx509_st_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** 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$
-**
-****************************************************************************/
-
-#ifndef QX509_ST_P_H
-#define QX509_ST_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.
-//
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <private/qx509_generic_p.h>
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlsPrivate {
-
-class X509CertificateSecureTransport final : public X509CertificateGeneric
-{
-public:
- TlsKey *publicKey() const override;
-};
-
-} // namespace QTlsPrivate
-
-QT_END_NAMESPACE
-
-#endif // QX509_ST_P_H