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

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