Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/plugins/tls/openssl/qsslcontext_openssl.cpp
Line
Count
Source
1
// Copyright (C) 2017 The Qt Company Ltd.
2
// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
3
// Copyright (C) 2014 Governikus GmbH & Co. KG.
4
// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
5
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
6
// Qt-Security score:critical reason:cryptography
7
8
#include <QtNetwork/qsslsocket.h>
9
#include <QtNetwork/qssldiffiehellmanparameters.h>
10
11
#include "qsslsocket_openssl_symbols_p.h"
12
#include "qsslcontext_openssl_p.h"
13
#include "qtlsbackend_openssl_p.h"
14
#include "qtlskey_openssl_p.h"
15
#include "qopenssl_p.h"
16
17
#include <QtNetwork/private/qssl_p.h>
18
#include <QtNetwork/private/qsslsocket_p.h>
19
#include <QtNetwork/private/qtlsbackend_p.h>
20
21
#include <QtNetwork/private/qssldiffiehellmanparameters_p.h>
22
23
#include <vector>
24
25
QT_BEGIN_NAMESPACE
26
27
Q_GLOBAL_STATIC(bool, forceSecurityLevel)
28
29
namespace QTlsPrivate
30
{
31
// These callback functions are defined in qtls_openssl.cpp.
32
int q_X509Callback(int ok, X509_STORE_CTX *ctx);
33
int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
34
35
#if QT_CONFIG(ocsp)
36
int qt_OCSP_status_server_callback(SSL *ssl, void *);
37
#endif // ocsp
38
39
#ifdef TLS1_3_VERSION
40
int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
41
#endif // TLS1_3_VERSION
42
43
} // namespace QTlsPrivate
44
45
#if QT_CONFIG(dtls)
46
// defined in qdtls_openssl.cpp:
47
namespace dtlscallbacks
48
{
49
int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx);
50
int q_generate_cookie_callback(SSL *ssl, unsigned char *dst, unsigned *cookieLength);
51
int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie, unsigned cookieLength);
52
} // namespace dtlscallbacks
53
#endif // dtls
54
55
static inline QString msgErrorSettingBackendConfig(const QString &why)
56
0
{
57
0
    return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why);
58
0
}
59
60
static inline QString msgErrorSettingEllipticCurves(const QString &why)
61
0
{
62
0
    return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
63
0
}
64
65
qssloptions QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
66
0
{
67
0
    qssloptions options;
68
0
    switch (protocol) {
69
0
QT_WARNING_PUSH
70
0
QT_WARNING_DISABLE_DEPRECATED
71
0
    case QSsl::TlsV1_0OrLater:
72
0
        options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
73
0
        break;
74
0
    case QSsl::TlsV1_1OrLater:
75
0
        options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
76
0
        break;
77
0
QT_WARNING_POP
78
0
    case QSsl::SecureProtocols:
79
0
    case QSsl::TlsV1_2OrLater:
80
0
        options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
81
0
        break;
82
0
    case QSsl::TlsV1_3OrLater:
83
0
        options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
84
0
        break;
85
0
    default:
86
0
        options = SSL_OP_ALL;
87
0
    }
88
89
    // This option is disabled by default, so we need to be able to clear it
90
0
    if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
91
0
        options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
92
0
    else
93
0
        options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
94
95
0
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
96
    // This option is disabled by default, so we need to be able to clear it
97
0
    if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
98
0
        options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
99
0
    else
100
0
        options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
101
0
#endif
102
103
0
#ifdef SSL_OP_NO_TICKET
104
0
    if (sslOptions & QSsl::SslOptionDisableSessionTickets)
105
0
        options |= SSL_OP_NO_TICKET;
106
0
#endif
107
0
#ifdef SSL_OP_NO_COMPRESSION
108
0
    if (sslOptions & QSsl::SslOptionDisableCompression)
109
0
        options |= SSL_OP_NO_COMPRESSION;
110
0
#endif
111
112
0
    if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
113
0
        options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
114
115
0
    return options;
116
0
}
117
118
QSslContext::QSslContext()
119
0
    : ctx(nullptr),
120
0
    pkey(nullptr),
121
0
    session(nullptr),
122
0
    m_sessionTicketLifeTimeHint(-1)
