summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qasn1element.cpp391
-rw-r--r--src/network/ssl/qasn1element_p.h188
-rw-r--r--src/network/ssl/qdtls.cpp470
-rw-r--r--src/network/ssl/qdtls.h42
-rw-r--r--src/network/ssl/qdtls_openssl.cpp1401
-rw-r--r--src/network/ssl/qdtls_openssl_p.h212
-rw-r--r--src/network/ssl/qdtls_p.h132
-rw-r--r--src/network/ssl/qocsp_p.h40
-rw-r--r--src/network/ssl/qocspresponse.cpp75
-rw-r--r--src/network/ssl/qocspresponse.h60
-rw-r--r--src/network/ssl/qocspresponse_p.h41
-rw-r--r--src/network/ssl/qpassworddigestor.cpp144
-rw-r--r--src/network/ssl/qpassworddigestor.h44
-rw-r--r--src/network/ssl/qssl.cpp92
-rw-r--r--src/network/ssl/qssl.h94
-rw-r--r--src/network/ssl/qssl_p.h53
-rw-r--r--src/network/ssl/qsslcertificate.cpp454
-rw-r--r--src/network/ssl/qsslcertificate.h62
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp766
-rw-r--r--src/network/ssl/qsslcertificate_p.h140
-rw-r--r--src/network/ssl/qsslcertificate_qt.cpp557
-rw-r--r--src/network/ssl/qsslcertificate_schannel.cpp62
-rw-r--r--src/network/ssl/qsslcertificateextension.cpp40
-rw-r--r--src/network/ssl/qsslcertificateextension.h42
-rw-r--r--src/network/ssl/qsslcertificateextension_p.h40
-rw-r--r--src/network/ssl/qsslcipher.cpp47
-rw-r--r--src/network/ssl/qsslcipher.h49
-rw-r--r--src/network/ssl/qsslcipher_p.h40
-rw-r--r--src/network/ssl/qsslconfiguration.cpp112
-rw-r--r--src/network/ssl/qsslconfiguration.h61
-rw-r--r--src/network/ssl/qsslconfiguration_p.h44
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp767
-rw-r--r--src/network/ssl/qsslcontext_openssl_p.h129
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.cpp99
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.h81
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_dummy.cpp57
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_openssl.cpp224
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_p.h53
-rw-r--r--src/network/ssl/qsslellipticcurve.cpp110
-rw-r--r--src/network/ssl/qsslellipticcurve.h61
-rw-r--r--src/network/ssl/qsslellipticcurve_dummy.cpp71
-rw-r--r--src/network/ssl/qsslellipticcurve_openssl.cpp177
-rw-r--r--src/network/ssl/qsslerror.cpp56
-rw-r--r--src/network/ssl/qsslerror.h49
-rw-r--r--src/network/ssl/qsslkey.h48
-rw-r--r--src/network/ssl/qsslkey_mac.cpp99
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp383
-rw-r--r--src/network/ssl/qsslkey_p.cpp348
-rw-r--r--src/network/ssl/qsslkey_p.h119
-rw-r--r--src/network/ssl/qsslkey_qt.cpp785
-rw-r--r--src/network/ssl/qsslkey_schannel.cpp178
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.cpp78
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.h63
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator_p.h40
-rw-r--r--src/network/ssl/qsslserver.cpp412
-rw-r--r--src/network/ssl/qsslserver.h61
-rw-r--r--src/network/ssl/qsslserver_p.h71
-rw-r--r--src/network/ssl/qsslsocket.cpp709
-rw-r--r--src/network/ssl/qsslsocket.h57
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp1554
-rw-r--r--src/network/ssl/qsslsocket_mac_p.h138
-rw-r--r--src/network/ssl/qsslsocket_mac_shared.cpp155
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp2508
-rw-r--r--src/network/ssl/qsslsocket_openssl_android.cpp88
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h197
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp1231
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h761
-rw-r--r--src/network/ssl/qsslsocket_p.h187
-rw-r--r--src/network/ssl/qsslsocket_qt.cpp309
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp2064
-rw-r--r--src/network/ssl/qsslsocket_schannel_p.h145
-rw-r--r--src/network/ssl/qtls_utils_p.h103
-rw-r--r--src/network/ssl/qtlsbackend.cpp2357
-rw-r--r--src/network/ssl/qtlsbackend_p.h402
-rw-r--r--src/network/ssl/qwindowscarootfetcher.cpp289
-rw-r--r--src/network/ssl/qwindowscarootfetcher_p.h95
-rw-r--r--src/network/ssl/ssl.pri122
77 files changed, 5237 insertions, 18848 deletions
diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp
deleted file mode 100644
index 65a0e08961..0000000000
--- a/src/network/ssl/qasn1element.cpp
+++ /dev/null
@@ -1,391 +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;
- // value
- QByteArray tmpValue;
- tmpValue.resize(length);
- int count = stream.readRawData(tmpValue.data(), tmpValue.size());
- if (count != int(length))
- return false;
-
- 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
- if (mValue.at(0) & 0x80) {
- 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 c0dfc9db7e..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_MOVABLE_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.cpp b/src/network/ssl/qdtls.cpp
index af89740898..38ce144c8a 100644
--- a/src/network/ssl/qdtls.cpp
+++ b/src/network/ssl/qdtls.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslconfiguration.h"
-#include "qdtls_openssl_p.h"
+#include "qsslsocket_p.h"
#include "qudpsocket.h"
+#include "qsslcipher.h"
#include "qdtls_p.h"
#include "qssl_p.h"
#include "qdtls.h"
@@ -57,7 +22,7 @@
The QDtlsClientVerifier class implements server-side DTLS cookie generation
and verification. Datagram security protocols are highly susceptible to a
- variety of Denial-of-Service attacks. According to \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1},
+ variety of Denial-of-Service attacks. According to \l {RFC 6347, section 4.2.1},
these are two of the more common types of attack:
\list
@@ -70,7 +35,7 @@
which can be quite large, thus flooding the victim machine with datagrams.
\endlist
- As a countermeasure to these attacks, \l {https://tools.ietf.org/html/rfc6347#section-4.2.1}{RFC 6347, section 4.2.1}
+ As a countermeasure to these attacks, \l {RFC 6347, section 4.2.1}
proposes a stateless cookie technique that a server may deploy:
\list
@@ -118,7 +83,7 @@
\note The default secret is shared by all objects of the classes QDtlsClientVerifier
and QDtls. Since this can impose security risks, RFC 6347 recommends to change
- the server's secret frequently. Please see \l {https://tools.ietf.org/html/rfc6347}{RFC 6347, section 4.2.1}
+ the server's secret frequently. Please see \l {RFC 6347, section 4.2.1}
for hints about possible server implementations. Cookie generator parameters
can be set using the class QDtlsClientVerifier::GeneratorParameters and
setCookieGeneratorParameters():
@@ -249,7 +214,7 @@
\warning It's recommended to call shutdown() before destroying the client's QDtls
object if you are planning to re-use the same port number to connect to the
server later. Otherwise, the server may drop incoming ClientHello messages,
- see \l{https://tools.ietf.org/html/rfc6347#page-25}{RFC 6347, section 4.2.8}
+ see \l {RFC 6347, section 4.2.8}
for more details and implementation hints.
If the server does not use QDtlsClientVerifier, it \e must configure its
@@ -337,72 +302,6 @@
QT_BEGIN_NAMESPACE
-QSslConfiguration QDtlsBasePrivate::configuration() const
-{
- auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
- copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
- QSslConfiguration copy(copyPrivate);
- copyPrivate->sessionCipher = sessionCipher;
- copyPrivate->sessionProtocol = sessionProtocol;
-
- return copy;
-}
-
-void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
-{
- dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
- dtlsConfiguration.privateKey = configuration.privateKey();
- dtlsConfiguration.ciphers = configuration.ciphers();
- dtlsConfiguration.ellipticCurves = configuration.ellipticCurves();
- dtlsConfiguration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
- dtlsConfiguration.dhParams = configuration.diffieHellmanParameters();
- dtlsConfiguration.caCertificates = configuration.caCertificates();
- dtlsConfiguration.peerVerifyDepth = configuration.peerVerifyDepth();
- dtlsConfiguration.peerVerifyMode = configuration.peerVerifyMode();
- dtlsConfiguration.protocol = configuration.protocol();
- dtlsConfiguration.sslOptions = configuration.d->sslOptions;
- dtlsConfiguration.sslSession = configuration.sessionTicket();
- dtlsConfiguration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
- dtlsConfiguration.nextAllowedProtocols = configuration.allowedNextProtocols();
- dtlsConfiguration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
- dtlsConfiguration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
- dtlsConfiguration.dtlsCookieEnabled = configuration.dtlsCookieVerificationEnabled();
- dtlsConfiguration.allowRootCertOnDemandLoading = configuration.d->allowRootCertOnDemandLoading;
- dtlsConfiguration.backendConfig = configuration.backendConfiguration();
-
- clearDtlsError();
-}
-
-bool QDtlsBasePrivate::setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &key)
-{
- if (!key.size()) {
- setDtlsError(QDtlsError::InvalidInputParameters,
- QDtls::tr("Invalid (empty) secret"));
- return false;
- }
-
- clearDtlsError();
-
- hashAlgorithm = alg;
- secret = key;
-
- return true;
-}
-
-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;
- }
-}
-
static QString msgUnsupportedMulticastAddress()
{
return QDtls::tr("Multicast and broadcast addresses are not supported");
@@ -434,22 +333,37 @@ QDtlsClientVerifier::GeneratorParameters::GeneratorParameters(QCryptographicHash
{
}
+QDtlsClientVerifierPrivate::QDtlsClientVerifierPrivate()
+{
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available, cannot verify DTLS client");
+ return;
+ }
+ backend.reset(tlsBackend->createDtlsCookieVerifier());
+ if (!backend.get())
+ qCWarning(lcSsl) << "The backend" << tlsBackend->backendName() << "does not support DTLS cookies";
+}
+
+QDtlsClientVerifierPrivate::~QDtlsClientVerifierPrivate() = default;
+
/*!
Constructs a QDtlsClientVerifier object, \a parent is passed to QObject's
constructor.
*/
QDtlsClientVerifier::QDtlsClientVerifier(QObject *parent)
- : QObject(*new QDtlsClientVerifierOpenSSL, parent)
+ : QObject(*new QDtlsClientVerifierPrivate, parent)
{
Q_D(QDtlsClientVerifier);
- d->mode = QSslSocket::SslServerMode;
- // The default configuration suffices: verifier never does a full
- // handshake and upon verifying a cookie in a client hello message,
- // it reports success.
- auto conf = QSslConfiguration::defaultDtlsConfiguration();
- conf.setPeerVerifyMode(QSslSocket::VerifyNone);
- d->setConfiguration(conf);
+ if (auto *backend = d->backend.get()) {
+ // The default configuration suffices: verifier never does a full
+ // handshake and upon verifying a cookie in a client hello message,
+ // it reports success.
+ auto conf = QSslConfiguration::defaultDtlsConfiguration();
+ conf.setPeerVerifyMode(QSslSocket::VerifyNone);
+ backend->setConfiguration(conf);
+ }
}
/*!
@@ -473,8 +387,10 @@ QDtlsClientVerifier::~QDtlsClientVerifier()
bool QDtlsClientVerifier::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtlsClientVerifier);
+ if (auto *backend = d->backend.get())
+ return backend->setCookieGeneratorParameters(params);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ return false;
}
/*!
@@ -491,7 +407,10 @@ QDtlsClientVerifier::GeneratorParameters QDtlsClientVerifier::cookieGeneratorPar
{
Q_D(const QDtlsClientVerifier);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -514,19 +433,23 @@ bool QDtlsClientVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgr
{
Q_D(QDtlsClientVerifier);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || address.isNull() || !dgram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid UDP socket, non-empty datagram, valid address/port were expected"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid UDP socket, non-empty datagram, and valid address/port were expected"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- return d->verifyClient(socket, dgram, address, port);
+ return backend->verifyClient(socket, dgram, address, port);
}
/*!
@@ -539,7 +462,10 @@ QByteArray QDtlsClientVerifier::verifiedHello() const
{
Q_D(const QDtlsClientVerifier);
- return d->verifiedClientHello;
+ if (const auto *backend = d->backend.get())
+ return backend->verifiedHello();
+
+ return {};
}
/*!
@@ -551,7 +477,10 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
{
Q_D(const QDtlsClientVerifier);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::TlsInitializationError;
}
/*!
@@ -561,11 +490,17 @@ QDtlsError QDtlsClientVerifier::dtlsError() const
*/
QString QDtlsClientVerifier::dtlsErrorString() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtlsClientVerifier);
+
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
- return d->errorDescription;
+ return QStringLiteral("No TLS backend is available, no client verification");
}
+QDtlsPrivate::QDtlsPrivate() = default;
+QDtlsPrivate::~QDtlsPrivate() = default;
+
/*!
Creates a QDtls object, \a parent is passed to the QObject constructor.
\a mode is QSslSocket::SslServerMode for a server-side DTLS connection or
@@ -574,11 +509,19 @@ QString QDtlsClientVerifier::dtlsErrorString() const
\sa sslMode(), QSslSocket::SslMode
*/
QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent)
- : QObject(*new QDtlsPrivateOpenSSL, parent)
+ : QObject(*new QDtlsPrivate, parent)
{
Q_D(QDtls);
-
- d->mode = mode;
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend found, QDtls is unsupported");
+ return;
+ }
+ d->backend.reset(tlsBackend->createDtlsCryptograph(this, mode));
+ if (!d->backend.get()) {
+ qCWarning(lcSsl) << "TLS backend" << tlsBackend->backendName()
+ << "does not support the protocol DTLS";
+ }
setDtlsConfiguration(QSslConfiguration::defaultDtlsConfiguration());
}
@@ -601,29 +544,30 @@ bool QDtls::setPeer(const QHostAddress &address, quint16 port,
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set peer after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set peer after handshake started"));
return false;
}
if (address.isNull()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid address"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid address"));
return false;
}
if (address.isBroadcast() || address.isMulticast()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- msgUnsupportedMulticastAddress());
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ msgUnsupportedMulticastAddress());
return false;
}
- d->clearDtlsError();
-
- d->remoteAddress = address;
- d->remotePort = port;
- d->peerVerificationName = verificationName;
+ backend->clearDtlsError();
+ backend->setPeer(address, port, verificationName);
return true;
}
@@ -640,14 +584,18 @@ bool QDtls::setPeerVerificationName(const QString &name)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
tr("Cannot set verification name after handshake started"));
return false;
}
- d->clearDtlsError();
- d->peerVerificationName = name;
+ backend->clearDtlsError();
+ backend->setPeerVerificationName(name);
return true;
}
@@ -661,7 +609,10 @@ QHostAddress QDtls::peerAddress() const
{
Q_D(const QDtls);
- return d->remoteAddress;
+ if (const auto *backend = d->backend.get())
+ return backend->peerAddress();
+
+ return {};
}
/*!
@@ -671,9 +622,12 @@ QHostAddress QDtls::peerAddress() const
*/
quint16 QDtls::peerPort() const
{
- Q_D(const QDtlsBase);
+ Q_D(const QDtls);
+
+ if (const auto *backend = d->backend.get())
+ return backend->peerPort();
- return d->remotePort;
+ return 0;
}
/*!
@@ -686,7 +640,10 @@ QString QDtls::peerVerificationName() const
{
Q_D(const QDtls);
- return d->peerVerificationName;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationName();
+
+ return {};
}
/*!
@@ -699,7 +656,10 @@ QSslSocket::SslMode QDtls::sslMode() const
{
Q_D(const QDtls);
- return d->mode;
+ if (const auto *backend = d->backend.get())
+ return backend->cryptographMode();
+
+ return QSslSocket::UnencryptedMode;
}
/*!
@@ -712,7 +672,8 @@ void QDtls::setMtuHint(quint16 mtuHint)
{
Q_D(QDtls);
- d->mtuHint = mtuHint;
+ if (auto *backend = d->backend.get())
+ backend->setDtlsMtuHint(mtuHint);
}
/*!
@@ -724,7 +685,10 @@ quint16 QDtls::mtuHint() const
{
Q_D(const QDtls);
- return d->mtuHint;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsMtuHint();
+
+ return 0;
}
/*!
@@ -741,7 +705,10 @@ bool QDtls::setCookieGeneratorParameters(const GeneratorParameters &params)
{
Q_D(QDtls);
- return d->setCookieGeneratorParameters(params.hash, params.secret);
+ if (auto *backend = d->backend.get())
+ backend->setCookieGeneratorParameters(params);
+
+ return false;
}
/*!
@@ -759,7 +726,10 @@ QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
{
Q_D(const QDtls);
- return {d->hashAlgorithm, d->secret};
+ if (const auto *backend = d->backend.get())
+ return backend->cookieGeneratorParameters();
+
+ return {};
}
/*!
@@ -774,13 +744,17 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
{
Q_D(QDtls);
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot set configuration after handshake started"));
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot set configuration after handshake started"));
return false;
}
- d->setConfiguration(configuration);
+ backend->setConfiguration(configuration);
return true;
}
@@ -793,8 +767,10 @@ bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
QSslConfiguration QDtls::dtlsConfiguration() const
{
Q_D(const QDtls);
+ if (const auto *backend = d->backend.get())
+ return backend->configuration();
- return d->configuration();
+ return {};
}
/*!
@@ -806,7 +782,10 @@ QDtls::HandshakeState QDtls::handshakeState()const
{
Q_D(const QDtls);
- return d->handshakeState;
+ if (const auto *backend = d->backend.get())
+ return backend->state();
+
+ return QDtls::HandshakeNotStarted;
}
/*!
@@ -832,13 +811,17 @@ bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
- if (d->handshakeState == HandshakeNotStarted)
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
+ if (backend->state() == HandshakeNotStarted)
return startHandshake(socket, dgram);
- else if (d->handshakeState == HandshakeInProgress)
+ else if (backend->state() == HandshakeInProgress)
return continueHandshake(socket, dgram);
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start/continue handshake, invalid handshake state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start/continue handshake, invalid handshake state"));
return false;
}
@@ -849,34 +832,38 @@ bool QDtls::startHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->remoteAddress.isNull()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("To start a handshake you must set peer's address and port first"));
+ if (backend->peerAddress().isNull()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("To start a handshake you must set peer's address and port first"));
return false;
}
if (sslMode() == QSslSocket::SslServerMode && !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("To start a handshake, DTLS server requires non-empty datagram (client hello)"));
return false;
}
- if (d->handshakeState != HandshakeNotStarted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot start handshake, already done/in progress"));
+ if (backend->state() != HandshakeNotStarted) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot start handshake, already done/in progress"));
return false;
}
- return d->startHandshake(socket, datagram);
+ return backend->startHandshake(socket, datagram);
}
/*!
- If a timeout occures during the handshake, the handshakeTimeout() signal
+ If a timeout occurs during the handshake, the handshakeTimeout() signal
is emitted. The application must call handleTimeout() to retransmit handshake
messages; handleTimeout() returns \c true if a timeout has occurred, false
otherwise. \a socket must be a valid pointer.
@@ -887,12 +874,16 @@ bool QDtls::handleTimeout(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- return d->handleTimeout(socket);
+ return backend->handleTimeout(socket);
}
/*!
@@ -902,19 +893,23 @@ bool QDtls::continueHandshake(QUdpSocket *socket, const QByteArray &datagram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket || !datagram.size()) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("A valid QUdpSocket and non-empty datagram are needed to continue the handshake"));
return false;
}
- if (d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot continue handshake, not in InProgress state"));
+ if (backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot continue handshake, not in InProgress state"));
return false;
}
- return d->continueHandshake(socket, datagram);
+ return backend->continueHandshake(socket, datagram);
}
/*!
@@ -929,18 +924,22 @@ bool QDtls::resumeHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot resume, not in VerificationError state"));
+ if (backend->state() != PeerVerificationFailed) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot resume, not in VerificationError state"));
return false;
}
- return d->resumeHandshake(socket);
+ return backend->resumeHandshake(socket);
}
/*!
@@ -953,18 +952,22 @@ bool QDtls::abortHandshake(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return false;
}
- if (d->handshakeState != PeerVerificationFailed && d->handshakeState != HandshakeInProgress) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("No handshake in progress, nothing to abort"));
+ if (backend->state() != PeerVerificationFailed && backend->state() != HandshakeInProgress) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("No handshake in progress, nothing to abort"));
return false;
}
- d->abortHandshake(socket);
+ backend->abortHandshake(socket);
return true;
}
@@ -979,19 +982,23 @@ bool QDtls::shutdown(QUdpSocket *socket)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return false;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters,
- tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters,
+ tr("Invalid (nullptr) socket"));
return false;
}
- if (!d->connectionEncrypted) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot send shutdown alert, not encrypted"));
+ if (!backend->isConnectionEncrypted()) {
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot send shutdown alert, not encrypted"));
return false;
}
- d->sendShutdownAlert(socket);
+ backend->sendShutdownAlert(socket);
return true;
}
@@ -1004,7 +1011,11 @@ bool QDtls::isConnectionEncrypted() const
{
Q_D(const QDtls);
- return d->connectionEncrypted;
+
+ if (const auto *backend = d->backend.get())
+ return backend->isConnectionEncrypted();
+
+ return false;
}
/*!
@@ -1023,7 +1034,10 @@ QSslCipher QDtls::sessionCipher() const
{
Q_D(const QDtls);
- return d->sessionCipher;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionCipher();
+
+ return {};
}
/*!
@@ -1040,7 +1054,10 @@ QSsl::SslProtocol QDtls::sessionProtocol() const
{
Q_D(const QDtls);
- return d->sessionProtocol;
+ if (const auto *backend = d->backend.get())
+ return backend->dtlsSessionProtocol();
+
+ return QSsl::UnknownProtocol;
}
/*!
@@ -1055,18 +1072,22 @@ qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return -1;
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return -1;
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot write a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot write a datagram, not in encrypted state"));
return -1;
}
- return d->writeDatagramEncrypted(socket, dgram);
+ return backend->writeDatagramEncrypted(socket, dgram);
}
/*!
@@ -1079,21 +1100,25 @@ QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
{
Q_D(QDtls);
+ auto *backend = d->backend.get();
+ if (!backend)
+ return {};
+
if (!socket) {
- d->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
+ backend->setDtlsError(QDtlsError::InvalidInputParameters, tr("Invalid (nullptr) socket"));
return {};
}
if (!isConnectionEncrypted()) {
- d->setDtlsError(QDtlsError::InvalidOperation,
- tr("Cannot read a datagram, not in encrypted state"));
+ backend->setDtlsError(QDtlsError::InvalidOperation,
+ tr("Cannot read a datagram, not in encrypted state"));
return {};
}
if (!dgram.size())
return {};
- return d->decryptDatagram(socket, dgram);
+ return backend->decryptDatagram(socket, dgram);
}
/*!
@@ -1105,7 +1130,10 @@ QDtlsError QDtls::dtlsError() const
{
Q_D(const QDtls);
- return d->errorCode;
+ if (const auto *backend = d->backend.get())
+ return backend->error();
+
+ return QDtlsError::NoError;
}
/*!
@@ -1118,7 +1146,10 @@ QString QDtls::dtlsErrorString() const
{
Q_D(const QDtls);
- return d->errorDescription;
+ if (const auto *backend = d->backend.get())
+ return backend->errorString();
+
+ return {};
}
/*!
@@ -1131,7 +1162,11 @@ QList<QSslError> QDtls::peerVerificationErrors() const
{
Q_D(const QDtls);
- return d->tlsErrors;
+ if (const auto *backend = d->backend.get())
+ return backend->peerVerificationErrors();
+
+ //return d->tlsErrors;
+ return {};
}
/*!
@@ -1156,7 +1191,10 @@ void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
{
Q_D(QDtls);
- d->tlsErrorsToIgnore = errorsToIgnore;
+ if (auto *backend = d->backend.get())
+ backend->ignoreVerificationErrors(errorsToIgnore);
}
QT_END_NAMESPACE
+
+#include "moc_qdtls.cpp"
diff --git a/src/network/ssl/qdtls.h b/src/network/ssl/qdtls.h
index aee8dc0f87..dd24aa219a 100644
--- a/src/network/ssl/qdtls.h
+++ b/src/network/ssl/qdtls.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDTLS_H
#define QDTLS_H
@@ -51,7 +15,7 @@
Q_MOC_INCLUDE(<QtNetwork/QSslPreSharedKeyAuthenticator>)
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
QT_REQUIRE_CONFIG(dtls);
#endif
diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp
deleted file mode 100644
index c5891390a7..0000000000
--- a/src/network/ssl/qdtls_openssl.cpp
+++ /dev/null
@@ -1,1401 +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 "qsslsocket_openssl_p.h"
-#include "qsslcertificate_p.h"
-#include "qdtls_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 'deleter' for QScopedPointer<BIO>.
-struct bio_deleter
-{
- static void cleanup(BIO *bio)
- {
- if (bio)
- q_BIO_free(bio);
- }
-};
-
-// 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, QSslSocketBackendPrivate::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, QSslSocketBackendPrivate::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(QSslErrorEntry::fromStoreContext(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,
- QSslSocketBackendPrivate::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,
- QSslSocketBackendPrivate::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;
- }
-
- // Create a deep copy of our configuration
- auto configurationCopy = new QSslConfigurationPrivate(dtlsBase->dtlsConfiguration);
- configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
-
- // DTLSTODO: check we do not set something DTLS-incompatible there ...
- TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode,
- configurationCopy,
- dtlsBase->dtlsConfiguration.allowRootCertOnDemandLoading));
-
- 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(),
- QSslSocketBackendPrivate::s_indexForSSLExtraData,
- this);
-
- if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("SSL_set_ex_data"));
- return false;
- }
-
- if (dtlsBase->mode == QSslSocket::SslServerMode) {
- if (dtlsBase->dtlsConfiguration.dtlsCookieEnabled)
- 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);
-
- QScopedPointer<BIO, dtlsutil::bio_deleter> newBio(q_BIO_new(biom));
- BIO *bio = newBio.data();
- if (!bio) {
- dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
- msgFunctionFailed("BIO_new"));
- return false;
- }
-
- q_SSL_set_bio(tlsConnection.data(), bio, bio);
- newBio.take();
-
- 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()
-{
- secret = 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, QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- return false;
- }
-
- if (ret > 0) {
- verifiedClientHello = dgram;
- return true;
- }
-
- return false;
-}
-
-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()
-{
- secret = dtlsutil::fallbackSecret();
- dtls.dtlsPrivate = this;
-}
-
-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.dtlsCookieEnabled) {
- 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,
- QSslSocketBackendPrivate::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();
-}
-
-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(QSslSocketBackendPrivate::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(QSslSocketBackendPrivate::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.
-
- Q_Q(QDtls);
-
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for client code)
- if (hint) {
- identityHint.clear();
- identityHint.append(hint);
- // From the original code in QSslSocket:
- // "it's NULL terminated, but do not include the NULL" == this fromRawData(ptr/size).
- authenticator.d->identityHint = QByteArray::fromRawData(identityHint.constData(),
- int(std::strlen(hint)));
- }
-
- authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NULL terminated
- authenticator.d->maximumPreSharedKeyLength = int(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)
-{
- Q_Q(QDtls);
-
- {
- QSslPreSharedKeyAuthenticator authenticator;
- // Fill in some read-only fields (for the user)
- authenticator.d->identityHint = dtlsConfiguration.preSharedKeyIdentityHint;
- authenticator.d->identity = identity;
- authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
- authenticator.d->maximumPreSharedKeyLength = int(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;
-}
-
-// The definition is located in qsslsocket_openssl.cpp.
-QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert);
-
-bool QDtlsPrivateOpenSSL::verifyPeer()
-{
- // DTLSTODO: Windows-specific code for CA fetcher is not here yet.
- QList<QSslError> errors;
-
- // Check the whole chain for blacklisting (including root, as we check for
- // subjectInfo and issuer)
- for (const QSslCertificate &cert : qAsConst(dtlsConfiguration.peerCertificateChain)) {
- if (QSslCertificatePrivate::isBlacklisted(cert))
- errors << QSslError(QSslError::CertificateBlacklisted, cert);
- }
-
- if (dtlsConfiguration.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 = peerVerificationName;
- if (name.isEmpty()) {
- Q_ASSERT(dtls.udpSocket);
- name = dtls.udpSocket->peerName();
- }
-
- if (!QSslSocketPrivate::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
- errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
- }
-
- // Translate errors from the error list into QSslErrors
- errors.reserve(errors.size() + opensslErrors.size());
- for (const auto &error : qAsConst(opensslErrors)) {
- errors << _q_OpenSSL_to_QSslError(error.code,
- dtlsConfiguration.peerCertificateChain.value(error.depth));
- }
-
- 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());
- dtlsConfiguration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- if (dtlsConfiguration.peerCertificateChain.isEmpty()) {
- auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
- dtlsConfiguration.peerCertificateChain = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(stack);
- if (!dtlsConfiguration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
- dtlsConfiguration.peerCertificateChain.prepend(dtlsConfiguration.peerCertificate);
- }
-}
-
-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());
-
- const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data());
- sessionCipher = cipher ? QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher)
- : QSslCipher();
-
- // 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()
-{
- Q_Q(QDtls);
-
- emit q->handshakeTimeout();
-}
-
-void QDtlsPrivateOpenSSL::resetDtls()
-{
- dtls.reset();
- connectionEncrypted = false;
- tlsErrors.clear();
- tlsErrorsToIgnore.clear();
- dtlsConfiguration.peerCertificate.clear();
- dtlsConfiguration.peerCertificateChain.clear();
- 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 b1fcc99d5a..0000000000
--- a/src/network/ssl/qdtls_openssl_p.h
+++ /dev/null
@@ -1,212 +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 QDTLS_OPENSSL_P_H
-#define QDTLS_OPENSSL_P_H
-
-#include <private/qtnetworkglobal_p.h>
-
-#include <QtCore/qglobal.h>
-
-#include <openssl/ossl_typ.h>
-
-#include "qdtls_p.h"
-
-#include <private/qsslcontext_openssl_p.h>
-#include <private/qsslsocket_openssl_p.h>
-
-#include <QtNetwork/qsslpresharedkeyauthenticator.h>
-#include <QtNetwork/qhostaddress.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qcryptographichash.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 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
-
-class QDtlsClientVerifierOpenSSL : public QDtlsClientVerifierPrivate
-{
-public:
-
- QDtlsClientVerifierOpenSSL();
-
- bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) override;
-
-private:
- dtlsopenssl::DtlsState dtls;
-};
-
-class QDtlsPrivateOpenSSL : public QDtlsPrivate
-{
-public:
- QDtlsPrivateOpenSSL();
-
- 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;
-
- qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
- QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
-
- 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;
- };
-
- // 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;
-
- Q_DECLARE_PUBLIC(QDtls)
-};
-
-
-
-QT_END_NAMESPACE
-
-#endif // QDTLS_OPENSSL_P_H
diff --git a/src/network/ssl/qdtls_p.h b/src/network/ssl/qdtls_p.h
index be54c0e06e..5d519e2344 100644
--- a/src/network/ssl/qdtls_p.h
+++ b/src/network/ssl/qdtls_p.h
@@ -1,62 +1,14 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDTLS_P_H
#define QDTLS_P_H
#include <private/qtnetworkglobal_p.h>
-#include "qdtls.h"
-
-#include <private/qsslconfiguration_p.h>
-#include <private/qobject_p.h>
-
-#include <QtNetwork/qabstractsocket.h>
-#include <QtNetwork/qhostaddress.h>
-#include <QtNetwork/qsslsocket.h>
-#include <QtNetwork/qsslcipher.h>
-#include <QtNetwork/qssl.h>
-
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qstring.h>
+#include "qtlsbackend_p.h"
+#include <QtCore/private/qobject_p.h>
//
// W A R N I N G
// -------------
@@ -74,80 +26,20 @@ QT_BEGIN_NAMESPACE
class QHostAddress;
-class QDtlsBasePrivate : public QObjectPrivate
-{
-public:
-
- void setDtlsError(QDtlsError code, const QString &description)
- {
- errorCode = code;
- errorDescription = description;
- }
-
- void clearDtlsError()
- {
- errorCode = QDtlsError::NoError;
- errorDescription.clear();
- }
-
- void setConfiguration(const QSslConfiguration &configuration);
- QSslConfiguration configuration() const;
-
- bool setCookieGeneratorParameters(QCryptographicHash::Algorithm alg,
- const QByteArray &secret);
-
- static bool isDtlsProtocol(QSsl::SslProtocol protocol);
-
- QHostAddress remoteAddress;
- quint16 remotePort = 0;
- quint16 mtuHint = 0;
-
- QDtlsError errorCode = QDtlsError::NoError;
- QString errorDescription;
- QSslConfigurationPrivate dtlsConfiguration;
- QSslSocket::SslMode mode = QSslSocket::SslClientMode;
- QSslCipher sessionCipher;
- QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
- QString peerVerificationName;
- QByteArray secret;
-
-#ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
-#else
- QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
-#endif
-};
-
-class QDtlsClientVerifierPrivate : public QDtlsBasePrivate
+class QDtlsClientVerifierPrivate : public QObjectPrivate
{
public:
-
- QByteArray verifiedClientHello;
-
- virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
- const QHostAddress &address, quint16 port) = 0;
+ QDtlsClientVerifierPrivate();
+ ~QDtlsClientVerifierPrivate();
+ std::unique_ptr<QTlsPrivate::DtlsCookieVerifier> backend;
};
-class QDtlsPrivate : public QDtlsBasePrivate
+class QDtlsPrivate : public QObjectPrivate
{
public:
-
- virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool handleTimeout(QUdpSocket *socket) = 0;
- virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual bool resumeHandshake(QUdpSocket *socket) = 0;
- virtual void abortHandshake(QUdpSocket *socket) = 0;
- virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
-
- virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
- virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
-
- QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
-
- QList<QSslError> tlsErrors;
- QList<QSslError> tlsErrorsToIgnore;
-
- bool connectionEncrypted = false;
+ QDtlsPrivate();
+ ~QDtlsPrivate();
+ std::unique_ptr<QTlsPrivate::DtlsCryptograph> backend;
};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qocsp_p.h b/src/network/ssl/qocsp_p.h
index 71f59da0b4..596cb1357f 100644
--- a/src/network/ssl/qocsp_p.h
+++ b/src/network/ssl/qocsp_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSP_P_H
#define QOCSP_P_H
diff --git a/src/network/ssl/qocspresponse.cpp b/src/network/ssl/qocspresponse.cpp
index ab046b74c1..74e2c814fd 100644
--- a/src/network/ssl/qocspresponse.cpp
+++ b/src/network/ssl/qocspresponse.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qocspresponse_p.h"
#include "qocspresponse.h"
@@ -44,6 +9,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QOcspResponse)
+
/*!
\class QOcspResponse
\brief This class represents Online Certificate Status Protocol response.
@@ -53,7 +20,7 @@ QT_BEGIN_NAMESPACE
\ingroup ssl
\inmodule QtNetwork
- The QOcspResponse class represents the revocation status of a server's certficate,
+ The QOcspResponse class represents the revocation status of a server's certificate,
received by the client-side socket during the TLS handshake. QSslSocket must be
configured with OCSP stapling enabled.
@@ -95,7 +62,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtNetwork
- This enumeration describes revocation reasons, defined in \l{https://tools.ietf.org/html/rfc5280#section-5.3.1}{RFC 5280, section 5.3.1}
+ This enumeration describes revocation reasons, defined in \l{RFC 5280, section 5.3.1}
\value None
\value Unspecified
@@ -206,34 +173,34 @@ QSslCertificate QOcspResponse::subject() const
}
/*!
- \fn bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ \fn bool QOcspResponse::operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
Returns \c true if \a lhs and \a rhs are the responses for the same
certificate, signed by the same responder, have the same
revocation reason and the same certificate status.
\since 5.13
- \relates QOcspResponse
- */
-Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
-{
- return lhs.d == rhs.d || *lhs.d == *rhs.d;
-}
+*/
/*!
- \fn bool operator != (const QOcspResponse &lhs, const QOcspResponse &rhs)
+ \fn bool QOcspResponse::operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs)
- Returns \c true if \a lhs and \a rhs are responses for different certificates,
- or signed by different responders, or have different revocation reasons, or different
- certificate statuses.
+ Returns \c true if \a lhs and \a rhs are responses for different certificates,
+ or signed by different responders, or have different revocation reasons, or different
+ certificate statuses.
- \since 5.13
- \relates QOcspResponse
+ \since 5.13
*/
/*!
- \fn size_t qHash(const QOcspResponse &response, size_t seed)
+ \internal
+*/
+bool QOcspResponse::isEqual(const QOcspResponse &other) const
+{
+ return d == other.d || *d == *other.d;
+}
+/*!
Returns the hash value for the \a response, using \a seed to seed the calculation.
\since 5.13
diff --git a/src/network/ssl/qocspresponse.h b/src/network/ssl/qocspresponse.h
index 1fc3377d58..68251a1547 100644
--- a/src/network/ssl/qocspresponse.h
+++ b/src/network/ssl/qocspresponse.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSPRESPONSE_H
#define QOCSPRESPONSE_H
@@ -46,7 +11,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qobject.h>
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
QT_REQUIRE_CONFIG(ssl);
#endif
@@ -72,6 +37,10 @@ enum class QOcspRevocationReason
RemoveFromCRL
};
+namespace QTlsPrivate {
+class TlsCryptographOpenSSL;
+}
+
class QOcspResponse;
Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed = 0) noexcept;
@@ -97,20 +66,23 @@ public:
void swap(QOcspResponse &other) noexcept { d.swap(other.d); }
private:
+ bool isEqual(const QOcspResponse &other) const;
+
+ friend class QTlsPrivate::TlsCryptographOpenSSL;
+ friend bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs)
+ { return !lhs.isEqual(rhs); }
- friend class QSslSocketBackendPrivate;
- friend Q_NETWORK_EXPORT bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs);
friend Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed) noexcept;
QSharedDataPointer<QOcspResponsePrivate> d;
};
-inline bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs) { return !(lhs == rhs); }
-
Q_DECLARE_SHARED(QOcspResponse)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QOcspResponse)
+QT_DECL_METATYPE_EXTERN(QOcspResponse, Q_NETWORK_EXPORT)
#endif // QOCSPRESPONSE_H
diff --git a/src/network/ssl/qocspresponse_p.h b/src/network/ssl/qocspresponse_p.h
index e421b76899..5f08e306cd 100644
--- a/src/network/ssl/qocspresponse_p.h
+++ b/src/network/ssl/qocspresponse_p.h
@@ -1,41 +1,6 @@
-/****************************************************************************
-** Copyright (C) 2011 Richard J. Moore <rich@kde.org>
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOCSPRESPONSE_P_H
#define QOCSPRESPONSE_P_H
diff --git a/src/network/ssl/qpassworddigestor.cpp b/src/network/ssl/qpassworddigestor.cpp
index 706fa1de05..94de14abd4 100644
--- a/src/network/ssl/qpassworddigestor.cpp
+++ b/src/network/ssl/qpassworddigestor.cpp
@@ -1,50 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpassworddigestor.h"
#include <QtCore/QDebug>
#include <QtCore/QMessageAuthenticationCode>
#include <QtCore/QtEndian>
+#include <QtCore/QList>
+
+#include "qtcore-config_p.h"
#include <limits>
+#if QT_CONFIG(opensslv30) && QT_CONFIG(openssl_linked)
+#define USING_OPENSSL30
+#include <openssl/core_names.h>
+#include <openssl/kdf.h>
+#include <openssl/params.h>
+#include <openssl/provider.h>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QPasswordDigestor {
@@ -60,7 +35,7 @@ namespace QPasswordDigestor {
\since 5.12
Returns a hash computed using the PBKDF1-algorithm as defined in
- \l {https://tools.ietf.org/html/rfc8018#section-5.1} {RFC 8018}.
+ \l {RFC 8018, section 5.1}.
The function takes the \a data and \a salt, and then hashes it repeatedly
for \a iterations iterations using the specified hash \a algorithm. If the
@@ -122,11 +97,90 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algori
return key.left(dkLen);
}
+#ifdef USING_OPENSSL30
+// Copied from QCryptographicHashPrivate
+static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept
+{
+ switch (method) {
+#define CASE(Enum, Name) \
+ case QCryptographicHash:: Enum : \
+ return Name \
+ /*end*/
+ CASE(Sha1, "SHA1");
+ CASE(Md4, "MD4");
+ CASE(Md5, "MD5");
+ CASE(Sha224, "SHA224");
+ CASE(Sha256, "SHA256");
+ CASE(Sha384, "SHA384");
+ CASE(Sha512, "SHA512");
+ CASE(RealSha3_224, "SHA3-224");
+ CASE(RealSha3_256, "SHA3-256");
+ CASE(RealSha3_384, "SHA3-384");
+ CASE(RealSha3_512, "SHA3-512");
+ CASE(Keccak_224, "SHA3-224");
+ CASE(Keccak_256, "SHA3-256");
+ CASE(Keccak_384, "SHA3-384");
+ CASE(Keccak_512, "SHA3-512");
+ CASE(Blake2b_512, "BLAKE2B512");
+ CASE(Blake2s_256, "BLAKE2S256");
+#undef CASE
+ default: return nullptr;
+ }
+}
+
+static QByteArray opensslDeriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm,
+ const QByteArray &data, const QByteArray &salt,
+ uint64_t iterations, quint64 dkLen)
+{
+ EVP_KDF *kdf = EVP_KDF_fetch(nullptr, "PBKDF2", nullptr);
+
+ if (!kdf)
+ return QByteArray();
+
+ auto cleanUpKdf = qScopeGuard([kdf] {
+ EVP_KDF_free(kdf);
+ });
+
+ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
+
+ if (!ctx)
+ return QByteArray();
+
+ auto cleanUpCtx = qScopeGuard([ctx] {
+ EVP_KDF_CTX_free(ctx);
+ });
+
+ // Do not enable SP800-132 compliance check, otherwise we will require:
+ // - the iteration count is at least 1000
+ // - the salt length is at least 128 bits
+ // - the derived key length is at least 112 bits
+ // This would be a different behavior from the original implementation.
+ int checkDisabled = 1;
+ QList<OSSL_PARAM> params;
+ params.append(OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(methodToName(algorithm)), 0));
+ params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, const_cast<char*>(salt.data()), salt.size()));
+ params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, const_cast<char*>(data.data()), data.size()));
+ params.append(OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_ITER, &iterations));
+ params.append(OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &checkDisabled));
+ params.append(OSSL_PARAM_construct_end());
+
+ if (EVP_KDF_CTX_set_params(ctx, params.data()) <= 0)
+ return QByteArray();
+
+ QByteArray derived(dkLen, '\0');
+
+ if (!EVP_KDF_derive(ctx, reinterpret_cast<unsigned char*>(derived.data()), derived.size(), nullptr))
+ return QByteArray();
+
+ return derived;
+}
+#endif
+
/*!
\since 5.12
Derive a key using the PBKDF2-algorithm as defined in
- \l {https://tools.ietf.org/html/rfc8018#section-5.2} {RFC 8018}.
+ \l {RFC 8018, section 5.2}.
This function takes the \a data and \a salt, and then applies HMAC-X, where
the X is \a algorithm, repeatedly. It internally concatenates intermediate
@@ -143,8 +197,6 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori
const QByteArray &data, const QByteArray &salt,
int iterations, quint64 dkLen)
{
- // https://tools.ietf.org/html/rfc8018#section-5.2
-
// The RFC recommends checking that 'dkLen' is not greater than '(2^32 - 1) * hLen'
int hashLen = QCryptographicHash::hashLength(algorithm);
const quint64 maxLen = quint64(std::numeric_limits<quint32>::max() - 1) * hashLen;
@@ -158,11 +210,17 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori
if (iterations < 1 || dkLen < 1)
return QByteArray();
+#ifdef USING_OPENSSL30
+ if (methodToName(algorithm))
+ return opensslDeriveKeyPbkdf2(algorithm, data, salt, iterations, dkLen);
+#endif
+
+ // https://tools.ietf.org/html/rfc8018#section-5.2
QByteArray key;
quint32 currentIteration = 1;
QMessageAuthenticationCode hmac(algorithm, data);
QByteArray index(4, Qt::Uninitialized);
- while (quint64(key.length()) < dkLen) {
+ while (quint64(key.size()) < dkLen) {
hmac.addData(salt);
qToBigEndian(currentIteration, index.data());
diff --git a/src/network/ssl/qpassworddigestor.h b/src/network/ssl/qpassworddigestor.h
index 0f88643298..279450178b 100644
--- a/src/network/ssl/qpassworddigestor.h
+++ b/src/network/ssl/qpassworddigestor.h
@@ -1,45 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore 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$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPASSWORDDIGESTOR_H
#define QPASSWORDDIGESTOR_H
+#if 0
+#pragma qt_class(QPasswordDigestor)
+#endif
+
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/QByteArray>
#include <QtCore/QCryptographicHash>
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index ffa211630e..dfd3745d3e 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslkey.h"
@@ -204,7 +168,7 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\ingroup ssl
\inmodule QtNetwork
- See \l{https://tools.ietf.org/html/rfc8446#page-85}{RFC 8446, section 6}
+ See \l{RFC 8446, section 6}
for the possible values and their meaning.
\value CloseNotify,
@@ -243,4 +207,54 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value UnknownAlertMessage
*/
+/*!
+ \enum QSsl::ImplementedClass
+ \brief Enumerates classes that a TLS backend implements
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork, some classes have backend-specific implementation and thus
+ can be left unimplemented. Enumerators in this enum indicate, which class
+ has a working implementation in the backend.
+
+ \value Key Class QSslKey.
+ \value Certificate Class QSslCertificate.
+ \value Socket Class QSslSocket.
+ \value DiffieHellman Class QSslDiffieHellmanParameters.
+ \value EllipticCurve Class QSslEllipticCurve.
+ \value Dtls Class QDtls.
+ \value DtlsCookie Class QDtlsClientVerifier.
+*/
+
+/*!
+ \enum QSsl::SupportedFeature
+ \brief Enumerates possible features that a TLS backend supports
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork TLS-related classes have public API, that may be left unimplemented
+ by some backend, for example, our SecureTransport backend does not support
+ server-side ALPN. Enumerators from SupportedFeature enum indicate that a particular
+ feature is supported.
+
+ \value CertificateVerification Indicates that QSslCertificate::verify() is
+ implemented by the backend.
+ \value ClientSideAlpn Client-side ALPN (Application Layer Protocol Negotiation).
+ \value ServerSideAlpn Server-side ALPN.
+ \value Ocsp OCSP stapling (Online Certificate Status Protocol).
+ \value Psk Pre-shared keys.
+ \value SessionTicket Session tickets.
+ \value Alerts Information about alert messages sent and received.
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qssl.cpp"
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index cb0871fff6..e52b8c6361 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -1,62 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSL_H
#define QSSL_H
+#if 0
+#pragma qt_class(QSsl)
+#endif
+
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qobjectdefs.h>
#include <QtCore/QFlags>
QT_BEGIN_NAMESPACE
namespace QSsl {
+ Q_NAMESPACE_EXPORT(Q_NETWORK_EXPORT)
+
enum KeyType {
PrivateKey,
PublicKey
};
+ Q_ENUM_NS(KeyType)
enum EncodingFormat {
Pem,
Der
};
+ Q_ENUM_NS(EncodingFormat)
enum KeyAlgorithm {
Opaque,
@@ -65,26 +38,28 @@ namespace QSsl {
Ec,
Dh,
};
+ Q_ENUM_NS(KeyAlgorithm)
enum AlternativeNameEntryType {
EmailEntry,
DnsEntry,
IpAddressEntry
};
+ Q_ENUM_NS(AlternativeNameEntryType)
enum SslProtocol {
- TlsV1_0 = 2,
- TlsV1_1,
+ TlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
+ TlsV1_1 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
TlsV1_2,
AnyProtocol,
- SecureProtocols = AnyProtocol + 2,
+ SecureProtocols,
- TlsV1_0OrLater,
- TlsV1_1OrLater,
+ TlsV1_0OrLater QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
+ TlsV1_1OrLater QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
TlsV1_2OrLater,
- DtlsV1_0,
- DtlsV1_0OrLater,
+ DtlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use DtlsV1_2OrLater instead."),
+ DtlsV1_0OrLater QT_DEPRECATED_VERSION_X_6_3("Use DtlsV1_2OrLater instead."),
DtlsV1_2,
DtlsV1_2OrLater,
@@ -93,6 +68,7 @@ namespace QSsl {
UnknownProtocol = -1
};
+ Q_ENUM_NS(SslProtocol)
enum SslOption {
SslOptionDisableEmptyFragments = 0x01,
@@ -104,6 +80,7 @@ namespace QSsl {
SslOptionDisableSessionPersistence = 0x40,
SslOptionDisableServerCipherPreference = 0x80
};
+ Q_ENUM_NS(SslOption)
Q_DECLARE_FLAGS(SslOptions, SslOption)
enum class AlertLevel {
@@ -111,6 +88,7 @@ namespace QSsl {
Fatal,
Unknown
};
+ Q_ENUM_NS(AlertLevel)
enum class AlertType {
CloseNotify,
@@ -148,7 +126,31 @@ namespace QSsl {
NoApplicationProtocol = 120,
UnknownAlertMessage = 255
};
-
+ Q_ENUM_NS(AlertType)
+
+ enum class ImplementedClass
+ {
+ Key,
+ Certificate,
+ Socket,
+ DiffieHellman,
+ EllipticCurve,
+ Dtls,
+ DtlsCookie
+ };
+ Q_ENUM_NS(ImplementedClass)
+
+ enum class SupportedFeature
+ {
+ CertificateVerification,
+ ClientSideAlpn,
+ ServerSideAlpn,
+ Ocsp,
+ Psk,
+ SessionTicket,
+ Alerts
+ };
+ Q_ENUM_NS(SupportedFeature)
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions)
diff --git a/src/network/ssl/qssl_p.h b/src/network/ssl/qssl_p.h
index 83ccdc7fc3..ccbcf87029 100644
--- a/src/network/ssl/qssl_p.h
+++ b/src/network/ssl/qssl_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSL_P_H
@@ -60,6 +24,19 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcSsl)
+namespace QTlsPrivate {
+
+enum class Cipher {
+ DesCbc,
+ DesEde3Cbc,
+ Rc2Cbc,
+ Aes128Cbc,
+ Aes192Cbc,
+ Aes256Cbc
+};
+
+} // namespace QTlsPrivate
+
QT_END_NAMESPACE
#endif // QSSL_P_H
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 956a1df29c..9878c603b6 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -121,8 +85,7 @@
\value Wildcard This provides a simple pattern matching syntax
similar to that used by shells (command interpreters) for "file
- globbing". See \l {QRegularExpression#Wildcard matching}
- {QRegularExpression Wildcard Matching}.
+ globbing". See \l {QRegularExpression::fromWildcard()}.
\value FixedString The pattern is a fixed string. This is
equivalent to using the RegularExpression pattern on a string in
@@ -131,31 +94,46 @@
*/
#include <QtNetwork/qtnetworkglobal.h>
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
-#ifdef QT_SECURETRANSPORT
-#include "qsslsocket_mac_p.h"
-#endif
-#if QT_CONFIG(schannel)
-#include "qsslsocket_schannel_p.h"
-#endif
+
#if QT_CONFIG(regularexpression)
#include "qregularexpression.h"
#endif
-#include "qssl_p.h"
-#include "qsslcertificate.h"
+
+#include "qsslcertificateextension_p.h"
#include "qsslcertificate_p.h"
+#include "qsslcertificate.h"
+#include "qssl_p.h"
+
#ifndef QT_NO_SSL
+#include "qsslsocket_p.h"
#include "qsslkey_p.h"
#endif
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
+#include <QtCore/qdirlisting.h>
#include <QtCore/qfile.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN(QSslCertificate)
+
+QSslCertificatePrivate::QSslCertificatePrivate()
+{
+#ifndef QT_NO_SSL
+ QSslSocketPrivate::ensureInitialized();
+#endif
+
+ const QTlsBackend *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (tlsBackend)
+ backend.reset(tlsBackend->createCertificate());
+ else
+ qCWarning(lcSsl, "No TLS backend is available");
+}
+
+QSslCertificatePrivate::~QSslCertificatePrivate() = default;
+
/*!
Constructs a QSslCertificate by reading \a format encoded data
from \a device and using the first certificate found. You can
@@ -165,13 +143,25 @@ QT_BEGIN_NAMESPACE
QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (device && QSslSocket::supportsSsl())
-#else
- if (device)
-#endif
- d->init(device->readAll(), format);
+ if (device) {
+ const auto data = device->readAll();
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
+ }
}
/*!
@@ -183,11 +173,22 @@ QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
: d(new QSslCertificatePrivate)
{
-#ifndef QT_NO_OPENSSL
- QSslSocketPrivate::ensureInitialized();
- if (QSslSocket::supportsSsl())
-#endif
- d->init(data, format);
+ if (data.isEmpty())
+ return;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend)
+ return;
+
+ auto *X509Reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!X509Reader) {
+ qCWarning(lcSsl, "Current TLS plugin does not support reading from PEM/DER");
+ return;
+ }
+
+ const QList<QSslCertificate> certs = X509Reader(data, 1);
+ if (!certs.isEmpty())
+ d = certs.first().d;
}
/*!
@@ -229,6 +230,20 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
returns \c false.
*/
+bool QSslCertificate::operator==(const QSslCertificate &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (isNull() && other.isNull())
+ return true;
+
+ if (d->backend.get() && other.d->backend.get())
+ return d->backend->isEqual(*other.d->backend.get());
+
+ return false;
+}
+
/*!
\fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
@@ -246,25 +261,13 @@ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
\sa clear()
*/
+bool QSslCertificate::isNull() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isNull();
-#if QT_DEPRECATED_SINCE(5,0)
-/*!
- \fn bool QSslCertificate::isValid() const
- \obsolete
-
- To verify a certificate, use verify().
- To check if a certificate is blacklisted, use isBlacklisted().
- To check if a certificate has expired or is not yet valid, compare
- expiryDate() and effectiveDate() with QDateTime::currentDateTime()
-
- This function checks that the current
- date-time is within the date-time range during which the
- certificate is considered valid, and checks that the
- certificate is not in a blacklist of fraudulent certificates.
-
- \sa isNull(), verify(), isBlacklisted(), expiryDate(), effectiveDate()
-*/
-#endif
+ return true;
+}
/*!
Returns \c true if this certificate is blacklisted; otherwise
@@ -287,6 +290,13 @@ bool QSslCertificate::isBlacklisted() const
A certificate is considered self-signed its issuer and subject
are identical.
*/
+bool QSslCertificate::isSelfSigned() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->isSelfSigned();
+
+ return false;
+}
/*!
Clears the contents of this certificate, making it a null
@@ -305,12 +315,26 @@ void QSslCertificate::clear()
\fn QByteArray QSslCertificate::version() const
Returns the certificate's version string.
*/
+QByteArray QSslCertificate::version() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->version();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::serialNumber() const
Returns the certificate's serial number string in hexadecimal format.
*/
+QByteArray QSslCertificate::serialNumber() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->serialNumber();
+
+ return {};
+}
/*!
Returns a cryptographic digest of this certificate. By default,
@@ -332,6 +356,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
@@ -342,6 +373,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfo(attribute);
+
+ return {};
+}
/*!
\fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
@@ -352,6 +390,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(info);
+
+ return {};
+}
/*!
\fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
@@ -362,6 +407,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa issuerInfo()
*/
+QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfo(attribute);
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
@@ -375,6 +427,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectInfoAttributes();
+
+ return {};
+}
/*!
\fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
@@ -388,6 +447,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->issuerInfoAttributes();
+
+ return {};
+}
/*!
\fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
@@ -404,6 +470,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa subjectInfo()
*/
+QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->subjectAlternativeNames();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::effectiveDate() const
@@ -413,6 +486,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa expiryDate()
*/
+QDateTime QSslCertificate::effectiveDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->effectiveDate();
+
+ return {};
+}
/*!
\fn QDateTime QSslCertificate::expiryDate() const
@@ -422,6 +502,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\sa effectiveDate()
*/
+QDateTime QSslCertificate::expiryDate() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->expiryDate();
+
+ return {};
+}
/*!
\fn Qt::HANDLE QSslCertificate::handle() const
@@ -435,11 +522,29 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
non-portable, and its return value may vary from platform to
platform or change from minor release to minor release.
*/
+Qt::HANDLE QSslCertificate::handle() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->handle();
+ return {};
+}
+
+#ifndef QT_NO_SSL
/*!
\fn QSslKey QSslCertificate::publicKey() const
Returns the certificate subject's public key.
*/
+QSslKey QSslCertificate::publicKey() const
+{
+ QSslKey key;
+ if (const auto *backend = d->backend.get())
+ QTlsBackend::resetBackend(key, backend->publicKey());
+
+ return key;
+}
+#endif // QT_NO_SSL
+
/*!
\fn QList<QSslCertificateExtension> QSslCertificate::extensions() const
@@ -447,6 +552,10 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns a list containing the X509 extensions of this certificate.
\since 5.0
*/
+QList<QSslCertificateExtension> QSslCertificate::extensions() const
+{
+ return d->extensions();
+}
/*!
\fn QByteArray QSslCertificate::toPem() const
@@ -454,6 +563,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a PEM (Base64) encoded
representation.
*/
+QByteArray QSslCertificate::toPem() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toPem();
+
+ return {};
+}
/*!
\fn QByteArray QSslCertificate::toDer() const
@@ -461,6 +577,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
Returns this certificate converted to a DER (binary) encoded
representation.
*/
+QByteArray QSslCertificate::toDer() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toDer();
+
+ return {};
+}
/*!
\fn QString QSslCertificate::toText() const
@@ -470,6 +593,13 @@ QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) cons
\since 5.0
*/
+QString QSslCertificate::toText() const
+{
+ if (const auto *backend = d->backend.get())
+ return backend->toText();
+
+ return {};
+}
/*!
\since 5.15
@@ -494,16 +624,16 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QString sourcePath = QDir::fromNativeSeparators(path);
// Find the path without the filename
- QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(QLatin1Char('/')));
+ QStringView pathPrefix = QStringView(sourcePath).left(sourcePath.lastIndexOf(u'/'));
// Check if the path contains any special chars
int pos = -1;
#if QT_CONFIG(regularexpression)
if (syntax == PatternSyntax::Wildcard)
- pos = pathPrefix.indexOf(QRegularExpression(QLatin1String("[*?[]")));
+ pos = pathPrefix.indexOf(QRegularExpression("[*?[]"_L1));
else if (syntax == PatternSyntax::RegularExpression)
- pos = sourcePath.indexOf(QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
+ pos = sourcePath.indexOf(QRegularExpression("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]"_L1));
#else
if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp)
qWarning("Regular expression support is disabled in this build. Only fixed string can be searched");
@@ -513,11 +643,11 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
if (pos != -1) {
// there was a special char in the path so cut of the part containing that char.
pathPrefix = pathPrefix.left(pos);
- const int lastIndexOfSlash = pathPrefix.lastIndexOf(QLatin1Char('/'));
+ const qsizetype lastIndexOfSlash = pathPrefix.lastIndexOf(u'/');
if (lastIndexOfSlash != -1)
pathPrefix = pathPrefix.left(lastIndexOfSlash);
else
- pathPrefix.clear();
+ pathPrefix = {};
} else {
// Check if the path is a file.
if (QFileInfo(sourcePath).isFile()) {
@@ -534,10 +664,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
// Special case - if the prefix ends up being nothing, use "." instead.
int startIndex = 0;
if (pathPrefix.isEmpty()) {
- pathPrefix = QLatin1String(".");
+ pathPrefix = u".";
startIndex = 2;
}
+ const QString pathPrefixString = pathPrefix.toString();
+
// The path can be a file or directory.
QList<QSslCertificate> certs;
@@ -548,9 +680,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath));
#endif
- QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
- while (it.hasNext()) {
- QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
+ using F = QDirListing::IteratorFlag;
+ constexpr auto iterFlags = F::FollowSymlinks | F::Recursive;
+ for (const auto &dirEntry : QDirListing(pathPrefixString, QDir::Files, iterFlags)) {
+ QString filePath = dirEntry.filePath();
+ if (startIndex > 0)
+ filePath.remove(0, startIndex);
#if QT_CONFIG(regularexpression)
if (!pattern.match(filePath).hasMatch())
@@ -595,13 +730,22 @@ QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::Enco
*/
QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
{
- return (format == QSsl::Pem)
- ? QSslCertificatePrivate::certificatesFromPem(data)
- : QSslCertificatePrivate::certificatesFromDer(data);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+
+ auto reader = format == QSsl::Pem ? tlsBackend->X509PemReader() : tlsBackend->X509DerReader();
+ if (!reader) {
+ qCWarning(lcSsl, "The available TLS backend does not support reading PEM/DER");
+ return {};
+ }
+
+ return reader(data, -1);
}
#ifndef QT_NO_SSL
-
/*!
Verifies a certificate chain. The chain to be verified is passed in the
\a certificateChain parameter. The first certificate in the list should
@@ -610,19 +754,25 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
the specified host name.
Note that the root (CA) certificate should not be included in the list to be verified,
- this will be looked up automatically either using the CA list specified by
- QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand
- on Unix.
+ this will be looked up automatically using the CA list specified in the
+ default QSslConfiguration, and, in addition, if possible, CA certificates loaded on
+ demand on Unix and Windows.
\since 5.0
*/
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
-#else
-QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
-#endif
{
- return QSslSocketBackendPrivate::verify(certificateChain, hostName);
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return {};
+ }
+ auto verifyPtr = tlsBackend->X509Verifier();
+ if (!verifyPtr) {
+ qCWarning(lcSsl, "Available TLS backend does not support manual certificate verification");
+ return {};
+ }
+ return verifyPtr(certificateChain, hostName);
}
/*!
@@ -642,10 +792,43 @@ bool QSslCertificate::importPkcs12(QIODevice *device,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase)
{
- return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
+ if (!device || !key || !certificate)
+ return false;
+
+ const auto *tlsBackend = QTlsBackend::activeOrAnyBackend();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return false;
+ }
+
+ if (auto reader = tlsBackend->X509Pkcs12Reader())
+ return reader(device, key, certificate, caCertificates, passPhrase);
+
+ qCWarning(lcSsl, "Available TLS backend does not support PKCS12");
+
+ return false;
}
+#endif // QT_NO_SSL
-#endif
+QList<QSslCertificateExtension> QSslCertificatePrivate::extensions() const
+{
+ QList<QSslCertificateExtension> result;
+
+ if (backend.get()) {
+ auto nExt = backend->numberOfExtensions();
+ for (decltype (nExt) i = 0; i < nExt; ++i) {
+ QSslCertificateExtension ext;
+ ext.d->oid = backend->oidForExtension(i);
+ ext.d->name = backend->nameForExtension(i);
+ ext.d->value = backend->valueForExtension(i);
+ ext.d->critical = backend->isExtensionCritical(i);
+ ext.d->supported = backend->isExtensionSupported(i);
+ result << ext;
+ }
+ }
+
+ return result;
+}
// These certificates are known to be fraudulent and were created during the comodo
// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
@@ -700,7 +883,7 @@ static const char *const certificate_blacklist[] = {
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != nullptr; a++) {
- QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);
+ auto blacklistedCommonName = QAnyStringView(QUtf8StringView(certificate_blacklist[(a+1)]));
if (certificate.serialNumber() == certificate_blacklist[a++] &&
(certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
@@ -711,19 +894,18 @@ bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
QByteArray QSslCertificatePrivate::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;
+ case QSslCertificate::Organization: return "O"_ba;
+ case QSslCertificate::CommonName: return "CN"_ba;
+ case QSslCertificate::LocalityName: return"L"_ba;
+ case QSslCertificate::OrganizationalUnitName: return "OU"_ba;
+ case QSslCertificate::CountryName: return "C"_ba;
+ case QSslCertificate::StateOrProvinceName: return "ST"_ba;
+ case QSslCertificate::DistinguishedNameQualifier: return "dnQualifier"_ba;
+ case QSslCertificate::SerialNumber: return "serialNumber"_ba;
+ case QSslCertificate::EmailAddress: return "emailAddress"_ba;
}
- return str;
+ return QByteArray();
}
/*!
@@ -740,13 +922,13 @@ QString QSslCertificate::issuerDisplayName() const
QStringList names;
names = issuerInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
@@ -765,24 +947,30 @@ QString QSslCertificate::subjectDisplayName() const
QStringList names;
names = subjectInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
/*!
- \fn size_t qHash(const QSslCertificate &key, size_t seed)
-
Returns the hash value for the \a key, using \a seed to seed the calculation.
\since 5.4
\relates QHash
*/
+size_t qHash(const QSslCertificate &key, size_t seed) noexcept
+{
+ if (const auto *backend = key.d->backend.get())
+ return backend->hash(seed);
+
+ return seed;
+
+}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
@@ -790,15 +978,15 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
QDebugStateSaver saver(debug);
debug.resetFormat().nospace();
debug << "QSslCertificate("
- << certificate.version()
- << ", " << certificate.serialNumber()
- << ", " << certificate.digest().toBase64()
- << ", " << certificate.issuerDisplayName()
- << ", " << certificate.subjectDisplayName()
- << ", " << certificate.subjectAlternativeNames()
+ << "Version=" << certificate.version()
+ << ", SerialNumber=" << certificate.serialNumber()
+ << ", Digest=" << certificate.digest().toBase64()
+ << ", Issuer=" << certificate.issuerDisplayName()
+ << ", Subject=" << certificate.subjectDisplayName()
+ << ", AlternativeSubjectNames=" << certificate.subjectAlternativeNames()
#if QT_CONFIG(datestring)
- << ", " << certificate.effectiveDate()
- << ", " << certificate.expiryDate()
+ << ", EffectiveDate=" << certificate.effectiveDate()
+ << ", ExpiryDate=" << certificate.expiryDate()
#endif
<< ')';
return debug;
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index 8cfeaeb273..cdf11b28b0 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATE_H
@@ -50,8 +14,8 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdatetime.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qmap.h>
+#include <QtCore/qshareddata.h>
#include <QtNetwork/qssl.h>
QT_BEGIN_NAMESPACE
@@ -97,20 +61,12 @@ public:
QSslCertificate &operator=(const QSslCertificate &other);
void swap(QSslCertificate &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslCertificate &other) const;
inline bool operator!=(const QSslCertificate &other) const { return !operator==(other); }
bool isNull() const;
-#if QT_DEPRECATED_SINCE(5,0)
- QT_DEPRECATED inline bool isValid() const {
- const QDateTime currentTime = QDateTime::currentDateTimeUtc();
- return currentTime >= effectiveDate() &&
- currentTime <= expiryDate() &&
- !isBlacklisted();
- }
-#endif
bool isBlacklisted() const;
bool isSelfSigned() const;
void clear();
@@ -150,12 +106,7 @@ public:
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
#ifndef QT_NO_SSL
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName = QString());
-#else
- static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName = QString());
-#endif
-
static bool importPkcs12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates = nullptr,
@@ -166,8 +117,7 @@ public:
private:
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
- friend class QSslCertificatePrivate;
- friend class QSslSocketBackendPrivate;
+ friend class QTlsBackend;
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
};
@@ -181,6 +131,6 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo in
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslCertificate)
+QT_DECL_METATYPE_EXTERN(QSslCertificate, Q_NETWORK_EXPORT)
#endif
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp
deleted file mode 100644
index 35521427b2..0000000000
--- a/src/network/ssl/qsslcertificate_openssl.cpp
+++ /dev/null
@@ -1,766 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** 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 "qssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslcertificate_p.h"
-#include "qsslkey_p.h"
-#include "qsslcertificateextension_p.h"
-
-#include <QtCore/qendian.h>
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-constexpr int MutexPoolSize = 17;
-static QBasicMutex mutexPool[MutexPoolSize];
-namespace QMutexPool {
- static QBasicMutex *globalInstanceGet(const void *addr)
- {
- return mutexPool + (quintptr(addr) % MutexPoolSize);
- }
-}
-
-// forward declaration
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- if (d->null && other.d->null)
- return true;
- if (d->x509 && other.d->x509)
- return q_X509_cmp(d->x509, other.d->x509) == 0;
- return false;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- if (X509 * const x509 = key.d->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;
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (!d->x509)
- return false;
-
- return (q_X509_check_issued(d->x509, d->x509) == X509_V_OK);
-}
-
-QByteArray QSslCertificate::version() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->versionString.isEmpty() && d->x509)
- d->versionString = QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1);
-
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- if (d->serialNumberString.isEmpty() && d->x509) {
- ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->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);
- d->serialNumberString = hexString;
- }
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(d->subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->subjectInfo.isEmpty() && d->x509)
- d->subjectInfo =
- _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
-
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
-#if QT_CONFIG(thread)
- QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
-#endif
- // lazy init
- if (d->issuerInfo.isEmpty() && d->x509)
- d->issuerInfo =
- _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
-
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
-
- if (!d->x509)
- return result;
-
- STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME) *)q_X509_get_ext_d2i(
- d->x509, NID_subject_alt_name, nullptr, nullptr);
-
- 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);
- };
- if (altNames) {
- 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;
-
- 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;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->x509);
-}
-
-QSslKey QSslCertificate::publicKey() const
-{
- if (!d->x509)
- return QSslKey();
-
- QSslKey key;
-
- key.d->type = QSsl::PublicKey;
-
- EVP_PKEY *pkey = q_X509_get_pubkey(d->x509);
- Q_ASSERT(pkey);
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
-
- if (keyType == EVP_PKEY_RSA) {
- key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
- key.d->algorithm = QSsl::Rsa;
- key.d->isNull = false;
- } else if (keyType == EVP_PKEY_DSA) {
- key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
- key.d->algorithm = QSsl::Dsa;
- key.d->isNull = false;
-#ifndef OPENSSL_NO_EC
- } else if (keyType == EVP_PKEY_EC) {
- key.d->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- key.d->algorithm = QSsl::Ec;
- key.d->isNull = false;
-#endif
- } else if (keyType == EVP_PKEY_DH) {
- // DH unsupported
- } else {
- // error?
- }
-
- q_EVP_PKEY_free(pkey);
- return key;
-}
-
-/*
- * Convert unknown extensions to a QVariant.
- */
-static 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.
- 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);
- QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
- q_ASN1_STRING_length(value));
- return result;
- }
-
- //const unsigned char *data = ext->value->data;
- 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(CONF_VALUE, 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) {
- //qCDebug(lcSsl) << meth->i2s(meth, 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.
- */
-static 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));
-
- 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));
-
- QVariantMap result;
- for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, 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(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
- } else {
- qCWarning(lcSsl) << "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);
-
- // 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));
-
- 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 QVariant();
-}
-
-QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext)
-{
- QSslCertificateExtension result;
-
- ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
- QByteArray oid = QSslCertificatePrivate::asn1ObjectId(obj);
- QByteArray name = QSslCertificatePrivate::asn1ObjectName(obj);
-
- result.d->oid = QString::fromUtf8(oid);
- result.d->name = QString::fromUtf8(name);
-
- bool critical = q_X509_EXTENSION_get_critical(ext);
- result.d->critical = critical;
-
- // Lets see if we have custom support for this one
- QVariant extensionValue = x509ExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = true;
-
- return result;
- }
-
- extensionValue = x509UnknownExtensionToValue(ext);
- if (extensionValue.isValid()) {
- result.d->value = extensionValue;
- result.d->supported = false;
- return result;
- }
-
- return result;
-}
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- QList<QSslCertificateExtension> result;
-
- if (!d->x509)
- return result;
-
- int count = q_X509_get_ext_count(d->x509);
- result.reserve(count);
-
- for (int i = 0; i < count; i++) {
- X509_EXTENSION *ext = q_X509_get_ext(d->x509, i);
- result << QSslCertificatePrivate::convertExtension(ext);
- }
-
- // Converting an extension may result in an error(s), clean them up.
- Q_UNUSED(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
-
- return result;
-}
-
-QByteArray QSslCertificate::toPem() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Pem);
-}
-
-QByteArray QSslCertificate::toDer() const
-{
- if (!d->x509)
- return QByteArray();
- return d->QByteArray_from_X509(d->x509, QSsl::Der);
-}
-
-QString QSslCertificate::toText() const
-{
- if (!d->x509)
- return QString();
- return d->text_from_X509(d->x509);
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
- if (x509)
- x509 = q_X509_dup(x509);
- }
- }
-}
-
-// ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
-QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
- return QByteArray();
- }
-
- // Use i2d_X509 to convert the X509 to an array.
- int length = q_i2d_X509(x509, nullptr);
- 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 QSslCertificatePrivate::text_from_X509(X509 *x509)
-{
- if (!x509) {
- qCWarning(lcSsl, "QSslSocketBackendPrivate::text_from_X509: null X509");
- return QString();
- }
-
- QByteArray result;
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QString();
-
- 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 );
- }
-
- q_BIO_free(bio);
-
- return QString::fromLatin1(result);
-}
-
-QByteArray QSslCertificatePrivate::asn1ObjectId(ASN1_OBJECT *object)
-{
- 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 QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object)
-{
- int nid = q_OBJ_obj2nid(object);
- if (nid != NID_undef)
- return QByteArray(q_OBJ_nid2sn(nid));
-
- return asn1ObjectId(object);
-}
-
-static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
-{
- 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 = QSslCertificatePrivate::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));
-#if QT_CONFIG(opensslv11)
- q_CRYPTO_free(data, nullptr, 0);
-#else
- q_CRYPTO_free(data);
-#endif
- }
-
- return info;
-}
-
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
-{
- QSslCertificate certificate;
- if (!x509 || !QSslSocket::supportsSsl())
- return certificate;
-
- ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
- ASN1_TIME *naft = q_X509_getm_notAfter(x509);
-
- certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
- certificate.d->notValidAfter = q_getTimeFromASN1(naft);
- certificate.d->null = false;
- certificate.d->x509 = q_X509_dup(x509);
-
- return certificate;
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *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;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- 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 << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- }
- }
-
- return certificates;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
- QSslSocketPrivate::ensureInitialized();
-
- 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 << QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- } else {
- break;
- }
- size -= ((const char *)data - der.data());
- }
-
- return certificates;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4588aa7d6f..ca59abae82 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -1,48 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QSSLCERTIFICATE_OPENSSL_P_H
-#define QSSLCERTIFICATE_OPENSSL_P_H
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qsslcertificate.h"
+#ifndef QSSLCERTIFICATE_P_H
+#define QSSLCERTIFICATE_P_H
//
// W A R N I N G
@@ -55,99 +16,32 @@
// We mean it.
//
-#ifndef QT_NO_SSL
-#include "qsslsocket_p.h"
-#endif
+#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include "qsslcertificateextension.h"
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmap.h>
+#include "qsslcertificate.h"
+#include "qtlsbackend_p.h"
-#ifndef QT_NO_OPENSSL
-#include <openssl/x509.h>
-#else
-struct X509;
-struct X509_EXTENSION;
-struct ASN1_OBJECT;
-#endif
+#include <qlist.h>
-#if QT_CONFIG(schannel)
-#include <wincrypt.h>
-#endif
+#include <memory>
QT_BEGIN_NAMESPACE
-// forward declaration
-
class QSslCertificatePrivate
{
public:
- QSslCertificatePrivate()
- : null(true), x509(nullptr)
- {
-#ifndef QT_NO_SSL
- QSslSocketPrivate::ensureInitialized();
-#endif
- }
-
- ~QSslCertificatePrivate()
- {
-#ifndef QT_NO_OPENSSL
- if (x509)
- q_X509_free(x509);
-#endif
-#if QT_CONFIG(schannel)
- if (certificateContext)
- CertFreeCertificateContext(certificateContext);
-#endif
- }
-
- bool null;
- QByteArray versionString;
- QByteArray serialNumberString;
+ QSslCertificatePrivate();
+ ~QSslCertificatePrivate();
- QMultiMap<QByteArray, QString> issuerInfo;
- QMultiMap<QByteArray, QString> subjectInfo;
- QDateTime notValidAfter;
- QDateTime notValidBefore;
-
-#ifdef QT_NO_OPENSSL
- bool subjectMatchesIssuer;
- QSsl::KeyAlgorithm publicKeyAlgorithm;
- QByteArray publicKeyDerData;
- QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
- QList<QSslCertificateExtension> extensions;
-
- QByteArray derData;
-
- bool parse(const QByteArray &data);
- bool parseExtension(const QByteArray &data, QSslCertificateExtension *extension);
-#endif
- X509 *x509;
-
- void init(const QByteArray &data, QSsl::EncodingFormat format);
-
- static QByteArray asn1ObjectId(ASN1_OBJECT *object);
- static QByteArray asn1ObjectName(ASN1_OBJECT *object);
- static QByteArray QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format);
- static QString text_from_X509(X509 *x509);
- static QSslCertificate QSslCertificate_from_X509(X509 *x509);
- static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count = -1);
- static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count = -1);
- static bool isBlacklisted(const QSslCertificate &certificate);
- static QSslCertificateExtension convertExtension(X509_EXTENSION *ext);
- static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
-
- friend class QSslSocketBackendPrivate;
+ QList<QSslCertificateExtension> extensions() const;
+ Q_NETWORK_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
+ Q_NETWORK_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
QAtomicInt ref;
-
-#if QT_CONFIG(schannel)
- const CERT_CONTEXT *certificateContext = nullptr;
-
- static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
-#endif
+ std::unique_ptr<QTlsPrivate::X509Certificate> backend;
};
QT_END_NAMESPACE
-#endif // QSSLCERTIFICATE_OPENSSL_P_H
+#endif // QSSLCERTIFICATE_P_H
diff --git a/src/network/ssl/qsslcertificate_qt.cpp b/src/network/ssl/qsslcertificate_qt.cpp
deleted file mode 100644
index c0f3710a9a..0000000000
--- a/src/network/ssl/qsslcertificate_qt.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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.h"
-#include "qsslcertificate_p.h"
-
-#include "qssl_p.h"
-#ifndef QT_NO_SSL
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#endif
-#include "qsslcertificateextension.h"
-#include "qsslcertificateextension_p.h"
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qendian.h>
-#include <QtNetwork/qhostaddress.h>
-
-QT_BEGIN_NAMESPACE
-
-bool QSslCertificate::operator==(const QSslCertificate &other) const
-{
- if (d == other.d)
- return true;
- if (d->null && other.d->null)
- return true;
- return d->derData == other.d->derData;
-}
-
-size_t qHash(const QSslCertificate &key, size_t seed) noexcept
-{
- // DER is the native encoding here, so toDer() is just "return d->derData":
- return qHash(key.toDer(), seed);
-}
-
-bool QSslCertificate::isNull() const
-{
- return d->null;
-}
-
-bool QSslCertificate::isSelfSigned() const
-{
- if (d->null)
- return false;
-
- qCWarning(lcSsl,
- "QSslCertificate::isSelfSigned: This function does not check, whether the certificate "
- "is actually signed. It just checks whether issuer and subject are identical");
- return d->subjectMatchesIssuer;
-}
-
-QByteArray QSslCertificate::version() const
-{
- return d->versionString;
-}
-
-QByteArray QSslCertificate::serialNumber() const
-{
- return d->serialNumberString;
-}
-
-QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
-{
- return issuerInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
-{
- return d->issuerInfo.values(attribute);
-}
-
-QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
-{
- return subjectInfo(QSslCertificatePrivate::subjectInfoToString(info));
-}
-
-QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
-{
- return d->subjectInfo.values(attribute);
-}
-
-QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
-{
- return d->subjectInfo.uniqueKeys();
-}
-
-QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
-{
- return d->issuerInfo.uniqueKeys();
-}
-
-QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
-{
- return d->subjectAlternativeNames;
-}
-
-QDateTime QSslCertificate::effectiveDate() const
-{
- return d->notValidBefore;
-}
-
-QDateTime QSslCertificate::expiryDate() const
-{
- return d->notValidAfter;
-}
-
-#if !QT_CONFIG(schannel) // implemented in qsslcertificate_schannel.cpp
-Qt::HANDLE QSslCertificate::handle() const
-{
- Q_UNIMPLEMENTED();
- return nullptr;
-}
-#endif
-
-#ifndef QT_NO_SSL
-QSslKey QSslCertificate::publicKey() const
-{
- QSslKey key;
- key.d->type = QSsl::PublicKey;
- if (d->publicKeyAlgorithm != QSsl::Opaque) {
- key.d->algorithm = d->publicKeyAlgorithm;
- key.d->decodeDer(d->publicKeyDerData);
- }
- return key;
-}
-#endif
-
-QList<QSslCertificateExtension> QSslCertificate::extensions() const
-{
- return d->extensions;
-}
-
-#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
-#define ENDCERTSTRING "-----END CERTIFICATE-----"
-
-QByteArray QSslCertificate::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 QSslCertificate::toDer() const
-{
- return d->derData;
-}
-
-QString QSslCertificate::toText() const
-{
- Q_UNIMPLEMENTED();
- return QString();
-}
-
-void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
-{
- if (!data.isEmpty()) {
- const QList<QSslCertificate> certs = (format == QSsl::Pem)
- ? certificatesFromPem(data, 1)
- : certificatesFromDer(data, 1);
- if (!certs.isEmpty()) {
- *this = *certs.first().d;
-#if QT_CONFIG(schannel)
- if (certificateContext)
- certificateContext = CertDuplicateCertificateContext(certificateContext);
-#endif
- }
- }
-}
-
-static bool matchLineFeed(const QByteArray &pem, int *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;
-}
-
-QList<QSslCertificate> QSslCertificatePrivate::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> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
-{
- QList<QSslCertificate> certificates;
-
- QByteArray data = der;
- while (count == -1 || certificates.size() < count) {
- QSslCertificate cert;
- if (!cert.d->parse(data))
- break;
-
- certificates << cert;
- data.remove(0, cert.d->derData.size());
- }
-
- return certificates;
-}
-
-static 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(':');
-}
-
-bool QSslCertificatePrivate::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)
- 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());
- issuerInfo = 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());
- subjectInfo = 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) {
- QSslCertificateExtension extension;
- if (!parseExtension(elem.value(), &extension))
- return false;
- extensions << extension;
-
- if (extension.oid() == QLatin1String("2.5.29.17")) {
- // subjectAltName
- 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:
- subjectAlternativeNames.insert(QSsl::EmailEntry, nameElem.toString());
- break;
- case QAsn1Element::DnsNameType:
- subjectAlternativeNames.insert(QSsl::DnsEntry, 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())
- subjectAlternativeNames.insert(QSsl::IpAddressEntry, ipAddress.toString());
- break;
- }
- default:
- break;
- }
- }
- }
- }
- }
- }
- }
- }
-
- derData = data.left(dataStream.device()->pos());
- null = false;
- return true;
-}
-
-bool QSslCertificatePrivate::parseExtension(const QByteArray &data, QSslCertificateExtension *extension)
-{
- bool ok;
- 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->d->critical = critical;
- extension->d->supported = supported;
- extension->d->oid = QString::fromLatin1(oid);
- extension->d->name = QString::fromLatin1(oidElem.toObjectName());
- extension->d->value = value;
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate_schannel.cpp b/src/network/ssl/qsslcertificate_schannel.cpp
deleted file mode 100644
index 5ea713612a..0000000000
--- a/src/network/ssl/qsslcertificate_schannel.cpp
+++ /dev/null
@@ -1,62 +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 "qsslcertificate.h"
-#include "qsslcertificate_p.h"
-
-#include <wincrypt.h>
-
-QT_BEGIN_NAMESPACE
-
-QSslCertificate QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
-{
- QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
- certificateContext->cbCertEncoded);
-
- QSslCertificate certificate(derData, QSsl::Der);
- certificate.d->certificateContext = CertDuplicateCertificateContext(certificateContext);
- return certificate;
-}
-
-Qt::HANDLE QSslCertificate::handle() const
-{
- return Qt::HANDLE(d->certificateContext);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificateextension.cpp b/src/network/ssl/qsslcertificateextension.cpp
index 4896d3909a..3f583e2e2f 100644
--- a/src/network/ssl/qsslcertificateextension.cpp
+++ b/src/network/ssl/qsslcertificateextension.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QSslCertificateExtension
diff --git a/src/network/ssl/qsslcertificateextension.h b/src/network/ssl/qsslcertificateextension.h
index 7cc8a888be..c639d2fa45 100644
--- a/src/network/ssl/qsslcertificateextension.h
+++ b/src/network/ssl/qsslcertificateextension.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATEEXTENSION_H
#define QSSLCERTIFICATEEXTENSION_H
@@ -59,7 +23,7 @@ public:
QSslCertificateExtension &operator=(const QSslCertificateExtension &other);
~QSslCertificateExtension();
- void swap(QSslCertificateExtension &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslCertificateExtension &other) noexcept { d.swap(other.d); }
QString oid() const;
QString name() const;
diff --git a/src/network/ssl/qsslcertificateextension_p.h b/src/network/ssl/qsslcertificateextension_p.h
index 373f92a5cf..3f5d1e373e 100644
--- a/src/network/ssl/qsslcertificateextension_p.h
+++ b/src/network/ssl/qsslcertificateextension_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 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$
-**
-****************************************************************************/
+// Copyright (C) 2011 Richard J. Moore <rich@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCERTIFICATEEXTENSION_P_H
#define QSSLCERTIFICATEEXTENSION_P_H
diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp
index 738d521a38..2a4da7991a 100644
--- a/src/network/ssl/qsslcipher.cpp
+++ b/src/network/ssl/qsslcipher.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -68,6 +32,9 @@
QT_BEGIN_NAMESPACE
+static_assert(QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ && sizeof(QScopedPointer<QSslCipherPrivate>) == sizeof(std::unique_ptr<QSslCipherPrivate>));
+
/*!
Constructs an empty QSslCipher object.
*/
@@ -127,7 +94,7 @@ QSslCipher::QSslCipher(const QString &name, QSsl::SslProtocol protocol)
QSslCipher::QSslCipher(const QSslCipher &other)
: d(new QSslCipherPrivate)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
}
/*!
@@ -143,7 +110,7 @@ QSslCipher::~QSslCipher()
*/
QSslCipher &QSslCipher::operator=(const QSslCipher &other)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
return *this;
}
diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h
index 6994f590ae..ed727947f5 100644
--- a/src/network/ssl/qsslcipher.h
+++ b/src/network/ssl/qsslcipher.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCIPHER_H
@@ -46,6 +10,8 @@
#include <QtCore/qscopedpointer.h>
#include <QtNetwork/qssl.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
@@ -64,7 +30,7 @@ public:
~QSslCipher();
void swap(QSslCipher &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslCipher &other) const;
inline bool operator!=(const QSslCipher &other) const { return !operator==(other); }
@@ -81,8 +47,9 @@ public:
QSsl::SslProtocol protocol() const;
private:
- QScopedPointer<QSslCipherPrivate> d;
- friend class QSslSocketBackendPrivate;
+ // ### Qt 7: make implicitly shared
+ std::unique_ptr<QSslCipherPrivate> d;
+ friend class QTlsBackend;
};
Q_DECLARE_SHARED(QSslCipher)
diff --git a/src/network/ssl/qsslcipher_p.h b/src/network/ssl/qsslcipher_p.h
index b8629f9f96..d7f5e7c471 100644
--- a/src/network/ssl/qsslcipher_p.h
+++ b/src/network/ssl/qsslcipher_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLCIPHER_P_H
#define QSSLCIPHER_P_H
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 8f8773ebaa..fd308d7037 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qssl_p.h"
#include "qsslconfiguration.h"
@@ -48,6 +12,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslConfiguration)
+
const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOptionDisableEmptyFragments
|QSsl::SslOptionDisableLegacyRenegotiation
|QSsl::SslOptionDisableCompression
@@ -107,7 +73,7 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
change the settings in the related SSL connection. You must call
setSslConfiguration on a modified QSslConfiguration object to
achieve that. The following example illustrates how to change the
- protocol to TLSv1_0 in a QSslSocket object:
+ protocol to TLSv1_2 in a QSslSocket object:
\snippet code/src_network_ssl_qsslconfiguration.cpp 0
@@ -139,6 +105,12 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
*/
/*!
+ \variable QSslConfiguration::ALPNProtocolHTTP2
+ \brief The value used for negotiating HTTP 2 during the Application-Layer
+ Protocol Negotiation.
+*/
+
+/*!
Constructs an empty SSL configuration. This configuration contains
no valid settings and the state will be empty. isNull() will
return true after this constructor is called.
@@ -252,15 +224,15 @@ bool QSslConfiguration::isNull() const
d->peerVerifyMode == QSslSocket::AutoVerifyPeer &&
d->peerVerifyDepth == 0 &&
d->allowRootCertOnDemandLoading == true &&
- d->caCertificates.count() == 0 &&
- d->ciphers.count() == 0 &&
+ d->caCertificates.size() == 0 &&
+ d->ciphers.size() == 0 &&
d->ellipticCurves.isEmpty() &&
d->ephemeralServerKey.isNull() &&
d->dhParams == QSslDiffieHellmanParameters::defaultParameters() &&
d->localCertificateChain.isEmpty() &&
d->privateKey.isNull() &&
d->peerCertificate.isNull() &&
- d->peerCertificateChain.count() == 0 &&
+ d->peerCertificateChain.size() == 0 &&
d->backendConfig.isEmpty() &&
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
d->sslSession.isNull() &&
@@ -518,7 +490,7 @@ QList<QSslCertificate> QSslConfiguration::peerCertificateChain() const
eventually select the session cipher. This ordered list must be in
place before the handshake phase begins.
- \sa ciphers(), setCiphers(), QSslSocket::supportedCiphers()
+ \sa ciphers(), setCiphers(), supportedCiphers()
*/
QSslCipher QSslConfiguration::sessionCipher() const
{
@@ -578,15 +550,13 @@ void QSslConfiguration::setPrivateKey(const QSslKey &key)
By default, the handshake phase can choose any of the ciphers
supported by this system's SSL libraries, which may vary from
system to system. The list of ciphers supported by this system's
- SSL libraries is returned by QSslSocket::supportedCiphers(). You can restrict
+ SSL libraries is returned by supportedCiphers(). You can restrict
the list of ciphers used for choosing the session cipher for this
socket by calling setCiphers() with a subset of the supported
ciphers. You can revert to using the entire set by calling
- setCiphers() with the list returned by QSslSocket::supportedCiphers().
-
- \note This is not currently supported in the Schannel backend.
+ setCiphers() with the list returned by supportedCiphers().
- \sa setCiphers(), QSslSocket::supportedCiphers()
+ \sa setCiphers(), supportedCiphers()
*/
QList<QSslCipher> QSslConfiguration::ciphers() const
{
@@ -601,9 +571,7 @@ QList<QSslCipher> QSslConfiguration::ciphers() const
Restricting the cipher suite must be done before the handshake
phase, where the session cipher is chosen.
- \note This is not currently supported in the Schannel backend.
-
- \sa ciphers(), QSslSocket::supportedCiphers()
+ \sa ciphers(), supportedCiphers()
*/
void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
{
@@ -615,27 +583,26 @@ void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
Sets the cryptographic cipher suite for this configuration to \a ciphers,
which is a colon-separated list of cipher suite names. The ciphers are listed
- in order of preference, starting with the most preferred cipher. For example:
-
- \snippet code/src_network_ssl_qsslconfiguration.cpp 1
-
+ in order of preference, starting with the most preferred cipher.
Each cipher name in \a ciphers must be the name of a cipher in the
list returned by supportedCiphers(). Restricting the cipher suite
must be done before the handshake phase, where the session cipher
is chosen.
- \note This is not currently supported in the Schannel backend.
+ \note With the Schannel backend the order of the ciphers is ignored and Schannel
+ picks the most secure one during the handshake.
\sa ciphers()
*/
void QSslConfiguration::setCiphers(const QString &ciphers)
{
- d->ciphers.clear();
- const auto cipherNames = ciphers.split(QLatin1Char(':'), Qt::SkipEmptyParts);
+ auto *p = d.data();
+ p->ciphers.clear();
+ const auto cipherNames = ciphers.split(u':', Qt::SkipEmptyParts);
for (const QString &cipherName : cipherNames) {
QSslCipher cipher(cipherName);
if (!cipher.isNull())
- d->ciphers << cipher;
+ p->ciphers << cipher;
}
}
@@ -955,7 +922,11 @@ void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint)
Retrieves the current set of Diffie-Hellman parameters.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
{
@@ -969,7 +940,14 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
a server to \a dhparams.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ Since 6.7 you can provide an empty Diffie-Hellman parameter to use auto selection
+ (see SSL_CTX_set_dh_auto of openssl) if the tls backend supports it.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams)
{
@@ -1063,11 +1041,7 @@ QByteArray QSslConfiguration::nextNegotiatedProtocol() const
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolHttp1_1
*/
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
void QSslConfiguration::setAllowedNextProtocols(const QList<QByteArray> &protocols)
-#else
-void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols)
-#endif
{
d->nextAllowedProtocols = protocols;
}
@@ -1116,7 +1090,7 @@ QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocol
supported SSL ciphers that are 128 bits or more
\endlist
- \sa QSslSocket::supportedCiphers(), setDefaultConfiguration()
+ \sa supportedCiphers(), setDefaultConfiguration()
*/
QSslConfiguration QSslConfiguration::defaultConfiguration()
{
@@ -1128,14 +1102,14 @@ QSslConfiguration QSslConfiguration::defaultConfiguration()
connections to be \a configuration. Existing connections are not
affected by this call.
- \sa QSslSocket::supportedCiphers(), defaultConfiguration()
+ \sa supportedCiphers(), defaultConfiguration()
*/
void QSslConfiguration::setDefaultConfiguration(const QSslConfiguration &configuration)
{
QSslConfigurationPrivate::setDefaultConfiguration(configuration);
}
-#if QT_CONFIG(dtls) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(dtls) || defined(Q_QDOC)
/*!
This function returns true if DTLS cookie verification was enabled on a
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 706ac5775f..dd2dd2a97c 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -72,11 +36,6 @@ class QSslKey;
class QSslEllipticCurve;
class QSslDiffieHellmanParameters;
-namespace dtlsopenssl
-{
-class DtlsState;
-}
-
class QSslConfigurationPrivate;
class Q_NETWORK_EXPORT QSslConfiguration
{
@@ -88,7 +47,7 @@ public:
QSslConfiguration &operator=(const QSslConfiguration &other);
void swap(QSslConfiguration &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
bool operator==(const QSslConfiguration &other) const;
inline bool operator!=(const QSslConfiguration &other) const
@@ -166,7 +125,7 @@ public:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
-#if QT_CONFIG(dtls) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(dtls) || defined(Q_QDOC)
bool dtlsCookieVerificationEnabled() const;
void setDtlsCookieVerificationEnabled(bool enable);
@@ -189,11 +148,7 @@ public:
NextProtocolNegotiationUnsupported
};
-#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
void setAllowedNextProtocols(const QList<QByteArray> &protocols);
-#else
- void setAllowedNextProtocols(QList<QByteArray> protocols);
-#endif
QList<QByteArray> allowedNextProtocols() const;
QByteArray nextNegotiatedProtocol() const;
@@ -205,10 +160,8 @@ public:
private:
friend class QSslSocket;
friend class QSslConfigurationPrivate;
- friend class QSslSocketBackendPrivate;
friend class QSslContext;
- friend class QDtlsBasePrivate;
- friend class dtlsopenssl::DtlsState;
+ friend class QTlsBackend;
QSslConfiguration(QSslConfigurationPrivate *dd);
QSharedDataPointer<QSslConfigurationPrivate> d;
};
@@ -217,7 +170,7 @@ Q_DECLARE_SHARED(QSslConfiguration)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslConfiguration)
+QT_DECL_METATYPE_EXTERN(QSslConfiguration, Q_NETWORK_EXPORT)
#endif // QT_NO_SSL
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 3d416b42d7..a31e7e1f04 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/****************************************************************************
**
@@ -118,7 +82,7 @@ public:
QSsl::SslOptions sslOptions;
- Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions;
+ static const QSsl::SslOptions defaultSslOptions;
QList<QSslEllipticCurve> ellipticCurves;
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
deleted file mode 100644
index 5fb7172583..0000000000
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ /dev/null
@@ -1,767 +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/qssl_p.h"
-#include "private/qsslsocket_p.h"
-#include "private/qsslcontext_openssl_p.h"
-#include "private/qsslsocket_openssl_p.h"
-#include "private/qsslsocket_openssl_symbols_p.h"
-#include "private/qssldiffiehellmanparameters_p.h"
-
-#include <vector>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(bool, forceSecurityLevel)
-
-Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
-{
- *forceSecurityLevel() = true;
-}
-
-// defined in qsslsocket_openssl.cpp:
-extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
-extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
-extern QString getErrorsFromOpenSsl();
-
-#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
-
-// Defined in qsslsocket.cpp
-QList<QSslCipher> q_getDefaultDtlsCiphers();
-
-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);
-}
-
-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;
-}
-
-#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->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") : QSslSocketBackendPrivate::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.
- long options = QSslSocketBackendPrivate::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 ? q_getDefaultDtlsCiphers() : QSslSocketPrivate::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(QSslSocketBackendPrivate::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(QSslSocketBackendPrivate::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::s_loadRootCertsOnDemand && 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 = QSslSocketBackendPrivate::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(QSslSocketBackendPrivate::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(QSslSocketBackendPrivate::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(QSslSocketBackendPrivate::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
- q_X509Callback;
-
- if (!isDtls && configuration.handshakeMustInterruptOnError())
- verificationCallback = 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(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
- sslContext->errorCode = QSslError::UnspecifiedError;
- return;
- }
-#endif
- }
-
- applyBackendConfig(sslContext);
-}
-
-#if QT_CONFIG(ocsp)
-extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *); // Defined in qsslsocket_openssl.cpp.
-#endif // ocsp
-// static
-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, 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 5385c42240..0000000000
--- a/src/network/ssl/qsslcontext_openssl_p.h
+++ /dev/null
@@ -1,129 +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);
-
- 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.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp
index c8f3e564a5..7da14f3536 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -56,6 +20,7 @@
#include "qssldiffiehellmanparameters.h"
#include "qssldiffiehellmanparameters_p.h"
+#include "qtlsbackend_p.h"
#include "qsslsocket.h"
#include "qsslsocket_p.h"
@@ -68,17 +33,18 @@
QT_BEGIN_NAMESPACE
-// The 1024-bit MODP group from RFC 2459 (Second Oakley Group)
+// The 2048-bit MODP group from RFC 3526
Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 =
- "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR"
- "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL"
- "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC";
+ "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO"
+ "NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr"
+ "+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc"
+ "YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei"
+ "j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==";
/*!
Returns the default QSslDiffieHellmanParameters used by QSslSocket.
- This is currently the 1024-bit MODP group from RFC 2459, also
- known as the Second Oakley Group.
+ This is currently the 2048-bit MODP group from RFC 3526.
*/
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters()
{
@@ -117,12 +83,15 @@ QSslDiffieHellmanParameters::QSslDiffieHellmanParameters()
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat encoding)
{
QSslDiffieHellmanParameters result;
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend)
+ return result;
switch (encoding) {
case QSsl::Der:
- result.d->decodeDer(encoded);
+ result.d->initFromDer(encoded);
break;
case QSsl::Pem:
- result.d->decodePem(encoded);
+ result.d->initFromPem(encoded);
break;
}
return result;
@@ -273,19 +242,47 @@ QString QSslDiffieHellmanParameters::errorString() const noexcept
return QCoreApplication::translate("QSslDiffieHellmanParameter", "The given Diffie-Hellman parameters are deemed unsafe");
}
- Q_UNREACHABLE();
- return QString();
+ Q_UNREACHABLE_RETURN(QString());
}
/*!
+ \fn bool QSslDiffieHellmanParameters::operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
\since 5.8
- \relates QSslDiffieHellmanParameters
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
*/
-bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+
+/*!
+ \fn bool QSslDiffieHellmanParameters::operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ \since 5.8
+
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns \c false.
+*/
+
+/*!
+ \internal
+*/
+bool QSslDiffieHellmanParameters::isEqual(const QSslDiffieHellmanParameters &other) const noexcept
+{
+ return d->derData == other.d->derData;
+}
+
+/*!
+ \internal
+*/
+void QSslDiffieHellmanParametersPrivate::initFromDer(const QByteArray &der)
+{
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromDer(der, &derData));
+}
+
+/*!
+ \internal
+*/
+void QSslDiffieHellmanParametersPrivate::initFromPem(const QByteArray &pem)
{
- return lhs.d->derData == rhs.d->derData;
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ error = QSslDiffieHellmanParameters::Error(tlsBackend->dhParametersFromPem(pem, &derData));
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/network/ssl/qssldiffiehellmanparameters.h b/src/network/ssl/qssldiffiehellmanparameters.h
index 6a3cf01ddc..d1a525ba26 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.h
+++ b/src/network/ssl/qssldiffiehellmanparameters.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLDIFFIEHELLMANPARAMETERS_H
@@ -63,14 +27,7 @@ class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparams);
#endif
-Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
-
-inline bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
-{
- return !operator==(lhs, rhs);
-}
-
-class QSslDiffieHellmanParameters
+class Q_NETWORK_EXPORT QSslDiffieHellmanParameters
{
public:
enum Error {
@@ -79,30 +36,36 @@ public:
UnsafeParametersError
};
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters defaultParameters();
+ static QSslDiffieHellmanParameters defaultParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other);
+ QSslDiffieHellmanParameters();
+ QSslDiffieHellmanParameters(const QSslDiffieHellmanParameters &other);
QSslDiffieHellmanParameters(QSslDiffieHellmanParameters &&other) noexcept : d(other.d) { other.d = nullptr; }
- Q_NETWORK_EXPORT ~QSslDiffieHellmanParameters();
+ ~QSslDiffieHellmanParameters();
- Q_NETWORK_EXPORT QSslDiffieHellmanParameters &operator=(const QSslDiffieHellmanParameters &other);
+ QSslDiffieHellmanParameters &operator=(const QSslDiffieHellmanParameters &other);
QSslDiffieHellmanParameters &operator=(QSslDiffieHellmanParameters &&other) noexcept { swap(other); return *this; }
- void swap(QSslDiffieHellmanParameters &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslDiffieHellmanParameters &other) noexcept { qt_ptr_swap(d, other.d); }
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat format = QSsl::Pem);
- Q_NETWORK_EXPORT static QSslDiffieHellmanParameters fromEncoded(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
+ static QSslDiffieHellmanParameters fromEncoded(const QByteArray &encoded, QSsl::EncodingFormat format = QSsl::Pem);
+ static QSslDiffieHellmanParameters fromEncoded(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
- Q_NETWORK_EXPORT bool isEmpty() const noexcept;
- Q_NETWORK_EXPORT bool isValid() const noexcept;
- Q_NETWORK_EXPORT Error error() const noexcept;
- Q_NETWORK_EXPORT QString errorString() const noexcept;
+ bool isEmpty() const noexcept;
+ bool isValid() const noexcept;
+ Error error() const noexcept;
+ QString errorString() const noexcept;
private:
QSslDiffieHellmanParametersPrivate *d;
friend class QSslContext;
- friend Q_NETWORK_EXPORT bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept;
+
+ bool isEqual(const QSslDiffieHellmanParameters &other) const noexcept;
+ friend bool operator==(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QSslDiffieHellmanParameters &lhs, const QSslDiffieHellmanParameters &rhs) noexcept
+ { return !lhs.isEqual(rhs); }
+
#ifndef QT_NO_DEBUG_STREAM
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslDiffieHellmanParameters &dhparam);
#endif
diff --git a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp b/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
deleted file mode 100644
index 8fcf141f73..0000000000
--- a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** 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 "qssldiffiehellmanparameters.h"
-#include "qssldiffiehellmanparameters_p.h"
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qbytearray.h>
-
-QT_BEGIN_NAMESPACE
-
-void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &)
-{
-}
-
-void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &)
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
deleted file mode 100644
index 05b3408b75..0000000000
--- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
+++ /dev/null
@@ -1,224 +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 "qssldiffiehellmanparameters.h"
-#include "qssldiffiehellmanparameters_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_p.h"
-
-#include "private/qssl_p.h"
-
-#include <QtCore/qatomic.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qscopeguard.h>
-#ifndef QT_NO_DEBUG_STREAM
-#include <QtCore/qdebug.h>
-#endif
-
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifdef OPENSSL_NO_DEPRECATED_3_0
-
-static 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");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
- const auto keyDeleter = qScopeGuard([key](){
- q_EVP_PKEY_free(key);
- });
- if (!q_EVP_PKEY_set1_DH(key, dh)) {
- qCWarning(lcSsl, "EVP_PKEY_set1_DH failed");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
-
- EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
- if (!keyCtx) {
- qCWarning(lcSsl, "EVP_PKEY_CTX_new failed");
- QSslSocketBackendPrivate::logAndClearErrorQueue();
- return 0;
- }
- const auto ctxDeleter = qScopeGuard([keyCtx]{
- q_EVP_PKEY_CTX_free(keyCtx);
- });
-
- const int result = q_EVP_PKEY_param_check(keyCtx);
- QSslSocketBackendPrivate::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
-
-static bool isSafeDH(DH *dh)
-{
- int status = 0;
- int bad = 0;
-
- 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);
-}
-
-void QSslDiffieHellmanParametersPrivate::decodeDer(const QByteArray &der)
-{
- if (der.isEmpty()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data());
- int len = der.size();
-
- QSslSocketPrivate::ensureInitialized();
-
- DH *dh = q_d2i_DHparams(nullptr, &data, len);
- if (dh) {
- if (isSafeDH(dh))
- derData = der;
- else
- error = QSslDiffieHellmanParameters::UnsafeParametersError;
- } else {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- }
-
- q_DH_free(dh);
-}
-
-void QSslDiffieHellmanParametersPrivate::decodePem(const QByteArray &pem)
-{
- if (pem.isEmpty()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- if (!QSslSocket::supportsSsl()) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- QSslSocketPrivate::ensureInitialized();
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio) {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- return;
- }
-
- DH *dh = nullptr;
- q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr);
-
- if (dh) {
- if (isSafeDH(dh)) {
- char *buf = nullptr;
- int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
- if (len > 0)
- derData = QByteArray(buf, len);
- else
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- } else {
- error = QSslDiffieHellmanParameters::UnsafeParametersError;
- }
- } else {
- error = QSslDiffieHellmanParameters::InvalidInputDataError;
- }
-
- q_DH_free(dh);
- q_BIO_free(bio);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qssldiffiehellmanparameters_p.h b/src/network/ssl/qssldiffiehellmanparameters_p.h
index 722c2e9cf0..705e0f007c 100644
--- a/src/network/ssl/qssldiffiehellmanparameters_p.h
+++ b/src/network/ssl/qssldiffiehellmanparameters_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLDIFFIEHELLMANPARAMETERS_P_H
@@ -53,23 +17,20 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QSharedData>
-#include "qsslkey.h"
#include "qssldiffiehellmanparameters.h"
-#include "qsslsocket_p.h" // includes wincrypt.h
+
+#include <QSharedData>
QT_BEGIN_NAMESPACE
class QSslDiffieHellmanParametersPrivate : public QSharedData
{
public:
- QSslDiffieHellmanParametersPrivate() : error(QSslDiffieHellmanParameters::NoError) {}
-
- void decodeDer(const QByteArray &der);
- void decodePem(const QByteArray &pem);
+ void initFromDer(const QByteArray &der);
+ void initFromPem(const QByteArray &pem);
- QSslDiffieHellmanParameters::Error error;
+ QSslDiffieHellmanParameters::Error error = QSslDiffieHellmanParameters::NoError;
QByteArray derData;
};
diff --git a/src/network/ssl/qsslellipticcurve.cpp b/src/network/ssl/qsslellipticcurve.cpp
index f7faa607bd..77aa66f3cc 100644
--- a/src/network/ssl/qsslellipticcurve.cpp
+++ b/src/network/ssl/qsslellipticcurve.cpp
@@ -1,43 +1,9 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslellipticcurve.h"
+#include "qtlsbackend_p.h"
+#include "qsslsocket_p.h"
#ifndef QT_NO_DEBUG_STREAM
#include <QDebug>
@@ -45,6 +11,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslEllipticCurve)
+
/*!
\class QSslEllipticCurve
\since 5.5
@@ -77,8 +45,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-
Returns an QSslEllipticCurve instance representing the
named curve \a name. The \a name is the conventional short
name for the curve, as represented by RFC 4492 (for instance \c{secp521r1}),
@@ -91,10 +57,19 @@ QT_BEGIN_NAMESPACE
\sa shortName()
*/
+QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
+{
+ QSslEllipticCurve result;
+ if (name.isEmpty())
+ return result;
-/*!
- \fn QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ result.id = tlsBackend->curveIdFromShortName(name);
+ return result;
+}
+
+/*!
Returns an QSslEllipticCurve instance representing the named curve \a name.
The \a name is a long name for the curve, whose exact spelling depends on the
SSL implementation.
@@ -105,24 +80,49 @@ QT_BEGIN_NAMESPACE
\sa longName()
*/
+QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
+{
+ QSslEllipticCurve result;
+ if (name.isEmpty())
+ return result;
-/*!
- \fn QString QSslEllipticCurve::shortName() const
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ result.id = tlsBackend->curveIdFromLongName(name);
+
+ return result;
+}
+/*!
Returns the conventional short name for this curve. If this
curve is invalid, returns an empty string.
\sa longName()
*/
+QString QSslEllipticCurve::shortName() const
+{
+ QString name;
-/*!
- \fn QString QSslEllipticCurve::longName() const
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ name = tlsBackend->shortNameForId(id);
+ return name;
+}
+
+/*!
Returns the conventional long name for this curve. If this
curve is invalid, returns an empty string.
\sa shortName()
*/
+QString QSslEllipticCurve::longName() const
+{
+ QString name;
+
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ name = tlsBackend->longNameForId(id);
+
+ return name;
+}
/*!
\fn bool QSslEllipticCurve::isValid() const
@@ -131,32 +131,36 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QSslEllipticCurve::isTlsNamedCurve() const
-
Returns true if this elliptic curve is one of the named curves that can be
used in the key exchange when using an elliptic curve cipher with TLS;
false otherwise.
*/
+bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
+{
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->isTlsNamedCurve(id);
+
+ return false;
+}
+
/*!
- \fn bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \fn bool QSslEllipticCurve::operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
\since 5.5
- \relates QSslEllipticCurve
Returns true if the curve \a lhs represents the same curve of \a rhs;
*/
/*!
- \fn bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
+ \fn bool QSslEllipticCurve::operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs)
\since 5.5
- \relates QSslEllipticCurve
Returns true if the curve \a lhs represents a different curve than \a rhs;
false otherwise.
*/
/*!
- \fn size_t qHash(QSslEllipticCurve curve, size_t seed)
+ \fn size_t qHash(QSslEllipticCurve curve, size_t seed = 0)
\since 5.5
\relates QHash
diff --git a/src/network/ssl/qsslellipticcurve.h b/src/network/ssl/qsslellipticcurve.h
index d777087344..0585ffbd0e 100644
--- a/src/network/ssl/qsslellipticcurve.h
+++ b/src/network/ssl/qsslellipticcurve.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLELLIPTICCURVE_H
#define QSSLELLIPTICCURVE_H
@@ -43,9 +7,6 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/QString>
#include <QtCore/QMetaType>
-#if QT_DEPRECATED_SINCE(5, 6)
-#include <QtCore/QHash>
-#endif
#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -64,8 +25,8 @@ public:
Q_NETWORK_EXPORT static QSslEllipticCurve fromShortName(const QString &name);
Q_NETWORK_EXPORT static QSslEllipticCurve fromLongName(const QString &name);
- Q_REQUIRED_RESULT Q_NETWORK_EXPORT QString shortName() const;
- Q_REQUIRED_RESULT Q_NETWORK_EXPORT QString longName() const;
+ [[nodiscard]] Q_NETWORK_EXPORT QString shortName() const;
+ [[nodiscard]] Q_NETWORK_EXPORT QString longName() const;
constexpr bool isValid() const noexcept
{
@@ -77,12 +38,14 @@ public:
private:
int id;
- friend constexpr bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept;
+ friend constexpr bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
+ { return lhs.id == rhs.id; }
+ friend constexpr bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
+ { return !(lhs == rhs); }
friend constexpr size_t qHash(QSslEllipticCurve curve, size_t seed) noexcept;
friend class QSslContext;
friend class QSslSocketPrivate;
- friend class QSslSocketBackendPrivate;
};
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
@@ -90,12 +53,6 @@ Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
constexpr inline size_t qHash(QSslEllipticCurve curve, size_t seed) noexcept
{ return qHash(curve.id, seed); }
-constexpr inline bool operator==(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
-{ return lhs.id == rhs.id; }
-
-constexpr inline bool operator!=(QSslEllipticCurve lhs, QSslEllipticCurve rhs) noexcept
-{ return !operator==(lhs, rhs); }
-
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslEllipticCurve curve);
@@ -103,6 +60,6 @@ Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslEllipticCurve curve);
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslEllipticCurve)
+QT_DECL_METATYPE_EXTERN(QSslEllipticCurve, Q_NETWORK_EXPORT)
#endif // QSSLELLIPTICCURVE_H
diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp
deleted file mode 100644
index 1313e06875..0000000000
--- a/src/network/ssl/qsslellipticcurve_dummy.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qsslellipticcurve.h"
-
-QT_BEGIN_NAMESPACE
-
-QString QSslEllipticCurve::shortName() const
-{
- return QString();
-}
-
-QString QSslEllipticCurve::longName() const
-{
- return QString();
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-{
- Q_UNUSED(name);
- return QSslEllipticCurve();
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
-{
- Q_UNUSED(name);
- return QSslEllipticCurve();
-}
-
-bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
-{
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslellipticcurve_openssl.cpp b/src/network/ssl/qsslellipticcurve_openssl.cpp
deleted file mode 100644
index bb7ad66bd2..0000000000
--- a/src/network/ssl/qsslellipticcurve_openssl.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** 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 "qsslellipticcurve.h"
-#include "qsslsocket_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-
-#include <openssl/ssl.h>
-#include <openssl/obj_mac.h>
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-QString QSslEllipticCurve::shortName() const
-{
- QString result;
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2sn(id));
-#endif
- return result;
-}
-
-QString QSslEllipticCurve::longName() const
-{
- QString result;
-#ifndef OPENSSL_NO_EC
- if (id != 0)
- result = QString::fromLatin1(q_OBJ_nid2ln(id));
-#endif
- return result;
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromShortName(const QString &name)
-{
- if (name.isEmpty())
- return QSslEllipticCurve();
-
- QSslSocketPrivate::ensureInitialized();
-
- QSslEllipticCurve result;
-
-#ifndef OPENSSL_NO_EC
-
- const QByteArray curveNameLatin1 = name.toLatin1();
- int nid = q_OBJ_sn2nid(curveNameLatin1.data());
-
- if (nid == 0)
- nid = q_EC_curve_nist2nid(curveNameLatin1.data());
-
- result.id = nid;
-
-#endif // !OPENSSL_NO_EC
-
- return result;
-}
-
-QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name)
-{
- if (name.isEmpty())
- return QSslEllipticCurve();
-
- QSslSocketPrivate::ensureInitialized();
-
- QSslEllipticCurve result;
-
-#ifndef OPENSSL_NO_EC
- const QByteArray curveNameLatin1 = name.toLatin1();
-
- int nid = q_OBJ_ln2nid(curveNameLatin1.data());
- result.id = nid;
-#endif
-
- return result;
-}
-
-
-// The brainpool curve NIDs (RFC 7027) have been introduced in OpenSSL 1.0.2,
-// redefine them here to make Qt compile with previous versions of OpenSSL
-// (yet correctly recognize them as TLS named curves).
-// See crypto/objects/obj_mac.h
-#ifndef NID_brainpoolP256r1
-#define NID_brainpoolP256r1 927
-#endif
-
-#ifndef NID_brainpoolP384r1
-#define NID_brainpoolP384r1 931
-#endif
-
-#ifndef NID_brainpoolP512r1
-#define NID_brainpoolP512r1 933
-#endif
-
-// 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
-};
-
-static const size_t tlsNamedCurveNIDCount = sizeof(tlsNamedCurveNIDs) / sizeof(tlsNamedCurveNIDs[0]);
-
-bool QSslEllipticCurve::isTlsNamedCurve() const noexcept
-{
- const int * const tlsNamedCurveNIDsEnd = tlsNamedCurveNIDs + tlsNamedCurveNIDCount;
- return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp
index 5e935adf09..241e6291ac 100644
--- a/src/network/ssl/qsslerror.cpp
+++ b/src/network/ssl/qsslerror.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -111,6 +75,16 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_SSL
+QT_IMPL_METATYPE_EXTERN_TAGGED(QList<QSslError>, QList_QSslError)
+#endif
+
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+// Avoid an ABI break due to the QScopedPointer->std::unique_ptr change
+static_assert(sizeof(QScopedPointer<QSslErrorPrivate>) == sizeof(std::unique_ptr<QSslErrorPrivate>));
+#endif
+
class QSslErrorPrivate
{
public:
@@ -163,7 +137,7 @@ QSslError::QSslError(SslError error, const QSslCertificate &certificate)
QSslError::QSslError(const QSslError &other)
: d(new QSslErrorPrivate)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
}
/*!
@@ -180,7 +154,7 @@ QSslError::~QSslError()
*/
QSslError &QSslError::operator=(const QSslError &other)
{
- *d.data() = *other.d.data();
+ *d.get() = *other.d.get();
return *this;
}
@@ -385,3 +359,5 @@ QDebug operator<<(QDebug debug, const QSslError::SslError &error)
#endif
QT_END_NAMESPACE
+
+#include "moc_qsslerror.cpp"
diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h
index f135dd10b7..d82b086d39 100644
--- a/src/network/ssl/qsslerror.h
+++ b/src/network/ssl/qsslerror.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLERROR_H
@@ -45,6 +9,8 @@
#include <QtCore/qvariant.h>
#include <QtNetwork/qsslcertificate.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
@@ -106,7 +72,7 @@ public:
QSslError(const QSslError &other);
void swap(QSslError &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
~QSslError();
QSslError &operator=(QSslError &&other) noexcept { swap(other); return *this; }
@@ -120,7 +86,8 @@ public:
QSslCertificate certificate() const;
private:
- QScopedPointer<QSslErrorPrivate> d;
+ // ### Qt 7: make QSslError implicitly shared
+ std::unique_ptr<QSslErrorPrivate> d;
};
Q_DECLARE_SHARED(QSslError)
@@ -138,7 +105,7 @@ class Q_NETWORK_EXPORT QSslError {}; // dummy class so that moc has a complete t
QT_END_NAMESPACE
#ifndef QT_NO_SSL
-Q_DECLARE_METATYPE(QList<QSslError>)
+QT_DECL_METATYPE_EXTERN_TAGGED(QList<QSslError>, QList_QSslError, Q_NETWORK_EXPORT)
#endif
#endif
diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h
index 9e70554716..decfc4b5a1 100644
--- a/src/network/ssl/qsslkey.h
+++ b/src/network/ssl/qsslkey.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLKEY_H
@@ -44,7 +8,7 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qsharedpointer.h>
+#include <QtCore/qshareddata.h>
#include <QtNetwork/qssl.h>
QT_BEGIN_NAMESPACE
@@ -74,7 +38,7 @@ public:
QSslKey &operator=(const QSslKey &other);
~QSslKey();
- void swap(QSslKey &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslKey &other) noexcept { d.swap(other.d); }
bool isNull() const;
void clear();
@@ -84,6 +48,7 @@ public:
QSsl::KeyAlgorithm algorithm() const;
QByteArray toPem(const QByteArray &passPhrase = QByteArray()) const;
+ // ### Qt 7: drop passPhrase
QByteArray toDer(const QByteArray &passPhrase = QByteArray()) const;
Qt::HANDLE handle() const;
@@ -93,8 +58,7 @@ public:
private:
QExplicitlySharedDataPointer<QSslKeyPrivate> d;
- friend class QSslCertificate;
- friend class QSslSocketBackendPrivate;
+ friend class QTlsBackend;
};
Q_DECLARE_SHARED(QSslKey)
diff --git a/src/network/ssl/qsslkey_mac.cpp b/src/network/ssl/qsslkey_mac.cpp
deleted file mode 100644
index 814fe1c4bc..0000000000
--- a/src/network/ssl/qsslkey_mac.cpp
+++ /dev/null
@@ -1,99 +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 "qsslkey.h"
-#include "qsslkey_p.h"
-
-#include <CommonCrypto/CommonCrypto.h>
-
-#include <cstddef>
-
-QT_BEGIN_NAMESPACE
-
-static QByteArray wrapCCCrypt(CCOperation ccOp,
- QSslKeyPrivate::Cipher cipher,
- const QByteArray &data,
- const QByteArray &key, const QByteArray &iv)
-{
- int blockSize;
- CCAlgorithm ccAlgorithm;
- switch (cipher) {
- case QSslKeyPrivate::DesCbc:
- blockSize = kCCBlockSizeDES;
- ccAlgorithm = kCCAlgorithmDES;
- break;
- case QSslKeyPrivate::DesEde3Cbc:
- blockSize = kCCBlockSize3DES;
- ccAlgorithm = kCCAlgorithm3DES;
- break;
- case QSslKeyPrivate::Rc2Cbc:
- blockSize = kCCBlockSizeRC2;
- ccAlgorithm = kCCAlgorithmRC2;
- break;
- case QSslKeyPrivate::Aes128Cbc:
- case QSslKeyPrivate::Aes192Cbc:
- case QSslKeyPrivate::Aes256Cbc:
- blockSize = kCCBlockSizeAES128;
- ccAlgorithm = kCCAlgorithmAES;
- break;
- }
- 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 QByteArray();
-}
-
-QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return wrapCCCrypt(kCCDecrypt, cipher, data, key, iv);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return wrapCCCrypt(kCCEncrypt, cipher, data, key, iv);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
deleted file mode 100644
index 43cb8c6de8..0000000000
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** 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 "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_p.h"
-
-#include <QtCore/qatomic.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qiodevice.h>
-#ifndef QT_NO_DEBUG_STREAM
-#include <QtCore/qdebug.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-void QSslKeyPrivate::clear(bool deep)
-{
- isNull = true;
- if (!QSslSocket::supportsSsl())
- return;
- 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;
- }
-}
-
-bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
-{
- if (pkey == nullptr)
- return false;
-
- const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
- if (keyType == EVP_PKEY_RSA) {
- isNull = false;
- algorithm = QSsl::Rsa;
- type = QSsl::PrivateKey;
- rsa = q_EVP_PKEY_get1_RSA(pkey);
- return true;
- } else if (keyType == EVP_PKEY_DSA) {
- isNull = false;
- algorithm = QSsl::Dsa;
- type = QSsl::PrivateKey;
- dsa = q_EVP_PKEY_get1_DSA(pkey);
- return true;
- } else if (keyType == EVP_PKEY_DH) {
- isNull = false;
- algorithm = QSsl::Dh;
- type = QSsl::PrivateKey;
- dh = q_EVP_PKEY_get1_DH(pkey);
- return true;
- }
-#ifndef OPENSSL_NO_EC
- else if (keyType == EVP_PKEY_EC) {
- isNull = false;
- algorithm = QSsl::Ec;
- type = QSsl::PrivateKey;
- ec = q_EVP_PKEY_get1_EC_KEY(pkey);
- return true;
- }
-#endif
- else {
- // 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;
-}
-
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
-{
- QMap<QByteArray, QByteArray> headers;
- decodePem(pemFromDer(der, headers), passPhrase, deepClear);
-}
-
-void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear)
-{
- if (pem.isEmpty())
- return;
-
- clear(deepClear);
-
- if (!QSslSocket::supportsSsl())
- return;
-
- BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
- if (!bio)
- return;
-
- void *phrase = const_cast<char *>(passPhrase.constData());
-
- 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)
- isNull = 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)
- isNull = 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)
- isNull = 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)
- isNull = false;
-#endif
- }
-
- q_BIO_free(bio);
-}
-
-int QSslKeyPrivate::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 QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
-{
- if (!QSslSocket::supportsSsl() || isNull || algorithm == QSsl::Opaque)
- return QByteArray();
-
- // ### the cipher should be selectable in the API:
- const EVP_CIPHER *cipher = nullptr;
- if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) {
-#ifndef OPENSSL_NO_DES
- cipher = q_EVP_des_ede3_cbc();
-#else
- return QByteArray();
-#endif
- }
-
- BIO *bio = q_BIO_new(q_BIO_s_mem());
- if (!bio)
- return QByteArray();
-
- 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;
- long size = q_BIO_get_mem_data(bio, &data);
- pem = QByteArray(data, size);
- }
- q_BIO_free(bio);
- return pem;
-}
-
-Qt::HANDLE QSslKeyPrivate::handle() const
-{
- switch (algorithm) {
- 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);
- }
-}
-
-static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, int enc)
-{
- const EVP_CIPHER* type = nullptr;
- int i = 0, len = 0;
-
- switch (cipher) {
- case QSslKeyPrivate::DesCbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_cbc();
-#endif
- break;
- case QSslKeyPrivate::DesEde3Cbc:
-#ifndef OPENSSL_NO_DES
- type = q_EVP_des_ede3_cbc();
-#endif
- break;
- case QSslKeyPrivate::Rc2Cbc:
-#ifndef OPENSSL_NO_RC2
- type = q_EVP_rc2_cbc();
-#endif
- break;
- case QSslKeyPrivate::Aes128Cbc:
- type = q_EVP_aes_128_cbc();
- break;
- case QSslKeyPrivate::Aes192Cbc:
- type = q_EVP_aes_192_cbc();
- break;
- case QSslKeyPrivate::Aes256Cbc:
- type = q_EVP_aes_256_cbc();
- break;
- }
-
- if (type == nullptr)
- return QByteArray();
-
- 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 == QSslKeyPrivate::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 QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, 0);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, 1);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index ce12f49989..55cb2b0436 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -54,14 +18,12 @@
\sa QSslSocket, QSslCertificate, QSslCipher
*/
+#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>
#include <QtCore/qbytearray.h>
@@ -73,11 +35,6 @@
QT_BEGIN_NAMESPACE
/*!
- \fn void QSslKeyPrivate::clear(bool deep)
- \internal
- */
-
-/*!
\fn void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear)
\internal
@@ -94,210 +51,57 @@ QT_BEGIN_NAMESPACE
*/
/*!
- Constructs a null key.
-
- \sa isNull()
-*/
-QSslKey::QSslKey()
- : d(new QSslKeyPrivate)
-{
-}
-
-/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemHeader() const
+QSslKeyPrivate::QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
-}
-
-static QByteArray pkcs8Header(bool encrypted)
-{
- return encrypted
- ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend)
+ return;
+ backend.reset(tlsBackend->createKey());
+ if (backend.get())
+ backend->clear(false /*not deep clear*/);
+ else
+ qCWarning(lcSsl, "Active TLS backend does not support key creation");
}
/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemFooter() const
+QSslKeyPrivate::~QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----END PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----END PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
+ if (backend.get())
+ backend->clear(true /*deep clear*/);
}
-static QByteArray pkcs8Footer(bool encrypted)
+QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- return encrypted
- ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----END PRIVATE KEY-----");
-}
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->decrypt(cipher, data, key, iv);
+ }
-/*!
- \internal
+ return {};
+}
- Returns a DER key formatted as PEM.
-*/
-QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- QByteArray pem(der.toBase64());
-
- const int lineWidth = 64; // RFC 1421
- const int newLines = pem.size() / lineWidth;
- const bool rem = pem.size() % lineWidth;
-
- // ### optimize
- 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 (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->encrypt(cipher, data, key, iv);
}
- if (isEncryptedPkcs8(der)) {
- pem.prepend(pkcs8Header(true) + '\n' + extra);
- pem.append(pkcs8Footer(true) + '\n');
-#if !QT_CONFIG(openssl)
- } else if (isPkcs8) {
- pem.prepend(pkcs8Header(false) + '\n' + extra);
- pem.append(pkcs8Footer(false) + '\n');
-#endif
- } else {
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
- }
-
- return pem;
+ return {};
}
/*!
- \internal
+ Constructs a null key.
- Returns a PEM key formatted as DER.
+ \sa isNull()
*/
-QByteArray QSslKeyPrivate::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
-}
-
-bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
+QSslKey::QSslKey()
+ : d(new QSslKeyPrivate)
{
- 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);
}
/*!
@@ -314,12 +118,12 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
: d(new QSslKeyPrivate)
{
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -339,12 +143,13 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QByteArray encoded;
if (device)
encoded = device->readAll();
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -358,20 +163,8 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
: d(new QSslKeyPrivate)
{
-#ifndef QT_NO_OPENSSL
- EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
- if (!evpKey || !d->fromEVP_PKEY(evpKey)) {
- d->opaque = evpKey;
- d->algorithm = QSsl::Opaque;
- } else {
- q_EVP_PKEY_free(evpKey);
- }
-#else
- d->opaque = handle;
- d->algorithm = QSsl::Opaque;
-#endif
- d->type = type;
- d->isNull = !d->opaque;
+ if (auto *tlsKey = d->backend.get())
+ tlsKey->fromHandle(handle, type);
}
/*!
@@ -433,7 +226,10 @@ QSslKey &QSslKey::operator=(const QSslKey &other)
*/
bool QSslKey::isNull() const
{
- return d->isNull;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->isNull();
+
+ return true;
}
/*!
@@ -451,7 +247,10 @@ void QSslKey::clear()
*/
int QSslKey::length() const
{
- return d->length();
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->length();
+
+ return -1;
}
/*!
@@ -459,7 +258,10 @@ int QSslKey::length() const
*/
QSsl::KeyType QSslKey::type() const
{
- return d->type;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->type();
+
+ return QSsl::PublicKey;
}
/*!
@@ -467,7 +269,10 @@ QSsl::KeyType QSslKey::type() const
*/
QSsl::KeyAlgorithm QSslKey::algorithm() const
{
- return d->algorithm;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->algorithm();
+
+ return QSsl::Opaque;
}
/*!
@@ -478,19 +283,18 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const
*/
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
{
- if (d->isNull || d->algorithm == QSsl::Opaque)
- return QByteArray();
+ if (isNull() || algorithm() == QSsl::Opaque)
+ return {};
// Encrypted DER is nonsense, see QTBUG-41038.
- if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
- return QByteArray();
+ if (type() == QSsl::PrivateKey && !passPhrase.isEmpty())
+ return {};
-#ifndef QT_NO_OPENSSL
QMap<QByteArray, QByteArray> headers;
- return d->derFromPem(toPem(passPhrase), &headers);
-#else
- return d->derData;
-#endif
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->derFromPem(toPem(passPhrase), &headers);
+
+ return {};
}
/*!
@@ -500,7 +304,10 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
*/
QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
{
- return d->toPem(passPhrase);
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->toPem(passPhrase);
+
+ return {};
}
/*!
@@ -516,7 +323,10 @@ QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
*/
Qt::HANDLE QSslKey::handle() const
{
- return d->handle();
+ if (d->backend.get())
+ return d->backend->handle();
+
+ return nullptr;
}
/*!
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index dd1a31b0e5..d28ee5ad11 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLKEY_OPENSSL_P_H
@@ -53,83 +17,30 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include "qsslkey.h"
-#include "qsslsocket_p.h" // includes wincrypt.h
+#include "qssl_p.h"
-#ifndef QT_NO_OPENSSL
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-#endif
+#include <memory>
QT_BEGIN_NAMESPACE
+namespace QTlsPrivate {
+class TlsKey;
+}
+
class QSslKeyPrivate
{
public:
- inline QSslKeyPrivate()
- : algorithm(QSsl::Opaque)
- , opaque(nullptr)
- {
- clear(false);
- }
-
- inline ~QSslKeyPrivate()
- { clear(); }
-
- void clear(bool deep = true);
-
-#ifndef QT_NO_OPENSSL
- bool fromEVP_PKEY(EVP_PKEY *pkey);
-#endif
- void decodeDer(const QByteArray &der, const QByteArray &passPhrase = {}, bool deepClear = true);
- void decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear = true);
- QByteArray pemHeader() const;
- QByteArray pemFooter() const;
- QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const;
- QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const;
-
- int length() const;
- QByteArray toPem(const QByteArray &passPhrase) const;
- Qt::HANDLE handle() const;
-
- bool isEncryptedPkcs8(const QByteArray &der) const;
-#if !QT_CONFIG(openssl)
- QByteArray decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase);
- bool isPkcs8 = false;
-#endif
-
- bool isNull;
- QSsl::KeyType type;
- QSsl::KeyAlgorithm algorithm;
-
- enum Cipher {
- DesCbc,
- DesEde3Cbc,
- Rc2Cbc,
- Aes128Cbc,
- Aes192Cbc,
- Aes256Cbc
- };
+ QSslKeyPrivate();
+ ~QSslKeyPrivate();
- 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);
+ using Cipher = QTlsPrivate::Cipher;
-#ifndef QT_NO_OPENSSL
- union {
- EVP_PKEY *opaque;
- RSA *rsa;
- DSA *dsa;
- DH *dh;
-#ifndef OPENSSL_NO_EC
- EC_KEY *ec;
-#endif
- };
-#else
- Qt::HANDLE opaque;
- QByteArray derData;
- int keyLength;
-#endif
+ 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;
private:
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
deleted file mode 100644
index 3b8fada8fc..0000000000
--- a/src/network/ssl/qsslkey_qt.cpp
+++ /dev/null
@@ -1,785 +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 "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qasn1element_p.h"
-
-#include <QtCore/qdatastream.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/QMessageAuthenticationCode>
-#include <QtCore/qrandom.h>
-
-#include <QtNetwork/qpassworddigestor.h>
-
-#include <cstring>
-
-QT_USE_NAMESPACE
-
-static 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,
-};
-
-// 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
-
-typedef QMap<QByteArray, int> OidLengthMap;
-static 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;
-}
-Q_GLOBAL_STATIC_WITH_ARGS(OidLengthMap, oidLengthMap, (createOidMap()))
-
-static int curveBits(const QByteArray &oid)
-{
- const int length = oidLengthMap->value(oid);
- return length ? length : -1;
-}
-
-static 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;
-}
-
-static 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 == QSslKeyPrivate::Aes128Cbc)
- return hash.result();
-
- QByteArray key(hash.result());
- hash.reset();
- hash.addData(key);
- hash.addData(data);
-
- if (cipher == QSslKeyPrivate::Aes192Cbc)
- return key.append(hash.result().constData(), 8);
-
- return key.append(hash.result());
-}
-
-static 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 QSslKeyPrivate::DesCbc:
- key = hash.result().left(8);
- break;
- case QSslKeyPrivate::DesEde3Cbc:
- key = hash.result();
- hash.reset();
- hash.addData(key);
- hash.addData(passPhrase);
- hash.addData(iv);
- key += hash.result().left(8);
- break;
- case QSslKeyPrivate::Rc2Cbc:
- key = hash.result();
- break;
- case QSslKeyPrivate::Aes128Cbc:
- case QSslKeyPrivate::Aes192Cbc:
- case QSslKeyPrivate::Aes256Cbc:
- return deriveAesKey(cipher, passPhrase, iv);
- }
- return key;
-}
-
-void QSslKeyPrivate::clear(bool deep)
-{
- isNull = true;
- if (deep)
- std::memset(derData.data(), 0, derData.size());
- derData.clear();
- keyLength = -1;
-}
-
-static int extractPkcs8KeyLength(const QList<QAsn1Element> &items, QSslKeyPrivate *that)
-{
- Q_ASSERT(items.size() == 3);
- int keyLength;
-
- 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(items[2].value());
- // 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;
-}
-
-void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
-{
- 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;
- isPkcs8 = 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;
- isNull = false;
-}
-
-void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear)
-{
- 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;
- }
-
- Cipher cipher;
- if (dekInfo.first() == "DES-CBC") {
- cipher = DesCbc;
- } else if (dekInfo.first() == "DES-EDE3-CBC") {
- cipher = DesEde3Cbc;
- } else if (dekInfo.first() == "RC2-CBC") {
- cipher = Rc2Cbc;
- } else if (dekInfo.first() == "AES-128-CBC") {
- cipher = Aes128Cbc;
- } else if (dekInfo.first() == "AES-192-CBC") {
- cipher = Aes192Cbc;
- } else if (dekInfo.first() == "AES-256-CBC") {
- 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(data, passPhrase, deepClear);
-}
-
-int QSslKeyPrivate::length() const
-{
- return keyLength;
-}
-
-QByteArray QSslKeyPrivate::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));
-
- 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);
-}
-
-Qt::HANDLE QSslKeyPrivate::handle() const
-{
- return opaque;
-}
-
-// Maps OIDs to the encryption cipher they specify
-static 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() : initialized(false)
- {}
- EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
- : initialized(true), cipher(cipher), key(key), iv(iv)
- {}
- bool initialized;
- QSslKeyPrivate::Cipher cipher;
- QByteArray key;
- QByteArray iv;
-};
-
-static 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 bugreport 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
-static 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}
-};
-
-static 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};
-}
-
-QByteArray QSslKeyPrivate::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();
-}
diff --git a/src/network/ssl/qsslkey_schannel.cpp b/src/network/ssl/qsslkey_schannel.cpp
deleted file mode 100644
index 1e21d123f4..0000000000
--- a/src/network/ssl/qsslkey_schannel.cpp
+++ /dev/null
@@ -1,178 +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 "qssl_p.h"
-#include "qsslkey.h"
-#include "qsslkey_p.h"
-#include "qsslcertificate_p.h"
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qscopeguard.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace {
-const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
-{
- switch (cipher) {
- case QSslKeyPrivate::Cipher::DesCbc:
- return BCRYPT_DES_ALGORITHM;
- case QSslKeyPrivate::Cipher::DesEde3Cbc:
- return BCRYPT_3DES_ALGORITHM;
- case QSslKeyPrivate::Cipher::Rc2Cbc:
- return BCRYPT_RC2_ALGORITHM;
- case QSslKeyPrivate::Cipher::Aes128Cbc:
- case QSslKeyPrivate::Cipher::Aes192Cbc:
- case QSslKeyPrivate::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(lcSsl, "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(lcSsl, "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(lcSsl, "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(lcSsl, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt", status);
- return {};
- }
- }
-
- return QByteArray(reinterpret_cast<const char *>(output.constData()), int(sizeNeeded));
-}
-} // anonymous namespace
-
-QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, false);
-}
-
-QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key,
- const QByteArray &iv)
-{
- return doCrypt(cipher, data, key, iv, true);
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.cpp b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
index ed6dbb87cf..0045a83bea 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.cpp
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsslpresharedkeyauthenticator.h"
#include "qsslpresharedkeyauthenticator_p.h"
@@ -44,6 +8,9 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QSslPreSharedKeyAuthenticator)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QSslPreSharedKeyAuthenticator*, QSslPreSharedKeyAuthenticator_ptr)
+
/*!
\internal
*/
@@ -240,35 +207,36 @@ int QSslPreSharedKeyAuthenticator::maximumPreSharedKeyLength() const
}
/*!
- \relates QSslPreSharedKeyAuthenticator
+ \fn bool QSslPreSharedKeyAuthenticator::operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
\since 5.5
- Returns true if the authenticator object \a lhs is equal to \a rhs; false
- otherwise.
+ Returns \c true if the authenticator object \a lhs is equal to \a rhs;
+ \c false otherwise.
Two authenticator objects are equal if and only if they have the same
identity hint, identity, pre shared key, maximum length for the identity
and maximum length for the pre shared key.
-
*/
-bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
-{
- return ((lhs.d == rhs.d) ||
- (lhs.d->identityHint == rhs.d->identityHint &&
- lhs.d->identity == rhs.d->identity &&
- lhs.d->maximumIdentityLength == rhs.d->maximumIdentityLength &&
- lhs.d->preSharedKey == rhs.d->preSharedKey &&
- lhs.d->maximumPreSharedKeyLength == rhs.d->maximumPreSharedKeyLength));
-}
/*!
- \fn bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
- \relates QSslPreSharedKeyAuthenticator
+ \fn bool QSslPreSharedKeyAuthenticator::operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
\since 5.5
- Returns true if the authenticator object \a lhs is different than \a rhs;
- false otherwise.
+ Returns \c true if the authenticator object \a lhs is not equal to \a rhs;
+ \c false otherwise.
+*/
+/*!
+ \internal
*/
+bool QSslPreSharedKeyAuthenticator::isEqual(const QSslPreSharedKeyAuthenticator &other) const
+{
+ return ((d == other.d) ||
+ (d->identityHint == other.d->identityHint &&
+ d->identity == other.d->identity &&
+ d->maximumIdentityLength == other.d->maximumIdentityLength &&
+ d->preSharedKey == other.d->preSharedKey &&
+ d->maximumPreSharedKeyLength == other.d->maximumPreSharedKeyLength));
+}
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h
index 5d714dc34e..a3912406d3 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_H
#define QSSLPRESHAREDKEYAUTHENTICATOR_H
@@ -50,9 +14,9 @@ QT_REQUIRE_CONFIG(ssl);
QT_BEGIN_NAMESPACE
class QSslPreSharedKeyAuthenticatorPrivate;
-
class QSslPreSharedKeyAuthenticator
{
+ Q_GADGET_EXPORT(Q_NETWORK_EXPORT)
public:
Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator();
Q_NETWORK_EXPORT ~QSslPreSharedKeyAuthenticator();
@@ -61,7 +25,7 @@ public:
QSslPreSharedKeyAuthenticator &operator=(QSslPreSharedKeyAuthenticator &&other) noexcept { swap(other); return *this; }
- void swap(QSslPreSharedKeyAuthenticator &other) noexcept { qSwap(d, other.d); }
+ void swap(QSslPreSharedKeyAuthenticator &other) noexcept { d.swap(other.d); }
Q_NETWORK_EXPORT QByteArray identityHint() const;
@@ -74,23 +38,24 @@ public:
Q_NETWORK_EXPORT int maximumPreSharedKeyLength() const;
private:
- friend Q_NETWORK_EXPORT bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs);
- friend class QSslSocketBackendPrivate;
- friend class QDtlsPrivateOpenSSL;
+ Q_NETWORK_EXPORT bool isEqual(const QSslPreSharedKeyAuthenticator &other) const;
+
+ friend class QTlsBackend;
+
+ friend bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+ { return !lhs.isEqual(rhs); }
QSharedDataPointer<QSslPreSharedKeyAuthenticatorPrivate> d;
};
-inline bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
-{
- return !operator==(lhs, rhs);
-}
Q_DECLARE_SHARED(QSslPreSharedKeyAuthenticator)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator)
-Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator*)
+QT_DECL_METATYPE_EXTERN(QSslPreSharedKeyAuthenticator, Q_NETWORK_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QSslPreSharedKeyAuthenticator*, QSslPreSharedKeyAuthenticator_ptr, Q_NETWORK_EXPORT)
#endif // QSSLPRESHAREDKEYAUTHENTICATOR_H
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator_p.h b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
index e5566c3b3c..0075579074 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator_p.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2014 Governikus GmbH & Co. KG.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_P_H
#define QSSLPRESHAREDKEYAUTHENTICATOR_P_H
diff --git a/src/network/ssl/qsslserver.cpp b/src/network/ssl/qsslserver.cpp
new file mode 100644
index 0000000000..40a6a6f526
--- /dev/null
+++ b/src/network/ssl/qsslserver.cpp
@@ -0,0 +1,412 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*!
+ \class QSslServer
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+ \since 6.4
+
+ \brief Implements an encrypted, secure TCP server over TLS.
+
+ Class to use in place of QTcpServer to implement TCP server using
+ Transport Layer Security (TLS).
+
+ To configure the secure handshake settings, use the applicable setter
+ functions on a QSslConfiguration object, and then use it as an argument
+ to the setSslConfiguration() function. All following incoming
+ connections handled will use these settings.
+
+ To start listening to incoming connections use the listen() function
+ inherited from QTcpServer. Other settings can be configured by using the
+ setter functions inherited from the QTcpServer class.
+
+ Connect to the signals of this class to respond to the incoming connection
+ attempts. They are the same as the signals on QSslSocket, but also
+ passes a pointer to the socket in question.
+
+ When responding to the pendingConnectionAvailable() signal, use the
+ nextPendingConnection() function to fetch the next incoming connection and
+ take it out of the pending connection queue. The QSslSocket is a child of
+ the QSslServer and will be deleted when the QSslServer is deleted. It is
+ still a good idea to destroy the object explicitly when you are done
+ with it, to avoid wasting memory.
+
+ \sa QTcpServer, QSslConfiguration, QSslSocket
+*/
+
+/*!
+ \fn void QSslServer::peerVerifyError(QSslSocket *socket, const QSslError &error)
+
+ QSslServer can emit this signal several times during the SSL handshake,
+ before encryption has been established, to indicate that an error has
+ occurred while establishing the identity of the peer. The \a error is
+ usually an indication that \a socket is unable to securely identify the
+ peer.
+
+ This signal provides you with an early indication when something's wrong.
+ By connecting to this signal, you can manually choose to tear down the
+ connection from inside the connected slot before the handshake has
+ completed. If no action is taken, QSslServer will proceed to emitting
+ sslErrors().
+
+ \sa sslErrors()
+*/
+
+/*!
+ \fn void QSslServer::sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
+
+ QSslServer emits this signal after the SSL handshake to indicate that one
+ or more errors have occurred while establishing the identity of the
+ peer. The errors are usually an indication that \a socket is unable to
+ securely identify the peer. Unless any action is taken, the connection
+ will be dropped after this signal has been emitted.
+
+ If you want to continue connecting despite the errors that have occurred,
+ you must call QSslSocket::ignoreSslErrors() from inside a slot connected to
+ this signal. If you need to access the error list at a later point, you
+ can call sslHandshakeErrors().
+
+ \a errors contains one or more errors that prevent QSslSocket from
+ verifying the identity of the peer.
+
+ \note You cannot use Qt::QueuedConnection when connecting to this signal,
+ or calling QSslSocket::ignoreSslErrors() will have no effect.
+
+ \sa peerVerifyError()
+*/
+
+/*!
+ \fn void QSslServer::errorOccurred(QSslSocket *socket, QAbstractSocket::SocketError socketError)
+
+ This signal is emitted after an error occurred during handshake. The
+ \a socketError parameter describes the type of error that occurred.
+
+ The \a socket is automatically deleted after this signal is emitted if the
+ socket handshake has not reached encrypted state. But if the \a socket is
+ successfully encrypted, it is inserted into the QSslServer's pending
+ connections queue. When the user has called
+ QTcpServer::nextPendingConnection() it is the user's responsibility to
+ destroy the \a socket or the \a socket will not be destroyed until the
+ QSslServer object is destroyed. If an error occurs on a \a socket after
+ it has been inserted into the pending connections queue, this signal
+ will not be emitted, and the \a socket will not be removed or destroyed.
+
+ \note You cannot use Qt::QueuedConnection when connecting to this signal,
+ or the \a socket will have been already destroyed when the signal is
+ handled.
+
+ \sa QSslSocket::error(), errorString()
+*/
+
+/*!
+ \fn void QSslServer::preSharedKeyAuthenticationRequired(QSslSocket *socket,
+ QSslPreSharedKeyAuthenticator *authenticator)
+
+ QSslServer emits this signal when \a socket negotiates a PSK ciphersuite,
+ and therefore PSK authentication is then required.
+
+ When using PSK, the server must supply a valid identity and a valid pre
+ shared key, in order for the SSL handshake to continue.
+ Applications can provide this information in a slot connected to this
+ signal, by filling in the passed \a authenticator object according to their
+ needs.
+
+ \note Ignoring this signal, or failing to provide the required credentials,
+ will cause the handshake to fail, and therefore the connection to be aborted.
+
+ \note The \a authenticator object is owned by the \a socket and must not be
+ deleted by the application.
+
+ \sa QSslPreSharedKeyAuthenticator
+*/
+
+/*!
+ \fn void QSslServer::alertSent(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description)
+
+ QSslServer emits this signal if an alert message was sent from \a socket
+ to a peer. \a level describes if it was a warning or a fatal error.
+ \a type gives the code of the alert message. When a textual description
+ of the alert message is available, it is supplied in \a description.
+
+ \note This signal is mostly informational and can be used for debugging
+ purposes, normally it does not require any actions from the application.
+ \note Not all backends support this functionality.
+
+ \sa alertReceived(), QSsl::AlertLevel, QSsl::AlertType
+*/
+
+/*!
+ \fn void QSslServer::alertReceived(QSslSocket *socket, QSsl::AlertLevel level, QSsl::AlertType
+ type, const QString &description)
+
+ QSslServer emits this signal if an alert message was received by the
+ \a socket from a peer. \a level tells if the alert was fatal or it was a
+ warning. \a type is the code explaining why the alert was sent.
+ When a textual description of the alert message is available, it is
+ supplied in \a description.
+
+ \note The signal is mostly for informational and debugging purposes and does not
+ require any handling in the application. If the alert was fatal, underlying
+ backend will handle it and close the connection.
+ \note Not all backends support this functionality.
+
+ \sa alertSent(), QSsl::AlertLevel, QSsl::AlertType
+*/
+
+/*!
+ \fn void QSslServer::handshakeInterruptedOnError(QSslSocket *socket, const QSslError &error)
+
+ QSslServer emits this signal if a certificate verification error was found
+ by \a socket and if early error reporting was enabled in QSslConfiguration.
+ An application is expected to inspect the \a error and decide if it wants
+ to continue the handshake, or abort it and send an alert message to the
+ peer. The signal-slot connection must be direct.
+
+ \sa QSslSocket::continueInterruptedHandshake(), sslErrors(),
+ QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+
+/*!
+ \fn void QSslServer::startedEncryptionHandshake(QSslSocket *socket)
+
+ This signal is emitted when the client, connected to \a socket,
+ initiates the TLS handshake.
+*/
+
+#include "qsslserver.h"
+#include "qsslserver_p.h"
+
+#include <QtNetwork/QSslSocket>
+#include <QtNetwork/QSslCipher>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+*/
+QSslServerPrivate::QSslServerPrivate() :
+ sslConfiguration(QSslConfiguration::defaultConfiguration())
+{
+}
+
+/*!
+ Constructs a new QSslServer with the given \a parent.
+*/
+QSslServer::QSslServer(QObject *parent) :
+ QTcpServer(QAbstractSocket::TcpSocket, *new QSslServerPrivate, parent)
+{
+}
+
+/*!
+ Destroys the QSslServer.
+
+ All open connections are closed.
+*/
+QSslServer::~QSslServer()
+{
+}
+
+/*!
+ Sets the \a sslConfiguration to use for all following incoming connections.
+
+ This must be called before listen() to ensure that the desired
+ configuration was in use during all handshakes.
+
+ \sa QSslSocket::setSslConfiguration()
+*/
+void QSslServer::setSslConfiguration(const QSslConfiguration &sslConfiguration)
+{
+ Q_D(QSslServer);
+ d->sslConfiguration = sslConfiguration;
+}
+
+/*!
+ Returns the current ssl configuration.
+*/
+QSslConfiguration QSslServer::sslConfiguration() const
+{
+ const Q_D(QSslServer);
+ return d->sslConfiguration;
+}
+
+/*!
+ Sets the \a timeout to use for all incoming handshakes, in milliseconds.
+
+ This is relevant in the scenario where a client, whether malicious or
+ accidental, connects to the server but makes no attempt at communicating or
+ initiating a handshake. QSslServer will then automatically end the
+ connection after \a timeout milliseconds have elapsed.
+
+ By default the timeout is 5000 milliseconds (5 seconds).
+
+ \note The underlying TLS framework may have their own timeout logic now or
+ in the future, this function does not affect that.
+
+ \note The \a timeout passed to this function will only apply to \e{new}
+ connections. If a client is already connected it will use the timeout which
+ was set when it connected.
+
+ \sa handshakeTimeout()
+*/
+void QSslServer::setHandshakeTimeout(int timeout)
+{
+ Q_D(QSslServer);
+ d->handshakeTimeout = timeout;
+}
+
+/*!
+ Returns the currently configured handshake timeout.
+
+ \sa setHandshakeTimeout()
+*/
+int QSslServer::handshakeTimeout() const
+{
+ const Q_D(QSslServer);
+ return d->handshakeTimeout;
+}
+
+/*!
+ Called when a new connection is established.
+
+ Converts \a socket to a QSslSocket.
+
+ \reimp
+*/
+void QSslServer::incomingConnection(qintptr socket)
+{
+ QSslSocket *pSslSocket = new QSslSocket(this);
+
+ pSslSocket->setSslConfiguration(sslConfiguration());
+
+ if (Q_LIKELY(pSslSocket->setSocketDescriptor(socket))) {
+ connect(pSslSocket, &QSslSocket::peerVerifyError, this,
+ [this, pSslSocket](const QSslError &error) {
+ Q_EMIT peerVerifyError(pSslSocket, error);
+ });
+ connect(pSslSocket, &QSslSocket::sslErrors, this,
+ [this, pSslSocket](const QList<QSslError> &errors) {
+ Q_EMIT sslErrors(pSslSocket, errors);
+ });
+ connect(pSslSocket, &QAbstractSocket::errorOccurred, this,
+ [this, pSslSocket](QAbstractSocket::SocketError error) {
+ Q_EMIT errorOccurred(pSslSocket, error);
+ if (!pSslSocket->isEncrypted())
+ pSslSocket->deleteLater();
+ });
+ connect(pSslSocket, &QSslSocket::encrypted, this, [this, pSslSocket]() {
+ Q_D(QSslServer);
+ d->removeSocketData(quintptr(pSslSocket));
+ pSslSocket->disconnect(this);
+ addPendingConnection(pSslSocket);
+ });
+ connect(pSslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, this,
+ [this, pSslSocket](QSslPreSharedKeyAuthenticator *authenticator) {
+ Q_EMIT preSharedKeyAuthenticationRequired(pSslSocket, authenticator);
+ });
+ connect(pSslSocket, &QSslSocket::alertSent, this,
+ [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description) {
+ Q_EMIT alertSent(pSslSocket, level, type, description);
+ });
+ connect(pSslSocket, &QSslSocket::alertReceived, this,
+ [this, pSslSocket](QSsl::AlertLevel level, QSsl::AlertType type,
+ const QString &description) {
+ Q_EMIT alertReceived(pSslSocket, level, type, description);
+ });
+ connect(pSslSocket, &QSslSocket::handshakeInterruptedOnError, this,
+ [this, pSslSocket](const QSslError &error) {
+ Q_EMIT handshakeInterruptedOnError(pSslSocket, error);
+ });
+
+ d_func()->initializeHandshakeProcess(pSslSocket);
+ }
+}
+
+void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket)
+{
+ Q_Q(QSslServer);
+ QMetaObject::Connection readyRead = QObject::connect(
+ socket, &QSslSocket::readyRead, q, [this]() { checkClientHelloAndContinue(); });
+
+ QMetaObject::Connection destroyed =
+ QObject::connect(socket, &QSslSocket::destroyed, q, [this](QObject *obj) {
+ // This cast is not safe to use since the socket is inside the
+ // QObject dtor, but we only use the pointer value!
+ removeSocketData(quintptr(obj));
+ });
+ auto it = socketData.emplace(quintptr(socket), readyRead, destroyed, std::make_shared<QTimer>());
+ it->timeoutTimer->setSingleShot(true);
+ it->timeoutTimer->callOnTimeout(q, [this, socket]() { handleHandshakeTimedOut(socket); });
+ it->timeoutTimer->setInterval(handshakeTimeout);
+ it->timeoutTimer->start();
+}
+
+// This function may be called while in the socket's QObject dtor, __never__ use
+// the socket for anything other than a lookup!
+void QSslServerPrivate::removeSocketData(quintptr socket)
+{
+ auto it = socketData.find(socket);
+ if (it != socketData.end()) {
+ it->disconnectSignals();
+ socketData.erase(it);
+ }
+}
+
+int QSslServerPrivate::totalPendingConnections() const
+{
+ // max pending connections is int, so this cannot exceed that
+ return QTcpServerPrivate::totalPendingConnections() + int(socketData.size());
+}
+
+void QSslServerPrivate::checkClientHelloAndContinue()
+{
+ Q_Q(QSslServer);
+ QSslSocket *socket = qobject_cast<QSslSocket *>(q->sender());
+ if (Q_UNLIKELY(!socket) || socket->bytesAvailable() <= 0)
+ return;
+
+ char byte = '\0';
+ if (socket->peek(&byte, 1) != 1) {
+ socket->deleteLater();
+ return;
+ }
+
+ auto it = socketData.find(quintptr(socket));
+ const bool foundData = it != socketData.end();
+ if (foundData && it->readyReadConnection)
+ QObject::disconnect(std::exchange(it->readyReadConnection, {}));
+
+ constexpr char CLIENT_HELLO = 0x16;
+ if (byte != CLIENT_HELLO) {
+ socket->disconnectFromHost();
+ socket->deleteLater();
+ return;
+ }
+
+ // Be nice and restart the timeout timer since some progress was made
+ if (foundData)
+ it->timeoutTimer->start();
+
+ socket->startServerEncryption();
+ Q_EMIT q->startedEncryptionHandshake(socket);
+}
+
+void QSslServerPrivate::handleHandshakeTimedOut(QSslSocket *socket)
+{
+ Q_Q(QSslServer);
+ removeSocketData(quintptr(socket));
+ socket->disconnectFromHost();
+ Q_EMIT q->errorOccurred(socket, QAbstractSocket::SocketTimeoutError);
+ socket->deleteLater();
+ if (!socketEngine->isReadNotificationEnabled() && totalPendingConnections() < maxConnections)
+ q->resumeAccepting();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsslserver.cpp"
diff --git a/src/network/ssl/qsslserver.h b/src/network/ssl/qsslserver.h
new file mode 100644
index 0000000000..aaa0f43c35
--- /dev/null
+++ b/src/network/ssl/qsslserver.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSSLSERVER_H
+#define QSSLSERVER_H
+
+#include <QtNetwork/QTcpServer>
+
+QT_REQUIRE_CONFIG(ssl);
+
+#include <QtNetwork/QSslError>
+#include <QtNetwork/QSslConfiguration>
+#include <QtNetwork/QSslPreSharedKeyAuthenticator>
+#include <QtNetwork/QSslSocket>
+
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QSslSocket;
+class QSslServerPrivate;
+
+class Q_NETWORK_EXPORT QSslServer : public QTcpServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QSslServer)
+
+public:
+ explicit QSslServer(QObject *parent = nullptr);
+ ~QSslServer() override;
+
+ void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+ QSslConfiguration sslConfiguration() const;
+
+ void setHandshakeTimeout(int timeout);
+ int handshakeTimeout() const;
+
+Q_SIGNALS:
+ void sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
+ void peerVerifyError(QSslSocket *socket, const QSslError &error);
+ void errorOccurred(QSslSocket *socket, QAbstractSocket::SocketError error);
+ void preSharedKeyAuthenticationRequired(QSslSocket *socket,
+ QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QSslSocket *socket, QSsl::AlertLevel level,
+ QSsl::AlertType type, const QString &description);
+ void alertReceived(QSslSocket *socket, QSsl::AlertLevel level,
+ QSsl::AlertType type, const QString &description);
+ void handshakeInterruptedOnError(QSslSocket *socket, const QSslError &error);
+ void startedEncryptionHandshake(QSslSocket *socket);
+
+protected:
+ void incomingConnection(qintptr socket) override;
+
+private:
+ Q_DECLARE_PRIVATE(QSslServer)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_H
diff --git a/src/network/ssl/qsslserver_p.h b/src/network/ssl/qsslserver_p.h
new file mode 100644
index 0000000000..1b90d35d48
--- /dev/null
+++ b/src/network/ssl/qsslserver_p.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSSLSERVER_P_H
+#define QSSLSERVER_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/qhash.h>
+#include <QtCore/qtimer.h>
+
+#include <QtNetwork/QSslConfiguration>
+#include <QtNetwork/private/qtcpserver_p.h>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+class Q_NETWORK_EXPORT QSslServerPrivate : public QTcpServerPrivate
+{
+ static constexpr int DefaultHandshakeTimeout = 5'000; // 5 seconds
+public:
+ Q_DECLARE_PUBLIC(QSslServer)
+
+ QSslServerPrivate();
+ void checkClientHelloAndContinue();
+ void initializeHandshakeProcess(QSslSocket *socket);
+ void removeSocketData(quintptr socket);
+ void handleHandshakeTimedOut(QSslSocket *socket);
+ int totalPendingConnections() const override;
+
+ struct SocketData {
+ QMetaObject::Connection readyReadConnection;
+ QMetaObject::Connection destroyedConnection;
+ std::shared_ptr<QTimer> timeoutTimer; // shared_ptr because QHash demands copying
+
+ SocketData(QMetaObject::Connection readyRead, QMetaObject::Connection destroyed,
+ std::shared_ptr<QTimer> &&timer)
+ : readyReadConnection(readyRead),
+ destroyedConnection(destroyed),
+ timeoutTimer(std::move(timer))
+ {
+ }
+
+ void disconnectSignals()
+ {
+ QObject::disconnect(std::exchange(readyReadConnection, {}));
+ QObject::disconnect(std::exchange(destroyedConnection, {}));
+ }
+ };
+ QHash<quintptr, SocketData> socketData;
+
+ QSslConfiguration sslConfiguration;
+ int handshakeTimeout = DefaultHandshakeTimeout;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_P_H
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index c5444b139e..395394d432 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//#define QSSLSOCKET_DEBUG
@@ -54,10 +18,10 @@
QSslSocket establishes a secure, encrypted TCP connection you can
use for transmitting encrypted data. It can operate in both client
- and server mode, and it supports modern SSL protocols, including
- SSL 3 and TLS 1.2. By default, QSslSocket uses only SSL protocols
+ and server mode, and it supports modern TLS protocols, including
+ TLS 1.3. By default, QSslSocket uses only TLS protocols
which are considered to be secure (QSsl::SecureProtocols), but you can
- change the SSL protocol by calling setProtocol() as long as you do
+ change the TLS protocol by calling setProtocol() as long as you do
it before the handshake has started.
SSL encryption operates on top of the existing TCP stream after
@@ -133,8 +97,7 @@
\list
\li The socket's cryptographic cipher suite can be customized before
- the handshake phase with QSslConfiguration::setCiphers()
- and QSslConfiguration::setDefaultCiphers().
+ the handshake phase with QSslConfiguration::setCiphers().
\li The socket's local certificate and private key can be customized
before the handshake phase with setLocalCertificate() and
setPrivateKey().
@@ -188,7 +151,7 @@
behavior is identical to QTcpSocket.
\value SslClientMode The socket is a client-side SSL socket.
- It is either alreayd encrypted, or it is in the SSL handshake
+ It is either already encrypted, or it is in the SSL handshake
phase (see QSslSocket::isEncrypted()).
\value SslServerMode The socket is a server-side SSL socket.
@@ -385,16 +348,9 @@
#include "qsslsocket.h"
#include "qsslcipher.h"
#include "qocspresponse.h"
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_p.h"
-#endif
-#ifdef QT_SECURETRANSPORT
-#include "qsslsocket_mac_p.h"
-#endif
-#if QT_CONFIG(schannel)
-#include "qsslsocket_schannel_p.h"
-#endif
+#include "qtlsbackend_p.h"
#include "qsslconfiguration_p.h"
+#include "qsslsocket_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
@@ -406,6 +362,14 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+#ifdef Q_OS_VXWORKS
+constexpr auto isVxworks = true;
+#else
+constexpr auto isVxworks = false;
+#endif
+
class QSslSocketGlobalData
{
public:
@@ -432,7 +396,7 @@ Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
set to the one returned by the static method defaultCiphers().
*/
QSslSocket::QSslSocket(QObject *parent)
- : QTcpSocket(*new QSslSocketBackendPrivate, parent)
+ : QTcpSocket(*new QSslSocketPrivate, parent)
{
Q_D(QSslSocket);
#ifdef QSSLSOCKET_DEBUG
@@ -902,7 +866,8 @@ void QSslSocket::close()
// On Windows, CertGetCertificateChain is probably still doing its
// job, if the socket is re-used, we want to ignore its reported
// root CA.
- d->caToFetch = QSslCertificate{};
+ if (auto *backend = d->backend.get())
+ backend->cancelCAFetch();
if (!d->abortCalled && (encryptedBytesToWrite() || !d->writeBuffer.isEmpty()))
flush();
@@ -1209,7 +1174,9 @@ QSsl::SslProtocol QSslSocket::sessionProtocol() const
QList<QOcspResponse> QSslSocket::ocspResponses() const
{
Q_D(const QSslSocket);
- return d->ocspResponses;
+ if (const auto *backend = d->backend.get())
+ return backend->ocsps();
+ return {};
}
/*!
@@ -1484,7 +1451,9 @@ bool QSslSocket::waitForDisconnected(int msecs)
QList<QSslError> QSslSocket::sslHandshakeErrors() const
{
Q_D(const QSslSocket);
- return d->sslErrors;
+ if (const auto *backend = d->backend.get())
+ return backend->tlsErrors();
+ return {};
}
/*!
@@ -1501,12 +1470,14 @@ bool QSslSocket::supportsSsl()
\since 5.0
Returns the version number of the SSL library in use. Note that
this is the version of the library in use at run-time not compile
- time. If no SSL support is available then this will return an
- undefined value.
+ time. If no SSL support is available then this will return -1.
*/
long QSslSocket::sslLibraryVersionNumber()
{
- return QSslSocketPrivate::sslLibraryVersionNumber();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryVersionNumber();
+
+ return -1;
}
/*!
@@ -1517,20 +1488,23 @@ long QSslSocket::sslLibraryVersionNumber()
*/
QString QSslSocket::sslLibraryVersionString()
{
- return QSslSocketPrivate::sslLibraryVersionString();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryVersionString();
+ return {};
}
/*!
\since 5.4
Returns the version number of the SSL library in use at compile
- time. If no SSL support is available then this will return an
- undefined value.
+ time. If no SSL support is available then this will return -1.
\sa sslLibraryVersionNumber()
*/
long QSslSocket::sslLibraryBuildVersionNumber()
{
- return QSslSocketPrivate::sslLibraryBuildVersionNumber();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryBuildVersionNumber();
+ return -1;
}
/*!
@@ -1543,7 +1517,166 @@ long QSslSocket::sslLibraryBuildVersionNumber()
*/
QString QSslSocket::sslLibraryBuildVersionString()
{
- return QSslSocketPrivate::sslLibraryBuildVersionString();
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
+ return tlsBackend->tlsLibraryBuildVersionString();
+
+ return {};
+}
+
+/*!
+ \since 6.1
+ Returns the names of the currently available backends. These names
+ are in lower case, e.g. "openssl", "securetransport", "schannel"
+ (similar to the already existing feature names for TLS backends in Qt).
+
+ \sa activeBackend()
+*/
+QList<QString> QSslSocket::availableBackends()
+{
+ return QTlsBackend::availableBackendNames();
+}
+
+/*!
+ \since 6.1
+ Returns the name of the backend that QSslSocket and related classes
+ use. If the active backend was not set explicitly, this function
+ returns the name of a default backend that QSslSocket selects implicitly
+ from the list of available backends.
+
+ \note When selecting a default backend implicitly, QSslSocket prefers
+ the OpenSSL backend if available. If it's not available, the Schannel backend
+ is implicitly selected on Windows, and Secure Transport on Darwin platforms.
+ Failing these, if a custom TLS backend is found, it is used.
+ If no other backend is found, the "certificate only" backend is selected.
+ For more information about TLS plugins, please see
+ \l {Enabling and Disabling SSL Support when Building Qt from Source}.
+
+ \sa setActiveBackend(), availableBackends()
+*/
+QString QSslSocket::activeBackend()
+{
+ const QMutexLocker locker(&QSslSocketPrivate::backendMutex);
+
+ if (!QSslSocketPrivate::activeBackendName.size())
+ QSslSocketPrivate::activeBackendName = QTlsBackend::defaultBackendName();
+
+ return QSslSocketPrivate::activeBackendName;
+}
+
+/*!
+ \since 6.1
+ Returns true if a backend with name \a backendName was set as
+ active backend. \a backendName must be one of names returned
+ by availableBackends().
+
+ \note An application cannot mix different backends simultaneously.
+ This implies that a non-default backend must be selected prior
+ to any use of QSslSocket or related classes, e.g. QSslCertificate
+ or QSslKey.
+
+ \sa activeBackend(), availableBackends()
+*/
+bool QSslSocket::setActiveBackend(const QString &backendName)
+{
+ if (!backendName.size()) {
+ qCWarning(lcSsl, "Invalid parameter (backend name cannot be an empty string)");
+ return false;
+ }
+
+ QMutexLocker locker(&QSslSocketPrivate::backendMutex);
+ if (QSslSocketPrivate::tlsBackend) {
+ qCWarning(lcSsl) << "Cannot set backend named" << backendName
+ << "as active, another backend is already in use";
+ locker.unlock();
+ return activeBackend() == backendName;
+ }
+
+ if (!QTlsBackend::availableBackendNames().contains(backendName)) {
+ qCWarning(lcSsl) << "Cannot set unavailable backend named" << backendName
+ << "as active";
+ return false;
+ }
+
+ QSslSocketPrivate::activeBackendName = backendName;
+
+ return true;
+}
+
+/*!
+ \since 6.1
+ If a backend with name \a backendName is available, this function returns the
+ list of TLS protocol versions supported by this backend. An empty \a backendName
+ is understood as a query about the currently active backend. Otherwise, this
+ function returns an empty list.
+
+ \sa availableBackends(), activeBackend(), isProtocolSupported()
+*/
+QList<QSsl::SslProtocol> QSslSocket::supportedProtocols(const QString &backendName)
+{
+ return QTlsBackend::supportedProtocols(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if \a protocol is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa supportedProtocols()
+*/
+bool QSslSocket::isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName)
+{
+ const auto versions = supportedProtocols(backendName);
+ return versions.contains(protocol);
+}
+
+/*!
+ \since 6.1
+ This function returns backend-specific classes implemented by the backend named
+ \a backendName. An empty \a backendName is understood as a query about the
+ currently active backend.
+
+ \sa QSsl::ImplementedClass, activeBackend(), isClassImplemented()
+*/
+QList<QSsl::ImplementedClass> QSslSocket::implementedClasses(const QString &backendName)
+{
+ return QTlsBackend::implementedClasses(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if a class \a cl is implemented by the backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa implementedClasses()
+*/
+
+bool QSslSocket::isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName)
+{
+ return implementedClasses(backendName).contains(cl);
+}
+
+/*!
+ \since 6.1
+ This function returns features supported by a backend named \a backendName.
+ An empty \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, activeBackend()
+*/
+QList<QSsl::SupportedFeature> QSslSocket::supportedFeatures(const QString &backendName)
+{
+ return QTlsBackend::supportedFeatures(backendName.size() ? backendName : activeBackend());
+}
+
+/*!
+ \since 6.1
+ Returns true if a feature \a ft is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, supportedFeatures()
+*/
+bool QSslSocket::isFeatureSupported(QSsl::SupportedFeature ft, const QString &backendName)
+{
+ return supportedFeatures(backendName).contains(ft);
}
/*!
@@ -1705,7 +1838,8 @@ void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
void QSslSocket::continueInterruptedHandshake()
{
Q_D(QSslSocket);
- d->handshakeInterrupted = false;
+ if (auto *backend = d->backend.get())
+ backend->enableHandshakeContinuation();
}
/*!
@@ -1762,7 +1896,8 @@ void QSslSocket::disconnectFromHost()
}
// Make sure we don't process any signal from the CA fetcher
// (Windows):
- d->caToFetch = QSslCertificate{};
+ if (auto *backend = d->backend.get())
+ backend->cancelCAFetch();
// Perhaps emit closing()
if (d->state != ClosingState) {
@@ -1798,7 +1933,7 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen)
#endif
} else {
// possibly trigger another transmit() to decrypt more data from the socket
- if (d->plainSocket->bytesAvailable())
+ if (d->plainSocket->bytesAvailable() || d->hasUndecryptedData())
QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection);
else if (d->state != QAbstractSocket::ConnectedState)
return maxlen ? qint64(-1) : qint64(0);
@@ -1830,6 +1965,8 @@ qint64 QSslSocket::writeData(const char *data, qint64 len)
return len;
}
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+
/*!
\internal
*/
@@ -1838,7 +1975,6 @@ QSslSocketPrivate::QSslSocketPrivate()
, mode(QSslSocket::UnencryptedMode)
, autoStartHandshake(false)
, connectionEncrypted(false)
- , shutdown(false)
, ignoreAllSslErrors(false)
, readyReadEmittedPointer(nullptr)
, allowRootCertOnDemandLoading(true)
@@ -1847,6 +1983,21 @@ QSslSocketPrivate::QSslSocketPrivate()
, flushTriggered(false)
{
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+ // If the global configuration doesn't allow root certificates to be loaded
+ // on demand then we have to disable it for this socket as well.
+ if (!configuration.allowRootCertOnDemandLoading)
+ allowRootCertOnDemandLoading = false;
+
+ const auto *tlsBackend = tlsBackendInUse();
+ if (!tlsBackend) {
+ qCWarning(lcSsl, "No TLS backend is available");
+ return;
+ }
+ backend.reset(tlsBackend->createTlsCryptograph());
+ if (!backend.get()) {
+ qCWarning(lcSsl) << "The backend named" << tlsBackend->backendName()
+ << "does not support TLS";
+ }
}
/*!
@@ -1859,28 +2010,54 @@ QSslSocketPrivate::~QSslSocketPrivate()
/*!
\internal
*/
+bool QSslSocketPrivate::supportsSsl()
+{
+ if (const auto *tlsBackend = tlsBackendInUse())
+ return tlsBackend->implementedClasses().contains(QSsl::ImplementedClass::Socket);
+ return false;
+}
+
+/*!
+ \internal
+
+ Declared static in QSslSocketPrivate, makes sure the SSL libraries have
+ been initialized.
+*/
+void QSslSocketPrivate::ensureInitialized()
+{
+ if (!supportsSsl())
+ return;
+
+ const auto *tlsBackend = tlsBackendInUse();
+ Q_ASSERT(tlsBackend);
+ tlsBackend->ensureInitialized();
+}
+
+/*!
+ \internal
+*/
void QSslSocketPrivate::init()
{
+ // TLSTODO: delete those data members.
mode = QSslSocket::UnencryptedMode;
autoStartHandshake = false;
connectionEncrypted = false;
ignoreAllSslErrors = false;
- shutdown = false;
abortCalled = false;
pendingClose = false;
flushTriggered = false;
- ocspResponses.clear();
- systemOrSslErrorDetected = false;
- // we don't want to clear the ignoreErrorsList, so
- // that it is possible setting it before connecting
-// ignoreErrorsList.clear();
+ // We don't want to clear the ignoreErrorsList, so
+ // that it is possible setting it before connecting.
buffer.clear();
writeBuffer.clear();
configuration.peerCertificate.clear();
configuration.peerCertificateChain.clear();
- fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
+
+ if (backend.get()) {
+ Q_ASSERT(q_ptr);
+ backend->init(static_cast<QSslSocket *>(q_ptr), this);
+ }
}
/*!
@@ -1888,13 +2065,15 @@ void QSslSocketPrivate::init()
*/
bool QSslSocketPrivate::verifyProtocolSupported(const char *where)
{
- QLatin1String protocolName("DTLS");
+ auto protocolName = "DTLS"_L1;
switch (configuration.protocol) {
case QSsl::UnknownProtocol:
// UnknownProtocol, according to our docs, is for cipher whose protocol is unknown.
// Should not be used when configuring QSslSocket.
- protocolName = QLatin1String("UnknownProtocol");
+ protocolName = "UnknownProtocol"_L1;
Q_FALLTHROUGH();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
case QSsl::DtlsV1_0:
case QSsl::DtlsV1_2:
case QSsl::DtlsV1_0OrLater:
@@ -1903,6 +2082,7 @@ bool QSslSocketPrivate::verifyProtocolSupported(const char *where)
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Attempted to use an unsupported protocol."));
return false;
+QT_WARNING_POP
default:
return true;
}
@@ -1951,7 +2131,35 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
/*!
\internal
*/
-void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+void QSslSocketPrivate::resetDefaultEllipticCurves()
+{
+ const auto *tlsBackend = tlsBackendInUse();
+ if (!tlsBackend)
+ return;
+
+ auto ids = tlsBackend->ellipticCurvesIds();
+ if (!ids.size())
+ return;
+
+ QList<QSslEllipticCurve> curves;
+ curves.reserve(ids.size());
+ for (int id : ids) {
+ QSslEllipticCurve curve;
+ curve.id = id;
+ curves.append(curve);
+ }
+
+ // Set the list of supported ECs, but not the list
+ // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong
+ // ciphersuite, so don't try it -- leave the empty list to mean
+ // "the implementation will choose the most suitable one".
+ setDefaultSupportedEllipticCurves(curves);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
{
QMutexLocker locker(&globalData()->mutex);
globalData()->dtlsConfig.detach();
@@ -1961,7 +2169,7 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
/*!
\internal
*/
-QList<QSslCipher> q_getDefaultDtlsCiphers()
+QList<QSslCipher> QSslSocketPrivate::defaultDtlsCiphers()
{
QSslSocketPrivate::ensureInitialized();
QMutexLocker locker(&globalData()->mutex);
@@ -2087,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->sessionProtocol = global->sessionProtocol;
ptr->ciphers = global->ciphers;
ptr->caCertificates = global->caCertificates;
+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
ptr->protocol = global->protocol;
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
@@ -2208,6 +2417,11 @@ bool QSslSocketPrivate::isPaused() const
return paused;
}
+void QSslSocketPrivate::setPaused(bool p)
+{
+ paused = p;
+}
+
bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
{
// this function is called from QAbstractSocket::bind
@@ -2326,7 +2540,7 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
// this moves encrypted bytes from plain socket into our buffer
- if (plainSocket->bytesAvailable()) {
+ if (plainSocket->bytesAvailable() && mode != QSslSocket::UnencryptedMode) {
qint64 tmpReadBufferMaxSize = readBufferMaxSize;
readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
transmit();
@@ -2438,6 +2652,7 @@ void QSslSocketPrivate::_q_resumeImplementation()
if (verifyErrorsHaveBeenIgnored()) {
continueHandshake();
} else {
+ const auto sslErrors = backend->tlsErrors();
Q_ASSERT(!sslErrors.isEmpty());
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
plainSocket->disconnectFromHost();
@@ -2452,13 +2667,16 @@ void QSslSocketPrivate::_q_resumeImplementation()
*/
bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
{
+ Q_ASSERT(backend.get());
+
bool doEmitSslError;
if (!ignoreErrorsList.empty()) {
// check whether the errors we got are all in the list of expected errors
// (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
// was called)
+ const auto &sslErrors = backend->tlsErrors();
doEmitSslError = false;
- for (int a = 0; a < sslErrors.count(); a++) {
+ for (int a = 0; a < sslErrors.size(); a++) {
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
doEmitSslError = true;
break;
@@ -2476,6 +2694,91 @@ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
/*!
\internal
*/
+bool QSslSocketPrivate::isAutoStartingHandshake() const
+{
+ return autoStartHandshake;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::isPendingClose() const
+{
+ return pendingClose;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setPendingClose(bool pc)
+{
+ pendingClose = pc;
+}
+
+/*!
+ \internal
+*/
+qint64 QSslSocketPrivate::maxReadBufferSize() const
+{
+ return readBufferMaxSize;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setMaxReadBufferSize(qint64 maxSize)
+{
+ readBufferMaxSize = maxSize;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setEncrypted(bool enc)
+{
+ connectionEncrypted = enc;
+}
+
+/*!
+ \internal
+*/
+QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsWriteBuffer()
+{
+ return writeBuffer;
+}
+
+/*!
+ \internal
+*/
+QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsBuffer()
+{
+ return buffer;
+}
+
+/*!
+ \internal
+*/
+bool &QSslSocketPrivate::tlsEmittedBytesWritten()
+{
+ return emittedBytesWritten;
+}
+
+/*!
+ \internal
+*/
+bool *QSslSocketPrivate::readyReadPointer()
+{
+ return readyReadEmittedPointer;
+}
+
+bool QSslSocketPrivate::hasUndecryptedData() const
+{
+ return backend.get() && backend->hasUndecryptedData();
+}
+
+/*!
+ \internal
+*/
qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
{
if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) {
@@ -2491,9 +2794,9 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
if (r2 < 0)
return (r > 0 ? r : r2);
return r + r2;
- } else {
- return -1;
}
+
+ return -1;
} else {
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
return QTcpSocketPrivate::peek(data, maxSize);
@@ -2511,13 +2814,13 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize)
QByteArray ret;
ret.reserve(maxSize);
ret.resize(buffer.peek(ret.data(), maxSize, transactionPos));
- if (ret.length() == maxSize)
+ if (ret.size() == maxSize)
return ret;
//peek at data in the plain socket
if (plainSocket)
- return ret + plainSocket->peek(maxSize - ret.length());
- else
- return QByteArray();
+ return ret + plainSocket->peek(maxSize - ret.size());
+
+ return QByteArray();
} else {
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
return QTcpSocketPrivate::peek(maxSize);
@@ -2559,6 +2862,82 @@ bool QSslSocketPrivate::flush()
/*!
\internal
*/
+void QSslSocketPrivate::startClientEncryption()
+{
+ if (backend.get())
+ backend->startClientEncryption();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::startServerEncryption()
+{
+ if (backend.get())
+ backend->startServerEncryption();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::transmit()
+{
+ if (backend.get())
+ backend->transmit();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::disconnectFromHost()
+{
+ if (backend.get())
+ backend->disconnectFromHost();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::disconnected()
+{
+ if (backend.get())
+ backend->disconnected();
+}
+
+/*!
+ \internal
+*/
+QSslCipher QSslSocketPrivate::sessionCipher() const
+{
+ if (backend.get())
+ return backend->sessionCipher();
+
+ return {};
+}
+
+/*!
+ \internal
+*/
+QSsl::SslProtocol QSslSocketPrivate::sessionProtocol() const
+{
+ if (backend.get())
+ return backend->sessionProtocol();
+
+ return QSsl::UnknownProtocol;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::continueHandshake()
+{
+ if (backend.get())
+ backend->continueHandshake();
+}
+
+/*!
+ \internal
+*/
bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
{
return s_loadRootCertsOnDemand;
@@ -2567,34 +2946,63 @@ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
/*!
\internal
*/
+void QSslSocketPrivate::setRootCertOnDemandLoadingSupported(bool supported)
+{
+ s_loadRootCertsOnDemand = supported;
+}
+
+/*!
+ \internal
+*/
QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
{
- return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva ...
- << "/usr/lib/ssl/certs/" // Gentoo, Mandrake
- << "/usr/share/ssl/" // Centos, Redhat, SuSE
- << "/usr/local/ssl/" // Normal OpenSSL Tarball
- << "/var/ssl/certs/" // AIX
- << "/usr/local/ssl/certs/" // Solaris
- << "/etc/openssl/certs/" // BlackBerry
- << "/opt/openssl/certs/" // HP-UX
- << "/etc/ssl/"; // OpenBSD
+ const auto ba = [](const auto &cstr) constexpr {
+ return QByteArray::fromRawData(std::begin(cstr), std::size(cstr) - 1);
+ };
+ static const QByteArray dirs[] = {
+ ba("/etc/ssl/certs/"), // (K)ubuntu, OpenSUSE, Mandriva ...
+ ba("/usr/lib/ssl/certs/"), // Gentoo, Mandrake
+ ba("/usr/share/ssl/"), // Centos, Redhat, SuSE
+ ba("/usr/local/ssl/"), // Normal OpenSSL Tarball
+ ba("/var/ssl/certs/"), // AIX
+ ba("/usr/local/ssl/certs/"), // Solaris
+ ba("/etc/openssl/certs/"), // BlackBerry
+ ba("/opt/openssl/certs/"), // HP-UX
+ ba("/etc/ssl/"), // OpenBSD
+ };
+ QList<QByteArray> result = QList<QByteArray>::fromReadOnlyData(dirs);
+ if constexpr (isVxworks) {
+ static QByteArray vxworksCertsDir = qgetenv("VXWORKS_CERTS_DIR");
+ if (!vxworksCertsDir.isEmpty())
+ result.push_back(vxworksCertsDir);
+ }
+ return result;
}
/*!
\internal
*/
-void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> sslContext)
+void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, std::shared_ptr<QSslContext> tlsContext)
{
- if (socket->d_func()->sslContextPointer.isNull())
- socket->d_func()->sslContextPointer = sslContext;
+ if (!socket)
+ return;
+
+ if (auto *backend = socket->d_func()->backend.get())
+ backend->checkSettingSslContext(tlsContext);
}
/*!
\internal
*/
-QSharedPointer<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
+std::shared_ptr<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket)
{
- return (socket) ? socket->d_func()->sslContextPointer : QSharedPointer<QSslContext>();
+ if (!socket)
+ return {};
+
+ if (const auto *backend = socket->d_func()->backend.get())
+ return backend->sslContext();
+
+ return {};
}
bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
@@ -2634,17 +3042,17 @@ bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QS
*/
bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
- int wildcard = cn.indexOf(QLatin1Char('*'));
+ qsizetype wildcard = cn.indexOf(u'*');
// Check this is a wildcard cert, if not then just compare the strings
if (wildcard < 0)
- return QLatin1String(QUrl::toAce(cn)) == hostname;
+ return QLatin1StringView(QUrl::toAce(cn)) == hostname;
- int firstCnDot = cn.indexOf(QLatin1Char('.'));
- int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
+ qsizetype firstCnDot = cn.indexOf(u'.');
+ qsizetype secondCnDot = cn.indexOf(u'.', firstCnDot+1);
// Check at least 3 components
- if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
+ if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.size()))
return false;
// Check * is last character of 1st component (ie. there's a following .)
@@ -2652,12 +3060,12 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return false;
// Check only one star
- if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
+ if (cn.lastIndexOf(u'*') != wildcard)
return false;
// Reject wildcard character embedded within the A-labels or U-labels of an internationalized
// domain name (RFC6125 section 7.2)
- if (cn.startsWith(QLatin1String("xn--"), Qt::CaseInsensitive))
+ if (cn.startsWith("xn--"_L1, Qt::CaseInsensitive))
return false;
// Check characters preceding * (if any) match
@@ -2665,9 +3073,9 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return false;
// Check characters following first . match
- int hnDot = hostname.indexOf(QLatin1Char('.'));
+ qsizetype hnDot = hostname.indexOf(u'.');
if (QStringView{hostname}.mid(hnDot + 1) != QStringView{cn}.mid(firstCnDot + 1)
- && QStringView{hostname}.mid(hnDot + 1) != QLatin1String(QUrl::toAce(cn.mid(firstCnDot + 1)))) {
+ && QStringView{hostname}.mid(hnDot + 1) != QLatin1StringView(QUrl::toAce(cn.mid(firstCnDot + 1)))) {
return false;
}
@@ -2680,6 +3088,81 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos
return true;
}
+/*!
+ \internal
+*/
+QTlsBackend *QSslSocketPrivate::tlsBackendInUse()
+{
+ const QMutexLocker locker(&backendMutex);
+ if (tlsBackend)
+ return tlsBackend;
+
+ if (!activeBackendName.size())
+ activeBackendName = QTlsBackend::defaultBackendName();
+
+ if (!activeBackendName.size()) {
+ qCWarning(lcSsl, "No functional TLS backend was found");
+ return nullptr;
+ }
+
+ tlsBackend = QTlsBackend::findBackend(activeBackendName);
+ if (tlsBackend) {
+ QObject::connect(tlsBackend, &QObject::destroyed, tlsBackend, [] {
+ const QMutexLocker locker(&backendMutex);
+ tlsBackend = nullptr;
+ },
+ Qt::DirectConnection);
+ }
+ return tlsBackend;
+}
+
+/*!
+ \internal
+*/
+QSslSocket::SslMode QSslSocketPrivate::tlsMode() const
+{
+ return mode;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::isRootsOnDemandAllowed() const
+{
+ return allowRootCertOnDemandLoading;
+}
+
+/*!
+ \internal
+*/
+QString QSslSocketPrivate::verificationName() const
+{
+ return verificationPeerName;
+}
+
+/*!
+ \internal
+*/
+QString QSslSocketPrivate::tlsHostName() const
+{
+ return hostName;
+}
+
+QTcpSocket *QSslSocketPrivate::plainTcpSocket() const
+{
+ return plainSocket;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
+{
+ if (const auto *tlsBackend = tlsBackendInUse())
+ return tlsBackend->systemCaCertificates();
+ return {};
+}
+
QT_END_NAMESPACE
#include "moc_qsslsocket.cpp"
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index a808efbfdf..3ed1bc45cc 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLSOCKET_H
@@ -71,6 +35,7 @@ public:
SslClientMode,
SslServerMode
};
+ Q_ENUM(SslMode)
enum PeerVerifyMode {
VerifyNone,
@@ -78,6 +43,7 @@ public:
VerifyPeer,
AutoVerifyPeer
};
+ Q_ENUM(PeerVerifyMode)
explicit QSslSocket(QObject *parent = nullptr);
~QSslSocket();
@@ -163,6 +129,16 @@ public:
static long sslLibraryBuildVersionNumber();
static QString sslLibraryBuildVersionString();
+ static QList<QString> availableBackends();
+ static QString activeBackend();
+ static bool setActiveBackend(const QString &backendName);
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName = {});
+ static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {});
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName = {});
+ static bool isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName = {});
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName = {});
+ static bool isFeatureSupported(QSsl::SupportedFeature feat, const QString &backendName = {});
+
void ignoreSslErrors(const QList<QSslError> &errors);
void continueInterruptedHandshake();
@@ -191,6 +167,7 @@ protected:
private:
Q_DECLARE_PRIVATE(QSslSocket)
Q_DISABLE_COPY_MOVE(QSslSocket)
+
Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
Q_PRIVATE_SLOT(d_func(), void _q_disconnectedSlot())
@@ -204,10 +181,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
Q_PRIVATE_SLOT(d_func(), void _q_resumeImplementation())
-#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
- Q_PRIVATE_SLOT(d_func(), void _q_caRootLoaded(QSslCertificate,QSslCertificate))
-#endif
- friend class QSslSocketBackendPrivate;
};
#endif // QT_NO_SSL
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
deleted file mode 100644
index 4096fb68c6..0000000000
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ /dev/null
@@ -1,1554 +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 "qsslsocket.h"
-
-#include "qssl_p.h"
-#include "qsslsocket_mac_p.h"
-#include "qasn1element_p.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_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
-
-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(lcSsl) << "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(lcSsl) << "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(lcSsl) << "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(lcSsl) << "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(lcSsl) << "SecKeychainSettings: failed to disable lock on sleep";
- }
-
-#ifdef QSSLSOCKET_DEBUG
- if (keychain) {
- qCDebug(lcSsl) << "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
-
-} // unnamed namespace
-
-static 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;
-}
-
-static void qt_releaseSecureTransportContext(SSLContextRef context)
-{
- if (context)
- CFRelease(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;
-}
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
-
-//#define QSSLSOCKET_DEBUG
-
-bool QSslSocketPrivate::s_libraryLoaded = false;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
-
-
-#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 QSslSocketBackendPrivate::ReadCallback(QSslSocketBackendPrivate *socket,
- char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- QTcpSocket *plainSocket = socket->plainSocket;
- 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(lcSsl) << 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 QSslSocketBackendPrivate::WriteCallback(QSslSocketBackendPrivate *socket,
- const char *data, size_t *dataLength)
-{
- Q_ASSERT(socket);
- Q_ASSERT(data);
- Q_ASSERT(dataLength);
-
- QTcpSocket *plainSocket = socket->plainSocket;
- Q_ASSERT(plainSocket);
-
- const qint64 bytes = plainSocket->write(data, *dataLength);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "write" << bytes;
-#endif
- if (bytes < 0) {
- *dataLength = 0;
- return errSecIO;
- }
-
- const OSStatus err = (size_t(bytes) < *dataLength) ? errSSLWouldBlock : errSecSuccess;
- *dataLength = bytes;
-
- return err;
-}
-
-void QSslSocketPrivate::ensureInitialized()
-{
- 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 QSecureTransportContext context(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(QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(cfCiphers.at(i)));
- if (!ciph.isNull()) {
- ciphers << ciph;
- if (ciph.usedBits() >= 128)
- defaultCiphers << ciph;
- }
- }
-
- setDefaultSupportedCiphers(ciphers);
- setDefaultCiphers(defaultCiphers);
-
- if (!s_loadRootCertsOnDemand)
- setDefaultCaCertificates(systemCaCertificates());
- } else {
- s_loadedCiphersAndCerts = false;
- }
-
-}
-
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- return 0;
-}
-
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- return QLatin1String("Secure Transport, ") + QSysInfo::prettyProductName();
-}
-
-long QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- return 0;
-}
-
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- return sslLibraryVersionString();
-}
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return true;
-}
-
-void QSslSocketPrivate::resetDefaultCiphers()
-{
- Q_UNIMPLEMENTED();
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- // No public API for this (?).
- Q_UNIMPLEMENTED();
-}
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
- : context(nullptr)
-{
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- destroySslContext();
-}
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "connection encrypted";
-#endif
- Q_Q(QSslSocket);
- connectionEncrypted = true;
-
-#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).
- if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
- const auto &requestedProtocols = configuration.nextAllowedProtocols;
- if (const int requestedCount = requestedProtocols.size()) {
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- configuration.nextNegotiatedProtocol.clear();
-
- 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]) {
- configuration.nextNegotiatedProtocol = requestedName.toLatin1();
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- break;
- }
- }
- if (configuration.nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNegotiated)
- break;
- }
- }
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (!renegotiating)
- emit q->encrypted();
-
- if (autoStartHandshake && pendingClose) {
- pendingClose = false;
- q->disconnectFromHost();
- }
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- if (plainSocket->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 QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (context) {
- if (!shutdown) {
- SSLClose(context);
- shutdown = true;
- }
- }
- plainSocket->disconnectFromHost();
-}
-
-QSslCipher QSslSocketBackendPrivate::sessionCipher() const
-{
- SSLCipherSuite cipher = 0;
- if (context && SSLGetNegotiatedCipher(context, &cipher) == errSecSuccess)
- return QSslCipher_from_SSLCipherSuite(cipher);
-
- return QSslCipher();
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!context)
- return QSsl::UnknownProtocol;
-
- SSLProtocol protocol = kSSLProtocolUnknown;
- const OSStatus err = SSLGetNegotiatedProtocolVersion(context, &protocol);
- if (err != errSecSuccess) {
- qCWarning(lcSsl) << "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 QSslSocketBackendPrivate::startClientEncryption()
-{
- if (!initSslContext()) {
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (!initSslContext()) {
- // Error description/code were set, 'error' emitted
- // by initSslContext, but OpenSSL socket also sets error
- // emits a signal twice, so ...
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
- return;
- }
-
- startHandshake();
-}
-
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- // 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();
-
- 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(lcSsl) << plainSocket << "SSLWrite returned" << err;
-#endif
- if (err != errSecSuccess && err != errSSLWouldBlock) {
- 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.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- 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(lcSsl) << plainSocket << "SSLRead returned" << err;
-#endif
- if (err == errSSLClosedGraceful) {
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
- QSslSocket::tr("The TLS/SSL connection has been closed"));
- break;
- } else if (err != errSecSuccess && err != errSSLWouldBlock) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLRead failed: %1").arg(err));
- break;
- }
-
- if (err == errSSLWouldBlock && renegotiating) {
- startHandshake();
- break;
- }
-
- if (readBytes) {
- buffer.append(data.constData(), readBytes);
- if (readyReadEmittedPointer)
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
-
- if (err == errSSLWouldBlock)
- break;
- }
- }
-}
-
-
-QList<QSslError> (QSslSocketBackendPrivate::verify)(QList<QSslCertificate> certificateChain, const QString &hostName)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(certificateChain);
- Q_UNUSED(hostName);
-
- QList<QSslError> errors;
- errors << QSslError(QSslError::UnspecifiedError);
-
- return errors;
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- Q_UNIMPLEMENTED();
- Q_UNUSED(device);
- Q_UNUSED(key);
- Q_UNUSED(cert);
- Q_UNUSED(caCertificates);
- Q_UNUSED(passPhrase);
- return false;
-}
-
-QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
-{
- QSslCipher ciph;
- 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:
- ciph.d->name = QLatin1String("AES128-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("AES256-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA");
- break;
-
- // ECDSA addenda, RFC 4492
- case TLS_ECDH_ECDSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-NULL-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-RC4-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
- break;
- case TLS_ECDH_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-NULL-SHA");
- break;
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-RC4-SHA");
- break;
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-NULL-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-RC4-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA");
- break;
-
- // TLS 1.2 addenda, RFC 5246
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DES-CBC3-SHA");
- break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("AES128-SHA256");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->name = QLatin1String("AES256-SHA256");
- break;
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA256");
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->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:
- ciph.d->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:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA256");
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA384");
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA256");
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- ciph.d->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:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384");
- break;
-
- default:
- return ciph;
- }
- ciph.d->isNull = false;
-
- // protocol
- ciph.d->protocol = QSsl::TlsV1_2;
- ciph.d->protocolString = QLatin1String("TLSv1.2");
-
- const auto bits = QStringView{ciph.d->name}.split(QLatin1Char('-'));
- if (bits.size() >= 2) {
- if (bits.size() == 2 || bits.size() == 3) {
- ciph.d->keyExchangeMethod = QLatin1String("RSA");
- } else if (bits.front() == QLatin1String("DH") || bits.front() == QLatin1String("DHE")) {
- ciph.d->keyExchangeMethod = QLatin1String("DH");
- } else if (bits.front() == QLatin1String("ECDH") || bits.front() == QLatin1String("ECDHE")) {
- ciph.d->keyExchangeMethod = QLatin1String("ECDH");
- } else {
- qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name;
- }
-
- if (bits.size() == 2 || bits.size() == 3) {
- ciph.d->authenticationMethod = QLatin1String("RSA");
- } else if (ciph.d->name.contains(QLatin1String("-ECDSA-"))) {
- ciph.d->authenticationMethod = QLatin1String("ECDSA");
- } else if (ciph.d->name.contains(QLatin1String("-RSA-"))) {
- ciph.d->authenticationMethod = QLatin1String("RSA");
- } else {
- qCWarning(lcSsl) << "Unknown Au" << ciph.d->name;
- }
-
- if (ciph.d->name.contains(QLatin1String("RC4-"))) {
- ciph.d->encryptionMethod = QLatin1String("RC4(128)");
- ciph.d->bits = 128;
- ciph.d->supportedBits = 128;
- } else if (ciph.d->name.contains(QLatin1String("DES-CBC3-"))) {
- ciph.d->encryptionMethod = QLatin1String("3DES(168)");
- ciph.d->bits = 168;
- ciph.d->supportedBits = 168;
- } else if (ciph.d->name.contains(QLatin1String("AES128-"))) {
- ciph.d->encryptionMethod = QLatin1String("AES(128)");
- ciph.d->bits = 128;
- ciph.d->supportedBits = 128;
- } else if (ciph.d->name.contains(QLatin1String("AES256-GCM"))) {
- ciph.d->encryptionMethod = QLatin1String("AESGCM(256)");
- ciph.d->bits = 256;
- ciph.d->supportedBits = 256;
- } else if (ciph.d->name.contains(QLatin1String("AES256-"))) {
- ciph.d->encryptionMethod = QLatin1String("AES(256)");
- ciph.d->bits = 256;
- ciph.d->supportedBits = 256;
- } else if (ciph.d->name.contains(QLatin1String("NULL-"))) {
- ciph.d->encryptionMethod = QLatin1String("NULL");
- } else {
- qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name;
- }
- }
- return ciph;
-}
-SSLCipherSuite QSslSocketBackendPrivate::SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph)
-{
- if (ciph.d->name == QLatin1String("AES128-SHA"))
- return TLS_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES128-SHA"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("AES256-SHA"))
- return TLS_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES256-SHA"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-NULL-SHA"))
- return TLS_ECDH_ECDSA_WITH_NULL_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-RC4-SHA"))
- return TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-DES-CBC3-SHA"))
- return TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-NULL-SHA"))
- return TLS_ECDH_RSA_WITH_NULL_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDH_RSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-RC4-SHA"))
- return TLS_ECDHE_RSA_WITH_RC4_128_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-DES-CBC3-SHA"))
- return TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES128-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
- if (ciph.d->name == QLatin1String("ECDH-RSA-AES256-SHA"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
- if (ciph.d->name == QLatin1String("DES-CBC3-SHA"))
- return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("AES128-SHA256"))
- return TLS_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("AES256-SHA256"))
- return TLS_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.d->name == QLatin1String("DHE-RSA-DES-CBC3-SHA"))
- return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES128-SHA256"))
- return TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("DHE-RSA-AES256-SHA256"))
- return TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
- if (ciph.d->name == QLatin1String("AES256-GCM-SHA384"))
- return TLS_RSA_WITH_AES_256_GCM_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-ECDSA-AES128-SHA256"))
- return TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-ECDSA-AES256-SHA384"))
- return TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES128-SHA256"))
- return TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDH-ECDSA-AES256-SHA384"))
- return TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES128-SHA256"))
- return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-SHA384"))
- return TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
- if (ciph.d->name == QLatin1String("ECDHE-RSA-AES256-GCM-SHA384"))
- return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
- return 0;
-}
-
-bool QSslSocketBackendPrivate::initSslContext()
-{
- Q_Q(QSslSocket);
-
- Q_ASSERT_X(!context, Q_FUNC_INFO, "invalid socket state, context is not null");
- Q_ASSERT(plainSocket);
-
- context.reset(qt_createSecureTransportContext(mode));
- if (!context) {
- setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
- return false;
- }
-
- const OSStatus err = SSLSetIOFuncs(context,
- reinterpret_cast<SSLReadFunc>(&QSslSocketBackendPrivate::ReadCallback),
- reinterpret_cast<SSLWriteFunc>(&QSslSocketBackendPrivate::WriteCallback));
- if (err != errSecSuccess) {
- destroySslContext();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QStringLiteral("SSLSetIOFuncs failed: %1").arg(err));
- return false;
- }
-
- SSLSetConnection(context, this);
-
- if (mode == QSslSocket::SslServerMode
- && !configuration.localCertificateChain.isEmpty()) {
- QString errorDescription;
- QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
- if (!setSessionCertificate(errorDescription, errorCode)) {
- destroySslContext();
- setErrorAndEmit(errorCode, errorDescription);
- return false;
- }
- }
-
- if (!setSessionProtocol()) {
- destroySslContext();
- 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.nextAllowedProtocols;
- QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
- if (cfNames) {
- for (const QByteArray &name : protocolNames) {
- if (name.size() > 255) {
- qCWarning(lcSsl) << "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(lcSsl) << "SSLSetALPNProtocols failed - too long protocol names?";
- }
- } else {
- qCWarning(lcSsl) << "failed to allocate ALPN names array";
- }
- }
-#endif // QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE
-
- if (mode == QSslSocket::SslClientMode) {
- // enable Server Name Indication (SNI)
- QString tlsHostName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
- if (tlsHostName.isEmpty())
- tlsHostName = hostName;
-
- 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();
- 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();
- 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 = QSslSocketBackendPrivate::SSLCipherSuite_from_QSslCipher(cipher))
- cfCiphers << sslCipher;
- }
- if (cfCiphers.size() == 0) {
- qCWarning(lcSsl) << "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(lcSsl) << "failed to set the ciphers from the configuration";
- return false;
- }
- }
- return true;
-}
-
-void QSslSocketBackendPrivate::destroySslContext()
-{
- context.reset(nullptr);
-}
-
-bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode)
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- 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(lcSsl) << 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(lcSsl) << 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(lcSsl) << 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(lcSsl) << 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 QSslSocketBackendPrivate::setSessionProtocol()
-{
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
-
- // 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.
- switch (configuration.protocol) {
- case QSsl::TlsV1_3:
- case QSsl::TlsV1_3OrLater:
- qCWarning(lcSsl) << plainSocket << "SecureTransport does not support TLS 1.3";
- return false;
- default:;
- }
-
- OSStatus err = errSecSuccess;
-
- if (configuration.protocol == QSsl::TlsV1_0) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << 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(lcSsl) << 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(lcSsl) << 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(lcSsl) << plainSocket << "requesting : any";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::SecureProtocols) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- } else {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
- #endif
- return false;
- }
-
- return err == errSecSuccess;
-}
-
-bool QSslSocketBackendPrivate::canIgnoreTrustVerificationFailure() const
-{
- const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
- return mode == QSslSocket::SslServerMode
- && (verifyMode == QSslSocket::QueryPeer
- || verifyMode == QSslSocket::AutoVerifyPeer
- || verifyMode == QSslSocket::VerifyNone);
-}
-
-bool QSslSocketBackendPrivate::verifySessionProtocol() const
-{
- 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 QSslSocketBackendPrivate::verifyPeerTrust()
-{
- Q_Q(QSslSocket);
-
- const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
- const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
-
- Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- 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) {
- 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 ...
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SecTrustEvaluate failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- configuration.peerCertificate.clear();
- configuration.peerCertificateChain.clear();
-
- const CFIndex certCount = SecTrustGetCertificateCount(trust);
- for (CFIndex i = 0; i < certCount; ++i) {
- SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
- QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
- configuration.peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
-
- if (configuration.peerCertificateChain.size())
- configuration.peerCertificate = configuration.peerCertificateChain.at(0);
-
- // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
- for (const QSslCertificate &cert : qAsConst(configuration.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
- && 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.
- 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 (mode == QSslSocket::SslClientMode) {
- const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
- if (!isMatchingHostname(configuration.peerCertificate, peerName) && !canIgnoreVerify) {
- // No matches in common names or alternate names.
- const 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 && !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);
- for (const QSslCertificate &cert : qAsConst(configuration.caCertificates)) {
- QCFType<CFDataRef> certData = cert.d->derData.toCFData();
- if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
- CFArrayAppendValue(certArray, secRef);
- else
- qCWarning(lcSsl, "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, configuration.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 QSslSocketBackendPrivate::checkSslErrors()
-{
- Q_Q(QSslSocket);
- if (sslErrors.isEmpty())
- return true;
-
- emit q->sslErrors(sslErrors);
-
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-bool QSslSocketBackendPrivate::startHandshake()
-{
- Q_ASSERT(context);
- Q_Q(QSslSocket);
-
- OSStatus err = SSLHandshake(context);
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << 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)) {
- 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;
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QStringLiteral("SSLHandshake failed: %1").arg(err));
- plainSocket->disconnectFromHost();
- return false;
- }
-
- // Connection aborted during handshake phase.
- if (q->state() != QAbstractSocket::ConnectedState) {
- qCDebug(lcSsl) << "connection aborted";
- renegotiating = false;
- return false;
- }
-
- // check protocol version ourselves, as Secure Transport does not enforce
- // the requested min / max versions.
- if (!verifySessionProtocol()) {
- 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;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h
deleted file mode 100644
index dcd4f4de72..0000000000
--- a/src/network/ssl/qsslsocket_mac_p.h
+++ /dev/null
@@ -1,138 +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 QSSLSOCKET_MAC_P_H
-#define QSSLSOCKET_MAC_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 <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
-
-class QSecureTransportContext
-{
-public:
- explicit QSecureTransportContext(SSLContextRef context);
- ~QSecureTransportContext();
-
- operator SSLContextRef () const;
- void reset(SSLContextRef newContext);
-private:
- SSLContextRef context;
-
- Q_DISABLE_COPY_MOVE(QSecureTransportContext)
-};
-
-class QSslSocketBackendPrivate : public QSslSocketPrivate
-{
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- virtual ~QSslSocketBackendPrivate();
-
- // Final-overriders (QSslSocketPrivate):
- 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;
-
- static QList<QSslError> verify(QList<QSslCertificate> certificateChain,
- const QString &hostName);
-
- static bool importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
-
- static QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
- static SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &cipher);
-
-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 {return connectionEncrypted && !renegotiating;}
-
- // IO callbacks:
- static OSStatus ReadCallback(QSslSocketBackendPrivate *socket, char *data, size_t *dataLength);
- static OSStatus WriteCallback(QSslSocketBackendPrivate *plainSocket, const char *data, size_t *dataLength);
-
- QSecureTransportContext context;
- bool renegotiating = false;
-
- Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
deleted file mode 100644
index 0bc4647e8b..0000000000
--- a/src/network/ssl/qsslsocket_mac_shared.cpp
+++ /dev/null
@@ -1,155 +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$
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-//#define QT_DECRYPT_SSL_TRAFFIC
-
-#include "qssl_p.h"
-#include "qsslsocket.h"
-
-#ifndef QT_NO_OPENSSL
-# include "qsslsocket_openssl_p.h"
-# include "qsslsocket_openssl_symbols_p.h"
-#endif
-
-#include "qsslcertificate_p.h"
-
-#ifdef Q_OS_DARWIN
-# include <private/qcore_mac_p.h>
-#endif
-
-#include <QtCore/qdebug.h>
-
-#ifdef Q_OS_MACOS
-# include <Security/Security.h>
-#endif
-
-
-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(lcSsl, "Error receiving trust for a CA certificate");
- }
- return false;
-}
-
-} // anon namespace
-#endif // Q_OS_MACOS
-
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- ensureInitialized();
-
- 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 == NULL) {
- qCWarning(lcSsl, "Error retrieving a CA certificate from the system store");
- } else {
- systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
- }
- }
- }
- }
- }
-#endif
- return systemCerts;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
deleted file mode 100644
index c5f82502fc..0000000000
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ /dev/null
@@ -1,2508 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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.
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-
-#include "qssl_p.h"
-#include "qsslsocket_openssl_p.h"
-#include "qsslsocket_openssl_symbols_p.h"
-#include "qsslsocket.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_p.h"
-#include "qsslkey_p.h"
-#include "qsslellipticcurve.h"
-#include "qsslpresharedkeyauthenticator.h"
-#include "qsslpresharedkeyauthenticator_p.h"
-#include "qocspresponse_p.h"
-#include "qsslkey.h"
-
-#ifdef Q_OS_WIN
-#include "qwindowscarootfetcher_p.h"
-#endif
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qscopedvaluerollback.h>
-#include <QtCore/qscopeguard.h>
-#include <QtCore/qlibrary.h>
-#include <QtCore/qoperatingsystemversion.h>
-
-#if QT_CONFIG(ocsp)
-#include "qocsp_p.h"
-#endif
-
-#include <algorithm>
-#include <memory>
-
-#include <string.h>
-
-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(lcSsl) << 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
-
-extern "C"
-{
-
-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(lcSsl, "Invalid 'connection' parameter (nullptr)");
-#endif // QSSLSOCKET_DEBUG
- return;
- }
-
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::socketOffsetInExData;
- auto privateSocket =
- static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(connection, offset));
- if (!privateSocket) {
- // SSL_set_ex_data can fail:
-#ifdef QSSLSOCKET_DEBUG
- qCWarning(lcSsl, "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)
- privateSocket->alertMessageSent(value);
- else
- privateSocket->alertMessageReceived(value);
-}
-
-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(lcSsl, "No external data (SSL) found in X509 store object");
- return 0;
- }
-
- const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::socketOffsetInExData;
- auto privateSocket = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, offset));
- if (!privateSocket) {
- qCWarning(lcSsl, "No external data (QSslSocketBackendPrivate) found in SSL object");
- return 0;
- }
-
- return privateSocket->emitErrorFromCallback(ctx);
- }
- return 1;
-}
-
-} // extern "C"
-
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
-
-bool QSslSocketPrivate::s_libraryLoaded = false;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
-int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1;
-
-QString QSslSocketBackendPrivate::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 QSslSocketBackendPrivate::logAndClearErrorQueue()
-{
- const auto errors = getErrorsFromOpenSsl();
- if (errors.size())
- qCWarning(lcSsl) << "Discarding errors:" << errors;
-}
-
-extern "C" {
-
-#ifndef OPENSSL_NO_PSK
-static unsigned int q_ssl_psk_client_callback(SSL *ssl,
- const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- return d->tlsPskClientCallback(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)
-{
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- return d->tlsPskServerCallback(identity, psk, max_psk_len);
-}
-
-#ifdef TLS1_3_VERSION
-static unsigned int q_ssl_psk_restore_client(SSL *ssl,
- const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int 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
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- Q_ASSERT(d->mode == 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
- QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- Q_ASSERT(d);
- Q_ASSERT(d->mode == 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(lcSsl, "Invalid SSL (nullptr)");
- return 0;
- }
- if (!session) {
- qCWarning(lcSsl, "Invalid SSL_SESSION (nullptr)");
- return 0;
- }
-
- auto socketPrivate = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl,
- QSslSocketBackendPrivate::s_indexForSSLExtraData));
- return socketPrivate->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 d = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
- if (!d)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
-
- Q_ASSERT(d->mode == QSslSocket::SslServerMode);
- const QByteArray &response = d->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
-
-} // extern "C"
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
- : ssl(nullptr),
- readBio(nullptr),
- writeBio(nullptr),
- session(nullptr)
-{
- // Calls SSL_library_init().
- ensureInitialized();
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- destroySslContext();
-}
-
-QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher)
-{
- QSslCipher ciph;
-
- char buf [256];
- QString descriptionOneLine = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
-
- const auto descriptionList = QStringView{descriptionOneLine}.split(QLatin1Char(' '), Qt::SkipEmptyParts);
- if (descriptionList.size() > 5) {
- // ### crude code.
- ciph.d->isNull = false;
- ciph.d->name = descriptionList.at(0).toString();
-
- QString protoString = descriptionList.at(1).toString();
- ciph.d->protocolString = protoString;
- ciph.d->protocol = QSsl::UnknownProtocol;
- if (protoString == QLatin1String("TLSv1"))
- ciph.d->protocol = QSsl::TlsV1_0;
- else if (protoString == QLatin1String("TLSv1.1"))
- ciph.d->protocol = QSsl::TlsV1_1;
- else if (protoString == QLatin1String("TLSv1.2"))
- ciph.d->protocol = QSsl::TlsV1_2;
- else if (protoString == QLatin1String("TLSv1.3"))
- ciph.d->protocol = QSsl::TlsV1_3;
-
- if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))
- ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString();
- if (descriptionList.at(3).startsWith(QLatin1String("Au=")))
- ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString();
- if (descriptionList.at(4).startsWith(QLatin1String("Enc=")))
- ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString();
- ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export"));
-
- ciph.d->bits = q_SSL_CIPHER_get_bits(cipher, &ciph.d->supportedBits);
- }
- return ciph;
-}
-
-QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx)
-{
- return {
- q_X509_STORE_CTX_get_error(ctx),
- q_X509_STORE_CTX_get_error_depth(ctx)
- };
-}
-
-#if QT_CONFIG(ocsp)
-
-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;
-}
-
-#endif // ocsp
-
-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 = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::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(lcSsl, "Neither X509_STORE, nor SSL contains error list, handshake failure");
- return 0;
- }
-
- errors->append(QSslErrorEntry::fromStoreContext(ctx));
- }
- // Always return OK to allow verification to continue. We handle the
- // errors gracefully after collecting all errors, after verification has
- // completed.
- return 1;
-}
-
-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)) {
- QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(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;
- }
- }
- }
- }
-}
-
-// Defined in qsslsocket.cpp
-void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
-
-long QSslSocketBackendPrivate::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;
-}
-
-bool QSslSocketBackendPrivate::initSslContext()
-{
- Q_Q(QSslSocket);
-
- // If no external context was set (e.g. by QHttpNetworkConnection) we will
- // create a default context
- if (!sslContextPointer) {
- // create a deep copy of our configuration
- QSslConfigurationPrivate *configurationCopy = new QSslConfigurationPrivate(configuration);
- configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
- sslContextPointer = QSslContext::sharedFromConfiguration(mode, configurationCopy, allowRootCertOnDemandLoading);
- }
-
- if (sslContextPointer->error() != QSslError::NoError) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
- sslContextPointer.clear(); // deletes the QSslContext
- return false;
- }
-
- // Create and initialize SSL session
- if (!(ssl = sslContextPointer->createSsl())) {
- // ### Bad error code
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session, %1").arg(getErrorsFromOpenSsl()));
- return false;
- }
-
- if (configuration.protocol != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
- // 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 = hostName;
- 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.sslOptions & 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(lcSsl, "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) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error creating SSL session: %1").arg(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, 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) {
- 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) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Failed to enable OCSP stapling"));
- return false;
- }
- }
-
- ocspResponseDer.clear();
- auto responsePos = configuration.backendConfig.find("Qt-OCSP-response");
- if (responsePos != configuration.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) {
- setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
- QSslSocket::tr("Client-side sockets do not send OCSP responses"));
- return false;
- }
- }
-#endif // ocsp
-
- return true;
-}
-
-void QSslSocketBackendPrivate::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 = getErrorsFromOpenSsl();
- Q_UNUSED(errors);
- }
- }
- q_SSL_free(ssl);
- ssl = nullptr;
- }
- sslContextPointer.clear();
-}
-
-/*!
- \internal
-
- Does the minimum amount of initialization to determine whether SSL
- is supported or not.
-*/
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return ensureLibraryLoaded();
-}
-
-
-/*!
- \internal
-
- Returns the version number of the SSL library in use. Note that
- this is the version of the library in use at run-time, not compile
- time.
-*/
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- if (!supportsSsl())
- return 0;
-
- return q_OpenSSL_version_num();
-}
-
-/*!
- \internal
-
- Returns the version string of the SSL library in use. Note that
- this is the version of the library in use at run-time, not compile
- time. If no SSL support is available then this will return an empty value.
-*/
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- if (!supportsSsl())
- return QString();
-
- const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
- if (!versionString)
- return QString();
-
- return QString::fromLatin1(versionString);
-}
-
-/*!
- \internal
-
- Declared static in QSslSocketPrivate, makes sure the SSL libraries have
- been initialized.
-*/
-void QSslSocketPrivate::ensureInitialized()
-{
- if (!supportsSsl())
- return;
-
- ensureCiphersAndCertsLoaded();
-}
-
-/*!
- \internal
-
- Returns the version number of the SSL library in use at compile
- time.
-*/
-long QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- return OPENSSL_VERSION_NUMBER;
-}
-
-/*!
- \internal
-
- Returns the version string of the SSL library in use at compile
- time.
-*/
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- // 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);
-}
-
-/*!
- \internal
-
- Declared static in QSslSocketPrivate, backend-dependent loading of
- application-wide global ciphers.
-*/
-void QSslSocketPrivate::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);
- q_setDefaultDtlsCiphers(defaultCiphers);
- q_SSL_free(mySsl);
- }
- q_SSL_CTX_free(myCtx);
- }
-#endif // dtls
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- QList<QSslEllipticCurve> curves;
-
-#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) {
- curves.reserve(int(curveCount));
- for (size_t i = 0; i < curveCount; ++i) {
- QSslEllipticCurve curve;
- curve.id = builtinCurves[int(i)].nid;
- curves.append(curve);
- }
- }
-#endif // OPENSSL_NO_EC
-
- // set the list of supported ECs, but not the list
- // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong
- // ciphersuite, so don't try it -- leave the empty list to mean
- // "the implementation will choose the most suitable one".
- setDefaultSupportedEllipticCurves(curves);
-}
-
-#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- ensureInitialized();
-#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 = 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(lcSsl) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
- qCDebug(lcSsl) << "imported " << systemCerts.count() << " certificates";
-#endif
-
- return systemCerts;
-}
-#endif // Q_OS_DARWIN
-
-void QSslSocketBackendPrivate::startClientEncryption()
-{
- if (!initSslContext()) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (!initSslContext()) {
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to init SSL Context: %1").arg(getErrorsFromOpenSsl()));
- return;
- }
-
- // Start connecting. This will place outgoing data in the BIO, so we
- // follow up with calling transmit().
- startHandshake();
- transmit();
-}
-
-/*!
- \internal
-
- Transmits encrypted data between the BIOs and the socket.
-*/
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return;
-
- // If we don't have any SSL context, don't bother transmitting.
- if (!ssl)
- return;
-
- 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 (connectionEncrypted && !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);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to write data: %1").arg(
- getErrorsFromOpenSsl()));
- return;
- }
- }
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::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(lcSsl) << "QSslSocketBackendPrivate::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);
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- transmitting = true;
- }
-
- // Check if we've got any data to be read from the socket.
- if (!connectionEncrypted || !readBufferMaxSize || buffer.size() < readBufferMaxSize)
- 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(lcSsl) << "QSslSocketBackendPrivate::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);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Unable to decrypt data: %1").arg(
- getErrorsFromOpenSsl()));
- return;
- }
-
- transmitting = true;
- }
-
- // If the connection isn't secured yet, this is the time to retry the
- // connect / accept.
- if (!connectionEncrypted) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: testing encryption";
-#endif
- if (startHandshake()) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: encryption established";
-#endif
- connectionEncrypted = true;
- transmitting = true;
- } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::transmit: connection lost";
-#endif
- break;
- } else if (paused) {
- // just wait until the user continues
- return;
- } else {
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::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 (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(lcSsl) << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes";
-#endif
- buffer.chop(bytesToRead - readBytes);
-
- if (readyReadEmittedPointer)
- *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(lcSsl) << "QSslSocketBackendPrivate::transmit: remote disconnect";
-#endif
- shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves
- {
- const ScopedBool bg(inSetAndEmitError, true);
- 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);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1").arg(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);
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
- }
- break;
- }
- } while (ssl && readBytes > 0);
- } while (ssl && transmitting);
-}
-
-QSslError _q_OpenSSL_to_QSslError(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;
-}
-
-QString QSslSocketBackendPrivate::msgErrorsDuringHandshake()
-{
- return QSslSocket::tr("Error during SSL handshake: %1")
- .arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
-}
-
-bool QSslSocketBackendPrivate::startHandshake()
-{
- Q_Q(QSslSocket);
-
- // Check if the connection has been established. Get all errors from the
- // verification stage.
-
- using ScopedBool = QScopedValueRollback<bool>;
-
- if (inSetAndEmitError)
- return false;
-
- pendingFatalAlert = false;
- errorsReportedFromCallback = false;
- QList<QSslErrorEntry> lastErrors;
- q_SSL_set_ex_data(ssl, 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, 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, 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();
-
- if (!errorsReportedFromCallback) {
- for (const auto &currentError : qAsConst(lastErrors)) {
- emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.code,
- configuration.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 = QSslSocketBackendPrivate::msgErrorsDuringHandshake();
-#ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << "QSslSocketBackendPrivate::startHandshake: error!" << errorString;
-#endif
- {
- const ScopedBool bg(inSetAndEmitError, true);
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, errorString);
- if (pendingFatalAlert) {
- trySendFatalAlert();
- pendingFatalAlert = false;
- }
- }
- q->abort();
- }
- return false;
- }
-
- // store peer certificate chain
- storePeerCertificates();
-
- // Start translating errors.
- QList<QSslError> errors;
-
- // check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
- for (const QSslCertificate &cert : qAsConst(configuration.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);
- 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
- 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 << _q_OpenSSL_to_QSslError(error.code, configuration.peerCertificateChain.value(error.depth));
-
- if (!errors.isEmpty()) {
- sslErrors = errors;
-
-#ifdef Q_OS_WIN
- const bool fetchEnabled = s_loadRootCertsOnDemand
- && allowRootCertOnDemandLoading;
- // !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 && !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
- 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 QSslSocketBackendPrivate::storePeerCertificates()
-{
- // 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);
- configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
- q_X509_free(x509);
- if (configuration.peerCertificateChain.isEmpty()) {
- configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));
- if (!configuration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
- configuration.peerCertificateChain.prepend(configuration.peerCertificate);
- }
-}
-
-int QSslSocketBackendPrivate::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_Q(QSslSocket);
-
- Q_ASSERT(connection);
-
- 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(lcSsl,
- "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(lcSsl, "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(lcSsl, "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(lcSsl, "could not store persistent version of SSL session");
- return 0;
- }
-
- configuration.sslSession = sessionTicket;
- configuration.sslSessionTicketLifeTimeHint = int(q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
-
- emit q->newSessionTicketReceived();
- return 0;
-}
-
-bool QSslSocketBackendPrivate::checkSslErrors()
-{
- Q_Q(QSslSocket);
- if (sslErrors.isEmpty())
- return true;
-
- emit q->sslErrors(sslErrors);
-
- bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
- return true;
-}
-
-unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint,
- char *identity, unsigned int max_identity_len,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslPreSharedKeyAuthenticator authenticator;
-
- // Fill in some read-only fields (for the user)
- if (hint)
- authenticator.d->identityHint = QByteArray::fromRawData(hint, int(::strlen(hint))); // it's NUL terminated, but do not include the NUL
-
- authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NUL terminated
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- // Let the client provide the remaining bits...
- Q_Q(QSslSocket);
- 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());
- ::memcpy(identity, authenticator.identity().constData(), identityLength);
- identity[identityLength] = 0;
-
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
- ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-unsigned int QSslSocketBackendPrivate::tlsPskServerCallback(const char *identity,
- unsigned char *psk, unsigned int max_psk_len)
-{
- QSslPreSharedKeyAuthenticator authenticator;
-
- // Fill in some read-only fields (for the user)
- authenticator.d->identityHint = configuration.preSharedKeyIdentityHint;
- authenticator.d->identity = identity;
- authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
- authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
-
- // Let the client provide the remaining bits...
- Q_Q(QSslSocket);
- 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());
- ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
- return pskLength;
-}
-
-#ifdef Q_OS_WIN
-
-void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
-{
- Q_Q(QSslSocket);
- //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 = configuration.caCertificates;
-
- //Remember we are fetching and what we are fetching:
- caToFetch = cert;
-
- QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, mode, customRoots, q->peerVerifyName());
- QObjectPrivate::connect(fetcher, &QWindowsCaRootFetcher::finished,
- this, &QSslSocketBackendPrivate::_q_caRootLoaded,
- Qt::QueuedConnection);
- QMetaObject::invokeMethod(fetcher, "start", Qt::QueuedConnection);
- pauseSocketNotifiers(q);
- paused = true;
-}
-
-//This is the callback from QWindowsCaRootFetcher, trustedRoot will be invalid (default constructed) if it failed.
-void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot)
-{
- if (caToFetch != cert) {
- //Ooops, something from the previous connection attempt, ignore!
- return;
- }
-
- //Done, fetched already:
- caToFetch = QSslCertificate{};
-
- if (fetchAuthorityInformation) {
- if (!configuration.caCertificates.contains(trustedRoot))
- trustedRoot = QSslCertificate{};
- fetchAuthorityInformation = false;
- }
-
- if (!trustedRoot.isNull() && !trustedRoot.isBlacklisted()) {
- if (s_loadRootCertsOnDemand) {
- //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
- if (!configuration.caCertificates.contains(trustedRoot))
- configuration.caCertificates += 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;
- }
- }
- }
- }
-
- // Continue with remaining errors
- if (plainSocket)
- plainSocket->resume();
- paused = false;
- if (checkSslErrors() && ssl) {
- bool willClose = (autoStartHandshake && pendingClose);
- continueHandshake();
- if (!willClose)
- transmit();
- }
-}
-
-#endif
-
-#if QT_CONFIG(ocsp)
-
-bool QSslSocketBackendPrivate::checkOcspStatus()
-{
- Q_ASSERT(ssl);
- Q_ASSERT(mode == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
- Q_ASSERT(configuration.peerVerifyMode != QSslSocket::VerifyNone);
-
- const auto clearErrorQueue = qScopeGuard([] {
- 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 (configuration.peerCertificate.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 = QSslCertificatePrivate::QSslCertificate_from_X509(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 // ocsp
-
-void QSslSocketBackendPrivate::alertMessageSent(int value)
-{
- Q_Q(QSslSocket);
-
- const auto level = tlsAlertLevel(value);
- if (level == QSsl::AlertLevel::Fatal && !connectionEncrypted) {
- // Note, this logic is handshake-time only:
- pendingFatalAlert = true;
- }
-
- emit q->alertSent(level, tlsAlertType(value), tlsAlertDescription(value));
-}
-
-void QSslSocketBackendPrivate::alertMessageReceived(int value)
-{
- Q_Q(QSslSocket);
-
- emit q->alertReceived(tlsAlertLevel(value), tlsAlertType(value), tlsAlertDescription(value));
-}
-
-int QSslSocketBackendPrivate::emitErrorFromCallback(X509_STORE_CTX *ctx)
-{
- // Returns 0 to abort verification, 1 to continue despite error (as
- // OpenSSL expects from the verification callback).
- Q_Q(QSslSocket);
-
- 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(lcSsl, "Could not obtain the certificate (that failed to verify)");
- return 0;
- }
- const QSslCertificate certificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
-
- const auto errorAndDepth = QSslErrorEntry::fromStoreContext(ctx);
- const QSslError tlsError = _q_OpenSSL_to_QSslError(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 = QSslSocketBackendPrivate::s_indexForSSLExtraData
- + QSslSocketBackendPrivate::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 QSslSocketBackendPrivate::trySendFatalAlert()
-{
- Q_ASSERT(pendingFatalAlert);
-
- 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();
- }
-}
-
-void QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (ssl) {
- if (!shutdown && !q_SSL_in_init(ssl) && !systemOrSslErrorDetected) {
- if (q_SSL_shutdown(ssl) != 1) {
- // Some error may be queued, clear it.
- const auto errors = getErrorsFromOpenSsl();
- Q_UNUSED(errors);
- }
- shutdown = true;
- transmit();
- }
- }
- plainSocket->disconnectFromHost();
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- if (plainSocket->bytesAvailable() <= 0)
- destroySslContext();
- else {
- // Move all bytes into the plain buffer
- qint64 tmpReadBufferMaxSize = readBufferMaxSize;
- readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
- transmit();
- readBufferMaxSize = 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 QSslSocketBackendPrivate::sessionCipher() const
-{
- if (!ssl)
- return QSslCipher();
-
- const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
- return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!ssl)
- return QSsl::UnknownProtocol;
- 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;
-}
-
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
- Q_Q(QSslSocket);
- // if we have a max read buffer size, reset the plain socket's to match
- if (readBufferMaxSize)
- plainSocket->setReadBufferSize(readBufferMaxSize);
-
- if (q_SSL_session_reused(ssl))
- configuration.peerSessionShared = 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), 0, 0);
- size_t client_random_len = q_SSL_get_client_random(ssl, 0, 0);
- QByteArray masterKey(int(master_key_len), 0); // Will not overflow
- QByteArray clientRandom(int(client_random_len), 0); // 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(lcSsl, "could not decrypt SSL traffic");
- }
-#endif
-
- // Cache this SSL session inside the QSslContext
- if (!(configuration.sslOptions & 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.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
- if (!sslContextPointer->sessionASN1().isEmpty())
- configuration.sslSession = sslContextPointer->sessionASN1();
- configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
- }
- }
- }
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-
- configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
- if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
- // we could not agree -> be conservative and use HTTP/1.1
- configuration.nextNegotiatedProtocol = 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 ...
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- }
-
- if (!proto_len) { // Test if NPN was more lucky ...
- q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
- }
-
- if (proto_len)
- configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
- else
- configuration.nextNegotiatedProtocol.clear();
- }
-#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
-
- if (mode == QSslSocket::SslClientMode) {
- EVP_PKEY *key;
- if (q_SSL_get_server_tmp_key(ssl, &key))
- configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
- }
-
- connectionEncrypted = true;
- emit q->encrypted();
- if (autoStartHandshake && pendingClose) {
- pendingClose = false;
- q->disconnectFromHost();
- }
-}
-
-bool QSslSocketPrivate::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(lcSsl, "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();
-
- QSslSocketBackendPrivate::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;
-}
-
-void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
-{
- 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)
- s_loadRootCertsOnDemand = 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 = 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()) {
- s_loadRootCertsOnDemand = true;
- break;
- }
- }
-#endif
-#endif // QT_CONFIG(library)
- // if on-demand loading was not enabled, load the certs now
- if (!s_loadRootCertsOnDemand)
- 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.
- s_loadRootCertsOnDemand = true;
-#endif
-}
-
-QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
-{
- ensureInitialized();
- QList<QSslCertificate> certificates;
- for (int i = 0; i < q_sk_X509_num(x509); ++i) {
- if (X509 *entry = q_sk_X509_value(x509, i))
- certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry);
- }
- return certificates;
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- if (s_loadRootCertsOnDemand)
- setDefaultCaCertificates(defaultCaCertificates() + systemCaCertificates());
-
- return verify(QSslConfiguration::defaultConfiguration().caCertificates(), certificateChain, hostName);
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &caCertificates,
- const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- if (certificateChain.count() <= 0)
- return {QSslError(QSslError::UnspecifiedError)};
-
- QList<QSslError> errors;
- // Setup the store with the default CA certificates
- X509_STORE *certStore = q_X509_STORE_new();
- if (!certStore) {
- qCWarning(lcSsl) << "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(lcSsl) << "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, q_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 (QSslCertificatePrivate::isBlacklisted(certificateChain[0])) {
- QSslError error(QSslError::CertificateBlacklisted, certificateChain[0]);
- errors << error;
- }
-
- // Check the certificate name against the hostname if one was specified
- if ((!hostName.isEmpty()) && (!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 << _q_OpenSSL_to_QSslError(error.code, certificateChain.value(error.depth));
-
- return errors;
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- if (!supportsSsl())
- return false;
-
- // 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());
-
- // Create the PKCS#12 object
- PKCS12 *p12 = q_d2i_PKCS12_bio(bio, nullptr);
- if (!p12) {
- qCWarning(lcSsl, "Unable to read PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_BIO_free(bio);
- return false;
- }
-
- // Extract the data
- EVP_PKEY *pkey = nullptr;
- X509 *x509;
- STACK_OF(X509) *ca = nullptr;
-
- if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) {
- qCWarning(lcSsl, "Unable to parse PKCS#12 structure, %s",
- q_ERR_error_string(q_ERR_get_error(), nullptr));
- q_PKCS12_free(p12);
- q_BIO_free(bio);
- return false;
- }
-
- // Convert to Qt types
- if (!key->d->fromEVP_PKEY(pkey)) {
- qCWarning(lcSsl, "Unable to convert private key");
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return false;
- }
-
- *cert = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
-
- if (caCertificates)
- *caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca);
-
- // Clean up
- q_OPENSSL_sk_pop_free(reinterpret_cast<OPENSSL_STACK *>(ca),
- reinterpret_cast<void (*)(void *)>(q_X509_free));
-
- q_X509_free(x509);
- q_EVP_PKEY_free(pkey);
- q_PKCS12_free(p12);
- q_BIO_free(bio);
-
- return true;
-}
-
-
-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 b5d2458d56..0000000000
--- a/src/network/ssl/qsslsocket_openssl_android.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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_openssl_p.h"
-#include <QtCore/private/qjni_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
-{
- QList<QByteArray> certificateData;
-
- QJNIObjectPrivate certificates = QJNIObjectPrivate::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",
- "getSSLCertificates",
- "()[[B");
- if (!certificates.isValid())
- return certificateData;
-
- QJNIEnvironmentPrivate 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;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
deleted file mode 100644
index b45bbb0a30..0000000000
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ /dev/null
@@ -1,197 +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 <QtCore/qlist.h>
-#include <QtCore/qstring.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
-
-#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>
-
-#if QT_CONFIG(opensslv11)
-#include <openssl/dh.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-struct QSslErrorEntry {
- int code;
- int depth;
-
- static QSslErrorEntry fromStoreContext(X509_STORE_CTX *ctx);
-};
-Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
-
-class QSslSocketBackendPrivate : public QSslSocketPrivate
-{
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- virtual ~QSslSocketBackendPrivate();
-
- // SSL context
- bool initSslContext();
- void destroySslContext();
- SSL *ssl;
- BIO *readBio;
- BIO *writeBio;
- SSL_SESSION *session;
- QList<QSslErrorEntry> errorList;
- static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
- enum ExDataOffset {
- errorOffsetInExData = 1,
- socketOffsetInExData = 2
- };
-
- bool inSetAndEmitError = false;
-
- // Platform specific functions
- void startClientEncryption() override;
- void startServerEncryption() override;
- void transmit() override;
- bool startHandshake();
- void disconnectFromHost() override;
- void disconnected() override;
- QSslCipher sessionCipher() const override;
- QSsl::SslProtocol sessionProtocol() const override;
- void continueHandshake() override;
- bool checkSslErrors();
- void storePeerCertificates();
- int handleNewSessionTicket(SSL *context);
- unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
- unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len);
-#ifdef Q_OS_WIN
- void fetchCaRootForCert(const QSslCertificate &cert);
- void _q_caRootLoaded(QSslCertificate,QSslCertificate) override;
-#endif
-
-#if QT_CONFIG(ocsp)
- bool checkOcspStatus();
-#endif
-
- void alertMessageSent(int encoded);
- void alertMessageReceived(int encoded);
-
- int emitErrorFromCallback(X509_STORE_CTX *ctx);
- void trySendFatalAlert();
-
- bool pendingFatalAlert = false;
- bool errorsReportedFromCallback = false;
-
- // This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
- QString ocspErrorDescription;
- // These will go to sslErrors()
- QList<QSslError> ocspErrors;
- QByteArray ocspResponseDer;
-
- Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
- static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
- static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
- static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
- static QList<QSslError> verify(const QList<QSslCertificate> &cas, const QList<QSslCertificate> &certificateChain,
- const QString &hostName);
- static QString getErrorsFromOpenSsl();
- static void logAndClearErrorQueue();
- static bool importPkcs12(QIODevice *device,
- QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase);
- static QString msgErrorsDuringHandshake();
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
deleted file mode 100644
index 9396516670..0000000000
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ /dev/null
@@ -1,1231 +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/qmemory_p.h>
-#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 = qt_make_unique<QSystemLibrary>(ssleay32LibName);
- if (!ssleay32->load(false)) {
- return FALSE;
- }
-
- auto libeay32 = qt_make_unique<QSystemLibrary>(libeay32LibName);
- if (!libeay32->load(false)) {
- return FALSE;
- }
-
- result.ssl = std::move(ssleay32);
- result.crypto = std::move(libeay32);
- return TRUE;
-}
-
-static LoadedOpenSsl loadOpenSsl()
-{
- LoadedOpenSsl result;
-
- // With OpenSSL 1.1 the names have changed to libssl-1_1(-x64) and libcrypto-1_1(-x64), for builds using
- // MSVC and GCC, (-x64 suffix for 64-bit builds).
-
-#ifdef Q_PROCESSOR_X86_64
-#define QT_SSL_SUFFIX "-x64"
-#else // !Q_PROCESSOFR_X86_64
-#define QT_SSL_SUFFIX
-#endif // !Q_PROCESSOR_x86_64
-
- tryToLoadOpenSslWin32Library(QLatin1String("libssl-1_1" QT_SSL_SUFFIX),
- QLatin1String("libcrypto-1_1" QT_SSL_SUFFIX), result);
-
-#undef QT_SSL_SUFFIX
- return result;
-}
-#else
-
-struct LoadedOpenSsl {
- std::unique_ptr<QLibrary> ssl, crypto;
-};
-
-static LoadedOpenSsl loadOpenSsl()
-{
- LoadedOpenSsl result = {qt_make_unique<QLibrary>(), qt_make_unique<QLibrary>()};
-
-# if defined(Q_OS_UNIX)
- QLibrary * const libssl = result.ssl.get();
- QLibrary * const libcrypto = result.crypto.get();
-
- // Try to find the libssl library on the system.
- //
- // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that
- // is, libssl.so on most Unix systems. However, the .so file isn't present in
- // user installations because it's considered a development file.
- //
- // The right thing to do is to load the library at the major version we know how
- // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h)
- //
- // However, OpenSSL is a well-known case of binary-compatibility breakage. To
- // avoid such problems, many system integrators and Linux distributions change
- // the soname of the binary, letting the full version number be the soname. So
- // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that
- // reason, we will search a few common paths (see findAllLibSsl() above) in hopes
- // we find one that works.
- //
- // If that fails, for OpenSSL 1.0 we also try some fallbacks -- look up
- // libssl.so with a hardcoded soname. The reason is QTBUG-68156: the binary
- // builds of Qt happen (at the time of this writing) on RHEL machines,
- // which change SHLIB_VERSION_NUMBER to a non-portable string. When running
- // those binaries on the target systems, this code won't pick up
- // libssl.so.MODIFIED_SHLIB_VERSION_NUMBER because it doesn't exist there.
- // Given that the only 1.0 supported release (at the time of this writing)
- // is 1.0.2, with soname "1.0.0", give that a try too. Note that we mandate
- // OpenSSL >= 1.0.0 with a configure-time check, and OpenSSL has kept binary
- // compatibility between 1.0.0 and 1.0.2.
- //
- // It is important, however, to try the canonical name and the unversioned name
- // without going through the loop. By not specifying a path, we let the system
- // dlopen(3) function determine it for us. This will include any DT_RUNPATH or
- // DT_RPATH tags on our library header as well as other system-specific search
- // paths. See the man page for dlopen(3) on your system for more information.
-
-#ifdef Q_OS_OPENBSD
- libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
-#endif
-#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
- // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
- libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER));
- libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER));
- if (libcrypto->load() && libssl->load()) {
- // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
- return result;
- } else {
- libssl->unload();
- libcrypto->unload();
- }
-#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 9f54efddaa..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 "qsslsocket_openssl_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(type, st) ((int (*)(const STACK_OF(type) *))q_OPENSSL_sk_num)(st)
-#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_OPENSSL_sk_value)(st, i)
-
-#define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS \
- | OPENSSL_INIT_LOAD_CONFIG, NULL)
-#define q_OPENSSL_add_all_algorithms_noconf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)
-
-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(GENERAL_NAME, (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(X509, (st))
-#define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i))
-#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num(SSL_CIPHER, (st))
-#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
-#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
- q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
-#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
- (char *)(rsa))
-#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
- (char *)(dsa))
-#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
-
-#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 31b8b79302..9dafb36a08 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSSLSOCKET_P_H
@@ -55,55 +19,26 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+
#include <private/qtcpsocket_p.h>
-#include "qsslkey.h"
-#include "qsslconfiguration_p.h"
+
#include "qocspresponse.h"
-#ifndef QT_NO_OPENSSL
-#include <private/qsslcontext_openssl_p.h>
-#else
-class QSslContext;
-#endif
+#include "qsslconfiguration_p.h"
+#include "qsslkey.h"
+#include "qtlsbackend_p.h"
#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qstringlist.h>
-#include <private/qringbuffer_p.h>
-#if defined(Q_OS_MAC)
-#include <Security/SecCertificate.h>
-#include <CoreFoundation/CFArray.h>
-#elif defined(Q_OS_WIN)
-#include <QtCore/qt_windows.h>
#include <memory>
-#include <wincrypt.h>
-#ifndef HCRYPTPROV_LEGACY
-#define HCRYPTPROV_LEGACY HCRYPTPROV
-#endif // !HCRYPTPROV_LEGACY
-#endif // Q_OS_WIN
QT_BEGIN_NAMESPACE
-#if defined(Q_OS_MACOS)
- typedef CFDataRef (*PtrSecCertificateCopyData)(SecCertificateRef);
- typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*);
- typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*);
-#endif
-
-#if defined(Q_OS_WIN)
-
-// Those are needed by both OpenSSL and SChannel back-ends on Windows:
-struct QHCertStoreDeleter {
- void operator()(HCERTSTORE store)
- {
- CertCloseStore(store, 0);
- }
-};
-
-using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
-
-#endif // Q_OS_WIN
+class QSslContext;
+class QTlsBackend;
-class QSslSocketPrivate : public QTcpSocketPrivate
+class Q_NETWORK_EXPORT QSslSocketPrivate : public QTcpSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
public:
@@ -117,14 +52,11 @@ public:
QSslSocket::SslMode mode;
bool autoStartHandshake;
bool connectionEncrypted;
- bool shutdown;
bool ignoreAllSslErrors;
QList<QSslError> ignoreErrorsList;
bool* readyReadEmittedPointer;
QSslConfigurationPrivate configuration;
- QList<QSslError> sslErrors;
- QSharedPointer<QSslContext> sslContextPointer;
// if set, this hostname is used for certificate validation instead of the hostname
// that was used for connecting to.
@@ -135,16 +67,14 @@ public:
static bool s_loadRootCertsOnDemand;
static bool supportsSsl();
- static long sslLibraryVersionNumber();
- static QString sslLibraryVersionString();
- static long sslLibraryBuildVersionNumber();
- static QString sslLibraryBuildVersionString();
static void ensureInitialized();
+
static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> defaultDtlsCiphers();
static QList<QSslCipher> supportedCiphers();
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
- static void resetDefaultCiphers();
static QList<QSslEllipticCurve> supportedEllipticCurves();
static void setDefaultSupportedEllipticCurves(const QList<QSslEllipticCurve> &curves);
@@ -155,19 +85,19 @@ public:
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
static void addDefaultCaCertificate(const QSslCertificate &cert);
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
- Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert,
- const QString &peerName);
- Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
+ static bool isMatchingHostname(const QString &cn, const QString &hostname);
// The socket itself, including private slots.
- QTcpSocket *plainSocket;
+ QTcpSocket *plainSocket = nullptr;
void createPlainSocket(QIODevice::OpenMode openMode);
static void pauseSocketNotifiers(QSslSocket*);
static void resumeSocketNotifiers(QSslSocket*);
// ### The 2 methods below should be made member methods once the QSslContext class is made public
- static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
- static QSharedPointer<QSslContext> sslContext(QSslSocket *socket);
+ static void checkSettingSslContext(QSslSocket*, std::shared_ptr<QSslContext>);
+ static std::shared_ptr<QSslContext> sslContext(QSslSocket *socket);
bool isPaused() const;
+ void setPaused(bool p);
bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) override;
void _q_connectedSlot();
void _q_hostFoundSlot();
@@ -182,52 +112,57 @@ public:
void _q_flushWriteBuffer();
void _q_flushReadBuffer();
void _q_resumeImplementation();
-#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
- virtual void _q_caRootLoaded(QSslCertificate,QSslCertificate) = 0;
-#endif
static QList<QByteArray> unixRootCertDirectories(); // used also by QSslContext
- virtual qint64 peek(char *data, qint64 maxSize) override;
- virtual QByteArray peek(qint64 maxSize) override;
+ qint64 peek(char *data, qint64 maxSize) override;
+ QByteArray peek(qint64 maxSize) override;
bool flush() override;
- // Platform specific functions
- virtual void startClientEncryption() = 0;
- virtual void startServerEncryption() = 0;
- virtual void transmit() = 0;
- virtual void disconnectFromHost() = 0;
- virtual void disconnected() = 0;
- virtual QSslCipher sessionCipher() const = 0;
- virtual QSsl::SslProtocol sessionProtocol() const = 0;
- virtual void continueHandshake() = 0;
-
- Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
-
-private:
- static bool ensureLibraryLoaded();
- static void ensureCiphersAndCertsLoaded();
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
- static QList<QByteArray> fetchSslCertificateData();
-#endif
+ void startClientEncryption();
+ void startServerEncryption();
+ void transmit();
+ void disconnectFromHost();
+ void disconnected();
+ QSslCipher sessionCipher() const;
+ QSsl::SslProtocol sessionProtocol() const;
+ void continueHandshake();
+
+ static bool rootCertOnDemandLoadingSupported();
+ static void setRootCertOnDemandLoadingSupported(bool supported);
+
+ static QTlsBackend *tlsBackendInUse();
+
+ // Needed by TlsCryptograph:
+ QSslSocket::SslMode tlsMode() const;
+ bool isRootsOnDemandAllowed() const;
+ QString verificationName() const;
+ QString tlsHostName() const;
+ QTcpSocket *plainTcpSocket() const;
+ bool verifyErrorsHaveBeenIgnored();
+ bool isAutoStartingHandshake() const;
+ bool isPendingClose() const;
+ void setPendingClose(bool pc);
+ qint64 maxReadBufferSize() const;
+ void setMaxReadBufferSize(qint64 maxSize);
+ void setEncrypted(bool enc);
+ QRingBufferRef &tlsWriteBuffer();
+ QRingBufferRef &tlsBuffer();
+ bool &tlsEmittedBytesWritten();
+ bool *readyReadPointer();
- static bool s_libraryLoaded;
- static bool s_loadedCiphersAndCerts;
protected:
- bool verifyErrorsHaveBeenIgnored();
+
+ bool hasUndecryptedData() const;
bool paused;
bool flushTriggered;
- bool systemOrSslErrorDetected = false;
- QList<QOcspResponse> ocspResponses;
- bool handshakeInterrupted = false;
- bool fetchAuthorityInformation = false;
- QSslCertificate caToFetch;
-};
-#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
-// Implemented in qsslsocket_qt.cpp
-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase);
-#endif
+ static inline QMutex backendMutex;
+ static inline QString activeBackendName;
+ static inline QTlsBackend *tlsBackend = nullptr;
+
+ std::unique_ptr<QTlsPrivate::TlsCryptograph> backend;
+};
QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_qt.cpp b/src/network/ssl/qsslsocket_qt.cpp
deleted file mode 100644
index a5d21bd77e..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(QSslKeyPrivate::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/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
deleted file mode 100644
index f0a9f6a027..0000000000
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ /dev/null
@@ -1,2064 +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$
-**
-****************************************************************************/
-
-// #define QSSLSOCKET_DEBUG
-
-#include "qssl_p.h"
-#include "qsslsocket.h"
-#include "qsslsocket_schannel_p.h"
-#include "qsslcertificate.h"
-#include "qsslcertificateextension.h"
-#include "qsslcertificate_p.h"
-#include "qsslcipher_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
-
-// 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
-
-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);
- }
-}
-
-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;
- // @future Add TLS 1.3 when supported by Windows!
- 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 ((false)) // @future[0/1] Replace with version check once it's supported in Windows
- 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 ((false)) // @future[1/1] Also replace this with a version check
- 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;
-}
-
-/*!
- \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
-
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
-bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
-Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
-
-void QSslSocketPrivate::ensureInitialized()
-{
- const QMutexLocker locker(qt_schannel_mutex);
- if (s_loadedCiphersAndCerts)
- return;
- s_loadedCiphersAndCerts = true;
-
- setDefaultCaCertificates(systemCaCertificates());
- s_loadRootCertsOnDemand = true; // setDefaultCaCertificates sets it to false, re-enable it.
-
- resetDefaultCiphers();
-}
-
-void QSslSocketPrivate::resetDefaultCiphers()
-{
- setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
- setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
-}
-
-void QSslSocketPrivate::resetDefaultEllipticCurves()
-{
- Q_UNIMPLEMENTED();
-}
-
-bool QSslSocketPrivate::supportsSsl()
-{
- return true;
-}
-
-QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
-{
- // Copied from qsslsocket_openssl.cpp's 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(QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(pc));
- }
- }
- return systemCerts;
-}
-
-long QSslSocketPrivate::sslLibraryVersionNumber()
-{
- const auto os = QOperatingSystemVersion::current();
- return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
-}
-
-QString QSslSocketPrivate::sslLibraryVersionString()
-{
- 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 QSslSocketPrivate::sslLibraryBuildVersionNumber()
-{
- // There is no separate build version
- return sslLibraryVersionNumber();
-}
-
-QString QSslSocketPrivate::sslLibraryBuildVersionString()
-{
- const auto os = QOperatingSystemVersion::current();
- return QString::fromLatin1("%1.%2.%3")
- .arg(QString::number(os.majorVersion()),
- QString::number(os.minorVersion()),
- QString::number(os.microVersion()));
-}
-
-QSslSocketBackendPrivate::QSslSocketBackendPrivate()
-{
- SecInvalidateHandle(&credentialHandle);
- SecInvalidateHandle(&contextHandle);
- ensureInitialized();
-}
-
-QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
-{
- closeCertificateStores();
- deallocateContext();
- freeCredentialsHandle();
- CertFreeCertificateContext(localCertContext);
-}
-
-bool QSslSocketBackendPrivate::sendToken(void *token, unsigned long tokenLength, bool emitError)
-{
- if (tokenLength == 0)
- return true;
- 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)
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return false;
- }
- return true;
-}
-
-QString QSslSocketBackendPrivate::targetName() const
-{
- // Used for SNI extension
- return verificationPeerName.isEmpty() ? q_func()->peerName() : verificationPeerName;
-}
-
-ULONG QSslSocketBackendPrivate::getContextRequirements()
-{
- const bool isClient = mode == 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 (configuration.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 QSslSocketBackendPrivate::acquireCredentialsHandle()
-{
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
-
- const bool isClient = mode == QSslSocket::SslClientMode;
- const DWORD protocols = toSchannelProtocol(configuration.protocol);
- if (protocols == DWORD(-1)) {
- 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.");
- 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);
- }
-
- SCHANNEL_CRED 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) @future: QSslCipher-related
-
- 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)
- };
-
- 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)
- &cred, // pAuthData
- nullptr, // pGetKeyFn (unused)
- nullptr, // pvGetKeyArgument (unused)
- &credentialHandle, // phCredential
- &expiration // ptsExpir
- );
-
- if (status != SEC_E_OK) {
- setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
- return false;
- }
- return true;
-}
-
-void QSslSocketBackendPrivate::deallocateContext()
-{
- if (SecIsValidHandle(&contextHandle)) {
- DeleteSecurityContext(&contextHandle);
- SecInvalidateHandle(&contextHandle);
- }
-}
-
-void QSslSocketBackendPrivate::freeCredentialsHandle()
-{
- if (SecIsValidHandle(&credentialHandle)) {
- FreeCredentialsHandle(&credentialHandle);
- SecInvalidateHandle(&credentialHandle);
- }
-}
-
-void QSslSocketBackendPrivate::closeCertificateStores()
-{
- localCertificateStore.reset();
- peerCertificateStore.reset();
- caCertificateStore.reset();
-}
-
-bool QSslSocketBackendPrivate::createContext()
-{
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(mode == 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
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
- 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) {
- 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 QSslSocketBackendPrivate::acceptContext()
-{
- Q_ASSERT(SecIsValidHandle(&credentialHandle));
- Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
- Q_ASSERT(mode == 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
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
- // The string must be alive when we call AcceptSecurityContext
- QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
- 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) {
- 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 QSslSocketBackendPrivate::performHandshake()
-{
- if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
- 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.
- 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
- 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:
- 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)
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
- return false;
-}
-
-bool QSslSocketBackendPrivate::verifyHandshake()
-{
- Q_Q(QSslSocket);
- sslErrors.clear();
-
- const bool isClient = mode == QSslSocket::SslClientMode;
-#define CHECK_STATUS(status) \
- if (status != SEC_E_OK) { \
- 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)) {
- 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
- if (!configuration.nextAllowedProtocols.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 (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- QSslSocket::tr("Unwanted protocol was negotiated"));
- return false;
- }
- configuration.nextNegotiatedProtocol = negotiatedProto;
- configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
- } else {
- configuration.nextNegotiatedProtocol = "";
- configuration.nextProtocolNegotiationStatus = 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() || 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 paused && state == QAbstractSocket::ConnectedState;
- }
-
- schannelState = SchannelState::Done;
- return true;
-}
-
-bool QSslSocketBackendPrivate::renegotiate()
-{
- 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 (mode == 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);
- }
- 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 QSslSocketBackendPrivate::reset()
-{
- 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;
-
- connectionEncrypted = false;
- shutdown = false;
- renegotiating = false;
-
- missingData = 0;
-}
-
-void QSslSocketBackendPrivate::startClientEncryption()
-{
- if (connectionEncrypted)
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void QSslSocketBackendPrivate::startServerEncryption()
-{
- if (connectionEncrypted)
- return; // let's not mess up the connection...
- reset();
- continueHandshake();
-}
-
-void QSslSocketBackendPrivate::transmit()
-{
- Q_Q(QSslSocket);
-
- // 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;
- }
-
- if (connectionEncrypted) { // 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) {
- 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 {
- setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
- return;
- }
- }
-
- if (totalBytesWritten > 0) {
- // Don't emit bytesWritten() recursively.
- if (!emittedBytesWritten) {
- emittedBytesWritten = true;
- emit q->bytesWritten(totalBytesWritten);
- emittedBytesWritten = false;
- }
- emit q->channelBytesWritten(0, totalBytesWritten);
- }
- }
-
- if (connectionEncrypted) { // Decrypt data from remote
- int totalRead = 0;
- bool hadIncompleteData = false;
- 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();
- 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();
- setErrorAndEmit(QAbstractSocket::SslInternalError,
- schannelErrorToString(status));
- break;
- } else if (status == SEC_I_CONTEXT_EXPIRED) {
- // 'remote' has initiated a shutdown
- disconnectFromHost();
- 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 (readyReadEmittedPointer)
- *readyReadEmittedPointer = true;
- emit q->readyRead();
- emit q->channelReadyRead(0);
- }
- }
-}
-
-void QSslSocketBackendPrivate::sendShutdown()
-{
- const bool isClient = mode == QSslSocket::SslClientMode;
- DWORD shutdownToken = SCHANNEL_SHUTDOWN;
- SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(SCHANNEL_SHUTDOWN), 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 QSslSocketBackendPrivate::disconnectFromHost()
-{
- if (SecIsValidHandle(&contextHandle)) {
- if (!shutdown) {
- shutdown = true;
- if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
- if (connectionEncrypted) {
- // Read as much as possible because this is likely our last chance
- qint64 tempMax = readBufferMaxSize;
- readBufferMaxSize = 0;
- transmit();
- readBufferMaxSize = tempMax;
- sendShutdown();
- }
- }
- }
- }
- if (plainSocket->state() != QAbstractSocket::UnconnectedState)
- plainSocket->disconnectFromHost();
-}
-
-void QSslSocketBackendPrivate::disconnected()
-{
- shutdown = true;
- connectionEncrypted = false;
- deallocateContext();
- freeCredentialsHandle();
-}
-
-QSslCipher QSslSocketBackendPrivate::sessionCipher() const
-{
- if (!connectionEncrypted)
- return QSslCipher();
- return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
-}
-
-QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
-{
- if (!connectionEncrypted)
- return QSsl::SslProtocol::UnknownProtocol;
- return toQtSslProtocol(connectionInfo.dwProtocol);
-}
-
-void QSslSocketBackendPrivate::continueHandshake()
-{
- Q_Q(QSslSocket);
- const bool isServer = mode == 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 (!connectionEncrypted) {
- connectionEncrypted = true; // all is done
- emit q->encrypted();
- }
- renegotiating = false;
- if (pendingClose) {
- pendingClose = false;
- disconnectFromHost();
- } else {
- transmit();
- }
- break;
- case SchannelState::Renegotiate:
- if (!renegotiate()) {
- disconnectFromHost();
- return;
- }
- break;
- }
-}
-
-QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
-{
- 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) {
- QSslCipher cipher;
- cipher.d->isNull = false;
- cipher.d->name = QStringLiteral("Schannel");
- cipher.d->protocol = protocols[i];
- cipher.d->protocolString = protocolStrings[i];
- ciphers.append(cipher);
- }
-
- return ciphers;
-}
-
-QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName)
-{
- Q_UNUSED(certificateChain);
- Q_UNUSED(hostName);
-
- Q_UNIMPLEMENTED();
- return {}; // @future implement(?)
-}
-
-bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates,
- const QByteArray &passPhrase)
-{
- Q_UNUSED(device);
- Q_UNUSED(key);
- Q_UNUSED(cert);
- Q_UNUSED(caCertificates);
- Q_UNUSED(passPhrase);
- // @future: can load into its own certificate store (encountered problems extracting key).
- Q_UNIMPLEMENTED();
- return false;
-}
-
-/*
- Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
-*/
-bool QSslSocketBackendPrivate::checkSslErrors()
-{
- if (sslErrors.isEmpty())
- return true;
- Q_Q(QSslSocket);
-
- emit q->sslErrors(sslErrors);
-
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && mode == QSslSocket::SslClientMode);
- const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
- // check whether we need to emit an SSL handshake error
- if (doVerifyPeer && doEmitSslError) {
- if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
- pauseSocketNotifiers(q);
- paused = true;
- } else {
- setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
- sslErrors.constFirst().errorString());
- plainSocket->disconnectFromHost();
- }
- return false;
- }
-
- return true;
-}
-
-void QSslSocketBackendPrivate::initializeCertificateStores()
-{
- //// helper function which turns a chain into a certificate store
- 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()) {
- 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 QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
-{
- Q_ASSERT(certContext);
- Q_Q(QSslSocket);
-
- const bool isClient = mode == 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;
-
- configuration.peerCertificate.clear();
- configuration.peerCertificateChain.clear();
- 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 QSslCertificatePrivate::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 (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
- verifyDepth = DWORD(configuration.peerVerifyDepth);
-
- 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(lcSsl) << "issuer:" << certificate.issuerDisplayName()
- << "\nsubject:" << certificate.subjectDisplayName()
- << "\nQSslCertificate info:" << certificate
- << "\nextended error info:" << element->pwszExtendedErrorInfo
- << "\nerror status:" << element->TrustStatus.dwErrorStatus;
-#endif
-
- configuration.peerCertificateChain.append(certificate);
-
- 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 = configuration.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 (!configuration.peerCertificateChain.isEmpty())
- configuration.peerCertificate = configuration.peerCertificateChain.first();
-
- // @Note: Somewhat copied from qsslsocket_mac.cpp
- const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
- || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
- && 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.
- 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 (mode == QSslSocket::SslClientMode) {
- 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 QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
-{
- return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_schannel_p.h b/src/network/ssl/qsslsocket_schannel_p.h
deleted file mode 100644
index fe29dadec0..0000000000
--- a/src/network/ssl/qsslsocket_schannel_p.h
+++ /dev/null
@@ -1,145 +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 QSSLSOCKET_SCHANNEL_P_H
-#define QSSLSOCKET_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.
-//
-
-QT_REQUIRE_CONFIG(schannel);
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-
-#include "qsslsocket_p.h"
-
-#define SECURITY_WIN32
-#include <security.h>
-#include <schnlsp.h>
-#undef SECURITY_WIN32
-
-QT_BEGIN_NAMESPACE
-
-class QSslSocketBackendPrivate final : public QSslSocketPrivate
-{
- Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
- Q_DECLARE_PUBLIC(QSslSocket)
-public:
- QSslSocketBackendPrivate();
- ~QSslSocketBackendPrivate();
-
- // Platform specific functions
- 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;
-
- static QList<QSslCipher> defaultCiphers();
- static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain,
- const QString &hostName);
- static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
- QList<QSslCertificate> *caCertificates, const QByteArray &passPhrase);
-
-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();
-
- 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;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSSLSOCKET_SCHANNEL_P_H
diff --git a/src/network/ssl/qtls_utils_p.h b/src/network/ssl/qtls_utils_p.h
deleted file mode 100644
index ceca3030d6..0000000000
--- a/src/network/ssl/qtls_utils_p.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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_UTILS_P_H
-#define QTLS_UTILS_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>
-
-#if QT_CONFIG(openssl)
-#include <QtNetwork/private/qsslsocket_openssl_p.h>
-#endif
-
-#include <QtNetwork/private/qssl_p.h>
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qdebug.h>
-
-#include <memory>
-
-QT_BEGIN_NAMESPACE
-
-namespace QTlslUtils
-{
-
-template <class NativeTlsType, void (*Deleter)(NativeTlsType *)>
-void safe_delete(NativeTlsType *object)
-{
- static_assert (Deleter, "safe_delete: invalid (nullptr) function pointer provided");
-
- if (object)
- Deleter(object);
-}
-
-template<class NativeTlsType, int ok, int (*Deleter)(NativeTlsType *)>
-void safe_delete(NativeTlsType *object)
-{
- static_assert (Deleter, "safe_delete: invalid (nullptr) function pointer provided");
-
- if (object) {
- if (Deleter(object) != ok) {
- qCWarning(lcSsl, "Failed to free a resource.");
-#if QT_CONFIG(openssl) // || wolfssl later
- QSslSocketBackendPrivate::logAndClearErrorQueue();
-#endif // QT_CONFIG(openssl)
- }
- }
-}
-
-template<class NativeTlsType>
-using Deleter = std::unique_ptr<NativeTlsType, void (*)(NativeTlsType *)>;
-
-} // namespace QTlsUtils
-
-QT_END_NAMESPACE
-
-#endif // QTLS_UTILS_P_H
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
new file mode 100644
index 0000000000..761ab33fbe
--- /dev/null
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -0,0 +1,2357 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtlsbackend_p.h"
+
+#if QT_CONFIG(ssl)
+#include "qsslpresharedkeyauthenticator_p.h"
+#include "qsslpresharedkeyauthenticator.h"
+#include "qsslsocket_p.h"
+#include "qsslcipher_p.h"
+#include "qsslkey_p.h"
+#include "qsslkey.h"
+#endif
+
+#include "qssl_p.h"
+
+#include <QtCore/private/qfactoryloader_p.h>
+
+#include "QtCore/qapplicationstatic.h"
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmutex.h>
+
+#include <algorithm>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_APPLICATION_STATIC(QFactoryLoader, qtlsbLoader, QTlsBackend_iid,
+ QStringLiteral("/tls"))
+
+namespace {
+
+class BackendCollection
+{
+public:
+ void addBackend(QTlsBackend *backend)
+ {
+ Q_ASSERT(backend);
+ Q_ASSERT(std::find(backends.begin(), backends.end(), backend) == backends.end());
+ const QMutexLocker locker(&collectionMutex);
+ backends.push_back(backend);
+ }
+
+ void removeBackend(QTlsBackend *backend)
+ {
+ Q_ASSERT(backend);
+ const QMutexLocker locker(&collectionMutex);
+ const auto it = std::find(backends.begin(), backends.end(), backend);
+ Q_ASSERT(it != backends.end());
+ backends.erase(it);
+ }
+
+ bool tryPopulateCollection()
+ {
+ if (!qtlsbLoader())
+ return false;
+
+ Q_CONSTINIT static QBasicMutex mutex;
+ const QMutexLocker locker(&mutex);
+ if (backends.size())
+ return true;
+
+#if QT_CONFIG(library)
+ qtlsbLoader->update();
+#endif
+ int index = 0;
+ while (qtlsbLoader->instance(index))
+ ++index;
+
+ return true;
+ }
+
+ QList<QString> backendNames()
+ {
+ QList<QString> names;
+ if (!tryPopulateCollection())
+ return names;
+
+ const QMutexLocker locker(&collectionMutex);
+ if (!backends.size())
+ return names;
+
+ names.reserve(backends.size());
+ for (const auto *backend : backends) {
+ if (backend->isValid())
+ names.append(backend->backendName());
+ }
+
+ return names;
+ }
+
+ QTlsBackend *backend(const QString &name)
+ {
+ if (!tryPopulateCollection())
+ return nullptr;
+
+ const QMutexLocker locker(&collectionMutex);
+ const auto it = std::find_if(backends.begin(), backends.end(),
+ [&name](const auto *fct) {return fct->backendName() == name;});
+
+ return it == backends.end() ? nullptr : *it;
+ }
+
+private:
+ std::vector<QTlsBackend *> backends;
+ QMutex collectionMutex;
+};
+
+} // Unnamed namespace
+
+Q_GLOBAL_STATIC(BackendCollection, backends);
+
+/*!
+ \class QTlsBackend
+ \internal (Network-private)
+ \brief QTlsBackend is a factory class, providing implementations
+ for the QSsl classes.
+
+ The purpose of QTlsBackend is to enable and simplify the addition
+ of new TLS backends to be used by QSslSocket and related classes.
+ Starting from Qt 6.1, these backends have plugin-based design (and
+ thus can co-exist simultaneously, unlike pre 6.1 times), although
+ any given run of a program can only use one of them.
+
+ Inheriting from QTlsBackend and creating an object of such
+ a class adds a new backend into the list of available TLS backends.
+
+ A new backend must provide a list of classes, features and protocols
+ it supports, and override the corresponding virtual functions that
+ create backend-specific implementations for these QSsl-classes.
+
+ The base abstract class - QTlsBackend - provides, where possible,
+ default implementations of its virtual member functions. These
+ default implementations can be overridden by a derived backend
+ class, if needed.
+
+ QTlsBackend also provides some auxiliary functions that a derived
+ backend class can use to interact with the internals of network-private classes.
+
+ \sa QSslSocket::availableBackends(), supportedFeatures(), supportedProtocols(), implementedClasses()
+*/
+
+/*!
+ \fn QString QTlsBackend::backendName() const
+ \internal
+ Returns the name of this backend. The name will be reported by QSslSocket::availableBackends().
+ Example of backend names: "openssl", "schannel", "securetransport".
+
+ \sa QSslSocket::availableBackends(), isValid()
+*/
+
+const QString QTlsBackend::builtinBackendNames[] = {
+ QStringLiteral("schannel"),
+ QStringLiteral("securetransport"),
+ QStringLiteral("openssl"),
+ QStringLiteral("cert-only")
+};
+
+/*!
+ \internal
+ The default constructor, adds a new backend to the list of available backends.
+
+ \sa ~QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends()
+*/
+QTlsBackend::QTlsBackend()
+{
+ if (backends())
+ backends->addBackend(this);
+
+ if (QCoreApplication::instance()) {
+ connect(QCoreApplication::instance(), &QCoreApplication::destroyed, this, [this] {
+ delete this;
+ });
+ }
+}
+
+/*!
+ \internal
+ Removes this backend from the list of available backends.
+
+ \sa QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends()
+*/
+QTlsBackend::~QTlsBackend()
+{
+ if (backends())
+ backends->removeBackend(this);
+}
+
+/*!
+ \internal
+ Returns \c true if this backend was initialised successfully. The default implementation
+ always returns \c true.
+
+ \note This function must be overridden if a particular backend has a non-trivial initialization
+ that can fail. If reimplemented, returning \c false will exclude this backend from the list of
+ backends, reported as available by QSslSocket.
+
+ \sa QSslSocket::availableBackends()
+*/
+
+bool QTlsBackend::isValid() const
+{
+ return true;
+}
+
+/*!
+ \internal
+ Returns an implementations-specific integer value, representing the TLS library's
+ version, that is currently used by this backend (i.e. runtime library version).
+ The default implementation returns 0.
+
+ \sa tlsLibraryBuildVersionNumber()
+*/
+long QTlsBackend::tlsLibraryVersionNumber() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific string, representing the TLS library's version,
+ that is currently used by this backend (i.e. runtime library version). The default
+ implementation returns an empty string.
+
+ \sa tlsLibraryBuildVersionString()
+*/
+
+QString QTlsBackend::tlsLibraryVersionString() const
+{
+ return {};
+}
+
+/*!
+ \internal
+ Returns an implementation-specific integer value, representing the TLS library's
+ version that this backend was built against (i.e. compile-time library version).
+ The default implementation returns 0.
+
+ \sa tlsLibraryVersionNumber()
+*/
+
+long QTlsBackend::tlsLibraryBuildVersionNumber() const
+{
+ return 0;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific string, representing the TLS library's version
+ that this backend was built against (i.e. compile-time version). The default
+ implementation returns an empty string.
+
+ \sa tlsLibraryVersionString()
+*/
+QString QTlsBackend::tlsLibraryBuildVersionString() const
+{
+ return {};
+}
+
+/*!
+ \internal
+ QSslSocket and related classes call this function to ensure that backend's internal
+ resources - e.g. CA certificates, or ciphersuites - were properly initialized.
+*/
+void QTlsBackend::ensureInitialized() const
+{
+}
+
+#define REPORT_MISSING_SUPPORT(message) \
+ qCWarning(lcSsl) << "The backend" << backendName() << message
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Key is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance
+ of an implementation-specific type, inheriting from the class QTlsPrivate::TlsKey.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslKey, implementedClasses(), QTlsPrivate::TlsKey
+*/
+QTlsPrivate::TlsKey *QTlsBackend::createKey() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslKey");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Certificate is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::X509Certificate.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslCertificate, QTlsPrivate::X509Certificate, implementedClasses()
+*/
+QTlsPrivate::X509Certificate *QTlsBackend::createCertificate() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslCertificate");
+ return nullptr;
+}
+
+/*!
+ \internal
+ This function returns a list of system CA certificates - e.g. certificates, loaded
+ from a system store, if available. This function allows implementation of the class
+ QSslConfiguration. The default implementation of this function returns an empty list.
+
+ \sa QSslCertificate, QSslConfiguration
+*/
+QList<QSslCertificate> QTlsBackend::systemCaCertificates() const
+{
+ REPORT_MISSING_SUPPORT("does not provide system CA certificates");
+ return {};
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Socket is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::TlsCryptograph.
+ The default implementation of this function returns \nullptr.
+
+ \sa QSslSocket, QTlsPrivate::TlsCryptograph, implementedClasses()
+*/
+QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslSocket");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::Dtls is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::DtlsCryptograph.
+ The default implementation of this function returns \nullptr.
+
+ \sa QDtls, QTlsPrivate::DtlsCryptograph, implementedClasses()
+*/
+QTlsPrivate::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mode) const
+{
+ Q_UNUSED(qObject);
+ Q_UNUSED(mode);
+ REPORT_MISSING_SUPPORT("does not support QDtls");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::DtlsCookie is present in this backend's implementedClasses(),
+ the backend must reimplement this method to return a dynamically-allocated instance of an
+ implementation-specific type, inheriting from the class QTlsPrivate::DtlsCookieVerifier. The
+ default implementation returns \nullptr.
+
+ \sa QDtlsClientVerifier, QTlsPrivate::DtlsCookieVerifier, implementedClasses()
+*/
+QTlsPrivate::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const
+{
+ REPORT_MISSING_SUPPORT("does not support DTLS cookies");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::SupportedFeature::CertificateVerification is present in this backend's
+ supportedFeatures(), the backend must reimplement this method to return a pointer
+ to a function, that checks a certificate (or a chain of certificates) against available
+ CA certificates. The default implementation returns \nullptr.
+
+ \sa supportedFeatures(), QSslCertificate
+*/
+
+QTlsPrivate::X509ChainVerifyPtr QTlsBackend::X509Verifier() const
+{
+ REPORT_MISSING_SUPPORT("does not support (manual) certificate verification");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that reads certificates in PEM format. The
+ default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509PemReaderPtr QTlsBackend::X509PemReader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read PEM format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that can read certificates in DER format.
+ The default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509DerReaderPtr QTlsBackend::X509DerReader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read DER format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns a pointer to function, that can read certificates in PKCS 12 format.
+ The default implementation returns \nullptr.
+
+ \sa QSslCertificate
+*/
+QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const
+{
+ REPORT_MISSING_SUPPORT("cannot read PKCS12 format");
+ return nullptr;
+}
+
+/*!
+ \internal
+ If QSsl::ImplementedClass::EllipticCurve is present in this backend's implementedClasses(),
+ and the backend provides information about supported curves, it must reimplement this
+ method to return a list of unique identifiers of the supported elliptic curves. The default
+ implementation returns an empty list.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa implemenedClasses(), QSslEllipticCurve
+*/
+QList<int> QTlsBackend::ellipticCurvesIds() const
+{
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves, this
+ function should return a unique integer identifier for a curve named \a name,
+ which is a conventional short name for the curve. The default implementation
+ returns 0.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa QSslEllipticCurve::shortName()
+*/
+int QTlsBackend::curveIdFromShortName(const QString &name) const
+{
+ Q_UNUSED(name);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return 0;
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves, this
+ function should return a unique integer identifier for a curve named \a name,
+ which is a conventional long name for the curve. The default implementation
+ returns 0.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa QSslElliptiCurve::longName()
+*/
+int QTlsBackend::curveIdFromLongName(const QString &name) const
+{
+ Q_UNUSED(name);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return 0;
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves,
+ this function should return a conventional short name for a curve identified
+ by \a cid. The default implementation returns an empty string.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa ellipticCurvesIds(), QSslEllipticCurve::shortName()
+*/
+QString QTlsBackend::shortNameForId(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend provides information about available elliptic curves,
+ this function should return a conventional long name for a curve identified
+ by \a cid. The default implementation returns an empty string.
+
+ \note The meaning of a curve identifier is implementation-specific.
+
+ \sa ellipticCurvesIds(), QSslEllipticCurve::shortName()
+*/
+QString QTlsBackend::longNameForId(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return {};
+}
+
+/*!
+ \internal
+ Returns true if the elliptic curve identified by \a cid is one of the named
+ curves, that can be used in the key exchange when using an elliptic curve
+ cipher with TLS; false otherwise. The default implementation returns false.
+
+ \note The meaning of curve identifier is implementation-specific.
+*/
+bool QTlsBackend::isTlsNamedCurve(int cid) const
+{
+ Q_UNUSED(cid);
+ REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve");
+ return false;
+}
+
+/*!
+ \internal
+ If this backend supports the class QSslDiffieHellmanParameters, this function is
+ needed for construction of a QSslDiffieHellmanParameters from DER encoded data.
+ This function is expected to return a value that matches an enumerator in
+ QSslDiffieHellmanParameters::Error enumeration. The default implementation of this
+ function returns 0 (equals to QSslDiffieHellmanParameters::NoError).
+
+ \sa QSslDiffieHellmanParameters, implementedClasses()
+*/
+int QTlsBackend::dhParametersFromDer(const QByteArray &derData, QByteArray *data) const
+{
+ Q_UNUSED(derData);
+ Q_UNUSED(data);
+ REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in DER format");
+ return {};
+}
+
+/*!
+ \internal
+ If this backend supports the class QSslDiffieHellmanParameters, this function is
+ is needed for construction of a QSslDiffieHellmanParameters from PEM encoded data.
+ This function is expected to return a value that matches an enumerator in
+ QSslDiffieHellmanParameters::Error enumeration. The default implementation of this
+ function returns 0 (equals to QSslDiffieHellmanParameters::NoError).
+
+ \sa QSslDiffieHellmanParameters, implementedClasses()
+*/
+int QTlsBackend::dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const
+{
+ Q_UNUSED(pemData);
+ Q_UNUSED(data);
+ REPORT_MISSING_SUPPORT("does not support QSslDiffieHellmanParameters in PEM format");
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of names of available backends.
+
+ \note This list contains only properly initialized backends.
+
+ \sa QTlsBackend(), isValid()
+*/
+QList<QString> QTlsBackend::availableBackendNames()
+{
+ if (!backends())
+ return {};
+
+ return backends->backendNames();
+}
+
+/*!
+ \internal
+ Returns the name of the backend that QSslSocket() would use by default. If no
+ backend was found, the function returns an empty string.
+*/
+QString QTlsBackend::defaultBackendName()
+{
+ // We prefer OpenSSL as default:
+ const auto names = availableBackendNames();
+ auto name = builtinBackendNames[nameIndexOpenSSL];
+ if (names.contains(name))
+ return name;
+ name = builtinBackendNames[nameIndexSchannel];
+ if (names.contains(name))
+ return name;
+ 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];
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a backend named \a backendName, if it exists.
+ Otherwise, it returns \nullptr.
+
+ \sa backendName(), QSslSocket::availableBackends()
+*/
+QTlsBackend *QTlsBackend::findBackend(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (auto *fct = backends->backend(backendName))
+ return fct;
+
+ qCWarning(lcSsl) << "Cannot create unknown backend named" << backendName;
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns the backend that QSslSocket is using. If Qt was built without TLS support,
+ this function returns a minimal backend that only supports QSslCertificate.
+
+ \sa defaultBackend()
+*/
+QTlsBackend *QTlsBackend::activeOrAnyBackend()
+{
+#if QT_CONFIG(ssl)
+ return QSslSocketPrivate::tlsBackendInUse();
+#else
+ return findBackend(defaultBackendName());
+#endif // QT_CONFIG(ssl)
+}
+
+/*!
+ \internal
+ Returns a list of TLS and DTLS protocol versions, that a backend named
+ \a backendName supports.
+
+ \note This list is supposed to also include range-based versions, which
+ allows negotiation of protocols during the handshake, so that these versions
+ can be used when configuring QSslSocket (e.g. QSsl::TlsV1_2OrLater).
+
+ \sa QSsl::SslProtocol
+*/
+QList<QSsl::SslProtocol> QTlsBackend::supportedProtocols(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->supportedProtocols();
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of features that a backend named \a backendName supports. E.g.
+ a backend may support PSK (pre-shared keys, defined as QSsl::SupportedFeature::Psk)
+ or ALPN (application layer protocol negotiation, identified by
+ QSsl::SupportedFeature::ClientSideAlpn or QSsl::SupportedFeature::ServerSideAlpn).
+
+ \sa QSsl::SupportedFeature
+*/
+QList<QSsl::SupportedFeature> QTlsBackend::supportedFeatures(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->supportedFeatures();
+
+ return {};
+}
+
+/*!
+ \internal
+ Returns a list of classes that a backend named \a backendName supports. E.g. a backend
+ may implement QSslSocket (QSsl::ImplementedClass::Socket), and QDtls
+ (QSsl::ImplementedClass::Dtls).
+
+ \sa QSsl::ImplementedClass
+*/
+QList<QSsl::ImplementedClass> QTlsBackend::implementedClasses(const QString &backendName)
+{
+ if (!backends())
+ return {};
+
+ if (const auto *fct = backends->backend(backendName))
+ return fct->implementedClasses();
+
+ return {};
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes \a key to use \a keyBackend.
+*/
+void QTlsBackend::resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend)
+{
+#if QT_CONFIG(ssl)
+ key.d->backend.reset(keyBackend);
+#else
+ Q_UNUSED(key);
+ Q_UNUSED(keyBackend);
+#endif // QT_CONFIG(ssl)
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes client-side \a auth using the \a hint, \a hintLength,
+ \a maxIdentityLength and \a maxPskLen.
+*/
+void QTlsBackend::setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint,
+ int hintLength, unsigned maxIdentityLen, unsigned maxPskLen)
+{
+ Q_ASSERT(auth);
+#if QT_CONFIG(ssl)
+ if (hint)
+ auth->d->identityHint = QByteArray::fromRawData(hint, hintLength); // it's NUL terminated, but do not include the NUL
+
+ auth->d->maximumIdentityLength = int(maxIdentityLen) - 1; // needs to be NUL terminated
+ auth->d->maximumPreSharedKeyLength = int(maxPskLen);
+#else
+ Q_UNUSED(auth);
+ Q_UNUSED(hint);
+ Q_UNUSED(hintLength);
+ Q_UNUSED(maxIdentityLen);
+ Q_UNUSED(maxPskLen);
+#endif
+}
+
+/*!
+ \internal
+ Auxiliary function. Initializes server-side \a auth using the \a identity, \a identityHint and
+ \a maxPskLen.
+*/
+void QTlsBackend::setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity,
+ const QByteArray &identityHint, unsigned int maxPskLen)
+{
+#if QT_CONFIG(ssl)
+ Q_ASSERT(auth);
+ auth->d->identityHint = identityHint;
+ auth->d->identity = identity;
+ auth->d->maximumIdentityLength = 0; // user cannot set an identity
+ auth->d->maximumPreSharedKeyLength = int(maxPskLen);
+#else
+ Q_UNUSED(auth);
+ Q_UNUSED(identity);
+ Q_UNUSED(identityHint);
+ Q_UNUSED(maxPskLen);
+#endif
+}
+
+#if QT_CONFIG(ssl)
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a descriptionOneLine, \a bits
+ and \a supportedBits. \a descriptionOneLine consists of several fields, separated by
+ whitespace. These include: cipher name, protocol version, key exchange method,
+ authentication method, encryption method, message digest (Mac). Example:
+ "ECDHE-RSA-AES256-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD"
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &descriptionOneLine, int bits, int supportedBits)
+{
+ QSslCipher ciph;
+
+ const auto descriptionList = QStringView{descriptionOneLine}.split(u' ', Qt::SkipEmptyParts);
+ if (descriptionList.size() > 5) {
+ ciph.d->isNull = false;
+ ciph.d->name = descriptionList.at(0).toString();
+
+ QStringView protoString = descriptionList.at(1);
+ ciph.d->protocolString = protoString.toString();
+ ciph.d->protocol = QSsl::UnknownProtocol;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ if (protoString.startsWith(u"TLSv1")) {
+ QStringView tail = protoString.sliced(5);
+ if (tail.startsWith(u'.')) {
+ tail = tail.sliced(1);
+ if (tail == u"3")
+ ciph.d->protocol = QSsl::TlsV1_3;
+ else if (tail == u"2")
+ ciph.d->protocol = QSsl::TlsV1_2;
+ else if (tail == u"1")
+ ciph.d->protocol = QSsl::TlsV1_1;
+ } else if (tail.isEmpty()) {
+ ciph.d->protocol = QSsl::TlsV1_0;
+ }
+ }
+QT_WARNING_POP
+
+ if (descriptionList.at(2).startsWith("Kx="_L1))
+ ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString();
+ if (descriptionList.at(3).startsWith("Au="_L1))
+ ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString();
+ if (descriptionList.at(4).startsWith("Enc="_L1))
+ ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString();
+ ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == "export"_L1);
+
+ ciph.d->bits = bits;
+ ciph.d->supportedBits = supportedBits;
+ }
+
+ return ciph;
+}
+
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a suiteName, \a protocol version and
+ \a protocolString. For example:
+ \code
+ createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, QSsl::TlsV1_2, "TLSv1.2"_L1);
+ \endcode
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol,
+ const QString &protocolString)
+{
+ QSslCipher ciph;
+
+ if (!suiteName.size())
+ return ciph;
+
+ ciph.d->isNull = false;
+ ciph.d->name = suiteName;
+ ciph.d->protocol = protocol;
+ ciph.d->protocolString = protocolString;
+
+ const auto bits = QStringView{ciph.d->name}.split(u'-');
+ if (bits.size() >= 2) {
+ if (bits.size() == 2 || bits.size() == 3)
+ ciph.d->keyExchangeMethod = "RSA"_L1;
+ else if (bits.front() == "DH"_L1 || bits.front() == "DHE"_L1)
+ ciph.d->keyExchangeMethod = "DH"_L1;
+ else if (bits.front() == "ECDH"_L1 || bits.front() == "ECDHE"_L1)
+ ciph.d->keyExchangeMethod = "ECDH"_L1;
+ else
+ qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name;
+
+ if (bits.size() == 2 || bits.size() == 3)
+ ciph.d->authenticationMethod = "RSA"_L1;
+ else if (ciph.d->name.contains("-ECDSA-"_L1))
+ ciph.d->authenticationMethod = "ECDSA"_L1;
+ else if (ciph.d->name.contains("-RSA-"_L1))
+ ciph.d->authenticationMethod = "RSA"_L1;
+ else
+ qCWarning(lcSsl) << "Unknown Au" << ciph.d->name;
+
+ if (ciph.d->name.contains("RC4-"_L1)) {
+ ciph.d->encryptionMethod = "RC4(128)"_L1;
+ ciph.d->bits = 128;
+ ciph.d->supportedBits = 128;
+ } else if (ciph.d->name.contains("DES-CBC3-"_L1)) {
+ ciph.d->encryptionMethod = "3DES(168)"_L1;
+ ciph.d->bits = 168;
+ ciph.d->supportedBits = 168;
+ } else if (ciph.d->name.contains("AES128-"_L1)) {
+ ciph.d->encryptionMethod = "AES(128)"_L1;
+ ciph.d->bits = 128;
+ ciph.d->supportedBits = 128;
+ } else if (ciph.d->name.contains("AES256-GCM"_L1)) {
+ ciph.d->encryptionMethod = "AESGCM(256)"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("AES256-"_L1)) {
+ ciph.d->encryptionMethod = "AES(256)"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("CHACHA20-"_L1)) {
+ ciph.d->encryptionMethod = "CHACHA20"_L1;
+ ciph.d->bits = 256;
+ ciph.d->supportedBits = 256;
+ } else if (ciph.d->name.contains("NULL-"_L1)) {
+ ciph.d->encryptionMethod = "NULL"_L1;
+ } else {
+ qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name;
+ }
+ }
+ return ciph;
+}
+
+/*!
+ \internal
+ Auxiliary function. Creates a new QSslCipher from \a name, \a keyExchangeMethod, \a encryptionMethod,
+ \a authenticationMethod, \a bits, \a protocol version and \a protocolString.
+ For example:
+ \code
+ createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, "ECDH"_L1, "AES"_L1, "RSA"_L1, 256,
+ QSsl::TlsV1_2, "TLSv1.2"_L1);
+ \endcode
+*/
+QSslCipher QTlsBackend::createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString)
+{
+ QSslCipher cipher;
+ cipher.d->isNull = false;
+ cipher.d->name = name;
+ cipher.d->bits = bits;
+ cipher.d->supportedBits = bits;
+ cipher.d->keyExchangeMethod = keyExchangeMethod;
+ cipher.d->encryptionMethod = encryptionMethod;
+ cipher.d->authenticationMethod = authenticationMethod;
+ cipher.d->protocol = protocol;
+ cipher.d->protocolString = protocolString;
+ return cipher;
+}
+
+/*!
+ \internal
+ Returns an implementation-specific list of ciphersuites that can be used by QSslSocket.
+
+ \sa QSslConfiguration::defaultCiphers()
+*/
+QList<QSslCipher> QTlsBackend::defaultCiphers()
+{
+ return QSslSocketPrivate::defaultCiphers();
+}
+
+/*!
+ \internal
+ Returns an implementation-specific list of ciphersuites that can be used by QDtls.
+*/
+QList<QSslCipher> QTlsBackend::defaultDtlsCiphers()
+{
+ return QSslSocketPrivate::defaultDtlsCiphers();
+}
+
+/*!
+ \internal
+ Sets \a ciphers as defaults ciphers that QSslSocket can use.
+
+ \sa defaultCiphers()
+*/
+void QTlsBackend::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets \a ciphers as defaults ciphers that QDtls can use.
+
+ \sa defaultDtlsCiphers()
+*/
+void QTlsBackend::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultDtlsCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets \a ciphers as a list of supported ciphers.
+
+ \sa QSslConfiguration::supportedCiphers()
+*/
+void QTlsBackend::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultSupportedCiphers(ciphers);
+}
+
+/*!
+ \internal
+ Sets the list of QSslEllipticCurve objects, that QSslConfiguration::supportedEllipticCurves()
+ returns, to ones that are supported by this backend.
+*/
+void QTlsBackend::resetDefaultEllipticCurves()
+{
+ QSslSocketPrivate::resetDefaultEllipticCurves();
+}
+
+/*!
+ Sets \a certs as a list of certificates, that QSslConfiguration::caCertificates()
+ reports.
+
+ \sa QSslConfiguration::defaultConfiguration(), QSslConfiguration::caCertificates()
+*/
+void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::setDefaultCaCertificates(certs);
+}
+
+/*!
+ \internal
+ Returns true if \a configuration allows loading root certificates on demand.
+*/
+bool QTlsBackend::rootLoadingOnDemandAllowed(const QSslConfiguration &configuration)
+{
+ return configuration.d->allowRootCertOnDemandLoading;
+}
+
+/*!
+ \internal
+ Stores \a peerCert in the \a configuration.
+*/
+void QTlsBackend::storePeerCertificate(QSslConfiguration &configuration,
+ const QSslCertificate &peerCert)
+{
+ configuration.d->peerCertificate = peerCert;
+}
+
+/*!
+ \internal
+ Stores \a peerChain in the \a configuration.
+*/
+void QTlsBackend::storePeerCertificateChain(QSslConfiguration &configuration,
+ const QList<QSslCertificate> &peerChain)
+{
+ configuration.d->peerCertificateChain = peerChain;
+}
+
+/*!
+ \internal
+ Clears the peer certificate chain in \a configuration.
+*/
+void QTlsBackend::clearPeerCertificates(QSslConfiguration &configuration)
+{
+ configuration.d->peerCertificate.clear();
+ configuration.d->peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+ Clears the peer certificate chain in \a d.
+*/
+void QTlsBackend::clearPeerCertificates(QSslSocketPrivate *d)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificate.clear();
+ d->configuration.peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+ Updates the configuration in \a d with \a shared value.
+*/
+void QTlsBackend::setPeerSessionShared(QSslSocketPrivate *d, bool shared)
+{
+ Q_ASSERT(d);
+ d->configuration.peerSessionShared = shared;
+}
+
+/*!
+ \internal
+ Sets TLS session in \a d to \a asn1.
+*/
+void QTlsBackend::setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1)
+{
+ Q_ASSERT(d);
+ d->configuration.sslSession = asn1;
+}
+
+/*!
+ \internal
+ Sets TLS session lifetime hint in \a d to \a hint.
+*/
+void QTlsBackend::setSessionLifetimeHint(QSslSocketPrivate *d, int hint)
+{
+ Q_ASSERT(d);
+ d->configuration.sslSessionTicketLifeTimeHint = hint;
+}
+
+/*!
+ \internal
+ Sets application layer protocol negotiation status in \a d to \a st.
+*/
+void QTlsBackend::setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st)
+{
+ Q_ASSERT(d);
+ d->configuration.nextProtocolNegotiationStatus = st;
+}
+
+/*!
+ \internal
+ Sets \a protocol in \a d as a negotiated application layer protocol.
+*/
+void QTlsBackend::setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol)
+{
+ Q_ASSERT(d);
+ d->configuration.nextNegotiatedProtocol = protocol;
+}
+
+/*!
+ \internal
+ Stores \a peerCert in the TLS configuration of \a d.
+*/
+void QTlsBackend::storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificate = peerCert;
+}
+
+/*!
+ \internal
+
+ Stores \a peerChain in the TLS configuration of \a d.
+
+ \note This is a helper function that TlsCryptograph and DtlsCryptograph
+ call during a handshake.
+*/
+void QTlsBackend::storePeerCertificateChain(QSslSocketPrivate *d,
+ const QList<QSslCertificate> &peerChain)
+{
+ Q_ASSERT(d);
+ d->configuration.peerCertificateChain = peerChain;
+}
+
+/*!
+ \internal
+
+ Adds \a rootCert to the list of trusted root certificates in \a d.
+
+ \note In Qt 6.1 it's only used on Windows, during so called 'CA fetch'.
+*/
+void QTlsBackend::addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert)
+{
+ Q_ASSERT(d);
+ if (!d->configuration.caCertificates.contains(rootCert))
+ d->configuration.caCertificates += rootCert;
+}
+
+/*!
+ \internal
+
+ Saves ephemeral \a key in \a d.
+
+ \sa QSslConfiguration::ephemeralKey()
+*/
+void QTlsBackend::setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key)
+{
+ Q_ASSERT(d);
+ d->configuration.ephemeralServerKey = key;
+}
+
+/*!
+ \internal
+
+ Implementation-specific. Sets the security level suitable for Qt's
+ auto-tests.
+*/
+void QTlsBackend::forceAutotestSecurityLevel()
+{
+}
+
+#endif // QT_CONFIG(ssl)
+
+namespace QTlsPrivate {
+
+/*!
+ \internal (Network-private)
+ \namespace QTlsPrivate
+ \brief Namespace containing onternal types that TLS backends implement.
+
+ This namespace is private to Qt and the backends that implement its TLS support.
+*/
+
+/*!
+ \class TlsKey
+ \internal (Network-private)
+ \brief TlsKey is an abstract class, that allows a TLS plugin to provide
+ an underlying implementation for the class QSslKey.
+
+ Most functions in the class TlsKey are pure virtual and thus have to be
+ reimplemented by a TLS backend that supports QSslKey. In many cases an
+ empty implementation as an overrider is sufficient, albeit with some
+ of QSslKey's functionality missing.
+
+ \sa QTlsBackend::createKey(), QTlsBackend::implementedClasses(), QSslKey
+*/
+
+/*!
+ \fn void TlsKey::decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
+ \internal
+
+ If a support of public and private keys in DER format is required, this function
+ must be overridden and should initialize this key using the \a type, \a algorithm, \a der
+ and \a passPhrase. If this key was initialized previously, \a deepClear
+ has an implementation-specific meaning (e.g., if an implementation is using
+ reference-counting and can share internally some data structures, a value \c true may
+ trigger decrementing a reference counter on some implementation-specific object).
+
+ \note An empty overrider is sufficient, but then reading keys in QSsl::Der format
+ will not be supported.
+
+ \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm
+*/
+
+/*!
+ \fn void TlsKey::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, const QByteArray &passPhrase, bool deepClear)
+ \internal
+
+ If a support of public and private keys in PEM format is required, this function must
+ be overridden and should initialize this key using the \a type, \a algorithm, \a pem and
+ \a passPhrase. If this key was initialized previously, \a deepClear has an
+ implementation-specific meaning (e.g., in an implementation using reference-counting,
+ a value \c true may trigger decrementing a reference counter on some implementation-specific
+ object).
+
+ \note An empty overrider is sufficient, but then reading keys in QSsl::Pem format
+ will not be supported.
+
+ \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm
+*/
+
+/*!
+ \fn QByteArray TlsKey::toPem(const QByteArray &passPhrase) const
+ \internal
+
+ This function must be overridden, if converting a key to PEM format, potentially with
+ encryption, is needed (e.g. to save a QSslKey into a file). If this key is
+ private and \a passPhrase is not empty, the key's data is expected to be encrypted using
+ some conventional encryption algorithm (e.g. DES or AES - the one that different tools
+ or even the class QSslKey can understand later).
+
+ \note If this particular functionality is not needed, an overrider returning an
+ empty QByteArray is sufficient.
+
+ \sa QSslKey::toPem()
+*/
+
+/*!
+ \fn QByteArray TlsKey::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
+ \internal
+
+ Converts \a pem to DER format, using this key's type and algorithm. The parameter \a headers
+ must be a valid, non-null pointer. When parsing \a pem, the headers found there will be saved
+ into \a headers.
+
+ \note An overrider returning an empty QByteArray is sufficient, if QSslKey::toDer() is not
+ needed.
+
+ \note This function is very implementation-specific. A backend, that already has this key's
+ non-empty DER data, may simply return this data.
+
+ \sa QSslKey::toDer()
+*/
+
+/*!
+ \fn QByteArray TlsKey::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+ \internal
+
+ If overridden, this function is expected to convert \a der, using \a headers, to PEM format.
+
+ \note This function is very implementation-specific. As of now (Qt 6.1), it is only required by
+ Qt's own non-OpenSSL backends, that internally use DER and implement QSslKey::toPem()
+ via pemFromDer().
+*/
+
+/*!
+ \fn void TlsKey::fromHandle(Qt::HANDLE handle, KeyType type)
+ \internal
+
+ Initializes this key using the \a handle and \a type, taking the ownership
+ of the \a handle.
+
+ \note The meaning of the \a handle is implementation-specific.
+
+ \note If a TLS backend does not support such keys, it must provide an
+ empty implementation.
+
+ \sa handle(), QSslKey::QSslKey(), QSslKet::handle()
+*/
+
+/*!
+ \fn TlsKey::handle() const
+ \internal
+
+ If a TLS backend supports opaque keys, returns a native handle that
+ this key was initialized with.
+
+ \sa fromHandle(), QSslKey::handle()
+*/
+
+/*!
+ \fn bool TlsKey::isNull() const
+ \internal
+
+ Returns \c true if this is a null key, \c false otherwise.
+
+ \note A null key corresponds to the default-constructed
+ QSslKey or the one, that was cleared via QSslKey::clear().
+
+ \sa QSslKey::isNull()
+*/
+
+/*!
+ \fn QSsl::KeyType TlsKey::type() const
+ \internal
+
+ Returns the type of this key (public or private).
+*/
+
+/*!
+ \fn QSsl::KeyAlgorithm TlsKey::algorithm() const
+ \internal
+
+ Return this key's algorithm.
+*/
+
+/*!
+ \fn int TlsKey::length() const
+ \internal
+
+ Returns the length of the key in bits, or -1 if the key is null.
+*/
+
+/*!
+ \fn void TlsKey::clear(bool deep)
+ \internal
+
+ Clears the contents of this key, making it a null key. The meaning
+ of \a deep is implementation-specific (e.g. if some internal objects
+ representing a key can be shared using reference counting, \a deep equal
+ to \c true would imply decrementing a reference count).
+
+ \sa isNull()
+*/
+
+/*!
+ \fn bool TlsKey::isPkcs8() const
+ \internal
+
+ This function is internally used only by Qt's own TLS plugins and affects
+ the way PEM file is generated by TlsKey. It's sufficient to override it
+ and return \c false in case a new TLS backend is not using Qt's plugin
+ as a base.
+*/
+
+/*!
+ \fn QByteArray TlsKey::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const
+ \internal
+
+ This function allows to decrypt \a data (for example, a private key read from a file), using
+ \a passPhrase, initialization vector \a iv. \a cipher is describing a block cipher and its
+ mode (for example, AES256 + CBC). decrypt() is needed to implement QSslKey's constructor.
+
+ \note A TLS backend may provide an empty implementation, but as a result QSslKey will not be able
+ to work with private encrypted keys.
+
+ \sa QSslKey
+*/
+
+/*!
+ \fn QByteArray TlsKey::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const
+ \internal
+
+ This function is needed to implement QSslKey::toPem() with encryption (for a private
+ key). \a cipher names a block cipher to use to encrypt \a data, using
+ \a passPhrase and initialization vector \a iv.
+
+ \note An empty implementation is sufficient, but QSslKey::toPem() will fail for
+ a private key and non-empty passphrase.
+
+ \sa QSslKey
+*/
+
+/*!
+ \internal
+
+ Destroys this key.
+*/
+TlsKey::~TlsKey() = default;
+
+/*!
+ \internal
+
+ A convenience function that returns a string, corresponding to the
+ key type or algorithm, which can be used as a header in a PEM file.
+*/
+QByteArray TlsKey::pemHeader() const
+{
+ if (type() == QSsl::PublicKey)
+ return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
+ else if (algorithm() == QSsl::Rsa)
+ return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dsa)
+ return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Ec)
+ return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dh)
+ return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \internal
+ A convenience function that returns a string, corresponding to the
+ key type or algorithm, which can be used as a footer in a PEM file.
+*/
+QByteArray TlsKey::pemFooter() const
+{
+ if (type() == QSsl::PublicKey)
+ return QByteArrayLiteral("-----END PUBLIC KEY-----");
+ else if (algorithm() == QSsl::Rsa)
+ return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dsa)
+ return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Ec)
+ return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
+ else if (algorithm() == QSsl::Dh)
+ return QByteArrayLiteral("-----END PRIVATE KEY-----");
+
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \class X509Certificate
+ \internal (Network-private)
+ \brief X509Certificate is an abstract class that allows a TLS backend to
+ provide an implementation of the QSslCertificate class.
+
+ This class provides an interface that must be reimplemented by a TLS plugin,
+ that supports QSslCertificate. Most functions are pure virtual, and thus
+ have to be overridden. For some of them, an empty overrider is acceptable,
+ though a part of functionality in QSslCertificate will be missing.
+
+ \sa QTlsBackend::createCertificate(), QTlsBackend::X509PemReader(), QTlsBackend::X509DerReader()
+*/
+
+/*!
+ \fn bool X509Certificate::isEqual(const X509Certificate &other) const
+ \internal
+
+ This function is expected to return \c true if this certificate is the same as
+ the \a other, \c false otherwise. Used by QSslCertificate's comparison operators.
+*/
+
+/*!
+ \fn bool X509Certificate::isNull() const
+ \internal
+
+ Returns true if this certificate was default-constructed and not initialized yet.
+ This function is called by QSslCertificate::isNull().
+
+ \sa QSslCertificate::isNull()
+*/
+
+/*!
+ \fn bool X509Certificate::isSelfSigned() const
+ \internal
+
+ This function is needed to implement QSslCertificate::isSelfSigned()
+
+ \sa QSslCertificate::isSelfSigned()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::version() const
+ \internal
+
+ Implements QSslCertificate::version().
+
+ \sa QSslCertificate::version()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::serialNumber() const
+ \internal
+
+ This function is expected to return the certificate's serial number string in
+ hexadecimal format.
+
+ \sa QSslCertificate::serialNumber()
+*/
+
+/*!
+ \fn QStringList X509Certificate::issuerInfo(QSslCertificate::SubjectInfo subject) const
+ \internal
+
+ This function is expected to return the issuer information for the \a subject
+ from the certificate, or an empty list if there is no information for subject
+ in the certificate. There can be more than one entry of each type.
+
+ \sa QSslCertificate::issuerInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::issuerInfo(const QByteArray &attribute) const
+ \internal
+
+ This function is expected to return the issuer information for attribute from
+ the certificate, or an empty list if there is no information for \a attribute
+ in the certificate. There can be more than one entry for an attribute.
+
+ \sa QSslCertificate::issuerInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::subjectInfo(QSslCertificate::SubjectInfo subject) const
+ \internal
+
+ This function is expected to return the information for the \a subject, or an empty list
+ if there is no information for subject in the certificate. There can be more than one
+ entry of each type.
+
+ \sa QSslCertificate::subjectInfo().
+*/
+
+/*!
+ \fn QStringList X509Certificate::subjectInfo(const QByteArray &attribute) const
+ \internal
+
+ This function is expected to return the subject information for \a attribute, or
+ an empty list if there is no information for attribute in the certificate.
+ There can be more than one entry for an attribute.
+
+ \sa QSslCertificate::subjectInfo().
+*/
+
+/*!
+ \fn QList<QByteArray> X509Certificate::subjectInfoAttributes() const
+ \internal
+
+ This function is expected to return a list of the attributes that have values
+ in the subject information of this certificate. The information associated
+ with a given attribute can be accessed using the subjectInfo() method. Note
+ that this list may include the OIDs for any elements that are not known by
+ the TLS backend.
+
+ \note This function is needed for QSslCertificate:::subjectInfoAttributes().
+
+ \sa subjectInfo()
+*/
+
+/*!
+ \fn QList<QByteArray> X509Certificate::issuerInfoAttributes() const
+ \internal
+
+ This function is expected to return a list of the attributes that have
+ values in the issuer information of this certificate. The information
+ associated with a given attribute can be accessed using the issuerInfo()
+ method. Note that this list may include the OIDs for any
+ elements that are not known by the TLS backend.
+
+ \note This function implements QSslCertificate::issuerInfoAttributes().
+
+ \sa issuerInfo()
+*/
+
+/*!
+ \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> X509Certificate::subjectAlternativeNames() const
+ \internal
+
+ This function is expected to return the list of alternative subject names for
+ this certificate. The alternative names typically contain host names, optionally
+ with wildcards, that are valid for this certificate.
+
+ \sa subjectInfo()
+*/
+
+/*!
+ \fn QDateTime X509Certificate::effectiveDate() const
+ \internal
+
+ This function is expected to return the date-time that the certificate
+ becomes valid, or an empty QDateTime if this is a null certificate.
+
+ \sa expiryDate()
+*/
+
+/*!
+ \fn QDateTime X509Certificate::expiryDate() const
+ \internal
+
+ This function is expected to return the date-time that the certificate expires,
+ or an empty QDateTime if this is a null certificate.
+
+ \sa effectiveDate()
+*/
+
+/*!
+ \fn qsizetype X509Certificate::numberOfExtensions() const
+ \internal
+
+ This function is expected to return the number of X509 extensions of
+ this certificate.
+*/
+
+/*!
+ \fn QString X509Certificate::oidForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the ASN.1 OID for the extension
+ with index \a i.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn QString X509Certificate::nameForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the name for the extension
+ with index \a i. If no name is known for the extension then the
+ OID will be returned.
+
+ \sa numberOfExtensions(), oidForExtension()
+*/
+
+/*!
+ \fn QVariant X509Certificate::valueForExtension(qsizetype i) const
+ \internal
+
+ This function is expected to return the value of the extension
+ with index \a i. The structure of the value returned depends on
+ the extension type
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn bool X509Certificate::isExtensionCritical(qsizetype i) const
+ \internal
+
+ This function is expected to return the criticality of the extension
+ with index \a i.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn bool X509Certificate::isExtensionSupported(qsizetype i) const
+ \internal
+
+ This function is expected to return \c true if this extension is supported.
+ In this case, supported simply means that the structure of the QVariant returned
+ by the valueForExtension() accessor will remain unchanged between versions.
+
+ \sa numberOfExtensions()
+*/
+
+/*!
+ \fn QByteArray X509Certificate::toPem() const
+ \internal
+
+ This function is expected to return this certificate converted to a PEM (Base64)
+ encoded representation.
+*/
+
+/*!
+ \fn QByteArray X509Certificate::toDer() const
+ \internal
+
+ This function is expected to return this certificate converted to a DER (binary)
+ encoded representation.
+*/
+
+/*!
+ \fn QString X509Certificate::toText() const
+ \internal
+
+ This function is expected to return this certificate converted to a human-readable
+ text representation.
+*/
+
+/*!
+ \fn Qt::HANDLE X509Certificate::handle() const
+ \internal
+
+ This function is expected to return a pointer to the native certificate handle,
+ if there is one, else nullptr.
+*/
+
+/*!
+ \fn size_t X509Certificate::hash(size_t seed) const
+ \internal
+
+ This function is expected to return the hash value for this certificate,
+ using \a seed to seed the calculation.
+*/
+
+/*!
+ \internal
+
+ Destroys this certificate.
+*/
+X509Certificate::~X509Certificate() = default;
+
+/*!
+ \internal
+
+ Returns the certificate subject's public key.
+*/
+TlsKey *X509Certificate::publicKey() const
+{
+ return nullptr;
+}
+
+#if QT_CONFIG(ssl)
+
+/*!
+ \class TlsCryptograph
+ \internal (Network-private)
+ \brief TlsCryptograph is an abstract class, that allows a TLS plugin to implement QSslSocket.
+
+ This abstract base class provides an interface that must be reimplemented by a TLS plugin,
+ that supports QSslSocket. A class, implementing TlsCryptograph's interface, is responsible
+ for TLS handshake, reading and writing encryped application data; it is expected
+ to work with QSslSocket and it's private implementation - QSslSocketPrivate.
+ QSslSocketPrivate provides access to its read/write buffers, QTcpSocket it
+ internally uses for connecting, reading and writing. QSslSocketPrivate
+ can also be used for reporting errors and storing the certificates received
+ during the handshake phase.
+
+ \note Most of the functions in this class are pure virtual and have no actual implementation
+ in the QtNetwork module. This documentation is mostly conceptual and only describes what those
+ functions are expected to do, but not how they must be implemented.
+
+ \sa QTlsBackend::createTlsCryptograph()
+*/
+
+/*!
+ \fn void TlsCryptograph::init(QSslSocket *q, QSslSocketPrivate *d)
+ \internal
+
+ When initializing this TlsCryptograph, QSslSocket will pass a pointer to self and
+ its d-object using this function.
+*/
+
+/*!
+ \fn QList<QSslError> TlsCryptograph::tlsErrors() const
+ \internal
+
+ Returns a list of QSslError, describing errors encountered during
+ the TLS handshake.
+
+ \sa QSslSocket::sslHandshakeErrors()
+*/
+
+/*!
+ \fn void TlsCryptograph::startClientEncryption()
+ \internal
+
+ A client-side QSslSocket calls this function after its internal TCP socket
+ establishes a connection with a remote host, or from QSslSocket::startClientEncryption().
+ This TlsCryptograph is expected to initialize some implementation-specific TLS context,
+ if needed, and then start the client side of the TLS handshake (for example, by calling
+ transmit()), using TCP socket from QSslSocketPrivate.
+
+ \sa init(), transmit(), QSslSocket::startClientEncryption(), QSslSocket::connectToHostEncrypted()
+*/
+
+/*!
+ \fn void TlsCryptograph::startServerEncryption()
+ \internal
+
+ This function is called by QSslSocket::startServerEncryption(). The TlsCryptograph
+ is expected to initialize some implementation-specific TLS context, if needed,
+ and then try to read the ClientHello message and continue the TLS handshake
+ (for example, by calling transmit()).
+
+ \sa transmit(), QSslSocket::startServerEncryption()
+*/
+
+/*!
+ \fn void TlsCryptograph::continueHandshake()
+ \internal
+
+ QSslSocket::resume() calls this function if its pause mode is QAbstractSocket::PauseOnSslErrors,
+ and errors, found during the handshake, were ignored. If implemented, this function is expected
+ to emit QSslSocket::encrypted().
+
+ \sa QAbstractSocket::pauseMode(), QSslSocket::sslHandshakeErrors(), QSslSocket::ignoreSslErrors(), QSslSocket::resume()
+*/
+
+/*!
+ \fn void TlsCryptograph::disconnectFromHost()
+ \internal
+
+ This function is expected to call disconnectFromHost() on the TCP socket
+ that can be obtained from QSslSocketPrivate. Any additional actions
+ are implementation-specific (e.g., sending shutdown alert message).
+
+*/
+
+/*!
+ \fn void TlsCryptograph::disconnected()
+ \internal
+
+ This function is called when the remote has disconnected. If there
+ is data left to be read you may ignore the maxReadBufferSize restriction
+ and read it all now.
+*/
+
+/*!
+ \fn QSslCipher TlsCryptograph::sessionCipher() const
+ \internal
+
+ This function returns a QSslCipher object describing the ciphersuite negotiated
+ during the handshake.
+*/
+
+/*!
+ \fn QSsl::SslProtocol TlsCryptograph::sessionProtocol() const
+ \internal
+
+ This function returns the version of TLS (or DTLS) protocol negotiated during the handshake.
+*/
+
+/*!
+ \fn void TlsCryptograph::transmit()
+ \internal
+
+ This function is responsible for reading and writing data. The meaning of these I/O
+ operations depends on an implementation-specific TLS state machine. These read and write
+ operations can be reading and writing parts of a TLS handshake (e.g. by calling handshake-specific
+ functions), or reading and writing application data (if encrypted connection was already
+ established). transmit() is expected to use the QSslSocket's TCP socket (accessible via
+ QSslSocketPrivate) to read the incoming data and write the outgoing data. When in encrypted
+ state, transmit() is also using QSslSocket's internal read and write buffers: the read buffer
+ to fill with decrypted incoming data; the write buffer - for the data to encrypt and send.
+ This TlsCryptograph can also use QSslSocketPrivate to check which TLS errors were ignored during
+ the handshake.
+
+ \note This function is responsible for emitting QSslSocket's signals, that occur during the
+ handshake (e.g. QSslSocket::sslErrors() or QSslSocket::encrypted()), and also read/write signals,
+ e.g. QSslSocket::bytesWritten() and QSslSocket::readyRead().
+
+ \sa init()
+*/
+
+/*!
+ \internal
+
+ Destroys this object.
+*/
+TlsCryptograph::~TlsCryptograph() = default;
+
+/*!
+ \internal
+
+ This function allows to share QSslContext between several QSslSocket objects.
+ The default implementation does nothing.
+
+ \note The definition of the class QSslContext is implementation-specific.
+
+ \sa sslContext()
+*/
+void TlsCryptograph::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext)
+{
+ Q_UNUSED(tlsContext);
+}
+
+/*!
+ \internal
+
+ Returns the context previously set by checkSettingSslContext() or \nullptr,
+ if no context was set. The default implementation returns \nullptr.
+
+ \sa checkSettingSslContext()
+*/
+std::shared_ptr<QSslContext> TlsCryptograph::sslContext() const
+{
+ return {};
+}
+
+/*!
+ \internal
+
+ If this TLS backend supports reporting errors before handshake is finished,
+ e.g. from a verification callback function, enableHandshakeContinuation()
+ allows this object to continue handshake. The default implementation does
+ nothing.
+
+ \sa QSslSocket::handshakeInterruptedOnError(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+void TlsCryptograph::enableHandshakeContinuation()
+{
+}
+
+/*!
+ \internal
+
+ Windows and OpenSSL-specific, only used internally by Qt's OpenSSL TLS backend.
+
+ \note The default empty implementation is sufficient.
+*/
+void TlsCryptograph::cancelCAFetch()
+{
+}
+
+/*!
+ \internal
+
+ Windows and Schannel-specific, only used by Qt's Schannel TLS backend, in
+ general, if a backend has its own buffer where it stores undecrypted data
+ then it must report true if it contains any data through this function.
+
+ \note The default empty implementation, returning \c false is sufficient.
+*/
+bool TlsCryptograph::hasUndecryptedData() const
+{
+ return false;
+}
+
+/*!
+ \internal
+
+ Returns the list of OCSP (Online Certificate Status Protocol) responses,
+ received during the handshake. The default implementation returns an empty
+ list.
+*/
+QList<QOcspResponse> TlsCryptograph::ocsps() const
+{
+ return {};
+}
+
+/*!
+ \internal
+
+ A helper function that can be used during a handshake. Returns \c true if the \a peerName
+ matches one of subject alternative names or common names found in the \a certificate.
+*/
+bool TlsCryptograph::isMatchingHostname(const QSslCertificate &certificate, const QString &peerName)
+{
+ return QSslSocketPrivate::isMatchingHostname(certificate, peerName);
+}
+
+/*!
+ \internal
+ Calls QAbstractSocketPrivate::setErrorAndEmit() for \a d, passing \a errorCode and
+ \a errorDescription as parameters.
+*/
+void TlsCryptograph::setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const
+{
+ Q_ASSERT(d);
+ d->setErrorAndEmit(errorCode, errorDescription);
+}
+
+#if QT_CONFIG(dtls)
+/*!
+ \class DtlsBase
+ \internal (Network-private)
+ \brief DtlsBase is a base class for the classes DtlsCryptograph and DtlsCookieVerifier.
+
+ DtlsBase is the base class for the classes DtlsCryptograph and DtlsCookieVerifier. It's
+ an abstract class, an interface that these before-mentioned classes share. It allows to
+ set, get and clear the last error that occurred, set and get cookie generation parameters,
+ set and get QSslConfiguration.
+
+ \note This class is not supposed to be inherited directly, it's only needed by DtlsCryptograph
+ and DtlsCookieVerifier.
+
+ \sa QDtls, QDtlsClientVerifier, DtlsCryptograph, DtlsCookieVerifier
+*/
+
+/*!
+ \fn void DtlsBase::setDtlsError(QDtlsError code, const QString &description)
+ \internal
+
+ Sets the last error to \a code and its textual description to \a description.
+
+ \sa QDtlsError, error(), errorString()
+*/
+
+/*!
+ \fn QDtlsError DtlsBase::error() const
+ \internal
+
+ This function, when overridden, is expected to return the code for the last error that occurred.
+ If no error occurred it should return QDtlsError::NoError.
+
+ \sa QDtlsError, errorString(), setDtlsError()
+*/
+
+/*!
+ \fn QDtlsError DtlsBase::errorString() const
+ \internal
+
+ This function, when overridden, is expected to return the textual description for the last error
+ that occurred or an empty string if no error occurred.
+
+ \sa QDtlsError, error(), setDtlsError()
+*/
+
+/*!
+ \fn void DtlsBase::clearDtlsError()
+ \internal
+
+ This function is expected to set the error code for the last error to QDtlsError::NoError and
+ its textual description to an empty string.
+
+ \sa QDtlsError, setDtlsError(), error(), errorString()
+*/
+
+/*!
+ \fn void DtlsBase::setConfiguration(const QSslConfiguration &configuration)
+ \internal
+
+ Sets a TLS configuration that an object of a class inheriting from DtlsCookieVerifier or
+ DtlsCryptograph will use, to \a configuration.
+
+ \sa configuration()
+*/
+
+/*!
+ \fn QSslConfiguration DtlsBase::configuration() const
+ \internal
+
+ Returns TLS configuration this object is using (either set by setConfiguration()
+ previously, or the default DTLS configuration).
+
+ \sa setConfiguration(), QSslConfiguration::defaultDtlsConfiguration()
+*/
+
+/*!
+ \fn bool DtlsBase::setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters &params)
+ \internal
+
+ Sets the DTLS cookie generation parameters that DtlsCookieVerifier or DtlsCryptograph will use to
+ \a params.
+
+ \note This function returns \c false if parameters were invalid - if the secret was empty. Otherwise,
+ this function must return true.
+
+ \sa QDtlsClientVerifier::GeneratorParameters, cookieGeneratorParameters()
+*/
+
+/*!
+ \fn QDtlsClientVerifier::GeneratorParameters DtlsBase::cookieGeneratorParameters() const
+ \internal
+
+ Returns DTLS cookie generation parameters that were either previously set by setCookieGeneratorParameters(),
+ or default parameters.
+
+ \sa setCookieGeneratorParameters()
+*/
+
+/*!
+ \internal
+
+ Destroys this object.
+*/
+DtlsBase::~DtlsBase() = default;
+
+/*!
+ \class DtlsCookieVerifier
+ \internal (Network-private)
+ \brief DtlsCookieVerifier is an interface that allows a TLS plugin to support the class QDtlsClientVerifier.
+
+ DtlsCookieVerifier is an interface, an abstract class, that has to be implemented by
+ a TLS plugin that supports DTLS cookie verification.
+
+ \sa QDtlsClientVerifier
+*/
+
+/*!
+ \fn bool DtlsCookieVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port)
+ \internal
+
+ This function is expected to verify a ClientHello message, found in \a dgram, using \a address,
+ \a port, and cookie generator parameters. The function returns \c true if such cookie was found
+ and \c false otherwise. If no valid cookie was found in the \a dgram, this verifier should use
+ \a socket to send a HelloVerifyRequest message, using \a address and \a port as the destination
+ and a source material for cookie generation, see also
+ \l {RFC 6347, section 4.2.1}
+
+ \sa QDtlsClientVerifier
+*/
+
+/*!
+ \fn QByteArray DtlsCookieVerifier::verifiedHello() const
+ \internal
+
+ Returns the last ClientHello message containing the DTLS cookie that this verifier was
+ able to verify as correct, or an empty byte array.
+
+ \sa verifyClient()
+*/
+
+/*!
+ \class DtlsCryptograph
+ \internal (Network-private)
+ \brief DtlsCryptograph is an interface that allows a TLS plugin to implement the class QDtls.
+
+ DtlsCryptograph is an abstract class; a TLS plugin can provide a class, inheriting from
+ DtlsCryptograph and implementing its pure virtual functions, thus implementing the class
+ QDtls and enabling DTLS over UDP.
+
+ To write DTLS datagrams, a class, inheriting DtlsCryptograph, is expected to use
+ QUdpSocket. In general, all reading is done externally, so DtlsCryptograph is
+ expected to only write into QUdpSocket, check possible socket errors, change socket
+ options if needed.
+
+ \note All functions in this class are pure virtual and have no actual implementation
+ in the QtNetwork module. This documentation is mostly conceptual and only describes
+ what those functions are expected to do, but not how they must be implemented.
+
+ \sa QDtls, QUdpSocket
+*/
+
+/*!
+ \fn QSslSocket::SslMode DtlsCryptograph::cryptographMode() const
+ \internal
+
+ Returns the mode (client or server) this object operates in.
+
+ \note This mode is set once when a new DtlsCryptograph is created
+ by QTlsBackend and cannot change.
+
+ \sa QTlsBackend::createDtlsCryptograph()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setPeer(const QHostAddress &addr, quint16 port, const QString &name)
+ \internal
+
+ Sets the remote peer's address to \a addr and remote port to \a port. \a name,
+ if not empty, is to be used when validating the peer's certificate.
+
+ \sa peerAddress(), peerPort(), peerVerificationName()
+*/
+
+/*!
+ \fn QHostAddress DtlsCryptograph::peerAddress() const
+ \internal
+
+ Returns the remote peer's address previously set by setPeer() or,
+ if no address was set, an empty address.
+
+ \sa setPeer()
+*/
+
+/*!
+ \fn quint16 DtlsCryptograph::peerPort() const
+ \internal
+
+ Returns the remote peer's port previously set by setPeer() or
+ 0 if no port was set.
+
+ \sa setPeer(), peerAddress()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setPeerVerificationName(const QString &name)
+ \internal
+
+ Sets the host name to use during certificate validation to \a name.
+
+ \sa peerVerificationName(), setPeer()
+*/
+
+/*!
+ \fn QString DtlsCryptograph::peerVerificationName() const
+ \internal
+
+ Returns the name that this object is using during the certificate validation,
+ previously set by setPeer() or setPeerVerificationName(). Returns an empty string
+ if no peer verification name was set.
+
+ \sa setPeer(), setPeerVerificationName()
+*/
+
+/*!
+ \fn void DtlsCryptograph::setDtlsMtuHint(quint16 mtu)
+ \internal
+
+ Sets the maximum transmission unit (MTU), if it is supported by a TLS implementation, to \a mtu.
+
+ \sa dtlsMtuHint()
+*/
+
+/*!
+ \fn quint16 DtlsCryptograph::dtlsMtuHint() const
+ \internal
+
+ Returns the value of the maximum transmission unit either previously set by setDtlsMtuHint(),
+ or some implementation-specific value (guessed or somehow known to this DtlsCryptograph).
+
+ \sa setDtlsMtuHint()
+*/
+
+/*!
+ \fn QDtls::HandshakeState DtlsCryptograph::state() const
+ \internal
+
+ Returns the current handshake state for this DtlsCryptograph (not started, in progress,
+ peer verification error found, complete).
+
+ \sa isConnectionEncrypted(), startHandshake()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::isConnectionEncrypted() const
+ \internal
+
+ Returns \c true if this DtlsCryptograph has completed a handshake without validation
+ errors (or these errors were ignored). Returns \c false otherwise.
+*/
+
+/*!
+ \fn bool DtlsCryptograph::startHandshake(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ This function is expected to initialize some implementation-specific context and to start a DTLS
+ handshake, using \a socket to write datagrams (but not to read them). If this object is operating
+ as a server, \a dgram is non-empty and contains the ClientHello message. This function returns
+ \c true if no error occurred (and this DtlsCryptograph's state switching to
+ QDtls::HandshakeState::HandshakeInProgress), \c false otherwise.
+
+ \sa continueHandshake(), handleTimeout(), resumeHandshake(), abortHandshake(), state()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::handleTimeout(QUdpSocket *socket)
+ \internal
+
+ In case a timeout occurred during the handshake, allows to re-transmit the last message,
+ using \a socket to write the datagram. Returns \c true if no error occurred, \c false otherwise.
+
+ \sa QDtls::handshakeTimeout(), QDtls::handleTimeout()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::continueHandshake(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ Continues the handshake, using \a socket to write datagrams (a handshake-specific message).
+ \a dgram contains the peer's handshake-specific message. Returns \c false in case some error
+ was encountered (this can include socket-related errors and errors found during the certificate
+ validation). Returns \c true if the handshake was complete successfully, or is still in progress.
+
+ This function, depending on the implementation-specific state machine, may leave the handshake
+ state in QDtls::HandshakeState::HandshakeInProgress, or switch to QDtls::HandshakeState::HandshakeComplete
+ or QDtls::HandshakeState::PeerVerificationFailed.
+
+ This function may store the peer's certificate (or chain of certificates), extract and store
+ the information about the negotiated session protocol and ciphersuite.
+
+ \sa startHandshake()
+*/
+
+/*!
+ \fn bool DtlsCryptograph::resumeHandshake(QUdpSocket *socket)
+ \internal
+
+ If peer validation errors were found duing the handshake, this function tries to
+ continue and complete the handshake. If errors were ignored, the function switches
+ this object's state to QDtls::HandshakeState::HandshakeComplete and returns \c true.
+
+ \sa abortHandshake()
+*/
+
+/*!
+ \fn void DtlsCryptograph::abortHandshake(QUdpSocket *socket)
+ \internal
+
+ Aborts the handshake if it's in progress or in the state QDtls::HandshakeState::PeerVerificationFailed.
+ The use of \a socket is implementation-specific (for example, this DtlsCryptograph may send
+ ShutdownAlert message).
+
+ \sa resumeHandshake()
+*/
+
+/*!
+ \fn void DtlsCryptograph::sendShutdownAlert(QUdpSocket *socket)
+ \internal
+
+ If the underlying TLS library provides the required functionality, this function
+ may sent ShutdownAlert message using \a socket.
+*/
+
+/*!
+ \fn QList<QSslError> DtlsCryptograph::peerVerificationErrors() const
+ \internal
+
+ Returns the list of errors that this object encountered during DTLS handshake
+ and certificate validation.
+
+ \sa ignoreVerificationErrors()
+*/
+
+/*!
+ \fn void DtlsCryptograph::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
+ \internal
+
+ Tells this object to ignore errors from \a errorsToIgnore when they are found during
+ DTLS handshake.
+
+ \sa peerVerificationErrors()
+*/
+
+/*!
+ \fn QSslCipher DtlsCryptograph::dtlsSessionCipher() const
+ \internal
+
+ If such information is available, returns the ciphersuite, negotiated during
+ the handshake.
+
+ \sa continueHandshake(), dtlsSessionProtocol()
+*/
+
+/*!
+ \fn QSsl::SslProtocol DtlsCryptograph::dtlsSessionProtocol() const
+ \internal
+
+ Returns the version of the session protocol that was negotiated during the handshake or
+ QSsl::UnknownProtocol if the handshake is incomplete or no information about the session
+ protocol is available.
+
+ \sa continueHandshake(), dtlsSessionCipher()
+*/
+
+/*!
+ \fn qint64 DtlsCryptograph::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, this function
+ encrypts \a dgram and writes this encrypted data into \a socket.
+
+ Returns the number of bytes (of \a dgram) written, or -1 in case of error. This function should
+ set the error code and description if some error was encountered.
+
+ \sa decryptDatagram()
+*/
+
+/*!
+ \fn QByteArray DtlsCryptograph::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
+ \internal
+
+ If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, decrypts \a dgram.
+ The use of \a socket is implementation-specific. This function should return an empty byte array
+ and set the error code and description if some error was encountered.
+*/
+
+#endif // QT_CONFIG(dtls)
+#endif // QT_CONFIG(ssl)
+
+} // namespace QTlsPrivate
+
+#if QT_CONFIG(ssl)
+/*!
+ \internal
+*/
+Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
+{
+ if (auto *backend = QSslSocketPrivate::tlsBackendInUse())
+ backend->forceAutotestSecurityLevel();
+}
+
+#endif // QT_CONFIG(ssl)
+
+QT_END_NAMESPACE
+
+#include "moc_qtlsbackend_p.cpp"
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
new file mode 100644
index 0000000000..090531014b
--- /dev/null
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -0,0 +1,402 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTLSBACKEND_P_H
+#define QTLSBACKEND_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 "qsslconfiguration.h"
+#include "qsslerror.h"
+#include "qssl_p.h"
+
+#if QT_CONFIG(dtls)
+#include "qdtls.h"
+#endif
+
+#include <QtNetwork/qsslcertificate.h>
+#include <QtNetwork/qsslcipher.h>
+#include <QtNetwork/qsslkey.h>
+#include <QtNetwork/qssl.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QSslPreSharedKeyAuthenticator;
+class QSslSocketPrivate;
+class QHostAddress;
+class QSslContext;
+
+class QSslSocket;
+class QByteArray;
+class QSslCipher;
+class QUdpSocket;
+class QIODevice;
+class QSslError;
+class QSslKey;
+
+namespace QTlsPrivate {
+
+class Q_NETWORK_EXPORT TlsKey {
+public:
+ virtual ~TlsKey();
+
+ using KeyType = QSsl::KeyType;
+ using KeyAlgorithm = QSsl::KeyAlgorithm;
+
+ virtual void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der,
+ const QByteArray &passPhrase, bool deepClear) = 0;
+ virtual void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
+ const QByteArray &passPhrase, bool deepClear) = 0;
+
+ virtual QByteArray toPem(const QByteArray &passPhrase) const = 0;
+ virtual QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const = 0;
+ virtual QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const = 0;
+
+ virtual void fromHandle(Qt::HANDLE handle, KeyType type) = 0;
+ virtual Qt::HANDLE handle() const = 0;
+
+ virtual bool isNull() const = 0;
+ virtual KeyType type() const = 0;
+ virtual KeyAlgorithm algorithm() const = 0;
+ virtual int length() const = 0;
+
+ virtual void clear(bool deepClear) = 0;
+
+ virtual bool isPkcs8() const = 0;
+
+ virtual QByteArray decrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &passPhrase, const QByteArray &iv) const = 0;
+ virtual QByteArray encrypt(Cipher cipher, const QByteArray &data,
+ const QByteArray &key, const QByteArray &iv) const = 0;
+
+ QByteArray pemHeader() const;
+ QByteArray pemFooter() const;
+};
+
+class Q_NETWORK_EXPORT X509Certificate
+{
+public:
+ virtual ~X509Certificate();
+
+ virtual bool isEqual(const X509Certificate &other) const = 0;
+ virtual bool isNull() const = 0;
+ virtual bool isSelfSigned() const = 0;
+ virtual QByteArray version() const = 0;
+ virtual QByteArray serialNumber() const = 0;
+ virtual QStringList issuerInfo(QSslCertificate::SubjectInfo subject) const = 0;
+ virtual QStringList issuerInfo(const QByteArray &attribute) const = 0;
+ virtual QStringList subjectInfo(QSslCertificate::SubjectInfo subject) const = 0;
+ virtual QStringList subjectInfo(const QByteArray &attribute) const = 0;
+
+ virtual QList<QByteArray> subjectInfoAttributes() const = 0;
+ virtual QList<QByteArray> issuerInfoAttributes() const = 0;
+ virtual QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const = 0;
+ virtual QDateTime effectiveDate() const = 0;
+ virtual QDateTime expiryDate() const = 0;
+
+ virtual TlsKey *publicKey() const;
+
+ // Extensions. Plugins do not expose internal representation
+ // and cannot rely on QSslCertificate's internals. Thus,
+ // we provide this information 'in pieces':
+ virtual qsizetype numberOfExtensions() const = 0;
+ virtual QString oidForExtension(qsizetype i) const = 0;
+ virtual QString nameForExtension(qsizetype i) const = 0;
+ virtual QVariant valueForExtension(qsizetype i) const = 0;
+ virtual bool isExtensionCritical(qsizetype i) const = 0;
+ virtual bool isExtensionSupported(qsizetype i) const = 0;
+
+ virtual QByteArray toPem() const = 0;
+ virtual QByteArray toDer() const = 0;
+ virtual QString toText() const = 0;
+
+ virtual Qt::HANDLE handle() const = 0;
+
+ virtual size_t hash(size_t seed) const noexcept = 0;
+};
+
+// TLSTODO: consider making those into virtuals in QTlsBackend. After all, we ask the backend
+// to return those pointers if the functionality is supported, but it's a bit odd to have
+// this level of indirection. They are not parts of the classes above because ...
+// you'd then have to ask backend to create a certificate to ... call those
+// functions on a certificate.
+using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain,
+ const QString &hostName);
+using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count);
+using X509DerReaderPtr = X509PemReaderPtr;
+using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase);
+
+#if QT_CONFIG(ssl)
+// TLS over TCP. Handshake, encryption/decryption.
+class Q_NETWORK_EXPORT TlsCryptograph : public QObject
+{
+public:
+ virtual ~TlsCryptograph();
+
+ virtual void init(QSslSocket *q, QSslSocketPrivate *d) = 0;
+ virtual void checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext);
+ virtual std::shared_ptr<QSslContext> sslContext() const;
+
+ virtual QList<QSslError> tlsErrors() const = 0;
+
+ virtual void startClientEncryption() = 0;
+ virtual void startServerEncryption() = 0;
+ virtual void continueHandshake() = 0;
+ virtual void enableHandshakeContinuation();
+ virtual void disconnectFromHost() = 0;
+ virtual void disconnected() = 0;
+ virtual void cancelCAFetch();
+ virtual QSslCipher sessionCipher() const = 0;
+ virtual QSsl::SslProtocol sessionProtocol() const = 0;
+
+ virtual void transmit() = 0;
+ virtual bool hasUndecryptedData() const;
+ virtual QList<QOcspResponse> ocsps() const;
+
+ static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
+
+ void setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode,
+ const QString &errorDescription) const;
+};
+#else
+class TlsCryptograph;
+#endif // QT_CONFIG(ssl)
+
+#if QT_CONFIG(dtls)
+
+class Q_NETWORK_EXPORT DtlsBase
+{
+public:
+ virtual ~DtlsBase();
+
+ virtual void setDtlsError(QDtlsError code, const QString &description) = 0;
+
+ virtual QDtlsError error() const = 0;
+ virtual QString errorString() const = 0;
+
+ virtual void clearDtlsError() = 0;
+
+ virtual void setConfiguration(const QSslConfiguration &configuration) = 0;
+ virtual QSslConfiguration configuration() const = 0;
+
+ using GenParams = QDtlsClientVerifier::GeneratorParameters;
+ virtual bool setCookieGeneratorParameters(const GenParams &params) = 0;
+ virtual GenParams cookieGeneratorParameters() const = 0;
+};
+
+// DTLS cookie: generation and verification.
+class Q_NETWORK_EXPORT DtlsCookieVerifier : virtual public DtlsBase
+{
+public:
+ virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
+ const QHostAddress &address, quint16 port) = 0;
+ virtual QByteArray verifiedHello() const = 0;
+};
+
+// TLS over UDP. Handshake, encryption/decryption.
+class Q_NETWORK_EXPORT DtlsCryptograph : virtual public DtlsBase
+{
+public:
+
+ virtual QSslSocket::SslMode cryptographMode() const = 0;
+ virtual void setPeer(const QHostAddress &addr, quint16 port, const QString &name) = 0;
+ virtual QHostAddress peerAddress() const = 0;
+ virtual quint16 peerPort() const = 0;
+ virtual void setPeerVerificationName(const QString &name) = 0;
+ virtual QString peerVerificationName() const = 0;
+
+ virtual void setDtlsMtuHint(quint16 mtu) = 0;
+ virtual quint16 dtlsMtuHint() const = 0;
+
+ virtual QDtls::HandshakeState state() const = 0;
+ virtual bool isConnectionEncrypted() const = 0;
+
+ virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool handleTimeout(QUdpSocket *socket) = 0;
+ virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual bool resumeHandshake(QUdpSocket *socket) = 0;
+ virtual void abortHandshake(QUdpSocket *socket) = 0;
+ virtual void sendShutdownAlert(QUdpSocket *socket) = 0;
+
+ virtual QList<QSslError> peerVerificationErrors() const = 0;
+ virtual void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) = 0;
+
+ virtual QSslCipher dtlsSessionCipher() const = 0;
+ virtual QSsl::SslProtocol dtlsSessionProtocol() const = 0;
+
+ virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0;
+ virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0;
+};
+
+#else
+
+class DtlsCookieVerifier;
+class DtlsCryptograph;
+
+#endif // QT_CONFIG(dtls)
+
+} // namespace QTlsPrivate
+
+// Factory, creating back-end specific implementations of
+// different entities QSslSocket is using.
+class Q_NETWORK_EXPORT QTlsBackend : public QObject
+{
+ Q_OBJECT
+public:
+ QTlsBackend();
+ ~QTlsBackend() override;
+
+ virtual bool isValid() const;
+ virtual long tlsLibraryVersionNumber() const;
+ virtual QString tlsLibraryVersionString() const;
+ virtual long tlsLibraryBuildVersionNumber() const;
+ virtual QString tlsLibraryBuildVersionString() const;
+ virtual void ensureInitialized() const;
+
+ virtual QString backendName() const = 0;
+ virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
+ virtual QList<QSsl::SupportedFeature> supportedFeatures() const = 0;
+ virtual QList<QSsl::ImplementedClass> implementedClasses() const = 0;
+
+ // X509 and keys:
+ virtual QTlsPrivate::TlsKey *createKey() const;
+ virtual QTlsPrivate::X509Certificate *createCertificate() const;
+
+ virtual QList<QSslCertificate> systemCaCertificates() const;
+
+ // TLS and DTLS:
+ virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const;
+ virtual QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) const;
+ virtual QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const;
+
+ // TLSTODO - get rid of these function pointers, make them virtuals in
+ // the backend itself. X509 machinery:
+ virtual QTlsPrivate::X509ChainVerifyPtr X509Verifier() const;
+ virtual QTlsPrivate::X509PemReaderPtr X509PemReader() const;
+ virtual QTlsPrivate::X509DerReaderPtr X509DerReader() const;
+ virtual QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const;
+
+ // Elliptic curves:
+ virtual QList<int> ellipticCurvesIds() const;
+ virtual int curveIdFromShortName(const QString &name) const;
+ virtual int curveIdFromLongName(const QString &name) const;
+ virtual QString shortNameForId(int cid) const;
+ virtual QString longNameForId(int cid) const;
+ virtual bool isTlsNamedCurve(int cid) const;
+
+ // Note: int and not QSslDiffieHellmanParameter::Error - because this class and
+ // its enum are QT_CONFIG(ssl)-conditioned. But not QTlsBackend and
+ // its virtual functions. DH decoding:
+ virtual int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const;
+ virtual int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const;
+
+ static QList<QString> availableBackendNames();
+ static QString defaultBackendName();
+ static QTlsBackend *findBackend(const QString &backendName);
+ static QTlsBackend *activeOrAnyBackend();
+
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName);
+
+ // Built-in, this is what Qt provides out of the box (depending on OS):
+ 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[];
+
+ template<class DynamicType, class TLSObject>
+ static DynamicType *backend(const TLSObject &o)
+ {
+ return static_cast<DynamicType *>(o.d->backend.get());
+ }
+
+ static void resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend);
+
+ static void setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint,
+ int hintLength, unsigned maxIdentityLen, unsigned maxPskLen);
+ static void setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity,
+ const QByteArray &identityHint, unsigned maxPskLen);
+#if QT_CONFIG(ssl)
+ static QSslCipher createCiphersuite(const QString &description, int bits, int supportedBits);
+ static QSslCipher createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol,
+ const QString &protocolString);
+ static QSslCipher createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString);
+
+ // Those statics are implemented using QSslSocketPrivate (which is not exported,
+ // unlike QTlsBackend).
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> defaultDtlsCiphers();
+
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
+
+ static void resetDefaultEllipticCurves();
+
+ static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
+
+ // Many thanks to people who designed QSslConfiguration with hidden
+ // data-members, that sneakily set by some 'friend' classes, having
+ // some twisted logic.
+ static bool rootLoadingOnDemandAllowed(const QSslConfiguration &configuration);
+ static void storePeerCertificate(QSslConfiguration &configuration, const QSslCertificate &peerCert);
+ static void storePeerCertificateChain(QSslConfiguration &configuration,
+ const QList<QSslCertificate> &peerCertificateChain);
+ static void clearPeerCertificates(QSslConfiguration &configuration);
+ // And those are even worse, this is where we don't have the original configuration,
+ // and can have only a copy. So instead we go to d->privateConfiguration.someMember:
+ static void clearPeerCertificates(QSslSocketPrivate *d);
+ static void setPeerSessionShared(QSslSocketPrivate *d, bool shared);
+ static void setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1);
+ static void setSessionLifetimeHint(QSslSocketPrivate *d, int hint);
+ using AlpnNegotiationStatus = QSslConfiguration::NextProtocolNegotiationStatus;
+ static void setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st);
+ static void setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol);
+ static void storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert);
+ static void storePeerCertificateChain(QSslSocketPrivate *d, const QList<QSslCertificate> &peerChain);
+ static void addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert);// TODO: "addTrusted..."
+ // 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)
+};
+
+#define QTlsBackend_iid "org.qt-project.Qt.QTlsBackend"
+Q_DECLARE_INTERFACE(QTlsBackend, QTlsBackend_iid);
+
+QT_END_NAMESPACE
+
+#endif // QTLSBACKEND_P_H
diff --git a/src/network/ssl/qwindowscarootfetcher.cpp b/src/network/ssl/qwindowscarootfetcher.cpp
deleted file mode 100644
index c414ca580b..0000000000
--- a/src/network/ssl/qwindowscarootfetcher.cpp
+++ /dev/null
@@ -1,289 +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 "qsslsocket_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 {
-
-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 = QSslSocketBackendPrivate::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) << "QSslSocketBackendPrivate::fetchCaRootForCert - 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 e98e59f0cf..0000000000
--- a/src/network/ssl/qwindowscarootfetcher_p.h
+++ /dev/null
@@ -1,95 +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 QWINDOWSCAROOTFETCHER_P_H
-#define QWINDOWSCAROOTFETCHER_P_H
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QObject>
-
-#include "qsslsocket_p.h"
-
-#include "qsslsocket.h"
-#include "qsslcertificate.h"
-
-#include <memory>
-
-//
-// 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/ssl.pri b/src/network/ssl/ssl.pri
deleted file mode 100644
index c1eb3d169e..0000000000
--- a/src/network/ssl/ssl.pri
+++ /dev/null
@@ -1,122 +0,0 @@
-HEADERS += ssl/qasn1element_p.h \
- ssl/qssl.h \
- ssl/qssl_p.h \
- ssl/qsslcertificate.h \
- ssl/qsslcertificate_p.h \
- ssl/qsslcertificateextension.h \
- ssl/qsslcertificateextension_p.h \
- ssl/qtls_utils_p.h
-
-SOURCES += ssl/qasn1element.cpp \
- ssl/qssl.cpp \
- ssl/qsslcertificate.cpp \
- ssl/qsslcertificateextension.cpp
-
-!qtConfig(openssl): SOURCES += ssl/qsslcertificate_qt.cpp
-
-qtConfig(ssl) {
- HEADERS += ssl/qsslconfiguration.h \
- ssl/qsslconfiguration_p.h \
- ssl/qsslcipher.h \
- ssl/qsslcipher_p.h \
- ssl/qssldiffiehellmanparameters.h \
- ssl/qssldiffiehellmanparameters_p.h \
- ssl/qsslellipticcurve.h \
- ssl/qsslerror.h \
- ssl/qsslkey.h \
- ssl/qsslkey_p.h \
- ssl/qsslsocket.h \
- ssl/qsslsocket_p.h \
- ssl/qsslpresharedkeyauthenticator.h \
- ssl/qsslpresharedkeyauthenticator_p.h \
- ssl/qocspresponse.h \
- ssl/qocspresponse_p.h
- SOURCES += ssl/qsslconfiguration.cpp \
- ssl/qsslcipher.cpp \
- ssl/qssldiffiehellmanparameters.cpp \
- ssl/qsslellipticcurve.cpp \
- ssl/qsslkey_p.cpp \
- ssl/qsslerror.cpp \
- ssl/qsslsocket.cpp \
- ssl/qsslpresharedkeyauthenticator.cpp \
- ssl/qocspresponse.cpp
-
- qtConfig(schannel) {
- HEADERS += ssl/qsslsocket_schannel_p.h
- SOURCES += ssl/qsslsocket_schannel.cpp \
- ssl/qsslcertificate_schannel.cpp \
- ssl/qsslkey_schannel.cpp \
- ssl/qsslkey_qt.cpp \
- ssl/qssldiffiehellmanparameters_dummy.cpp \
- ssl/qsslellipticcurve_dummy.cpp \
- ssl/qsslsocket_qt.cpp
-
- LIBS_PRIVATE += "-lSecur32" "-lCrypt32" "-lbcrypt" "-lncrypt"
- }
-
- qtConfig(securetransport) {
- HEADERS += ssl/qsslsocket_mac_p.h
- SOURCES += ssl/qssldiffiehellmanparameters_dummy.cpp \
- ssl/qsslkey_qt.cpp \
- ssl/qsslkey_mac.cpp \
- ssl/qsslsocket_mac_shared.cpp \
- ssl/qsslsocket_mac.cpp \
- ssl/qsslsocket_qt.cpp \
- ssl/qsslellipticcurve_dummy.cpp
- }
-
- qtConfig(dtls) {
- HEADERS += ssl/qdtls.h \
- ssl/qdtls_p.h
-
- SOURCES += ssl/qdtls.cpp
- }
-
- qtConfig(openssl) {
- HEADERS += ssl/qsslcontext_openssl_p.h \
- ssl/qsslsocket_openssl_p.h \
- ssl/qsslsocket_openssl_symbols_p.h
- SOURCES += ssl/qsslsocket_openssl_symbols.cpp \
- ssl/qssldiffiehellmanparameters_openssl.cpp \
- ssl/qsslcertificate_openssl.cpp \
- ssl/qsslellipticcurve_openssl.cpp \
- ssl/qsslkey_openssl.cpp \
- ssl/qsslsocket_openssl.cpp \
- ssl/qsslcontext_openssl.cpp \
-
- qtConfig(dtls) {
- HEADERS += ssl/qdtls_openssl_p.h
- SOURCES += ssl/qdtls_openssl.cpp
- }
-
- qtConfig(ocsp): HEADERS += ssl/qocsp_p.h
-
- QMAKE_CXXFLAGS += -DOPENSSL_API_COMPAT=0x10100000L
-
- darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp
-
- android:!android-embedded: SOURCES += ssl/qsslsocket_openssl_android.cpp
-
- # Add optional SSL libs
- # Static linking of OpenSSL with msvc:
- # - Binaries http://slproweb.com/products/Win32OpenSSL.html
- # - also needs -lUser32 -lAdvapi32 -lGdi32 -lCrypt32
- # - libs in <OPENSSL_DIR>\lib\VC\static
- # - configure: -openssl -openssl-linked -I <OPENSSL_DIR>\include -L <OPENSSL_DIR>\lib\VC\static OPENSSL_LIBS="-lUser32 -lAdvapi32 -lGdi32" OPENSSL_LIBS_DEBUG="-lssleay32MDd -llibeay32MDd" OPENSSL_LIBS_RELEASE="-lssleay32MD -llibeay32MD"
-
- qtConfig(openssl-linked): {
- android {
- build_pass|single_android_abi: LIBS_PRIVATE += -lssl_$${QT_ARCH} -lcrypto_$${QT_ARCH}
- } else: QMAKE_USE_FOR_PRIVATE += openssl
- } else: \
- QMAKE_USE_FOR_PRIVATE += openssl/nolink
- win32 {
- LIBS_PRIVATE += -lcrypt32
- HEADERS += ssl/qwindowscarootfetcher_p.h
- SOURCES += ssl/qwindowscarootfetcher.cpp
- }
- }
-}
-
-HEADERS += ssl/qpassworddigestor.h
-SOURCES += ssl/qpassworddigestor.cpp