1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 Richard J. Moore <rich@kde.org> |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtNetwork module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | |
42 | #include "qsslkey.h" |
43 | #include "qsslkey_p.h" |
44 | #include "qsslsocket_openssl_symbols_p.h" |
45 | #include "qsslsocket.h" |
46 | #include "qsslsocket_p.h" |
47 | |
48 | #include <QtCore/qatomic.h> |
49 | #include <QtCore/qbytearray.h> |
50 | #include <QtCore/qiodevice.h> |
51 | #ifndef QT_NO_DEBUG_STREAM |
52 | #include <QtCore/qdebug.h> |
53 | #endif |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | void QSslKeyPrivate::clear(bool deep) |
58 | { |
59 | isNull = true; |
60 | if (!QSslSocket::supportsSsl()) |
61 | return; |
62 | if (algorithm == QSsl::Rsa && rsa) { |
63 | if (deep) |
64 | q_RSA_free(a: rsa); |
65 | rsa = nullptr; |
66 | } |
67 | if (algorithm == QSsl::Dsa && dsa) { |
68 | if (deep) |
69 | q_DSA_free(a: dsa); |
70 | dsa = nullptr; |
71 | } |
72 | if (algorithm == QSsl::Dh && dh) { |
73 | if (deep) |
74 | q_DH_free(dh: dh); |
75 | dh = nullptr; |
76 | } |
77 | #ifndef OPENSSL_NO_EC |
78 | if (algorithm == QSsl::Ec && ec) { |
79 | if (deep) |
80 | q_EC_KEY_free(ecdh: ec); |
81 | ec = nullptr; |
82 | } |
83 | #endif |
84 | if (algorithm == QSsl::Opaque && opaque) { |
85 | if (deep) |
86 | q_EVP_PKEY_free(a: opaque); |
87 | opaque = nullptr; |
88 | } |
89 | } |
90 | |
91 | bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey) |
92 | { |
93 | if (pkey == nullptr) |
94 | return false; |
95 | |
96 | const int keyType = q_EVP_PKEY_type(a: q_EVP_PKEY_base_id(a: pkey)); |
97 | if (keyType == EVP_PKEY_RSA) { |
98 | isNull = false; |
99 | algorithm = QSsl::Rsa; |
100 | type = QSsl::PrivateKey; |
101 | rsa = q_EVP_PKEY_get1_RSA(a: pkey); |
102 | return true; |
103 | } else if (keyType == EVP_PKEY_DSA) { |
104 | isNull = false; |
105 | algorithm = QSsl::Dsa; |
106 | type = QSsl::PrivateKey; |
107 | dsa = q_EVP_PKEY_get1_DSA(a: pkey); |
108 | return true; |
109 | } else if (keyType == EVP_PKEY_DH) { |
110 | isNull = false; |
111 | algorithm = QSsl::Dh; |
112 | type = QSsl::PrivateKey; |
113 | dh = q_EVP_PKEY_get1_DH(a: pkey); |
114 | return true; |
115 | } |
116 | #ifndef OPENSSL_NO_EC |
117 | else if (keyType == EVP_PKEY_EC) { |
118 | isNull = false; |
119 | algorithm = QSsl::Ec; |
120 | type = QSsl::PrivateKey; |
121 | ec = q_EVP_PKEY_get1_EC_KEY(a: pkey); |
122 | return true; |
123 | } |
124 | #endif |
125 | else { |
126 | // Unknown key type. This could be handled as opaque, but then |
127 | // we'd eventually leak memory since we wouldn't be able to free |
128 | // the underlying EVP_PKEY structure. For now, we won't support |
129 | // this. |
130 | } |
131 | |
132 | return false; |
133 | } |
134 | |
135 | void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear) |
136 | { |
137 | QMap<QByteArray, QByteArray> ; |
138 | decodePem(pem: pemFromDer(der, headers), passPhrase, deepClear); |
139 | } |
140 | |
141 | void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase, |
142 | bool deepClear) |
143 | { |
144 | if (pem.isEmpty()) |
145 | return; |
146 | |
147 | clear(deep: deepClear); |
148 | |
149 | if (!QSslSocket::supportsSsl()) |
150 | return; |
151 | |
152 | BIO *bio = q_BIO_new_mem_buf(a: const_cast<char *>(pem.data()), b: pem.size()); |
153 | if (!bio) |
154 | return; |
155 | |
156 | void *phrase = const_cast<char *>(passPhrase.constData()); |
157 | |
158 | if (algorithm == QSsl::Rsa) { |
159 | RSA *result = (type == QSsl::PublicKey) |
160 | ? q_PEM_read_bio_RSA_PUBKEY(a: bio, b: &rsa, c: nullptr, d: phrase) |
161 | : q_PEM_read_bio_RSAPrivateKey(a: bio, b: &rsa, c: nullptr, d: phrase); |
162 | if (rsa && rsa == result) |
163 | isNull = false; |
164 | } else if (algorithm == QSsl::Dsa) { |
165 | DSA *result = (type == QSsl::PublicKey) |
166 | ? q_PEM_read_bio_DSA_PUBKEY(a: bio, b: &dsa, c: nullptr, d: phrase) |
167 | : q_PEM_read_bio_DSAPrivateKey(a: bio, b: &dsa, c: nullptr, d: phrase); |
168 | if (dsa && dsa == result) |
169 | isNull = false; |
170 | } else if (algorithm == QSsl::Dh) { |
171 | EVP_PKEY *result = (type == QSsl::PublicKey) |
172 | ? q_PEM_read_bio_PUBKEY(a: bio, b: nullptr, c: nullptr, d: phrase) |
173 | : q_PEM_read_bio_PrivateKey(a: bio, b: nullptr, c: nullptr, d: phrase); |
174 | if (result) |
175 | dh = q_EVP_PKEY_get1_DH(a: result); |
176 | if (dh) |
177 | isNull = false; |
178 | q_EVP_PKEY_free(a: result); |
179 | #ifndef OPENSSL_NO_EC |
180 | } else if (algorithm == QSsl::Ec) { |
181 | EC_KEY *result = (type == QSsl::PublicKey) |
182 | ? q_PEM_read_bio_EC_PUBKEY(a: bio, b: &ec, c: nullptr, d: phrase) |
183 | : q_PEM_read_bio_ECPrivateKey(a: bio, b: &ec, c: nullptr, d: phrase); |
184 | if (ec && ec == result) |
185 | isNull = false; |
186 | #endif |
187 | } |
188 | |
189 | q_BIO_free(a: bio); |
190 | } |
191 | |
192 | int QSslKeyPrivate::length() const |
193 | { |
194 | if (isNull || algorithm == QSsl::Opaque) |
195 | return -1; |
196 | |
197 | switch (algorithm) { |
198 | case QSsl::Rsa: return q_RSA_bits(a: rsa); |
199 | case QSsl::Dsa: return q_DSA_bits(a: dsa); |
200 | case QSsl::Dh: return q_DH_bits(dh: dh); |
201 | #ifndef OPENSSL_NO_EC |
202 | case QSsl::Ec: return q_EC_GROUP_get_degree(g: q_EC_KEY_get0_group(k: ec)); |
203 | #endif |
204 | default: return -1; |
205 | } |
206 | } |
207 | |
208 | QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const |
209 | { |
210 | if (!QSslSocket::supportsSsl() || isNull || algorithm == QSsl::Opaque) |
211 | return QByteArray(); |
212 | |
213 | // ### the cipher should be selectable in the API: |
214 | const EVP_CIPHER *cipher = nullptr; |
215 | if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) { |
216 | #ifndef OPENSSL_NO_DES |
217 | cipher = q_EVP_des_ede3_cbc(); |
218 | #else |
219 | return QByteArray(); |
220 | #endif |
221 | } |
222 | |
223 | BIO *bio = q_BIO_new(a: q_BIO_s_mem()); |
224 | if (!bio) |
225 | return QByteArray(); |
226 | |
227 | bool fail = false; |
228 | |
229 | if (algorithm == QSsl::Rsa) { |
230 | if (type == QSsl::PublicKey) { |
231 | if (!q_PEM_write_bio_RSA_PUBKEY(a: bio, b: rsa)) |
232 | fail = true; |
233 | } else { |
234 | if (!q_PEM_write_bio_RSAPrivateKey( |
235 | a: bio, b: rsa, c: cipher, d: (uchar *)passPhrase.data(), |
236 | e: passPhrase.size(), f: nullptr, g: nullptr)) { |
237 | fail = true; |
238 | } |
239 | } |
240 | } else if (algorithm == QSsl::Dsa) { |
241 | if (type == QSsl::PublicKey) { |
242 | if (!q_PEM_write_bio_DSA_PUBKEY(a: bio, b: dsa)) |
243 | fail = true; |
244 | } else { |
245 | if (!q_PEM_write_bio_DSAPrivateKey( |
246 | a: bio, b: dsa, c: cipher, d: (uchar *)passPhrase.data(), |
247 | e: passPhrase.size(), f: nullptr, g: nullptr)) { |
248 | fail = true; |
249 | } |
250 | } |
251 | } else if (algorithm == QSsl::Dh) { |
252 | EVP_PKEY *result = q_EVP_PKEY_new(); |
253 | if (!result || !q_EVP_PKEY_set1_DH(a: result, b: dh)) { |
254 | fail = true; |
255 | } else if (type == QSsl::PublicKey) { |
256 | if (!q_PEM_write_bio_PUBKEY(a: bio, b: result)) |
257 | fail = true; |
258 | } else if (!q_PEM_write_bio_PrivateKey( |
259 | a: bio, b: result, c: cipher, d: (uchar *)passPhrase.data(), |
260 | e: passPhrase.size(), f: nullptr, g: nullptr)) { |
261 | fail = true; |
262 | } |
263 | q_EVP_PKEY_free(a: result); |
264 | #ifndef OPENSSL_NO_EC |
265 | } else if (algorithm == QSsl::Ec) { |
266 | if (type == QSsl::PublicKey) { |
267 | if (!q_PEM_write_bio_EC_PUBKEY(a: bio, b: ec)) |
268 | fail = true; |
269 | } else { |
270 | if (!q_PEM_write_bio_ECPrivateKey( |
271 | a: bio, b: ec, c: cipher, d: (uchar *)passPhrase.data(), |
272 | e: passPhrase.size(), f: nullptr, g: nullptr)) { |
273 | fail = true; |
274 | } |
275 | } |
276 | #endif |
277 | } else { |
278 | fail = true; |
279 | } |
280 | |
281 | QByteArray pem; |
282 | if (!fail) { |
283 | char *data; |
284 | long size = q_BIO_get_mem_data(bio, &data); |
285 | pem = QByteArray(data, size); |
286 | } |
287 | q_BIO_free(a: bio); |
288 | return pem; |
289 | } |
290 | |
291 | Qt::HANDLE QSslKeyPrivate::handle() const |
292 | { |
293 | switch (algorithm) { |
294 | case QSsl::Opaque: |
295 | return Qt::HANDLE(opaque); |
296 | case QSsl::Rsa: |
297 | return Qt::HANDLE(rsa); |
298 | case QSsl::Dsa: |
299 | return Qt::HANDLE(dsa); |
300 | case QSsl::Dh: |
301 | return Qt::HANDLE(dh); |
302 | #ifndef OPENSSL_NO_EC |
303 | case QSsl::Ec: |
304 | return Qt::HANDLE(ec); |
305 | #endif |
306 | default: |
307 | return Qt::HANDLE(nullptr); |
308 | } |
309 | } |
310 | |
311 | static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, int enc) |
312 | { |
313 | const EVP_CIPHER* type = nullptr; |
314 | int i = 0, len = 0; |
315 | |
316 | switch (cipher) { |
317 | case QSslKeyPrivate::DesCbc: |
318 | #ifndef OPENSSL_NO_DES |
319 | type = q_EVP_des_cbc(); |
320 | #endif |
321 | break; |
322 | case QSslKeyPrivate::DesEde3Cbc: |
323 | #ifndef OPENSSL_NO_DES |
324 | type = q_EVP_des_ede3_cbc(); |
325 | #endif |
326 | break; |
327 | case QSslKeyPrivate::Rc2Cbc: |
328 | #ifndef OPENSSL_NO_RC2 |
329 | type = q_EVP_rc2_cbc(); |
330 | #endif |
331 | break; |
332 | case QSslKeyPrivate::Aes128Cbc: |
333 | type = q_EVP_aes_128_cbc(); |
334 | break; |
335 | case QSslKeyPrivate::Aes192Cbc: |
336 | type = q_EVP_aes_192_cbc(); |
337 | break; |
338 | case QSslKeyPrivate::Aes256Cbc: |
339 | type = q_EVP_aes_256_cbc(); |
340 | break; |
341 | } |
342 | |
343 | if (type == nullptr) |
344 | return QByteArray(); |
345 | |
346 | QByteArray output; |
347 | output.resize(size: data.size() + EVP_MAX_BLOCK_LENGTH); |
348 | |
349 | EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new(); |
350 | q_EVP_CIPHER_CTX_reset(c: ctx); |
351 | if (q_EVP_CipherInit(ctx, type, key: nullptr, iv: nullptr, enc) != 1) { |
352 | QSslSocketBackendPrivate::logAndClearErrorQueue(); |
353 | return QByteArray(); |
354 | } |
355 | q_EVP_CIPHER_CTX_set_key_length(x: ctx, keylen: key.size()); |
356 | if (cipher == QSslKeyPrivate::Rc2Cbc) |
357 | q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, arg: 8 * key.size(), ptr: nullptr); |
358 | |
359 | q_EVP_CipherInit_ex(ctx, cipher: nullptr, impl: nullptr, |
360 | key: reinterpret_cast<const unsigned char *>(key.constData()), |
361 | iv: reinterpret_cast<const unsigned char *>(iv.constData()), |
362 | enc); |
363 | q_EVP_CipherUpdate(ctx, |
364 | out: reinterpret_cast<unsigned char *>(output.data()), outl: &len, |
365 | in: reinterpret_cast<const unsigned char *>(data.constData()), inl: data.size()); |
366 | q_EVP_CipherFinal(ctx, |
367 | out: reinterpret_cast<unsigned char *>(output.data()) + len, outl: &i); |
368 | len += i; |
369 | |
370 | q_EVP_CIPHER_CTX_reset(c: ctx); |
371 | q_EVP_CIPHER_CTX_free(a: ctx); |
372 | |
373 | return output.left(len); |
374 | } |
375 | |
376 | QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) |
377 | { |
378 | return doCrypt(cipher, data, key, iv, enc: 0); |
379 | } |
380 | |
381 | QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) |
382 | { |
383 | return doCrypt(cipher, data, key, iv, enc: 1); |
384 | } |
385 | |
386 | QT_END_NAMESPACE |
387 | |