123
0
{
124
0
}
125
126
QSslContext::~QSslContext()
127
0
{
128
0
    if (ctx)
129
        // This will decrement the reference count by 1 and free the context eventually when possible
130
0
        q_SSL_CTX_free(ctx);
131
132
0
    if (pkey)
133
0
        q_EVP_PKEY_free(pkey);
134
135
0
    if (session)
136
0
        q_SSL_SESSION_free(session);
137
0
}
138
139
std::shared_ptr<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading)
140
0
{
141
0
    struct AccessToPrivateCtor : QSslContext {};
142
0
    std::shared_ptr<QSslContext> sslContext = std::make_shared<AccessToPrivateCtor>();
143
0
    initSslContext(sslContext.get(), mode, configuration, allowRootCertOnDemandLoading);
144
0
    return sslContext;
145
0
}
146
147
std::shared_ptr<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
148
                                                                        bool allowRootCertOnDemandLoading)
149
0
{
150
0
    return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
151
0
}
152
153
#ifndef OPENSSL_NO_NEXTPROTONEG
154
155
static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
156
                         const unsigned char *in, unsigned int inlen, void *arg)
157
0
{
158
0
    QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
159
160
    // comment out to debug:
161
//    QList<QByteArray> supportedVersions;
162
//    for (unsigned int i = 0; i < inlen; ) {
163
//        QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
164
//        supportedVersions << version;
165
//        i += in[i] + 1;
166
//    }
167
168
0
    int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
169
0
    switch (proto) {
170
0
    case OPENSSL_NPN_UNSUPPORTED:
171
0
        ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
172
0
        break;
173
0
    case OPENSSL_NPN_NEGOTIATED:
174
0
        ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
175
0
        break;
176
0
    case OPENSSL_NPN_NO_OVERLAP:
177
0
        ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
178
0
        break;
179
0
    default:
180
0
        qCWarning(lcTlsBackend, "OpenSSL sent unknown NPN status");
181
0
    }
182
183
0
    return SSL_TLSEXT_ERR_OK;
184
0
}
185
186
QSslContext::NPNContext QSslContext::npnContext() const
187
0
{
188
0
    return m_npnContext;
189
0
}
190
#endif // !OPENSSL_NO_NEXTPROTONEG
191
192
193
194
// Needs to be deleted by caller
195
SSL* QSslContext::createSsl()
196
0
{
197
0
    SSL* ssl = q_SSL_new(ctx);
198
0
    q_SSL_clear(ssl);
199
200
0
    if (!session && !sessionASN1().isEmpty()
201
0
            && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
202
0
        const unsigned char *data = reinterpret_cast<const unsigned char *>(m_sessionASN1.constData());
203
0
        session = q_d2i_SSL_SESSION(nullptr, &data, m_sessionASN1.size());
204
        // 'session' has refcount 1 already, set by the function above
205
0
    }
206
207
0
    if (session) {
208
        // Try to resume the last session we cached
209
0
        if (!q_SSL_set_session(ssl, session)) {
210
0
            qCWarning(lcTlsBackend, "could not set SSL session");
211
0
            q_SSL_SESSION_free(session);
212
0
            session = nullptr;
213
0
        }
214
0
    }
215
216
0
#ifndef OPENSSL_NO_NEXTPROTONEG
217
0
    QList<QByteArray> protocols = sslConfiguration.d.constData()->nextAllowedProtocols;
218
0
    if (!protocols.isEmpty()) {
219
0
        m_supportedNPNVersions.clear();
220
0
        for (int a = 0; a < protocols.size(); ++a) {
221
0
            if (protocols.at(a).size() > 255) {
222
0
                qCWarning(lcTlsBackend) << "TLS NPN extension" << protocols.at(a)
223
0
                                 << "is too long and will be ignored.";
224
0
                continue;
225
0
            } else if (protocols.at(a).isEmpty()) {
226
0
                continue;
227
0
            }
228
0
            m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
229
0
        }
230
0
        if (m_supportedNPNVersions.size()) {
231
0
            m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
232
0
            m_npnContext.len = m_supportedNPNVersions.size();
233
0
            m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
234
            // Callback's type has a parameter 'const unsigned char ** out'
235
            // since it was introduced in 1.0.2. Internally, OpenSSL's own code
236
            // (tests/examples) cast it to unsigned char * (since it's 'out').
237
            // We just re-use our NPN callback and cast here:
238
0
            typedef int (*alpn_callback_t) (SSL *, const unsigned char **, unsigned char *,
239
0
                                            const unsigned char *, unsigned int, void *);
240
            // With ALPN callback is for a server side only, for a client m_npnContext.status
241
            // will stay in NextProtocolNegotiationNone.
242
0
            q_SSL_CTX_set_alpn_select_cb(ctx, alpn_callback_t(next_proto_cb), &m_npnContext);
243
            // Client:
244
0
            q_SSL_set_alpn_protos(ssl, m_npnContext.data, m_npnContext.len);
245
            // And in case our peer does not support ALPN, but supports NPN:
246
0
            q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
247
0
        }
248
0
    }
249
0
#endif // !OPENSSL_NO_NEXTPROTONEG
250
251
0
    return ssl;
252
0
}
253
254
// We cache exactly one session here
255
bool QSslContext::cacheSession(SSL* ssl)
256
0
{
257
    // don't cache the same session again
258
0
    if (session && session == q_SSL_get_session(ssl))
259
0
        return true;
260
261
    // decrease refcount of currently stored session
262
    // (this might happen if there are several concurrent handshakes in flight)
263
0
    if (session)
264
0
        q_SSL_SESSION_free(session);
265
266
    // cache the session the caller gave us and increase reference count
267
0
    session = q_SSL_get1_session(ssl);
268
269
0
    if (session && !sslConfiguration.testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
270
0
        int sessionSize = q_i2d_SSL_SESSION(session, nullptr);
271
0
        if (sessionSize > 0) {
272
0
            m_sessionASN1.resize(sessionSize);
273
0
            unsigned char *data = reinterpret_cast<unsigned char *>(m_sessionASN1.data());
274
0
            if (!q_i2d_SSL_SESSION(session, &data))
275
0
                qCWarning(lcTlsBackend, "could not store persistent version of SSL session");
276
0
            m_sessionTicketLifeTimeHint = q_SSL_SESSION_get_ticket_lifetime_hint(session);
277
0
        }
278
0
    }
279
280
0
    return (session != nullptr);
281
0
}
282
283
QByteArray QSslContext::sessionASN1() const
284
0
{
285
0
    return m_sessionASN1;
286
0
}
287
288
void QSslContext::setSessionASN1(const QByteArray &session)
289
0
{
290
0
    m_sessionASN1 = session;
291
0
}
292
293
int QSslContext::sessionTicketLifeTimeHint() const
294
0
{
295
0
    return m_sessionTicketLifeTimeHint;
296
0
}
297
298
void QSslContext::forceAutoTestSecurityLevel()
299
0
{
300
0
    *forceSecurityLevel() = true;
301
0
}
302
303
QSslError::SslError QSslContext::error() const
304
0
{
305
0
    return errorCode;
306
0
}
307
308
QString QSslContext::errorString() const
309
0
{
310
0
    return errorStr;
311
0
}
312
313
void QSslContext::setGenericPrivateKey(QSslContext *sslContext,
314
                                       const QSslConfiguration &configuration)
