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 | #include "qsslsocket_openssl_symbols_p.h" |
5 | #include "qx509_openssl_p.h" |
6 | #include "qtls_openssl_p.h" |
7 | |
8 | #ifdef Q_OS_WIN |
9 | #include "qwindowscarootfetcher_p.h" |
10 | #endif |
11 | |
12 | #include <QtNetwork/private/qsslpresharedkeyauthenticator_p.h> |
13 | #include <QtNetwork/private/qsslcertificate_p.h> |
14 | #include <QtNetwork/private/qocspresponse_p.h> |
15 | #include <QtNetwork/private/qsslsocket_p.h> |
16 | |
17 | #include <QtNetwork/qsslpresharedkeyauthenticator.h> |
18 | |
19 | #include <QtCore/qscopedvaluerollback.h> |
20 | #include <QtCore/qscopeguard.h> |
21 | |
22 | #include <algorithm> |
23 | #include <cstring> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | using namespace Qt::StringLiterals; |
28 | |
29 | namespace { |
30 | |
31 | QSsl::AlertLevel tlsAlertLevel(int value) |
32 | { |
33 | using QSsl::AlertLevel; |
34 | |
35 | if (const char *typeString = q_SSL_alert_type_string(value)) { |
36 | // Documented to return 'W' for warning, 'F' for fatal, |
37 | // 'U' for unknown. |
38 | switch (typeString[0]) { |
39 | case 'W': |
40 | return AlertLevel::Warning; |
41 | case 'F': |
42 | return AlertLevel::Fatal; |
43 | default:; |
44 | } |
45 | } |
46 | |
47 | return AlertLevel::Unknown; |
48 | } |
49 | |
50 | QString tlsAlertDescription(int value) |
51 | { |
52 | QString description = QLatin1StringView(q_SSL_alert_desc_string_long(value)); |
53 | if (!description.size()) |
54 | description = "no description provided"_L1 ; |
55 | return description; |
56 | } |
57 | |
58 | QSsl::AlertType tlsAlertType(int value) |
59 | { |
60 | // In case for some reason openssl gives us a value, |
61 | // which is not in our enum actually, we leave it to |
62 | // an application to handle (supposedly they have |
63 | // if or switch-statements). |
64 | return QSsl::AlertType(value & 0xff); |
65 | } |
66 | |
67 | #ifdef Q_OS_WIN |
68 | |
69 | QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool checkAIA) |
70 | { |
71 | QSslCertificate certToFetch; |
72 | |
73 | for (const auto &tlsError : tlsErrors) { |
74 | switch (tlsError.error()) { |
75 | case QSslError::UnableToGetLocalIssuerCertificate: // site presented intermediate cert, but root is unknown |
76 | case QSslError::SelfSignedCertificateInChain: // site presented a complete chain, but root is unknown |
77 | certToFetch = tlsError.certificate(); |
78 | break; |
79 | case QSslError::SelfSignedCertificate: |
80 | case QSslError::CertificateBlacklisted: |
81 | //With these errors, we know it will be untrusted so save time by not asking windows |
82 | return QSslCertificate{}; |
83 | default: |
84 | #ifdef QSSLSOCKET_DEBUG |
85 | qCDebug(lcTlsBackend) << tlsError.errorString(); |
86 | #endif |
87 | //TODO - this part is strange. |
88 | break; |
89 | } |
90 | } |
91 | |
92 | if (checkAIA) { |
93 | const auto extensions = certToFetch.extensions(); |
94 | for (const auto &ext : extensions) { |
95 | if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.1" )) // See RFC 4325 |
96 | return certToFetch; |
97 | } |
98 | //The only reason we check this extensions is because an application set trusted |
99 | //CA certificates explicitly, thus technically disabling CA fetch. So, if it's |
100 | //the case and an intermediate certificate is missing, and no extensions is |
101 | //present on the leaf certificate - we fail the handshake immediately. |
102 | return QSslCertificate{}; |
103 | } |
104 | |
105 | return certToFetch; |
106 | } |
107 | |
108 | #endif // Q_OS_WIN |
109 | |
110 | } // unnamed namespace |
111 | |
112 | namespace QTlsPrivate { |
113 | |
114 | extern "C" { |
115 | |
116 | int q_X509Callback(int ok, X509_STORE_CTX *ctx) |
117 | { |
118 | if (!ok) { |
119 | // Store the error and at which depth the error was detected. |
120 | |
121 | using ErrorListPtr = QList<QSslErrorEntry> *; |
122 | ErrorListPtr errors = nullptr; |
123 | |
124 | // Error list is attached to either 'SSL' or 'X509_STORE'. |
125 | if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first: |
126 | errors = ErrorListPtr(q_X509_STORE_get_ex_data(r: store, idx: 0)); |
127 | |
128 | if (!errors) { |
129 | // Not found on store? Try SSL and its external data then. According to the OpenSSL's |
130 | // documentation: |
131 | // |
132 | // "Whenever a X509_STORE_CTX object is created for the verification of the |
133 | // peer's certificate during a handshake, a pointer to the SSL object is |
134 | // stored into the X509_STORE_CTX object to identify the connection affected. |
135 | // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be |
136 | // used with the correct index." |
137 | const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData |
138 | + TlsCryptographOpenSSL::errorOffsetInExData; |
139 | if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data( |
140 | ctx, idx: q_SSL_get_ex_data_X509_STORE_CTX_idx()))) { |
141 | |
142 | // We may be in a renegotiation, check if we are inside a call to SSL_read: |
143 | const auto tlsOffset = QTlsBackendOpenSSL::s_indexForSSLExtraData |
144 | + TlsCryptographOpenSSL::socketOffsetInExData; |
145 | auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: tlsOffset)); |
146 | Q_ASSERT(tls); |
147 | if (tls->isInSslRead()) { |
148 | // We are in a renegotiation, make a note of this for later. |
149 | // We'll check that the certificate is the same as the one we got during |
150 | // the initial handshake |
151 | tls->setRenegotiated(true); |
152 | return 1; |
153 | } |
154 | |
155 | errors = ErrorListPtr(q_SSL_get_ex_data(ssl, idx: offset)); |
156 | } |
157 | } |
158 | |
159 | if (!errors) { |
160 | qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, handshake failure" ); |
161 | return 0; |
162 | } |
163 | |
164 | errors->append(t: X509CertificateOpenSSL::errorEntryFromStoreContext(ctx)); |
165 | } |
166 | // Always return OK to allow verification to continue. We handle the |
167 | // errors gracefully after collecting all errors, after verification has |
168 | // completed. |
169 | return 1; |
170 | } |
171 | |
172 | int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx) |
173 | { |
174 | // Passed to SSL_CTX_set_verify() |
175 | // https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_verify.html |
176 | // Returns 0 to abort verification, 1 to continue. |
177 | |
178 | // This is a new, experimental verification callback, reporting |
179 | // errors immediately and returning 0 or 1 depending on an application |
180 | // either ignoring or not ignoring verification errors as they come. |
181 | if (!ctx) { |
182 | qCWarning(lcTlsBackend, "Invalid store context (nullptr)" ); |
183 | return 0; |
184 | } |
185 | |
186 | if (!ok) { |
187 | // "Whenever a X509_STORE_CTX object is created for the verification of the |
188 | // peer's certificate during a handshake, a pointer to the SSL object is |
189 | // stored into the X509_STORE_CTX object to identify the connection affected. |
190 | // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be |
191 | // used with the correct index." |
192 | SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, idx: q_SSL_get_ex_data_X509_STORE_CTX_idx())); |
193 | if (!ssl) { |
194 | qCWarning(lcTlsBackend, "No external data (SSL) found in X509 store object" ); |
195 | return 0; |
196 | } |
197 | |
198 | const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData |
199 | + TlsCryptographOpenSSL::socketOffsetInExData; |
200 | auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: offset)); |
201 | if (!crypto) { |
202 | qCWarning(lcTlsBackend, "No external data (TlsCryptographOpenSSL) found in SSL object" ); |
203 | return 0; |
204 | } |
205 | |
206 | return crypto->emitErrorFromCallback(ctx); |
207 | } |
208 | return 1; |
209 | } |
210 | |
211 | #ifndef OPENSSL_NO_PSK |
212 | static unsigned q_ssl_psk_client_callback(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len, |
213 | unsigned char *psk, unsigned max_psk_len) |
214 | { |
215 | auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
216 | return tls->pskClientTlsCallback(hint, identity, max_identity_len, psk, max_psk_len); |
217 | } |
218 | |
219 | static unsigned int q_ssl_psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, |
220 | unsigned int max_psk_len) |
221 | { |
222 | auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
223 | Q_ASSERT(tls); |
224 | return tls->pskServerTlsCallback(identity, psk, max_psk_len); |
225 | } |
226 | |
227 | #ifdef TLS1_3_VERSION |
228 | static unsigned q_ssl_psk_restore_client(SSL *ssl, const char *hint, char *identity, unsigned max_identity_len, |
229 | unsigned char *psk, unsigned max_psk_len) |
230 | { |
231 | Q_UNUSED(hint); |
232 | Q_UNUSED(identity); |
233 | Q_UNUSED(max_identity_len); |
234 | Q_UNUSED(psk); |
235 | Q_UNUSED(max_psk_len); |
236 | |
237 | #ifdef QT_DEBUG |
238 | auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
239 | Q_ASSERT(tls); |
240 | Q_ASSERT(tls->d); |
241 | Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode); |
242 | #endif |
243 | unsigned retVal = 0; |
244 | |
245 | // Let developers opt-in to having the normal PSK callback get called for TLS 1.3 |
246 | // PSK (which works differently in a few ways, and is called at the start of every connection). |
247 | // When they do opt-in we just call the old callback from here. |
248 | if (qEnvironmentVariableIsSet(varName: "QT_USE_TLS_1_3_PSK" )) |
249 | retVal = q_ssl_psk_client_callback(ssl, hint, identity, max_identity_len, psk, max_psk_len); |
250 | |
251 | q_SSL_set_psk_client_callback(ssl, callback: &q_ssl_psk_client_callback); |
252 | |
253 | return retVal; |
254 | } |
255 | |
256 | static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, |
257 | size_t *idlen, SSL_SESSION **sess) |
258 | { |
259 | Q_UNUSED(md); |
260 | Q_UNUSED(id); |
261 | Q_UNUSED(idlen); |
262 | Q_UNUSED(sess); |
263 | |
264 | #ifdef QT_DEBUG |
265 | auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
266 | Q_ASSERT(tls); |
267 | Q_ASSERT(tls->d); |
268 | Q_ASSERT(tls->d->tlsMode() == QSslSocket::SslClientMode); |
269 | #endif |
270 | |
271 | // Temporarily rebind the psk because it will be called next. The function will restore it. |
272 | q_SSL_set_psk_client_callback(ssl, callback: &q_ssl_psk_restore_client); |
273 | |
274 | return 1; // need to return 1 or else "the connection setup fails." |
275 | } |
276 | |
277 | int q_ssl_sess_set_new_cb(SSL *ssl, SSL_SESSION *session) |
278 | { |
279 | if (!ssl) { |
280 | qCWarning(lcTlsBackend, "Invalid SSL (nullptr)" ); |
281 | return 0; |
282 | } |
283 | if (!session) { |
284 | qCWarning(lcTlsBackend, "Invalid SSL_SESSION (nullptr)" ); |
285 | return 0; |
286 | } |
287 | |
288 | auto *tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
289 | Q_ASSERT(tls); |
290 | return tls->handleNewSessionTicket(connection: ssl); |
291 | } |
292 | #endif // TLS1_3_VERSION |
293 | |
294 | #endif // !OPENSSL_NO_PSK |
295 | |
296 | #if QT_CONFIG(ocsp) |
297 | |
298 | int qt_OCSP_status_server_callback(SSL *ssl, void *ocspRequest) |
299 | { |
300 | Q_UNUSED(ocspRequest); |
301 | if (!ssl) |
302 | return SSL_TLSEXT_ERR_ALERT_FATAL; |
303 | |
304 | auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData)); |
305 | if (!crypto) |
306 | return SSL_TLSEXT_ERR_ALERT_FATAL; |
307 | |
308 | Q_ASSERT(crypto->d); |
309 | Q_ASSERT(crypto->d->tlsMode() == QSslSocket::SslServerMode); |
310 | const QByteArray &response = crypto->ocspResponseDer; |
311 | Q_ASSERT(response.size()); |
312 | |
313 | unsigned char *derCopy = static_cast<unsigned char *>(q_OPENSSL_malloc(size_t(response.size()))); |
314 | if (!derCopy) |
315 | return SSL_TLSEXT_ERR_ALERT_FATAL; |
316 | |
317 | std::copy(first: response.data(), last: response.data() + response.size(), result: derCopy); |
318 | // We don't check the return value: internally OpenSSL simply assigns the |
319 | // pointer (it assumes it now owns this memory btw!) and the length. |
320 | q_SSL_set_tlsext_status_ocsp_resp(ssl, derCopy, response.size()); |
321 | |
322 | return SSL_TLSEXT_ERR_OK; |
323 | } |
324 | |
325 | #endif // ocsp |
326 | |
327 | void qt_AlertInfoCallback(const SSL *connection, int from, int value) |
328 | { |
329 | // Passed to SSL_set_info_callback() |
330 | // https://www.openssl.org/docs/man1.1.1/man3/SSL_set_info_callback.html |
331 | |
332 | if (!connection) { |
333 | #ifdef QSSLSOCKET_DEBUG |
334 | qCWarning(lcTlsBackend, "Invalid 'connection' parameter (nullptr)" ); |
335 | #endif // QSSLSOCKET_DEBUG |
336 | return; |
337 | } |
338 | |
339 | const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData |
340 | + TlsCryptographOpenSSL::socketOffsetInExData; |
341 | auto crypto = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl: connection, idx: offset)); |
342 | if (!crypto) { |
343 | // SSL_set_ex_data can fail: |
344 | #ifdef QSSLSOCKET_DEBUG |
345 | qCWarning(lcTlsBackend, "No external data (socket backend) found for parameter 'connection'" ); |
346 | #endif // QSSLSOCKET_DEBUG |
347 | return; |
348 | } |
349 | |
350 | if (!(from & SSL_CB_ALERT)) { |
351 | // We only want to know about alerts (at least for now). |
352 | return; |
353 | } |
354 | |
355 | if (from & SSL_CB_WRITE) |
356 | crypto->alertMessageSent(encoded: value); |
357 | else |
358 | crypto->alertMessageReceived(encoded: value); |
359 | } |
360 | |
361 | } // extern "C" |
362 | |
363 | #if QT_CONFIG(ocsp) |
364 | namespace { |
365 | |
366 | QSslError::SslError qt_OCSP_response_status_to_SslError(long code) |
367 | { |
368 | switch (code) { |
369 | case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: |
370 | return QSslError::OcspMalformedRequest; |
371 | case OCSP_RESPONSE_STATUS_INTERNALERROR: |
372 | return QSslError::OcspInternalError; |
373 | case OCSP_RESPONSE_STATUS_TRYLATER: |
374 | return QSslError::OcspTryLater; |
375 | case OCSP_RESPONSE_STATUS_SIGREQUIRED: |
376 | return QSslError::OcspSigRequred; |
377 | case OCSP_RESPONSE_STATUS_UNAUTHORIZED: |
378 | return QSslError::OcspUnauthorized; |
379 | case OCSP_RESPONSE_STATUS_SUCCESSFUL: |
380 | default: |
381 | return {}; |
382 | } |
383 | Q_UNREACHABLE(); |
384 | } |
385 | |
386 | QOcspRevocationReason qt_OCSP_revocation_reason(int reason) |
387 | { |
388 | switch (reason) { |
389 | case OCSP_REVOKED_STATUS_NOSTATUS: |
390 | return QOcspRevocationReason::None; |
391 | case OCSP_REVOKED_STATUS_UNSPECIFIED: |
392 | return QOcspRevocationReason::Unspecified; |
393 | case OCSP_REVOKED_STATUS_KEYCOMPROMISE: |
394 | return QOcspRevocationReason::KeyCompromise; |
395 | case OCSP_REVOKED_STATUS_CACOMPROMISE: |
396 | return QOcspRevocationReason::CACompromise; |
397 | case OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: |
398 | return QOcspRevocationReason::AffiliationChanged; |
399 | case OCSP_REVOKED_STATUS_SUPERSEDED: |
400 | return QOcspRevocationReason::Superseded; |
401 | case OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: |
402 | return QOcspRevocationReason::CessationOfOperation; |
403 | case OCSP_REVOKED_STATUS_CERTIFICATEHOLD: |
404 | return QOcspRevocationReason::CertificateHold; |
405 | case OCSP_REVOKED_STATUS_REMOVEFROMCRL: |
406 | return QOcspRevocationReason::RemoveFromCRL; |
407 | default: |
408 | return QOcspRevocationReason::None; |
409 | } |
410 | |
411 | Q_UNREACHABLE(); |
412 | } |
413 | |
414 | bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer) |
415 | { |
416 | // OCSP_basic_verify does verify that the responder is legit, the response is |
417 | // correctly signed, CertID is correct. But it does not know which certificate |
418 | // we were presented with by our peer, so it does not check if it's a response |
419 | // for our peer's certificate. |
420 | Q_ASSERT(singleResponse && peerCert && issuer); |
421 | |
422 | const OCSP_CERTID *certId = q_OCSP_SINGLERESP_get0_id(x: singleResponse); // Does not increment refcount. |
423 | if (!certId) { |
424 | qCWarning(lcTlsBackend, "A SingleResponse without CertID" ); |
425 | return false; |
426 | } |
427 | |
428 | ASN1_OBJECT *md = nullptr; |
429 | ASN1_INTEGER *reportedSerialNumber = nullptr; |
430 | const int result = q_OCSP_id_get0_info(piNameHash: nullptr, pmd: &md, pikeyHash: nullptr, pserial: &reportedSerialNumber, cid: const_cast<OCSP_CERTID *>(certId)); |
431 | if (result != 1 || !md || !reportedSerialNumber) { |
432 | qCWarning(lcTlsBackend, "Failed to extract a hash and serial number from CertID structure" ); |
433 | return false; |
434 | } |
435 | |
436 | if (!q_X509_get_serialNumber(a: peerCert)) { |
437 | // Is this possible at all? But we have to check this, |
438 | // ASN1_INTEGER_cmp (called from OCSP_id_cmp) dereferences |
439 | // without any checks at all. |
440 | qCWarning(lcTlsBackend, "No serial number in peer's ceritificate" ); |
441 | return false; |
442 | } |
443 | |
444 | const int nid = q_OBJ_obj2nid(a: md); |
445 | if (nid == NID_undef) { |
446 | qCWarning(lcTlsBackend, "Unknown hash algorithm in CertID" ); |
447 | return false; |
448 | } |
449 | |
450 | const EVP_MD *digest = q_EVP_get_digestbynid(nid); // Does not increment refcount. |
451 | if (!digest) { |
452 | qCWarning(lcTlsBackend) << "No digest for nid" << nid; |
453 | return false; |
454 | } |
455 | |
456 | OCSP_CERTID *recreatedId = q_OCSP_cert_to_id(dgst: digest, subject: peerCert, issuer); |
457 | if (!recreatedId) { |
458 | qCWarning(lcTlsBackend, "Failed to re-create CertID" ); |
459 | return false; |
460 | } |
461 | const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free); |
462 | |
463 | if (q_OCSP_id_cmp(a: const_cast<OCSP_CERTID *>(certId), b: recreatedId)) { |
464 | qCDebug(lcTlsBackend, "Certificate ID mismatch" ); |
465 | return false; |
466 | } |
467 | // Bingo! |
468 | return true; |
469 | } |
470 | |
471 | } // unnamed namespace |
472 | #endif // ocsp |
473 | |
474 | TlsCryptographOpenSSL::~TlsCryptographOpenSSL() |
475 | { |
476 | destroySslContext(); |
477 | } |
478 | |
479 | void TlsCryptographOpenSSL::init(QSslSocket *qObj, QSslSocketPrivate *dObj) |
480 | { |
481 | Q_ASSERT(qObj); |
482 | Q_ASSERT(dObj); |
483 | q = qObj; |
484 | d = dObj; |
485 | |
486 | ocspResponses.clear(); |
487 | ocspResponseDer.clear(); |
488 | |
489 | systemOrSslErrorDetected = false; |
490 | handshakeInterrupted = false; |
491 | |
492 | fetchAuthorityInformation = false; |
493 | caToFetch.reset(); |
494 | } |
495 | |
496 | void TlsCryptographOpenSSL::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext) |
497 | { |
498 | if (!sslContextPointer) |
499 | sslContextPointer = std::move(tlsContext); |
500 | } |
501 | |
502 | std::shared_ptr<QSslContext> TlsCryptographOpenSSL::sslContext() const |
503 | { |
504 | return sslContextPointer; |
505 | } |
506 | |
507 | QList<QSslError> TlsCryptographOpenSSL::tlsErrors() const |
508 | { |
509 | return sslErrors; |
510 | } |
511 | |
512 | void TlsCryptographOpenSSL::startClientEncryption() |
513 | { |
514 | if (!initSslContext()) { |
515 | Q_ASSERT(d); |
516 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
517 | errorDescription: QSslSocket::tr(s: "Unable to init SSL Context: %1" ).arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
518 | return; |
519 | } |
520 | |
521 | // Start connecting. This will place outgoing data in the BIO, so we |
522 | // follow up with calling transmit(). |
523 | startHandshake(); |
524 | transmit(); |
525 | } |
526 | |
527 | void TlsCryptographOpenSSL::startServerEncryption() |
528 | { |
529 | if (!initSslContext()) { |
530 | Q_ASSERT(d); |
531 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
532 | errorDescription: QSslSocket::tr(s: "Unable to init SSL Context: %1" ).arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
533 | return; |
534 | } |
535 | |
536 | // Start connecting. This will place outgoing data in the BIO, so we |
537 | // follow up with calling transmit(). |
538 | startHandshake(); |
539 | transmit(); |
540 | } |
541 | |
542 | bool TlsCryptographOpenSSL::startHandshake() |
543 | { |
544 | // Check if the connection has been established. Get all errors from the |
545 | // verification stage. |
546 | Q_ASSERT(q); |
547 | Q_ASSERT(d); |
548 | |
549 | using ScopedBool = QScopedValueRollback<bool>; |
550 | |
551 | if (inSetAndEmitError) |
552 | return false; |
553 | |
554 | const auto mode = d->tlsMode(); |
555 | |
556 | pendingFatalAlert = false; |
557 | errorsReportedFromCallback = false; |
558 | QList<QSslErrorEntry> lastErrors; |
559 | q_SSL_set_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, arg: &lastErrors); |
560 | |
561 | // SSL_set_ex_data can fail, but see the callback's code - we handle this there. |
562 | q_SSL_set_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData + socketOffsetInExData, arg: this); |
563 | q_SSL_set_info_callback(ssl, cb: qt_AlertInfoCallback); |
564 | |
565 | int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(a: ssl) : q_SSL_accept(a: ssl); |
566 | q_SSL_set_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData + errorOffsetInExData, arg: nullptr); |
567 | // Note, unlike errors as external data on SSL object, we do not unset |
568 | // a callback/ex-data if alert notifications are enabled: an alert can |
569 | // arrive after the handshake, for example, this happens when the server |
570 | // does not find a ClientCert or does not like it. |
571 | |
572 | if (!lastErrors.isEmpty() || errorsReportedFromCallback) |
573 | storePeerCertificates(); |
574 | |
575 | // storePeerCertificate() if called above - would update the |
576 | // configuration with peer's certificates. |
577 | auto configuration = q->sslConfiguration(); |
578 | if (!errorsReportedFromCallback) { |
579 | const auto &peerCertificateChain = configuration.peerCertificateChain(); |
580 | for (const auto ¤tError : std::as_const(t&: lastErrors)) { |
581 | emit q->peerVerifyError(error: QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(errorCode: currentError.code, |
582 | cert: peerCertificateChain.value(i: currentError.depth))); |
583 | if (q->state() != QAbstractSocket::ConnectedState) |
584 | break; |
585 | } |
586 | } |
587 | |
588 | errorList << lastErrors; |
589 | |
590 | // Connection aborted during handshake phase. |
591 | if (q->state() != QAbstractSocket::ConnectedState) |
592 | return false; |
593 | |
594 | // Check if we're encrypted or not. |
595 | if (result <= 0) { |
596 | switch (q_SSL_get_error(a: ssl, b: result)) { |
597 | case SSL_ERROR_WANT_READ: |
598 | case SSL_ERROR_WANT_WRITE: |
599 | // The handshake is not yet complete. |
600 | break; |
601 | default: |
602 | QString errorString = QTlsBackendOpenSSL::msgErrorsDuringHandshake(); |
603 | #ifdef QSSLSOCKET_DEBUG |
604 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::startHandshake: error!" << errorString; |
605 | #endif |
606 | { |
607 | const ScopedBool bg(inSetAndEmitError, true); |
608 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslHandshakeFailedError, errorDescription: errorString); |
609 | if (pendingFatalAlert) { |
610 | trySendFatalAlert(); |
611 | pendingFatalAlert = false; |
612 | } |
613 | } |
614 | q->abort(); |
615 | } |
616 | return false; |
617 | } |
618 | |
619 | // store peer certificate chain |
620 | storePeerCertificates(); |
621 | |
622 | // Start translating errors. |
623 | QList<QSslError> errors; |
624 | |
625 | // Note, the storePeerCerificates() probably updated the configuration at this point. |
626 | configuration = q->sslConfiguration(); |
627 | // Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer) |
628 | const auto &peerCertificateChain = configuration.peerCertificateChain(); |
629 | for (const QSslCertificate &cert : peerCertificateChain) { |
630 | if (QSslCertificatePrivate::isBlacklisted(certificate: cert)) { |
631 | QSslError error(QSslError::CertificateBlacklisted, cert); |
632 | errors << error; |
633 | emit q->peerVerifyError(error); |
634 | if (q->state() != QAbstractSocket::ConnectedState) |
635 | return false; |
636 | } |
637 | } |
638 | |
639 | const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer |
640 | || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer |
641 | && mode == QSslSocket::SslClientMode); |
642 | |
643 | #if QT_CONFIG(ocsp) |
644 | // For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early, |
645 | // if it's enabled in QSslSocket::SslServerMode. This can change. |
646 | if (!configuration.peerCertificate().isNull() && configuration.ocspStaplingEnabled() && doVerifyPeer) { |
647 | if (!checkOcspStatus()) { |
648 | if (ocspErrors.isEmpty()) { |
649 | { |
650 | const ScopedBool bg(inSetAndEmitError, true); |
651 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslHandshakeFailedError, errorDescription: ocspErrorDescription); |
652 | } |
653 | q->abort(); |
654 | return false; |
655 | } |
656 | |
657 | for (const QSslError &error : ocspErrors) { |
658 | errors << error; |
659 | emit q->peerVerifyError(error); |
660 | if (q->state() != QAbstractSocket::ConnectedState) |
661 | return false; |
662 | } |
663 | } |
664 | } |
665 | #endif // ocsp |
666 | |
667 | // Check the peer certificate itself. First try the subject's common name |
668 | // (CN) as a wildcard, then try all alternate subject name DNS entries the |
669 | // same way. |
670 | if (!configuration.peerCertificate().isNull()) { |
671 | // but only if we're a client connecting to a server |
672 | // if we're the server, don't check CN |
673 | const auto verificationPeerName = d->verificationName(); |
674 | if (mode == QSslSocket::SslClientMode) { |
675 | QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName); |
676 | |
677 | if (!isMatchingHostname(cert: configuration.peerCertificate(), peerName)) { |
678 | // No matches in common names or alternate names. |
679 | QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate()); |
680 | errors << error; |
681 | emit q->peerVerifyError(error); |
682 | if (q->state() != QAbstractSocket::ConnectedState) |
683 | return false; |
684 | } |
685 | } |
686 | } else { |
687 | // No peer certificate presented. Report as error if the socket |
688 | // expected one. |
689 | if (doVerifyPeer) { |
690 | QSslError error(QSslError::NoPeerCertificate); |
691 | errors << error; |
692 | emit q->peerVerifyError(error); |
693 | if (q->state() != QAbstractSocket::ConnectedState) |
694 | return false; |
695 | } |
696 | } |
697 | |
698 | // Translate errors from the error list into QSslErrors. |
699 | errors.reserve(asize: errors.size() + errorList.size()); |
700 | for (const auto &error : std::as_const(t&: errorList)) |
701 | errors << X509CertificateOpenSSL::openSSLErrorToQSslError(errorCode: error.code, cert: peerCertificateChain.value(i: error.depth)); |
702 | |
703 | if (!errors.isEmpty()) { |
704 | sslErrors = errors; |
705 | #ifdef Q_OS_WIN |
706 | const bool fetchEnabled = QSslSocketPrivate::rootCertOnDemandLoadingSupported() |
707 | && d->isRootsOnDemandAllowed(); |
708 | // !fetchEnabled is a special case scenario, when we potentially have a missing |
709 | // intermediate certificate and a recoverable chain, but on demand cert loading |
710 | // was disabled by setCaCertificates call. For this scenario we check if "Authority |
711 | // Information Access" is present - wincrypt can deal with such certificates. |
712 | QSslCertificate certToFetch; |
713 | if (doVerifyPeer && !d->verifyErrorsHaveBeenIgnored()) |
714 | certToFetch = findCertificateToFetch(sslErrors, !fetchEnabled); |
715 | |
716 | //Skip this if not using system CAs, or if the SSL errors are configured in advance to be ignorable |
717 | if (!certToFetch.isNull()) { |
718 | fetchAuthorityInformation = !fetchEnabled; |
719 | //Windows desktop versions starting from vista ship with minimal set of roots and download on demand |
720 | //from the windows update server CA roots that are trusted by MS. It also can fetch a missing intermediate |
721 | //in case "Authority Information Access" extension is present. |
722 | // |
723 | //However, this is only transparent if using WinINET - we have to trigger it |
724 | //ourselves. |
725 | fetchCaRootForCert(certToFetch); |
726 | return false; |
727 | } |
728 | #endif // Q_OS_WIN |
729 | if (!checkSslErrors()) |
730 | return false; |
731 | // A slot, attached to sslErrors signal can call |
732 | // abort/close/disconnetFromHost/etc; no need to |
733 | // continue handshake then. |
734 | if (q->state() != QAbstractSocket::ConnectedState) |
735 | return false; |
736 | } else { |
737 | sslErrors.clear(); |
738 | } |
739 | |
740 | continueHandshake(); |
741 | return true; |
742 | } |
743 | |
744 | void TlsCryptographOpenSSL::enableHandshakeContinuation() |
745 | { |
746 | handshakeInterrupted = false; |
747 | } |
748 | |
749 | void TlsCryptographOpenSSL::cancelCAFetch() |
750 | { |
751 | fetchAuthorityInformation = false; |
752 | caToFetch.reset(); |
753 | } |
754 | |
755 | void TlsCryptographOpenSSL::continueHandshake() |
756 | { |
757 | Q_ASSERT(q); |
758 | Q_ASSERT(d); |
759 | |
760 | auto *plainSocket = d->plainTcpSocket(); |
761 | Q_ASSERT(plainSocket); |
762 | |
763 | const auto mode = d->tlsMode(); |
764 | |
765 | // if we have a max read buffer size, reset the plain socket's to match |
766 | if (const auto maxSize = d->maxReadBufferSize()) |
767 | plainSocket->setReadBufferSize(maxSize); |
768 | |
769 | if (q_SSL_session_reused(a: ssl)) |
770 | QTlsBackend::setPeerSessionShared(d, shared: true); |
771 | |
772 | #ifdef QT_DECRYPT_SSL_TRAFFIC |
773 | if (q_SSL_get_session(ssl)) { |
774 | size_t master_key_len = q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), nullptr, 0); |
775 | size_t client_random_len = q_SSL_get_client_random(ssl, nullptr, 0); |
776 | QByteArray masterKey(int(master_key_len), Qt::Uninitialized); // Will not overflow |
777 | QByteArray clientRandom(int(client_random_len), Qt::Uninitialized); // Will not overflow |
778 | |
779 | q_SSL_SESSION_get_master_key(q_SSL_get_session(ssl), |
780 | reinterpret_cast<unsigned char*>(masterKey.data()), |
781 | masterKey.size()); |
782 | q_SSL_get_client_random(ssl, reinterpret_cast<unsigned char *>(clientRandom.data()), |
783 | clientRandom.size()); |
784 | |
785 | QByteArray debugLineClientRandom("CLIENT_RANDOM " ); |
786 | debugLineClientRandom.append(clientRandom.toHex().toUpper()); |
787 | debugLineClientRandom.append(" " ); |
788 | debugLineClientRandom.append(masterKey.toHex().toUpper()); |
789 | debugLineClientRandom.append("\n" ); |
790 | |
791 | QString sslKeyFile = QDir::tempPath() + "/qt-ssl-keys"_L1 ; |
792 | QFile file(sslKeyFile); |
793 | if (!file.open(QIODevice::Append)) |
794 | qCWarning(lcTlsBackend) << "could not open file" << sslKeyFile << "for appending" ; |
795 | if (!file.write(debugLineClientRandom)) |
796 | qCWarning(lcTlsBackend) << "could not write to file" << sslKeyFile; |
797 | file.close(); |
798 | } else { |
799 | qCWarning(lcTlsBackend, "could not decrypt SSL traffic" ); |
800 | } |
801 | #endif // QT_DECRYPT_SSL_TRAFFIC |
802 | |
803 | const auto &configuration = q->sslConfiguration(); |
804 | // Cache this SSL session inside the QSslContext |
805 | if (!(configuration.testSslOption(option: QSsl::SslOptionDisableSessionSharing))) { |
806 | if (!sslContextPointer->cacheSession(ssl)) { |
807 | sslContextPointer.reset(); // we could not cache the session |
808 | } else { |
809 | // Cache the session for permanent usage as well |
810 | if (!(configuration.testSslOption(option: QSsl::SslOptionDisableSessionPersistence))) { |
811 | if (!sslContextPointer->sessionASN1().isEmpty()) |
812 | QTlsBackend::setSessionAsn1(d, asn1: sslContextPointer->sessionASN1()); |
813 | QTlsBackend::setSessionLifetimeHint(d, hint: sslContextPointer->sessionTicketLifeTimeHint()); |
814 | } |
815 | } |
816 | } |
817 | |
818 | #if !defined(OPENSSL_NO_NEXTPROTONEG) |
819 | |
820 | QTlsBackend::setAlpnStatus(d, st: sslContextPointer->npnContext().status); |
821 | if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) { |
822 | // we could not agree -> be conservative and use HTTP/1.1 |
823 | // T.P.: I have to admit, this is a really strange notion of 'conservative', |
824 | // given the protocol-neutral nature of ALPN/NPN. |
825 | QTlsBackend::setNegotiatedProtocol(d, QByteArrayLiteral("http/1.1" )); |
826 | } else { |
827 | const unsigned char *proto = nullptr; |
828 | unsigned int proto_len = 0; |
829 | |
830 | q_SSL_get0_alpn_selected(ssl, data: &proto, len: &proto_len); |
831 | if (proto_len && mode == QSslSocket::SslClientMode) { |
832 | // Client does not have a callback that sets it ... |
833 | QTlsBackend::setAlpnStatus(d, st: QSslConfiguration::NextProtocolNegotiationNegotiated); |
834 | } |
835 | |
836 | if (!proto_len) { // Test if NPN was more lucky ... |
837 | q_SSL_get0_next_proto_negotiated(s: ssl, data: &proto, len: &proto_len); |
838 | } |
839 | |
840 | if (proto_len) |
841 | QTlsBackend::setNegotiatedProtocol(d, protocol: QByteArray(reinterpret_cast<const char *>(proto), proto_len)); |
842 | else |
843 | QTlsBackend::setNegotiatedProtocol(d,protocol: {}); |
844 | } |
845 | #endif // !defined(OPENSSL_NO_NEXTPROTONEG) |
846 | |
847 | if (mode == QSslSocket::SslClientMode) { |
848 | EVP_PKEY *key; |
849 | if (q_SSL_get_server_tmp_key(ssl, &key)) |
850 | QTlsBackend::setEphemeralKey(d, key: QSslKey(key, QSsl::PublicKey)); |
851 | } |
852 | |
853 | d->setEncrypted(true); |
854 | emit q->encrypted(); |
855 | if (d->isAutoStartingHandshake() && d->isPendingClose()) { |
856 | d->setPendingClose(false); |
857 | q->disconnectFromHost(); |
858 | } |
859 | } |
860 | |
861 | void TlsCryptographOpenSSL::transmit() |
862 | { |
863 | Q_ASSERT(q); |
864 | Q_ASSERT(d); |
865 | |
866 | using ScopedBool = QScopedValueRollback<bool>; |
867 | |
868 | if (inSetAndEmitError) |
869 | return; |
870 | |
871 | // If we don't have any SSL context, don't bother transmitting. |
872 | if (!ssl) |
873 | return; |
874 | |
875 | auto &writeBuffer = d->tlsWriteBuffer(); |
876 | auto &buffer = d->tlsBuffer(); |
877 | auto *plainSocket = d->plainTcpSocket(); |
878 | Q_ASSERT(plainSocket); |
879 | bool &emittedBytesWritten = d->tlsEmittedBytesWritten(); |
880 | |
881 | bool transmitting; |
882 | do { |
883 | transmitting = false; |
884 | |
885 | // If the connection is secure, we can transfer data from the write |
886 | // buffer (in plain text) to the write BIO through SSL_write. |
887 | if (q->isEncrypted() && !writeBuffer.isEmpty()) { |
888 | qint64 totalBytesWritten = 0; |
889 | int nextDataBlockSize; |
890 | while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) { |
891 | int writtenBytes = q_SSL_write(a: ssl, b: writeBuffer.readPointer(), c: nextDataBlockSize); |
892 | if (writtenBytes <= 0) { |
893 | int error = q_SSL_get_error(a: ssl, b: writtenBytes); |
894 | //write can result in a want_write_error - not an error - continue transmitting |
895 | if (error == SSL_ERROR_WANT_WRITE) { |
896 | transmitting = true; |
897 | break; |
898 | } else if (error == SSL_ERROR_WANT_READ) { |
899 | //write can result in a want_read error, possibly due to renegotiation - not an error - stop transmitting |
900 | transmitting = false; |
901 | break; |
902 | } else { |
903 | // ### Better error handling. |
904 | const ScopedBool bg(inSetAndEmitError, true); |
905 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
906 | errorDescription: QSslSocket::tr(s: "Unable to write data: %1" ).arg( |
907 | a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
908 | return; |
909 | } |
910 | } |
911 | #ifdef QSSLSOCKET_DEBUG |
912 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encrypted" << writtenBytes << "bytes" ; |
913 | #endif |
914 | writeBuffer.free(bytes: writtenBytes); |
915 | totalBytesWritten += writtenBytes; |
916 | |
917 | if (writtenBytes < nextDataBlockSize) { |
918 | // break out of the writing loop and try again after we had read |
919 | transmitting = true; |
920 | break; |
921 | } |
922 | } |
923 | |
924 | if (totalBytesWritten > 0) { |
925 | // Don't emit bytesWritten() recursively. |
926 | if (!emittedBytesWritten) { |
927 | emittedBytesWritten = true; |
928 | emit q->bytesWritten(bytes: totalBytesWritten); |
929 | emittedBytesWritten = false; |
930 | } |
931 | emit q->channelBytesWritten(channel: 0, bytes: totalBytesWritten); |
932 | } |
933 | } |
934 | |
935 | // Check if we've got any data to be written to the socket. |
936 | QVarLengthArray<char, 4096> data; |
937 | int pendingBytes; |
938 | while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0 |
939 | && plainSocket->openMode() != QIODevice::NotOpen) { |
940 | // Read encrypted data from the write BIO into a buffer. |
941 | data.resize(sz: pendingBytes); |
942 | int encryptedBytesRead = q_BIO_read(a: writeBio, b: data.data(), c: pendingBytes); |
943 | |
944 | // Write encrypted data from the buffer to the socket. |
945 | qint64 actualWritten = plainSocket->write(data: data.constData(), len: encryptedBytesRead); |
946 | #ifdef QSSLSOCKET_DEBUG |
947 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: wrote" << encryptedBytesRead |
948 | << "encrypted bytes to the socket" << actualWritten << "actual." ; |
949 | #endif |
950 | if (actualWritten < 0) { |
951 | //plain socket write fails if it was in the pending close state. |
952 | const ScopedBool bg(inSetAndEmitError, true); |
953 | setErrorAndEmit(d, errorCode: plainSocket->error(), errorDescription: plainSocket->errorString()); |
954 | return; |
955 | } |
956 | transmitting = true; |
957 | } |
958 | |
959 | // Check if we've got any data to be read from the socket. |
960 | if (!q->isEncrypted() || !d->maxReadBufferSize() || buffer.size() < d->maxReadBufferSize()) |
961 | while ((pendingBytes = plainSocket->bytesAvailable()) > 0) { |
962 | // Read encrypted data from the socket into a buffer. |
963 | data.resize(sz: pendingBytes); |
964 | // just peek() here because q_BIO_write could write less data than expected |
965 | int encryptedBytesRead = plainSocket->peek(data: data.data(), maxlen: pendingBytes); |
966 | |
967 | #ifdef QSSLSOCKET_DEBUG |
968 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket" ; |
969 | #endif |
970 | // Write encrypted data from the buffer into the read BIO. |
971 | int writtenToBio = q_BIO_write(a: readBio, b: data.constData(), c: encryptedBytesRead); |
972 | |
973 | // Throw away the results. |
974 | if (writtenToBio > 0) { |
975 | plainSocket->skip(maxSize: writtenToBio); |
976 | } else { |
977 | // ### Better error handling. |
978 | const ScopedBool bg(inSetAndEmitError, true); |
979 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
980 | errorDescription: QSslSocket::tr(s: "Unable to decrypt data: %1" ) |
981 | .arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
982 | return; |
983 | } |
984 | |
985 | transmitting = true; |
986 | } |
987 | |
988 | // If the connection isn't secured yet, this is the time to retry the |
989 | // connect / accept. |
990 | if (!q->isEncrypted()) { |
991 | #ifdef QSSLSOCKET_DEBUG |
992 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: testing encryption" ; |
993 | #endif |
994 | if (startHandshake()) { |
995 | #ifdef QSSLSOCKET_DEBUG |
996 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption established" ; |
997 | #endif |
998 | d->setEncrypted(true); |
999 | transmitting = true; |
1000 | } else if (plainSocket->state() != QAbstractSocket::ConnectedState) { |
1001 | #ifdef QSSLSOCKET_DEBUG |
1002 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: connection lost" ; |
1003 | #endif |
1004 | break; |
1005 | } else if (d->isPaused()) { |
1006 | // just wait until the user continues |
1007 | return; |
1008 | } else { |
1009 | #ifdef QSSLSOCKET_DEBUG |
1010 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: encryption not done yet" ; |
1011 | #endif |
1012 | } |
1013 | } |
1014 | |
1015 | // If the request is small and the remote host closes the transmission |
1016 | // after sending, there's a chance that startHandshake() will already |
1017 | // have triggered a shutdown. |
1018 | if (!ssl) |
1019 | continue; |
1020 | |
1021 | // We always read everything from the SSL decryption buffers, even if |
1022 | // we have a readBufferMaxSize. There's no point in leaving data there |
1023 | // just so that readBuffer.size() == readBufferMaxSize. |
1024 | int readBytes = 0; |
1025 | const int bytesToRead = 4096; |
1026 | do { |
1027 | if (q->readChannelCount() == 0) { |
1028 | // The read buffer is deallocated, don't try resize or write to it. |
1029 | break; |
1030 | } |
1031 | // Don't use SSL_pending(). It's very unreliable. |
1032 | inSslRead = true; |
1033 | readBytes = q_SSL_read(a: ssl, b: buffer.reserve(bytes: bytesToRead), c: bytesToRead); |
1034 | inSslRead = false; |
1035 | if (renegotiated) { |
1036 | renegotiated = false; |
1037 | X509 *x509 = q_SSL_get_peer_certificate(a: ssl); |
1038 | const auto peerCertificate = |
1039 | QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x: x509); |
1040 | // Fail the renegotiate if the certificate has changed, else: continue. |
1041 | if (peerCertificate != q->peerCertificate()) { |
1042 | const ScopedBool bg(inSetAndEmitError, true); |
1043 | setErrorAndEmit( |
1044 | d, errorCode: QAbstractSocket::RemoteHostClosedError, |
1045 | errorDescription: QSslSocket::tr( |
1046 | s: "TLS certificate unexpectedly changed during renegotiation!" )); |
1047 | q->abort(); |
1048 | return; |
1049 | } |
1050 | } |
1051 | if (readBytes > 0) { |
1052 | #ifdef QSSLSOCKET_DEBUG |
1053 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: decrypted" << readBytes << "bytes" ; |
1054 | #endif |
1055 | buffer.chop(bytes: bytesToRead - readBytes); |
1056 | |
1057 | if (bool *readyReadEmittedPointer = d->readyReadPointer()) |
1058 | *readyReadEmittedPointer = true; |
1059 | emit q->readyRead(); |
1060 | emit q->channelReadyRead(channel: 0); |
1061 | transmitting = true; |
1062 | continue; |
1063 | } |
1064 | buffer.chop(bytes: bytesToRead); |
1065 | |
1066 | // Error. |
1067 | switch (q_SSL_get_error(a: ssl, b: readBytes)) { |
1068 | case SSL_ERROR_WANT_READ: |
1069 | case SSL_ERROR_WANT_WRITE: |
1070 | // Out of data. |
1071 | break; |
1072 | case SSL_ERROR_ZERO_RETURN: |
1073 | // The remote host closed the connection. |
1074 | #ifdef QSSLSOCKET_DEBUG |
1075 | qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: remote disconnect" ; |
1076 | #endif |
1077 | shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves |
1078 | { |
1079 | const ScopedBool bg(inSetAndEmitError, true); |
1080 | setErrorAndEmit(d, errorCode: QAbstractSocket::RemoteHostClosedError, |
1081 | errorDescription: QSslSocket::tr(s: "The TLS/SSL connection has been closed" )); |
1082 | } |
1083 | return; |
1084 | case SSL_ERROR_SYSCALL: // some IO error |
1085 | case SSL_ERROR_SSL: // error in the SSL library |
1086 | // we do not know exactly what the error is, nor whether we can recover from it, |
1087 | // so just return to prevent an endless loop in the outer "while" statement |
1088 | systemOrSslErrorDetected = true; |
1089 | { |
1090 | const ScopedBool bg(inSetAndEmitError, true); |
1091 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
1092 | errorDescription: QSslSocket::tr(s: "Error while reading: %1" ) |
1093 | .arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
1094 | } |
1095 | return; |
1096 | default: |
1097 | // SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a |
1098 | // BIO_s_connect() or BIO_s_accept(), which we do not call. |
1099 | // SSL_ERROR_WANT_X509_LOOKUP: can only happen with a |
1100 | // SSL_CTX_set_client_cert_cb(), which we do not call. |
1101 | // So this default case should never be triggered. |
1102 | { |
1103 | const ScopedBool bg(inSetAndEmitError, true); |
1104 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
1105 | errorDescription: QSslSocket::tr(s: "Error while reading: %1" ) |
1106 | .arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
1107 | } |
1108 | break; |
1109 | } |
1110 | } while (ssl && readBytes > 0); |
1111 | } while (ssl && transmitting); |
1112 | } |
1113 | |
1114 | void TlsCryptographOpenSSL::disconnectFromHost() |
1115 | { |
1116 | if (ssl) { |
1117 | if (!shutdown && !q_SSL_in_init(s: ssl) && !systemOrSslErrorDetected) { |
1118 | if (q_SSL_shutdown(a: ssl) != 1) { |
1119 | // Some error may be queued, clear it. |
1120 | QTlsBackendOpenSSL::clearErrorQueue(); |
1121 | } |
1122 | shutdown = true; |
1123 | transmit(); |
1124 | } |
1125 | } |
1126 | Q_ASSERT(d); |
1127 | auto *plainSocket = d->plainTcpSocket(); |
1128 | Q_ASSERT(plainSocket); |
1129 | plainSocket->disconnectFromHost(); |
1130 | } |
1131 | |
1132 | void TlsCryptographOpenSSL::disconnected() |
1133 | { |
1134 | Q_ASSERT(d); |
1135 | auto *plainSocket = d->plainTcpSocket(); |
1136 | Q_ASSERT(plainSocket); |
1137 | d->setEncrypted(false); |
1138 | |
1139 | if (plainSocket->bytesAvailable() <= 0) { |
1140 | destroySslContext(); |
1141 | } else { |
1142 | // Move all bytes into the plain buffer. |
1143 | const qint64 tmpReadBufferMaxSize = d->maxReadBufferSize(); |
1144 | // Reset temporarily, so the plain socket buffer is completely drained: |
1145 | d->setMaxReadBufferSize(0); |
1146 | transmit(); |
1147 | d->setMaxReadBufferSize(tmpReadBufferMaxSize); |
1148 | } |
1149 | //if there is still buffered data in the plain socket, don't destroy the ssl context yet. |
1150 | //it will be destroyed when the socket is deleted. |
1151 | } |
1152 | |
1153 | QSslCipher TlsCryptographOpenSSL::sessionCipher() const |
1154 | { |
1155 | if (!ssl) |
1156 | return {}; |
1157 | |
1158 | const SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(a: ssl); |
1159 | return sessionCipher ? QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher: sessionCipher) : QSslCipher{}; |
1160 | } |
1161 | |
1162 | QSsl::SslProtocol TlsCryptographOpenSSL::sessionProtocol() const |
1163 | { |
1164 | if (!ssl) |
1165 | return QSsl::UnknownProtocol; |
1166 | |
1167 | const int ver = q_SSL_version(a: ssl); |
1168 | switch (ver) { |
1169 | QT_WARNING_PUSH |
1170 | QT_WARNING_DISABLE_DEPRECATED |
1171 | case 0x301: |
1172 | return QSsl::TlsV1_0; |
1173 | case 0x302: |
1174 | return QSsl::TlsV1_1; |
1175 | QT_WARNING_POP |
1176 | case 0x303: |
1177 | return QSsl::TlsV1_2; |
1178 | case 0x304: |
1179 | return QSsl::TlsV1_3; |
1180 | } |
1181 | |
1182 | return QSsl::UnknownProtocol; |
1183 | } |
1184 | |
1185 | QList<QOcspResponse> TlsCryptographOpenSSL::ocsps() const |
1186 | { |
1187 | return ocspResponses; |
1188 | } |
1189 | |
1190 | bool TlsCryptographOpenSSL::checkSslErrors() |
1191 | { |
1192 | Q_ASSERT(q); |
1193 | Q_ASSERT(d); |
1194 | |
1195 | if (sslErrors.isEmpty()) |
1196 | return true; |
1197 | |
1198 | emit q->sslErrors(errors: sslErrors); |
1199 | |
1200 | const auto vfyMode = q->peerVerifyMode(); |
1201 | const auto mode = d->tlsMode(); |
1202 | |
1203 | bool doVerifyPeer = vfyMode == QSslSocket::VerifyPeer || (vfyMode == QSslSocket::AutoVerifyPeer |
1204 | && mode == QSslSocket::SslClientMode); |
1205 | bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored(); |
1206 | // check whether we need to emit an SSL handshake error |
1207 | if (doVerifyPeer && doEmitSslError) { |
1208 | if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) { |
1209 | QSslSocketPrivate::pauseSocketNotifiers(q); |
1210 | d->setPaused(true); |
1211 | } else { |
1212 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslHandshakeFailedError, errorDescription: sslErrors.constFirst().errorString()); |
1213 | auto *plainSocket = d->plainTcpSocket(); |
1214 | Q_ASSERT(plainSocket); |
1215 | plainSocket->disconnectFromHost(); |
1216 | } |
1217 | return false; |
1218 | } |
1219 | return true; |
1220 | } |
1221 | |
1222 | int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection) |
1223 | { |
1224 | // If we return 1, this means we own the session, but we don't. |
1225 | // 0 would tell OpenSSL to deref (but they still have it in the |
1226 | // internal cache). |
1227 | Q_ASSERT(connection); |
1228 | |
1229 | Q_ASSERT(q); |
1230 | Q_ASSERT(d); |
1231 | |
1232 | if (q->sslConfiguration().testSslOption(option: QSsl::SslOptionDisableSessionPersistence)) { |
1233 | // We silently ignore, do nothing, remove from cache. |
1234 | return 0; |
1235 | } |
1236 | |
1237 | SSL_SESSION *currentSession = q_SSL_get_session(ssl: connection); |
1238 | if (!currentSession) { |
1239 | qCWarning(lcTlsBackend, |
1240 | "New session ticket callback, the session is invalid (nullptr)" ); |
1241 | return 0; |
1242 | } |
1243 | |
1244 | if (q_SSL_version(a: connection) < 0x304) { |
1245 | // We only rely on this mechanics with TLS >= 1.3 |
1246 | return 0; |
1247 | } |
1248 | |
1249 | #ifdef TLS1_3_VERSION |
1250 | if (!q_SSL_SESSION_is_resumable(s: currentSession)) { |
1251 | qCDebug(lcTlsBackend, "New session ticket, but the session is non-resumable" ); |
1252 | return 0; |
1253 | } |
1254 | #endif // TLS1_3_VERSION |
1255 | |
1256 | const int sessionSize = q_i2d_SSL_SESSION(in: currentSession, pp: nullptr); |
1257 | if (sessionSize <= 0) { |
1258 | qCWarning(lcTlsBackend, "could not store persistent version of SSL session" ); |
1259 | return 0; |
1260 | } |
1261 | |
1262 | // We have somewhat perverse naming, it's not a ticket, it's a session. |
1263 | QByteArray sessionTicket(sessionSize, 0); |
1264 | auto data = reinterpret_cast<unsigned char *>(sessionTicket.data()); |
1265 | if (!q_i2d_SSL_SESSION(in: currentSession, pp: &data)) { |
1266 | qCWarning(lcTlsBackend, "could not store persistent version of SSL session" ); |
1267 | return 0; |
1268 | } |
1269 | |
1270 | QTlsBackend::setSessionAsn1(d, asn1: sessionTicket); |
1271 | QTlsBackend::setSessionLifetimeHint(d, hint: q_SSL_SESSION_get_ticket_lifetime_hint(session: currentSession)); |
1272 | |
1273 | emit q->newSessionTicketReceived(); |
1274 | return 0; |
1275 | } |
1276 | |
1277 | void TlsCryptographOpenSSL::alertMessageSent(int value) |
1278 | { |
1279 | Q_ASSERT(q); |
1280 | Q_ASSERT(d); |
1281 | |
1282 | const auto level = tlsAlertLevel(value); |
1283 | if (level == QSsl::AlertLevel::Fatal && !q->isEncrypted()) { |
1284 | // Note, this logic is handshake-time only: |
1285 | pendingFatalAlert = true; |
1286 | } |
1287 | |
1288 | emit q->alertSent(level, type: tlsAlertType(value), description: tlsAlertDescription(value)); |
1289 | |
1290 | } |
1291 | |
1292 | void TlsCryptographOpenSSL::alertMessageReceived(int value) |
1293 | { |
1294 | Q_ASSERT(q); |
1295 | |
1296 | emit q->alertReceived(level: tlsAlertLevel(value), type: tlsAlertType(value), description: tlsAlertDescription(value)); |
1297 | } |
1298 | |
1299 | int TlsCryptographOpenSSL::emitErrorFromCallback(X509_STORE_CTX *ctx) |
1300 | { |
1301 | // Returns 0 to abort verification, 1 to continue despite error (as |
1302 | // OpenSSL expects from the verification callback). |
1303 | Q_ASSERT(q); |
1304 | Q_ASSERT(ctx); |
1305 | |
1306 | using ScopedBool = QScopedValueRollback<bool>; |
1307 | // While we are not setting, we are emitting and in general - |
1308 | // we want to prevent accidental recursive startHandshake() |
1309 | // calls: |
1310 | const ScopedBool bg(inSetAndEmitError, true); |
1311 | |
1312 | X509 *x509 = q_X509_STORE_CTX_get_current_cert(ctx); |
1313 | if (!x509) { |
1314 | qCWarning(lcTlsBackend, "Could not obtain the certificate (that failed to verify)" ); |
1315 | return 0; |
1316 | } |
1317 | |
1318 | const QSslCertificate certificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x: x509); |
1319 | const auto errorAndDepth = QTlsPrivate::X509CertificateOpenSSL::errorEntryFromStoreContext(ctx); |
1320 | const QSslError tlsError = QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(errorCode: errorAndDepth.code, cert: certificate); |
1321 | |
1322 | errorsReportedFromCallback = true; |
1323 | handshakeInterrupted = true; |
1324 | emit q->handshakeInterruptedOnError(error: tlsError); |
1325 | |
1326 | // Conveniently so, we also can access 'lastErrors' external data set |
1327 | // in startHandshake, we store it for the case an application later |
1328 | // wants to check errors (ignored or not): |
1329 | const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData |
1330 | + TlsCryptographOpenSSL::errorOffsetInExData; |
1331 | if (auto errorList = static_cast<QList<QSslErrorEntry> *>(q_SSL_get_ex_data(ssl, idx: offset))) |
1332 | errorList->append(t: errorAndDepth); |
1333 | |
1334 | // An application is expected to ignore this error (by calling ignoreSslErrors) |
1335 | // in its directly connected slot: |
1336 | return !handshakeInterrupted; |
1337 | } |
1338 | |
1339 | void TlsCryptographOpenSSL::trySendFatalAlert() |
1340 | { |
1341 | Q_ASSERT(pendingFatalAlert); |
1342 | Q_ASSERT(d); |
1343 | |
1344 | auto *plainSocket = d->plainTcpSocket(); |
1345 | |
1346 | pendingFatalAlert = false; |
1347 | QVarLengthArray<char, 4096> data; |
1348 | int pendingBytes = 0; |
1349 | while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0 |
1350 | && plainSocket->openMode() != QIODevice::NotOpen) { |
1351 | // Read encrypted data from the write BIO into a buffer. |
1352 | data.resize(sz: pendingBytes); |
1353 | const int bioReadBytes = q_BIO_read(a: writeBio, b: data.data(), c: pendingBytes); |
1354 | |
1355 | // Write encrypted data from the buffer to the socket. |
1356 | qint64 actualWritten = plainSocket->write(data: data.constData(), len: bioReadBytes); |
1357 | if (actualWritten < 0) |
1358 | return; |
1359 | plainSocket->flush(); |
1360 | } |
1361 | } |
1362 | |
1363 | bool TlsCryptographOpenSSL::initSslContext() |
1364 | { |
1365 | Q_ASSERT(q); |
1366 | Q_ASSERT(d); |
1367 | |
1368 | // If no external context was set (e.g. by QHttpNetworkConnection) we will |
1369 | // create a new one. |
1370 | const auto mode = d->tlsMode(); |
1371 | const auto configuration = q->sslConfiguration(); |
1372 | if (!sslContextPointer) |
1373 | sslContextPointer = QSslContext::sharedFromConfiguration(mode, configuration, allowRootCertOnDemandLoading: d->isRootsOnDemandAllowed()); |
1374 | |
1375 | if (sslContextPointer->error() != QSslError::NoError) { |
1376 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInvalidUserDataError, errorDescription: sslContextPointer->errorString()); |
1377 | sslContextPointer.reset(); |
1378 | return false; |
1379 | } |
1380 | |
1381 | // Create and initialize SSL session |
1382 | if (!(ssl = sslContextPointer->createSsl())) { |
1383 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
1384 | errorDescription: QSslSocket::tr(s: "Error creating SSL session, %1" ).arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
1385 | return false; |
1386 | } |
1387 | |
1388 | if (configuration.protocol() != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) { |
1389 | const auto verificationPeerName = d->verificationName(); |
1390 | // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format. |
1391 | QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName; |
1392 | if (tlsHostName.isEmpty()) |
1393 | tlsHostName = d->tlsHostName(); |
1394 | QByteArray ace = QUrl::toAce(domain: tlsHostName); |
1395 | // only send the SNI header if the URL is valid and not an IP |
1396 | if (!ace.isEmpty() |
1397 | && !QHostAddress().setAddress(tlsHostName) |
1398 | && !(configuration.testSslOption(option: QSsl::SslOptionDisableServerNameIndication))) { |
1399 | // We don't send the trailing dot from the host header if present see |
1400 | // https://tools.ietf.org/html/rfc6066#section-3 |
1401 | if (ace.endsWith(c: '.')) |
1402 | ace.chop(n: 1); |
1403 | if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, parg: ace.data())) |
1404 | qCWarning(lcTlsBackend, "could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled" ); |
1405 | } |
1406 | } |
1407 | |
1408 | // Clear the session. |
1409 | errorList.clear(); |
1410 | |
1411 | // Initialize memory BIOs for encryption and decryption. |
1412 | readBio = q_BIO_new(a: q_BIO_s_mem()); |
1413 | writeBio = q_BIO_new(a: q_BIO_s_mem()); |
1414 | if (!readBio || !writeBio) { |
1415 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
1416 | errorDescription: QSslSocket::tr(s: "Error creating SSL session: %1" ).arg(a: QTlsBackendOpenSSL::getErrorsFromOpenSsl())); |
1417 | if (readBio) |
1418 | q_BIO_free(a: readBio); |
1419 | if (writeBio) |
1420 | q_BIO_free(a: writeBio); |
1421 | return false; |
1422 | } |
1423 | |
1424 | // Assign the bios. |
1425 | q_SSL_set_bio(a: ssl, b: readBio, c: writeBio); |
1426 | |
1427 | if (mode == QSslSocket::SslClientMode) |
1428 | q_SSL_set_connect_state(a: ssl); |
1429 | else |
1430 | q_SSL_set_accept_state(a: ssl); |
1431 | |
1432 | q_SSL_set_ex_data(ssl, idx: QTlsBackendOpenSSL::s_indexForSSLExtraData, arg: this); |
1433 | |
1434 | #ifndef OPENSSL_NO_PSK |
1435 | // Set the client callback for PSK |
1436 | if (mode == QSslSocket::SslClientMode) |
1437 | q_SSL_set_psk_client_callback(ssl, callback: &q_ssl_psk_client_callback); |
1438 | else if (mode == QSslSocket::SslServerMode) |
1439 | q_SSL_set_psk_server_callback(ssl, callback: &q_ssl_psk_server_callback); |
1440 | |
1441 | #if OPENSSL_VERSION_NUMBER >= 0x10101006L |
1442 | // Set the client callback for TLSv1.3 PSK |
1443 | if (mode == QSslSocket::SslClientMode |
1444 | && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) { |
1445 | q_SSL_set_psk_use_session_callback(s: ssl, &q_ssl_psk_use_session_callback); |
1446 | } |
1447 | #endif // openssl version >= 0x10101006L |
1448 | |
1449 | #endif // OPENSSL_NO_PSK |
1450 | |
1451 | #if QT_CONFIG(ocsp) |
1452 | if (configuration.ocspStaplingEnabled()) { |
1453 | if (mode == QSslSocket::SslServerMode) { |
1454 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInvalidUserDataError, |
1455 | errorDescription: QSslSocket::tr(s: "Server-side QSslSocket does not support OCSP stapling" )); |
1456 | return false; |
1457 | } |
1458 | if (q_SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp) != 1) { |
1459 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInternalError, |
1460 | errorDescription: QSslSocket::tr(s: "Failed to enable OCSP stapling" )); |
1461 | return false; |
1462 | } |
1463 | } |
1464 | |
1465 | ocspResponseDer.clear(); |
1466 | const auto backendConfig = configuration.backendConfiguration(); |
1467 | auto responsePos = backendConfig.find(key: "Qt-OCSP-response" ); |
1468 | if (responsePos != backendConfig.end()) { |
1469 | // This is our private, undocumented 'API' we use for the auto-testing of |
1470 | // OCSP-stapling. It must be a der-encoded OCSP response, presumably set |
1471 | // by tst_QOcsp. |
1472 | const QVariant data(responsePos.value()); |
1473 | if (data.canConvert<QByteArray>()) |
1474 | ocspResponseDer = data.toByteArray(); |
1475 | } |
1476 | |
1477 | if (ocspResponseDer.size()) { |
1478 | if (mode != QSslSocket::SslServerMode) { |
1479 | setErrorAndEmit(d, errorCode: QAbstractSocket::SslInvalidUserDataError, |
1480 | errorDescription: QSslSocket::tr(s: "Client-side sockets do not send OCSP responses" )); |
1481 | return false; |
1482 | } |
1483 | } |
1484 | #endif // ocsp |
1485 | |
1486 | return true; |
1487 | } |
1488 | |
1489 | void TlsCryptographOpenSSL::destroySslContext() |
1490 | { |
1491 | if (ssl) { |
1492 | if (!q_SSL_in_init(s: ssl) && !systemOrSslErrorDetected) { |
1493 | // We do not send a shutdown alert here. Just mark the session as |
1494 | // resumable for qhttpnetworkconnection's "optimization", otherwise |
1495 | // OpenSSL won't start a session resumption. |
1496 | if (q_SSL_shutdown(a: ssl) != 1) { |
1497 | // Some error may be queued, clear it. |
1498 | const auto errors = QTlsBackendOpenSSL::getErrorsFromOpenSsl(); |
1499 | Q_UNUSED(errors); |
1500 | } |
1501 | } |
1502 | q_SSL_free(a: ssl); |
1503 | ssl = nullptr; |
1504 | } |
1505 | sslContextPointer.reset(); |
1506 | } |
1507 | |
1508 | void TlsCryptographOpenSSL::storePeerCertificates() |
1509 | { |
1510 | Q_ASSERT(d); |
1511 | |
1512 | // Store the peer certificate and chain. For clients, the peer certificate |
1513 | // chain includes the peer certificate; for servers, it doesn't. Both the |
1514 | // peer certificate and the chain may be empty if the peer didn't present |
1515 | // any certificate. |
1516 | X509 *x509 = q_SSL_get_peer_certificate(a: ssl); |
1517 | |
1518 | const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x: x509); |
1519 | QTlsBackend::storePeerCertificate(d, peerCert: peerCertificate); |
1520 | q_X509_free(a: x509); |
1521 | auto peerCertificateChain = q->peerCertificateChain(); |
1522 | if (peerCertificateChain.isEmpty()) { |
1523 | peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(x509: q_SSL_get_peer_cert_chain(a: ssl)); |
1524 | if (!peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode) |
1525 | peerCertificateChain.prepend(t: peerCertificate); |
1526 | QTlsBackend::storePeerCertificateChain(d, peerChain: peerCertificateChain); |
1527 | } |
1528 | } |
1529 | |
1530 | #if QT_CONFIG(ocsp) |
1531 | |
1532 | bool TlsCryptographOpenSSL::checkOcspStatus() |
1533 | { |
1534 | Q_ASSERT(ssl); |
1535 | Q_ASSERT(d); |
1536 | |
1537 | const auto &configuration = q->sslConfiguration(); |
1538 | Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode |
1539 | Q_ASSERT(configuration.peerVerifyMode() != QSslSocket::VerifyNone); |
1540 | |
1541 | const auto clearErrorQueue = qScopeGuard(f: [] { |
1542 | QTlsBackendOpenSSL::logAndClearErrorQueue(); |
1543 | }); |
1544 | |
1545 | ocspResponses.clear(); |
1546 | ocspErrorDescription.clear(); |
1547 | ocspErrors.clear(); |
1548 | |
1549 | const unsigned char *responseData = nullptr; |
1550 | const long responseLength = q_SSL_get_tlsext_status_ocsp_resp(ssl, &responseData); |
1551 | if (responseLength <= 0 || !responseData) { |
1552 | ocspErrors.push_back(t: QSslError(QSslError::OcspNoResponseFound)); |
1553 | return false; |
1554 | } |
1555 | |
1556 | OCSP_RESPONSE *response = q_d2i_OCSP_RESPONSE(a: nullptr, in: &responseData, len: responseLength); |
1557 | if (!response) { |
1558 | // Treat this as a fatal SslHandshakeError. |
1559 | ocspErrorDescription = QSslSocket::tr(s: "Failed to decode OCSP response" ); |
1560 | return false; |
1561 | } |
1562 | const QSharedPointer<OCSP_RESPONSE> responseGuard(response, q_OCSP_RESPONSE_free); |
1563 | |
1564 | const int ocspStatus = q_OCSP_response_status(resp: response); |
1565 | if (ocspStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) { |
1566 | // It's not a definitive response, it's an error message (not signed by the responder). |
1567 | ocspErrors.push_back(t: QSslError(qt_OCSP_response_status_to_SslError(code: ocspStatus))); |
1568 | return false; |
1569 | } |
1570 | |
1571 | OCSP_BASICRESP *basicResponse = q_OCSP_response_get1_basic(resp: response); |
1572 | if (!basicResponse) { |
1573 | // SslHandshakeError. |
1574 | ocspErrorDescription = QSslSocket::tr(s: "Failed to extract basic OCSP response" ); |
1575 | return false; |
1576 | } |
1577 | const QSharedPointer<OCSP_BASICRESP> basicResponseGuard(basicResponse, q_OCSP_BASICRESP_free); |
1578 | |
1579 | SSL_CTX *ctx = q_SSL_get_SSL_CTX(a: ssl); // Does not increment refcount. |
1580 | Q_ASSERT(ctx); |
1581 | X509_STORE *store = q_SSL_CTX_get_cert_store(a: ctx); // Does not increment refcount. |
1582 | if (!store) { |
1583 | // SslHandshakeError. |
1584 | ocspErrorDescription = QSslSocket::tr(s: "No certificate verification store, cannot verify OCSP response" ); |
1585 | return false; |
1586 | } |
1587 | |
1588 | STACK_OF(X509) *peerChain = q_SSL_get_peer_cert_chain(a: ssl); // Does not increment refcount. |
1589 | X509 *peerX509 = q_SSL_get_peer_certificate(a: ssl); |
1590 | Q_ASSERT(peerChain || peerX509); |
1591 | const QSharedPointer<X509> peerX509Guard(peerX509, q_X509_free); |
1592 | // OCSP_basic_verify with 0 as verificationFlags: |
1593 | // |
1594 | // 0) Tries to find the OCSP responder's certificate in either peerChain |
1595 | // or basicResponse->certs. If not found, verification fails. |
1596 | // 1) It checks the signature using the responder's public key. |
1597 | // 2) Then it tries to validate the responder's cert (building a chain |
1598 | // etc.) |
1599 | // 3) It checks CertID in response. |
1600 | // 4) Ensures the responder is authorized to sign the status respond. |
1601 | // |
1602 | // Note, OpenSSL prior to 1.0.2b would only use bs->certs to |
1603 | // verify the responder's chain (see their commit 4ba9a4265bd). |
1604 | // Working this around - is too much fuss for ancient versions we |
1605 | // are dropping quite soon anyway. |
1606 | const unsigned long verificationFlags = 0; |
1607 | const int success = q_OCSP_basic_verify(bs: basicResponse, certs: peerChain, st: store, flags: verificationFlags); |
1608 | if (success <= 0) |
1609 | ocspErrors.push_back(t: QSslError(QSslError::OcspResponseCannotBeTrusted)); |
1610 | |
1611 | if (q_OCSP_resp_count(bs: basicResponse) != 1) { |
1612 | ocspErrors.push_back(t: QSslError(QSslError::OcspMalformedResponse)); |
1613 | return false; |
1614 | } |
1615 | |
1616 | OCSP_SINGLERESP *singleResponse = q_OCSP_resp_get0(bs: basicResponse, idx: 0); |
1617 | if (!singleResponse) { |
1618 | ocspErrors.clear(); |
1619 | // A fatal problem -> SslHandshakeError. |
1620 | ocspErrorDescription = QSslSocket::tr(s: "Failed to decode a SingleResponse from OCSP status response" ); |
1621 | return false; |
1622 | } |
1623 | |
1624 | // Let's make sure the response is for the correct certificate - we |
1625 | // can re-create this CertID using our peer's certificate and its |
1626 | // issuer's public key. |
1627 | ocspResponses.push_back(t: QOcspResponse()); |
1628 | QOcspResponsePrivate *dResponse = ocspResponses.back().d.data(); |
1629 | dResponse->subjectCert = configuration.peerCertificate(); |
1630 | bool matchFound = false; |
1631 | if (dResponse->subjectCert.isSelfSigned()) { |
1632 | dResponse->signerCert = configuration.peerCertificate(); |
1633 | matchFound = qt_OCSP_certificate_match(singleResponse, peerCert: peerX509, issuer: peerX509); |
1634 | } else { |
1635 | const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(a: ssl); |
1636 | if (!certs) // Oh, what a cataclysm! Last try: |
1637 | certs = q_OCSP_resp_get0_certs(bs: basicResponse); |
1638 | if (certs) { |
1639 | // It could be the first certificate in 'certs' is our peer's |
1640 | // certificate. Since it was not captured by the 'self-signed' branch |
1641 | // above, the CertID will not match and we'll just iterate on to the |
1642 | // next certificate. So we start from 0, not 1. |
1643 | for (int i = 0, e = q_sk_X509_num(certs); i < e; ++i) { |
1644 | X509 *issuer = q_sk_X509_value(certs, i); |
1645 | matchFound = qt_OCSP_certificate_match(singleResponse, peerCert: peerX509, issuer); |
1646 | if (matchFound) { |
1647 | if (q_X509_check_issued(a: issuer, b: peerX509) == X509_V_OK) { |
1648 | dResponse->signerCert = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x: issuer); |
1649 | break; |
1650 | } |
1651 | matchFound = false; |
1652 | } |
1653 | } |
1654 | } |
1655 | } |
1656 | |
1657 | if (!matchFound) { |
1658 | dResponse->signerCert.clear(); |
1659 | ocspErrors.push_back(t: {QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate()}); |
1660 | } |
1661 | |
1662 | // Check if the response is valid time-wise: |
1663 | ASN1_GENERALIZEDTIME *revTime = nullptr; |
1664 | ASN1_GENERALIZEDTIME *thisUpdate = nullptr; |
1665 | ASN1_GENERALIZEDTIME *nextUpdate = nullptr; |
1666 | int reason; |
1667 | const int certStatus = q_OCSP_single_get0_status(single: singleResponse, reason: &reason, revtime: &revTime, thisupd: &thisUpdate, nextupd: &nextUpdate); |
1668 | if (!thisUpdate) { |
1669 | // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer |
1670 | // to be != nullptr. |
1671 | ocspErrors.clear(); |
1672 | ocspResponses.clear(); |
1673 | ocspErrorDescription = QSslSocket::tr(s: "Failed to extract 'this update time' from the SingleResponse" ); |
1674 | return false; |
1675 | } |
1676 | |
1677 | // OCSP_check_validity(this, next, nsec, maxsec) does this check: |
1678 | // this <= now <= next. They allow some freedom to account |
1679 | // for delays/time inaccuracy. |
1680 | // this > now + nsec ? -> NOT_YET_VALID |
1681 | // if maxsec >= 0: |
1682 | // now - maxsec > this ? -> TOO_OLD |
1683 | // now - nsec > next ? -> EXPIRED |
1684 | // next < this ? -> NEXT_BEFORE_THIS |
1685 | // OK. |
1686 | if (!q_OCSP_check_validity(thisupd: thisUpdate, nextupd: nextUpdate, nsec: 60, maxsec: -1)) |
1687 | ocspErrors.push_back(t: {QSslError::OcspResponseExpired, configuration.peerCertificate()}); |
1688 | |
1689 | // And finally, the status: |
1690 | switch (certStatus) { |
1691 | case V_OCSP_CERTSTATUS_GOOD: |
1692 | // This certificate was not found among the revoked ones. |
1693 | dResponse->certificateStatus = QOcspCertificateStatus::Good; |
1694 | break; |
1695 | case V_OCSP_CERTSTATUS_REVOKED: |
1696 | dResponse->certificateStatus = QOcspCertificateStatus::Revoked; |
1697 | dResponse->revocationReason = qt_OCSP_revocation_reason(reason); |
1698 | ocspErrors.push_back(t: {QSslError::CertificateRevoked, configuration.peerCertificate()}); |
1699 | break; |
1700 | case V_OCSP_CERTSTATUS_UNKNOWN: |
1701 | dResponse->certificateStatus = QOcspCertificateStatus::Unknown; |
1702 | ocspErrors.push_back(t: {QSslError::OcspStatusUnknown, configuration.peerCertificate()}); |
1703 | } |
1704 | |
1705 | return !ocspErrors.size(); |
1706 | } |
1707 | |
1708 | #endif // QT_CONFIG(ocsp) |
1709 | |
1710 | |
1711 | unsigned TlsCryptographOpenSSL::pskClientTlsCallback(const char *hint, char *identity, |
1712 | unsigned max_identity_len, |
1713 | unsigned char *psk, unsigned max_psk_len) |
1714 | { |
1715 | Q_ASSERT(q); |
1716 | |
1717 | QSslPreSharedKeyAuthenticator authenticator; |
1718 | // Fill in some read-only fields (for the user) |
1719 | const int hintLength = hint ? int(std::strlen(s: hint)) : 0; |
1720 | QTlsBackend::setupClientPskAuth(auth: &authenticator, hint, hintLength, maxIdentityLen: max_identity_len, maxPskLen: max_psk_len); |
1721 | // Let the client provide the remaining bits... |
1722 | emit q->preSharedKeyAuthenticationRequired(authenticator: &authenticator); |
1723 | |
1724 | // No PSK set? Return now to make the handshake fail |
1725 | if (authenticator.preSharedKey().isEmpty()) |
1726 | return 0; |
1727 | |
1728 | // Copy data back into OpenSSL |
1729 | const int identityLength = qMin(a: authenticator.identity().size(), b: authenticator.maximumIdentityLength()); |
1730 | std::memcpy(dest: identity, src: authenticator.identity().constData(), n: identityLength); |
1731 | identity[identityLength] = 0; |
1732 | |
1733 | const int pskLength = qMin(a: authenticator.preSharedKey().size(), b: authenticator.maximumPreSharedKeyLength()); |
1734 | std::memcpy(dest: psk, src: authenticator.preSharedKey().constData(), n: pskLength); |
1735 | return pskLength; |
1736 | } |
1737 | |
1738 | unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsigned char *psk, |
1739 | unsigned max_psk_len) |
1740 | { |
1741 | Q_ASSERT(q); |
1742 | |
1743 | QSslPreSharedKeyAuthenticator authenticator; |
1744 | |
1745 | // Fill in some read-only fields (for the user) |
1746 | QTlsBackend::setupServerPskAuth(auth: &authenticator, identity, identityHint: q->sslConfiguration().preSharedKeyIdentityHint(), |
1747 | maxPskLen: max_psk_len); |
1748 | emit q->preSharedKeyAuthenticationRequired(authenticator: &authenticator); |
1749 | |
1750 | // No PSK set? Return now to make the handshake fail |
1751 | if (authenticator.preSharedKey().isEmpty()) |
1752 | return 0; |
1753 | |
1754 | // Copy data back into OpenSSL |
1755 | const int pskLength = qMin(a: authenticator.preSharedKey().size(), b: authenticator.maximumPreSharedKeyLength()); |
1756 | std::memcpy(dest: psk, src: authenticator.preSharedKey().constData(), n: pskLength); |
1757 | return pskLength; |
1758 | } |
1759 | |
1760 | bool TlsCryptographOpenSSL::isInSslRead() const |
1761 | { |
1762 | return inSslRead; |
1763 | } |
1764 | |
1765 | void TlsCryptographOpenSSL::setRenegotiated(bool renegotiated) |
1766 | { |
1767 | this->renegotiated = renegotiated; |
1768 | } |
1769 | |
1770 | #ifdef Q_OS_WIN |
1771 | |
1772 | void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert) |
1773 | { |
1774 | Q_ASSERT(d); |
1775 | Q_ASSERT(q); |
1776 | |
1777 | //The root certificate is downloaded from windows update, which blocks for 15 seconds in the worst case |
1778 | //so the request is done in a worker thread. |
1779 | QList<QSslCertificate> customRoots; |
1780 | if (fetchAuthorityInformation) |
1781 | customRoots = q->sslConfiguration().caCertificates(); |
1782 | |
1783 | //Remember we are fetching and what we are fetching: |
1784 | caToFetch = cert; |
1785 | |
1786 | QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, d->tlsMode(), customRoots, |
1787 | q->peerVerifyName()); |
1788 | connect(fetcher, &QWindowsCaRootFetcher::finished, this, &TlsCryptographOpenSSL::caRootLoaded, |
1789 | Qt::QueuedConnection); |
1790 | QMetaObject::invokeMethod(fetcher, "start" , Qt::QueuedConnection); |
1791 | QSslSocketPrivate::pauseSocketNotifiers(q); |
1792 | d->setPaused(true); |
1793 | } |
1794 | |
1795 | void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot) |
1796 | { |
1797 | if (caToFetch != cert) { |
1798 | //Ooops, something from the previous connection attempt, ignore! |
1799 | return; |
1800 | } |
1801 | |
1802 | Q_ASSERT(d); |
1803 | Q_ASSERT(q); |
1804 | |
1805 | //Done, fetched already: |
1806 | caToFetch.reset(); |
1807 | |
1808 | if (fetchAuthorityInformation) { |
1809 | if (!q->sslConfiguration().caCertificates().contains(trustedRoot)) |
1810 | trustedRoot = QSslCertificate{}; |
1811 | fetchAuthorityInformation = false; |
1812 | } |
1813 | |
1814 | if (!trustedRoot.isNull() && !trustedRoot.isBlacklisted()) { |
1815 | if (QSslSocketPrivate::rootCertOnDemandLoadingSupported()) { |
1816 | //Add the new root cert to default cert list for use by future sockets |
1817 | auto defaultConfig = QSslConfiguration::defaultConfiguration(); |
1818 | defaultConfig.addCaCertificate(trustedRoot); |
1819 | QSslConfiguration::setDefaultConfiguration(defaultConfig); |
1820 | } |
1821 | //Add the new root cert to this socket for future connections |
1822 | QTlsBackend::addTustedRoot(d, trustedRoot); |
1823 | //Remove the broken chain ssl errors (as chain is verified by windows) |
1824 | for (int i=sslErrors.count() - 1; i >= 0; --i) { |
1825 | if (sslErrors.at(i).certificate() == cert) { |
1826 | switch (sslErrors.at(i).error()) { |
1827 | case QSslError::UnableToGetLocalIssuerCertificate: |
1828 | case QSslError::CertificateUntrusted: |
1829 | case QSslError::UnableToVerifyFirstCertificate: |
1830 | case QSslError::SelfSignedCertificateInChain: |
1831 | // error can be ignored if OS says the chain is trusted |
1832 | sslErrors.removeAt(i); |
1833 | break; |
1834 | default: |
1835 | // error cannot be ignored |
1836 | break; |
1837 | } |
1838 | } |
1839 | } |
1840 | } |
1841 | |
1842 | auto *plainSocket = d->plainTcpSocket(); |
1843 | Q_ASSERT(plainSocket); |
1844 | // Continue with remaining errors |
1845 | if (plainSocket) |
1846 | plainSocket->resume(); |
1847 | d->setPaused(false); |
1848 | if (checkSslErrors() && ssl) { |
1849 | bool willClose = (d->isAutoStartingHandshake() && d->isPendingClose()); |
1850 | continueHandshake(); |
1851 | if (!willClose) |
1852 | transmit(); |
1853 | } |
1854 | } |
1855 | |
1856 | #endif // Q_OS_WIN |
1857 | |
1858 | } // namespace QTlsPrivate |
1859 | |
1860 | QT_END_NAMESPACE |
1861 | |