1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QDTLS_OPENSSL_P_H
6#define QDTLS_OPENSSL_P_H
7
8#include <QtNetwork/private/qtnetworkglobal_p.h>
9
10#include "qsslcontext_openssl_p.h"
11#include "qtlsbackend_openssl_p.h"
12#include "qtls_openssl_p.h"
13#include "qopenssl_p.h"
14
15#include "../shared/qdtls_base_p.h"
16
17#include <QtNetwork/private/qdtls_p.h>
18
19#include <QtNetwork/qsslpresharedkeyauthenticator.h>
20#include <QtNetwork/qhostaddress.h>
21
22#include <QtCore/qbasictimer.h>
23#include <QtCore/qsharedpointer.h>
24#include <QtCore/qbytearray.h>
25#include <QtCore/qglobal.h>
26#include <QtCore/qlist.h>
27
28#include <openssl/ossl_typ.h>
29
30//
31// W A R N I N G
32// -------------
33//
34// This file is not part of the Qt API. It exists purely as an
35// implementation detail. This header file may change from version to
36// version without notice, or even be removed.
37//
38// We mean it.
39//
40
41QT_REQUIRE_CONFIG(openssl);
42QT_REQUIRE_CONFIG(dtls);
43
44QT_BEGIN_NAMESPACE
45
46class QDtlsPrivateOpenSSL;
47class QDtlsBasePrivate;
48class QUdpSocket;
49
50namespace dtlsopenssl
51{
52
53class DtlsState
54{
55public:
56 // Note, bioMethod _must_ outlive BIOs it was used to create. Thus
57 // the order of declarations here matters.
58 using BioMethod = QSharedPointer<BIO_METHOD>;
59 BioMethod bioMethod;
60
61 using TlsContext = std::shared_ptr<QSslContext>;
62 TlsContext tlsContext;
63
64 using TlsConnection = QSharedPointer<SSL>;
65 TlsConnection tlsConnection;
66
67 QByteArray dgram;
68
69 QHostAddress remoteAddress;
70 quint16 remotePort = 0;
71
72 QList<QSslErrorEntry> x509Errors;
73
74 long peeking = false;
75 QUdpSocket *udpSocket = nullptr;
76 bool writeSuppressed = false;
77
78 bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
79 const QHostAddress &remote, quint16 port,
80 const QByteArray &receivedMessage);
81
82 void reset();
83
84 QDtlsPrivateOpenSSL *dtlsPrivate = nullptr;
85 QByteArray secret;
86
87 QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
88
89private:
90
91 bool initTls(QDtlsBasePrivate *dtlsBase);
92 bool initCtxAndConnection(QDtlsBasePrivate *dtlsBase);
93 bool initBIO(QDtlsBasePrivate *dtlsBase);
94 void setLinkMtu(QDtlsBasePrivate *dtlsBase);
95};
96
97} // namespace dtlsopenssl
98
99// The trick with 'right' ancestor in the tree overriding (only once) some shared
100// virtual functions is intentional. Too bad MSVC warns me about ... exactly the
101// feature of C++ that I want to use.
102
103QT_WARNING_PUSH
104QT_WARNING_DISABLE_MSVC(4250)
105
106class QDtlsClientVerifierOpenSSL : public QTlsPrivate::DtlsCookieVerifier, public QDtlsBasePrivate
107{
108public:
109 QDtlsClientVerifierOpenSSL();
110
111 bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
112 const QHostAddress &address, quint16 port) override;
113 QByteArray verifiedHello() const override;
114
115private:
116 dtlsopenssl::DtlsState dtls;
117 QByteArray verifiedClientHello;
118};
119
120class QDtlsPrivateOpenSSL : public QTlsPrivate::DtlsCryptograph, public QDtlsBasePrivate
121{
122public:
123
124 QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode mode);
125
126private:
127
128 QSslSocket::SslMode cryptographMode() const override;
129 void setPeer(const QHostAddress &addr, quint16 port, const QString &name) override;
130 QHostAddress peerAddress() const override;
131 quint16 peerPort() const override;
132 void setPeerVerificationName(const QString &name) override;
133 QString peerVerificationName() const override;
134
135 virtual void setDtlsMtuHint(quint16 mtu) override;
136 virtual quint16 dtlsMtuHint() const override;
137
138 virtual QDtls::HandshakeState state() const override;
139 virtual bool isConnectionEncrypted() const override;
140
141 bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
142 bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
143 bool resumeHandshake(QUdpSocket *socket) override;
144 void abortHandshake(QUdpSocket *socket) override;
145 bool handleTimeout(QUdpSocket *socket) override;
146 void sendShutdownAlert(QUdpSocket *socket) override;
147
148 QList<QSslError> peerVerificationErrors() const override;
149 void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) override;
150
151 QSslCipher dtlsSessionCipher() const override;
152 QSsl::SslProtocol dtlsSessionProtocol() const override;
153
154 qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
155 QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
156
157public:
158 unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
159 unsigned char *psk, unsigned max_psk_len);
160 unsigned pskServerCallback(const char *identity, unsigned char *psk,
161 unsigned max_psk_len);
162
163private:
164
165 bool verifyPeer();
166 void storePeerCertificates();
167 bool tlsErrorsWereIgnored() const;
168 void fetchNegotiatedParameters();
169 void reportTimeout();
170 void resetDtls();
171
172 QList<QSslErrorEntry> opensslErrors;
173 dtlsopenssl::DtlsState dtls;
174
175 // We have to externally handle timeouts since we have non-blocking
176 // sockets and OpenSSL(DTLS) with non-blocking UDP sockets does not
177 // know if a timeout has occurred.
178 struct TimeoutHandler : QObject
179 {
180 TimeoutHandler() = default;
181
182 void start(int hintMs = 0);
183 void doubleTimeout();
184 void resetTimeout() {timeoutMs = 1000;}
185 void stop();
186 void timerEvent(QTimerEvent *event) override;
187
188 QBasicTimer timer;
189 int timeoutMs = 1000;
190
191 QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
192 };
193
194 QDtls *q = nullptr;
195 QDtls::HandshakeState handshakeState = QDtls::HandshakeNotStarted;
196
197 QList<QSslError> tlsErrors;
198 QList<QSslError> tlsErrorsToIgnore;
199 bool connectionEncrypted = false;
200 // We will initialize it 'lazily', just in case somebody wants to move
201 // QDtls to another thread.
202 QScopedPointer<TimeoutHandler> timeoutHandler;
203 bool connectionWasShutdown = false;
204 QSslPreSharedKeyAuthenticator pskAuthenticator;
205 QByteArray identityHint;
206};
207
208QT_WARNING_POP // C4250
209
210QT_END_NAMESPACE
211
212#endif // QDTLS_OPENSSL_P_H
213

source code of qtbase/src/plugins/tls/openssl/qdtls_openssl_p.h