315
0
{
316
0
    auto qtKey = QTlsBackend::backend<QTlsPrivate::TlsKeyOpenSSL>(configuration.d->privateKey);
317
0
    Q_ASSERT(qtKey);
318
0
    sslContext->pkey = qtKey->genericKey;
319
0
    Q_ASSERT(sslContext->pkey);
320
0
    q_EVP_PKEY_up_ref(sslContext->pkey);
321
0
}
322
323
void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode,
324
                                 const QSslConfiguration &configuration,
325
                                 bool allowRootCertOnDemandLoading)
326
0
{
327
0
    sslContext->sslConfiguration = configuration;
328
0
    sslContext->errorCode = QSslError::NoError;
329
330
0
    bool client = (mode == QSslSocket::SslClientMode);
331
332
0
    bool reinitialized = false;
333
0
    bool unsupportedProtocol = false;
334
0
    bool isDtls = false;
335
0
init_context:
336
0
    switch (sslContext->sslConfiguration.protocol()) {
337
0
QT_WARNING_PUSH
338
0
QT_WARNING_DISABLE_DEPRECATED
339
0
    case QSsl::DtlsV1_0:
340
0
    case QSsl::DtlsV1_0OrLater:
341
0
QT_WARNING_POP
342
0
    case QSsl::DtlsV1_2:
343
0
    case QSsl::DtlsV1_2OrLater:
344
0
#if QT_CONFIG(dtls)
345
0
        isDtls = true;
346
0
        sslContext->ctx = q_SSL_CTX_new(client ? q_DTLS_client_method() : q_DTLS_server_method());
347
#else // dtls
348
        sslContext->ctx = nullptr;
349
        unsupportedProtocol = true;
350
        qCWarning(lcTlsBackend, "DTLS protocol requested, but feature 'dtls' is disabled");
351
#endif // dtls
352
0
        break;
353
0
    case QSsl::TlsV1_3:
354
0
    case QSsl::TlsV1_3OrLater:
355
#if !defined(TLS1_3_VERSION)
356
        qCWarning(lcTlsBackend, "TLS 1.3 is not supported");
357
        sslContext->ctx = nullptr;
358
        unsupportedProtocol = true;
359
        break;
360
#endif // TLS1_3_VERSION
361
0
    default:
362
        // The ssl options will actually control the supported methods
363
0
        sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method());
364
0
    }
