/src/qtbase/src/plugins/tls/openssl/qdtls_openssl.cpp
Line | Count | Source |
1 | | // Copyright (C) 2018 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:critical reason:cryptography |
4 | | |
5 | | #include <QtNetwork/private/qnativesocketengine_p_p.h> |
6 | | |
7 | | #include "qsslsocket_openssl_symbols_p.h" |
8 | | #include "qdtls_openssl_p.h" |
9 | | #include "qx509_openssl_p.h" |
10 | | |
11 | | #include <QtNetwork/private/qsslpresharedkeyauthenticator_p.h> |
12 | | #include <QtNetwork/private/qsslcertificate_p.h> |
13 | | #include <QtNetwork/private/qssl_p.h> |
14 | | |
15 | | #include <QtNetwork/qudpsocket.h> |
16 | | |
17 | | #include <QtCore/qmessageauthenticationcode.h> |
18 | | #include <QtCore/qcryptographichash.h> |
19 | | |
20 | | #include <QtCore/qdebug.h> |
21 | | |
22 | | #include <cstring> |
23 | | #include <cstddef> |
24 | | |
25 | | QT_BEGIN_NAMESPACE |
26 | | |
27 | | #define QT_DTLS_VERBOSE 0 |
28 | | |
29 | | #if QT_DTLS_VERBOSE |
30 | | |
31 | | #define qDtlsWarning(arg) qWarning(arg) |
32 | | #define qDtlsDebug(arg) qDebug(arg) |
33 | | |
34 | | #else |
35 | | |
36 | | #define qDtlsWarning(arg) |
37 | | #define qDtlsDebug(arg) |
38 | | |
39 | | #endif // QT_DTLS_VERBOSE |
40 | | |
41 | | namespace dtlsutil |
42 | | { |
43 | | |
44 | | QByteArray cookie_for_peer(SSL *ssl) |
45 | 0 | { |
46 | 0 | Q_ASSERT(ssl); |
47 | | |
48 | | // SSL_get_rbio does not increment the reference count |
49 | 0 | BIO *readBIO = q_SSL_get_rbio(ssl); |
50 | 0 | if (!readBIO) { |
51 | 0 | qCWarning(lcTlsBackend, "No BIO (dgram) found in SSL object"); |
52 | 0 | return {}; |
53 | 0 | } |
54 | | |
55 | 0 | auto listener = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(readBIO)); |
56 | 0 | if (!listener) { |
57 | 0 | qCWarning(lcTlsBackend, "BIO_get_app_data returned invalid (nullptr) value"); |
58 | 0 | return {}; |
59 | 0 | } |
60 | | |
61 | 0 | const QHostAddress peerAddress(listener->remoteAddress); |
62 | 0 | const quint16 peerPort(listener->remotePort); |
63 | 0 | QByteArray peerData; |
64 | 0 | if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) { |
65 | 0 | const Q_IPV6ADDR sin6_addr(peerAddress.toIPv6Address()); |
66 | 0 | peerData.resize(int(sizeof sin6_addr + sizeof peerPort)); |
67 | 0 | char *dst = peerData.data(); |
68 | 0 | std::memcpy(dst, &peerPort, sizeof peerPort); |
69 | 0 | dst += sizeof peerPort; |
70 | 0 | std::memcpy(dst, &sin6_addr, sizeof sin6_addr); |
71 | 0 | } else if (peerAddress.protocol() == QAbstractSocket::IPv4Protocol) { |
72 | 0 | const quint32 sin_addr(peerAddress.toIPv4Address()); |
73 | 0 | peerData.resize(int(sizeof sin_addr + sizeof peerPort)); |
74 | 0 | char *dst = peerData.data(); |
75 | 0 | std::memcpy(dst, &peerPort, sizeof peerPort); |
76 | 0 | dst += sizeof peerPort; |
77 | 0 | std::memcpy(dst, &sin_addr, sizeof sin_addr); |
78 | 0 | } else { |
79 | 0 | Q_UNREACHABLE(); |
80 | 0 | } |
81 | | |
82 | 0 | return peerData; |
83 | 0 | } |
84 | | |
85 | | struct FallbackCookieSecret |
86 | | { |
87 | | FallbackCookieSecret() |
88 | 0 | { |
89 | 0 | key.resize(32); |
90 | 0 | const int status = q_RAND_bytes(reinterpret_cast<unsigned char *>(key.data()), |
91 | 0 | key.size()); |
92 | 0 | if (status <= 0) |
93 | 0 | key.clear(); |
94 | 0 | } |
95 | | |
96 | | QByteArray key; |
97 | | |
98 | | Q_DISABLE_COPY_MOVE(FallbackCookieSecret) |
99 | | }; |
100 | | |
101 | | QByteArray fallbackSecret() |
102 | 0 | { |
103 | 0 | static const FallbackCookieSecret generator; |
104 | 0 | return generator.key; |
105 | 0 | } |
106 | | |
107 | | int next_timeoutMs(SSL *tlsConnection) |
108 | 0 | { |
109 | 0 | Q_ASSERT(tlsConnection); |
110 | 0 | timeval timeLeft = {}; |
111 | 0 | q_DTLSv1_get_timeout(tlsConnection, &timeLeft); |
112 | 0 | return timeLeft.tv_sec * 1000; |
113 | 0 | } |
114 | | |
115 | | |
116 | | void delete_connection(SSL *ssl) |
117 | 0 | { |
118 | | // The 'deleter' for QSharedPointer<SSL>. |
119 | 0 | if (ssl) |
120 | 0 | q_SSL_free(ssl); |
121 | 0 | } |
122 | | |
123 | | void delete_BIO_ADDR(BIO_ADDR *bio) |
124 | 0 | { |
125 | | // A deleter for QSharedPointer<BIO_ADDR> |
126 | 0 | if (bio) |
127 | 0 | q_BIO_ADDR_free(bio); |
128 | 0 | } |
129 | | |
130 | | void delete_bio_method(BIO_METHOD *method) |
131 | 0 | { |
132 | | // The 'deleter' for QSharedPointer<BIO_METHOD>. |
133 | 0 | if (method) |
134 | 0 | q_BIO_meth_free(method); |
135 | 0 | } |
136 | | |
137 | | // The path MTU discovery is non-trivial: it's a mix of getsockopt/setsockopt |
138 | | // (IP_MTU/IP6_MTU/IP_MTU_DISCOVER) and fallback MTU values. It's not |
139 | | // supported on all platforms, worse so - imposes specific requirements on |
140 | | // underlying UDP socket etc. So for now, we either try a user-proposed MTU |
141 | | // hint or rely on our own fallback value. As a fallback mtu OpenSSL uses 576 |
142 | | // for IPv4 and 1280 for IPv6 (RFC 791, RFC 2460). To KIS we use 576. This |
143 | | // rather small MTU value does not affect the size that can be read/written |
144 | | // by QDtls, only a handshake (which is allowed to fragment). |
145 | | enum class MtuGuess : long |
146 | | { |
147 | | defaultMtu = 576 |
148 | | }; |
149 | | |
150 | | } // namespace dtlsutil |
151 | | |
152 | | namespace dtlscallbacks |
153 | | { |
154 | | |
155 | | int q_generate_cookie_callback(SSL *ssl, unsigned char *dst, unsigned *cookieLength) |
156 | 0 | { |
157 | 0 | if (!ssl || !dst || !cookieLength) { |
158 | 0 | qCWarning(lcTlsBackend, |
159 | 0 | "Failed to generate cookie - invalid (nullptr) parameter(s)"); |
160 | 0 | return 0; |
161 | 0 | } |
162 | | |
163 | 0 | void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData); |
164 | 0 | if (!generic) { |
165 | 0 | qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, cannot generate cookie"); |
166 | 0 | return 0; |
167 | 0 | } |
168 | | |
169 | 0 | *cookieLength = 0; |
170 | |
|
171 | 0 | auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic); |
172 | 0 | if (!dtls->secret.size()) |
173 | 0 | return 0; |
174 | | |
175 | 0 | const QByteArray peerData(dtlsutil::cookie_for_peer(ssl)); |
176 | 0 | if (!peerData.size()) |
177 | 0 | return 0; |
178 | | |
179 | 0 | QMessageAuthenticationCode hmac(dtls->hashAlgorithm, dtls->secret); |
180 | 0 | hmac.addData(peerData); |
181 | 0 | const QByteArrayView cookie = hmac.resultView(); |
182 | 0 | Q_ASSERT(cookie.size() >= 0); |
183 | | // DTLS1_COOKIE_LENGTH is erroneously 256 bytes long, must be 255 - RFC 6347, 4.2.1. |
184 | 0 | *cookieLength = qMin(DTLS1_COOKIE_LENGTH - 1, cookie.size()); |
185 | 0 | std::memcpy(dst, cookie.constData(), *cookieLength); |
186 | |
|
187 | 0 | return 1; |
188 | 0 | } |
189 | | |
190 | | int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie, unsigned cookieLength) |
191 | 0 | { |
192 | 0 | if (!ssl || !cookie || !cookieLength) { |
193 | 0 | qCWarning(lcTlsBackend, "Could not verify cookie, invalid (nullptr or zero) parameters"); |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | 0 | unsigned char newCookie[DTLS1_COOKIE_LENGTH] = {}; |
198 | 0 | unsigned newCookieLength = 0; |
199 | 0 | if (q_generate_cookie_callback(ssl, newCookie, &newCookieLength) != 1) |
200 | 0 | return 0; |
201 | | |
202 | 0 | return newCookieLength == cookieLength |
203 | 0 | && !q_CRYPTO_memcmp(cookie, newCookie, size_t(cookieLength)); |
204 | 0 | } |
205 | | |
206 | | int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx) |
207 | 0 | { |
208 | 0 | if (!ok) { |
209 | | // Store the error and at which depth the error was detected. |
210 | 0 | SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())); |
211 | 0 | if (!ssl) { |
212 | 0 | qCWarning(lcTlsBackend, "X509_STORE_CTX_get_ex_data returned nullptr, handshake failure"); |
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | 0 | void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData); |
217 | 0 | if (!generic) { |
218 | 0 | qCWarning(lcTlsBackend, "SSL_get_ex_data returned nullptr, handshake failure"); |
219 | 0 | return 0; |
220 | 0 | } |
221 | | |
222 | 0 | auto dtls = static_cast<dtlsopenssl::DtlsState *>(generic); |
223 | 0 | dtls->x509Errors.append(QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx)); |
224 | 0 | } |
225 | | |
226 | | // Always return 1 (OK) to allow verification to continue. We handle the |
227 | | // errors gracefully after collecting all errors, after verification has |
228 | | // completed. |
229 | 0 | return 1; |
230 | 0 | } |
231 | | |
232 | | unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *identity, |
233 | | unsigned max_identity_len, unsigned char *psk, unsigned max_psk_len) |
234 | 0 | { |
235 | 0 | auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl, |
236 | 0 | QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
237 | 0 | if (!dtls) |
238 | 0 | return 0; |
239 | | |
240 | 0 | Q_ASSERT(dtls->dtlsPrivate); |
241 | 0 | return dtls->dtlsPrivate->pskClientCallback(hint, identity, max_identity_len, psk, max_psk_len); |
242 | 0 | } |
243 | | |
244 | | unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsigned char *psk, |
245 | | unsigned max_psk_len) |
246 | 0 | { |
247 | 0 | auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl, |
248 | 0 | QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
249 | 0 | if (!dtls) |
250 | 0 | return 0; |
251 | | |
252 | 0 | Q_ASSERT(dtls->dtlsPrivate); |
253 | 0 | return dtls->dtlsPrivate->pskServerCallback(identity, psk, max_psk_len); |
254 | 0 | } |
255 | | |
256 | | } // namespace dtlscallbacks |
257 | | |
258 | | namespace dtlsbio |
259 | | { |
260 | | |
261 | | int q_dgram_read(BIO *bio, char *dst, int bytesToRead) |
262 | 0 | { |
263 | 0 | if (!bio || !dst || bytesToRead <= 0) { |
264 | 0 | qCWarning(lcTlsBackend, "invalid input parameter(s)"); |
265 | 0 | return 0; |
266 | 0 | } |
267 | | |
268 | 0 | q_BIO_clear_retry_flags(bio); |
269 | |
|
270 | 0 | auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio)); |
271 | | // It's us who set data, if OpenSSL does too, the logic here is wrong |
272 | | // then and we have to use BIO_set_app_data then! |
273 | 0 | Q_ASSERT(dtls); |
274 | 0 | int bytesRead = 0; |
275 | 0 | if (dtls->dgram.size()) { |
276 | 0 | bytesRead = qMin(dtls->dgram.size(), bytesToRead); |
277 | 0 | std::memcpy(dst, dtls->dgram.constData(), bytesRead); |
278 | |
|
279 | 0 | if (!dtls->peeking) |
280 | 0 | dtls->dgram = dtls->dgram.mid(bytesRead); |
281 | 0 | } else { |
282 | 0 | bytesRead = -1; |
283 | 0 | } |
284 | |
|
285 | 0 | if (bytesRead <= 0) |
286 | 0 | q_BIO_set_retry_read(bio); |
287 | |
|
288 | 0 | return bytesRead; |
289 | 0 | } |
290 | | |
291 | | int q_dgram_write(BIO *bio, const char *src, int bytesToWrite) |
292 | 0 | { |
293 | 0 | if (!bio || !src || bytesToWrite <= 0) { |
294 | 0 | qCWarning(lcTlsBackend, "invalid input parameter(s)"); |
295 | 0 | return 0; |
296 | 0 | } |
297 | | |
298 | 0 | q_BIO_clear_retry_flags(bio); |
299 | |
|
300 | 0 | auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio)); |
301 | 0 | Q_ASSERT(dtls); |
302 | 0 | if (dtls->writeSuppressed) { |
303 | | // See the comment in QDtls::startHandshake. |
304 | 0 | return bytesToWrite; |
305 | 0 | } |
306 | | |
307 | 0 | QUdpSocket *udpSocket = dtls->udpSocket; |
308 | 0 | Q_ASSERT(udpSocket); |
309 | |
|
310 | 0 | const QByteArray dgram(QByteArray::fromRawData(src, bytesToWrite)); |
311 | 0 | qint64 bytesWritten = -1; |
312 | 0 | if (udpSocket->state() == QAbstractSocket::ConnectedState) { |
313 | 0 | bytesWritten = udpSocket->write(dgram); |
314 | 0 | } else { |
315 | 0 | bytesWritten = udpSocket->writeDatagram(dgram, dtls->remoteAddress, |
316 | 0 | dtls->remotePort); |
317 | 0 | } |
318 | |
|
319 | 0 | if (bytesWritten <= 0) |
320 | 0 | q_BIO_set_retry_write(bio); |
321 | |
|
322 | 0 | Q_ASSERT(bytesWritten <= std::numeric_limits<int>::max()); |
323 | 0 | return int(bytesWritten); |
324 | 0 | } |
325 | | |
326 | | int q_dgram_puts(BIO *bio, const char *src) |
327 | 0 | { |
328 | 0 | if (!bio || !src) { |
329 | 0 | qCWarning(lcTlsBackend, "invalid input parameter(s)"); |
330 | 0 | return 0; |
331 | 0 | } |
332 | | |
333 | 0 | return q_dgram_write(bio, src, int(std::strlen(src))); |
334 | 0 | } |
335 | | |
336 | | long q_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr) |
337 | 0 | { |
338 | | // This is our custom BIO_ctrl. bio.h defines a lot of BIO_CTRL_* |
339 | | // and BIO_* constants and BIO_somename macros that expands to BIO_ctrl |
340 | | // call with one of those constants as argument. What exactly BIO_ctrl |
341 | | // does - depends on the 'cmd' and the type of BIO (so BIO_ctrl does |
342 | | // not even have a single well-defined value meaning success or failure). |
343 | | // We handle only the most generic commands - the ones documented for |
344 | | // BIO_ctrl - and also DGRAM specific ones. And even for them - in most |
345 | | // cases we do nothing but report a success or some non-error value. |
346 | | // Documents also state: "Source/sink BIOs return an 0 if they do not |
347 | | // recognize the BIO_ctrl() operation." - these are covered by 'default' |
348 | | // label in the switch-statement below. Debug messages in the switch mean: |
349 | | // 1) we got a command that is unexpected for dgram BIO, or: |
350 | | // 2) we do not call any function that would lead to OpenSSL using this |
351 | | // command. |
352 | |
|
353 | 0 | if (!bio) { |
354 | 0 | qCDebug(lcTlsBackend, "invalid 'bio' parameter (nullptr)"); |
355 | 0 | return -1; |
356 | 0 | } |
357 | | |
358 | 0 | auto dtls = static_cast<dtlsopenssl::DtlsState *>(q_BIO_get_app_data(bio)); |
359 | 0 | Q_ASSERT(dtls); |
360 | |
|
361 | 0 | switch (cmd) { |
362 | | // Let's start from the most generic ones, in the order in which they are |
363 | | // documented (as BIO_ctrl): |
364 | 0 | case BIO_CTRL_RESET: |
365 | | // BIO_reset macro. |
366 | | // From documentation: |
367 | | // "BIO_reset() normally returns 1 for success and 0 or -1 for failure. |
368 | | // File BIOs are an exception, they return 0 for success and -1 for |
369 | | // failure." |
370 | | // We have nothing to reset and we are not file BIO. |
371 | 0 | return 1; |
372 | 0 | case BIO_C_FILE_SEEK: |
373 | 0 | case BIO_C_FILE_TELL: |
374 | 0 | qDtlsWarning("Unexpected cmd (BIO_C_FILE_SEEK/BIO_C_FILE_TELL)"); |
375 | | // These are for BIO_seek, BIO_tell. We are not a file BIO. |
376 | | // Non-negative return value means success. |
377 | 0 | return 0; |
378 | 0 | case BIO_CTRL_FLUSH: |
379 | | // BIO_flush, nothing to do, we do not buffer any data. |
380 | | // 0 or -1 means error, 1 - success. |
381 | 0 | return 1; |
382 | 0 | case BIO_CTRL_EOF: |
383 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_EOF)"); |
384 | | // BIO_eof, 1 means EOF read. Makes no sense for us. |
385 | 0 | return 0; |
386 | 0 | case BIO_CTRL_SET_CLOSE: |
387 | | // BIO_set_close with BIO_CLOSE/BIO_NOCLOSE flags. Documented as |
388 | | // always returning 1. |
389 | | // From the documentation: |
390 | | // "Typically BIO_CLOSE is used in a source/sink BIO to indicate that |
391 | | // the underlying I/O stream should be closed when the BIO is freed." |
392 | | // |
393 | | // QUdpSocket we work with is not BIO's business, ignoring. |
394 | 0 | return 1; |
395 | 0 | case BIO_CTRL_GET_CLOSE: |
396 | | // BIO_get_close. No, never, see the comment above. |
397 | 0 | return 0; |
398 | 0 | case BIO_CTRL_PENDING: |
399 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_PENDING)"); |
400 | | // BIO_pending. Not used by DTLS/OpenSSL (we are not buffering). |
401 | 0 | return 0; |
402 | 0 | case BIO_CTRL_WPENDING: |
403 | | // No, we have nothing buffered. |
404 | 0 | return 0; |
405 | | // The constants below are not documented as a part BIO_ctrl documentation, |
406 | | // but they are also not type-specific. |
407 | 0 | case BIO_CTRL_DUP: |
408 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DUP)"); |
409 | | // BIO_dup_state, not used by DTLS (and socket-related BIOs in general). |
410 | | // For some very specific BIO type this 'cmd' would copy some state |
411 | | // from 'bio' to (BIO*)'ptr'. 1 means success. |
412 | 0 | return 0; |
413 | 0 | case BIO_CTRL_SET_CALLBACK: |
414 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_SET_CALLBACK)"); |
415 | | // BIO_set_info_callback. We never call this, OpenSSL does not do this |
416 | | // on its own (normally it's used if client code wants to have some |
417 | | // debug information, for example, dumping handshake state via |
418 | | // BIO_printf from SSL info_callback). |
419 | 0 | return 0; |
420 | 0 | case BIO_CTRL_GET_CALLBACK: |
421 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_GET_CALLBACK)"); |
422 | | // BIO_get_info_callback. We never call this. |
423 | 0 | if (ptr) |
424 | 0 | *static_cast<bio_info_cb **>(ptr) = nullptr; |
425 | 0 | return 0; |
426 | 0 | case BIO_CTRL_SET: |
427 | 0 | case BIO_CTRL_GET: |
428 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_SET/BIO_CTRL_GET)"); |
429 | | // Somewhat 'documented' as setting/getting IO type. Not used anywhere |
430 | | // except BIO_buffer_get_num_lines (which contradics 'get IO type'). |
431 | | // Ignoring. |
432 | 0 | return 0; |
433 | | // DGRAM-specific operation, we have to return some reasonable value |
434 | | // (so far, I've encountered only peek mode switching, connect). |
435 | 0 | case BIO_CTRL_DGRAM_CONNECT: |
436 | | // BIO_ctrl_dgram_connect. Not needed. Our 'dtls' already knows |
437 | | // the peer's address/port. Report success though. |
438 | 0 | return 1; |
439 | 0 | case BIO_CTRL_DGRAM_SET_CONNECTED: |
440 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_CONNECTED)"); |
441 | | // BIO_ctrl_dgram_set_connected. We never call it, OpenSSL does |
442 | | // not call it on its own (so normally it's done by client code). |
443 | | // Similar to BIO_CTRL_DGRAM_CONNECT, but it also informs the BIO |
444 | | // that its UDP socket is connected. We never need it though. |
445 | 0 | return -1; |
446 | 0 | case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: |
447 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_RECV_TIMEOUT)"); |
448 | | // Essentially setsockopt with SO_RCVTIMEO, not needed, our sockets |
449 | | // are non-blocking. |
450 | 0 | return -1; |
451 | 0 | case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: |
452 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_RECV_TIMEOUT)"); |
453 | | // getsockopt with SO_RCVTIMEO, not needed, our sockets are |
454 | | // non-blocking. ptr is timeval *. |
455 | 0 | return -1; |
456 | 0 | case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: |
457 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_SEND_TIMEOUT)"); |
458 | | // setsockopt, SO_SNDTIMEO, cannot happen. |
459 | 0 | return -1; |
460 | 0 | case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: |
461 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_SEND_TIMEOUT)"); |
462 | | // getsockopt, SO_SNDTIMEO, cannot happen. |
463 | 0 | return -1; |
464 | 0 | case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: |
465 | | // BIO_dgram_recv_timedout. No, we are non-blocking. |
466 | 0 | return 0; |
467 | 0 | case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: |
468 | | // BIO_dgram_send_timedout. No, we are non-blocking. |
469 | 0 | return 0; |
470 | 0 | case BIO_CTRL_DGRAM_MTU_DISCOVER: |
471 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_DISCOVER)"); |
472 | | // setsockopt, IP_MTU_DISCOVER/IP6_MTU_DISCOVER, to be done |
473 | | // in QUdpSocket instead. OpenSSL never calls it, only client |
474 | | // code. |
475 | 0 | return 1; |
476 | 0 | case BIO_CTRL_DGRAM_QUERY_MTU: |
477 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_QUERY_MTU)"); |
478 | | // To be done in QUdpSocket instead. |
479 | 0 | return 1; |
480 | 0 | case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: |
481 | 0 | qDtlsWarning("Unexpected command *BIO_CTRL_DGRAM_GET_FALLBACK_MTU)"); |
482 | | // Without SSL_OP_NO_QUERY_MTU set on SSL, OpenSSL can request for |
483 | | // fallback MTU after several re-transmissions. |
484 | | // Should never happen in our case. |
485 | 0 | return long(dtlsutil::MtuGuess::defaultMtu); |
486 | 0 | case BIO_CTRL_DGRAM_GET_MTU: |
487 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_GET_MTU)"); |
488 | 0 | return -1; |
489 | 0 | case BIO_CTRL_DGRAM_SET_MTU: |
490 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_SET_MTU)"); |
491 | | // Should not happen (we don't call BIO_ctrl with this parameter) |
492 | | // and set MTU on SSL instead. |
493 | 0 | return -1; // num is mtu and it's a return value meaning success. |
494 | 0 | case BIO_CTRL_DGRAM_MTU_EXCEEDED: |
495 | 0 | qDtlsWarning("Unexpected cmd (BIO_CTRL_DGRAM_MTU_EXCEEDED)"); |
496 | 0 | return 0; |
497 | 0 | case BIO_CTRL_DGRAM_GET_PEER: |
498 | 0 | qDtlsDebug("BIO_CTRL_DGRAM_GET_PEER"); |
499 | | // BIO_dgram_get_peer. We do not return a real address (DTLS is not |
500 | | // using this address), but let's pretend a success. |
501 | 0 | switch (dtls->remoteAddress.protocol()) { |
502 | 0 | case QAbstractSocket::IPv6Protocol: |
503 | 0 | return sizeof(sockaddr_in6); |
504 | 0 | case QAbstractSocket::IPv4Protocol: |
505 | 0 | return sizeof(sockaddr_in); |
506 | 0 | default: |
507 | 0 | return -1; |
508 | 0 | } |
509 | 0 | case BIO_CTRL_DGRAM_SET_PEER: |
510 | | // Similar to BIO_CTRL_DGRAM_CONNECTED. |
511 | 0 | return 1; |
512 | 0 | case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: |
513 | | // DTLSTODO: I'm not sure yet, how it's used by OpenSSL. |
514 | 0 | return 1; |
515 | 0 | case BIO_CTRL_DGRAM_SET_DONT_FRAG: |
516 | 0 | qDtlsDebug("BIO_CTRL_DGRAM_SET_DONT_FRAG"); |
517 | | // To be done in QUdpSocket, it's about IP_DONTFRAG etc. |
518 | 0 | return 1; |
519 | 0 | case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: |
520 | | // AFAIK it's 28 for IPv4 and 48 for IPv6, but let's pretend it's 0 |
521 | | // so that OpenSSL does not start suddenly fragmenting the first |
522 | | // client hello (which will result in DTLSv1_listen rejecting it). |
523 | 0 | return 0; |
524 | 0 | case BIO_CTRL_DGRAM_SET_PEEK_MODE: |
525 | 0 | dtls->peeking = num; |
526 | 0 | return 1; |
527 | 0 | default:; |
528 | | #if QT_DTLS_VERBOSE |
529 | | qWarning() << "Unexpected cmd (" << cmd << ")"; |
530 | | #endif |
531 | 0 | } |
532 | | |
533 | 0 | return 0; |
534 | 0 | } |
535 | | |
536 | | int q_dgram_create(BIO *bio) |
537 | 0 | { |
538 | |
|
539 | 0 | q_BIO_set_init(bio, 1); |
540 | | // With a custom BIO you'd normally allocate some implementation-specific |
541 | | // data and append it to this new BIO using BIO_set_data. We don't need |
542 | | // it and thus q_dgram_destroy below is a noop. |
543 | 0 | return 1; |
544 | 0 | } |
545 | | |
546 | | int q_dgram_destroy(BIO *bio) |
547 | 0 | { |
548 | 0 | Q_UNUSED(bio); |
549 | 0 | return 1; |
550 | 0 | } |
551 | | |
552 | | const char * const qdtlsMethodName = "qdtlsbio"; |
553 | | |
554 | | } // namespace dtlsbio |
555 | | |
556 | | namespace dtlsopenssl |
557 | | { |
558 | | |
559 | | bool DtlsState::init(QDtlsBasePrivate *dtlsBase, QUdpSocket *socket, |
560 | | const QHostAddress &remote, quint16 port, |
561 | | const QByteArray &receivedMessage) |
562 | 0 | { |
563 | 0 | Q_ASSERT(dtlsBase); |
564 | 0 | Q_ASSERT(socket); |
565 | |
|
566 | 0 | if (!tlsContext && !initTls(dtlsBase)) |
567 | 0 | return false; |
568 | | |
569 | 0 | udpSocket = socket; |
570 | |
|
571 | 0 | setLinkMtu(dtlsBase); |
572 | |
|
573 | 0 | dgram = receivedMessage; |
574 | 0 | remoteAddress = remote; |
575 | 0 | remotePort = port; |
576 | | |
577 | | // SSL_get_rbio does not increment a reference count. |
578 | 0 | BIO *bio = q_SSL_get_rbio(tlsConnection.data()); |
579 | 0 | Q_ASSERT(bio); |
580 | 0 | q_BIO_set_app_data(bio, this); |
581 | |
|
582 | 0 | return true; |
583 | 0 | } |
584 | | |
585 | | void DtlsState::reset() |
586 | 0 | { |
587 | 0 | tlsConnection.reset(); |
588 | 0 | tlsContext.reset(); |
589 | 0 | } |
590 | | |
591 | | bool DtlsState::initTls(QDtlsBasePrivate *dtlsBase) |
592 | 0 | { |
593 | 0 | if (tlsContext) |
594 | 0 | return true; |
595 | | |
596 | 0 | if (!QSslSocket::supportsSsl()) |
597 | 0 | return false; |
598 | | |
599 | 0 | if (!initCtxAndConnection(dtlsBase)) |
600 | 0 | return false; |
601 | | |
602 | 0 | if (!initBIO(dtlsBase)) { |
603 | 0 | tlsConnection.reset(); |
604 | 0 | tlsContext.reset(); |
605 | 0 | return false; |
606 | 0 | } |
607 | | |
608 | 0 | return true; |
609 | 0 | } |
610 | | |
611 | | static QString msgFunctionFailed(const char *function) |
612 | 0 | { |
613 | | //: %1: Some function |
614 | 0 | return QDtls::tr("%1 failed").arg(QLatin1StringView(function)); |
615 | 0 | } |
616 | | |
617 | | bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase) |
618 | 0 | { |
619 | 0 | Q_ASSERT(dtlsBase); |
620 | 0 | Q_ASSERT(QSslSocket::supportsSsl()); |
621 | |
|
622 | 0 | if (dtlsBase->mode == QSslSocket::UnencryptedMode) { |
623 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
624 | 0 | QDtls::tr("Invalid SslMode, SslServerMode or SslClientMode expected")); |
625 | 0 | return false; |
626 | 0 | } |
627 | | |
628 | 0 | if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) { |
629 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
630 | 0 | QDtls::tr("Invalid protocol version, DTLS protocol expected")); |
631 | 0 | return false; |
632 | 0 | } |
633 | | |
634 | 0 | const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration); |
635 | 0 | TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration, |
636 | 0 | rootsOnDemand)); |
637 | |
|
638 | 0 | if (newContext->error() != QSslError::NoError) { |
639 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString()); |
640 | 0 | return false; |
641 | 0 | } |
642 | | |
643 | 0 | TlsConnection newConnection(newContext->createSsl(), dtlsutil::delete_connection); |
644 | 0 | if (!newConnection.data()) { |
645 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
646 | 0 | msgFunctionFailed("SSL_new")); |
647 | 0 | return false; |
648 | 0 | } |
649 | | |
650 | 0 | const int set = q_SSL_set_ex_data(newConnection.data(), |
651 | 0 | QTlsBackendOpenSSL::s_indexForSSLExtraData, |
652 | 0 | this); |
653 | |
|
654 | 0 | if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) { |
655 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
656 | 0 | msgFunctionFailed("SSL_set_ex_data")); |
657 | 0 | return false; |
658 | 0 | } |
659 | | |
660 | 0 | if (dtlsBase->mode == QSslSocket::SslServerMode) { |
661 | 0 | if (dtlsBase->dtlsConfiguration.dtlsCookieVerificationEnabled()) |
662 | 0 | q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE); |
663 | 0 | q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback); |
664 | 0 | } else { |
665 | 0 | q_SSL_set_psk_client_callback(newConnection.data(), dtlscallbacks::q_PSK_client_callback); |
666 | 0 | } |
667 | |
|
668 | 0 | tlsContext.swap(newContext); |
669 | 0 | tlsConnection.swap(newConnection); |
670 | |
|
671 | 0 | return true; |
672 | 0 | } |
673 | | |
674 | | bool DtlsState::initBIO(QDtlsBasePrivate *dtlsBase) |
675 | 0 | { |
676 | 0 | Q_ASSERT(dtlsBase); |
677 | 0 | Q_ASSERT(tlsContext && tlsConnection); |
678 | |
|
679 | 0 | BioMethod customMethod(q_BIO_meth_new(BIO_TYPE_DGRAM, dtlsbio::qdtlsMethodName), |
680 | 0 | dtlsutil::delete_bio_method); |
681 | 0 | if (!customMethod.data()) { |
682 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
683 | 0 | msgFunctionFailed("BIO_meth_new")); |
684 | 0 | return false; |
685 | 0 | } |
686 | | |
687 | 0 | BIO_METHOD *biom = customMethod.data(); |
688 | 0 | q_BIO_meth_set_create(biom, dtlsbio::q_dgram_create); |
689 | 0 | q_BIO_meth_set_destroy(biom, dtlsbio::q_dgram_destroy); |
690 | 0 | q_BIO_meth_set_read(biom, dtlsbio::q_dgram_read); |
691 | 0 | q_BIO_meth_set_write(biom, dtlsbio::q_dgram_write); |
692 | 0 | q_BIO_meth_set_puts(biom, dtlsbio::q_dgram_puts); |
693 | 0 | q_BIO_meth_set_ctrl(biom, dtlsbio::q_dgram_ctrl); |
694 | |
|
695 | 0 | BIO *bio = q_BIO_new(biom); |
696 | 0 | if (!bio) { |
697 | 0 | dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, |
698 | 0 | msgFunctionFailed("BIO_new")); |
699 | 0 | return false; |
700 | 0 | } |
701 | | |
702 | 0 | q_SSL_set_bio(tlsConnection.data(), bio, bio); |
703 | |
|
704 | 0 | bioMethod.swap(customMethod); |
705 | |
|
706 | 0 | return true; |
707 | 0 | } |
708 | | |
709 | | void DtlsState::setLinkMtu(QDtlsBasePrivate *dtlsBase) |
710 | 0 | { |
711 | 0 | Q_ASSERT(dtlsBase); |
712 | 0 | Q_ASSERT(udpSocket); |
713 | 0 | Q_ASSERT(tlsConnection.data()); |
714 | |
|
715 | 0 | long mtu = dtlsBase->mtuHint; |
716 | 0 | if (!mtu) { |
717 | | // If the underlying QUdpSocket was connected, getsockopt with |
718 | | // IP_MTU/IP6_MTU can give us some hint: |
719 | 0 | bool optionFound = false; |
720 | 0 | if (udpSocket->state() == QAbstractSocket::ConnectedState) { |
721 | 0 | const QVariant val(udpSocket->socketOption(QAbstractSocket::PathMtuSocketOption)); |
722 | 0 | if (val.isValid() && val.canConvert<int>()) |
723 | 0 | mtu = val.toInt(&optionFound); |
724 | 0 | } |
725 | |
|
726 | 0 | if (!optionFound || mtu <= 0) { |
727 | | // OK, our own initial guess. |
728 | 0 | mtu = long(dtlsutil::MtuGuess::defaultMtu); |
729 | 0 | } |
730 | 0 | } |
731 | | |
732 | | // For now, we disable this option. |
733 | 0 | q_SSL_set_options(tlsConnection.data(), SSL_OP_NO_QUERY_MTU); |
734 | |
|
735 | 0 | q_DTLS_set_link_mtu(tlsConnection.data(), mtu); |
736 | 0 | } |
737 | | |
738 | | } // namespace dtlsopenssl |
739 | | |
740 | | QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL() |
741 | 0 | : QDtlsBasePrivate(QSslSocket::SslServerMode, dtlsutil::fallbackSecret()) |
742 | 0 | { |
743 | 0 | } Unexecuted instantiation: QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL() Unexecuted instantiation: QDtlsClientVerifierOpenSSL::QDtlsClientVerifierOpenSSL() |
744 | | |
745 | | bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArray &dgram, |
746 | | const QHostAddress &address, quint16 port) |
747 | 0 | { |
748 | 0 | Q_ASSERT(socket); |
749 | 0 | Q_ASSERT(dgram.size()); |
750 | 0 | Q_ASSERT(!address.isNull()); |
751 | 0 | Q_ASSERT(port); |
752 | |
|
753 | 0 | clearDtlsError(); |
754 | 0 | verifiedClientHello.clear(); |
755 | |
|
756 | 0 | if (!dtls.init(this, socket, address, port, dgram)) |
757 | 0 | return false; |
758 | | |
759 | 0 | dtls.secret = secret; |
760 | 0 | dtls.hashAlgorithm = hashAlgorithm; |
761 | |
|
762 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
763 | 0 | QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR); |
764 | 0 | if (!peer.data()) { |
765 | 0 | setDtlsError(QDtlsError::TlsInitializationError, |
766 | 0 | QDtlsClientVerifier::tr("BIO_ADDR_new failed, ignoring client hello")); |
767 | 0 | return false; |
768 | 0 | } |
769 | | |
770 | 0 | const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data()); |
771 | 0 | if (ret < 0) { |
772 | | // Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket) |
773 | 0 | setDtlsError(QDtlsError::TlsFatalError, QTlsBackendOpenSSL::getErrorsFromOpenSsl()); |
774 | 0 | return false; |
775 | 0 | } |
776 | | |
777 | 0 | if (ret > 0) { |
778 | 0 | verifiedClientHello = dgram; |
779 | 0 | return true; |
780 | 0 | } |
781 | | |
782 | 0 | return false; |
783 | 0 | } |
784 | | |
785 | | QByteArray QDtlsClientVerifierOpenSSL::verifiedHello() const |
786 | 0 | { |
787 | 0 | return verifiedClientHello; |
788 | 0 | } |
789 | | |
790 | | void QDtlsPrivateOpenSSL::TimeoutHandler::start(int hintMs) |
791 | 0 | { |
792 | 0 | Q_ASSERT(!timer.isActive()); |
793 | 0 | timer.start(hintMs > 0 ? hintMs : timeoutMs, Qt::PreciseTimer, this); |
794 | 0 | } |
795 | | |
796 | | void QDtlsPrivateOpenSSL::TimeoutHandler::doubleTimeout() |
797 | 0 | { |
798 | 0 | if (timeoutMs * 2 < 60000) |
799 | 0 | timeoutMs *= 2; |
800 | 0 | else |
801 | 0 | timeoutMs = 60000; |
802 | 0 | } |
803 | | |
804 | | void QDtlsPrivateOpenSSL::TimeoutHandler::stop() |
805 | 0 | { |
806 | 0 | timer.stop(); |
807 | 0 | } |
808 | | |
809 | | void QDtlsPrivateOpenSSL::TimeoutHandler::timerEvent(QTimerEvent *event) |
810 | 0 | { |
811 | 0 | Q_UNUSED(event); |
812 | 0 | Q_ASSERT(timer.isActive()); |
813 | |
|
814 | 0 | timer.stop(); |
815 | |
|
816 | 0 | Q_ASSERT(dtlsConnection); |
817 | 0 | dtlsConnection->reportTimeout(); |
818 | 0 | } |
819 | | |
820 | | QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls *qObject, QSslSocket::SslMode side) |
821 | 0 | : QDtlsBasePrivate(side, dtlsutil::fallbackSecret()), q(qObject) |
822 | 0 | { |
823 | 0 | Q_ASSERT(qObject); |
824 | |
|
825 | 0 | dtls.dtlsPrivate = this; |
826 | 0 | } Unexecuted instantiation: QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls*, QSslSocket::SslMode) Unexecuted instantiation: QDtlsPrivateOpenSSL::QDtlsPrivateOpenSSL(QDtls*, QSslSocket::SslMode) |
827 | | |
828 | | QSslSocket::SslMode QDtlsPrivateOpenSSL::cryptographMode() const |
829 | 0 | { |
830 | 0 | return mode; |
831 | 0 | } |
832 | | |
833 | | void QDtlsPrivateOpenSSL::setPeer(const QHostAddress &addr, quint16 port, const QString &name) |
834 | 0 | { |
835 | 0 | remoteAddress = addr; |
836 | 0 | remotePort = port; |
837 | 0 | peerVfyName = name; |
838 | 0 | } |
839 | | |
840 | | QHostAddress QDtlsPrivateOpenSSL::peerAddress() const |
841 | 0 | { |
842 | 0 | return remoteAddress; |
843 | 0 | } |
844 | | |
845 | | quint16 QDtlsPrivateOpenSSL::peerPort() const |
846 | 0 | { |
847 | 0 | return remotePort; |
848 | 0 | } |
849 | | |
850 | | void QDtlsPrivateOpenSSL::setPeerVerificationName(const QString &name) |
851 | 0 | { |
852 | 0 | peerVfyName = name; |
853 | 0 | } |
854 | | |
855 | | QString QDtlsPrivateOpenSSL::peerVerificationName() const |
856 | 0 | { |
857 | 0 | return peerVfyName; |
858 | 0 | } |
859 | | |
860 | | void QDtlsPrivateOpenSSL::setDtlsMtuHint(quint16 mtu) |
861 | 0 | { |
862 | 0 | mtuHint = mtu; |
863 | 0 | } |
864 | | |
865 | | quint16 QDtlsPrivateOpenSSL::dtlsMtuHint() const |
866 | 0 | { |
867 | 0 | return mtuHint; |
868 | 0 | } |
869 | | |
870 | | QDtls::HandshakeState QDtlsPrivateOpenSSL::state() const |
871 | 0 | { |
872 | 0 | return handshakeState; |
873 | 0 | } |
874 | | |
875 | | bool QDtlsPrivateOpenSSL::isConnectionEncrypted() const |
876 | 0 | { |
877 | 0 | return connectionEncrypted; |
878 | 0 | } |
879 | | |
880 | | bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &dgram) |
881 | 0 | { |
882 | 0 | Q_ASSERT(socket); |
883 | 0 | Q_ASSERT(handshakeState == QDtls::HandshakeNotStarted); |
884 | |
|
885 | 0 | clearDtlsError(); |
886 | 0 | connectionEncrypted = false; |
887 | |
|
888 | 0 | if (!dtls.init(this, socket, remoteAddress, remotePort, dgram)) |
889 | 0 | return false; |
890 | | |
891 | 0 | if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) { |
892 | 0 | dtls.secret = secret; |
893 | 0 | dtls.hashAlgorithm = hashAlgorithm; |
894 | | // Let's prepare the state machine so that message sequence 1 does not |
895 | | // surprise DTLS/OpenSSL (such a message would be disregarded as |
896 | | // 'stale or future' in SSL_accept otherwise): |
897 | 0 | int result = 0; |
898 | 0 | QSharedPointer<BIO_ADDR> peer(q_BIO_ADDR_new(), dtlsutil::delete_BIO_ADDR); |
899 | 0 | if (!peer.data()) { |
900 | 0 | setDtlsError(QDtlsError::TlsInitializationError, |
901 | 0 | QDtls::tr("BIO_ADD_new failed, cannot start handshake")); |
902 | 0 | return false; |
903 | 0 | } |
904 | | |
905 | | // If it's an invalid/unexpected ClientHello, we don't want to send |
906 | | // VerifyClientRequest - it's a job of QDtlsClientVerifier - so we |
907 | | // suppress any attempts to write into socket: |
908 | 0 | dtls.writeSuppressed = true; |
909 | 0 | result = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data()); |
910 | 0 | dtls.writeSuppressed = false; |
911 | |
|
912 | 0 | if (result <= 0) { |
913 | 0 | setDtlsError(QDtlsError::TlsFatalError, |
914 | 0 | QDtls::tr("Cannot start the handshake, verified client hello expected")); |
915 | 0 | dtls.reset(); |
916 | 0 | return false; |
917 | 0 | } |
918 | 0 | } |
919 | | |
920 | 0 | handshakeState = QDtls::HandshakeInProgress; |
921 | 0 | opensslErrors.clear(); |
922 | 0 | tlsErrors.clear(); |
923 | |
|
924 | 0 | return continueHandshake(socket, dgram); |
925 | 0 | } |
926 | | |
927 | | bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray &dgram) |
928 | 0 | { |
929 | 0 | Q_ASSERT(socket); |
930 | |
|
931 | 0 | Q_ASSERT(handshakeState == QDtls::HandshakeInProgress); |
932 | |
|
933 | 0 | clearDtlsError(); |
934 | |
|
935 | 0 | if (timeoutHandler.data()) |
936 | 0 | timeoutHandler->stop(); |
937 | |
|
938 | 0 | if (!dtls.init(this, socket, remoteAddress, remotePort, dgram)) |
939 | 0 | return false; |
940 | | |
941 | 0 | dtls.x509Errors.clear(); |
942 | |
|
943 | 0 | int result = 0; |
944 | 0 | if (mode == QSslSocket::SslServerMode) |
945 | 0 | result = q_SSL_accept(dtls.tlsConnection.data()); |
946 | 0 | else |
947 | 0 | result = q_SSL_connect(dtls.tlsConnection.data()); |
948 | | |
949 | | // DTLSTODO: Investigate/test if it makes sense - QSslSocket can emit |
950 | | // peerVerifyError at this point (and thus potentially client code |
951 | | // will close the underlying TCP connection immediately), but we are using |
952 | | // QUdpSocket, no connection to close, our verification callback returns 1 |
953 | | // (verified OK) and this probably means OpenSSL has already sent a reply |
954 | | // to the server's hello/certificate. |
955 | |
|
956 | 0 | opensslErrors << dtls.x509Errors; |
957 | |
|
958 | 0 | if (result <= 0) { |
959 | 0 | const auto code = q_SSL_get_error(dtls.tlsConnection.data(), result); |
960 | 0 | switch (code) { |
961 | 0 | case SSL_ERROR_WANT_READ: |
962 | 0 | case SSL_ERROR_WANT_WRITE: |
963 | | // DTLSTODO: to be tested - in principle, if it was the first call to |
964 | | // continueHandshake and server for some reason discards the client |
965 | | // hello message (even the verified one) - our 'this' will probably |
966 | | // forever stay in this strange InProgress state? (the client |
967 | | // will dully re-transmit the same hello and we discard it again?) |
968 | | // SSL_get_state can provide more information about state |
969 | | // machine and we can switch to NotStarted (since we have not |
970 | | // replied with our hello ...) |
971 | 0 | if (!timeoutHandler.data()) { |
972 | 0 | timeoutHandler.reset(new TimeoutHandler); |
973 | 0 | timeoutHandler->dtlsConnection = this; |
974 | 0 | } else { |
975 | | // Back to 1s. |
976 | 0 | timeoutHandler->resetTimeout(); |
977 | 0 | } |
978 | |
|
979 | 0 | timeoutHandler->start(); |
980 | |
|
981 | 0 | return true; // The handshake is not yet complete. |
982 | 0 | default: |
983 | 0 | storePeerCertificates(); |
984 | 0 | setDtlsError(QDtlsError::TlsFatalError, |
985 | 0 | QTlsBackendOpenSSL::msgErrorsDuringHandshake()); |
986 | 0 | dtls.reset(); |
987 | 0 | handshakeState = QDtls::HandshakeNotStarted; |
988 | 0 | return false; |
989 | 0 | } |
990 | 0 | } |
991 | | |
992 | 0 | storePeerCertificates(); |
993 | 0 | fetchNegotiatedParameters(); |
994 | |
|
995 | 0 | const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer |
996 | 0 | || (dtlsConfiguration.peerVerifyMode() == QSslSocket::AutoVerifyPeer |
997 | 0 | && mode == QSslSocket::SslClientMode); |
998 | |
|
999 | 0 | if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) { |
1000 | 0 | connectionEncrypted = true; |
1001 | 0 | handshakeState = QDtls::HandshakeComplete; |
1002 | 0 | return true; |
1003 | 0 | } |
1004 | | |
1005 | 0 | setDtlsError(QDtlsError::PeerVerificationError, QDtls::tr("Peer verification failed")); |
1006 | 0 | handshakeState = QDtls::PeerVerificationFailed; |
1007 | 0 | return false; |
1008 | 0 | } |
1009 | | |
1010 | | |
1011 | | bool QDtlsPrivateOpenSSL::handleTimeout(QUdpSocket *socket) |
1012 | 0 | { |
1013 | 0 | Q_ASSERT(socket); |
1014 | |
|
1015 | 0 | Q_ASSERT(timeoutHandler.data()); |
1016 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1017 | |
|
1018 | 0 | clearDtlsError(); |
1019 | |
|
1020 | 0 | dtls.udpSocket = socket; |
1021 | |
|
1022 | 0 | if (q_DTLSv1_handle_timeout(dtls.tlsConnection.data()) > 0) { |
1023 | 0 | timeoutHandler->doubleTimeout(); |
1024 | 0 | timeoutHandler->start(); |
1025 | 0 | } else { |
1026 | 0 | timeoutHandler->start(dtlsutil::next_timeoutMs(dtls.tlsConnection.data())); |
1027 | 0 | } |
1028 | |
|
1029 | 0 | return true; |
1030 | 0 | } |
1031 | | |
1032 | | bool QDtlsPrivateOpenSSL::resumeHandshake(QUdpSocket *socket) |
1033 | 0 | { |
1034 | 0 | Q_UNUSED(socket); |
1035 | 0 | Q_ASSERT(socket); |
1036 | 0 | Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed); |
1037 | |
|
1038 | 0 | clearDtlsError(); |
1039 | |
|
1040 | 0 | if (tlsErrorsWereIgnored()) { |
1041 | 0 | handshakeState = QDtls::HandshakeComplete; |
1042 | 0 | connectionEncrypted = true; |
1043 | 0 | tlsErrors.clear(); |
1044 | 0 | tlsErrorsToIgnore.clear(); |
1045 | 0 | return true; |
1046 | 0 | } |
1047 | | |
1048 | 0 | return false; |
1049 | 0 | } |
1050 | | |
1051 | | void QDtlsPrivateOpenSSL::abortHandshake(QUdpSocket *socket) |
1052 | 0 | { |
1053 | 0 | Q_ASSERT(socket); |
1054 | 0 | Q_ASSERT(handshakeState == QDtls::PeerVerificationFailed |
1055 | 0 | || handshakeState == QDtls::HandshakeInProgress); |
1056 | |
|
1057 | 0 | clearDtlsError(); |
1058 | |
|
1059 | 0 | if (handshakeState == QDtls::PeerVerificationFailed) { |
1060 | | // Yes, while peer verification failed, we were actually encrypted. |
1061 | | // Let's play it nice - inform our peer about connection shut down. |
1062 | 0 | sendShutdownAlert(socket); |
1063 | 0 | } else { |
1064 | 0 | resetDtls(); |
1065 | 0 | } |
1066 | 0 | } |
1067 | | |
1068 | | void QDtlsPrivateOpenSSL::sendShutdownAlert(QUdpSocket *socket) |
1069 | 0 | { |
1070 | 0 | Q_ASSERT(socket); |
1071 | |
|
1072 | 0 | clearDtlsError(); |
1073 | |
|
1074 | 0 | if (connectionEncrypted && !connectionWasShutdown) { |
1075 | 0 | dtls.udpSocket = socket; |
1076 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1077 | 0 | q_SSL_shutdown(dtls.tlsConnection.data()); |
1078 | 0 | } |
1079 | |
|
1080 | 0 | resetDtls(); |
1081 | 0 | } |
1082 | | |
1083 | | QList<QSslError> QDtlsPrivateOpenSSL::peerVerificationErrors() const |
1084 | 0 | { |
1085 | 0 | return tlsErrors; |
1086 | 0 | } |
1087 | | |
1088 | | void QDtlsPrivateOpenSSL::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) |
1089 | 0 | { |
1090 | 0 | tlsErrorsToIgnore = errorsToIgnore; |
1091 | 0 | } |
1092 | | |
1093 | | QSslCipher QDtlsPrivateOpenSSL::dtlsSessionCipher() const |
1094 | 0 | { |
1095 | 0 | return sessionCipher; |
1096 | 0 | } |
1097 | | |
1098 | | QSsl::SslProtocol QDtlsPrivateOpenSSL::dtlsSessionProtocol() const |
1099 | 0 | { |
1100 | 0 | return sessionProtocol; |
1101 | 0 | } |
1102 | | |
1103 | | qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket, |
1104 | | const QByteArray &dgram) |
1105 | 0 | { |
1106 | 0 | Q_ASSERT(socket); |
1107 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1108 | 0 | Q_ASSERT(connectionEncrypted); |
1109 | |
|
1110 | 0 | clearDtlsError(); |
1111 | |
|
1112 | 0 | dtls.udpSocket = socket; |
1113 | 0 | const int written = q_SSL_write(dtls.tlsConnection.data(), |
1114 | 0 | dgram.constData(), dgram.size()); |
1115 | 0 | if (written > 0) |
1116 | 0 | return written; |
1117 | | |
1118 | 0 | const unsigned long errorCode = q_ERR_get_error(); |
1119 | 0 | if (!dgram.size() && errorCode == SSL_ERROR_NONE) { |
1120 | | // With OpenSSL <= 1.1 this can happen. For example, DTLS client |
1121 | | // tries to reconnect (while re-using the same address/port) - |
1122 | | // DTLS server drops a message with unexpected epoch but says - no |
1123 | | // error. We leave to client code to resolve such problems until |
1124 | | // OpenSSL provides something better. |
1125 | 0 | return 0; |
1126 | 0 | } |
1127 | | |
1128 | 0 | switch (errorCode) { |
1129 | 0 | case SSL_ERROR_WANT_WRITE: |
1130 | 0 | case SSL_ERROR_WANT_READ: |
1131 | | // We do not set any error/description ... a user can probably re-try |
1132 | | // sending a datagram. |
1133 | 0 | break; |
1134 | 0 | case SSL_ERROR_ZERO_RETURN: |
1135 | 0 | connectionWasShutdown = true; |
1136 | 0 | setDtlsError(QDtlsError::TlsFatalError, QDtls::tr("The DTLS connection has been closed")); |
1137 | 0 | handshakeState = QDtls::HandshakeNotStarted; |
1138 | 0 | dtls.reset(); |
1139 | 0 | break; |
1140 | 0 | case SSL_ERROR_SYSCALL: |
1141 | 0 | case SSL_ERROR_SSL: |
1142 | 0 | default: |
1143 | | // DTLSTODO: we don't know yet what to do. Tests needed - probably, |
1144 | | // some errors can be just ignored (it's UDP, not TCP after all). |
1145 | | // Unlike QSslSocket we do not abort though. |
1146 | 0 | QString description(QTlsBackendOpenSSL::getErrorsFromOpenSsl()); |
1147 | 0 | if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) { |
1148 | 0 | setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString()); |
1149 | 0 | } else { |
1150 | 0 | setDtlsError(QDtlsError::TlsFatalError, |
1151 | 0 | QDtls::tr("Error while writing: %1").arg(description)); |
1152 | 0 | } |
1153 | 0 | } |
1154 | | |
1155 | 0 | return -1; |
1156 | 0 | } |
1157 | | |
1158 | | QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) |
1159 | 0 | { |
1160 | 0 | Q_ASSERT(socket); |
1161 | 0 | Q_ASSERT(tlsdgram.size()); |
1162 | |
|
1163 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1164 | 0 | Q_ASSERT(connectionEncrypted); |
1165 | |
|
1166 | 0 | dtls.dgram = tlsdgram; |
1167 | 0 | dtls.udpSocket = socket; |
1168 | |
|
1169 | 0 | clearDtlsError(); |
1170 | |
|
1171 | 0 | QByteArray dgram; |
1172 | 0 | dgram.resize(tlsdgram.size()); |
1173 | 0 | const int read = q_SSL_read(dtls.tlsConnection.data(), dgram.data(), |
1174 | 0 | dgram.size()); |
1175 | |
|
1176 | 0 | if (read > 0) { |
1177 | 0 | dgram.resize(read); |
1178 | 0 | return dgram; |
1179 | 0 | } |
1180 | | |
1181 | 0 | dgram.clear(); |
1182 | 0 | unsigned long errorCode = q_ERR_get_error(); |
1183 | 0 | if (errorCode == SSL_ERROR_NONE) { |
1184 | 0 | const int shutdown = q_SSL_get_shutdown(dtls.tlsConnection.data()); |
1185 | 0 | if (shutdown & SSL_RECEIVED_SHUTDOWN) |
1186 | 0 | errorCode = SSL_ERROR_ZERO_RETURN; |
1187 | 0 | else |
1188 | 0 | return dgram; |
1189 | 0 | } |
1190 | | |
1191 | 0 | switch (errorCode) { |
1192 | 0 | case SSL_ERROR_WANT_READ: |
1193 | 0 | case SSL_ERROR_WANT_WRITE: |
1194 | 0 | return dgram; |
1195 | 0 | case SSL_ERROR_ZERO_RETURN: |
1196 | | // "The connection was shut down cleanly" ... hmm, whatever, |
1197 | | // needs testing (DTLSTODO). |
1198 | 0 | connectionWasShutdown = true; |
1199 | 0 | setDtlsError(QDtlsError::RemoteClosedConnectionError, |
1200 | 0 | QDtls::tr("The DTLS connection has been shutdown")); |
1201 | 0 | dtls.reset(); |
1202 | 0 | connectionEncrypted = false; |
1203 | 0 | handshakeState = QDtls::HandshakeNotStarted; |
1204 | 0 | return dgram; |
1205 | 0 | case SSL_ERROR_SYSCALL: // some IO error |
1206 | 0 | case SSL_ERROR_SSL: // error in the SSL library |
1207 | | // DTLSTODO: Apparently, some errors can be ignored, for example, |
1208 | | // ECONNRESET etc. This all needs a lot of testing!!! |
1209 | 0 | default: |
1210 | 0 | setDtlsError(QDtlsError::TlsNonFatalError, |
1211 | 0 | QDtls::tr("Error while reading: %1") |
1212 | 0 | .arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
1213 | 0 | return dgram; |
1214 | 0 | } |
1215 | 0 | } |
1216 | | |
1217 | | unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity, |
1218 | | unsigned max_identity_len, |
1219 | | unsigned char *psk, |
1220 | | unsigned max_psk_len) |
1221 | 0 | { |
1222 | | // The code below is taken (with some modifications) from qsslsocket_openssl |
1223 | | // - alas, we cannot simply re-use it, it's in QSslSocketPrivate. |
1224 | 0 | { |
1225 | 0 | QSslPreSharedKeyAuthenticator authenticator; |
1226 | | // Fill in some read-only fields (for client code) |
1227 | 0 | if (hint) { |
1228 | 0 | identityHint.clear(); |
1229 | 0 | identityHint.append(hint); |
1230 | 0 | } |
1231 | |
|
1232 | 0 | QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr, |
1233 | 0 | hint ? int(std::strlen(hint)) : 0, max_identity_len, max_psk_len); |
1234 | 0 | pskAuthenticator.swap(authenticator); |
1235 | 0 | } |
1236 | | |
1237 | | // Let the client provide the remaining bits... |
1238 | 0 | emit q->pskRequired(&pskAuthenticator); |
1239 | | |
1240 | | // No PSK set? Return now to make the handshake fail |
1241 | 0 | if (pskAuthenticator.preSharedKey().isEmpty()) |
1242 | 0 | return 0; |
1243 | | |
1244 | | // Copy data back into OpenSSL |
1245 | 0 | const int identityLength = qMin(pskAuthenticator.identity().size(), |
1246 | 0 | pskAuthenticator.maximumIdentityLength()); |
1247 | 0 | std::memcpy(identity, pskAuthenticator.identity().constData(), identityLength); |
1248 | 0 | identity[identityLength] = 0; |
1249 | |
|
1250 | 0 | const int pskLength = qMin(pskAuthenticator.preSharedKey().size(), |
1251 | 0 | pskAuthenticator.maximumPreSharedKeyLength()); |
1252 | 0 | std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength); |
1253 | |
|
1254 | 0 | return pskLength; |
1255 | 0 | } |
1256 | | |
1257 | | unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned char *psk, |
1258 | | unsigned max_psk_len) |
1259 | 0 | { |
1260 | 0 | { |
1261 | 0 | QSslPreSharedKeyAuthenticator authenticator; |
1262 | | // Fill in some read-only fields (for the user) |
1263 | 0 | QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint(), |
1264 | 0 | max_psk_len); |
1265 | 0 | pskAuthenticator.swap(authenticator); |
1266 | 0 | } |
1267 | | |
1268 | | // Let the client provide the remaining bits... |
1269 | 0 | emit q->pskRequired(&pskAuthenticator); |
1270 | | |
1271 | | // No PSK set? Return now to make the handshake fail |
1272 | 0 | if (pskAuthenticator.preSharedKey().isEmpty()) |
1273 | 0 | return 0; |
1274 | | |
1275 | | // Copy data back into OpenSSL |
1276 | 0 | const int pskLength = qMin(pskAuthenticator.preSharedKey().size(), |
1277 | 0 | pskAuthenticator.maximumPreSharedKeyLength()); |
1278 | |
|
1279 | 0 | std::memcpy(psk, pskAuthenticator.preSharedKey().constData(), pskLength); |
1280 | |
|
1281 | 0 | return pskLength; |
1282 | 0 | } |
1283 | | |
1284 | | bool QDtlsPrivateOpenSSL::verifyPeer() |
1285 | 0 | { |
1286 | 0 | QList<QSslError> errors; |
1287 | | |
1288 | | // Check the whole chain for blacklisting (including root, as we check for |
1289 | | // subjectInfo and issuer) |
1290 | 0 | const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain(); |
1291 | 0 | for (const QSslCertificate &cert : peerCertificateChain) { |
1292 | 0 | if (QSslCertificatePrivate::isBlacklisted(cert)) |
1293 | 0 | errors << QSslError(QSslError::CertificateBlacklisted, cert); |
1294 | 0 | } |
1295 | |
|
1296 | 0 | const auto peerCertificate = dtlsConfiguration.peerCertificate(); |
1297 | 0 | if (peerCertificate.isNull()) { |
1298 | 0 | errors << QSslError(QSslError::NoPeerCertificate); |
1299 | 0 | } else if (mode == QSslSocket::SslClientMode) { |
1300 | | // Check the peer certificate itself. First try the subject's common name |
1301 | | // (CN) as a wildcard, then try all alternate subject name DNS entries the |
1302 | | // same way. |
1303 | | |
1304 | | // QSslSocket has a rather twisted logic: if verificationPeerName |
1305 | | // is empty, we call QAbstractSocket::peerName(), which returns |
1306 | | // either peerName (can be set by setPeerName) or host name |
1307 | | // (can be set as a result of connectToHost). |
1308 | 0 | QString name = peerVfyName; |
1309 | 0 | if (name.isEmpty()) { |
1310 | 0 | Q_ASSERT(dtls.udpSocket); |
1311 | 0 | name = dtls.udpSocket->peerName(); |
1312 | 0 | } |
1313 | |
|
1314 | 0 | if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name)) |
1315 | 0 | errors << QSslError(QSslError::HostNameMismatch, peerCertificate); |
1316 | 0 | } |
1317 | | |
1318 | | // Translate errors from the error list into QSslErrors |
1319 | 0 | using CertClass = QTlsPrivate::X509CertificateOpenSSL; |
1320 | 0 | errors.reserve(errors.size() + opensslErrors.size()); |
1321 | 0 | for (const auto &error : std::as_const(opensslErrors)) { |
1322 | 0 | const auto value = peerCertificateChain.value(error.depth); |
1323 | 0 | errors << CertClass::openSSLErrorToQSslError(error.code, value); |
1324 | 0 | } |
1325 | |
|
1326 | 0 | tlsErrors = errors; |
1327 | 0 | return tlsErrors.isEmpty(); |
1328 | 0 | } |
1329 | | |
1330 | | void QDtlsPrivateOpenSSL::storePeerCertificates() |
1331 | 0 | { |
1332 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1333 | | // Store the peer certificate and chain. For clients, the peer certificate |
1334 | | // chain includes the peer certificate; for servers, it doesn't. Both the |
1335 | | // peer certificate and the chain may be empty if the peer didn't present |
1336 | | // any certificate. |
1337 | 0 | X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data()); |
1338 | 0 | const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509); |
1339 | 0 | QTlsBackend::storePeerCertificate(dtlsConfiguration, peerCertificate); |
1340 | 0 | q_X509_free(x509); |
1341 | |
|
1342 | 0 | auto peerCertificateChain = dtlsConfiguration.peerCertificateChain(); |
1343 | 0 | if (peerCertificateChain.isEmpty()) { |
1344 | 0 | auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data()); |
1345 | 0 | peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack); |
1346 | 0 | if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode) |
1347 | 0 | peerCertificateChain.prepend(peerCertificate); |
1348 | 0 | QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain); |
1349 | 0 | } |
1350 | 0 | } |
1351 | | |
1352 | | bool QDtlsPrivateOpenSSL::tlsErrorsWereIgnored() const |
1353 | 0 | { |
1354 | | // check whether the errors we got are all in the list of expected errors |
1355 | | // (applies only if the method QDtlsConnection::ignoreTlsErrors(const |
1356 | | // QList<QSslError> &errors) was called) |
1357 | 0 | for (const QSslError &error : tlsErrors) { |
1358 | 0 | if (!tlsErrorsToIgnore.contains(error)) |
1359 | 0 | return false; |
1360 | 0 | } |
1361 | | |
1362 | 0 | return !tlsErrorsToIgnore.empty(); |
1363 | 0 | } |
1364 | | |
1365 | | void QDtlsPrivateOpenSSL::fetchNegotiatedParameters() |
1366 | 0 | { |
1367 | 0 | Q_ASSERT(dtls.tlsConnection.data()); |
1368 | |
|
1369 | 0 | if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data())) |
1370 | 0 | sessionCipher = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher); |
1371 | 0 | else |
1372 | 0 | sessionCipher = {}; |
1373 | | |
1374 | | // Note: cipher's protocol version will be reported as either TLS 1.0 or |
1375 | | // TLS 1.2, that's how it's set by OpenSSL (and that's what they are?). |
1376 | |
|
1377 | 0 | switch (q_SSL_version(dtls.tlsConnection.data())) { |
1378 | 0 | QT_WARNING_PUSH |
1379 | 0 | QT_WARNING_DISABLE_DEPRECATED |
1380 | 0 | case DTLS1_VERSION: |
1381 | 0 | sessionProtocol = QSsl::DtlsV1_0; |
1382 | 0 | break; |
1383 | 0 | QT_WARNING_POP |
1384 | 0 | case DTLS1_2_VERSION: |
1385 | 0 | sessionProtocol = QSsl::DtlsV1_2; |
1386 | 0 | break; |
1387 | 0 | default: |
1388 | 0 | qCWarning(lcTlsBackend, "unknown protocol version"); |
1389 | 0 | sessionProtocol = QSsl::UnknownProtocol; |
1390 | 0 | } |
1391 | 0 | } |
1392 | | |
1393 | | void QDtlsPrivateOpenSSL::reportTimeout() |
1394 | 0 | { |
1395 | 0 | emit q->handshakeTimeout(); |
1396 | 0 | } |
1397 | | |
1398 | | void QDtlsPrivateOpenSSL::resetDtls() |
1399 | 0 | { |
1400 | 0 | dtls.reset(); |
1401 | 0 | connectionEncrypted = false; |
1402 | 0 | tlsErrors.clear(); |
1403 | 0 | tlsErrorsToIgnore.clear(); |
1404 | 0 | QTlsBackend::clearPeerCertificates(dtlsConfiguration); |
1405 | 0 | connectionWasShutdown = false; |
1406 | 0 | handshakeState = QDtls::HandshakeNotStarted; |
1407 | 0 | sessionCipher = {}; |
1408 | 0 | sessionProtocol = QSsl::UnknownProtocol; |
1409 | 0 | } |
1410 | | |
1411 | | QT_END_NAMESPACE |