1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QDTLS_OPENSSL_P_H
41 #define QDTLS_OPENSSL_P_H
42 
43 #include <private/qtnetworkglobal_p.h>
44 
45 #include <QtCore/qglobal.h>
46 
47 #include <openssl/ossl_typ.h>
48 
49 #include "qdtls_p.h"
50 
51 #include <private/qsslcontext_openssl_p.h>
52 #include <private/qsslsocket_openssl_p.h>
53 
54 #include <QtNetwork/qsslpresharedkeyauthenticator.h>
55 #include <QtNetwork/qhostaddress.h>
56 
57 #include <QtCore/qcryptographichash.h>
58 #include <QtCore/qsharedpointer.h>
59 #include <QtCore/qbytearray.h>
60 #include <QtCore/qvector.h>
61 
62 //
63 //  W A R N I N G
64 //  -------------
65 //
66 // This file is not part of the Qt API.  It exists purely as an
67 // implementation detail.  This header file may change from version to
68 // version without notice, or even be removed.
69 //
70 // We mean it.
71 //
72 
73 QT_REQUIRE_CONFIG(openssl);
74 QT_REQUIRE_CONFIG(dtls);
75 
76 QT_BEGIN_NAMESPACE
77 
78 class QDtlsPrivateOpenSSL;
79 class QUdpSocket;
80 
81 namespace dtlsopenssl
82 {
83 
84 class DtlsState
85 {
86 public:
87     // Note, bioMethod _must_ outlive BIOs it was used to create. Thus
88     // the order of declarations here matters.
89     using BioMethod = QSharedPointer<BIO_METHOD>;
90     BioMethod bioMethod;
91 
92     using TlsContext = QSharedPointer<QSslContext>;
93     TlsContext tlsContext;
94 
95     using TlsConnection = QSharedPointer<SSL>;
96     TlsConnection tlsConnection;
97 
98     QByteArray dgram;
99 
100     QHostAddress remoteAddress;
101     quint16 remotePort = 0;
102 
103     QVector<QSslErrorEntry> x509Errors;
104 
105     long peeking = false;
106     QUdpSocket *udpSocket = nullptr;
107     bool writeSuppressed = false;
108 
109     bool init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket,
110               const QHostAddress &remote, quint16 port,
111               const QByteArray &receivedMessage);
112 
113     void reset();
114 
115     QDtlsPrivateOpenSSL *dtlsPrivate = nullptr;
116     QByteArray secret;
117 
118 #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
119     QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
120 #else
121     QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256;
122 #endif
123 
124 private:
125 
126     bool initTls(QDtlsBasePrivate *dtlsBase);
127     bool initCtxAndConnection(QDtlsBasePrivate *dtlsBase);
128     bool initBIO(QDtlsBasePrivate *dtlsBase);
129     void setLinkMtu(QDtlsBasePrivate *dtlsBase);
130 };
131 
132 } // namespace dtlsopenssl
133 
134 class QDtlsClientVerifierOpenSSL : public QDtlsClientVerifierPrivate
135 {
136 public:
137 
138     QDtlsClientVerifierOpenSSL();
139 
140     bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
141                       const QHostAddress &address, quint16 port) override;
142 
143 private:
144     dtlsopenssl::DtlsState dtls;
145 };
146 
147 class QDtlsPrivateOpenSSL : public QDtlsPrivate
148 {
149 public:
150     QDtlsPrivateOpenSSL();
151 
152     bool startHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
153     bool continueHandshake(QUdpSocket *socket, const QByteArray &datagram) override;
154     bool resumeHandshake(QUdpSocket *socket) override;
155     void abortHandshake(QUdpSocket *socket) override;
156     bool handleTimeout(QUdpSocket *socket) override;
157     void sendShutdownAlert(QUdpSocket *socket) override;
158 
159     qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &datagram) override;
160     QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
161 
162     unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
163                                unsigned char *psk, unsigned max_psk_len);
164     unsigned pskServerCallback(const char *identity, unsigned char *psk,
165                                unsigned max_psk_len);
166 
167 private:
168 
169     bool verifyPeer();
170     void storePeerCertificates();
171     bool tlsErrorsWereIgnored() const;
172     void fetchNegotiatedParameters();
173     void reportTimeout();
174     void resetDtls();
175 
176     QVector<QSslErrorEntry> opensslErrors;
177     dtlsopenssl::DtlsState dtls;
178 
179     // We have to externally handle timeouts since we have non-blocking
180     // sockets and OpenSSL(DTLS) with non-blocking UDP sockets does not
181     // know if a timeout has occurred.
182     struct TimeoutHandler : QObject
183     {
184         TimeoutHandler() = default;
185 
186         void start(int hintMs = 0);
187         void doubleTimeout();
resetTimeoutTimeoutHandler188         void resetTimeout() {timeoutMs = 1000;}
189         void stop();
190         void timerEvent(QTimerEvent *event);
191 
192         int timerId = -1;
193         int timeoutMs = 1000;
194 
195         QDtlsPrivateOpenSSL *dtlsConnection = nullptr;
196     };
197 
198     // We will initialize it 'lazily', just in case somebody wants to move
199     // QDtls to another thread.
200     QScopedPointer<TimeoutHandler> timeoutHandler;
201     bool connectionWasShutdown = false;
202     QSslPreSharedKeyAuthenticator pskAuthenticator;
203     QByteArray identityHint;
204 
205     Q_DECLARE_PUBLIC(QDtls)
206 };
207 
208 
209 
210 QT_END_NAMESPACE
211 
212 #endif // QDTLS_OPENSSL_P_H
213