365
366
0
    if (!sslContext->ctx) {
367
        // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them
368
        // by re-initializing the library.
369
0
        if (!reinitialized) {
370
0
            reinitialized = true;
371
0
            if (q_OPENSSL_init_ssl(0, nullptr) == 1)
372
0
                goto init_context;
373
0
        }
374
375
0
        sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
376
0
            unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QTlsBackendOpenSSL::getErrorsFromOpenSsl()
377
0
        );
378
0
        sslContext->errorCode = QSslError::UnspecifiedError;
379
0
        return;
380
0
    }
381
382
    // A nasty hacked OpenSSL using a level that will make our auto-tests fail:
383
0
    if (q_SSL_CTX_get_security_level(sslContext->ctx) > 1 && *forceSecurityLevel())
384
0
        q_SSL_CTX_set_security_level(sslContext->ctx, 1);
385
386
0
    const long anyVersion =
387
0
#if QT_CONFIG(dtls)
388
0
                            isDtls ? DTLS_ANY_VERSION : TLS_ANY_VERSION;
389
#else
390
                            TLS_ANY_VERSION;
391
#endif // dtls
392
0
    long minVersion = anyVersion;
393
0
    long maxVersion = anyVersion;
394
395
0
    switch (sslContext->sslConfiguration.protocol()) {
396
0
QT_WARNING_PUSH
397
0
QT_WARNING_DISABLE_DEPRECATED
398
0
    case QSsl::TlsV1_0:
399
0
        minVersion = TLS1_VERSION;
400
0
        maxVersion = TLS1_VERSION;
401
0
        break;
402
0
    case QSsl::TlsV1_1:
403
0
        minVersion = TLS1_1_VERSION;
404
0
        maxVersion = TLS1_1_VERSION;
405
0
        break;
406
0
QT_WARNING_POP
407
0
    case QSsl::TlsV1_2:
408
0
        minVersion = TLS1_2_VERSION;
409
0
        maxVersion = TLS1_2_VERSION;
410
0
        break;
411
0
    case QSsl::TlsV1_3:
412
0
#ifdef TLS1_3_VERSION
413
0
        minVersion = TLS1_3_VERSION;
414
0
        maxVersion = TLS1_3_VERSION;
415
#else
416
        // This protocol is not supported by OpenSSL 1.1 and we handle
417
        // it as an error (see the code above).
418
        Q_UNREACHABLE();
419
#endif // TLS1_3_VERSION
420
0
        break;
421
    // Ranges:
422
0
    case QSsl::AnyProtocol:
423
0
QT_WARNING_PUSH
424
0
QT_WARNING_DISABLE_DEPRECATED
425
0
    case QSsl::TlsV1_0OrLater:
426
0
        minVersion = TLS1_VERSION;
427
0
        maxVersion = 0;
428
0
        break;
429
0
    case QSsl::TlsV1_1OrLater:
430
0
        minVersion = TLS1_1_VERSION;
431
0
        maxVersion = 0;
432
0
        break;
433
0
QT_WARNING_POP
434
0
    case QSsl::SecureProtocols:
435
0
    case QSsl::TlsV1_2OrLater:
436
0
        minVersion = TLS1_2_VERSION;
437
0
        maxVersion = 0;
438
0
        break;
439
0
QT_WARNING_PUSH
440
0
QT_WARNING_DISABLE_DEPRECATED
441
0
    case QSsl::DtlsV1_0:
442
0
        minVersion = DTLS1_VERSION;
443
0
        maxVersion = DTLS1_VERSION;
444
0
        break;
445
0
    case QSsl::DtlsV1_0OrLater:
446
0
        minVersion = DTLS1_VERSION;
447
0
        maxVersion = 0;
448
0
        break;
449
0
QT_WARNING_POP
450
0
    case QSsl::DtlsV1_2:
451
0
        minVersion = DTLS1_2_VERSION;
452
0
        maxVersion = DTLS1_2_VERSION;
453
0
        break;
454
0
    case QSsl::DtlsV1_2OrLater:
455
0
        minVersion = DTLS1_2_VERSION;
456
0
        maxVersion = 0;
457
0
        break;
458
0
    case QSsl::TlsV1_3OrLater:
459
0
#ifdef TLS1_3_VERSION
460
0
        minVersion = TLS1_3_VERSION;
461
0
        maxVersion = 0;
462
0
        break;
463
#else
464
        // This protocol is not supported by OpenSSL 1.1 and we handle
465
        // it as an error (see the code above).
466
        Q_UNREACHABLE();
467
        break;
468
#endif // TLS1_3_VERSION
469
0
    case QSsl::UnknownProtocol:
470
0
        break;
471
0
    }
