/src/qtbase/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
Line | Count | Source |
1 | | // Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk> |
2 | | // Copyright (C) 2016 Richard J. Moore <rich@kde.org> |
3 | | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | | // Qt-Security score:critical reason:cryptography |
5 | | |
6 | | #include "qsslsocket_openssl_symbols_p.h" |
7 | | #include "qtlsbackend_openssl_p.h" |
8 | | |
9 | | #include <QtNetwork/private/qsslsocket_p.h> |
10 | | |
11 | | #include <QtCore/qscopeguard.h> |
12 | | #include <QtCore/qbytearray.h> |
13 | | #include <QtCore/qiodevice.h> |
14 | | #include <QtCore/qdebug.h> |
15 | | |
16 | | #include <openssl/bn.h> |
17 | | #include <openssl/dh.h> |
18 | | |
19 | | QT_BEGIN_NAMESPACE |
20 | | |
21 | | #ifndef OPENSSL_NO_DEPRECATED_3_0 |
22 | | |
23 | | namespace { |
24 | | |
25 | | bool isSafeDH(DH *dh) |
26 | 0 | { |
27 | 0 | int status = 0; |
28 | 0 | int bad = 0; |
29 | | |
30 | | // TLSTODO: check it's needed or if supportsSsl() |
31 | | // is enough. |
32 | 0 | QSslSocketPrivate::ensureInitialized(); |
33 | | |
34 | | // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters: |
35 | | // |
36 | | // The additional call to BN_mod_word(dh->p, 24) |
37 | | // (and unmasking of DH_NOT_SUITABLE_GENERATOR) |
38 | | // is performed to ensure your program accepts |
39 | | // IETF group parameters. OpenSSL checks the prime |
40 | | // is congruent to 11 when g = 2; while the IETF's |
41 | | // primes are congruent to 23 when g = 2. |
42 | | // Without the test, the IETF parameters would |
43 | | // fail validation. For details, see Diffie-Hellman |
44 | | // Parameter Check (when g = 2, must p mod 24 == 11?). |
45 | | // Mark p < 1024 bits as unsafe. |
46 | 0 | if (q_DH_bits(dh) < 1024) |
47 | 0 | return false; |
48 | | |
49 | 0 | if (q_DH_check(dh, &status) != 1) |
50 | 0 | return false; |
51 | | |
52 | 0 | const BIGNUM *p = nullptr; |
53 | 0 | const BIGNUM *q = nullptr; |
54 | 0 | const BIGNUM *g = nullptr; |
55 | 0 | q_DH_get0_pqg(dh, &p, &q, &g); |
56 | |
|
57 | 0 | if (q_BN_is_word(const_cast<BIGNUM *>(g), DH_GENERATOR_2)) { |
58 | 0 | const unsigned long residue = q_BN_mod_word(p, 24); |
59 | 0 | if (residue == 11 || residue == 23) |
60 | 0 | status &= ~DH_NOT_SUITABLE_GENERATOR; |
61 | 0 | } |
62 | |
|
63 | 0 | bad |= DH_CHECK_P_NOT_PRIME; |
64 | 0 | bad |= DH_CHECK_P_NOT_SAFE_PRIME; |
65 | 0 | bad |= DH_NOT_SUITABLE_GENERATOR; |
66 | |
|
67 | 0 | return !(status & bad); |
68 | 0 | } |
69 | | |
70 | | } // unnamed namespace |
71 | | |
72 | | #endif |
73 | | |
74 | | int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const |
75 | 0 | { |
76 | 0 | #ifndef OPENSSL_NO_DEPRECATED_3_0 |
77 | 0 | Q_ASSERT(derData); |
78 | |
|
79 | 0 | if (der.isEmpty()) |
80 | 0 | return DHParams::InvalidInputDataError; |
81 | | |
82 | 0 | const unsigned char *data = reinterpret_cast<const unsigned char *>(der.data()); |
83 | 0 | const int len = der.size(); |
84 | | |
85 | | // TLSTODO: check it's needed (loading ciphers and certs in |
86 | | // addition to the library!) |
87 | 0 | QSslSocketPrivate::ensureInitialized(); |
88 | |
|
89 | 0 | DH *dh = q_d2i_DHparams(nullptr, &data, len); |
90 | 0 | if (dh) { |
91 | 0 | const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);}); |
92 | |
|
93 | 0 | if (isSafeDH(dh)) |
94 | 0 | *derData = der; |
95 | 0 | else |
96 | 0 | return DHParams::UnsafeParametersError; |
97 | 0 | } else { |
98 | 0 | return DHParams::InvalidInputDataError; |
99 | 0 | } |
100 | | #else |
101 | | Q_UNUSED(der); |
102 | | Q_UNUSED(derData); |
103 | | qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed"); |
104 | | #endif |
105 | 0 | return DHParams::NoError; |
106 | 0 | } |
107 | | |
108 | | int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *data) const |
109 | 0 | { |
110 | 0 | #ifndef OPENSSL_NO_DEPRECATED_3_0 |
111 | 0 | Q_ASSERT(data); |
112 | |
|
113 | 0 | if (pem.isEmpty()) |
114 | 0 | return DHParams::InvalidInputDataError; |
115 | | |
116 | | // TLSTODO: check it was not a cargo-cult programming in case of |
117 | | // DH ... |
118 | 0 | QSslSocketPrivate::ensureInitialized(); |
119 | |
|
120 | 0 | BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size()); |
121 | 0 | if (!bio) |
122 | 0 | return DHParams::InvalidInputDataError; |
123 | | |
124 | 0 | const auto bioRaii = qScopeGuard([bio] |
125 | 0 | { |
126 | 0 | q_BIO_free(bio); |
127 | 0 | }); |
128 | |
|
129 | 0 | DH *dh = nullptr; |
130 | 0 | q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr); |
131 | |
|
132 | 0 | if (dh) { |
133 | 0 | const auto dhGuard = qScopeGuard([dh] |
134 | 0 | { |
135 | 0 | q_DH_free(dh); |
136 | 0 | }); |
137 | |
|
138 | 0 | if (isSafeDH(dh)) { |
139 | 0 | char *buf = nullptr; |
140 | 0 | const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf)); |
141 | 0 | const auto freeBuf = qScopeGuard([&] { q_OPENSSL_free(buf); }); |
142 | 0 | if (len > 0) |
143 | 0 | data->assign({buf, len}); |
144 | 0 | else |
145 | 0 | return DHParams::InvalidInputDataError; |
146 | 0 | } else { |
147 | 0 | return DHParams::UnsafeParametersError; |
148 | 0 | } |
149 | 0 | } else { |
150 | 0 | return DHParams::InvalidInputDataError; |
151 | 0 | } |
152 | | #else |
153 | | Q_UNUSED(pem); |
154 | | Q_UNUSED(data); |
155 | | qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed"); |
156 | | #endif |
157 | 0 | return DHParams::NoError; |
158 | 0 | } |
159 | | |
160 | | QT_END_NAMESPACE |