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// Qt-Security score:critical reason:cryptography
4
5#include "qsslsocket_openssl_symbols_p.h"
6#include "qtlsbackend_openssl_p.h"
7#include "qtlskey_openssl_p.h"
8
9#include <QtNetwork/private/qsslkey_p.h>
10
11#include <QtNetwork/qsslsocket.h>
12
13#include <QtCore/qscopeguard.h>
14
15QT_BEGIN_NAMESPACE
16
17namespace QTlsPrivate {
18
19void TlsKeyOpenSSL::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
20 const QByteArray &passPhrase, bool deepClear)
21{
22 if (der.isEmpty())
23 return;
24
25 keyType = type;
26 keyAlgorithm = algorithm;
27
28 QMap<QByteArray, QByteArray> headers;
29 const auto pem = pemFromDer(der, headers);
30
31 decodePem(type, algorithm, pem, passPhrase, deepClear);
32}
33
34void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
35 const QByteArray &passPhrase, bool deepClear)
36{
37 if (pem.isEmpty())
38 return;
39
40 keyType = type;
41 keyAlgorithm = algorithm;
42
43 clear(deep: deepClear);
44
45 BIO *bio = q_BIO_new_mem_buf(a: const_cast<char *>(pem.data()), b: pem.size());
46 if (!bio)
47 return;
48
49 const auto bioRaii = qScopeGuard(f: [bio]{q_BIO_free(a: bio);});
50
51 void *phrase = const_cast<char *>(passPhrase.data());
52
53#ifdef OPENSSL_NO_DEPRECATED_3_0
54 if (type == QSsl::PublicKey)
55 genericKey = q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase);
56 else
57 genericKey = q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
58 keyIsNull = !genericKey;
59 if (keyIsNull)
60 QTlsBackendOpenSSL::logAndClearErrorQueue();
61#else
62
63 if (algorithm == QSsl::Rsa) {
64 RSA *result = (type == QSsl::PublicKey)
65 ? q_PEM_read_bio_RSA_PUBKEY(a: bio, b: &rsa, c: nullptr, d: phrase)
66 : q_PEM_read_bio_RSAPrivateKey(a: bio, b: &rsa, c: nullptr, d: phrase);
67 if (rsa && rsa == result)
68 keyIsNull = false;
69 } else if (algorithm == QSsl::Dsa) {
70 DSA *result = (type == QSsl::PublicKey)
71 ? q_PEM_read_bio_DSA_PUBKEY(a: bio, b: &dsa, c: nullptr, d: phrase)
72 : q_PEM_read_bio_DSAPrivateKey(a: bio, b: &dsa, c: nullptr, d: phrase);
73 if (dsa && dsa == result)
74 keyIsNull = false;
75 } else if (algorithm == QSsl::Dh) {
76 EVP_PKEY *result = (type == QSsl::PublicKey)
77 ? q_PEM_read_bio_PUBKEY(a: bio, b: nullptr, c: nullptr, d: phrase)
78 : q_PEM_read_bio_PrivateKey(a: bio, b: nullptr, c: nullptr, d: phrase);
79 if (result)
80 dh = q_EVP_PKEY_get1_DH(a: result);
81 if (dh)
82 keyIsNull = false;
83 q_EVP_PKEY_free(a: result);
84#ifndef OPENSSL_NO_EC
85 } else if (algorithm == QSsl::Ec) {
86 EC_KEY *result = (type == QSsl::PublicKey)
87 ? q_PEM_read_bio_EC_PUBKEY(a: bio, b: &ec, c: nullptr, d: phrase)
88 : q_PEM_read_bio_ECPrivateKey(a: bio, b: &ec, c: nullptr, d: phrase);
89 if (ec && ec == result)
90 keyIsNull = false;
91#endif // OPENSSL_NO_EC
92 }
93
94#endif // OPENSSL_NO_DEPRECATED_3_0
95}
96
97QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
98{
99 QByteArray header = pemHeader();
100 QByteArray footer = pemFooter();
101
102 QByteArray der(pem);
103
104 int headerIndex = der.indexOf(bv: header);
105 int footerIndex = der.indexOf(bv: footer, from: headerIndex + header.size());
106 if (type() != QSsl::PublicKey) {
107 if (headerIndex == -1 || footerIndex == -1) {
108 header = pkcs8Header(encrypted: true);
109 footer = pkcs8Footer(encrypted: true);
110 headerIndex = der.indexOf(bv: header);
111 footerIndex = der.indexOf(bv: footer, from: headerIndex + header.size());
112 }
113 if (headerIndex == -1 || footerIndex == -1) {
114 header = pkcs8Header(encrypted: false);
115 footer = pkcs8Footer(encrypted: false);
116 headerIndex = der.indexOf(bv: header);
117 footerIndex = der.indexOf(bv: footer, from: headerIndex + header.size());
118 }
119 }
120 if (headerIndex == -1 || footerIndex == -1)
121 return QByteArray();
122
123 der = der.mid(index: headerIndex + header.size(), len: footerIndex - (headerIndex + header.size()));
124
125 if (der.contains(bv: "Proc-Type:")) {
126 // taken from QHttpNetworkReplyPrivate::parseHeader
127 int i = 0;
128 while (i < der.size()) {
129 int j = der.indexOf(ch: ':', from: i); // field-name
130 if (j == -1)
131 break;
132 const QByteArray field = der.mid(index: i, len: j - i).trimmed();
133 j++;
134 // any number of LWS is allowed before and after the value
135 QByteArray value;
136 do {
137 i = der.indexOf(ch: '\n', from: j);
138 if (i == -1)
139 break;
140 if (!value.isEmpty())
141 value += ' ';
142 // check if we have CRLF or only LF
143 bool hasCR = (i && der[i-1] == '\r');
144 int length = i -(hasCR ? 1: 0) - j;
145 value += der.mid(index: j, len: length).trimmed();
146 j = ++i;
147 } while (i < der.size() && (der.at(i) == ' ' || der.at(i) == '\t'));
148 if (i == -1)
149 break; // something is wrong
150
151 headers->insert(key: field, value);
152 }
153 der = der.mid(index: i);
154 }
155
156 return QByteArray::fromBase64(base64: der); // ignores newlines
157}
158
159void TlsKeyOpenSSL::clear(bool deep)
160{
161 keyIsNull = true;
162
163#ifndef OPENSSL_NO_DEPRECATED_3_0
164 if (algorithm() == QSsl::Rsa && rsa) {
165 if (deep)
166 q_RSA_free(a: rsa);
167 rsa = nullptr;
168 }
169 if (algorithm() == QSsl::Dsa && dsa) {
170 if (deep)
171 q_DSA_free(a: dsa);
172 dsa = nullptr;
173 }
174 if (algorithm() == QSsl::Dh && dh) {
175 if (deep)
176 q_DH_free(dh: dh);
177 dh = nullptr;
178 }
179#ifndef OPENSSL_NO_EC
180 if (algorithm() == QSsl::Ec && ec) {
181 if (deep)
182 q_EC_KEY_free(ecdh: ec);
183 ec = nullptr;
184 }
185#endif
186#endif // OPENSSL_NO_DEPRECATED_3_0
187
188 if (algorithm() == QSsl::Opaque && opaque) {
189 if (deep)
190 q_EVP_PKEY_free(a: opaque);
191 opaque = nullptr;
192 }
193
194 if (genericKey) {
195 // None of the above cleared it. genericKey is either
196 // initialised by PEM read operation, or from X509, and
197 // we are the owners and not sharing. So we free it.
198 q_EVP_PKEY_free(a: genericKey);
199 genericKey = nullptr;
200 }
201}
202
203Qt::HANDLE TlsKeyOpenSSL::handle() const
204{
205 if (keyAlgorithm == QSsl::Opaque)
206 return Qt::HANDLE(opaque);
207
208#ifndef OPENSSL_NO_DEPRECATED_3_0
209 switch (keyAlgorithm) {
210 case QSsl::Rsa:
211 return Qt::HANDLE(rsa);
212 case QSsl::Dsa:
213 return Qt::HANDLE(dsa);
214 case QSsl::Dh:
215 return Qt::HANDLE(dh);
216#ifndef OPENSSL_NO_EC
217 case QSsl::Ec:
218 return Qt::HANDLE(ec);
219#endif
220 default:
221 return Qt::HANDLE(nullptr);
222 }
223#else
224 qCWarning(lcTlsBackend,
225 "This version of OpenSSL disabled direct manipulation with RSA/DSA/DH/EC_KEY structures, consider using QSsl::Opaque instead.");
226 return Qt::HANDLE(genericKey);
227#endif
228}
229
230int TlsKeyOpenSSL::length() const
231{
232 if (isNull() || algorithm() == QSsl::Opaque)
233 return -1;
234
235#ifndef OPENSSL_NO_DEPRECATED_3_0
236 switch (algorithm()) {
237 case QSsl::Rsa:
238 return q_RSA_bits(a: rsa);
239 case QSsl::Dsa:
240 return q_DSA_bits(a: dsa);
241 case QSsl::Dh:
242 return q_DH_bits(dh: dh);
243#ifndef OPENSSL_NO_EC
244 case QSsl::Ec:
245 return q_EC_GROUP_get_degree(g: q_EC_KEY_get0_group(k: ec));
246#endif
247 default:
248 return -1;
249 }
250#else // OPENSSL_NO_DEPRECATED_3_0
251 Q_ASSERT(genericKey);
252 return q_EVP_PKEY_get_bits(genericKey);
253#endif // OPENSSL_NO_DEPRECATED_3_0
254}
255
256QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
257{
258 if (!QSslSocket::supportsSsl() || isNull() || algorithm() == QSsl::Opaque)
259 return {};
260
261 const EVP_CIPHER *cipher = nullptr;
262 if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
263#ifndef OPENSSL_NO_DES
264 cipher = q_EVP_des_ede3_cbc();
265#else
266 return {};
267#endif
268 }
269
270 BIO *bio = q_BIO_new(a: q_BIO_s_mem());
271 if (!bio)
272 return {};
273
274 const auto bioRaii = qScopeGuard(f: [bio]{q_BIO_free(a: bio);});
275
276#ifndef OPENSSL_NO_DEPRECATED_3_0
277
278#define write_pubkey(alg, key) q_PEM_write_bio_##alg##_PUBKEY(bio, key)
279#define write_privatekey(alg, key) \
280 q_PEM_write_bio_##alg##PrivateKey(bio, key, cipher, (uchar *)passPhrase.data(), \
281 passPhrase.size(), nullptr, nullptr)
282
283#else
284
285#define write_pubkey(alg, key) q_PEM_write_bio_PUBKEY(bio, genericKey)
286#define write_privatekey(alg, key) \
287 q_PEM_write_bio_PrivateKey_traditional(bio, genericKey, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr)
288
289#endif // OPENSSL_NO_DEPRECATED_3_0
290
291 bool fail = false;
292 if (algorithm() == QSsl::Rsa) {
293 if (type() == QSsl::PublicKey) {
294 if (!write_pubkey(RSA, rsa))
295 fail = true;
296 } else if (!write_privatekey(RSA, rsa)) {
297 fail = true;
298 }
299 } else if (algorithm() == QSsl::Dsa) {
300 if (type() == QSsl::PublicKey) {
301 if (!write_pubkey(DSA, dsa))
302 fail = true;
303 } else if (!write_privatekey(DSA, dsa)) {
304 fail = true;
305 }
306 } else if (algorithm() == QSsl::Dh) {
307#ifdef OPENSSL_NO_DEPRECATED_3_0
308 EVP_PKEY *result = genericKey;
309#else
310 EVP_PKEY *result = q_EVP_PKEY_new();
311 const auto guard = qScopeGuard(f: [result]{if (result) q_EVP_PKEY_free(a: result);});
312 if (!result || !q_EVP_PKEY_set1_DH(a: result, b: dh)) {
313 fail = true;
314 } else
315#endif
316 if (type() == QSsl::PublicKey) {
317 if (!q_PEM_write_bio_PUBKEY(a: bio, b: result))
318 fail = true;
319 } else if (!q_PEM_write_bio_PrivateKey(a: bio, b: result, c: cipher, d: (uchar *)passPhrase.data(),
320 e: passPhrase.size(), f: nullptr, g: nullptr)) {
321 fail = true;
322 }
323#ifndef OPENSSL_NO_EC
324 } else if (algorithm() == QSsl::Ec) {
325 if (type() == QSsl::PublicKey) {
326 if (!write_pubkey(EC, ec))
327 fail = true;
328 } else {
329 if (!write_privatekey(EC, ec))
330 fail = true;
331 }
332#endif
333 } else {
334 fail = true;
335 }
336
337 QByteArray pem;
338 if (!fail) {
339 char *data = nullptr;
340 const long size = q_BIO_get_mem_data(bio, &data);
341 if (size > 0 && data)
342 pem = QByteArray(data, size);
343 } else {
344 QTlsBackendOpenSSL::logAndClearErrorQueue();
345 }
346
347 return pem;
348}
349
350void TlsKeyOpenSSL::fromHandle(Qt::HANDLE handle, QSsl::KeyType expectedType)
351{
352 EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
353 if (!evpKey || !fromEVP_PKEY(pkey: evpKey)) {
354 opaque = evpKey;
355 keyAlgorithm = QSsl::Opaque;
356 } else {
357 q_EVP_PKEY_free(a: evpKey);
358 }
359
360 keyType = expectedType;
361 keyIsNull = !opaque;
362}
363
364bool TlsKeyOpenSSL::fromEVP_PKEY(EVP_PKEY *pkey)
365{
366 if (!pkey)
367 return false;
368
369#ifndef OPENSSL_NO_DEPRECATED_3_0
370#define get_key(key, alg) key = q_EVP_PKEY_get1_##alg(pkey)
371#else
372#define get_key(key, alg) q_EVP_PKEY_up_ref(pkey); genericKey = pkey;
373#endif
374
375 switch (q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey))) {
376 case EVP_PKEY_RSA:
377 keyIsNull = false;
378 keyAlgorithm = QSsl::Rsa;
379 keyType = QSsl::PrivateKey;
380 get_key(rsa, RSA);
381 return true;
382 case EVP_PKEY_DSA:
383 keyIsNull = false;
384 keyAlgorithm = QSsl::Dsa;
385 keyType = QSsl::PrivateKey;
386 get_key(dsa, DSA);
387 return true;
388 case EVP_PKEY_DH:
389 keyIsNull = false;
390 keyAlgorithm = QSsl::Dh;
391 keyType = QSsl::PrivateKey;
392 get_key(dh, DH);
393 return true;
394#ifndef OPENSSL_NO_EC
395 case EVP_PKEY_EC:
396 keyIsNull = false;
397 keyAlgorithm = QSsl::Ec;
398 keyType = QSsl::PrivateKey;
399 get_key(ec, EC_KEY);
400 return true;
401#endif
402 default:;
403 // Unknown key type. This could be handled as opaque, but then
404 // we'd eventually leak memory since we wouldn't be able to free
405 // the underlying EVP_PKEY structure. For now, we won't support
406 // this.
407 }
408
409 return false;
410}
411
412QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
413 const QByteArray &key, const QByteArray &iv, bool enc)
414{
415 const EVP_CIPHER *type = nullptr;
416 int i = 0, len = 0;
417
418 switch (cipher) {
419 case Cipher::DesCbc:
420#ifndef OPENSSL_NO_DES
421 type = q_EVP_des_cbc();
422#endif
423 break;
424 case Cipher::DesEde3Cbc:
425#ifndef OPENSSL_NO_DES
426 type = q_EVP_des_ede3_cbc();
427#endif
428 break;
429 case Cipher::Rc2Cbc:
430#ifndef OPENSSL_NO_RC2
431 type = q_EVP_rc2_cbc();
432#endif
433 break;
434 case Cipher::Aes128Cbc:
435 type = q_EVP_aes_128_cbc();
436 break;
437 case Cipher::Aes192Cbc:
438 type = q_EVP_aes_192_cbc();
439 break;
440 case Cipher::Aes256Cbc:
441 type = q_EVP_aes_256_cbc();
442 break;
443 }
444
445 if (type == nullptr)
446 return {};
447
448 QByteArray output;
449 output.resize(size: data.size() + EVP_MAX_BLOCK_LENGTH);
450
451 EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
452 q_EVP_CIPHER_CTX_reset(c: ctx);
453 if (q_EVP_CipherInit(ctx, type, key: nullptr, iv: nullptr, enc) != 1) {
454 q_EVP_CIPHER_CTX_free(a: ctx);
455 QTlsBackendOpenSSL::logAndClearErrorQueue();
456 return {};
457 }
458
459 q_EVP_CIPHER_CTX_set_key_length(x: ctx, keylen: key.size());
460 if (cipher == Cipher::Rc2Cbc)
461 q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, arg: 8 * key.size(), ptr: nullptr);
462
463 q_EVP_CipherInit_ex(ctx, cipher: nullptr, impl: nullptr,
464 key: reinterpret_cast<const unsigned char *>(key.constData()),
465 iv: reinterpret_cast<const unsigned char *>(iv.constData()),
466 enc);
467 q_EVP_CipherUpdate(ctx,
468 out: reinterpret_cast<unsigned char *>(output.data()), outl: &len,
469 in: reinterpret_cast<const unsigned char *>(data.constData()), inl: data.size());
470 q_EVP_CipherFinal(ctx,
471 out: reinterpret_cast<unsigned char *>(output.data()) + len, outl: &i);
472 len += i;
473
474 q_EVP_CIPHER_CTX_reset(c: ctx);
475 q_EVP_CIPHER_CTX_free(a: ctx);
476
477 return output.left(n: len);
478}
479
480QByteArray TlsKeyOpenSSL::decrypt(Cipher cipher, const QByteArray &data,
481 const QByteArray &key, const QByteArray &iv) const
482{
483 return doCrypt(cipher, data, key, iv, enc: false);
484}
485
486QByteArray TlsKeyOpenSSL::encrypt(Cipher cipher, const QByteArray &data,
487 const QByteArray &key, const QByteArray &iv) const
488{
489 return doCrypt(cipher, data, key, iv, enc: true);
490}
491
492TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
493{
494 TlsKeyOpenSSL *tlsKey = new TlsKeyOpenSSL;
495 std::unique_ptr<TlsKeyOpenSSL> keyRaii(tlsKey);
496
497 tlsKey->keyType = QSsl::PublicKey;
498
499#ifndef OPENSSL_NO_DEPRECATED_3_0
500
501#define get_pubkey(keyName, alg) tlsKey->keyName = q_EVP_PKEY_get1_##alg(pkey)
502
503#else
504
505#define get_pubkey(a, b) tlsKey->genericKey = pkey
506
507#endif
508
509 EVP_PKEY *pkey = q_X509_get_pubkey(a: x);
510 Q_ASSERT(pkey);
511 const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
512
513 if (keyType == EVP_PKEY_RSA) {
514 get_pubkey(rsa, RSA);
515 tlsKey->keyAlgorithm = QSsl::Rsa;
516 tlsKey->keyIsNull = false;
517 } else if (keyType == EVP_PKEY_DSA) {
518 get_pubkey(dsa, DSA);
519 tlsKey->keyAlgorithm = QSsl::Dsa;
520 tlsKey->keyIsNull = false;
521#ifndef OPENSSL_NO_EC
522 } else if (keyType == EVP_PKEY_EC) {
523 get_pubkey(ec, EC_KEY);
524 tlsKey->keyAlgorithm = QSsl::Ec;
525 tlsKey->keyIsNull = false;
526#endif
527 } else if (keyType == EVP_PKEY_DH) {
528 // DH unsupported (key is null)
529 } else {
530 // error? (key is null)
531 }
532
533#ifndef OPENSSL_NO_DEPRECATED_3_0
534 q_EVP_PKEY_free(a: pkey);
535#endif
536
537 return keyRaii.release();
538}
539
540} // namespace QTlsPrivate
541
542QT_END_NAMESPACE
543

source code of qtbase/src/plugins/tls/openssl/qtlskey_openssl.cpp