472
473
0
    if (minVersion != anyVersion
474
0
        && !q_SSL_CTX_set_min_proto_version(sslContext->ctx, minVersion)) {
475
0
        sslContext->errorStr = QSslSocket::tr("Error while setting the minimal protocol version");
476
0
        sslContext->errorCode = QSslError::UnspecifiedError;
477
0
        return;
478
0
    }
479
480
0
    if (maxVersion != anyVersion
481
0
        && !q_SSL_CTX_set_max_proto_version(sslContext->ctx, maxVersion)) {
482
0
        sslContext->errorStr = QSslSocket::tr("Error while setting the maximum protocol version");
483
0
        sslContext->errorCode = QSslError::UnspecifiedError;
484
0
        return;
485
0
    }
486
487
    // Enable bug workarounds.
488
0
    const qssloptions options = setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
489
0
    q_SSL_CTX_set_options(sslContext->ctx, options);
490
491
    // Tell OpenSSL to release memory early
492
    // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
493
0
    q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS);
494
495
0
    auto filterCiphers = [](const QList<QSslCipher> &ciphers, bool selectTls13)
496
0
    {
497
0
        QByteArray cipherString;
498
499
0
        for (const QSslCipher &cipher : ciphers) {
500
0
            const bool isTls13Cipher = cipher.protocol() == QSsl::TlsV1_3 || cipher.protocol() == QSsl::TlsV1_3OrLater;
501
0
            if (selectTls13 != isTls13Cipher)
502
0
                continue;
503
504
0
            if (cipherString.size())
505
0
                cipherString.append(':');
506
0
            cipherString.append(cipher.name().toLatin1());
507
0
        }
508
0
        return cipherString;
509
0
    };
510
511
    // Initialize ciphers
512
0
    QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
513
0
    if (ciphers.isEmpty())
514
0
        ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
515
516
0
    const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
517
518
0
    if (preTls13Ciphers.size()) {
519
0
        if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
520
0
            sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
521
0
            sslContext->errorCode = QSslError::UnspecifiedError;
522
0
            return;
523
0
        }
524
0
    }
525
526
0
    const QByteArray tls13Ciphers = filterCiphers(ciphers, true);
527
0
#ifdef TLS1_3_VERSION
528
0
    if (tls13Ciphers.size()) {
529
0
        if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
530
0
            sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
531
0
            sslContext->errorCode = QSslError::UnspecifiedError;
532
0
            return;
533
0
        }
534
0
    }
535
0
#endif // TLS1_3_VERSION
536
0
    if (!preTls13Ciphers.size() && !tls13Ciphers.size()) {
537
0
        sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QStringLiteral(""));
538
0
        sslContext->errorCode = QSslError::UnspecifiedError;
539
0
        return;
540
0
    }
541
542
0
    const QDateTime now = QDateTime::currentDateTimeUtc();
543
544
    // Add all our CAs to this store.
545
0
    const auto caCertificates = sslContext->sslConfiguration.caCertificates();
546
0
    for (const QSslCertificate &caCertificate : caCertificates) {
547
        // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
548
        //
549
        // If several CA certificates matching the name, key identifier, and
550
        // serial number condition are available, only the first one will be
551
        // examined. This may lead to unexpected results if the same CA
552
        // certificate is available with different expiration dates. If a
553
        // ``certificate expired'' verification error occurs, no other
554
        // certificate will be searched. Make sure to not have expired
555
        // certificates mixed with valid ones.
556
        //
557
        // See also: QSslSocketBackendPrivate::verify()
558
0
        if (caCertificate.expiryDate() >= now) {
559
0
            q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle());
560
0
        }
561
0
    }
562
563
0
    if (QSslSocketPrivate::rootCertOnDemandLoadingSupported() && allowRootCertOnDemandLoading) {
564
        // tell OpenSSL the directories where to look up the root certs on demand
565
0
        const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
566
0
        int success = 1;
567
0
#if OPENSSL_VERSION_MAJOR < 3
568
0
        for (const QByteArray &unixDir : unixDirs) {
569
0
            if ((success = q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData())) != 1)
570
0
                break;
571
0
        }
572
#else
573
        for (const QByteArray &unixDir : unixDirs) {
574
            if ((success = q_SSL_CTX_load_verify_dir(sslContext->ctx, unixDir.constData())) != 1)
575
                break;
576
        }
577
#endif // OPENSSL_VERSION_MAJOR
578
0
        if (success != 1) {
579
0
            const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
580
0
            qCWarning(lcTlsBackend) << "An error encountered while to set root certificates location:"
581
0
                              << qtErrors;
582
0
        }
583
0
    }
584
585
0
    if (!sslContext->sslConfiguration.localCertificate().isNull()) {
586
        // Require a private key as well.
587
0
        if (sslContext->sslConfiguration.privateKey().isNull()) {
588
0
            sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key");
589
0
            sslContext->errorCode = QSslError::UnspecifiedError;
590
0
            return;
591
0
        }
592
593
        // Load certificate
594
0
        if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
595
0
            sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
596
0
            sslContext->errorCode = QSslError::UnspecifiedError;
597
0
            return;
598
0
        }
599
600
0
        const auto algorithm = configuration.d->privateKey.algorithm();
601
0
        bool useOpaqueHandle = false;
602
603
0
        if (algorithm == QSsl::Opaque)
604
0
            useOpaqueHandle = true;
605
0
#if OPENSSL_VERSION_NUMBER < 0x3050000fL
606
        // ML-DSA is only supported in OpenSSL 3.5+, therefore treat it as Qssl::Opaque so it still
607
        // works and loads correctly.
608
0
        if (algorithm == QSsl::MlDsa)
609
0
            useOpaqueHandle = true;
610
0
#endif
611
612
0
        if (useOpaqueHandle) {
613
0
            sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle());
614
#if OPENSSL_VERSION_NUMBER >= 0x3050000fL
615
        } else if (algorithm == QSsl::MlDsa) {
616
            setGenericPrivateKey(sslContext, configuration);
617
#endif
618
0
        } else {
619
#ifdef OPENSSL_NO_DEPRECATED_3_0
620
            setGenericPrivateKey(sslContext, configuration);
621
#else
622
            // Load private key
623
0
            sslContext->pkey = q_EVP_PKEY_new();
624
            // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
625
            // this lead to a memory leak. Now we use the *_set1_* functions which do not
626
            // take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
627
0
            if (algorithm == QSsl::Rsa)
628
0
                q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
629
0
            else if (algorithm == QSsl::Dsa)
630
0
                q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
631
0
#ifndef OPENSSL_NO_EC
632
0
            else if (algorithm == QSsl::Ec)
633
0
                q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
634
0
#endif // OPENSSL_NO_EC
635
0
#endif // OPENSSL_NO_DEPRECATED_3_0
636
0
        }
637
0
        auto pkey = sslContext->pkey;
638
0
        if (useOpaqueHandle)
639
0
            sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
640
641
0
        if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
642
0
            sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
643
0
            sslContext->errorCode = QSslError::UnspecifiedError;
644
0
            return;
645
0
        }
646
647
        // Check if the certificate matches the private key.
648
0
        if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
649
0
            sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
650
0
            sslContext->errorCode = QSslError::UnspecifiedError;
651
0
            return;
652
0
        }
653
654
        // If we have any intermediate certificates then we need to add them to our chain
655
0
        bool first = true;
656
0
        for (const QSslCertificate &cert : std::as_const(configuration.d->localCertificateChain)) {
657
0
            if (first) {
658
0
                first = false;
659
0
                continue;
660
0
            }
661
0
            q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
662
0
                           q_X509_dup(reinterpret_cast<X509 *>(cert.handle())));
663
0
        }
664
0
    }
665
666
    // Initialize peer verification, different callbacks, TLS/DTLS verification first
667
    // (note, all these set_some_callback do not have return value):
668
0
    if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) {
669
0
        q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr);
670
0
    } else {
671
0
        auto verificationCallback =
672
0
        #if QT_CONFIG(dtls)
673
0
                                            isDtls ? dtlscallbacks::q_X509DtlsCallback :
674
0
        #endif // dtls
675
0
                                            QTlsPrivate::q_X509Callback;
676
677
0
        if (!isDtls && configuration.handshakeMustInterruptOnError())
678
0
            verificationCallback = QTlsPrivate::q_X509CallbackDirect;
679
680
0
        auto verificationMode = SSL_VERIFY_PEER;
681
0
        if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
682
0
            verificationMode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
683
684
0
        q_SSL_CTX_set_verify(sslContext->ctx, verificationMode, verificationCallback);
685
0
    }
686
687
0
#ifdef TLS1_3_VERSION
688
    // NewSessionTicket callback:
689
0
    if (mode == QSslSocket::SslClientMode && !isDtls) {
690
0
        q_SSL_CTX_sess_set_new_cb(sslContext->ctx, QTlsPrivate::q_ssl_sess_set_new_cb);
691
0
        q_SSL_CTX_set_session_cache_mode(sslContext->ctx, SSL_SESS_CACHE_CLIENT);
692
0
    }
693
694
0
#endif // TLS1_3_VERSION
695
696
0
#if QT_CONFIG(dtls)
697
    // DTLS cookies:
698
0
    if (mode == QSslSocket::SslServerMode && isDtls && configuration.dtlsCookieVerificationEnabled()) {
699
0
        q_SSL_CTX_set_cookie_generate_cb(sslContext->ctx, dtlscallbacks::q_generate_cookie_callback);
700
0
        q_SSL_CTX_set_cookie_verify_cb(sslContext->ctx, dtlscallbacks::q_verify_cookie_callback);
701
0
    }
702
0
#endif // dtls
703
704
    // Set verification depth.
705
0
    if (sslContext->sslConfiguration.peerVerifyDepth() != 0)
706
0
        q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth());
707
708
    // set persisted session if the user set it
709
0
    if (!configuration.sessionTicket().isEmpty())
710
0
        sslContext->setSessionASN1(configuration.sessionTicket());
711
712
    // Set temp DH params
713
0
    QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters();
714
715
0
    if (!dhparams.isValid()) {
716
0
        sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid");
717
0
        sslContext->errorCode = QSslError::UnspecifiedError;
718
0
        return;
719
0
    }
720
721
0
    if (dhparams.isEmpty()) {
722
0
        q_SSL_CTX_set_dh_auto(sslContext->ctx, 1);
723
0
    } else {
724
0
#ifndef OPENSSL_NO_DEPRECATED_3_0
725
0
        const QByteArray &params = dhparams.d->derData;
726
0
        const char *ptr = params.constData();
727
0
        DH *dh = q_d2i_DHparams(nullptr, reinterpret_cast<const unsigned char **>(&ptr),
728
0
                                params.size());
729
0
        if (dh == nullptr)
730
0
            qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form");
731
0
        q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh);
732
0
        q_DH_free(dh);
733
#else
734
        qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed");
735
#endif
736
0
    }
737
738
0
#ifndef OPENSSL_NO_PSK
739
0
    if (!client)
740
0
        q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
741
0
#endif // !OPENSSL_NO_PSK
742
743
0
    const auto qcurves = sslContext->sslConfiguration.ellipticCurves();
744
0
    if (!qcurves.isEmpty()) {
745
#ifdef OPENSSL_NO_EC
746
        sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves"));
747
        sslContext->errorCode = QSslError::UnspecifiedError;
748
        return;
749
#else
750
        // Set the curves to be used.
751
0
        std::vector<int> curves;
752
0
        curves.reserve(qcurves.size());
753
0
        for (const auto &sslCurve : qcurves)
754
0
            curves.push_back(sslCurve.id);
755
0
        if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
756
0
            sslContext->errorStr = msgErrorSettingEllipticCurves(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
757
0
            sslContext->errorCode = QSslError::UnspecifiedError;
758
0
            return;
759
0
        }
760
0
#endif
761
0
    }
762
763
0
    applyBackendConfig(sslContext);
764
0
}
765
766
void QSslContext::applyBackendConfig(QSslContext *sslContext)
767
0
{
768
0
    const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
769
0
    if (conf.isEmpty())
770
0
        return;
771
772
0
#if QT_CONFIG(ocsp)
773
0
    auto ocspResponsePos = conf.find("Qt-OCSP-response");
774
0
    if (ocspResponsePos != conf.end()) {
775
        // This is our private, undocumented configuration option, existing only for
776
        // the purpose of testing OCSP status responses. We don't even check this
777
        // callback was set. If no - the test must fail.
778
0
        q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
779
0
        if (conf.size() == 1)
780
0
            return;
781
0
    }
782
0
#endif // ocsp
783
784
0
    QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free);
785
0
    if (cctx) {
786
0
        q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx);
787
0
        q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE);
788
789
0
        for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) {
790
0
            if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd().
791
0
                continue;
792
793
0
            if (!i.value().canConvert(QMetaType(QMetaType::QByteArray))) {
794
0
                sslContext->errorCode = QSslError::UnspecifiedError;
795
0
                sslContext->errorStr = msgErrorSettingBackendConfig(
796
0
                QSslSocket::tr("Expecting QByteArray for %1").arg(i.key()));
797
0
                return;
798
0
            }
799
800
0
            const QByteArray &value = i.value().toByteArray();
801
0
            const int result = q_SSL_CONF_cmd(cctx.data(), i.key().constData(), value.constData());
802
0
            if (result == 2)
803
0
                continue;
804
805
0
            sslContext->errorCode = QSslError::UnspecifiedError;
806
0
            switch (result) {
807
0
            case 0:
808
0
                sslContext->errorStr = msgErrorSettingBackendConfig(
809
0
                    QSslSocket::tr("An error occurred attempting to set %1 to %2")
810
0
                            .arg(i.key(), value));
811
0
                return;
812
0
            case 1:
813
0
                sslContext->errorStr = msgErrorSettingBackendConfig(
814
0
                    QSslSocket::tr("Wrong value for %1 (%2)").arg(i.key(), value));
815
0
                return;
816
0
            default:
817
0
                sslContext->errorStr = msgErrorSettingBackendConfig(
818
0
                    QSslSocket::tr("Unrecognized command %1 = %2").arg(i.key(), value));
819
0
                return;
820
0
            }
821
0
        }
822
823
0
        if (q_SSL_CONF_CTX_finish(cctx.data()) == 0) {
824
0
            sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_finish() failed"));
825
0
            sslContext->errorCode = QSslError::UnspecifiedError;
826
0
        }
827
0
    } else {
828
0
        sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_CTX_new() failed"));
829
0
        sslContext->errorCode = QSslError::UnspecifiedError;
830
0
    }
831
0
}
832
833
QT_END_NAMESPACE